From lldb-commits at lists.llvm.org Mon May 12 01:14:34 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 01:14:34 -0700 (PDT) Subject: [Lldb-commits] [lldb] Extending LLDB to work on AIX (PR #102601) In-Reply-To: Message-ID: <6821adea.a70a0220.39931a.b147@mx.google.com> https://github.com/ravi-sh updated https://github.com/llvm/llvm-project/pull/102601 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Mon May 12 01:24:44 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 01:24:44 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add field member operators to DIL (PR #138093) In-Reply-To: Message-ID: <6821b04c.050a0220.1cd9af.b657@mx.google.com> ================ @@ -272,4 +272,66 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const MemberOfNode *node) { + Status error; + auto base_or_err = Evaluate(node->GetBase()); + if (!base_or_err) { + return base_or_err; + } + lldb::ValueObjectSP base = *base_or_err; + + // Perform basic type checking. + CompilerType base_type = base->GetCompilerType(); + // When using an arrow, make sure the base is a pointer or array type. + // When using a period, make sure the base type is NOT a pointer type. + if (node->GetIsArrow() && !base_type.IsPointerType() && + !base_type.IsArrayType()) { ---------------- labath wrote: I think we should drop the type checks and perform the dereference unconditionally. https://github.com/llvm/llvm-project/pull/138093 From lldb-commits at lists.llvm.org Mon May 12 01:24:44 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 01:24:44 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add field member operators to DIL (PR #138093) In-Reply-To: Message-ID: <6821b04c.170a0220.274bf7.b7b9@mx.google.com> ================ @@ -88,6 +89,29 @@ class IdentifierNode : public ASTNode { std::string m_name; }; +class MemberOfNode : public ASTNode { +public: + MemberOfNode(uint32_t location, ASTNodeUP base, bool is_arrow, + std::string name) + : ASTNode(location, NodeKind::eMemberOfNode), m_base(std::move(base)), + m_is_arrow(is_arrow), m_field_name(std::move(name)) {} + + llvm::Expected Accept(Visitor *v) const override; + + ASTNode *GetBase() const { return m_base.get(); } + bool GetIsArrow() const { return m_is_arrow; } + std::string GetFieldName() const { return m_field_name; } ---------------- labath wrote: ```suggestion llvm::StringRef GetFieldName() const { return m_field_name; } ``` https://github.com/llvm/llvm-project/pull/138093 From lldb-commits at lists.llvm.org Mon May 12 01:24:44 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 01:24:44 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add field member operators to DIL (PR #138093) In-Reply-To: Message-ID: <6821b04c.170a0220.c5db0.7f35@mx.google.com> ================ @@ -272,4 +272,66 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const MemberOfNode *node) { + Status error; ---------------- labath wrote: Declare it where it's being used to make it clear what's its scope and contents. https://github.com/llvm/llvm-project/pull/138093 From lldb-commits at lists.llvm.org Mon May 12 01:24:44 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 01:24:44 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add field member operators to DIL (PR #138093) In-Reply-To: Message-ID: <6821b04c.170a0220.2598dd.66b7@mx.google.com> ================ @@ -272,4 +272,66 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const MemberOfNode *node) { + Status error; + auto base_or_err = Evaluate(node->GetBase()); + if (!base_or_err) { + return base_or_err; + } + lldb::ValueObjectSP base = *base_or_err; + + // Perform basic type checking. + CompilerType base_type = base->GetCompilerType(); + // When using an arrow, make sure the base is a pointer or array type. + // When using a period, make sure the base type is NOT a pointer type. + if (node->GetIsArrow() && !base_type.IsPointerType() && + !base_type.IsArrayType()) { + lldb::ValueObjectSP deref_sp = base->Dereference(error); + if (error.Success()) { + base = deref_sp; + base_type = deref_sp->GetCompilerType().GetPointerType(); + } else { + std::string errMsg = + llvm::formatv("member reference type {0} is not a pointer; " + "did you mean to use '.'?", + base_type.TypeDescription()); + return llvm::make_error( + m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); + } + } else if (!node->GetIsArrow() && base_type.IsPointerType()) { ---------------- labath wrote: same here https://github.com/llvm/llvm-project/pull/138093 From lldb-commits at lists.llvm.org Mon May 12 01:24:45 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 01:24:45 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add field member operators to DIL (PR #138093) In-Reply-To: Message-ID: <6821b04d.170a0220.597c3.9208@mx.google.com> ================ @@ -111,7 +111,27 @@ ASTNodeUP DILParser::ParseUnaryExpression() { llvm_unreachable("invalid token kind"); } } - return ParsePrimaryExpression(); + return ParsePostfixExpression(); +} +// Parse a postfix_expression. ---------------- labath wrote: ```suggestion // Parse a postfix_expression. ``` https://github.com/llvm/llvm-project/pull/138093 From lldb-commits at lists.llvm.org Mon May 12 01:24:45 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 01:24:45 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add field member operators to DIL (PR #138093) In-Reply-To: Message-ID: <6821b04d.170a0220.32f084.6eb6@mx.google.com> ================ @@ -272,4 +272,66 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const MemberOfNode *node) { + Status error; + auto base_or_err = Evaluate(node->GetBase()); + if (!base_or_err) { + return base_or_err; + } ---------------- labath wrote: https://llvm.org/docs/CodingStandards.html#don-t-use-braces-on-simple-single-statement-bodies-of-if-else-loop-statements https://github.com/llvm/llvm-project/pull/138093 From lldb-commits at lists.llvm.org Mon May 12 01:24:45 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 01:24:45 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add field member operators to DIL (PR #138093) In-Reply-To: Message-ID: <6821b04d.170a0220.278e07.b4bc@mx.google.com> ================ @@ -0,0 +1,59 @@ +int +main(int argc, char**argv) +{ + int x = 2; + struct Sx { + int x; + int& r; + char y; + } s{1, x, 2}; + + Sx& sr = s; + Sx* sp = &s; + + Sx sarr[2] = {{5, x, 2}, {1, x, 3}}; + + using SxAlias = Sx; + SxAlias sa{3, x, 4}; + + return 0; // Set a breakpoint here +} + +/* + EXPECT_THAT(Eval("s.x"), IsEqual("1")); + EXPECT_THAT(Eval("s.r"), IsEqual("2")); + EXPECT_THAT(Eval("s.r + 1"), IsEqual("3")); + EXPECT_THAT(Eval("sr.x"), IsEqual("1")); + EXPECT_THAT(Eval("sr.r"), IsEqual("2")); + EXPECT_THAT(Eval("sr.r + 1"), IsEqual("3")); + EXPECT_THAT(Eval("sp->x"), IsEqual("1")); + EXPECT_THAT(Eval("sp->r"), IsEqual("2")); + EXPECT_THAT(Eval("sp->r + 1"), IsEqual("3")); + EXPECT_THAT(Eval("sarr->x"), IsEqual("5")); + EXPECT_THAT(Eval("sarr->r"), IsEqual("2")); + EXPECT_THAT(Eval("sarr->r + 1"), IsEqual("3")); + EXPECT_THAT(Eval("(sarr + 1)->x"), IsEqual("1")); + + EXPECT_THAT( + Eval("sp->4"), + IsError( + ":1:5: expected 'identifier', got: <'4' (numeric_constant)>\n" + "sp->4\n" + " ^")); + EXPECT_THAT(Eval("sp->foo"), IsError("no member named 'foo' in 'Sx'")); + EXPECT_THAT( + Eval("sp->r / (void*)0"), + IsError("invalid operands to binary expression ('int' and 'void *')")); + + EXPECT_THAT(Eval("sp.x"), IsError("member reference type 'Sx *' is a " + "pointer; did you mean to use '->'")); + EXPECT_THAT( + Eval("sarr.x"), + IsError( + "member reference base type 'Sx[2]' is not a structure or union")); + + // Test for record typedefs. + EXPECT_THAT(Eval("sa.x"), IsEqual("3")); + EXPECT_THAT(Eval("sa.y"), IsEqual("'\\x04'")); + +*/ ---------------- labath wrote: ?? https://github.com/llvm/llvm-project/pull/138093 From lldb-commits at lists.llvm.org Mon May 12 01:24:45 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 01:24:45 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add field member operators to DIL (PR #138093) In-Reply-To: Message-ID: <6821b04d.050a0220.3c73cc.bd20@mx.google.com> ================ @@ -272,4 +272,66 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const MemberOfNode *node) { + Status error; + auto base_or_err = Evaluate(node->GetBase()); + if (!base_or_err) { + return base_or_err; + } + lldb::ValueObjectSP base = *base_or_err; + + // Perform basic type checking. + CompilerType base_type = base->GetCompilerType(); + // When using an arrow, make sure the base is a pointer or array type. + // When using a period, make sure the base type is NOT a pointer type. + if (node->GetIsArrow() && !base_type.IsPointerType() && + !base_type.IsArrayType()) { + lldb::ValueObjectSP deref_sp = base->Dereference(error); + if (error.Success()) { + base = deref_sp; + base_type = deref_sp->GetCompilerType().GetPointerType(); + } else { + std::string errMsg = + llvm::formatv("member reference type {0} is not a pointer; " + "did you mean to use '.'?", + base_type.TypeDescription()); + return llvm::make_error( + m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); + } + } else if (!node->GetIsArrow() && base_type.IsPointerType()) { + std::string errMsg = + llvm::formatv("member reference type {0} is a pointer; " + "did you mean to use '->'?", + base_type.TypeDescription()); + return llvm::make_error( + m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); + } + + // User specified array->elem; need to get to element[0] to look for fields. + if (node->GetIsArrow() && base_type.IsArrayType()) + base = base->GetChildAtIndex(0); + + // Now look for the member with the specified name. + lldb::ValueObjectSP field_obj = + base->GetChildMemberWithName(llvm::StringRef(node->GetFieldName())); + if (field_obj && field_obj->GetName().GetString() == node->GetFieldName()) { + if (field_obj->GetCompilerType().IsReferenceType()) { + lldb::ValueObjectSP tmp_obj = field_obj->Dereference(error); + if (error.Fail()) + return error.ToError(); + return tmp_obj; + } + return field_obj; + } + + if (node->GetIsArrow() && base_type.IsPointerType()) + base_type = base_type.GetPointeeType(); + std::string errMsg = + llvm::formatv("no member named '{0}' in {1}", node->GetFieldName(), ---------------- labath wrote: What kind of error do we get from GetChildMemberWithName? Could we forward that? https://github.com/llvm/llvm-project/pull/138093 From lldb-commits at lists.llvm.org Mon May 12 01:24:46 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 01:24:46 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add field member operators to DIL (PR #138093) In-Reply-To: Message-ID: <6821b04e.630a0220.1a93a4.13ee@mx.google.com> ================ @@ -272,4 +272,66 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const MemberOfNode *node) { + Status error; + auto base_or_err = Evaluate(node->GetBase()); + if (!base_or_err) { + return base_or_err; + } + lldb::ValueObjectSP base = *base_or_err; + + // Perform basic type checking. + CompilerType base_type = base->GetCompilerType(); + // When using an arrow, make sure the base is a pointer or array type. + // When using a period, make sure the base type is NOT a pointer type. + if (node->GetIsArrow() && !base_type.IsPointerType() && + !base_type.IsArrayType()) { + lldb::ValueObjectSP deref_sp = base->Dereference(error); + if (error.Success()) { + base = deref_sp; + base_type = deref_sp->GetCompilerType().GetPointerType(); + } else { + std::string errMsg = + llvm::formatv("member reference type {0} is not a pointer; " + "did you mean to use '.'?", + base_type.TypeDescription()); + return llvm::make_error( + m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); + } + } else if (!node->GetIsArrow() && base_type.IsPointerType()) { + std::string errMsg = + llvm::formatv("member reference type {0} is a pointer; " + "did you mean to use '->'?", + base_type.TypeDescription()); + return llvm::make_error( + m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); + } + + // User specified array->elem; need to get to element[0] to look for fields. + if (node->GetIsArrow() && base_type.IsArrayType()) + base = base->GetChildAtIndex(0); + + // Now look for the member with the specified name. + lldb::ValueObjectSP field_obj = + base->GetChildMemberWithName(llvm::StringRef(node->GetFieldName())); + if (field_obj && field_obj->GetName().GetString() == node->GetFieldName()) { + if (field_obj->GetCompilerType().IsReferenceType()) { + lldb::ValueObjectSP tmp_obj = field_obj->Dereference(error); ---------------- labath wrote: Why is this necessary? GetChildMemberWithName seems to work just fine on references: ``` (lldb) script lldb.frame.FindVariable("b") (A &) b = 0x00007fffffffd7e8: { X = 42 x = 0x00007fffffffd7e8 } (lldb) script lldb.frame.FindVariable("b").GetChildMemberWithName("X") (int) X = 42 ``` https://github.com/llvm/llvm-project/pull/138093 From lldb-commits at lists.llvm.org Mon May 12 01:24:46 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 01:24:46 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add field member operators to DIL (PR #138093) In-Reply-To: Message-ID: <6821b04e.a70a0220.49f0c.9302@mx.google.com> ================ @@ -272,4 +272,66 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const MemberOfNode *node) { + Status error; + auto base_or_err = Evaluate(node->GetBase()); + if (!base_or_err) { + return base_or_err; + } + lldb::ValueObjectSP base = *base_or_err; + + // Perform basic type checking. + CompilerType base_type = base->GetCompilerType(); + // When using an arrow, make sure the base is a pointer or array type. + // When using a period, make sure the base type is NOT a pointer type. + if (node->GetIsArrow() && !base_type.IsPointerType() && + !base_type.IsArrayType()) { + lldb::ValueObjectSP deref_sp = base->Dereference(error); + if (error.Success()) { + base = deref_sp; + base_type = deref_sp->GetCompilerType().GetPointerType(); + } else { + std::string errMsg = + llvm::formatv("member reference type {0} is not a pointer; " + "did you mean to use '.'?", + base_type.TypeDescription()); + return llvm::make_error( + m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); + } + } else if (!node->GetIsArrow() && base_type.IsPointerType()) { + std::string errMsg = + llvm::formatv("member reference type {0} is a pointer; " + "did you mean to use '->'?", + base_type.TypeDescription()); + return llvm::make_error( + m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); + } + + // User specified array->elem; need to get to element[0] to look for fields. + if (node->GetIsArrow() && base_type.IsArrayType()) + base = base->GetChildAtIndex(0); ---------------- labath wrote: This probably shouldn't exist https://github.com/llvm/llvm-project/pull/138093 From lldb-commits at lists.llvm.org Mon May 12 01:58:14 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 01:58:14 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Support for XCOFF Sections (PR #131304) In-Reply-To: Message-ID: <6821b826.170a0220.3d8973.7ca2@mx.google.com> https://github.com/labath approved this pull request. https://github.com/llvm/llvm-project/pull/131304 From lldb-commits at lists.llvm.org Mon May 12 01:58:14 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 01:58:14 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Support for XCOFF Sections (PR #131304) In-Reply-To: Message-ID: <6821b826.050a0220.30beba.e5ed@mx.google.com> ================ @@ -190,7 +190,59 @@ void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) {} bool ObjectFileXCOFF::IsStripped() { return false; } -void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) {} +void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) { + if (m_sections_up) + return; + + m_sections_up = std::make_unique(); + ModuleSP module_sp(GetModule()); + + if (!module_sp) + return; + + std::lock_guard guard(module_sp->GetMutex()); + + const auto §ions = m_binary->sections64(); + int idx = 0; + for (size_t i = 0; i < sections.size(); ++i) { + const llvm::object::XCOFFSectionHeader64 §ion = sections[i]; + + ConstString const_sect_name(section.Name); + + SectionType section_type = lldb::eSectionTypeOther; + if (section.Flags & XCOFF::STYP_TEXT) + section_type = eSectionTypeCode; + else if (section.Flags & XCOFF::STYP_DATA) + section_type = eSectionTypeData; + else if (section.Flags & XCOFF::STYP_BSS) + section_type = eSectionTypeZeroFill; + else if (section.Flags & XCOFF::STYP_DWARF) { + section_type = llvm::StringSwitch(section.Name) + .Case(".dwinfo", eSectionTypeDWARFDebugInfo) + .Case(".dwline", eSectionTypeDWARFDebugLine) + .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev) + .Default(eSectionTypeInvalid); + + if (section_type == eSectionTypeInvalid) + section_type = lldb::eSectionTypeOther; ---------------- labath wrote: ```suggestion .Default(eSectionTypeOther); ``` https://github.com/llvm/llvm-project/pull/131304 From lldb-commits at lists.llvm.org Mon May 12 01:58:14 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 01:58:14 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Support for XCOFF Sections (PR #131304) In-Reply-To: Message-ID: <6821b826.a70a0220.13a601.97ac@mx.google.com> ================ @@ -190,7 +190,59 @@ void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) {} bool ObjectFileXCOFF::IsStripped() { return false; } -void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) {} +void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) { + if (m_sections_up) + return; + + m_sections_up = std::make_unique(); + ModuleSP module_sp(GetModule()); + + if (!module_sp) + return; + + std::lock_guard guard(module_sp->GetMutex()); + + const auto §ions = m_binary->sections64(); + int idx = 0; + for (size_t i = 0; i < sections.size(); ++i) { + const llvm::object::XCOFFSectionHeader64 §ion = sections[i]; ---------------- labath wrote: Does this not work for some reason? ```suggestion int idx = 0; for (const llvm::object::XCOFFSectionHeader64 §ion = m_binary->sections64()) { ``` https://github.com/llvm/llvm-project/pull/131304 From lldb-commits at lists.llvm.org Mon May 12 02:00:07 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 02:00:07 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Support for XCOFF Sections (PR #131304) In-Reply-To: Message-ID: <6821b897.050a0220.1417f5.aae7@mx.google.com> ================ @@ -7,6 +7,9 @@ # CHECK: Stripped: false # CHECK: Type: executable # CHECK: Strata: unknown +# CHECK: Name: .text +# CHECK-NEXT: code +# CHECK-NEXT: r-x ---------------- labath wrote: That's because most of their code is very old. I definitely wouldn't want to emulate that aspect of them. https://github.com/llvm/llvm-project/pull/131304 From lldb-commits at lists.llvm.org Mon May 12 02:00:30 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 02:00:30 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Support for XCOFF Sections (PR #131304) In-Reply-To: Message-ID: <6821b8ae.170a0220.310b6.7690@mx.google.com> ================ @@ -190,8 +190,83 @@ void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) {} bool ObjectFileXCOFF::IsStripped() { return false; } -void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) {} - +void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) { + + if (m_sections_up) + return; + m_sections_up = std::make_unique(); + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard guard(module_sp->GetMutex()); + + ModuleSP module_sp(GetModule()); + for (auto sIdx = m_binary->section_begin(); sIdx != m_binary->section_end(); + ++sIdx) { ---------------- labath wrote: SGTM https://github.com/llvm/llvm-project/pull/131304 From lldb-commits at lists.llvm.org Mon May 12 02:32:41 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 02:32:41 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb]Make `list` command work with headers when possible. (PR #139002) In-Reply-To: Message-ID: <6821c039.a70a0220.19aaf3.b111@mx.google.com> https://github.com/labath commented: It seems rather wasteful (and error-prone) to repeat the search through the support files of a compile unit, given that ResolveSymbolContextForFilePath has already searched through them and told us that the CU really does contain a file with the given name. The problem is that the return value is just the CU itself, so all the information we get is "the file is *somewhere* in this CU". However, this function is also (and primarily) used for setting file+line breakpoints, and you definitely can set breakpoints in the header files. So, how does that work? When setting a breakpoint, we pass eSymbolContextLineEntry to the function so that it returns a line entry matching the query. In this case, we're not really interested in the entire line entry, but I think it should be possible the line entry as a carrier for the file name: we ask for the function to fill it out, and then fetch the file from there. Can you see if that works? I also think that changing `0` to `start_line` was not right change. Since we're not actually line entry (just the file name, we'll extract the lines ourselves), we want to maximize our chances of finding a matching line entry. If it cannot find an exact file+line match, `ResolveSymbolContextForFilePath` will return a line entry for any line that comes after it. Using zero ensures we don't skip any line entries. https://github.com/llvm/llvm-project/pull/139002 From lldb-commits at lists.llvm.org Mon May 12 02:32:41 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 02:32:41 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb]Make `list` command work with headers when possible. (PR #139002) In-Reply-To: Message-ID: <6821c039.a70a0220.ce45a.ac3f@mx.google.com> https://github.com/labath edited https://github.com/llvm/llvm-project/pull/139002 From lldb-commits at lists.llvm.org Mon May 12 02:32:42 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 02:32:42 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb]Make `list` command work with headers when possible. (PR #139002) In-Reply-To: Message-ID: <6821c03a.170a0220.88abc.755e@mx.google.com> ================ @@ -1114,15 +1115,15 @@ class CommandObjectSourceList : public CommandObjectParsed { matching_modules.Clear(); target.GetImages().FindModules(module_spec, matching_modules); num_matches += matching_modules.ResolveSymbolContextForFilePath( - filename, 0, check_inlines, + filename, start_line, check_inlines, SymbolContextItem(eSymbolContextModule | eSymbolContextCompUnit), ---------------- labath wrote: ```suggestion filename, 0, check_inlines, SymbolContextItem(eSymbolContextModule | eSymbolContextCompUnit | eSymbolContextLineEntry), ``` https://github.com/llvm/llvm-project/pull/139002 From lldb-commits at lists.llvm.org Mon May 12 02:32:42 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 02:32:42 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb]Make `list` command work with headers when possible. (PR #139002) In-Reply-To: Message-ID: <6821c03a.170a0220.2069a8.9389@mx.google.com> ================ @@ -1170,10 +1171,41 @@ class CommandObjectSourceList : public CommandObjectParsed { if (m_options.num_lines == 0) m_options.num_lines = 10; const uint32_t column = 0; + + // Headers aren't always in the DWARF but if they have + // executable code (eg., inlined-functions) then the callsite's + // file(s) will be found. So if a header was requested and we got a + // primary file (ie., something with a different name), then look thru + // its support file(s) for the header. + lldb::SupportFileSP found_file_sp = ---------------- labath wrote: And now get the file from `sc.line_entry.file_sp` https://github.com/llvm/llvm-project/pull/139002 From lldb-commits at lists.llvm.org Mon May 12 03:00:35 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 03:00:35 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Don't create instance of `SymbolFileDWARFDebugMap` for non-Mach-O files (PR #139170) In-Reply-To: Message-ID: <6821c6c3.170a0220.27e633.8efc@mx.google.com> labath wrote: FWIW, I completely agree @royitaqi. I'm not saying inter-plugin dependencies should be a free-for-all (*), but I think that some kinds of dependencies make sense and I definitely think this is one of them. The debug map format is intimately tied to the MachO and darwin ecosystems and I think there's approximately zero chance that it will be implemented elsewhere. Using the debug map requires MachO files, so why not just admit that? This isn't the only example of that. For example, ProcessElfCore requires *elf* core files. ProcessMachCore requires MachO core files. And I think that's a perfectly natural state of the world and doing anything else would make things a lot more convoluted. I think something like `SupportsDebugMap` is a step in the wrong direction. It's true that removes the link time dependency but the moral dependency remains, and in fact this makes it worse, because now *every* object file plugin needs to know about the debug map. Why should ObjectFilePECOFF need to think about whether it supports a random symbol file plugin? (*) I think that plugin dependencies should form a DAG. The fact that SymbolFileDWARFDebugMap depends on ObjectFileMachO means that ObjectFileMachO should not depend on SymbolFileDWARFDebugMap -- which I think is also perfectly natural restriction. And even if there is a reason why you might want to depend the other way, you can try to break it using the usual dependency reversal techniques, but you'd only need to touch these two plugins -- not every plugin of the two kinds. I might also say that, for the sake of clarity, the dependency direction should be uniform across all plugins of the same type. So that SymbolFileDWARFDebugMap depends on ObjectFileMachO means that no other object file plugin can depend on any other symbol file plugin, which is, again, I think a reasonable requirement, and I would say that if we ever find a case where we have two plugin pairs which want to depend in the opposite directions, that this means that those plugin types are not designed properly (maybe they ought to be a single plugin?). https://github.com/llvm/llvm-project/pull/139170 From lldb-commits at lists.llvm.org Mon May 12 03:16:09 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 03:16:09 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][core] Fix getting summary of a variable pointing to r/o memory (PR #139196) In-Reply-To: Message-ID: <6821ca69.170a0220.10096a.850c@mx.google.com> ================ @@ -734,15 +734,22 @@ size_t ValueObject::GetPointeeData(DataExtractor &data, uint32_t item_idx, } break; case eAddressTypeLoad: { ExecutionContext exe_ctx(GetExecutionContextRef()); - Process *process = exe_ctx.GetProcessPtr(); - if (process) { - heap_buf_ptr->SetByteSize(bytes); - size_t bytes_read = process->ReadMemory( + heap_buf_ptr->SetByteSize(bytes); + size_t bytes_read = 0; + if (Process *process = exe_ctx.GetProcessPtr(); + process && process->IsLiveDebugSession()) { ---------------- labath wrote: I'd like to avoid special casing core files. Can we just call the target version all the time? https://github.com/llvm/llvm-project/pull/139196 From lldb-commits at lists.llvm.org Mon May 12 03:45:42 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 03:45:42 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][plugin] Clear in same thread as set (PR #139252) In-Reply-To: Message-ID: <6821d156.a70a0220.ce45a.afcb@mx.google.com> https://github.com/labath requested changes to this pull request. This defeats the purpose of storing the sentinel object -- the goal was to clear it only after performing all the indexing. I think the ScopedExtractDIEs object needs to be implemented differently. It uses the RWMutex as a counter of active object instances, which is... cute... but not really necessary. Instead of the RW mutex, it could count the number of instances directly (in an integer variable) and then clean up when the count goes to zero. The variable could be protected by a (regular) mutex, and this would only need to be locked while manipulating the variable, so it will always be unlocked/locked on the same thread. https://github.com/llvm/llvm-project/pull/139252 From lldb-commits at lists.llvm.org Mon May 12 03:54:12 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Mon, 12 May 2025 03:54:12 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Support for XCOFF Sections (PR #131304) In-Reply-To: Message-ID: <6821d354.050a0220.2b3b98.deb9@mx.google.com> https://github.com/DhruvSrivastavaX updated https://github.com/llvm/llvm-project/pull/131304 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Mon May 12 04:00:08 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Mon, 12 May 2025 04:00:08 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Support for XCOFF Sections (PR #131304) In-Reply-To: Message-ID: <6821d4b8.170a0220.fc9e8.83d7@mx.google.com> https://github.com/DhruvSrivastavaX updated https://github.com/llvm/llvm-project/pull/131304 >From 106e137fea7d4b420ce3d97a8df16c3a91400997 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Fri, 14 Mar 2025 02:51:21 -0500 Subject: [PATCH 1/6] Support for XCOFF Sections --- .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 153 +++++++++++++----- 1 file changed, 114 insertions(+), 39 deletions(-) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index b54d43c5dd737..0dd9126468923 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -190,50 +190,125 @@ void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) {} bool ObjectFileXCOFF::IsStripped() { return false; } -void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) {} - -void ObjectFileXCOFF::Dump(Stream *s) {} - -ArchSpec ObjectFileXCOFF::GetArchitecture() { - ArchSpec arch_spec = - ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); - return arch_spec; +void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) { + + if (m_sections_up) + return; + m_sections_up = std::make_unique(); + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard guard(module_sp->GetMutex()); + + ModuleSP module_sp(GetModule()); + for (auto sIdx = m_binary->section_begin(); sIdx != m_binary->section_end(); + ++sIdx) { + llvm::Expected name = + m_binary->getSectionName(sIdx->getRawDataRefImpl()); + if (!name) { + llvm::Error err = name.takeError(); + } + llvm::StringRef sect_name = *name; + ConstString const_sect_name(sect_name); + int sect_index = sIdx->getIndex(), idx = 1; + llvm::Expected section = + m_binary->getSectionByNum(sect_index); + if (!section) { + llvm::Error err = section.takeError(); + } + llvm::object::DataRefImpl dataref = section.get(); + const llvm::object::XCOFFSectionHeader64 *sectionPtr = + reinterpret_cast( + dataref.p); + + SectionType section_type = lldb::eSectionTypeOther; + if (sectionPtr->Flags & XCOFF::STYP_TEXT) + section_type = eSectionTypeCode; + if (sectionPtr->Flags & XCOFF::STYP_DATA) + section_type = eSectionTypeData; + if (sectionPtr->Flags & XCOFF::STYP_BSS) + section_type = eSectionTypeZeroFill; + if (sectionPtr->Flags & XCOFF::STYP_DWARF) { + SectionType section_type = + llvm::StringSwitch(sect_name) + .Case(".dwinfo", eSectionTypeDWARFDebugInfo) + .Case(".dwline", eSectionTypeDWARFDebugLine) + .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev) + .Default(eSectionTypeInvalid); + + if (section_type == eSectionTypeInvalid) + section_type = lldb::eSectionTypeOther; + } + SectionSP section_sp(new Section( + module_sp, // Module to which this section belongs + this, // Object file to which this section belongs + idx++, // Section ID is the 1 based section index. + const_sect_name, // Name of this section + section_type, + sectionPtr->VirtualAddress, // File VM address == addresses as + // they are found in the object file + sectionPtr->SectionSize, // VM size in bytes of this section + sectionPtr->FileOffsetToRawData, // Offset to the data for this + // section in the file + sectionPtr->SectionSize, // Size in bytes of this section as found in + // the file + 0, // FIXME: alignment + sectionPtr->Flags)); // Flags for this section + + uint32_t permissions = 0; + permissions |= ePermissionsReadable; + if (sectionPtr->Flags & (XCOFF::STYP_DATA | XCOFF::STYP_BSS)) + permissions |= ePermissionsWritable; + if (sectionPtr->Flags & XCOFF::STYP_TEXT) + permissions |= ePermissionsExecutable; + section_sp->SetPermissions(permissions); + + m_sections_up->AddSection(section_sp); + unified_section_list.AddSection(section_sp); + } + } } + void ObjectFileXCOFF::Dump(Stream * s) {} -UUID ObjectFileXCOFF::GetUUID() { return UUID(); } + ArchSpec ObjectFileXCOFF::GetArchitecture() { + ArchSpec arch_spec = + ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + return arch_spec; + } -uint32_t ObjectFileXCOFF::GetDependentModules(FileSpecList &files) { return 0; } + UUID ObjectFileXCOFF::GetUUID() { return UUID(); } -ObjectFile::Type ObjectFileXCOFF::CalculateType() { - if (m_binary->fileHeader64()->Flags & XCOFF::F_EXEC) - return eTypeExecutable; - else if (m_binary->fileHeader64()->Flags & XCOFF::F_SHROBJ) - return eTypeSharedLibrary; - return eTypeUnknown; -} + uint32_t ObjectFileXCOFF::GetDependentModules(FileSpecList & files) { + return 0; + } -ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { return eStrataUnknown; } + ObjectFile::Type ObjectFileXCOFF::CalculateType() { + if (m_binary->fileHeader64()->Flags & XCOFF::F_EXEC) + return eTypeExecutable; + else if (m_binary->fileHeader64()->Flags & XCOFF::F_SHROBJ) + return eTypeSharedLibrary; + return eTypeUnknown; + } -lldb::WritableDataBufferSP -ObjectFileXCOFF::MapFileDataWritable(const FileSpec &file, uint64_t Size, - uint64_t Offset) { - return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size, - Offset); -} + ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { + return eStrataUnknown; + } -ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp, - DataBufferSP data_sp, - lldb::offset_t data_offset, - const FileSpec *file, - lldb::offset_t file_offset, - lldb::offset_t length) - : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset) { - if (file) - m_file = *file; -} + lldb::WritableDataBufferSP ObjectFileXCOFF::MapFileDataWritable( + const FileSpec &file, uint64_t Size, uint64_t Offset) { + return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size, + Offset); + } + + ObjectFileXCOFF::ObjectFileXCOFF( + const lldb::ModuleSP &module_sp, DataBufferSP data_sp, + lldb::offset_t data_offset, const FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length) + : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset) { + if (file) + m_file = *file; + } -ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp, - DataBufferSP header_data_sp, - const lldb::ProcessSP &process_sp, - addr_t header_addr) - : ObjectFile(module_sp, process_sp, header_addr, header_data_sp) {} + ObjectFileXCOFF::ObjectFileXCOFF( + const lldb::ModuleSP &module_sp, DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, addr_t header_addr) + : ObjectFile(module_sp, process_sp, header_addr, header_data_sp) {} >From 9c06cd5204c3a78a74947fd8c18c741d701e5d8d Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Fri, 14 Mar 2025 06:15:58 -0500 Subject: [PATCH 2/6] format fix --- .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index 0dd9126468923..eebf6a3a657a5 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -267,48 +267,48 @@ void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) { } } } - void ObjectFileXCOFF::Dump(Stream * s) {} +void ObjectFileXCOFF::Dump(Stream *s) {} - ArchSpec ObjectFileXCOFF::GetArchitecture() { - ArchSpec arch_spec = - ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); - return arch_spec; - } +ArchSpec ObjectFileXCOFF::GetArchitecture() { + ArchSpec arch_spec = + ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + return arch_spec; +} - UUID ObjectFileXCOFF::GetUUID() { return UUID(); } +UUID ObjectFileXCOFF::GetUUID() { return UUID(); } - uint32_t ObjectFileXCOFF::GetDependentModules(FileSpecList & files) { - return 0; - } +uint32_t ObjectFileXCOFF::GetDependentModules(FileSpecList &files) { return 0; } - ObjectFile::Type ObjectFileXCOFF::CalculateType() { - if (m_binary->fileHeader64()->Flags & XCOFF::F_EXEC) - return eTypeExecutable; - else if (m_binary->fileHeader64()->Flags & XCOFF::F_SHROBJ) - return eTypeSharedLibrary; - return eTypeUnknown; - } +ObjectFile::Type ObjectFileXCOFF::CalculateType() { + if (m_binary->fileHeader64()->Flags & XCOFF::F_EXEC) + return eTypeExecutable; + else if (m_binary->fileHeader64()->Flags & XCOFF::F_SHROBJ) + return eTypeSharedLibrary; + return eTypeUnknown; +} - ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { - return eStrataUnknown; - } +ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { return eStrataUnknown; } - lldb::WritableDataBufferSP ObjectFileXCOFF::MapFileDataWritable( - const FileSpec &file, uint64_t Size, uint64_t Offset) { - return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size, - Offset); - } +lldb::WritableDataBufferSP +ObjectFileXCOFF::MapFileDataWritable(const FileSpec &file, uint64_t Size, + uint64_t Offset) { + return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size, + Offset); +} - ObjectFileXCOFF::ObjectFileXCOFF( - const lldb::ModuleSP &module_sp, DataBufferSP data_sp, - lldb::offset_t data_offset, const FileSpec *file, - lldb::offset_t file_offset, lldb::offset_t length) - : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset) { - if (file) - m_file = *file; - } +ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp, + DataBufferSP data_sp, + lldb::offset_t data_offset, + const FileSpec *file, + lldb::offset_t file_offset, + lldb::offset_t length) + : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset) { + if (file) + m_file = *file; +} - ObjectFileXCOFF::ObjectFileXCOFF( - const lldb::ModuleSP &module_sp, DataBufferSP header_data_sp, - const lldb::ProcessSP &process_sp, addr_t header_addr) - : ObjectFile(module_sp, process_sp, header_addr, header_data_sp) {} +ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp, + DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, + addr_t header_addr) + : ObjectFile(module_sp, process_sp, header_addr, header_data_sp) {} >From edb54c3ff6a63c97b4c1d46b046abde981109f40 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Thu, 3 Apr 2025 01:56:56 -0500 Subject: [PATCH 3/6] Test case modification --- lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 5 +++-- lldb/test/Shell/ObjectFile/XCOFF/basic-info.yaml | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index eebf6a3a657a5..179b26df612a0 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -200,6 +200,7 @@ void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) { std::lock_guard guard(module_sp->GetMutex()); ModuleSP module_sp(GetModule()); + int idx = 0; for (auto sIdx = m_binary->section_begin(); sIdx != m_binary->section_end(); ++sIdx) { llvm::Expected name = @@ -209,7 +210,7 @@ void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) { } llvm::StringRef sect_name = *name; ConstString const_sect_name(sect_name); - int sect_index = sIdx->getIndex(), idx = 1; + int sect_index = sIdx->getIndex(); llvm::Expected section = m_binary->getSectionByNum(sect_index); if (!section) { @@ -241,7 +242,7 @@ void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) { SectionSP section_sp(new Section( module_sp, // Module to which this section belongs this, // Object file to which this section belongs - idx++, // Section ID is the 1 based section index. + ++idx, // Section ID is the 1 based section index. const_sect_name, // Name of this section section_type, sectionPtr->VirtualAddress, // File VM address == addresses as diff --git a/lldb/test/Shell/ObjectFile/XCOFF/basic-info.yaml b/lldb/test/Shell/ObjectFile/XCOFF/basic-info.yaml index 3c0037db36dbb..e5cc9d0bc5063 100644 --- a/lldb/test/Shell/ObjectFile/XCOFF/basic-info.yaml +++ b/lldb/test/Shell/ObjectFile/XCOFF/basic-info.yaml @@ -7,6 +7,9 @@ # CHECK: Stripped: false # CHECK: Type: executable # CHECK: Strata: unknown +# CHECK: Name: .text +# CHECK-NEXT: code +# CHECK-NEXT: r-x --- !XCOFF FileHeader: >From a480048b60c4bf8510fdd28821d4d8146515bf61 Mon Sep 17 00:00:00 2001 From: DhruvSrivastavaX Date: Thu, 8 May 2025 03:51:32 -0500 Subject: [PATCH 4/6] Modified to sections64 and test case --- .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 116 +++++++----------- .../Shell/ObjectFile/XCOFF/basic-info.yaml | 86 ++++++++++++- 2 files changed, 128 insertions(+), 74 deletions(-) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index 179b26df612a0..59156bda948c6 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -191,83 +191,59 @@ void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) {} bool ObjectFileXCOFF::IsStripped() { return false; } void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) { - if (m_sections_up) return; + m_sections_up = std::make_unique(); ModuleSP module_sp(GetModule()); - if (module_sp) { - std::lock_guard guard(module_sp->GetMutex()); - - ModuleSP module_sp(GetModule()); - int idx = 0; - for (auto sIdx = m_binary->section_begin(); sIdx != m_binary->section_end(); - ++sIdx) { - llvm::Expected name = - m_binary->getSectionName(sIdx->getRawDataRefImpl()); - if (!name) { - llvm::Error err = name.takeError(); - } - llvm::StringRef sect_name = *name; - ConstString const_sect_name(sect_name); - int sect_index = sIdx->getIndex(); - llvm::Expected section = - m_binary->getSectionByNum(sect_index); - if (!section) { - llvm::Error err = section.takeError(); - } - llvm::object::DataRefImpl dataref = section.get(); - const llvm::object::XCOFFSectionHeader64 *sectionPtr = - reinterpret_cast( - dataref.p); - - SectionType section_type = lldb::eSectionTypeOther; - if (sectionPtr->Flags & XCOFF::STYP_TEXT) - section_type = eSectionTypeCode; - if (sectionPtr->Flags & XCOFF::STYP_DATA) - section_type = eSectionTypeData; - if (sectionPtr->Flags & XCOFF::STYP_BSS) - section_type = eSectionTypeZeroFill; - if (sectionPtr->Flags & XCOFF::STYP_DWARF) { - SectionType section_type = - llvm::StringSwitch(sect_name) - .Case(".dwinfo", eSectionTypeDWARFDebugInfo) - .Case(".dwline", eSectionTypeDWARFDebugLine) - .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev) - .Default(eSectionTypeInvalid); - - if (section_type == eSectionTypeInvalid) - section_type = lldb::eSectionTypeOther; - } - SectionSP section_sp(new Section( - module_sp, // Module to which this section belongs - this, // Object file to which this section belongs - ++idx, // Section ID is the 1 based section index. - const_sect_name, // Name of this section - section_type, - sectionPtr->VirtualAddress, // File VM address == addresses as - // they are found in the object file - sectionPtr->SectionSize, // VM size in bytes of this section - sectionPtr->FileOffsetToRawData, // Offset to the data for this - // section in the file - sectionPtr->SectionSize, // Size in bytes of this section as found in - // the file - 0, // FIXME: alignment - sectionPtr->Flags)); // Flags for this section - - uint32_t permissions = 0; - permissions |= ePermissionsReadable; - if (sectionPtr->Flags & (XCOFF::STYP_DATA | XCOFF::STYP_BSS)) - permissions |= ePermissionsWritable; - if (sectionPtr->Flags & XCOFF::STYP_TEXT) - permissions |= ePermissionsExecutable; - section_sp->SetPermissions(permissions); - - m_sections_up->AddSection(section_sp); - unified_section_list.AddSection(section_sp); + + if (!module_sp) + return; + + std::lock_guard guard(module_sp->GetMutex()); + + const auto §ions = m_binary->sections64(); + int idx = 0; + for (size_t i = 0; i < sections.size(); ++i) { + const llvm::object::XCOFFSectionHeader64 §ion = sections[i]; + + ConstString const_sect_name(section.Name); + + SectionType section_type = lldb::eSectionTypeOther; + if (section.Flags & XCOFF::STYP_TEXT) + section_type = eSectionTypeCode; + else if (section.Flags & XCOFF::STYP_DATA) + section_type = eSectionTypeData; + else if (section.Flags & XCOFF::STYP_BSS) + section_type = eSectionTypeZeroFill; + else if (section.Flags & XCOFF::STYP_DWARF) { + section_type = llvm::StringSwitch(section.Name) + .Case(".dwinfo", eSectionTypeDWARFDebugInfo) + .Case(".dwline", eSectionTypeDWARFDebugLine) + .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev) + .Default(eSectionTypeInvalid); + + if (section_type == eSectionTypeInvalid) + section_type = lldb::eSectionTypeOther; } + + SectionSP section_sp(new Section( + module_sp, this, ++idx, const_sect_name, section_type, + section.VirtualAddress, section.SectionSize, + section.FileOffsetToRawData, section.SectionSize, 0, section.Flags)); + + uint32_t permissions = ePermissionsReadable; + if (section.Flags & (XCOFF::STYP_DATA | XCOFF::STYP_BSS)) + permissions |= ePermissionsWritable; + if (section.Flags & XCOFF::STYP_TEXT) + permissions |= ePermissionsExecutable; + + section_sp->SetPermissions(permissions); + m_sections_up->AddSection(section_sp); + unified_section_list.AddSection(section_sp); } } + void ObjectFileXCOFF::Dump(Stream *s) {} ArchSpec ObjectFileXCOFF::GetArchitecture() { diff --git a/lldb/test/Shell/ObjectFile/XCOFF/basic-info.yaml b/lldb/test/Shell/ObjectFile/XCOFF/basic-info.yaml index e5cc9d0bc5063..17ff2f31c2fff 100644 --- a/lldb/test/Shell/ObjectFile/XCOFF/basic-info.yaml +++ b/lldb/test/Shell/ObjectFile/XCOFF/basic-info.yaml @@ -8,13 +8,31 @@ # CHECK: Type: executable # CHECK: Strata: unknown # CHECK: Name: .text -# CHECK-NEXT: code -# CHECK-NEXT: r-x +# CHECK-NEXT: Type: code +# CHECK-NEXT: Permissions: r-x +# CHECK: Name: .data +# CHECK-NEXT: Type: data +# CHECK-NEXT: Permissions: rw- +# CHECK: Name: .bss +# CHECK-NEXT: Type: zero-fill +# CHECK-NEXT: Permissions: rw- +# CHECK: Name: .loader +# CHECK-NEXT: Type: regular +# CHECK-NEXT: Permissions: r-- +# CHECK: Name: .dwline +# CHECK-NEXT: Type: dwarf-line +# CHECK-NEXT: Permissions: r-- +# CHECK: Name: .dwinfo +# CHECK-NEXT: Type: dwarf-info +# CHECK-NEXT: Permissions: r-- +# CHECK: Name: .dwabrev +# CHECK-NEXT: Type: dwarf-abbrev +# CHECK-NEXT: Permissions: r-- --- !XCOFF FileHeader: MagicNumber: 0x1F7 - NumberOfSections: 1 + NumberOfSections: 7 CreationTime: 000000000 Flags: 0x0002 Sections: @@ -25,6 +43,66 @@ Sections: FileOffsetToLineNumbers: 0x0 NumberOfLineNumbers: 0x0 Flags: [ STYP_TEXT ] - SectionData: E8C20000E94204 + SectionData: E8C20000 + - Name: .data + Address: 0x1100008D2 + Size: 0x2AE + FileOffsetToData: 0x8D2 + FileOffsetToRelocations: 0x132E + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x22 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_DATA ] + SectionData: '' + - Name: .bss + Address: 0x110000B80 + Size: 0x28 + FileOffsetToData: 0x0 + FileOffsetToRelocations: 0x0 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x0 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_BSS ] + SectionData: '' + - Name: .loader + Address: 0x0 + Size: 0x413 + FileOffsetToData: 0xB80 + FileOffsetToRelocations: 0x0 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x0 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_LOADER ] + SectionData: 00000001 + - Name: .dwline + Address: 0x0 + Size: 0x9C + FileOffsetToData: 0xF94 + FileOffsetToRelocations: 0x150A + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x5 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_DWARF ] + SectionData: FFFFFFFF + - Name: .dwinfo + Address: 0x0 + Size: 0xDD + FileOffsetToData: 0x1030 + FileOffsetToRelocations: 0x1550 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x6 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_DWARF ] + SectionData: FFFFFFFF + - Name: .dwabrev + Address: 0x0 + Size: 0x43 + FileOffsetToData: 0x110E + FileOffsetToRelocations: 0x0 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x0 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_DWARF ] + SectionData: 01110125 StringTable: {} ... >From 92b3acad3c9dc73a68f597d5df3144b7e7fc77f6 Mon Sep 17 00:00:00 2001 From: DhruvSrivastavaX Date: Mon, 12 May 2025 05:53:56 -0500 Subject: [PATCH 5/6] Addressred comments --- lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index 59156bda948c6..3bfd177efb10b 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -202,10 +202,8 @@ void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) { std::lock_guard guard(module_sp->GetMutex()); - const auto §ions = m_binary->sections64(); int idx = 0; - for (size_t i = 0; i < sections.size(); ++i) { - const llvm::object::XCOFFSectionHeader64 §ion = sections[i]; + for (const llvm::object::XCOFFSectionHeader64 §ion : m_binary->sections64()) { ConstString const_sect_name(section.Name); @@ -222,9 +220,6 @@ void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) { .Case(".dwline", eSectionTypeDWARFDebugLine) .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev) .Default(eSectionTypeInvalid); - - if (section_type == eSectionTypeInvalid) - section_type = lldb::eSectionTypeOther; } SectionSP section_sp(new Section( >From a530a696652aaff71d0d84b18a980ae6206472c3 Mon Sep 17 00:00:00 2001 From: DhruvSrivastavaX Date: Mon, 12 May 2025 05:59:51 -0500 Subject: [PATCH 6/6] Addressred comments --- lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index 3bfd177efb10b..1666677c360ba 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -203,7 +203,8 @@ void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) { std::lock_guard guard(module_sp->GetMutex()); int idx = 0; - for (const llvm::object::XCOFFSectionHeader64 §ion : m_binary->sections64()) { + for (const llvm::object::XCOFFSectionHeader64 §ion : + m_binary->sections64()) { ConstString const_sect_name(section.Name); From lldb-commits at lists.llvm.org Mon May 12 04:47:02 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 04:47:02 -0700 (PDT) Subject: [Lldb-commits] [lldb] 3aacd74 - [lldb][TypeSystemClang] Allow arrays to be dereferenced in C/C++. (#135843) Message-ID: <6821dfb6.170a0220.9d76a.9a1c@mx.google.com> Author: Ilia Kuklin Date: 2025-05-12T16:46:58+05:00 New Revision: 3aacd74594b1f8ab04904d277b6a106c98904b29 URL: https://github.com/llvm/llvm-project/commit/3aacd74594b1f8ab04904d277b6a106c98904b29 DIFF: https://github.com/llvm/llvm-project/commit/3aacd74594b1f8ab04904d277b6a106c98904b29.diff LOG: [lldb][TypeSystemClang] Allow arrays to be dereferenced in C/C++. (#135843) Add a function `GetDereferencedType` to `CompilerType` and allow `TypeSystemClang` to dereference arrays. Added: Modified: lldb/include/lldb/Symbol/CompilerType.h lldb/include/lldb/Symbol/TypeSystem.h lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h lldb/source/Symbol/CompilerType.cpp lldb/source/ValueObject/ValueObject.cpp lldb/test/API/commands/frame/var-dil/basics/PointerArithmetic/TestFrameVarDILPointerArithmetic.py lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py Removed: ################################################################################ diff --git a/lldb/include/lldb/Symbol/CompilerType.h b/lldb/include/lldb/Symbol/CompilerType.h index fdbc2057ac10f..b8badfda92cf3 100644 --- a/lldb/include/lldb/Symbol/CompilerType.h +++ b/lldb/include/lldb/Symbol/CompilerType.h @@ -433,6 +433,11 @@ class CompilerType { CompilerDecl GetStaticFieldWithName(llvm::StringRef name) const; + llvm::Expected + GetDereferencedType(ExecutionContext *exe_ctx, std::string &deref_name, + uint32_t &deref_byte_size, int32_t &deref_byte_offset, + ValueObject *valobj, uint64_t &language_flags) const; + llvm::Expected GetChildCompilerTypeAtIndex( ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers, bool omit_empty_base_classes, bool ignore_array_bounds, diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h index df87fea32b72a..1f1a3ac4bc56b 100644 --- a/lldb/include/lldb/Symbol/TypeSystem.h +++ b/lldb/include/lldb/Symbol/TypeSystem.h @@ -364,6 +364,12 @@ class TypeSystem : public PluginInterface, return CompilerDecl(); } + virtual llvm::Expected + GetDereferencedType(lldb::opaque_compiler_type_t type, + ExecutionContext *exe_ctx, std::string &deref_name, + uint32_t &deref_byte_size, int32_t &deref_byte_offset, + ValueObject *valobj, uint64_t &language_flags) = 0; + virtual llvm::Expected GetChildCompilerTypeAtIndex( lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers, bool omit_empty_base_classes, diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 3b286885cc37f..d24f3726b1d25 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -6184,6 +6184,24 @@ uint32_t TypeSystemClang::GetNumPointeeChildren(clang::QualType type) { return 0; } +llvm::Expected TypeSystemClang::GetDereferencedType( + lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, + std::string &deref_name, uint32_t &deref_byte_size, + int32_t &deref_byte_offset, ValueObject *valobj, uint64_t &language_flags) { + bool type_valid = IsPointerOrReferenceType(type, nullptr) || + IsArrayType(type, nullptr, nullptr, nullptr); + if (!type_valid) + return llvm::createStringError("not a pointer, reference or array type"); + uint32_t child_bitfield_bit_size = 0; + uint32_t child_bitfield_bit_offset = 0; + bool child_is_base_class; + bool child_is_deref_of_parent; + return GetChildCompilerTypeAtIndex( + type, exe_ctx, 0, false, true, false, deref_name, deref_byte_size, + deref_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, + child_is_base_class, child_is_deref_of_parent, valobj, language_flags); +} + llvm::Expected TypeSystemClang::GetChildCompilerTypeAtIndex( lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers, bool omit_empty_base_classes, diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 93933846d114d..f918cb017f51b 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -889,6 +889,12 @@ class TypeSystemClang : public TypeSystem { static uint32_t GetNumPointeeChildren(clang::QualType type); + llvm::Expected + GetDereferencedType(lldb::opaque_compiler_type_t type, + ExecutionContext *exe_ctx, std::string &deref_name, + uint32_t &deref_byte_size, int32_t &deref_byte_offset, + ValueObject *valobj, uint64_t &language_flags) override; + llvm::Expected GetChildCompilerTypeAtIndex( lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers, bool omit_empty_base_classes, diff --git a/lldb/source/Symbol/CompilerType.cpp b/lldb/source/Symbol/CompilerType.cpp index 90c4dbf0c6206..dd81fc2361f88 100644 --- a/lldb/source/Symbol/CompilerType.cpp +++ b/lldb/source/Symbol/CompilerType.cpp @@ -893,6 +893,18 @@ CompilerDecl CompilerType::GetStaticFieldWithName(llvm::StringRef name) const { return CompilerDecl(); } +llvm::Expected CompilerType::GetDereferencedType( + ExecutionContext *exe_ctx, std::string &deref_name, + uint32_t &deref_byte_size, int32_t &deref_byte_offset, ValueObject *valobj, + uint64_t &language_flags) const { + if (IsValid()) + if (auto type_system_sp = GetTypeSystem()) + return type_system_sp->GetDereferencedType( + m_type, exe_ctx, deref_name, deref_byte_size, deref_byte_offset, + valobj, language_flags); + return CompilerType(); +} + llvm::Expected CompilerType::GetChildCompilerTypeAtIndex( ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers, bool omit_empty_base_classes, bool ignore_array_bounds, diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp index e1c66763ff0b8..6f0fe9a5b83f9 100644 --- a/lldb/source/ValueObject/ValueObject.cpp +++ b/lldb/source/ValueObject/ValueObject.cpp @@ -2794,74 +2794,60 @@ ValueObjectSP ValueObject::Dereference(Status &error) { if (m_deref_valobj) return m_deref_valobj->GetSP(); - const bool is_pointer_or_reference_type = IsPointerOrReferenceType(); - if (is_pointer_or_reference_type) { - bool omit_empty_base_classes = true; - bool ignore_array_bounds = false; - - std::string child_name_str; - 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; - bool child_is_base_class = false; - bool child_is_deref_of_parent = false; - const bool transparent_pointers = false; - CompilerType compiler_type = GetCompilerType(); - uint64_t language_flags = 0; + std::string deref_name_str; + uint32_t deref_byte_size = 0; + int32_t deref_byte_offset = 0; + CompilerType compiler_type = GetCompilerType(); + uint64_t language_flags = 0; - ExecutionContext exe_ctx(GetExecutionContextRef()); + ExecutionContext exe_ctx(GetExecutionContextRef()); - CompilerType child_compiler_type; - auto child_compiler_type_or_err = compiler_type.GetChildCompilerTypeAtIndex( - &exe_ctx, 0, transparent_pointers, omit_empty_base_classes, - ignore_array_bounds, child_name_str, child_byte_size, child_byte_offset, - child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class, - child_is_deref_of_parent, this, language_flags); - if (!child_compiler_type_or_err) - LLDB_LOG_ERROR(GetLog(LLDBLog::Types), - child_compiler_type_or_err.takeError(), - "could not find child: {0}"); - else - child_compiler_type = *child_compiler_type_or_err; - - if (child_compiler_type && child_byte_size) { - ConstString child_name; - if (!child_name_str.empty()) - child_name.SetCString(child_name_str.c_str()); - - m_deref_valobj = new ValueObjectChild( - *this, child_compiler_type, 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, eAddressTypeInvalid, - language_flags); + CompilerType deref_compiler_type; + auto deref_compiler_type_or_err = compiler_type.GetDereferencedType( + &exe_ctx, deref_name_str, deref_byte_size, deref_byte_offset, this, + language_flags); + + std::string deref_error; + if (deref_compiler_type_or_err) { + deref_compiler_type = *deref_compiler_type_or_err; + if (deref_compiler_type && deref_byte_size) { + ConstString deref_name; + if (!deref_name_str.empty()) + deref_name.SetCString(deref_name_str.c_str()); + + m_deref_valobj = + new ValueObjectChild(*this, deref_compiler_type, deref_name, + deref_byte_size, deref_byte_offset, 0, 0, false, + true, eAddressTypeInvalid, language_flags); } - // In case of incomplete child compiler type, use the pointee type and try + // In case of incomplete deref compiler type, use the pointee type and try // to recreate a new ValueObjectChild using it. if (!m_deref_valobj) { // FIXME(#59012): C++ stdlib formatters break with incomplete types (e.g. // `std::vector &`). Remove ObjC restriction once that's resolved. if (Language::LanguageIsObjC(GetPreferredDisplayLanguage()) && HasSyntheticValue()) { - child_compiler_type = compiler_type.GetPointeeType(); + deref_compiler_type = compiler_type.GetPointeeType(); - if (child_compiler_type) { - ConstString child_name; - if (!child_name_str.empty()) - child_name.SetCString(child_name_str.c_str()); + if (deref_compiler_type) { + ConstString deref_name; + if (!deref_name_str.empty()) + deref_name.SetCString(deref_name_str.c_str()); m_deref_valobj = new ValueObjectChild( - *this, child_compiler_type, 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, eAddressTypeInvalid, language_flags); + *this, deref_compiler_type, deref_name, deref_byte_size, + deref_byte_offset, 0, 0, false, true, eAddressTypeInvalid, + language_flags); } } } - - } else if (IsSynthetic()) { - m_deref_valobj = GetChildMemberWithName("$$dereference$$").get(); + } else { + deref_error = llvm::toString(deref_compiler_type_or_err.takeError()); + LLDB_LOG(GetLog(LLDBLog::Types), "could not find child: {0}", deref_error); + if (IsSynthetic()) { + m_deref_valobj = GetChildMemberWithName("$$dereference$$").get(); + } } if (m_deref_valobj) { @@ -2871,13 +2857,13 @@ ValueObjectSP ValueObject::Dereference(Status &error) { StreamString strm; GetExpressionPath(strm); - if (is_pointer_or_reference_type) + if (deref_error.empty()) error = Status::FromErrorStringWithFormat( "dereference failed: (%s) %s", GetTypeName().AsCString(""), strm.GetData()); else error = Status::FromErrorStringWithFormat( - "not a pointer or reference type: (%s) %s", + "dereference failed: %s: (%s) %s", deref_error.c_str(), GetTypeName().AsCString(""), strm.GetData()); return ValueObjectSP(); } diff --git a/lldb/test/API/commands/frame/var-dil/basics/PointerArithmetic/TestFrameVarDILPointerArithmetic.py b/lldb/test/API/commands/frame/var-dil/basics/PointerArithmetic/TestFrameVarDILPointerArithmetic.py index d36c5fce6d43d..6753f988c4187 100644 --- a/lldb/test/API/commands/frame/var-dil/basics/PointerArithmetic/TestFrameVarDILPointerArithmetic.py +++ b/lldb/test/API/commands/frame/var-dil/basics/PointerArithmetic/TestFrameVarDILPointerArithmetic.py @@ -33,11 +33,7 @@ def test_dereference(self): self.expect_var_path("*offset_pref", True, type="int *") self.expect_var_path("**pp_int0", value="0") self.expect_var_path("&**pp_int0", type="int *") - self.expect( - "frame var '*array'", - error=True, - substrs=["not a pointer or reference type"], - ) + self.expect_var_path("*array", value="0") self.expect( "frame var '&*p_null'", error=True, diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py index 7dc656a7ae225..99d79a9f125b1 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py @@ -88,7 +88,7 @@ def cleanup(): self.expect( "frame variable *number_not_engaged", error=True, - substrs=["not a pointer or reference type"], + substrs=["dereference failed: not a pointer, reference or array type"], ) @add_test_categories(["libc++"]) From lldb-commits at lists.llvm.org Mon May 12 04:47:06 2025 From: lldb-commits at lists.llvm.org (Ilia Kuklin via lldb-commits) Date: Mon, 12 May 2025 04:47:06 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][TypeSystemClang] Allow arrays to be dereferenced in C/C++. (PR #135843) In-Reply-To: Message-ID: <6821dfba.170a0220.3916d7.c656@mx.google.com> https://github.com/kuilpd closed https://github.com/llvm/llvm-project/pull/135843 From lldb-commits at lists.llvm.org Mon May 12 04:48:56 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Mon, 12 May 2025 04:48:56 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit tests for protocol types (PR #139502) In-Reply-To: Message-ID: <6821e028.170a0220.1159b6.89d1@mx.google.com> da-viper wrote: LGTM. tiny nit for concrete types https://github.com/llvm/llvm-project/pull/139502 From lldb-commits at lists.llvm.org Mon May 12 04:49:04 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Mon, 12 May 2025 04:49:04 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit tests for protocol types (PR #139502) In-Reply-To: Message-ID: <6821e030.630a0220.1ed459.2f6b@mx.google.com> https://github.com/da-viper approved this pull request. https://github.com/llvm/llvm-project/pull/139502 From lldb-commits at lists.llvm.org Mon May 12 04:55:22 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Mon, 12 May 2025 04:55:22 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Adding NativeThreadAIX (PR #139537) Message-ID: https://github.com/DhruvSrivastavaX created https://github.com/llvm/llvm-project/pull/139537 This PR is in reference to porting LLDB on AIX. Link to discussions on llvm discourse and github: 1. https://discourse.llvm.org/t/port-lldb-to-ibm-aix/80640 2. https://github.com/llvm/llvm-project/issues/101657 The complete changes for porting are present in this draft PR: https://github.com/llvm/llvm-project/pull/102601 **Description:** Adding NativeThreadAIX base files, along with the implementation of GetName() for AIX, to be integrated with already merged NativeProcessAIX. >From 05aef7d40097d9a554c648fa2be75530f23ca05c Mon Sep 17 00:00:00 2001 From: DhruvSrivastavaX Date: Mon, 12 May 2025 03:23:49 -0500 Subject: [PATCH] Added NativeThreadAIX --- .../source/Plugins/Process/AIX/CMakeLists.txt | 1 + .../Plugins/Process/AIX/NativeThreadAIX.cpp | 71 +++++++++++++++++++ .../Plugins/Process/AIX/NativeThreadAIX.h | 53 ++++++++++++++ 3 files changed, 125 insertions(+) create mode 100644 lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeThreadAIX.h diff --git a/lldb/source/Plugins/Process/AIX/CMakeLists.txt b/lldb/source/Plugins/Process/AIX/CMakeLists.txt index 9a3c77bd2ffeb..911f30349ef52 100644 --- a/lldb/source/Plugins/Process/AIX/CMakeLists.txt +++ b/lldb/source/Plugins/Process/AIX/CMakeLists.txt @@ -1,5 +1,6 @@ add_lldb_library(lldbPluginProcessAIX NativeProcessAIX.cpp + NativeThreadAIX.cpp LINK_LIBS lldbCore diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp new file mode 100644 index 0000000000000..c9593fbf08441 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp @@ -0,0 +1,71 @@ +//===-- NativeThreadAIX.cpp ---------------------------------------------===// +// +// 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 "NativeThreadAIX.h" +#include "NativeProcessAIX.h" +#include "lldb/Utility/State.h" +#include +#include + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; + +NativeThreadAIX::NativeThreadAIX(NativeProcessAIX &process, lldb::tid_t tid) + : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid) {} + +std::string NativeThreadAIX::GetName() { + NativeProcessAIX &process = GetProcess(); + auto BufferOrError = getProcFile(process.GetID(), "psinfo"); + if (!BufferOrError) + return ""; + auto &Buffer = *BufferOrError; + if (Buffer->getBufferSize() < sizeof(psinfo_t)) + return ""; + const psinfo_t *psinfo = + reinterpret_cast(Buffer->getBufferStart()); + return std::string(psinfo->pr_fname); +} + +lldb::StateType NativeThreadAIX::GetState() { return m_state; } + +bool NativeThreadAIX::GetStopReason(ThreadStopInfo &stop_info, + std::string &description) { + return false; +} + +Status NativeThreadAIX::SetWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags, bool hardware) { + return Status(); +} + +Status NativeThreadAIX::RemoveWatchpoint(lldb::addr_t addr) { + return Status("Clearing hardware watchpoint failed."); +} + +Status NativeThreadAIX::SetHardwareBreakpoint(lldb::addr_t addr, size_t size) { + return Status(); +} + +Status NativeThreadAIX::RemoveHardwareBreakpoint(lldb::addr_t addr) { + return Status("Clearing hardware breakpoint failed."); +} + +NativeProcessAIX &NativeThreadAIX::GetProcess() { + return static_cast(m_process); +} + +const NativeProcessAIX &NativeThreadAIX::GetProcess() const { + return static_cast(m_process); +} + +llvm::Expected> +NativeThreadAIX::GetSiginfo() const { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Not implemented"); +} diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h new file mode 100644 index 0000000000000..e32d3db2c5fa2 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h @@ -0,0 +1,53 @@ +//===-- NativeThreadAIX.h ----------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_NATIVETHREADAIX_H_ +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_NATIVETHREADAIX_H_ + +#include "lldb/Host/common/NativeThreadProtocol.h" + +namespace lldb_private::process_aix { + +class NativeProcessAIX; + +class NativeThreadAIX : public NativeThreadProtocol { + friend class NativeProcessAIX; + +public: + NativeThreadAIX(NativeProcessAIX &process, lldb::tid_t tid); + + // NativeThreadProtocol Interface + std::string GetName() override; + + lldb::StateType GetState() override; + + bool GetStopReason(ThreadStopInfo &stop_info, + std::string &description) override; + + Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, + bool hardware) override; + + Status RemoveWatchpoint(lldb::addr_t addr) override; + + Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override; + + Status RemoveHardwareBreakpoint(lldb::addr_t addr) override; + + NativeProcessAIX &GetProcess(); + + const NativeProcessAIX &GetProcess() const; + + llvm::Expected> + GetSiginfo() const override; + +private: + lldb::StateType m_state; +}; +} // namespace lldb_private::process_aix + +#endif // #ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_NATIVETHREADAIX_H_ From lldb-commits at lists.llvm.org Mon May 12 04:55:54 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 04:55:54 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Adding NativeThreadAIX (PR #139537) In-Reply-To: Message-ID: <6821e1ca.170a0220.1673cb.9815@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Dhruv Srivastava (DhruvSrivastavaX)
Changes This PR is in reference to porting LLDB on AIX. Link to discussions on llvm discourse and github: 1. https://discourse.llvm.org/t/port-lldb-to-ibm-aix/80640 2. https://github.com/llvm/llvm-project/issues/101657 The complete changes for porting are present in this draft PR: https://github.com/llvm/llvm-project/pull/102601 **Description:** Adding NativeThreadAIX base files, along with the implementation of GetName() for AIX, to be integrated with already merged NativeProcessAIX. --- Full diff: https://github.com/llvm/llvm-project/pull/139537.diff 3 Files Affected: - (modified) lldb/source/Plugins/Process/AIX/CMakeLists.txt (+1) - (added) lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp (+71) - (added) lldb/source/Plugins/Process/AIX/NativeThreadAIX.h (+53) ``````````diff diff --git a/lldb/source/Plugins/Process/AIX/CMakeLists.txt b/lldb/source/Plugins/Process/AIX/CMakeLists.txt index 9a3c77bd2ffeb..911f30349ef52 100644 --- a/lldb/source/Plugins/Process/AIX/CMakeLists.txt +++ b/lldb/source/Plugins/Process/AIX/CMakeLists.txt @@ -1,5 +1,6 @@ add_lldb_library(lldbPluginProcessAIX NativeProcessAIX.cpp + NativeThreadAIX.cpp LINK_LIBS lldbCore diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp new file mode 100644 index 0000000000000..c9593fbf08441 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp @@ -0,0 +1,71 @@ +//===-- NativeThreadAIX.cpp ---------------------------------------------===// +// +// 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 "NativeThreadAIX.h" +#include "NativeProcessAIX.h" +#include "lldb/Utility/State.h" +#include +#include + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; + +NativeThreadAIX::NativeThreadAIX(NativeProcessAIX &process, lldb::tid_t tid) + : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid) {} + +std::string NativeThreadAIX::GetName() { + NativeProcessAIX &process = GetProcess(); + auto BufferOrError = getProcFile(process.GetID(), "psinfo"); + if (!BufferOrError) + return ""; + auto &Buffer = *BufferOrError; + if (Buffer->getBufferSize() < sizeof(psinfo_t)) + return ""; + const psinfo_t *psinfo = + reinterpret_cast(Buffer->getBufferStart()); + return std::string(psinfo->pr_fname); +} + +lldb::StateType NativeThreadAIX::GetState() { return m_state; } + +bool NativeThreadAIX::GetStopReason(ThreadStopInfo &stop_info, + std::string &description) { + return false; +} + +Status NativeThreadAIX::SetWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags, bool hardware) { + return Status(); +} + +Status NativeThreadAIX::RemoveWatchpoint(lldb::addr_t addr) { + return Status("Clearing hardware watchpoint failed."); +} + +Status NativeThreadAIX::SetHardwareBreakpoint(lldb::addr_t addr, size_t size) { + return Status(); +} + +Status NativeThreadAIX::RemoveHardwareBreakpoint(lldb::addr_t addr) { + return Status("Clearing hardware breakpoint failed."); +} + +NativeProcessAIX &NativeThreadAIX::GetProcess() { + return static_cast(m_process); +} + +const NativeProcessAIX &NativeThreadAIX::GetProcess() const { + return static_cast(m_process); +} + +llvm::Expected> +NativeThreadAIX::GetSiginfo() const { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Not implemented"); +} diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h new file mode 100644 index 0000000000000..e32d3db2c5fa2 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h @@ -0,0 +1,53 @@ +//===-- NativeThreadAIX.h ----------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_NATIVETHREADAIX_H_ +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_NATIVETHREADAIX_H_ + +#include "lldb/Host/common/NativeThreadProtocol.h" + +namespace lldb_private::process_aix { + +class NativeProcessAIX; + +class NativeThreadAIX : public NativeThreadProtocol { + friend class NativeProcessAIX; + +public: + NativeThreadAIX(NativeProcessAIX &process, lldb::tid_t tid); + + // NativeThreadProtocol Interface + std::string GetName() override; + + lldb::StateType GetState() override; + + bool GetStopReason(ThreadStopInfo &stop_info, + std::string &description) override; + + Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, + bool hardware) override; + + Status RemoveWatchpoint(lldb::addr_t addr) override; + + Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override; + + Status RemoveHardwareBreakpoint(lldb::addr_t addr) override; + + NativeProcessAIX &GetProcess(); + + const NativeProcessAIX &GetProcess() const; + + llvm::Expected> + GetSiginfo() const override; + +private: + lldb::StateType m_state; +}; +} // namespace lldb_private::process_aix + +#endif // #ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_NATIVETHREADAIX_H_ ``````````
https://github.com/llvm/llvm-project/pull/139537 From lldb-commits at lists.llvm.org Mon May 12 05:22:05 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 05:22:05 -0700 (PDT) Subject: [Lldb-commits] [lldb] 39f5a42 - [lldb][AIX] Support for XCOFF Sections (#131304) Message-ID: <6821e7ed.a70a0220.1b7311.9e9d@mx.google.com> Author: Dhruv Srivastava Date: 2025-05-12T17:52:02+05:30 New Revision: 39f5a420b6801c0cb6035ec77c53154674786a60 URL: https://github.com/llvm/llvm-project/commit/39f5a420b6801c0cb6035ec77c53154674786a60 DIFF: https://github.com/llvm/llvm-project/commit/39f5a420b6801c0cb6035ec77c53154674786a60.diff LOG: [lldb][AIX] Support for XCOFF Sections (#131304) This PR is in reference to porting LLDB on AIX. Link to discussions on llvm discourse and github: 1. https://discourse.llvm.org/t/port-lldb-to-ibm-aix/80640 2. https://github.com/llvm/llvm-project/issues/101657 The complete changes for porting are present in this draft PR: https://github.com/llvm/llvm-project/pull/102601 Incremental PR on ObjectFileXCOFF.cpp This PR is intended to handle XCOFF sections. Added: Modified: lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp lldb/test/Shell/ObjectFile/XCOFF/basic-info.yaml Removed: ################################################################################ diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index b54d43c5dd737..1666677c360ba 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -190,7 +190,55 @@ void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) {} bool ObjectFileXCOFF::IsStripped() { return false; } -void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) {} +void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) { + if (m_sections_up) + return; + + m_sections_up = std::make_unique(); + ModuleSP module_sp(GetModule()); + + if (!module_sp) + return; + + std::lock_guard guard(module_sp->GetMutex()); + + int idx = 0; + for (const llvm::object::XCOFFSectionHeader64 §ion : + m_binary->sections64()) { + + ConstString const_sect_name(section.Name); + + SectionType section_type = lldb::eSectionTypeOther; + if (section.Flags & XCOFF::STYP_TEXT) + section_type = eSectionTypeCode; + else if (section.Flags & XCOFF::STYP_DATA) + section_type = eSectionTypeData; + else if (section.Flags & XCOFF::STYP_BSS) + section_type = eSectionTypeZeroFill; + else if (section.Flags & XCOFF::STYP_DWARF) { + section_type = llvm::StringSwitch(section.Name) + .Case(".dwinfo", eSectionTypeDWARFDebugInfo) + .Case(".dwline", eSectionTypeDWARFDebugLine) + .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev) + .Default(eSectionTypeInvalid); + } + + SectionSP section_sp(new Section( + module_sp, this, ++idx, const_sect_name, section_type, + section.VirtualAddress, section.SectionSize, + section.FileOffsetToRawData, section.SectionSize, 0, section.Flags)); + + uint32_t permissions = ePermissionsReadable; + if (section.Flags & (XCOFF::STYP_DATA | XCOFF::STYP_BSS)) + permissions |= ePermissionsWritable; + if (section.Flags & XCOFF::STYP_TEXT) + permissions |= ePermissionsExecutable; + + section_sp->SetPermissions(permissions); + m_sections_up->AddSection(section_sp); + unified_section_list.AddSection(section_sp); + } +} void ObjectFileXCOFF::Dump(Stream *s) {} diff --git a/lldb/test/Shell/ObjectFile/XCOFF/basic-info.yaml b/lldb/test/Shell/ObjectFile/XCOFF/basic-info.yaml index 3c0037db36dbb..17ff2f31c2fff 100644 --- a/lldb/test/Shell/ObjectFile/XCOFF/basic-info.yaml +++ b/lldb/test/Shell/ObjectFile/XCOFF/basic-info.yaml @@ -7,11 +7,32 @@ # CHECK: Stripped: false # CHECK: Type: executable # CHECK: Strata: unknown +# CHECK: Name: .text +# CHECK-NEXT: Type: code +# CHECK-NEXT: Permissions: r-x +# CHECK: Name: .data +# CHECK-NEXT: Type: data +# CHECK-NEXT: Permissions: rw- +# CHECK: Name: .bss +# CHECK-NEXT: Type: zero-fill +# CHECK-NEXT: Permissions: rw- +# CHECK: Name: .loader +# CHECK-NEXT: Type: regular +# CHECK-NEXT: Permissions: r-- +# CHECK: Name: .dwline +# CHECK-NEXT: Type: dwarf-line +# CHECK-NEXT: Permissions: r-- +# CHECK: Name: .dwinfo +# CHECK-NEXT: Type: dwarf-info +# CHECK-NEXT: Permissions: r-- +# CHECK: Name: .dwabrev +# CHECK-NEXT: Type: dwarf-abbrev +# CHECK-NEXT: Permissions: r-- --- !XCOFF FileHeader: MagicNumber: 0x1F7 - NumberOfSections: 1 + NumberOfSections: 7 CreationTime: 000000000 Flags: 0x0002 Sections: @@ -22,6 +43,66 @@ Sections: FileOffsetToLineNumbers: 0x0 NumberOfLineNumbers: 0x0 Flags: [ STYP_TEXT ] - SectionData: E8C20000E94204 + SectionData: E8C20000 + - Name: .data + Address: 0x1100008D2 + Size: 0x2AE + FileOffsetToData: 0x8D2 + FileOffsetToRelocations: 0x132E + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x22 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_DATA ] + SectionData: '' + - Name: .bss + Address: 0x110000B80 + Size: 0x28 + FileOffsetToData: 0x0 + FileOffsetToRelocations: 0x0 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x0 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_BSS ] + SectionData: '' + - Name: .loader + Address: 0x0 + Size: 0x413 + FileOffsetToData: 0xB80 + FileOffsetToRelocations: 0x0 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x0 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_LOADER ] + SectionData: 00000001 + - Name: .dwline + Address: 0x0 + Size: 0x9C + FileOffsetToData: 0xF94 + FileOffsetToRelocations: 0x150A + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x5 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_DWARF ] + SectionData: FFFFFFFF + - Name: .dwinfo + Address: 0x0 + Size: 0xDD + FileOffsetToData: 0x1030 + FileOffsetToRelocations: 0x1550 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x6 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_DWARF ] + SectionData: FFFFFFFF + - Name: .dwabrev + Address: 0x0 + Size: 0x43 + FileOffsetToData: 0x110E + FileOffsetToRelocations: 0x0 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x0 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_DWARF ] + SectionData: 01110125 StringTable: {} ... From lldb-commits at lists.llvm.org Mon May 12 05:22:10 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Mon, 12 May 2025 05:22:10 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Support for XCOFF Sections (PR #131304) In-Reply-To: Message-ID: <6821e7f2.170a0220.59850.982e@mx.google.com> https://github.com/DhruvSrivastavaX closed https://github.com/llvm/llvm-project/pull/131304 From lldb-commits at lists.llvm.org Mon May 12 05:46:56 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Mon, 12 May 2025 05:46:56 -0700 (PDT) Subject: [Lldb-commits] [lldb] Extending LLDB to work on AIX (PR #102601) In-Reply-To: Message-ID: <6821edc0.a70a0220.5ad31.c5d9@mx.google.com> https://github.com/DhruvSrivastavaX updated https://github.com/llvm/llvm-project/pull/102601 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Mon May 12 06:07:37 2025 From: lldb-commits at lists.llvm.org (Jacques Pienaar via lldb-commits) Date: Mon, 12 May 2025 06:07:37 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][plugin] Clear in same thread as set (PR #139252) In-Reply-To: Message-ID: <6821f299.170a0220.116692.92f8@mx.google.com> jpienaar wrote: I agree a condition variable would work here. I realized this later too (wanted all destroyed at end), one could do that as follows too // In ManualDWARFIndex ... std::vector clear_cu_dies; clear_cu_dies.reserve(units_to_index.size()); for (auto &unit : units_to_index) clear_cu_dies.push_back(*unit); for_each_unit([&clear_cu_dies](size_t, size_t idx, DWARFUnit*) { clear_cu_dies[idx].Extract(); }); ... // in DWARFUnit.cpp void DWARFUnit::ScopedExtractDIEs::Extract() { { llvm::sys::ScopedReader lock(m_cu->m_die_array_mutex); if (!m_cu->m_die_array.empty()) return; // Already parsed } llvm::sys::ScopedWriter lock(m_cu->m_die_array_mutex); if (!m_cu->m_die_array.empty()) return; // Already parsed // Otherwise m_die_array would be already populated. lldbassert(!m_cu->m_cancel_scopes); m_cu->ExtractDIEsRWLocked(); m_clear_dies = true; } DWARFUnit::ScopedExtractDIEs DWARFUnit::ExtractDIEsScoped() { ScopedExtractDIEs scoped(*this); scoped.Extract(); return scoped; } --- But if plain counter preferred, will switch to that. https://github.com/llvm/llvm-project/pull/139252 From lldb-commits at lists.llvm.org Mon May 12 06:19:58 2025 From: lldb-commits at lists.llvm.org (Jacques Pienaar via lldb-commits) Date: Mon, 12 May 2025 06:19:58 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][plugin] Clear in same thread as set (PR #139252) In-Reply-To: Message-ID: <6821f57e.170a0220.fb9ee.1bb2@mx.google.com> https://github.com/jpienaar updated https://github.com/llvm/llvm-project/pull/139252 >From c5ffbd84f8b68bae2112e8cec68803cefe571a72 Mon Sep 17 00:00:00 2001 From: Jacques Pienaar Date: Fri, 9 May 2025 05:23:00 -0700 Subject: [PATCH 1/3] [lldb][plugin] Clear in same thread as set Here we were initializing & locking a mutex in a thread, while releasing it in the parent which may/often turned out to be a different thread (shared_mutex::unlock_shared is undefined behavior if called from a thread that doesn't hold the lock). I'm not quite sure what the expectation is here as the variable is never used, so instead I've just reset in same thread as which it was set to ensure its freed in thread holding lock. --- lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index 523820874752a..0f0226ea9650c 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -121,6 +121,7 @@ void ManualDWARFIndex::Index() { units_to_index.size()); for_each_unit([&clear_cu_dies](size_t, size_t idx, DWARFUnit *unit) { clear_cu_dies[idx] = unit->ExtractDIEsScoped(); + ckear_cu_duex[idx].reset(); }); // Now index all DWARF unit in parallel. >From 5f5b8dc0deae4f63ddb83e0dfab96ab3a9e0cc80 Mon Sep 17 00:00:00 2001 From: Jacques Pienaar Date: Fri, 9 May 2025 08:15:26 -0700 Subject: [PATCH 2/3] Fix typo --- lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index 0f0226ea9650c..6139d005b4f2e 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -121,7 +121,7 @@ void ManualDWARFIndex::Index() { units_to_index.size()); for_each_unit([&clear_cu_dies](size_t, size_t idx, DWARFUnit *unit) { clear_cu_dies[idx] = unit->ExtractDIEsScoped(); - ckear_cu_duex[idx].reset(); + ckear_cu_dies[idx].reset(); }); // Now index all DWARF unit in parallel. >From 6d8c69c480ce214772cb84a27da645b428916ecb Mon Sep 17 00:00:00 2001 From: Jacques Pienaar Date: Mon, 12 May 2025 13:19:45 +0000 Subject: [PATCH 3/3] Use plain reader counter --- lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp | 12 +++++++++--- lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h | 4 +++- .../Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp | 1 - 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index 7d0afc04ac3b6..3a8409b1c3b66 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -189,17 +189,23 @@ DWARFUnit::ScopedExtractDIEs DWARFUnit::ExtractDIEsScoped() { } DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(DWARFUnit &cu) : m_cu(&cu) { - m_cu->m_die_array_scoped_mutex.lock_shared(); + llvm::sys::ScopedLock lock(m_cu->m_die_array_scoped_mutex); + ++m_cu->m_die_array_scoped_count; } DWARFUnit::ScopedExtractDIEs::~ScopedExtractDIEs() { if (!m_cu) return; - m_cu->m_die_array_scoped_mutex.unlock_shared(); + { + llvm::sys::ScopedLock lock(m_cu->m_die_array_scoped_mutex); + --m_cu->m_die_array_scoped_count; + if (m_cu->m_die_array_scoped_count == 0) + return; + } if (!m_clear_dies || m_cu->m_cancel_scopes) return; // Be sure no other ScopedExtractDIEs is running anymore. - llvm::sys::ScopedWriter lock_scoped(m_cu->m_die_array_scoped_mutex); + llvm::sys::ScopedLock lock_scoped(m_cu->m_die_array_scoped_mutex); llvm::sys::ScopedWriter lock(m_cu->m_die_array_mutex); if (m_cu->m_cancel_scopes) return; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index 75a003e0a663c..c05bba36ed74b 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -17,6 +17,7 @@ #include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" #include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h" +#include "llvm/Support/Mutex.h" #include "llvm/Support/RWMutex.h" #include #include @@ -328,7 +329,8 @@ class DWARFUnit : public DWARFExpression::Delegate, public UserID { DWARFDebugInfoEntry::collection m_die_array; mutable llvm::sys::RWMutex m_die_array_mutex; // It is used for tracking of ScopedExtractDIEs instances. - mutable llvm::sys::RWMutex m_die_array_scoped_mutex; + mutable llvm::sys::Mutex m_die_array_scoped_mutex; + mutable int m_die_array_scoped_count = 0; // ScopedExtractDIEs instances should not call ClearDIEsRWLocked() // as someone called ExtractDIEsIfNeeded(). std::atomic m_cancel_scopes; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index 6139d005b4f2e..523820874752a 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -121,7 +121,6 @@ void ManualDWARFIndex::Index() { units_to_index.size()); for_each_unit([&clear_cu_dies](size_t, size_t idx, DWARFUnit *unit) { clear_cu_dies[idx] = unit->ExtractDIEsScoped(); - ckear_cu_dies[idx].reset(); }); // Now index all DWARF unit in parallel. From lldb-commits at lists.llvm.org Mon May 12 06:36:25 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 06:36:25 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Merge/unify ABI-provided AArch64 unwind plans (PR #139545) Message-ID: https://github.com/labath created https://github.com/llvm/llvm-project/pull/139545 The macos and sysv ABIs return functionally equivalent unwind plans, so they can be implemented in the base AArch64 class. The only difference between them was that the macos plan provided a "pc=lr" rule whereas the sysv plan called SetReturnAddressRegister (which causes the unwind machinery to act as if that rule was present). This difference was enough to cause `CompareUnwindPlansForIdenticalInitialPCLocation` to return a different value and break the (temporarily reverted) TestUnwindFramelessFaulted test. While merging the two functions, I couldn't stop myself from simplifying them to use the generic register number schemes -- which exposed another bug in CompareUnwindPlansForIdenticalInitialPCLocation, namely that it was expecting all unwind plans to use the LLDB numbering scheme. This patch fixes that as well. Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Mon May 12 06:37:01 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 06:37:01 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Merge/unify ABI-provided AArch64 unwind plans (PR #139545) In-Reply-To: Message-ID: <6821f97d.050a0220.158753.da2f@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Pavel Labath (labath)
Changes The macos and sysv ABIs return functionally equivalent unwind plans, so they can be implemented in the base AArch64 class. The only difference between them was that the macos plan provided a "pc=lr" rule whereas the sysv plan called SetReturnAddressRegister (which causes the unwind machinery to act as if that rule was present). This difference was enough to cause `CompareUnwindPlansForIdenticalInitialPCLocation` to return a different value and break the (temporarily reverted) TestUnwindFramelessFaulted test. While merging the two functions, I couldn't stop myself from simplifying them to use the generic register number schemes -- which exposed another bug in CompareUnwindPlansForIdenticalInitialPCLocation, namely that it was expecting all unwind plans to use the LLDB numbering scheme. This patch fixes that as well. --- Full diff: https://github.com/llvm/llvm-project/pull/139545.diff 7 Files Affected: - (modified) lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp (+39) - (modified) lldb/source/Plugins/ABI/AArch64/ABIAArch64.h (+3) - (modified) lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp (-45) - (modified) lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h (-4) - (modified) lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp (-44) - (modified) lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h (-4) - (modified) lldb/source/Symbol/FuncUnwinders.cpp (+18-21) ``````````diff diff --git a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp index 7d8d0a4d3d671..58b8459b1806f 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp +++ b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp @@ -19,6 +19,7 @@ #include using namespace lldb; +using namespace lldb_private; LLDB_PLUGIN_DEFINE(ABIAArch64) @@ -200,3 +201,41 @@ void ABIAArch64::AugmentRegisterInfo( lldb::eEncodingIEEE754, lldb::eFormatFloat); } } + +UnwindPlanSP ABIAArch64::CreateFunctionEntryUnwindPlan() { + UnwindPlan::Row row; + + // Our previous Call Frame Address is the stack pointer + row.GetCFAValue().SetIsRegisterPlusOffset(LLDB_REGNUM_GENERIC_SP, 0); + + // Our previous PC is in the LR, all other registers are the same. + row.SetRegisterLocationToRegister(LLDB_REGNUM_GENERIC_PC, LLDB_REGNUM_GENERIC_RA, true); + + auto plan_sp = std::make_shared(eRegisterKindGeneric); + plan_sp->AppendRow(std::move(row)); + plan_sp->SetSourceName("arm64 at-func-entry default"); + plan_sp->SetSourcedFromCompiler(eLazyBoolNo); + plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); + plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo); + return plan_sp; +} + +UnwindPlanSP ABIAArch64::CreateDefaultUnwindPlan() { + UnwindPlan::Row row; + const int32_t ptr_size = 8; + + row.GetCFAValue().SetIsRegisterPlusOffset(LLDB_REGNUM_GENERIC_FP, 2 * ptr_size); + row.SetUnspecifiedRegistersAreUndefined(true); + + row.SetRegisterLocationToAtCFAPlusOffset(LLDB_REGNUM_GENERIC_FP, ptr_size * -2, true); + row.SetRegisterLocationToAtCFAPlusOffset(LLDB_REGNUM_GENERIC_PC, ptr_size * -1, true); + + auto plan_sp = std::make_shared(eRegisterKindGeneric); + plan_sp->AppendRow(std::move(row)); + plan_sp->SetSourceName("arm64 default unwind plan"); + plan_sp->SetSourcedFromCompiler(eLazyBoolNo); + plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); + plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo); + return plan_sp; +} + diff --git a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h index 52e42f1260a83..53702f4da580d 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h +++ b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h @@ -19,6 +19,9 @@ class ABIAArch64 : public lldb_private::MCBasedABI { lldb::addr_t FixCodeAddress(lldb::addr_t pc) override; lldb::addr_t FixDataAddress(lldb::addr_t pc) override; + lldb::UnwindPlanSP CreateFunctionEntryUnwindPlan() override; + lldb::UnwindPlanSP CreateDefaultUnwindPlan() override; + protected: virtual lldb::addr_t FixAddress(lldb::addr_t pc, lldb::addr_t mask) { return pc; diff --git a/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp index f86ab8cbb1195..094e0523a4edf 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp +++ b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp @@ -17,7 +17,6 @@ #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Value.h" -#include "lldb/Symbol/UnwindPlan.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Target.h" @@ -30,8 +29,6 @@ #include "lldb/Utility/Status.h" #include "lldb/ValueObject/ValueObjectConstResult.h" -#include "Utility/ARM64_DWARF_Registers.h" - using namespace lldb; using namespace lldb_private; @@ -344,48 +341,6 @@ ABIMacOSX_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, return error; } -UnwindPlanSP ABIMacOSX_arm64::CreateFunctionEntryUnwindPlan() { - uint32_t lr_reg_num = arm64_dwarf::lr; - uint32_t sp_reg_num = arm64_dwarf::sp; - uint32_t pc_reg_num = arm64_dwarf::pc; - - UnwindPlan::Row row; - - // Our previous Call Frame Address is the stack pointer - row.GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0); - - // Our previous PC is in the LR, all other registers are the same. - row.SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true); - - auto plan_sp = std::make_shared(eRegisterKindDWARF); - plan_sp->AppendRow(std::move(row)); - plan_sp->SetSourceName("arm64 at-func-entry default"); - plan_sp->SetSourcedFromCompiler(eLazyBoolNo); - return plan_sp; -} - -UnwindPlanSP ABIMacOSX_arm64::CreateDefaultUnwindPlan() { - uint32_t fp_reg_num = arm64_dwarf::fp; - uint32_t pc_reg_num = arm64_dwarf::pc; - - UnwindPlan::Row row; - const int32_t ptr_size = 8; - - row.GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size); - row.SetUnspecifiedRegistersAreUndefined(true); - - row.SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); - row.SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); - - auto plan_sp = std::make_shared(eRegisterKindDWARF); - plan_sp->AppendRow(std::move(row)); - plan_sp->SetSourceName("arm64-apple-darwin default unwind plan"); - plan_sp->SetSourcedFromCompiler(eLazyBoolNo); - plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); - plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo); - return plan_sp; -} - // AAPCS64 (Procedure Call Standard for the ARM 64-bit Architecture) says // registers x19 through x28 and sp are callee preserved. v8-v15 are non- // volatile (and specifically only the lower 8 bytes of these regs), the rest diff --git a/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h index 94a60327c6181..c8851709f50ad 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h +++ b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h @@ -27,10 +27,6 @@ class ABIMacOSX_arm64 : public ABIAArch64 { bool GetArgumentValues(lldb_private::Thread &thread, lldb_private::ValueList &values) const override; - lldb::UnwindPlanSP CreateFunctionEntryUnwindPlan() override; - - lldb::UnwindPlanSP CreateDefaultUnwindPlan() override; - bool RegisterIsVolatile(const lldb_private::RegisterInfo *reg_info) override; // The arm64 ABI requires that stack frames be 16 byte aligned. diff --git a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp index 6e07c0982be0e..aa9c20b6bb2cf 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp +++ b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp @@ -30,8 +30,6 @@ #include "lldb/Utility/Status.h" #include "lldb/ValueObject/ValueObjectConstResult.h" -#include "Utility/ARM64_DWARF_Registers.h" - using namespace lldb; using namespace lldb_private; @@ -385,48 +383,6 @@ Status ABISysV_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, return error; } -UnwindPlanSP ABISysV_arm64::CreateFunctionEntryUnwindPlan() { - uint32_t lr_reg_num = arm64_dwarf::lr; - uint32_t sp_reg_num = arm64_dwarf::sp; - - UnwindPlan::Row row; - - // Our previous Call Frame Address is the stack pointer, all other registers - // are the same. - row.GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0); - - auto plan_sp = std::make_shared(eRegisterKindDWARF); - plan_sp->AppendRow(std::move(row)); - plan_sp->SetReturnAddressRegister(lr_reg_num); - plan_sp->SetSourceName("arm64 at-func-entry default"); - plan_sp->SetSourcedFromCompiler(eLazyBoolNo); - plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); - plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo); - return plan_sp; -} - -UnwindPlanSP ABISysV_arm64::CreateDefaultUnwindPlan() { - uint32_t fp_reg_num = arm64_dwarf::fp; - uint32_t pc_reg_num = arm64_dwarf::pc; - - UnwindPlan::Row row; - const int32_t ptr_size = 8; - - row.GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size); - row.SetUnspecifiedRegistersAreUndefined(true); - - row.SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); - row.SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); - - auto plan_sp = std::make_shared(eRegisterKindDWARF); - plan_sp->AppendRow(std::move(row)); - plan_sp->SetSourceName("arm64 default unwind plan"); - plan_sp->SetSourcedFromCompiler(eLazyBoolNo); - plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); - plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo); - return plan_sp; -} - // AAPCS64 (Procedure Call Standard for the ARM 64-bit Architecture) says // registers x19 through x28 and sp are callee preserved. v8-v15 are non- // volatile (and specifically only the lower 8 bytes of these regs), the rest diff --git a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h index 2b8e608d4caab..213fbf7417b2c 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h +++ b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h @@ -30,10 +30,6 @@ class ABISysV_arm64 : public ABIAArch64 { SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value) override; - lldb::UnwindPlanSP CreateFunctionEntryUnwindPlan() override; - - lldb::UnwindPlanSP CreateDefaultUnwindPlan() override; - bool RegisterIsVolatile(const lldb_private::RegisterInfo *reg_info) override; // The arm64 ABI requires that stack frames be 16 byte aligned. diff --git a/lldb/source/Symbol/FuncUnwinders.cpp b/lldb/source/Symbol/FuncUnwinders.cpp index faec24cde7fdd..8f3e3d0a9188a 100644 --- a/lldb/source/Symbol/FuncUnwinders.cpp +++ b/lldb/source/Symbol/FuncUnwinders.cpp @@ -365,33 +365,30 @@ FuncUnwinders::GetAssemblyUnwindPlan(Target &target, Thread &thread) { LazyBool FuncUnwinders::CompareUnwindPlansForIdenticalInitialPCLocation( Thread &thread, const std::shared_ptr &a, const std::shared_ptr &b) { - LazyBool plans_are_identical = eLazyBoolCalculate; + if (!a ||!b) + return eLazyBoolCalculate; - RegisterNumber pc_reg(thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); - uint32_t pc_reg_lldb_regnum = pc_reg.GetAsKind(eRegisterKindLLDB); + const UnwindPlan::Row *a_first_row = a->GetRowAtIndex(0); + const UnwindPlan::Row *b_first_row = b->GetRowAtIndex(0); + if (!a_first_row ||! b_first_row) + return eLazyBoolCalculate; - if (a && b) { - const UnwindPlan::Row *a_first_row = a->GetRowAtIndex(0); - const UnwindPlan::Row *b_first_row = b->GetRowAtIndex(0); + RegisterNumber pc_reg(thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + uint32_t a_pc_regnum = pc_reg.GetAsKind(a->GetRegisterKind()); + uint32_t b_pc_regnum = pc_reg.GetAsKind(b->GetRegisterKind()); - if (a_first_row && b_first_row) { - UnwindPlan::Row::AbstractRegisterLocation a_pc_regloc; - UnwindPlan::Row::AbstractRegisterLocation b_pc_regloc; + UnwindPlan::Row::AbstractRegisterLocation a_pc_regloc; + UnwindPlan::Row::AbstractRegisterLocation b_pc_regloc; - a_first_row->GetRegisterInfo(pc_reg_lldb_regnum, a_pc_regloc); - b_first_row->GetRegisterInfo(pc_reg_lldb_regnum, b_pc_regloc); + a_first_row->GetRegisterInfo(a_pc_regnum, a_pc_regloc); + b_first_row->GetRegisterInfo(b_pc_regnum, b_pc_regloc); - plans_are_identical = eLazyBoolYes; + if (a_first_row->GetCFAValue() != b_first_row->GetCFAValue()) + return eLazyBoolNo; + if (a_pc_regloc != b_pc_regloc) + return eLazyBoolNo; - if (a_first_row->GetCFAValue() != b_first_row->GetCFAValue()) { - plans_are_identical = eLazyBoolNo; - } - if (a_pc_regloc != b_pc_regloc) { - plans_are_identical = eLazyBoolNo; - } - } - } - return plans_are_identical; + return eLazyBoolYes; } std::shared_ptr ``````````
https://github.com/llvm/llvm-project/pull/139545 From lldb-commits at lists.llvm.org Mon May 12 06:39:31 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 06:39:31 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Merge/unify ABI-provided AArch64 unwind plans (PR #139545) In-Reply-To: Message-ID: <6821fa13.170a0220.2d5d49.c813@mx.google.com> github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning:
You can test this locally with the following command: ``````````bash git-clang-format --diff HEAD~1 HEAD --extensions h,cpp -- lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp lldb/source/Plugins/ABI/AArch64/ABIAArch64.h lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h lldb/source/Symbol/FuncUnwinders.cpp ``````````
View the diff from clang-format here. ``````````diff diff --git a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp index 58b8459b1..3bafb21f7 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp +++ b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp @@ -209,7 +209,8 @@ UnwindPlanSP ABIAArch64::CreateFunctionEntryUnwindPlan() { row.GetCFAValue().SetIsRegisterPlusOffset(LLDB_REGNUM_GENERIC_SP, 0); // Our previous PC is in the LR, all other registers are the same. - row.SetRegisterLocationToRegister(LLDB_REGNUM_GENERIC_PC, LLDB_REGNUM_GENERIC_RA, true); + row.SetRegisterLocationToRegister(LLDB_REGNUM_GENERIC_PC, + LLDB_REGNUM_GENERIC_RA, true); auto plan_sp = std::make_shared(eRegisterKindGeneric); plan_sp->AppendRow(std::move(row)); @@ -224,11 +225,14 @@ UnwindPlanSP ABIAArch64::CreateDefaultUnwindPlan() { UnwindPlan::Row row; const int32_t ptr_size = 8; - row.GetCFAValue().SetIsRegisterPlusOffset(LLDB_REGNUM_GENERIC_FP, 2 * ptr_size); + row.GetCFAValue().SetIsRegisterPlusOffset(LLDB_REGNUM_GENERIC_FP, + 2 * ptr_size); row.SetUnspecifiedRegistersAreUndefined(true); - row.SetRegisterLocationToAtCFAPlusOffset(LLDB_REGNUM_GENERIC_FP, ptr_size * -2, true); - row.SetRegisterLocationToAtCFAPlusOffset(LLDB_REGNUM_GENERIC_PC, ptr_size * -1, true); + row.SetRegisterLocationToAtCFAPlusOffset(LLDB_REGNUM_GENERIC_FP, + ptr_size * -2, true); + row.SetRegisterLocationToAtCFAPlusOffset(LLDB_REGNUM_GENERIC_PC, + ptr_size * -1, true); auto plan_sp = std::make_shared(eRegisterKindGeneric); plan_sp->AppendRow(std::move(row)); @@ -238,4 +242,3 @@ UnwindPlanSP ABIAArch64::CreateDefaultUnwindPlan() { plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo); return plan_sp; } - diff --git a/lldb/source/Symbol/FuncUnwinders.cpp b/lldb/source/Symbol/FuncUnwinders.cpp index 8f3e3d0a9..12a6d101d 100644 --- a/lldb/source/Symbol/FuncUnwinders.cpp +++ b/lldb/source/Symbol/FuncUnwinders.cpp @@ -365,12 +365,12 @@ FuncUnwinders::GetAssemblyUnwindPlan(Target &target, Thread &thread) { LazyBool FuncUnwinders::CompareUnwindPlansForIdenticalInitialPCLocation( Thread &thread, const std::shared_ptr &a, const std::shared_ptr &b) { - if (!a ||!b) + if (!a || !b) return eLazyBoolCalculate; const UnwindPlan::Row *a_first_row = a->GetRowAtIndex(0); const UnwindPlan::Row *b_first_row = b->GetRowAtIndex(0); - if (!a_first_row ||! b_first_row) + if (!a_first_row || !b_first_row) return eLazyBoolCalculate; RegisterNumber pc_reg(thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); ``````````
https://github.com/llvm/llvm-project/pull/139545 From lldb-commits at lists.llvm.org Mon May 12 06:54:18 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 06:54:18 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Move lldb_enable_attach from test_common to a separate header (PR #139550) Message-ID: https://github.com/labath created https://github.com/llvm/llvm-project/pull/139550 test_common is force-included into every compilation, which causes problems when we're compiling assembly code, as we were in #138805. This avoids that as we can include the header only when it's needed. Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Mon May 12 06:54:50 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 06:54:50 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Move lldb_enable_attach from test_common to a separate header (PR #139550) In-Reply-To: Message-ID: <6821fdaa.050a0220.c3feb.2605@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Pavel Labath (labath)
Changes test_common is force-included into every compilation, which causes problems when we're compiling assembly code, as we were in #138805. This avoids that as we can include the header only when it's needed. --- Full diff: https://github.com/llvm/llvm-project/pull/139550.diff 17 Files Affected: - (added) lldb/packages/Python/lldbsuite/test/make/attach.h (+34) - (modified) lldb/packages/Python/lldbsuite/test/make/test_common.h (-30) - (modified) lldb/test/API/commands/process/attach-resume/main.cpp (+3-3) - (modified) lldb/test/API/commands/process/attach/main.cpp (+2-2) - (modified) lldb/test/API/commands/process/detach-resumes/main.cpp (+2-1) - (modified) lldb/test/API/commands/register/register/register_command/main.cpp (+2-2) - (modified) lldb/test/API/driver/batch_mode/main.c (+1) - (modified) lldb/test/API/functionalities/deleted-executable/main.cpp (+1) - (modified) lldb/test/API/functionalities/load_after_attach/main.cpp (+3-2) - (modified) lldb/test/API/functionalities/process_group/main.c (+2-1) - (modified) lldb/test/API/functionalities/thread/create_after_attach/main.cpp (+2-1) - (modified) lldb/test/API/iohandler/completion/main.c (-1) - (modified) lldb/test/API/python_api/hello_world/main.c (+1) - (modified) lldb/test/API/tools/lldb-dap/attach/main.c (+1) - (modified) lldb/test/API/tools/lldb-dap/disconnect/main.cpp (+1) - (modified) lldb/test/API/tools/lldb-server/attach-wait/shim.cpp (+2-1) - (modified) lldb/test/API/tools/lldb-server/main.cpp (+1) ``````````diff diff --git a/lldb/packages/Python/lldbsuite/test/make/attach.h b/lldb/packages/Python/lldbsuite/test/make/attach.h new file mode 100644 index 0000000000000..decd3ea986a4b --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/make/attach.h @@ -0,0 +1,34 @@ +#ifndef LLDB_TEST_ATTACH_H +#define LLDB_TEST_ATTACH_H + +// On some systems (e.g., some versions of linux) it is not possible to attach +// to a process without it giving us special permissions. This defines the +// lldb_enable_attach macro, which should perform any such actions, if needed by +// the platform. +#if defined(__linux__) +#include + +// Android API <= 16 does not have these defined. +#ifndef PR_SET_PTRACER +#define PR_SET_PTRACER 0x59616d61 +#endif +#ifndef PR_SET_PTRACER_ANY +#define PR_SET_PTRACER_ANY ((unsigned long)-1) +#endif + +// For now we execute on best effort basis. If this fails for some reason, so +// be it. +#define lldb_enable_attach() \ + do { \ + const int prctl_result = \ + prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0); \ + (void)prctl_result; \ + } while (0) + +#else // not linux + +#define lldb_enable_attach() + +#endif // defined(__linux__) + +#endif // LLDB_TEST_ATTACH_H diff --git a/lldb/packages/Python/lldbsuite/test/make/test_common.h b/lldb/packages/Python/lldbsuite/test/make/test_common.h index aa8960e1c0aea..5082e41987020 100644 --- a/lldb/packages/Python/lldbsuite/test/make/test_common.h +++ b/lldb/packages/Python/lldbsuite/test/make/test_common.h @@ -20,33 +20,3 @@ #else #define LLVM_PRETTY_FUNCTION LLVM_PRETTY_FUNCTION #endif - - -// On some systems (e.g., some versions of linux) it is not possible to attach to a process -// without it giving us special permissions. This defines the lldb_enable_attach macro, which -// should perform any such actions, if needed by the platform. This is a macro instead of a -// function to avoid the need for complex linking of the test programs. -#if defined(__linux__) -#include - -// Android API <= 16 does not have these defined. -#ifndef PR_SET_PTRACER -#define PR_SET_PTRACER 0x59616d61 -#endif -#ifndef PR_SET_PTRACER_ANY -#define PR_SET_PTRACER_ANY ((unsigned long)-1) -#endif - -// For now we execute on best effort basis. If this fails for some reason, so be it. -#define lldb_enable_attach() \ - do \ - { \ - const int prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0); \ - (void)prctl_result; \ - } while (0) - -#else // not linux - -#define lldb_enable_attach() - -#endif diff --git a/lldb/test/API/commands/process/attach-resume/main.cpp b/lldb/test/API/commands/process/attach-resume/main.cpp index 82aad70eed560..3fe54d1e45601 100644 --- a/lldb/test/API/commands/process/attach-resume/main.cpp +++ b/lldb/test/API/commands/process/attach-resume/main.cpp @@ -1,7 +1,7 @@ -#include -#include - +#include "attach.h" #include +#include +#include #include volatile bool debugger_flag = true; // The debugger will flip this to false diff --git a/lldb/test/API/commands/process/attach/main.cpp b/lldb/test/API/commands/process/attach/main.cpp index b4ed48fade306..034e80ed5f2b3 100644 --- a/lldb/test/API/commands/process/attach/main.cpp +++ b/lldb/test/API/commands/process/attach/main.cpp @@ -1,6 +1,6 @@ -#include - +#include "attach.h" #include +#include #include volatile int g_val = 12345; diff --git a/lldb/test/API/commands/process/detach-resumes/main.cpp b/lldb/test/API/commands/process/detach-resumes/main.cpp index e8050fef2c385..9005c0a95847b 100644 --- a/lldb/test/API/commands/process/detach-resumes/main.cpp +++ b/lldb/test/API/commands/process/detach-resumes/main.cpp @@ -1,8 +1,9 @@ +#include "attach.h" #include "pseudo_barrier.h" #include +#include #include #include -#include #include #include diff --git a/lldb/test/API/commands/register/register/register_command/main.cpp b/lldb/test/API/commands/register/register/register_command/main.cpp index 860dfef0b3b97..5950c19f82967 100644 --- a/lldb/test/API/commands/register/register/register_command/main.cpp +++ b/lldb/test/API/commands/register/register/register_command/main.cpp @@ -1,6 +1,6 @@ -#include - +#include "attach.h" #include +#include #include long double outermost_return_long_double (long double my_long_double); diff --git a/lldb/test/API/driver/batch_mode/main.c b/lldb/test/API/driver/batch_mode/main.c index c85a0f272d2c1..4527c144f96fc 100644 --- a/lldb/test/API/driver/batch_mode/main.c +++ b/lldb/test/API/driver/batch_mode/main.c @@ -1,3 +1,4 @@ +#include "attach.h" #include #include #include diff --git a/lldb/test/API/functionalities/deleted-executable/main.cpp b/lldb/test/API/functionalities/deleted-executable/main.cpp index af00ac263cc1b..1536c6cf9e4a7 100644 --- a/lldb/test/API/functionalities/deleted-executable/main.cpp +++ b/lldb/test/API/functionalities/deleted-executable/main.cpp @@ -1,3 +1,4 @@ +#include "attach.h" #include #include #include diff --git a/lldb/test/API/functionalities/load_after_attach/main.cpp b/lldb/test/API/functionalities/load_after_attach/main.cpp index 96012a126001a..60bfefb72bb11 100644 --- a/lldb/test/API/functionalities/load_after_attach/main.cpp +++ b/lldb/test/API/functionalities/load_after_attach/main.cpp @@ -1,9 +1,10 @@ +#include "attach.h" #include "dylib.h" #include -#include -#include #include +#include #include +#include int main(int argc, char* argv[]) { lldb_enable_attach(); diff --git a/lldb/test/API/functionalities/process_group/main.c b/lldb/test/API/functionalities/process_group/main.c index 7e986bbac65de..b4d5abc58169c 100644 --- a/lldb/test/API/functionalities/process_group/main.c +++ b/lldb/test/API/functionalities/process_group/main.c @@ -1,6 +1,7 @@ +#include "attach.h" #include -#include #include +#include volatile int release_child_flag = 0; diff --git a/lldb/test/API/functionalities/thread/create_after_attach/main.cpp b/lldb/test/API/functionalities/thread/create_after_attach/main.cpp index d8f06e55a2dd9..d99fb05f08315 100644 --- a/lldb/test/API/functionalities/thread/create_after_attach/main.cpp +++ b/lldb/test/API/functionalities/thread/create_after_attach/main.cpp @@ -1,5 +1,6 @@ -#include +#include "attach.h" #include +#include #include using std::chrono::microseconds; diff --git a/lldb/test/API/iohandler/completion/main.c b/lldb/test/API/iohandler/completion/main.c index 03350dd8299a6..6dd3616c1ae40 100644 --- a/lldb/test/API/iohandler/completion/main.c +++ b/lldb/test/API/iohandler/completion/main.c @@ -1,5 +1,4 @@ int main(int argc, char **argv) { - lldb_enable_attach(); int to_complete = 0; return to_complete; } diff --git a/lldb/test/API/python_api/hello_world/main.c b/lldb/test/API/python_api/hello_world/main.c index c516f923614f1..865baa4f4ed11 100644 --- a/lldb/test/API/python_api/hello_world/main.c +++ b/lldb/test/API/python_api/hello_world/main.c @@ -1,3 +1,4 @@ +#include "attach.h" #include #ifdef _MSC_VER #include diff --git a/lldb/test/API/tools/lldb-dap/attach/main.c b/lldb/test/API/tools/lldb-dap/attach/main.c index c0b128afe445a..f56d5d53afa05 100644 --- a/lldb/test/API/tools/lldb-dap/attach/main.c +++ b/lldb/test/API/tools/lldb-dap/attach/main.c @@ -1,3 +1,4 @@ +#include "attach.h" #include #ifdef _WIN32 #include diff --git a/lldb/test/API/tools/lldb-dap/disconnect/main.cpp b/lldb/test/API/tools/lldb-dap/disconnect/main.cpp index d3d7a4b7338a8..ca9610da4566a 100644 --- a/lldb/test/API/tools/lldb-dap/disconnect/main.cpp +++ b/lldb/test/API/tools/lldb-dap/disconnect/main.cpp @@ -1,3 +1,4 @@ +#include "attach.h" #include #include #include diff --git a/lldb/test/API/tools/lldb-server/attach-wait/shim.cpp b/lldb/test/API/tools/lldb-server/attach-wait/shim.cpp index 60d0ba3753026..5b8bcc97e3e8f 100644 --- a/lldb/test/API/tools/lldb-server/attach-wait/shim.cpp +++ b/lldb/test/API/tools/lldb-server/attach-wait/shim.cpp @@ -1,5 +1,6 @@ -#include +#include "attach.h" #include +#include int main(int argc, char *argv[]) { lldb_enable_attach(); diff --git a/lldb/test/API/tools/lldb-server/main.cpp b/lldb/test/API/tools/lldb-server/main.cpp index c661f5b4e82c4..0e9323cce88cf 100644 --- a/lldb/test/API/tools/lldb-server/main.cpp +++ b/lldb/test/API/tools/lldb-server/main.cpp @@ -1,3 +1,4 @@ +#include "attach.h" #include #include #include ``````````
https://github.com/llvm/llvm-project/pull/139550 From lldb-commits at lists.llvm.org Mon May 12 06:56:03 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 06:56:03 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Move lldb_enable_attach from test_common to a separate header (PR #139550) In-Reply-To: Message-ID: <6821fdf3.630a0220.222872.83ee@mx.google.com> labath wrote: @DavidSpickett, following up on https://github.com/llvm/llvm-project/issues/138085#issuecomment-2871438305, I noticed that some of these tests don't have the synchronization to prevent the test attaching before they disable YAMA -- and I think most of those tests are marked `@flakyIfArm` https://github.com/llvm/llvm-project/pull/139550 From lldb-commits at lists.llvm.org Mon May 12 07:04:55 2025 From: lldb-commits at lists.llvm.org (Michael Buch via lldb-commits) Date: Mon, 12 May 2025 07:04:55 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][TypeSystemClang][NFC] Use GetNumBaseClasses in TypeSystemClang::GetNumChildren (PR #139552) Message-ID: https://github.com/Michael137 created https://github.com/llvm/llvm-project/pull/139552 `TypeSystemClang::GetNumBaseClasses` does exactly the same base-class accounting that we were doing in GetNumChildren. So re-use it. Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Mon May 12 07:05:25 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 07:05:25 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][TypeSystemClang][NFC] Use GetNumBaseClasses in TypeSystemClang::GetNumChildren (PR #139552) In-Reply-To: Message-ID: <68220025.a70a0220.1658d4.f300@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Michael Buch (Michael137)
Changes `TypeSystemClang::GetNumBaseClasses` does exactly the same base-class accounting that we were doing in GetNumChildren. So re-use it. --- Full diff: https://github.com/llvm/llvm-project/pull/139552.diff 1 Files Affected: - (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp (+2-26) ``````````diff diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 45f044733c0ff..b8ea2c17244c4 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -5355,33 +5355,9 @@ TypeSystemClang::GetNumChildren(lldb::opaque_compiler_type_t type, assert(record_decl); const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast(record_decl); - if (cxx_record_decl) { - if (omit_empty_base_classes) { - // Check each base classes to see if it or any of its base classes - // contain any fields. This can help limit the noise in variable - // views by not having to show base classes that contain no members. - clang::CXXRecordDecl::base_class_const_iterator base_class, - base_class_end; - for (base_class = cxx_record_decl->bases_begin(), - base_class_end = cxx_record_decl->bases_end(); - base_class != base_class_end; ++base_class) { - const clang::CXXRecordDecl *base_class_decl = - llvm::cast( - base_class->getType() - ->getAs() - ->getDecl()); - - // Skip empty base classes - if (!TypeSystemClang::RecordHasFields(base_class_decl)) - continue; - num_children++; - } - } else { - // Include all base classes - num_children += cxx_record_decl->getNumBases(); - } - } + num_children += + GetNumBaseClasses(cxx_record_decl, omit_empty_base_classes); num_children += std::distance(record_decl->field_begin(), record_decl->field_end()); } else ``````````
https://github.com/llvm/llvm-project/pull/139552 From lldb-commits at lists.llvm.org Mon May 12 07:07:58 2025 From: lldb-commits at lists.llvm.org (Felipe de Azevedo Piovezan via lldb-commits) Date: Mon, 12 May 2025 07:07:58 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][TypeSystemClang] Allow arrays to be dereferenced in C/C++. (PR #135843) In-Reply-To: Message-ID: <682200be.170a0220.d71a0.dc84@mx.google.com> felipepiovezan wrote: hi @kuilpd , I think this may have broken the mac incremental bots: https://green.lab.llvm.org//job/as-lldb-cmake/25656/ ``` [2025-05-12T12:08:03.542Z] runCmd: frame variable -d run-target *cfDictionaryRef [2025-05-12T12:08:03.542Z] [2025-05-12T12:08:03.542Z] runCmd failed! [2025-05-12T12:08:03.542Z] error: dereference failed: incomplete type "const __CFDictionary": (CFDictionaryRef) cfDictionaryRef ``` https://github.com/llvm/llvm-project/pull/135843 From lldb-commits at lists.llvm.org Mon May 12 07:08:55 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 07:08:55 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Provide lr value in faulting frame on arm64 (PR #138805) In-Reply-To: Message-ID: <682200f7.170a0220.31e123.1bfb@mx.google.com> labath wrote: I looked at why the test fails on linux. It turns out it's due to a bunch of reasons, but most of them are unrelated to the problem at hand. #139545 and #139550 fix the surrounding issues, and https://github.com/llvm/llvm-project/commit/c290e555d6e7d196ebbe5fd6d64e0be25275a5b4 is enough to fix the test itself. I needed to change the compile command because, for some reason the compiler was not finding the temporary file. I didn't look at what causes the difference because I think this is more robust and idiomatic. I also needed to remove the `brk #0xf000` instruction because lldb is not able to step over it -- it just ends up spinning forever. FWICS, it's not actually necessary now that you're stepping through the test. Nonetheless, this is a bug -- one that @DavidSpickett might be interested in :) Interestingly, the mac debug server does not step onto the breakpoint instruction at all. It skips over it when stepping over the previous instruction (i.e. that single step operation actually steps two instructions). This is most likely also some kind of a bug. > FTR that test is skipped on darwin because _sigtramp in libc on aarch64 doesn't have any hand-supplied eh_frame right now :/ Oh... FWIW, we're in the same situation on aarch64 linux, but here we hard code the plan into lldb in `PlatformLinux::GetTrapHandlerUnwindPlan` (which we can, because it's part of the OS ABI). Maybe you could do the same? https://github.com/llvm/llvm-project/pull/138805 From lldb-commits at lists.llvm.org Mon May 12 07:10:22 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 07:10:22 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Merge/unify ABI-provided AArch64 unwind plans (PR #139545) In-Reply-To: Message-ID: <6822014e.170a0220.8f373.fb24@mx.google.com> https://github.com/labath updated https://github.com/llvm/llvm-project/pull/139545 >From 2aa2fd0d0777bd0bcdd1b627c2c3d306b79512c4 Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Mon, 12 May 2025 04:38:05 -0700 Subject: [PATCH] [lldb] Merge/unify ABI-provided AArch64 unwind plans The macos and sysv ABIs return functionally equivalent unwind plans, so they can be implemented in the base AArch64 class. The only difference between them was that the macos plan provided a "pc=lr" rule whereas the sysv plan called SetReturnAddressRegister (which causes the unwind machinery to act as if that rule was present). This difference was enough to cause `CompareUnwindPlansForIdenticalInitialPCLocation` to return a different value and break the (temporarily reverted) TestUnwindFramelessFaulted test. While merging the two functions, I couldn't help myself from simplifying them to use the generic register number schemes -- which exposed another bug in CompareUnwindPlansForIdenticalInitialPCLocation, namely that it was expecting all unwind plans to use the LLDB numbering scheme. This patch fixes that as well. --- .../source/Plugins/ABI/AArch64/ABIAArch64.cpp | 42 +++++++++++++++++ lldb/source/Plugins/ABI/AArch64/ABIAArch64.h | 3 ++ .../Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp | 45 ------------------- .../Plugins/ABI/AArch64/ABIMacOSX_arm64.h | 4 -- .../Plugins/ABI/AArch64/ABISysV_arm64.cpp | 44 ------------------ .../Plugins/ABI/AArch64/ABISysV_arm64.h | 4 -- lldb/source/Symbol/FuncUnwinders.cpp | 39 ++++++++-------- 7 files changed, 63 insertions(+), 118 deletions(-) diff --git a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp index 7d8d0a4d3d671..3bafb21f7c33a 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp +++ b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp @@ -19,6 +19,7 @@ #include using namespace lldb; +using namespace lldb_private; LLDB_PLUGIN_DEFINE(ABIAArch64) @@ -200,3 +201,44 @@ void ABIAArch64::AugmentRegisterInfo( lldb::eEncodingIEEE754, lldb::eFormatFloat); } } + +UnwindPlanSP ABIAArch64::CreateFunctionEntryUnwindPlan() { + UnwindPlan::Row row; + + // Our previous Call Frame Address is the stack pointer + row.GetCFAValue().SetIsRegisterPlusOffset(LLDB_REGNUM_GENERIC_SP, 0); + + // Our previous PC is in the LR, all other registers are the same. + row.SetRegisterLocationToRegister(LLDB_REGNUM_GENERIC_PC, + LLDB_REGNUM_GENERIC_RA, true); + + auto plan_sp = std::make_shared(eRegisterKindGeneric); + plan_sp->AppendRow(std::move(row)); + plan_sp->SetSourceName("arm64 at-func-entry default"); + plan_sp->SetSourcedFromCompiler(eLazyBoolNo); + plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); + plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo); + return plan_sp; +} + +UnwindPlanSP ABIAArch64::CreateDefaultUnwindPlan() { + UnwindPlan::Row row; + const int32_t ptr_size = 8; + + row.GetCFAValue().SetIsRegisterPlusOffset(LLDB_REGNUM_GENERIC_FP, + 2 * ptr_size); + row.SetUnspecifiedRegistersAreUndefined(true); + + row.SetRegisterLocationToAtCFAPlusOffset(LLDB_REGNUM_GENERIC_FP, + ptr_size * -2, true); + row.SetRegisterLocationToAtCFAPlusOffset(LLDB_REGNUM_GENERIC_PC, + ptr_size * -1, true); + + auto plan_sp = std::make_shared(eRegisterKindGeneric); + plan_sp->AppendRow(std::move(row)); + plan_sp->SetSourceName("arm64 default unwind plan"); + plan_sp->SetSourcedFromCompiler(eLazyBoolNo); + plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); + plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo); + return plan_sp; +} diff --git a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h index 52e42f1260a83..53702f4da580d 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h +++ b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h @@ -19,6 +19,9 @@ class ABIAArch64 : public lldb_private::MCBasedABI { lldb::addr_t FixCodeAddress(lldb::addr_t pc) override; lldb::addr_t FixDataAddress(lldb::addr_t pc) override; + lldb::UnwindPlanSP CreateFunctionEntryUnwindPlan() override; + lldb::UnwindPlanSP CreateDefaultUnwindPlan() override; + protected: virtual lldb::addr_t FixAddress(lldb::addr_t pc, lldb::addr_t mask) { return pc; diff --git a/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp index f86ab8cbb1195..094e0523a4edf 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp +++ b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp @@ -17,7 +17,6 @@ #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Value.h" -#include "lldb/Symbol/UnwindPlan.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Target.h" @@ -30,8 +29,6 @@ #include "lldb/Utility/Status.h" #include "lldb/ValueObject/ValueObjectConstResult.h" -#include "Utility/ARM64_DWARF_Registers.h" - using namespace lldb; using namespace lldb_private; @@ -344,48 +341,6 @@ ABIMacOSX_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, return error; } -UnwindPlanSP ABIMacOSX_arm64::CreateFunctionEntryUnwindPlan() { - uint32_t lr_reg_num = arm64_dwarf::lr; - uint32_t sp_reg_num = arm64_dwarf::sp; - uint32_t pc_reg_num = arm64_dwarf::pc; - - UnwindPlan::Row row; - - // Our previous Call Frame Address is the stack pointer - row.GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0); - - // Our previous PC is in the LR, all other registers are the same. - row.SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true); - - auto plan_sp = std::make_shared(eRegisterKindDWARF); - plan_sp->AppendRow(std::move(row)); - plan_sp->SetSourceName("arm64 at-func-entry default"); - plan_sp->SetSourcedFromCompiler(eLazyBoolNo); - return plan_sp; -} - -UnwindPlanSP ABIMacOSX_arm64::CreateDefaultUnwindPlan() { - uint32_t fp_reg_num = arm64_dwarf::fp; - uint32_t pc_reg_num = arm64_dwarf::pc; - - UnwindPlan::Row row; - const int32_t ptr_size = 8; - - row.GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size); - row.SetUnspecifiedRegistersAreUndefined(true); - - row.SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); - row.SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); - - auto plan_sp = std::make_shared(eRegisterKindDWARF); - plan_sp->AppendRow(std::move(row)); - plan_sp->SetSourceName("arm64-apple-darwin default unwind plan"); - plan_sp->SetSourcedFromCompiler(eLazyBoolNo); - plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); - plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo); - return plan_sp; -} - // AAPCS64 (Procedure Call Standard for the ARM 64-bit Architecture) says // registers x19 through x28 and sp are callee preserved. v8-v15 are non- // volatile (and specifically only the lower 8 bytes of these regs), the rest diff --git a/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h index 94a60327c6181..c8851709f50ad 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h +++ b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h @@ -27,10 +27,6 @@ class ABIMacOSX_arm64 : public ABIAArch64 { bool GetArgumentValues(lldb_private::Thread &thread, lldb_private::ValueList &values) const override; - lldb::UnwindPlanSP CreateFunctionEntryUnwindPlan() override; - - lldb::UnwindPlanSP CreateDefaultUnwindPlan() override; - bool RegisterIsVolatile(const lldb_private::RegisterInfo *reg_info) override; // The arm64 ABI requires that stack frames be 16 byte aligned. diff --git a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp index 6e07c0982be0e..aa9c20b6bb2cf 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp +++ b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp @@ -30,8 +30,6 @@ #include "lldb/Utility/Status.h" #include "lldb/ValueObject/ValueObjectConstResult.h" -#include "Utility/ARM64_DWARF_Registers.h" - using namespace lldb; using namespace lldb_private; @@ -385,48 +383,6 @@ Status ABISysV_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, return error; } -UnwindPlanSP ABISysV_arm64::CreateFunctionEntryUnwindPlan() { - uint32_t lr_reg_num = arm64_dwarf::lr; - uint32_t sp_reg_num = arm64_dwarf::sp; - - UnwindPlan::Row row; - - // Our previous Call Frame Address is the stack pointer, all other registers - // are the same. - row.GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0); - - auto plan_sp = std::make_shared(eRegisterKindDWARF); - plan_sp->AppendRow(std::move(row)); - plan_sp->SetReturnAddressRegister(lr_reg_num); - plan_sp->SetSourceName("arm64 at-func-entry default"); - plan_sp->SetSourcedFromCompiler(eLazyBoolNo); - plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); - plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo); - return plan_sp; -} - -UnwindPlanSP ABISysV_arm64::CreateDefaultUnwindPlan() { - uint32_t fp_reg_num = arm64_dwarf::fp; - uint32_t pc_reg_num = arm64_dwarf::pc; - - UnwindPlan::Row row; - const int32_t ptr_size = 8; - - row.GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size); - row.SetUnspecifiedRegistersAreUndefined(true); - - row.SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); - row.SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); - - auto plan_sp = std::make_shared(eRegisterKindDWARF); - plan_sp->AppendRow(std::move(row)); - plan_sp->SetSourceName("arm64 default unwind plan"); - plan_sp->SetSourcedFromCompiler(eLazyBoolNo); - plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); - plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo); - return plan_sp; -} - // AAPCS64 (Procedure Call Standard for the ARM 64-bit Architecture) says // registers x19 through x28 and sp are callee preserved. v8-v15 are non- // volatile (and specifically only the lower 8 bytes of these regs), the rest diff --git a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h index 2b8e608d4caab..213fbf7417b2c 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h +++ b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h @@ -30,10 +30,6 @@ class ABISysV_arm64 : public ABIAArch64 { SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value) override; - lldb::UnwindPlanSP CreateFunctionEntryUnwindPlan() override; - - lldb::UnwindPlanSP CreateDefaultUnwindPlan() override; - bool RegisterIsVolatile(const lldb_private::RegisterInfo *reg_info) override; // The arm64 ABI requires that stack frames be 16 byte aligned. diff --git a/lldb/source/Symbol/FuncUnwinders.cpp b/lldb/source/Symbol/FuncUnwinders.cpp index faec24cde7fdd..12a6d101d9930 100644 --- a/lldb/source/Symbol/FuncUnwinders.cpp +++ b/lldb/source/Symbol/FuncUnwinders.cpp @@ -365,33 +365,30 @@ FuncUnwinders::GetAssemblyUnwindPlan(Target &target, Thread &thread) { LazyBool FuncUnwinders::CompareUnwindPlansForIdenticalInitialPCLocation( Thread &thread, const std::shared_ptr &a, const std::shared_ptr &b) { - LazyBool plans_are_identical = eLazyBoolCalculate; + if (!a || !b) + return eLazyBoolCalculate; - RegisterNumber pc_reg(thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); - uint32_t pc_reg_lldb_regnum = pc_reg.GetAsKind(eRegisterKindLLDB); + const UnwindPlan::Row *a_first_row = a->GetRowAtIndex(0); + const UnwindPlan::Row *b_first_row = b->GetRowAtIndex(0); + if (!a_first_row || !b_first_row) + return eLazyBoolCalculate; - if (a && b) { - const UnwindPlan::Row *a_first_row = a->GetRowAtIndex(0); - const UnwindPlan::Row *b_first_row = b->GetRowAtIndex(0); + RegisterNumber pc_reg(thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + uint32_t a_pc_regnum = pc_reg.GetAsKind(a->GetRegisterKind()); + uint32_t b_pc_regnum = pc_reg.GetAsKind(b->GetRegisterKind()); - if (a_first_row && b_first_row) { - UnwindPlan::Row::AbstractRegisterLocation a_pc_regloc; - UnwindPlan::Row::AbstractRegisterLocation b_pc_regloc; + UnwindPlan::Row::AbstractRegisterLocation a_pc_regloc; + UnwindPlan::Row::AbstractRegisterLocation b_pc_regloc; - a_first_row->GetRegisterInfo(pc_reg_lldb_regnum, a_pc_regloc); - b_first_row->GetRegisterInfo(pc_reg_lldb_regnum, b_pc_regloc); + a_first_row->GetRegisterInfo(a_pc_regnum, a_pc_regloc); + b_first_row->GetRegisterInfo(b_pc_regnum, b_pc_regloc); - plans_are_identical = eLazyBoolYes; + if (a_first_row->GetCFAValue() != b_first_row->GetCFAValue()) + return eLazyBoolNo; + if (a_pc_regloc != b_pc_regloc) + return eLazyBoolNo; - if (a_first_row->GetCFAValue() != b_first_row->GetCFAValue()) { - plans_are_identical = eLazyBoolNo; - } - if (a_pc_regloc != b_pc_regloc) { - plans_are_identical = eLazyBoolNo; - } - } - } - return plans_are_identical; + return eLazyBoolYes; } std::shared_ptr From lldb-commits at lists.llvm.org Mon May 12 07:13:37 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 07:13:37 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][TypeSystemClang][NFC] Use GetNumBaseClasses in TypeSystemClang::GetNumChildren (PR #139552) In-Reply-To: Message-ID: <68220211.050a0220.1417e0.0266@mx.google.com> https://github.com/labath approved this pull request. yay https://github.com/llvm/llvm-project/pull/139552 From lldb-commits at lists.llvm.org Mon May 12 07:36:05 2025 From: lldb-commits at lists.llvm.org (Michael Buch via lldb-commits) Date: Mon, 12 May 2025 07:36:05 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][SymbolFileDWARF] Don't search for DWP files on macOS (PR #139554) Message-ID: https://github.com/Michael137 created https://github.com/llvm/llvm-project/pull/139554 A contrived performance measurement on my local machine: 1. Attach LLDB to LLDB 2. Measure how much time it takes to run `b operator[]` Without this patch, we would spend a total of 400ms (which was ~4-5% of total execution) looking for DWP files (and failing to find them because they are not a concept on macOS). We call into `GetDwpSymbolFile` via `DebugNamesDWARFIndex::GetFunctions -> ManualDWARFIndex::GetFunctions -> ManualDWARFIndex::Index`. rdar://148212738 >From 17223e9ce0b95c112b18e6edfef5fee429ac6017 Mon Sep 17 00:00:00 2001 From: Michael Buch Date: Mon, 12 May 2025 15:30:02 +0100 Subject: [PATCH] [lldb][SymbolFileDWARF] Don't search for DWP files on macOS A contrived performance measurement on my local machine: 1. Attach LLDB to LLDB 2. Measure how much time it takes to run `b operator[]` Without this patch, we would spend a total of 400ms (which was ~4-5% of total execution) looking for DWP files (and failing to find them because they are not a concept on macOS). We call into `GetDwpSymbolFile` via `DebugNamesDWARFIndex::GetFunctions -> ManualDWARFIndex::GetFunctions -> ManualDWARFIndex::Index`. rdar://148212738 --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 907d63eb51afe..3f53e562ba65b 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -4211,6 +4211,9 @@ SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() { const std::shared_ptr &SymbolFileDWARF::GetDwpSymbolFile() { llvm::call_once(m_dwp_symfile_once_flag, [this]() { + if (m_objfile_sp->GetArchitecture().GetTriple().isAppleMachO()) + return; + // Create a list of files to try and append .dwp to. FileSpecList symfiles; // Append the module's object file path. From lldb-commits at lists.llvm.org Mon May 12 07:36:37 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 07:36:37 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][SymbolFileDWARF] Don't search for DWP files on macOS (PR #139554) In-Reply-To: Message-ID: <68220775.170a0220.c58c2.04eb@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Michael Buch (Michael137)
Changes A contrived performance measurement on my local machine: 1. Attach LLDB to LLDB 2. Measure how much time it takes to run `b operator[]` Without this patch, we would spend a total of 400ms (which was ~4-5% of total execution) looking for DWP files (and failing to find them because they are not a concept on macOS). We call into `GetDwpSymbolFile` via `DebugNamesDWARFIndex::GetFunctions -> ManualDWARFIndex::GetFunctions -> ManualDWARFIndex::Index`. rdar://148212738 --- Full diff: https://github.com/llvm/llvm-project/pull/139554.diff 1 Files Affected: - (modified) lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp (+3) ``````````diff diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 907d63eb51afe..3f53e562ba65b 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -4211,6 +4211,9 @@ SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() { const std::shared_ptr &SymbolFileDWARF::GetDwpSymbolFile() { llvm::call_once(m_dwp_symfile_once_flag, [this]() { + if (m_objfile_sp->GetArchitecture().GetTriple().isAppleMachO()) + return; + // Create a list of files to try and append .dwp to. FileSpecList symfiles; // Append the module's object file path. ``````````
https://github.com/llvm/llvm-project/pull/139554 From lldb-commits at lists.llvm.org Mon May 12 07:55:39 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 07:55:39 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][plugin] Clear in same thread as set (PR #139252) In-Reply-To: Message-ID: <68220beb.a70a0220.49f0c.39e3@mx.google.com> ================ @@ -189,17 +189,23 @@ DWARFUnit::ScopedExtractDIEs DWARFUnit::ExtractDIEsScoped() { } DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(DWARFUnit &cu) : m_cu(&cu) { - m_cu->m_die_array_scoped_mutex.lock_shared(); + llvm::sys::ScopedLock lock(m_cu->m_die_array_scoped_mutex); + ++m_cu->m_die_array_scoped_count; } DWARFUnit::ScopedExtractDIEs::~ScopedExtractDIEs() { if (!m_cu) return; - m_cu->m_die_array_scoped_mutex.unlock_shared(); + { + llvm::sys::ScopedLock lock(m_cu->m_die_array_scoped_mutex); + --m_cu->m_die_array_scoped_count; + if (m_cu->m_die_array_scoped_count == 0) + return; + } if (!m_clear_dies || m_cu->m_cancel_scopes) return; // Be sure no other ScopedExtractDIEs is running anymore. ---------------- labath wrote: I think all of this can/should be one critical section. The reason the code was originally doing the unlock is because it was switching the lock type (shared->exclusive). So, I think something like this ought to do it: ``` llvm::sys::ScopedLock lock(m_cu->m_die_array_scoped_mutex); --m_cu->m_die_array_scoped_count; if (m_cu->m_die_array_scoped_count == 0 && m_clear_dies && !m_cu->m_cancel_scopes) m_cu->ClearDIEsRWLocked(); ``` https://github.com/llvm/llvm-project/pull/139252 From lldb-commits at lists.llvm.org Mon May 12 07:57:43 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 07:57:43 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][plugin] Clear in same thread as set (PR #139252) In-Reply-To: Message-ID: <68220c67.170a0220.10e5d2.3884@mx.google.com> labath wrote: > But if plain counter preferred, will switch to that. That is the first idea that crossed my mind, I'm not saying its the best one. I'm not really sure how would a condition variable help here (like, you still need some kind of a counter to trigger the condition), but I'm open to other approaches. https://github.com/llvm/llvm-project/pull/139252 From lldb-commits at lists.llvm.org Mon May 12 08:21:48 2025 From: lldb-commits at lists.llvm.org (Vy Nguyen via lldb-commits) Date: Mon, 12 May 2025 08:21:48 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb]Make `list` command work with headers when possible. (PR #139002) In-Reply-To: Message-ID: <6822120c.620a0220.34d2fc.aeb6@mx.google.com> oontvoo wrote: > When setting a breakpoint, we pass eSymbolContextLineEntry to the function so that it returns a line entry matching the query. In this case, we're not really interested in the entire line entry, but I think it should be possible the line entry as a carrier for the file name: we ask for the function to fill it out, and then fetch the file from there. Can you see if that works? Yes - that worked! Thanks! > I also think that changing `0` to `start_line` was not right change. Since we're not actually line entry (just the file name, we'll extract the lines ourselves), we want to maximize our chances of finding a matching line entry. If it cannot find an exact file+line match, `ResolveSymbolContextForFilePath` will return a line entry for any line that comes after it. Using zero ensures we don't skip any line entries. Leaving the line-number as `0` somehow result in it couldn't find the file! (Changing it to the right line number - or anything non-zero, on the other hand works). Any idea why? https://github.com/llvm/llvm-project/pull/139002 From lldb-commits at lists.llvm.org Mon May 12 08:21:49 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Mon, 12 May 2025 08:21:49 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit tests for protocol types (PR #139502) In-Reply-To: Message-ID: <6822120d.050a0220.1cedc.5cdc@mx.google.com> JDevlieghere wrote: > tiny nit for concrete types @da-viper I don't see your comment, is it possible it wasn't submitted? https://github.com/llvm/llvm-project/pull/139502 From lldb-commits at lists.llvm.org Mon May 12 08:22:47 2025 From: lldb-commits at lists.llvm.org (Vy Nguyen via lldb-commits) Date: Mon, 12 May 2025 08:22:47 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb]Make `list` command work with headers when possible. (PR #139002) In-Reply-To: Message-ID: <68221247.a70a0220.5ad31.7e36@mx.google.com> https://github.com/oontvoo updated https://github.com/llvm/llvm-project/pull/139002 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Mon May 12 08:22:52 2025 From: lldb-commits at lists.llvm.org (Vy Nguyen via lldb-commits) Date: Mon, 12 May 2025 08:22:52 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb]Make `list` command work with headers when possible. (PR #139002) In-Reply-To: Message-ID: <6822124c.170a0220.5982b.472a@mx.google.com> ================ @@ -1170,10 +1171,41 @@ class CommandObjectSourceList : public CommandObjectParsed { if (m_options.num_lines == 0) m_options.num_lines = 10; const uint32_t column = 0; + + // Headers aren't always in the DWARF but if they have + // executable code (eg., inlined-functions) then the callsite's + // file(s) will be found. So if a header was requested and we got a + // primary file (ie., something with a different name), then look thru + // its support file(s) for the header. + lldb::SupportFileSP found_file_sp = ---------------- oontvoo wrote: done https://github.com/llvm/llvm-project/pull/139002 From lldb-commits at lists.llvm.org Mon May 12 08:23:05 2025 From: lldb-commits at lists.llvm.org (Vy Nguyen via lldb-commits) Date: Mon, 12 May 2025 08:23:05 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb]Make `list` command work with headers when possible. (PR #139002) In-Reply-To: Message-ID: <68221259.050a0220.1f30d2.54ed@mx.google.com> ================ @@ -1114,15 +1115,15 @@ class CommandObjectSourceList : public CommandObjectParsed { matching_modules.Clear(); target.GetImages().FindModules(module_spec, matching_modules); num_matches += matching_modules.ResolveSymbolContextForFilePath( - filename, 0, check_inlines, + filename, start_line, check_inlines, SymbolContextItem(eSymbolContextModule | eSymbolContextCompUnit), ---------------- oontvoo wrote: done (applied) https://github.com/llvm/llvm-project/pull/139002 From lldb-commits at lists.llvm.org Mon May 12 08:24:40 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Mon, 12 May 2025 08:24:40 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit tests for protocol types (PR #139502) In-Reply-To: Message-ID: <682212b8.170a0220.231201.9f23@mx.google.com> ================ @@ -0,0 +1,268 @@ +//===-- ProtocolTypesTest.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 "Protocol/ProtocolTypes.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap::protocol; + +TEST(ProtocolTypesTest, ExceptionBreakpointsFilter) { + ExceptionBreakpointsFilter filter; + filter.filter = "testFilter"; + filter.label = "Test Filter"; + filter.description = "This is a test filter"; + filter.defaultState = true; + filter.supportsCondition = true; + filter.conditionDescription = "Condition for test filter"; + + llvm::json::Value value = toJSON(filter); + const json::Object *obj = value.getAsObject(); + ASSERT_NE(obj, nullptr); + + EXPECT_EQ(obj->getString("filter"), "testFilter"); + EXPECT_EQ(obj->getString("label"), "Test Filter"); + EXPECT_EQ(obj->getString("description"), "This is a test filter"); + EXPECT_EQ(obj->getBoolean("default"), true); + EXPECT_EQ(obj->getBoolean("supportsCondition"), true); + EXPECT_EQ(obj->getString("conditionDescription"), + "Condition for test filter"); +} + +TEST(ProtocolTypesTest, ColumnDescriptor) { + ColumnDescriptor column; + column.attributeName = "testAttribute"; + column.label = "Test Label"; + column.format = "testFormat"; + column.type = eColumnTypeString; + column.width = 20; + + llvm::json::Value value = toJSON(column); + const json::Object *obj = value.getAsObject(); + ASSERT_NE(obj, nullptr); + + EXPECT_EQ(obj->getString("attributeName"), "testAttribute"); + EXPECT_EQ(obj->getString("label"), "Test Label"); + EXPECT_EQ(obj->getString("format"), "testFormat"); + EXPECT_EQ(obj->getString("type"), "string"); + EXPECT_EQ(obj->getInteger("width"), 20); +} + +TEST(ProtocolTypesTest, BreakpointMode) { + BreakpointMode mode; + mode.mode = "testMode"; + mode.label = "Test Label"; + mode.description = "This is a test description"; + mode.appliesTo = {eBreakpointModeApplicabilitySource, + eBreakpointModeApplicabilityException}; + + llvm::json::Value value = toJSON(mode); + const json::Object *obj = value.getAsObject(); + ASSERT_NE(obj, nullptr); + + EXPECT_EQ(obj->getString("mode"), "testMode"); + EXPECT_EQ(obj->getString("label"), "Test Label"); + EXPECT_EQ(obj->getString("description"), "This is a test description"); + + const auto *appliesToArray = obj->getArray("appliesTo"); + ASSERT_NE(appliesToArray, nullptr); + ASSERT_EQ(appliesToArray->size(), 2UL); + EXPECT_EQ(appliesToArray->front().getAsString(), "source"); + EXPECT_EQ(appliesToArray->back().getAsString(), "exception"); +} + +TEST(ProtocolTypesTest, Capabilities) { + Capabilities capabilities; + capabilities.supportedFeatures = {eAdapterFeatureANSIStyling, + eAdapterFeatureTerminateRequest}; + capabilities.exceptionBreakpointFilters = { + {"filter1", "Filter 1", "Description 1", true, true, "Condition 1"}, + {"filter2", "Filter 2", "Description 2", false, false, "Condition 2"}}; + capabilities.completionTriggerCharacters = {"."}; + capabilities.additionalModuleColumns = { + {"attribute1", "Label 1", "Format 1", eColumnTypeString, 10}, + {"attribute2", "Label 2", "Format 2", eColumnTypeNumber, 20}}; + capabilities.supportedChecksumAlgorithms = {eChecksumAlgorithmMD5, + eChecksumAlgorithmSHA256}; + capabilities.breakpointModes = {{"mode1", + "Mode 1", + "Description 1", + {eBreakpointModeApplicabilitySource}}, + {"mode2", + "Mode 2", + "Description 2", + {eBreakpointModeApplicabilityException}}}; + capabilities.lldbExtVersion = "1.0.0"; + + llvm::json::Value value = toJSON(capabilities); + const json::Object *obj = value.getAsObject(); + ASSERT_NE(obj, nullptr); + + // Verify supported features. + EXPECT_EQ(obj->getBoolean("supportsANSIStyling"), true); + EXPECT_EQ(obj->getBoolean("supportsTerminateRequest"), true); + + // Verify exception breakpoint filters. + const auto *filtersArray = obj->getArray("exceptionBreakpointFilters"); + ASSERT_NE(filtersArray, nullptr); + ASSERT_EQ(filtersArray->size(), 2UL); + const auto *filter1 = filtersArray->front().getAsObject(); ---------------- da-viper wrote: was referring to the auto in the function. https://github.com/llvm/llvm-project/pull/139502 From lldb-commits at lists.llvm.org Mon May 12 08:51:21 2025 From: lldb-commits at lists.llvm.org (Ilia Kuklin via lldb-commits) Date: Mon, 12 May 2025 08:51:21 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Restore ObjC incomplete type dereferencing fix (PR #139567) Message-ID: https://github.com/kuilpd created https://github.com/llvm/llvm-project/pull/139567 Attempt an ObjC incomplete type fix even if `GetDereferencedType` returns an error. Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Mon May 12 08:51:47 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 08:51:47 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Restore ObjC incomplete type dereferencing fix (PR #139567) In-Reply-To: Message-ID: <68221913.170a0220.64ecf.66b1@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Ilia Kuklin (kuilpd)
Changes Attempt an ObjC incomplete type fix even if `GetDereferencedType` returns an error. --- Full diff: https://github.com/llvm/llvm-project/pull/139567.diff 1 Files Affected: - (modified) lldb/source/ValueObject/ValueObject.cpp (+35-34) ``````````diff diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp index 6f0fe9a5b83f9..46426ae499be9 100644 --- a/lldb/source/ValueObject/ValueObject.cpp +++ b/lldb/source/ValueObject/ValueObject.cpp @@ -2810,46 +2810,47 @@ ValueObjectSP ValueObject::Dereference(Status &error) { std::string deref_error; if (deref_compiler_type_or_err) { deref_compiler_type = *deref_compiler_type_or_err; - if (deref_compiler_type && deref_byte_size) { - ConstString deref_name; - if (!deref_name_str.empty()) - deref_name.SetCString(deref_name_str.c_str()); - - m_deref_valobj = - new ValueObjectChild(*this, deref_compiler_type, deref_name, - deref_byte_size, deref_byte_offset, 0, 0, false, - true, eAddressTypeInvalid, language_flags); - } - - // In case of incomplete deref compiler type, use the pointee type and try - // to recreate a new ValueObjectChild using it. - if (!m_deref_valobj) { - // FIXME(#59012): C++ stdlib formatters break with incomplete types (e.g. - // `std::vector &`). Remove ObjC restriction once that's resolved. - if (Language::LanguageIsObjC(GetPreferredDisplayLanguage()) && - HasSyntheticValue()) { - deref_compiler_type = compiler_type.GetPointeeType(); - - if (deref_compiler_type) { - ConstString deref_name; - if (!deref_name_str.empty()) - deref_name.SetCString(deref_name_str.c_str()); - - m_deref_valobj = new ValueObjectChild( - *this, deref_compiler_type, deref_name, deref_byte_size, - deref_byte_offset, 0, 0, false, true, eAddressTypeInvalid, - language_flags); - } - } - } } else { deref_error = llvm::toString(deref_compiler_type_or_err.takeError()); LLDB_LOG(GetLog(LLDBLog::Types), "could not find child: {0}", deref_error); - if (IsSynthetic()) { - m_deref_valobj = GetChildMemberWithName("$$dereference$$").get(); + } + + if (deref_compiler_type && deref_byte_size) { + ConstString deref_name; + if (!deref_name_str.empty()) + deref_name.SetCString(deref_name_str.c_str()); + + m_deref_valobj = + new ValueObjectChild(*this, deref_compiler_type, deref_name, + deref_byte_size, deref_byte_offset, 0, 0, false, + true, eAddressTypeInvalid, language_flags); + } + + // In case of incomplete deref compiler type, use the pointee type and try + // to recreate a new ValueObjectChild using it. + if (!m_deref_valobj) { + // FIXME(#59012): C++ stdlib formatters break with incomplete types (e.g. + // `std::vector &`). Remove ObjC restriction once that's resolved. + if (Language::LanguageIsObjC(GetPreferredDisplayLanguage()) && + HasSyntheticValue()) { + deref_compiler_type = compiler_type.GetPointeeType(); + + if (deref_compiler_type) { + ConstString deref_name; + if (!deref_name_str.empty()) + deref_name.SetCString(deref_name_str.c_str()); + + m_deref_valobj = new ValueObjectChild( + *this, deref_compiler_type, deref_name, deref_byte_size, + deref_byte_offset, 0, 0, false, true, eAddressTypeInvalid, + language_flags); + } } } + if (!m_deref_valobj && IsSynthetic()) + m_deref_valobj = GetChildMemberWithName("$$dereference$$").get(); + if (m_deref_valobj) { error.Clear(); return m_deref_valobj->GetSP(); ``````````
https://github.com/llvm/llvm-project/pull/139567 From lldb-commits at lists.llvm.org Mon May 12 08:59:26 2025 From: lldb-commits at lists.llvm.org (Ilia Kuklin via lldb-commits) Date: Mon, 12 May 2025 08:59:26 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Restore ObjC incomplete type dereferencing fix (PR #139567) In-Reply-To: Message-ID: <68221ade.050a0220.12f3c2.97f9@mx.google.com> kuilpd wrote: @felipepiovezan I don't have a machine to run ObjC tests on, could you apply this patch and see if it fixes the issue in #135843 ? https://github.com/llvm/llvm-project/pull/139567 From lldb-commits at lists.llvm.org Mon May 12 09:02:35 2025 From: lldb-commits at lists.llvm.org (Adrian Prantl via lldb-commits) Date: Mon, 12 May 2025 09:02:35 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][SymbolFileDWARF] Don't search for DWP files on macOS (PR #139554) In-Reply-To: Message-ID: <68221b9b.050a0220.11bc41.9932@mx.google.com> ================ @@ -4211,6 +4211,9 @@ SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() { const std::shared_ptr &SymbolFileDWARF::GetDwpSymbolFile() { llvm::call_once(m_dwp_symfile_once_flag, [this]() { + if (m_objfile_sp->GetArchitecture().GetTriple().isAppleMachO()) ---------------- adrian-prantl wrote: Should this be a check for the ObjectFile subclass instead? https://github.com/llvm/llvm-project/pull/139554 From lldb-commits at lists.llvm.org Mon May 12 09:03:08 2025 From: lldb-commits at lists.llvm.org (Adrian Prantl via lldb-commits) Date: Mon, 12 May 2025 09:03:08 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][SymbolFileDWARF] Don't search for DWP files on macOS (PR #139554) In-Reply-To: Message-ID: <68221bbc.170a0220.6d070.6c5f@mx.google.com> ================ @@ -4211,6 +4211,9 @@ SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() { const std::shared_ptr &SymbolFileDWARF::GetDwpSymbolFile() { llvm::call_once(m_dwp_symfile_once_flag, [this]() { + if (m_objfile_sp->GetArchitecture().GetTriple().isAppleMachO()) ---------------- adrian-prantl wrote: @JDevlieghere Maybe you have a better layering suggestion? https://github.com/llvm/llvm-project/pull/139554 From lldb-commits at lists.llvm.org Mon May 12 09:12:56 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 09:12:56 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb]Make `list` command work with headers when possible. (PR #139002) In-Reply-To: Message-ID: <68221e08.170a0220.e44e5.6b83@mx.google.com> labath wrote: > Leaving the line-number as `0` somehow result in it couldn't find the file! (Changing it to the right line number - or anything non-zero, on the other hand works). Any idea why? Line zero means "I don't know", so it's possible that it's treated specially (you could step through the code to see if it bails out somewhere). Maybe we should use line 1 than as that's the first real line number? https://github.com/llvm/llvm-project/pull/139002 From lldb-commits at lists.llvm.org Mon May 12 09:17:37 2025 From: lldb-commits at lists.llvm.org (Michael Buch via lldb-commits) Date: Mon, 12 May 2025 09:17:37 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][SymbolFileDWARF] Don't search for DWP files on macOS (PR #139554) In-Reply-To: Message-ID: <68221f21.170a0220.ce8e8.7ffe@mx.google.com> ================ @@ -4211,6 +4211,9 @@ SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() { const std::shared_ptr &SymbolFileDWARF::GetDwpSymbolFile() { llvm::call_once(m_dwp_symfile_once_flag, [this]() { + if (m_objfile_sp->GetArchitecture().GetTriple().isAppleMachO()) ---------------- Michael137 wrote: That was my first inclination. But then I was reading the discussion at https://github.com/llvm/llvm-project/pull/139170#issuecomment-2871870612 and was going to see where that goes https://github.com/llvm/llvm-project/pull/139554 From lldb-commits at lists.llvm.org Mon May 12 09:17:57 2025 From: lldb-commits at lists.llvm.org (Michael Buch via lldb-commits) Date: Mon, 12 May 2025 09:17:57 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][SymbolFileDWARF] Don't search for DWP files on macOS (PR #139554) In-Reply-To: Message-ID: <68221f35.170a0220.d0ce7.6a47@mx.google.com> https://github.com/Michael137 edited https://github.com/llvm/llvm-project/pull/139554 From lldb-commits at lists.llvm.org Mon May 12 09:18:15 2025 From: lldb-commits at lists.llvm.org (Michael Buch via lldb-commits) Date: Mon, 12 May 2025 09:18:15 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][SymbolFileDWARF] Don't search for DWP files on macOS (PR #139554) In-Reply-To: Message-ID: <68221f47.170a0220.3d90e6.e176@mx.google.com> https://github.com/Michael137 edited https://github.com/llvm/llvm-project/pull/139554 From lldb-commits at lists.llvm.org Mon May 12 09:18:47 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Mon, 12 May 2025 09:18:47 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit tests for protocol types (PR #139502) In-Reply-To: Message-ID: <68221f67.170a0220.301af4.679d@mx.google.com> ================ @@ -0,0 +1,268 @@ +//===-- ProtocolTypesTest.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 "Protocol/ProtocolTypes.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap::protocol; + +TEST(ProtocolTypesTest, ExceptionBreakpointsFilter) { + ExceptionBreakpointsFilter filter; + filter.filter = "testFilter"; + filter.label = "Test Filter"; + filter.description = "This is a test filter"; + filter.defaultState = true; + filter.supportsCondition = true; + filter.conditionDescription = "Condition for test filter"; + + llvm::json::Value value = toJSON(filter); + const json::Object *obj = value.getAsObject(); + ASSERT_NE(obj, nullptr); + + EXPECT_EQ(obj->getString("filter"), "testFilter"); + EXPECT_EQ(obj->getString("label"), "Test Filter"); + EXPECT_EQ(obj->getString("description"), "This is a test filter"); + EXPECT_EQ(obj->getBoolean("default"), true); + EXPECT_EQ(obj->getBoolean("supportsCondition"), true); + EXPECT_EQ(obj->getString("conditionDescription"), + "Condition for test filter"); ---------------- ashgti wrote: Should we make a helper for matching these with a string literal? Something like: ``` MATCHER_P(equalToDAP, msg, "Protocol Message " + llvm::to_string(msg)) { if (toJSON(arg) != json::parse(msg)) { *result_listener << llvm::formatv("expected:\n{0:2}\ngot\n{1:2}", toJSON(msg), toJSON(arg)) .str(); return false; } return true; } ``` And then use: ``` EXPECT_THAT(filter, equalToDAP(R"json({"filter": "testFilter",...})json")); ``` I think that might help improve the brevity of these tests and help account for some additional fields or defaults that may appear in some structs. We might be able to make the test case into a `vector>` to make it easier to add cases as well. https://github.com/llvm/llvm-project/pull/139502 From lldb-commits at lists.llvm.org Mon May 12 09:32:29 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 09:32:29 -0700 (PDT) Subject: [Lldb-commits] [lldb] 74a5884 - [lldb][TypeSystemClang][NFC] Use GetNumBaseClasses in TypeSystemClang::GetNumChildren (#139552) Message-ID: <6822229d.170a0220.2f9c30.8aed@mx.google.com> Author: Michael Buch Date: 2025-05-12T17:32:26+01:00 New Revision: 74a588464c133447b2d644cee7910084f4f57065 URL: https://github.com/llvm/llvm-project/commit/74a588464c133447b2d644cee7910084f4f57065 DIFF: https://github.com/llvm/llvm-project/commit/74a588464c133447b2d644cee7910084f4f57065.diff LOG: [lldb][TypeSystemClang][NFC] Use GetNumBaseClasses in TypeSystemClang::GetNumChildren (#139552) `TypeSystemClang::GetNumBaseClasses` does exactly the same base-class accounting that we were doing in GetNumChildren. So re-use it. Added: Modified: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp Removed: ################################################################################ diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index d24f3726b1d25..28081e8f6b965 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -5355,33 +5355,9 @@ TypeSystemClang::GetNumChildren(lldb::opaque_compiler_type_t type, assert(record_decl); const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast(record_decl); - if (cxx_record_decl) { - if (omit_empty_base_classes) { - // Check each base classes to see if it or any of its base classes - // contain any fields. This can help limit the noise in variable - // views by not having to show base classes that contain no members. - clang::CXXRecordDecl::base_class_const_iterator base_class, - base_class_end; - for (base_class = cxx_record_decl->bases_begin(), - base_class_end = cxx_record_decl->bases_end(); - base_class != base_class_end; ++base_class) { - const clang::CXXRecordDecl *base_class_decl = - llvm::cast( - base_class->getType() - ->getAs() - ->getDecl()); - - // Skip empty base classes - if (!TypeSystemClang::RecordHasFields(base_class_decl)) - continue; - num_children++; - } - } else { - // Include all base classes - num_children += cxx_record_decl->getNumBases(); - } - } + num_children += + GetNumBaseClasses(cxx_record_decl, omit_empty_base_classes); num_children += std::distance(record_decl->field_begin(), record_decl->field_end()); } else From lldb-commits at lists.llvm.org Mon May 12 09:32:32 2025 From: lldb-commits at lists.llvm.org (Michael Buch via lldb-commits) Date: Mon, 12 May 2025 09:32:32 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][TypeSystemClang][NFC] Use GetNumBaseClasses in TypeSystemClang::GetNumChildren (PR #139552) In-Reply-To: Message-ID: <682222a0.170a0220.274bf7.ae11@mx.google.com> https://github.com/Michael137 closed https://github.com/llvm/llvm-project/pull/139552 From lldb-commits at lists.llvm.org Mon May 12 09:36:27 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Mon, 12 May 2025 09:36:27 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit tests for protocol types (PR #139502) In-Reply-To: Message-ID: <6822238b.170a0220.e301c.7551@mx.google.com> ================ @@ -0,0 +1,268 @@ +//===-- ProtocolTypesTest.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 "Protocol/ProtocolTypes.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap::protocol; + +TEST(ProtocolTypesTest, ExceptionBreakpointsFilter) { + ExceptionBreakpointsFilter filter; + filter.filter = "testFilter"; + filter.label = "Test Filter"; + filter.description = "This is a test filter"; + filter.defaultState = true; + filter.supportsCondition = true; + filter.conditionDescription = "Condition for test filter"; + + llvm::json::Value value = toJSON(filter); + const json::Object *obj = value.getAsObject(); + ASSERT_NE(obj, nullptr); + + EXPECT_EQ(obj->getString("filter"), "testFilter"); + EXPECT_EQ(obj->getString("label"), "Test Filter"); + EXPECT_EQ(obj->getString("description"), "This is a test filter"); + EXPECT_EQ(obj->getBoolean("default"), true); + EXPECT_EQ(obj->getBoolean("supportsCondition"), true); + EXPECT_EQ(obj->getString("conditionDescription"), + "Condition for test filter"); ---------------- JDevlieghere wrote: I was thinking about ways to make the test easier to write. I'm not super thrilled about putting JSON into the tests but maybe it's not worse than how verbose the current approach is. I think my preference would be to have what I did for the `Source` struct: if every type has both a fromJSON and toJSON, then we can just roundtrip every object. https://github.com/llvm/llvm-project/pull/139502 From lldb-commits at lists.llvm.org Mon May 12 09:38:29 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Mon, 12 May 2025 09:38:29 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Split lldb-dap into library and tool (NFC) (PR #139402) In-Reply-To: Message-ID: <68222405.170a0220.328d3.e2a8@mx.google.com> ashgti wrote: Hmm after a sync, this started causing my cmake to fail to configure with: ``` $ cmake --fresh -B ~/Projects/lldb-build -G Ninja \ -C ~/Projects/llvm-project/lldb/cmake/caches/Apple-lldb-macOS.cmake \ -DCMAKE_EXPORT_COMPILE_COMMANDS=1 \ -DCMAKE_OSX_DEPLOYMENT_TARGET=10.12 \ -DLLVM_ENABLE_PROJECTS="clang;lld;lldb;clang-tools-extra" \ -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;compiler-rt;libunwind" \ -DLLDB_USE_SYSTEM_DEBUGSERVER:BOOL=true \ -DLIBCXX_HARDENING_MODE=none \ -DLLVM_LIT_ARGS=-v \ -DLIBCXX_ENABLE_SHARED:BOOL=true \ -DCMAKE_BUILD_TYPE=Debug \ -DLLVM_ENABLE_ASSERTIONS:BOOL=true \ ~/Projects/llvm-project/llvm loading initial cache file /Users/harjohn/Projects/llvm-project/lldb/cmake/caches/Apple-lldb-macOS.cmake ... CMake Error at /Users/harjohn/Projects/llvm-project/lldb/cmake/modules/AddLLDB.cmake:352 (set_target_properties): set_target_properties Can not find target to add properties to: lldb-dap Call Stack (most recent call first): /Users/harjohn/Projects/llvm-project/lldb/tools/lldb-dap/CMakeLists.txt:91 (lldb_setup_rpaths) ``` Adding `-DLLDB_BUILD_FRAMEWORK:BOOL=false` fixed this, but I think the rpath may not be correct. https://github.com/llvm/llvm-project/pull/139402 From lldb-commits at lists.llvm.org Mon May 12 09:43:07 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Mon, 12 May 2025 09:43:07 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Split lldb-dap into library and tool (NFC) (PR #139402) In-Reply-To: Message-ID: <6822251b.170a0220.1166a9.73e4@mx.google.com> JDevlieghere wrote: I'll take a look. I see it failing here too: https://green.lab.llvm.org/job/llvm.org/view/LLDB/job/lldb-cmake-standalone/1688/ https://github.com/llvm/llvm-project/pull/139402 From lldb-commits at lists.llvm.org Mon May 12 09:51:59 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Mon, 12 May 2025 09:51:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] fb9b43a - [lldb-dap] Fix the framework build Message-ID: <6822272f.050a0220.2409e4.d332@mx.google.com> Author: Jonas Devlieghere Date: 2025-05-12T09:51:15-07:00 New Revision: fb9b43a0c56de9b1f36e862565c33e0ad637fb36 URL: https://github.com/llvm/llvm-project/commit/fb9b43a0c56de9b1f36e862565c33e0ad637fb36 DIFF: https://github.com/llvm/llvm-project/commit/fb9b43a0c56de9b1f36e862565c33e0ad637fb36.diff LOG: [lldb-dap] Fix the framework build I forgot to remove the original logic after moving it into the tool subdirectory. Added: Modified: lldb/tools/lldb-dap/CMakeLists.txt Removed: ################################################################################ diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 608166bf0e0dd..224d64b83b7d4 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -84,18 +84,3 @@ if(LLDB_DAP_WELCOME_MESSAGE) PRIVATE -DLLDB_DAP_WELCOME_MESSAGE=\"${LLDB_DAP_WELCOME_MESSAGE}\") endif() - -if(LLDB_BUILD_FRAMEWORK) - # In the build-tree, we know the exact path to the framework directory. - # The installed framework can be in diff erent locations. - lldb_setup_rpaths(lldb-dap - BUILD_RPATH - "${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}" - INSTALL_RPATH - "@loader_path/../../../SharedFrameworks" - "@loader_path/../../System/Library/PrivateFrameworks" - "@loader_path/../../Library/PrivateFrameworks" - ) -endif() - -add_subdirectory(tool) From lldb-commits at lists.llvm.org Mon May 12 09:52:49 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Mon, 12 May 2025 09:52:49 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Split lldb-dap into library and tool (NFC) (PR #139402) In-Reply-To: Message-ID: <68222761.630a0220.1452f9.fec5@mx.google.com> JDevlieghere wrote: Fixed by fb9b43a0c56de9b1f36e862565c33e0ad637fb36 https://github.com/llvm/llvm-project/pull/139402 From lldb-commits at lists.llvm.org Mon May 12 10:03:58 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Mon, 12 May 2025 10:03:58 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit tests for protocol types (PR #139502) In-Reply-To: Message-ID: <682229fe.170a0220.385598.81c6@mx.google.com> ================ @@ -0,0 +1,268 @@ +//===-- ProtocolTypesTest.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 "Protocol/ProtocolTypes.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap::protocol; + +TEST(ProtocolTypesTest, ExceptionBreakpointsFilter) { + ExceptionBreakpointsFilter filter; + filter.filter = "testFilter"; + filter.label = "Test Filter"; + filter.description = "This is a test filter"; + filter.defaultState = true; + filter.supportsCondition = true; + filter.conditionDescription = "Condition for test filter"; + + llvm::json::Value value = toJSON(filter); + const json::Object *obj = value.getAsObject(); + ASSERT_NE(obj, nullptr); + + EXPECT_EQ(obj->getString("filter"), "testFilter"); + EXPECT_EQ(obj->getString("label"), "Test Filter"); + EXPECT_EQ(obj->getString("description"), "This is a test filter"); + EXPECT_EQ(obj->getBoolean("default"), true); + EXPECT_EQ(obj->getBoolean("supportsCondition"), true); + EXPECT_EQ(obj->getString("conditionDescription"), + "Condition for test filter"); ---------------- ashgti wrote: We could make it more of a convention to have both going forward for testing purposes. https://github.com/llvm/llvm-project/pull/139502 From lldb-commits at lists.llvm.org Mon May 12 10:04:16 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Mon, 12 May 2025 10:04:16 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit tests for protocol types (PR #139502) In-Reply-To: Message-ID: <68222a10.050a0220.2409e4.d935@mx.google.com> https://github.com/ashgti approved this pull request. https://github.com/llvm/llvm-project/pull/139502 From lldb-commits at lists.llvm.org Mon May 12 10:07:30 2025 From: lldb-commits at lists.llvm.org (Jan Svoboda via lldb-commits) Date: Mon, 12 May 2025 10:07:30 -0700 (PDT) Subject: [Lldb-commits] [clang] [clang-tools-extra] [lldb] [clang] Remove intrusive reference count from `DiagnosticOptions` (PR #139584) Message-ID: https://github.com/jansvoboda11 created https://github.com/llvm/llvm-project/pull/139584 The `DiagnosticOptions` class is currently intrusively reference-counted, which makes reasoning about its lifetime very difficult in some cases. For example, `CompilerInvocation` owns the `DiagnosticOptions` instance (wrapped in `llvm::IntrusiveRefCntPtr`) and only exposes an accessor returning `DiagnosticOptions &`. One would think this gives `CompilerInvocation` exclusive ownership of the object, but that's not the case: ```c++ void shareOwnership(CompilerInvocation &CI) { llvm::IntrusiveRefCntPtr CoOwner = &CI.getDiagnosticOptions(); // ... } ``` This is a perfectly valid pattern that is being actually used in the codebase. I would like to ensure the ownership of `DiagnosticOptions` by `CompilerInvocation` is guaranteed to be exclusive. This can be leveraged for a copy-on-write optimization later on. This PR changes usages of `DiagnosticOptions` across `clang`, `clang-tools-extra` and `lldb` to not be intrusively reference-counted. Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Mon May 12 10:08:04 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 10:08:04 -0700 (PDT) Subject: [Lldb-commits] [clang] [clang-tools-extra] [lldb] [clang] Remove intrusive reference count from `DiagnosticOptions` (PR #139584) In-Reply-To: Message-ID: <68222af4.170a0220.1330.798a@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-clang-format @llvm/pr-subscribers-clang Author: Jan Svoboda (jansvoboda11)
Changes The `DiagnosticOptions` class is currently intrusively reference-counted, which makes reasoning about its lifetime very difficult in some cases. For example, `CompilerInvocation` owns the `DiagnosticOptions` instance (wrapped in `llvm::IntrusiveRefCntPtr`) and only exposes an accessor returning `DiagnosticOptions &`. One would think this gives `CompilerInvocation` exclusive ownership of the object, but that's not the case: ```c++ void shareOwnership(CompilerInvocation &CI) { llvm::IntrusiveRefCntPtr<DiagnosticOptions> CoOwner = &CI.getDiagnosticOptions(); // ... } ``` This is a perfectly valid pattern that is being actually used in the codebase. I would like to ensure the ownership of `DiagnosticOptions` by `CompilerInvocation` is guaranteed to be exclusive. This can be leveraged for a copy-on-write optimization later on. This PR changes usages of `DiagnosticOptions` across `clang`, `clang-tools-extra` and `lldb` to not be intrusively reference-counted. --- Patch is 189.21 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/139584.diff 134 Files Affected: - (modified) clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp (+2-2) - (modified) clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp (+3-3) - (modified) clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp (+3-3) - (modified) clang-tools-extra/clang-move/tool/ClangMove.cpp (+3-3) - (modified) clang-tools-extra/clang-query/Query.cpp (+1-1) - (modified) clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp (+3-3) - (modified) clang-tools-extra/clang-tidy/ClangTidy.cpp (+12-12) - (modified) clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp (+2-2) - (modified) clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h (+4-1) - (modified) clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp (+1-1) - (modified) clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h (+1) - (modified) clang-tools-extra/clangd/Compiler.cpp (+3-2) - (modified) clang-tools-extra/clangd/ModulesBuilder.cpp (+2-2) - (modified) clang-tools-extra/clangd/ParsedAST.cpp (+2-1) - (modified) clang-tools-extra/clangd/Preamble.cpp (+1-1) - (modified) clang-tools-extra/clangd/SystemIncludeExtractor.cpp (+2-1) - (modified) clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp (+2-1) - (modified) clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp (+2-1) - (modified) clang-tools-extra/include-cleaner/unittests/RecordTest.cpp (+2-2) - (modified) clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp (+3-3) - (modified) clang-tools-extra/modularize/ModularizeUtilities.cpp (+2-4) - (modified) clang-tools-extra/modularize/ModularizeUtilities.h (+1-1) - (modified) clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp (+2-2) - (modified) clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp (+9-9) - (modified) clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h (+3-3) - (modified) clang/include/clang/Basic/Diagnostic.h (+3-3) - (modified) clang/include/clang/Basic/DiagnosticOptions.h (+1-3) - (modified) clang/include/clang/Basic/SourceManager.h (+1) - (modified) clang/include/clang/Frontend/ASTUnit.h (+2) - (modified) clang/include/clang/Frontend/CompilerInstance.h (+1-1) - (modified) clang/include/clang/Frontend/CompilerInvocation.h (+1-1) - (modified) clang/include/clang/Frontend/DiagnosticRenderer.h (+3-4) - (modified) clang/include/clang/Frontend/LogDiagnosticPrinter.h (+2-2) - (modified) clang/include/clang/Frontend/SARIFDiagnostic.h (+1-1) - (modified) clang/include/clang/Frontend/SARIFDiagnosticPrinter.h (+2-2) - (modified) clang/include/clang/Frontend/SerializedDiagnosticPrinter.h (+1-1) - (modified) clang/include/clang/Frontend/TextDiagnostic.h (+1-1) - (modified) clang/include/clang/Frontend/TextDiagnosticPrinter.h (+2-2) - (modified) clang/include/clang/Serialization/ASTReader.h (+4-5) - (modified) clang/lib/Basic/Diagnostic.cpp (+5-5) - (modified) clang/lib/Basic/SourceManager.cpp (+2-2) - (modified) clang/lib/CrossTU/CrossTranslationUnit.cpp (+9-9) - (modified) clang/lib/Frontend/ASTMerge.cpp (+4-5) - (modified) clang/lib/Frontend/ASTUnit.cpp (+2) - (modified) clang/lib/Frontend/ChainedIncludesSource.cpp (+2-2) - (modified) clang/lib/Frontend/CompilerInstance.cpp (+13-14) - (modified) clang/lib/Frontend/CompilerInvocation.cpp (+7-20) - (modified) clang/lib/Frontend/CreateInvocationFromCommandLine.cpp (+9-5) - (modified) clang/lib/Frontend/DiagnosticRenderer.cpp (+8-9) - (modified) clang/lib/Frontend/FrontendAction.cpp (+2-3) - (modified) clang/lib/Frontend/FrontendActions.cpp (+8-8) - (modified) clang/lib/Frontend/LogDiagnosticPrinter.cpp (+2-2) - (modified) clang/lib/Frontend/SARIFDiagnostic.cpp (+2-2) - (modified) clang/lib/Frontend/SARIFDiagnosticPrinter.cpp (+3-4) - (modified) clang/lib/Frontend/SerializedDiagnosticPrinter.cpp (+15-14) - (modified) clang/lib/Frontend/TextDiagnostic.cpp (+39-40) - (modified) clang/lib/Frontend/TextDiagnosticPrinter.cpp (+6-9) - (modified) clang/lib/Interpreter/Interpreter.cpp (+4-4) - (modified) clang/lib/Rewrite/HTMLRewrite.cpp (+2-2) - (modified) clang/lib/Serialization/ASTReader.cpp (+12-13) - (modified) clang/lib/Testing/TestAST.cpp (+1-1) - (modified) clang/lib/Tooling/CompilationDatabase.cpp (+4-4) - (modified) clang/lib/Tooling/Core/Replacement.cpp (+2-2) - (modified) clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp (+3-3) - (modified) clang/lib/Tooling/Refactoring.cpp (+4-4) - (modified) clang/lib/Tooling/Tooling.cpp (+4-4) - (modified) clang/tools/c-index-test/core_main.cpp (+4-2) - (modified) clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp (+7-5) - (modified) clang/tools/clang-format/ClangFormat.cpp (+4-4) - (modified) clang/tools/clang-import-test/clang-import-test.cpp (+2-2) - (modified) clang/tools/clang-installapi/ClangInstallAPI.cpp (+4-4) - (modified) clang/tools/clang-scan-deps/ClangScanDeps.cpp (+5-4) - (modified) clang/tools/diagtool/ShowEnabledWarnings.cpp (+3-3) - (modified) clang/tools/diagtool/TreeView.cpp (+2-2) - (modified) clang/tools/driver/cc1_main.cpp (+2-2) - (modified) clang/tools/driver/cc1as_main.cpp (+4-4) - (modified) clang/tools/driver/cc1gen_reproducer_main.cpp (+3-3) - (modified) clang/tools/driver/driver.cpp (+5-6) - (modified) clang/tools/libclang/CIndex.cpp (+5-4) - (modified) clang/tools/libclang/CIndexCodeCompletion.cpp (+5-5) - (modified) clang/tools/libclang/CIndexDiagnostic.cpp (+8-9) - (modified) clang/tools/libclang/Indexing.cpp (+2-1) - (modified) clang/unittests/AST/ASTVectorTest.cpp (+2-1) - (modified) clang/unittests/AST/CommentLexer.cpp (+4-6) - (modified) clang/unittests/AST/CommentParser.cpp (+4-6) - (modified) clang/unittests/AST/CommentTextTest.cpp (+2-1) - (modified) clang/unittests/AST/ExternalASTSourceTest.cpp (+2-2) - (modified) clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp (+2-3) - (modified) clang/unittests/Analysis/MacroExpansionContextTest.cpp (+3-3) - (modified) clang/unittests/Analysis/UnsafeBufferUsageTest.cpp (+2-1) - (modified) clang/unittests/Basic/DiagnosticTest.cpp (+14-9) - (modified) clang/unittests/Basic/SarifTest.cpp (+3-3) - (modified) clang/unittests/Basic/SourceManagerTest.cpp (+4-5) - (modified) clang/unittests/Driver/DXCModeTest.cpp (+6-6) - (modified) clang/unittests/Driver/SanitizerArgsTest.cpp (+3-4) - (modified) clang/unittests/Driver/SimpleDiagnosticConsumer.h (+2-3) - (modified) clang/unittests/Driver/ToolChainTest.cpp (+36-35) - (modified) clang/unittests/Frontend/ASTUnitTest.cpp (+14-13) - (modified) clang/unittests/Frontend/CompilerInstanceTest.cpp (+6-5) - (modified) clang/unittests/Frontend/CompilerInvocationTest.cpp (+2-1) - (modified) clang/unittests/Frontend/OutputStreamTest.cpp (+6-6) - (modified) clang/unittests/Frontend/PCHPreambleTest.cpp (+3-1) - (modified) clang/unittests/Frontend/ReparseWorkingDirTest.cpp (+2-1) - (modified) clang/unittests/Frontend/SearchPathTest.cpp (+2-2) - (modified) clang/unittests/Frontend/TextDiagnosticTest.cpp (+4-4) - (modified) clang/unittests/Frontend/UtilsTest.cpp (+5-4) - (modified) clang/unittests/Interpreter/InterpreterTest.cpp (+9-6) - (modified) clang/unittests/Lex/HeaderSearchTest.cpp (+2-1) - (modified) clang/unittests/Lex/LexerTest.cpp (+4-6) - (modified) clang/unittests/Lex/ModuleDeclStateTest.cpp (+2-1) - (modified) clang/unittests/Lex/PPCallbacksTest.cpp (+4-4) - (modified) clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp (+4-6) - (modified) clang/unittests/Lex/PPDependencyDirectivesTest.cpp (+2-1) - (modified) clang/unittests/Lex/PPMemoryAllocationsTest.cpp (+2-1) - (modified) clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp (+2-2) - (modified) clang/unittests/Sema/SemaNoloadLookupTest.cpp (+2-2) - (modified) clang/unittests/Serialization/ForceCheckFileInputTest.cpp (+4-4) - (modified) clang/unittests/Serialization/LoadSpecLazilyTest.cpp (+2-1) - (modified) clang/unittests/Serialization/ModuleCacheTest.cpp (+4-2) - (modified) clang/unittests/Serialization/NoCommentsTest.cpp (+2-1) - (modified) clang/unittests/Serialization/PreambleInNamedModulesTest.cpp (+2-1) - (modified) clang/unittests/Serialization/VarDeclConstantInitTest.cpp (+2-1) - (modified) clang/unittests/Support/TimeProfilerTest.cpp (+2-2) - (modified) clang/unittests/Tooling/RewriterTestContext.h (+4-5) - (modified) clang/unittests/Tooling/Syntax/TokensTest.cpp (+2-1) - (modified) clang/unittests/Tooling/Syntax/TreeTestBase.cpp (+1-1) - (modified) clang/unittests/Tooling/Syntax/TreeTestBase.h (+2-2) - (modified) clang/unittests/Tooling/ToolingTest.cpp (+4-4) - (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp (+5-5) - (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp (+1-2) - (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp (+13-8) - (modified) lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp (+1-2) - (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp (+2-1) - (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h (+1) ``````````diff diff --git a/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp b/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp index 68b5743c6540f..062e236d3e51f 100644 --- a/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp +++ b/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp @@ -96,9 +96,9 @@ int main(int argc, char **argv) { cl::SetVersionPrinter(printVersion); cl::ParseCommandLineOptions(argc, argv); - IntrusiveRefCntPtr DiagOpts(new DiagnosticOptions()); + DiagnosticOptions DiagOpts; DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr(new DiagnosticIDs()), DiagOpts.get()); + IntrusiveRefCntPtr(new DiagnosticIDs()), DiagOpts); // Determine a formatting style from options. auto FormatStyleOrError = format::getStyle(FormatStyleOpt, FormatStyleConfig, diff --git a/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp b/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp index 22d26db0c11bc..2a8fe2d06d185 100644 --- a/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp +++ b/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp @@ -126,10 +126,10 @@ int main(int argc, const char **argv) { if (int Result = Tool.run(Factory.get())) return Result; LangOptions DefaultLangOptions; - IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); - clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts); + DiagnosticOptions DiagOpts; + clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts); DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr(new DiagnosticIDs()), &*DiagOpts, + IntrusiveRefCntPtr(new DiagnosticIDs()), DiagOpts, &DiagnosticPrinter, false); auto &FileMgr = Tool.getFiles(); SourceManager Sources(Diagnostics, FileMgr); diff --git a/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp b/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp index 6e51f25a66407..746ba7bcea015 100644 --- a/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp +++ b/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp @@ -455,9 +455,9 @@ int includeFixerMain(int argc, const char **argv) { } // Set up a new source manager for applying the resulting replacements. - IntrusiveRefCntPtr DiagOpts(new DiagnosticOptions); - DiagnosticsEngine Diagnostics(new DiagnosticIDs, &*DiagOpts); - TextDiagnosticPrinter DiagnosticPrinter(outs(), &*DiagOpts); + DiagnosticOptions DiagOpts; + DiagnosticsEngine Diagnostics(new DiagnosticIDs, DiagOpts); + TextDiagnosticPrinter DiagnosticPrinter(outs(), DiagOpts); SourceManager SM(Diagnostics, tool.getFiles()); Diagnostics.setClient(&DiagnosticPrinter, false); diff --git a/clang-tools-extra/clang-move/tool/ClangMove.cpp b/clang-tools-extra/clang-move/tool/ClangMove.cpp index 655ea81ee37d4..750eb952714f7 100644 --- a/clang-tools-extra/clang-move/tool/ClangMove.cpp +++ b/clang-tools-extra/clang-move/tool/ClangMove.cpp @@ -176,10 +176,10 @@ int main(int argc, const char **argv) { } } - IntrusiveRefCntPtr DiagOpts(new DiagnosticOptions()); - clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts); + DiagnosticOptions DiagOpts; + clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts); DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr(new DiagnosticIDs()), &*DiagOpts, + IntrusiveRefCntPtr(new DiagnosticIDs()), DiagOpts, &DiagnosticPrinter, false); auto &FileMgr = Tool.getFiles(); SourceManager SM(Diagnostics, FileMgr); diff --git a/clang-tools-extra/clang-query/Query.cpp b/clang-tools-extra/clang-query/Query.cpp index 382aa5d6fe25e..574b64ee0f759 100644 --- a/clang-tools-extra/clang-query/Query.cpp +++ b/clang-tools-extra/clang-query/Query.cpp @@ -172,7 +172,7 @@ bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const { clang::SourceRange R = BI->second.getSourceRange(); if (R.isValid()) { TextDiagnostic TD(OS, AST->getASTContext().getLangOpts(), - &AST->getDiagnostics().getDiagnosticOptions()); + AST->getDiagnostics().getDiagnosticOptions()); TD.emitDiagnostic( FullSourceLoc(R.getBegin(), AST->getSourceManager()), DiagnosticsEngine::Note, "\"" + BI->first + "\" binds here", diff --git a/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp b/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp index 5b77ee7b5738c..03502525417b2 100644 --- a/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp +++ b/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp @@ -72,10 +72,10 @@ int main(int argc, const char **argv) { int ExitCode = Tool.run(Factory.get()); LangOptions DefaultLangOptions; - IntrusiveRefCntPtr DiagOpts(new DiagnosticOptions()); - TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts); + DiagnosticOptions DiagOpts; + TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts); DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr(new DiagnosticIDs()), &*DiagOpts, + IntrusiveRefCntPtr(new DiagnosticIDs()), DiagOpts, &DiagnosticPrinter, false); auto &FileMgr = Tool.getFiles(); diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp index 733a53a0f5dcc..26f9afbc0880e 100644 --- a/clang-tools-extra/clang-tidy/ClangTidy.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -97,15 +97,14 @@ class ErrorReporter { ErrorReporter(ClangTidyContext &Context, FixBehaviour ApplyFixes, llvm::IntrusiveRefCntPtr BaseFS) : Files(FileSystemOptions(), std::move(BaseFS)), - DiagOpts(new DiagnosticOptions()), - DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), &*DiagOpts)), - Diags(IntrusiveRefCntPtr(new DiagnosticIDs), &*DiagOpts, + DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), DiagOpts)), + Diags(IntrusiveRefCntPtr(new DiagnosticIDs), DiagOpts, DiagPrinter), SourceMgr(Diags, Files), Context(Context), ApplyFixes(ApplyFixes) { - DiagOpts->ShowColors = Context.getOptions().UseColor.value_or( + DiagOpts.ShowColors = Context.getOptions().UseColor.value_or( llvm::sys::Process::StandardOutHasColors()); DiagPrinter->BeginSourceFile(LangOpts); - if (DiagOpts->ShowColors && !llvm::sys::Process::StandardOutIsDisplayed()) { + if (DiagOpts.ShowColors && !llvm::sys::Process::StandardOutIsDisplayed()) { llvm::sys::Process::UseANSIEscapeCodes(true); } } @@ -308,7 +307,7 @@ class ErrorReporter { FileManager Files; LangOptions LangOpts; // FIXME: use langopts from each original file - IntrusiveRefCntPtr DiagOpts; + DiagnosticOptions DiagOpts; DiagnosticConsumer *DiagPrinter; DiagnosticsEngine Diags; SourceManager SourceMgr; @@ -516,10 +515,10 @@ getCheckOptions(const ClangTidyOptions &Options, Options), AllowEnablingAnalyzerAlphaCheckers); ClangTidyDiagnosticConsumer DiagConsumer(Context); - DiagnosticsEngine DE(llvm::makeIntrusiveRefCnt(), - llvm::makeIntrusiveRefCnt(), + auto DiagOpts = std::make_unique(); + DiagnosticsEngine DE(llvm::makeIntrusiveRefCnt(), *DiagOpts, &DiagConsumer, /*ShouldOwnClient=*/false); - Context.setDiagnosticsEngine(&DE); + Context.setDiagnosticsEngine(std::move(DiagOpts), &DE); ClangTidyASTConsumerFactory Factory(Context); return Factory.getCheckOptions(); } @@ -558,9 +557,10 @@ runClangTidy(clang::tidy::ClangTidyContext &Context, Context.setProfileStoragePrefix(StoreCheckProfile); ClangTidyDiagnosticConsumer DiagConsumer(Context, nullptr, true, ApplyAnyFix); - DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions(), - &DiagConsumer, /*ShouldOwnClient=*/false); - Context.setDiagnosticsEngine(&DE); + auto DiagOpts = std::make_unique(); + DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer, + /*ShouldOwnClient=*/false); + Context.setDiagnosticsEngine(std::move(DiagOpts), &DE); Tool.setDiagnosticConsumer(&DiagConsumer); class ActionFactory : public FrontendActionFactory { diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp index b216970bfbd8c..a0253a5fd1a48 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -49,7 +49,7 @@ namespace { class ClangTidyDiagnosticRenderer : public DiagnosticRenderer { public: ClangTidyDiagnosticRenderer(const LangOptions &LangOpts, - DiagnosticOptions *DiagOpts, + DiagnosticOptions &DiagOpts, ClangTidyError &Error) : DiagnosticRenderer(LangOpts, DiagOpts), Error(Error) {} @@ -429,7 +429,7 @@ void ClangTidyDiagnosticConsumer::HandleDiagnostic( forwardDiagnostic(Info); } else { ClangTidyDiagnosticRenderer Converter( - Context.getLangOpts(), &Context.DiagEngine->getDiagnosticOptions(), + Context.getLangOpts(), Context.DiagEngine->getDiagnosticOptions(), Errors.back()); SmallString<100> Message; Info.FormatDiagnostic(Message); diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h index d6cf6a2b2731e..bd7a1bf2c11c7 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -75,7 +75,9 @@ class ClangTidyContext { /// Sets the DiagnosticsEngine that diag() will emit diagnostics to. // FIXME: this is required initialization, and should be a constructor param. // Fix the context -> diag engine -> consumer -> context initialization cycle. - void setDiagnosticsEngine(DiagnosticsEngine *DiagEngine) { + void setDiagnosticsEngine(std::unique_ptr DiagOpts, + DiagnosticsEngine *DiagEngine) { + this->DiagOpts = std::move(DiagOpts); this->DiagEngine = DiagEngine; } @@ -231,6 +233,7 @@ class ClangTidyContext { // Writes to Stats. friend class ClangTidyDiagnosticConsumer; + std::unique_ptr DiagOpts = nullptr; DiagnosticsEngine *DiagEngine = nullptr; std::unique_ptr OptionsProvider; diff --git a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp index 03a3e8404e069..6a84704434c33 100644 --- a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp +++ b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp @@ -71,7 +71,7 @@ ExpandModularHeadersPPCallbacks::ExpandModularHeadersPPCallbacks( InMemoryFs(new llvm::vfs::InMemoryFileSystem), Sources(Compiler.getSourceManager()), // Forward the new diagnostics to the original DiagnosticConsumer. - Diags(new DiagnosticIDs, new DiagnosticOptions, + Diags(new DiagnosticIDs, DiagOpts, new ForwardingDiagnosticConsumer(Compiler.getDiagnosticClient())), LangOpts(Compiler.getLangOpts()), HSOpts(Compiler.getHeaderSearchOpts()) { // Add a FileSystem containing the extra files needed in place of modular diff --git a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h index a263681b3c633..c3478917ef498 100644 --- a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h +++ b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h @@ -128,6 +128,7 @@ class ExpandModularHeadersPPCallbacks : public PPCallbacks { llvm::IntrusiveRefCntPtr InMemoryFs; SourceManager &Sources; + DiagnosticOptions DiagOpts; DiagnosticsEngine Diags; LangOptions LangOpts; HeaderSearchOptions HSOpts; diff --git a/clang-tools-extra/clangd/Compiler.cpp b/clang-tools-extra/clangd/Compiler.cpp index 9be0152afd2f7..8b3865c8a8e5c 100644 --- a/clang-tools-extra/clangd/Compiler.cpp +++ b/clang-tools-extra/clangd/Compiler.cpp @@ -110,8 +110,9 @@ buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D, CIOpts.VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory); CIOpts.CC1Args = CC1Args; CIOpts.RecoverOnError = true; - CIOpts.Diags = CompilerInstance::createDiagnostics( - *CIOpts.VFS, new DiagnosticOptions, &D, false); + DiagnosticOptions DiagOpts; + CIOpts.Diags = + CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts, &D, false); CIOpts.ProbePrecompiled = false; std::unique_ptr CI = createInvocation(ArgStrs, CIOpts); if (!CI) diff --git a/clang-tools-extra/clangd/ModulesBuilder.cpp b/clang-tools-extra/clangd/ModulesBuilder.cpp index c1878f91b5e16..bf77f43bd28bb 100644 --- a/clang-tools-extra/clangd/ModulesBuilder.cpp +++ b/clang-tools-extra/clangd/ModulesBuilder.cpp @@ -187,9 +187,9 @@ bool IsModuleFileUpToDate(PathRef ModuleFilePath, HSOpts.ValidateASTInputFilesContent = true; clang::clangd::IgnoreDiagnostics IgnoreDiags; + DiagnosticOptions DiagOpts; IntrusiveRefCntPtr Diags = - CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions, - &IgnoreDiags, + CompilerInstance::createDiagnostics(*VFS, DiagOpts, &IgnoreDiags, /*ShouldOwnClient=*/false); LangOptions LangOpts; diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp index 3f63daaf400db..9e1f6bb977226 100644 --- a/clang-tools-extra/clangd/ParsedAST.cpp +++ b/clang-tools-extra/clangd/ParsedAST.cpp @@ -556,7 +556,8 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs, *AllCTFactories, Cfg.Diagnostics.ClangTidy.FastCheckFilter); CTContext.emplace(std::make_unique( tidy::ClangTidyGlobalOptions(), ClangTidyOpts)); - CTContext->setDiagnosticsEngine(&Clang->getDiagnostics()); + // The lifetime of DiagnosticOptions is managed by \c Clang. + CTContext->setDiagnosticsEngine(nullptr, &Clang->getDiagnostics()); CTContext->setASTContext(&Clang->getASTContext()); CTContext->setCurrentFile(Filename); CTContext->setSelfContainedDiags(true); diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp index ba9a53db8a0dc..7b4d63ff197e7 100644 --- a/clang-tools-extra/clangd/Preamble.cpp +++ b/clang-tools-extra/clangd/Preamble.cpp @@ -615,7 +615,7 @@ buildPreamble(PathRef FileName, CompilerInvocation CI, }); auto VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory); llvm::IntrusiveRefCntPtr PreambleDiagsEngine = - CompilerInstance::createDiagnostics(*VFS, &CI.getDiagnosticOpts(), + CompilerInstance::createDiagnostics(*VFS, CI.getDiagnosticOpts(), &PreambleDiagnostics, /*ShouldOwnClient=*/false); const Config &Cfg = Config::current(); diff --git a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp index 6417bf8765622..0b067e8b0b2b2 100644 --- a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp +++ b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp @@ -253,7 +253,8 @@ namespace { bool isValidTarget(llvm::StringRef Triple) { std::shared_ptr TargetOpts(new TargetOptions); TargetOpts->Triple = Triple.str(); - DiagnosticsEngine Diags(new DiagnosticIDs, new DiagnosticOptions, + DiagnosticOptions DiagOpts; + DiagnosticsEngine Diags(new DiagnosticIDs, DiagOpts, new IgnoringDiagConsumer); llvm::IntrusiveRefCntPtr Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts); diff --git a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp index c3e484a1a79c4..75d0ff244038d 100644 --- a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp +++ b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp @@ -298,7 +298,8 @@ TEST_F(ConfigCompileTests, DiagnosticSuppression) { "unreachable-code", "unused-variable", "typecheck_bool_condition", "unexpected_friend", "warn_alloca")); - clang::DiagnosticsEngine DiagEngine(new DiagnosticIDs, nullptr, + clang::DiagnosticOptions DiagOpts; + clang::DiagnosticsEngine DiagEngine(new DiagnosticIDs, DiagOpts, new clang::IgnoringDiagConsumer); using Diag = clang::Diagnostic; diff --git a/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp index 8bd40c1429012..e39b70224d97c 100644 --- a/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp +++ b/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp @@ -44,7 +44,8 @@ TEST(FileEdits, AbsolutePath) { for (const auto *Path : RelPaths) MemFS->addFile(Path, 0, llvm::MemoryBuffer::getMemBuffer("", Path)); FileManager FM(FileSystemOptions(), MemFS); - DiagnosticsEngine DE(new DiagnosticIDs, new DiagnosticOptions); + DiagnosticOptions DiagOpts; + DiagnosticsEngine DE(new DiagnosticIDs, DiagOpts); SourceManager SM(DE, FM); for (const auto *Path : RelPaths) { diff --git a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp index a10c0d5a54a95..91d2697712b6e 100644 --- a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp @@ -618,8 +618,8 @@ TEST_F(PragmaIncludeTest, ExportInUnnamedBuffer) { llvm::MemoryBuffer::getMemBufferCopy(Extra.getValue(), /*BufferName=*/"")); - auto DiagOpts = llvm::makeIntrusiveRefCnt(); - auto Diags = CompilerInstance::createDiagnostics(*VFS, DiagOpts.get()); + DiagnosticOptions DiagOpts; + auto Diags = CompilerInstance::createDiagnostics(*VFS, DiagOpts); auto Invocation = std::make_unique(); ASSERT_TRUE(CompilerInvocation::CreateFromArgs(*Invocation, {Filename.data()}, *Diags, "clang")); diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp index e45ea36f7938e..5223eb563e4cb 100644 --- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp @@ -85,9 +85,9 @@ std::vector testWalk(llvm::StringRef TargetCode, // For each difference, show the target point in context, like a diagnostic. std::string DiagBuf; llvm::raw_string_ostream DiagOS(DiagBuf); - auto *DiagOpts = new DiagnosticOptions(); - DiagOpts->ShowLevel = 0; - DiagOpts->ShowNoteIncludeStack = 0; + DiagnosticOptions DiagOpts; + DiagOpts.ShowLevel = 0; + DiagOpts.ShowNoteIncludeStack = 0; TextDiagnostic Diag(DiagOS, AST.context().getLangOpts(), DiagOpts); auto DiagnosePoint = [&](llvm::StringRef Message, unsigned Offset) { Diag.emitDiagnostic( diff --git a/clang-tools-extra/modularize/ModularizeUtilities.cpp b/clang-tools-extra/modularize/ModularizeUtilities.cpp index 576e863c8a9d2..b04eb80a67717 100644 --- a/clang-tools-extra/modularize/ModularizeUtilities.cpp +++ b/clang-tools-extra/modularize/ModularizeUtilities.cpp @@ -48,10 +48,8 @@ ModularizeUtilities::ModularizeUtilities(... [truncated] ``````````
https://github.com/llvm/llvm-project/pull/139584 From lldb-commits at lists.llvm.org Mon May 12 10:08:05 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 10:08:05 -0700 (PDT) Subject: [Lldb-commits] [clang] [clang-tools-extra] [lldb] [clang] Remove intrusive reference count from `DiagnosticOptions` (PR #139584) In-Reply-To: Message-ID: <68222af5.170a0220.3b15e.aeb2@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-hlsl Author: Jan Svoboda (jansvoboda11)
Changes The `DiagnosticOptions` class is currently intrusively reference-counted, which makes reasoning about its lifetime very difficult in some cases. For example, `CompilerInvocation` owns the `DiagnosticOptions` instance (wrapped in `llvm::IntrusiveRefCntPtr`) and only exposes an accessor returning `DiagnosticOptions &`. One would think this gives `CompilerInvocation` exclusive ownership of the object, but that's not the case: ```c++ void shareOwnership(CompilerInvocation &CI) { llvm::IntrusiveRefCntPtr<DiagnosticOptions> CoOwner = &CI.getDiagnosticOptions(); // ... } ``` This is a perfectly valid pattern that is being actually used in the codebase. I would like to ensure the ownership of `DiagnosticOptions` by `CompilerInvocation` is guaranteed to be exclusive. This can be leveraged for a copy-on-write optimization later on. This PR changes usages of `DiagnosticOptions` across `clang`, `clang-tools-extra` and `lldb` to not be intrusively reference-counted. --- Patch is 189.21 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/139584.diff 134 Files Affected: - (modified) clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp (+2-2) - (modified) clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp (+3-3) - (modified) clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp (+3-3) - (modified) clang-tools-extra/clang-move/tool/ClangMove.cpp (+3-3) - (modified) clang-tools-extra/clang-query/Query.cpp (+1-1) - (modified) clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp (+3-3) - (modified) clang-tools-extra/clang-tidy/ClangTidy.cpp (+12-12) - (modified) clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp (+2-2) - (modified) clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h (+4-1) - (modified) clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp (+1-1) - (modified) clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h (+1) - (modified) clang-tools-extra/clangd/Compiler.cpp (+3-2) - (modified) clang-tools-extra/clangd/ModulesBuilder.cpp (+2-2) - (modified) clang-tools-extra/clangd/ParsedAST.cpp (+2-1) - (modified) clang-tools-extra/clangd/Preamble.cpp (+1-1) - (modified) clang-tools-extra/clangd/SystemIncludeExtractor.cpp (+2-1) - (modified) clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp (+2-1) - (modified) clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp (+2-1) - (modified) clang-tools-extra/include-cleaner/unittests/RecordTest.cpp (+2-2) - (modified) clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp (+3-3) - (modified) clang-tools-extra/modularize/ModularizeUtilities.cpp (+2-4) - (modified) clang-tools-extra/modularize/ModularizeUtilities.h (+1-1) - (modified) clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp (+2-2) - (modified) clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp (+9-9) - (modified) clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h (+3-3) - (modified) clang/include/clang/Basic/Diagnostic.h (+3-3) - (modified) clang/include/clang/Basic/DiagnosticOptions.h (+1-3) - (modified) clang/include/clang/Basic/SourceManager.h (+1) - (modified) clang/include/clang/Frontend/ASTUnit.h (+2) - (modified) clang/include/clang/Frontend/CompilerInstance.h (+1-1) - (modified) clang/include/clang/Frontend/CompilerInvocation.h (+1-1) - (modified) clang/include/clang/Frontend/DiagnosticRenderer.h (+3-4) - (modified) clang/include/clang/Frontend/LogDiagnosticPrinter.h (+2-2) - (modified) clang/include/clang/Frontend/SARIFDiagnostic.h (+1-1) - (modified) clang/include/clang/Frontend/SARIFDiagnosticPrinter.h (+2-2) - (modified) clang/include/clang/Frontend/SerializedDiagnosticPrinter.h (+1-1) - (modified) clang/include/clang/Frontend/TextDiagnostic.h (+1-1) - (modified) clang/include/clang/Frontend/TextDiagnosticPrinter.h (+2-2) - (modified) clang/include/clang/Serialization/ASTReader.h (+4-5) - (modified) clang/lib/Basic/Diagnostic.cpp (+5-5) - (modified) clang/lib/Basic/SourceManager.cpp (+2-2) - (modified) clang/lib/CrossTU/CrossTranslationUnit.cpp (+9-9) - (modified) clang/lib/Frontend/ASTMerge.cpp (+4-5) - (modified) clang/lib/Frontend/ASTUnit.cpp (+2) - (modified) clang/lib/Frontend/ChainedIncludesSource.cpp (+2-2) - (modified) clang/lib/Frontend/CompilerInstance.cpp (+13-14) - (modified) clang/lib/Frontend/CompilerInvocation.cpp (+7-20) - (modified) clang/lib/Frontend/CreateInvocationFromCommandLine.cpp (+9-5) - (modified) clang/lib/Frontend/DiagnosticRenderer.cpp (+8-9) - (modified) clang/lib/Frontend/FrontendAction.cpp (+2-3) - (modified) clang/lib/Frontend/FrontendActions.cpp (+8-8) - (modified) clang/lib/Frontend/LogDiagnosticPrinter.cpp (+2-2) - (modified) clang/lib/Frontend/SARIFDiagnostic.cpp (+2-2) - (modified) clang/lib/Frontend/SARIFDiagnosticPrinter.cpp (+3-4) - (modified) clang/lib/Frontend/SerializedDiagnosticPrinter.cpp (+15-14) - (modified) clang/lib/Frontend/TextDiagnostic.cpp (+39-40) - (modified) clang/lib/Frontend/TextDiagnosticPrinter.cpp (+6-9) - (modified) clang/lib/Interpreter/Interpreter.cpp (+4-4) - (modified) clang/lib/Rewrite/HTMLRewrite.cpp (+2-2) - (modified) clang/lib/Serialization/ASTReader.cpp (+12-13) - (modified) clang/lib/Testing/TestAST.cpp (+1-1) - (modified) clang/lib/Tooling/CompilationDatabase.cpp (+4-4) - (modified) clang/lib/Tooling/Core/Replacement.cpp (+2-2) - (modified) clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp (+3-3) - (modified) clang/lib/Tooling/Refactoring.cpp (+4-4) - (modified) clang/lib/Tooling/Tooling.cpp (+4-4) - (modified) clang/tools/c-index-test/core_main.cpp (+4-2) - (modified) clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp (+7-5) - (modified) clang/tools/clang-format/ClangFormat.cpp (+4-4) - (modified) clang/tools/clang-import-test/clang-import-test.cpp (+2-2) - (modified) clang/tools/clang-installapi/ClangInstallAPI.cpp (+4-4) - (modified) clang/tools/clang-scan-deps/ClangScanDeps.cpp (+5-4) - (modified) clang/tools/diagtool/ShowEnabledWarnings.cpp (+3-3) - (modified) clang/tools/diagtool/TreeView.cpp (+2-2) - (modified) clang/tools/driver/cc1_main.cpp (+2-2) - (modified) clang/tools/driver/cc1as_main.cpp (+4-4) - (modified) clang/tools/driver/cc1gen_reproducer_main.cpp (+3-3) - (modified) clang/tools/driver/driver.cpp (+5-6) - (modified) clang/tools/libclang/CIndex.cpp (+5-4) - (modified) clang/tools/libclang/CIndexCodeCompletion.cpp (+5-5) - (modified) clang/tools/libclang/CIndexDiagnostic.cpp (+8-9) - (modified) clang/tools/libclang/Indexing.cpp (+2-1) - (modified) clang/unittests/AST/ASTVectorTest.cpp (+2-1) - (modified) clang/unittests/AST/CommentLexer.cpp (+4-6) - (modified) clang/unittests/AST/CommentParser.cpp (+4-6) - (modified) clang/unittests/AST/CommentTextTest.cpp (+2-1) - (modified) clang/unittests/AST/ExternalASTSourceTest.cpp (+2-2) - (modified) clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp (+2-3) - (modified) clang/unittests/Analysis/MacroExpansionContextTest.cpp (+3-3) - (modified) clang/unittests/Analysis/UnsafeBufferUsageTest.cpp (+2-1) - (modified) clang/unittests/Basic/DiagnosticTest.cpp (+14-9) - (modified) clang/unittests/Basic/SarifTest.cpp (+3-3) - (modified) clang/unittests/Basic/SourceManagerTest.cpp (+4-5) - (modified) clang/unittests/Driver/DXCModeTest.cpp (+6-6) - (modified) clang/unittests/Driver/SanitizerArgsTest.cpp (+3-4) - (modified) clang/unittests/Driver/SimpleDiagnosticConsumer.h (+2-3) - (modified) clang/unittests/Driver/ToolChainTest.cpp (+36-35) - (modified) clang/unittests/Frontend/ASTUnitTest.cpp (+14-13) - (modified) clang/unittests/Frontend/CompilerInstanceTest.cpp (+6-5) - (modified) clang/unittests/Frontend/CompilerInvocationTest.cpp (+2-1) - (modified) clang/unittests/Frontend/OutputStreamTest.cpp (+6-6) - (modified) clang/unittests/Frontend/PCHPreambleTest.cpp (+3-1) - (modified) clang/unittests/Frontend/ReparseWorkingDirTest.cpp (+2-1) - (modified) clang/unittests/Frontend/SearchPathTest.cpp (+2-2) - (modified) clang/unittests/Frontend/TextDiagnosticTest.cpp (+4-4) - (modified) clang/unittests/Frontend/UtilsTest.cpp (+5-4) - (modified) clang/unittests/Interpreter/InterpreterTest.cpp (+9-6) - (modified) clang/unittests/Lex/HeaderSearchTest.cpp (+2-1) - (modified) clang/unittests/Lex/LexerTest.cpp (+4-6) - (modified) clang/unittests/Lex/ModuleDeclStateTest.cpp (+2-1) - (modified) clang/unittests/Lex/PPCallbacksTest.cpp (+4-4) - (modified) clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp (+4-6) - (modified) clang/unittests/Lex/PPDependencyDirectivesTest.cpp (+2-1) - (modified) clang/unittests/Lex/PPMemoryAllocationsTest.cpp (+2-1) - (modified) clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp (+2-2) - (modified) clang/unittests/Sema/SemaNoloadLookupTest.cpp (+2-2) - (modified) clang/unittests/Serialization/ForceCheckFileInputTest.cpp (+4-4) - (modified) clang/unittests/Serialization/LoadSpecLazilyTest.cpp (+2-1) - (modified) clang/unittests/Serialization/ModuleCacheTest.cpp (+4-2) - (modified) clang/unittests/Serialization/NoCommentsTest.cpp (+2-1) - (modified) clang/unittests/Serialization/PreambleInNamedModulesTest.cpp (+2-1) - (modified) clang/unittests/Serialization/VarDeclConstantInitTest.cpp (+2-1) - (modified) clang/unittests/Support/TimeProfilerTest.cpp (+2-2) - (modified) clang/unittests/Tooling/RewriterTestContext.h (+4-5) - (modified) clang/unittests/Tooling/Syntax/TokensTest.cpp (+2-1) - (modified) clang/unittests/Tooling/Syntax/TreeTestBase.cpp (+1-1) - (modified) clang/unittests/Tooling/Syntax/TreeTestBase.h (+2-2) - (modified) clang/unittests/Tooling/ToolingTest.cpp (+4-4) - (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp (+5-5) - (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp (+1-2) - (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp (+13-8) - (modified) lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp (+1-2) - (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp (+2-1) - (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h (+1) ``````````diff diff --git a/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp b/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp index 68b5743c6540f..062e236d3e51f 100644 --- a/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp +++ b/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp @@ -96,9 +96,9 @@ int main(int argc, char **argv) { cl::SetVersionPrinter(printVersion); cl::ParseCommandLineOptions(argc, argv); - IntrusiveRefCntPtr DiagOpts(new DiagnosticOptions()); + DiagnosticOptions DiagOpts; DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr(new DiagnosticIDs()), DiagOpts.get()); + IntrusiveRefCntPtr(new DiagnosticIDs()), DiagOpts); // Determine a formatting style from options. auto FormatStyleOrError = format::getStyle(FormatStyleOpt, FormatStyleConfig, diff --git a/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp b/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp index 22d26db0c11bc..2a8fe2d06d185 100644 --- a/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp +++ b/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp @@ -126,10 +126,10 @@ int main(int argc, const char **argv) { if (int Result = Tool.run(Factory.get())) return Result; LangOptions DefaultLangOptions; - IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); - clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts); + DiagnosticOptions DiagOpts; + clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts); DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr(new DiagnosticIDs()), &*DiagOpts, + IntrusiveRefCntPtr(new DiagnosticIDs()), DiagOpts, &DiagnosticPrinter, false); auto &FileMgr = Tool.getFiles(); SourceManager Sources(Diagnostics, FileMgr); diff --git a/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp b/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp index 6e51f25a66407..746ba7bcea015 100644 --- a/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp +++ b/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp @@ -455,9 +455,9 @@ int includeFixerMain(int argc, const char **argv) { } // Set up a new source manager for applying the resulting replacements. - IntrusiveRefCntPtr DiagOpts(new DiagnosticOptions); - DiagnosticsEngine Diagnostics(new DiagnosticIDs, &*DiagOpts); - TextDiagnosticPrinter DiagnosticPrinter(outs(), &*DiagOpts); + DiagnosticOptions DiagOpts; + DiagnosticsEngine Diagnostics(new DiagnosticIDs, DiagOpts); + TextDiagnosticPrinter DiagnosticPrinter(outs(), DiagOpts); SourceManager SM(Diagnostics, tool.getFiles()); Diagnostics.setClient(&DiagnosticPrinter, false); diff --git a/clang-tools-extra/clang-move/tool/ClangMove.cpp b/clang-tools-extra/clang-move/tool/ClangMove.cpp index 655ea81ee37d4..750eb952714f7 100644 --- a/clang-tools-extra/clang-move/tool/ClangMove.cpp +++ b/clang-tools-extra/clang-move/tool/ClangMove.cpp @@ -176,10 +176,10 @@ int main(int argc, const char **argv) { } } - IntrusiveRefCntPtr DiagOpts(new DiagnosticOptions()); - clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts); + DiagnosticOptions DiagOpts; + clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts); DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr(new DiagnosticIDs()), &*DiagOpts, + IntrusiveRefCntPtr(new DiagnosticIDs()), DiagOpts, &DiagnosticPrinter, false); auto &FileMgr = Tool.getFiles(); SourceManager SM(Diagnostics, FileMgr); diff --git a/clang-tools-extra/clang-query/Query.cpp b/clang-tools-extra/clang-query/Query.cpp index 382aa5d6fe25e..574b64ee0f759 100644 --- a/clang-tools-extra/clang-query/Query.cpp +++ b/clang-tools-extra/clang-query/Query.cpp @@ -172,7 +172,7 @@ bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const { clang::SourceRange R = BI->second.getSourceRange(); if (R.isValid()) { TextDiagnostic TD(OS, AST->getASTContext().getLangOpts(), - &AST->getDiagnostics().getDiagnosticOptions()); + AST->getDiagnostics().getDiagnosticOptions()); TD.emitDiagnostic( FullSourceLoc(R.getBegin(), AST->getSourceManager()), DiagnosticsEngine::Note, "\"" + BI->first + "\" binds here", diff --git a/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp b/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp index 5b77ee7b5738c..03502525417b2 100644 --- a/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp +++ b/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp @@ -72,10 +72,10 @@ int main(int argc, const char **argv) { int ExitCode = Tool.run(Factory.get()); LangOptions DefaultLangOptions; - IntrusiveRefCntPtr DiagOpts(new DiagnosticOptions()); - TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts); + DiagnosticOptions DiagOpts; + TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts); DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr(new DiagnosticIDs()), &*DiagOpts, + IntrusiveRefCntPtr(new DiagnosticIDs()), DiagOpts, &DiagnosticPrinter, false); auto &FileMgr = Tool.getFiles(); diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp index 733a53a0f5dcc..26f9afbc0880e 100644 --- a/clang-tools-extra/clang-tidy/ClangTidy.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -97,15 +97,14 @@ class ErrorReporter { ErrorReporter(ClangTidyContext &Context, FixBehaviour ApplyFixes, llvm::IntrusiveRefCntPtr BaseFS) : Files(FileSystemOptions(), std::move(BaseFS)), - DiagOpts(new DiagnosticOptions()), - DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), &*DiagOpts)), - Diags(IntrusiveRefCntPtr(new DiagnosticIDs), &*DiagOpts, + DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), DiagOpts)), + Diags(IntrusiveRefCntPtr(new DiagnosticIDs), DiagOpts, DiagPrinter), SourceMgr(Diags, Files), Context(Context), ApplyFixes(ApplyFixes) { - DiagOpts->ShowColors = Context.getOptions().UseColor.value_or( + DiagOpts.ShowColors = Context.getOptions().UseColor.value_or( llvm::sys::Process::StandardOutHasColors()); DiagPrinter->BeginSourceFile(LangOpts); - if (DiagOpts->ShowColors && !llvm::sys::Process::StandardOutIsDisplayed()) { + if (DiagOpts.ShowColors && !llvm::sys::Process::StandardOutIsDisplayed()) { llvm::sys::Process::UseANSIEscapeCodes(true); } } @@ -308,7 +307,7 @@ class ErrorReporter { FileManager Files; LangOptions LangOpts; // FIXME: use langopts from each original file - IntrusiveRefCntPtr DiagOpts; + DiagnosticOptions DiagOpts; DiagnosticConsumer *DiagPrinter; DiagnosticsEngine Diags; SourceManager SourceMgr; @@ -516,10 +515,10 @@ getCheckOptions(const ClangTidyOptions &Options, Options), AllowEnablingAnalyzerAlphaCheckers); ClangTidyDiagnosticConsumer DiagConsumer(Context); - DiagnosticsEngine DE(llvm::makeIntrusiveRefCnt(), - llvm::makeIntrusiveRefCnt(), + auto DiagOpts = std::make_unique(); + DiagnosticsEngine DE(llvm::makeIntrusiveRefCnt(), *DiagOpts, &DiagConsumer, /*ShouldOwnClient=*/false); - Context.setDiagnosticsEngine(&DE); + Context.setDiagnosticsEngine(std::move(DiagOpts), &DE); ClangTidyASTConsumerFactory Factory(Context); return Factory.getCheckOptions(); } @@ -558,9 +557,10 @@ runClangTidy(clang::tidy::ClangTidyContext &Context, Context.setProfileStoragePrefix(StoreCheckProfile); ClangTidyDiagnosticConsumer DiagConsumer(Context, nullptr, true, ApplyAnyFix); - DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions(), - &DiagConsumer, /*ShouldOwnClient=*/false); - Context.setDiagnosticsEngine(&DE); + auto DiagOpts = std::make_unique(); + DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer, + /*ShouldOwnClient=*/false); + Context.setDiagnosticsEngine(std::move(DiagOpts), &DE); Tool.setDiagnosticConsumer(&DiagConsumer); class ActionFactory : public FrontendActionFactory { diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp index b216970bfbd8c..a0253a5fd1a48 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -49,7 +49,7 @@ namespace { class ClangTidyDiagnosticRenderer : public DiagnosticRenderer { public: ClangTidyDiagnosticRenderer(const LangOptions &LangOpts, - DiagnosticOptions *DiagOpts, + DiagnosticOptions &DiagOpts, ClangTidyError &Error) : DiagnosticRenderer(LangOpts, DiagOpts), Error(Error) {} @@ -429,7 +429,7 @@ void ClangTidyDiagnosticConsumer::HandleDiagnostic( forwardDiagnostic(Info); } else { ClangTidyDiagnosticRenderer Converter( - Context.getLangOpts(), &Context.DiagEngine->getDiagnosticOptions(), + Context.getLangOpts(), Context.DiagEngine->getDiagnosticOptions(), Errors.back()); SmallString<100> Message; Info.FormatDiagnostic(Message); diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h index d6cf6a2b2731e..bd7a1bf2c11c7 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -75,7 +75,9 @@ class ClangTidyContext { /// Sets the DiagnosticsEngine that diag() will emit diagnostics to. // FIXME: this is required initialization, and should be a constructor param. // Fix the context -> diag engine -> consumer -> context initialization cycle. - void setDiagnosticsEngine(DiagnosticsEngine *DiagEngine) { + void setDiagnosticsEngine(std::unique_ptr DiagOpts, + DiagnosticsEngine *DiagEngine) { + this->DiagOpts = std::move(DiagOpts); this->DiagEngine = DiagEngine; } @@ -231,6 +233,7 @@ class ClangTidyContext { // Writes to Stats. friend class ClangTidyDiagnosticConsumer; + std::unique_ptr DiagOpts = nullptr; DiagnosticsEngine *DiagEngine = nullptr; std::unique_ptr OptionsProvider; diff --git a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp index 03a3e8404e069..6a84704434c33 100644 --- a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp +++ b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp @@ -71,7 +71,7 @@ ExpandModularHeadersPPCallbacks::ExpandModularHeadersPPCallbacks( InMemoryFs(new llvm::vfs::InMemoryFileSystem), Sources(Compiler.getSourceManager()), // Forward the new diagnostics to the original DiagnosticConsumer. - Diags(new DiagnosticIDs, new DiagnosticOptions, + Diags(new DiagnosticIDs, DiagOpts, new ForwardingDiagnosticConsumer(Compiler.getDiagnosticClient())), LangOpts(Compiler.getLangOpts()), HSOpts(Compiler.getHeaderSearchOpts()) { // Add a FileSystem containing the extra files needed in place of modular diff --git a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h index a263681b3c633..c3478917ef498 100644 --- a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h +++ b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h @@ -128,6 +128,7 @@ class ExpandModularHeadersPPCallbacks : public PPCallbacks { llvm::IntrusiveRefCntPtr InMemoryFs; SourceManager &Sources; + DiagnosticOptions DiagOpts; DiagnosticsEngine Diags; LangOptions LangOpts; HeaderSearchOptions HSOpts; diff --git a/clang-tools-extra/clangd/Compiler.cpp b/clang-tools-extra/clangd/Compiler.cpp index 9be0152afd2f7..8b3865c8a8e5c 100644 --- a/clang-tools-extra/clangd/Compiler.cpp +++ b/clang-tools-extra/clangd/Compiler.cpp @@ -110,8 +110,9 @@ buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D, CIOpts.VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory); CIOpts.CC1Args = CC1Args; CIOpts.RecoverOnError = true; - CIOpts.Diags = CompilerInstance::createDiagnostics( - *CIOpts.VFS, new DiagnosticOptions, &D, false); + DiagnosticOptions DiagOpts; + CIOpts.Diags = + CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts, &D, false); CIOpts.ProbePrecompiled = false; std::unique_ptr CI = createInvocation(ArgStrs, CIOpts); if (!CI) diff --git a/clang-tools-extra/clangd/ModulesBuilder.cpp b/clang-tools-extra/clangd/ModulesBuilder.cpp index c1878f91b5e16..bf77f43bd28bb 100644 --- a/clang-tools-extra/clangd/ModulesBuilder.cpp +++ b/clang-tools-extra/clangd/ModulesBuilder.cpp @@ -187,9 +187,9 @@ bool IsModuleFileUpToDate(PathRef ModuleFilePath, HSOpts.ValidateASTInputFilesContent = true; clang::clangd::IgnoreDiagnostics IgnoreDiags; + DiagnosticOptions DiagOpts; IntrusiveRefCntPtr Diags = - CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions, - &IgnoreDiags, + CompilerInstance::createDiagnostics(*VFS, DiagOpts, &IgnoreDiags, /*ShouldOwnClient=*/false); LangOptions LangOpts; diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp index 3f63daaf400db..9e1f6bb977226 100644 --- a/clang-tools-extra/clangd/ParsedAST.cpp +++ b/clang-tools-extra/clangd/ParsedAST.cpp @@ -556,7 +556,8 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs, *AllCTFactories, Cfg.Diagnostics.ClangTidy.FastCheckFilter); CTContext.emplace(std::make_unique( tidy::ClangTidyGlobalOptions(), ClangTidyOpts)); - CTContext->setDiagnosticsEngine(&Clang->getDiagnostics()); + // The lifetime of DiagnosticOptions is managed by \c Clang. + CTContext->setDiagnosticsEngine(nullptr, &Clang->getDiagnostics()); CTContext->setASTContext(&Clang->getASTContext()); CTContext->setCurrentFile(Filename); CTContext->setSelfContainedDiags(true); diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp index ba9a53db8a0dc..7b4d63ff197e7 100644 --- a/clang-tools-extra/clangd/Preamble.cpp +++ b/clang-tools-extra/clangd/Preamble.cpp @@ -615,7 +615,7 @@ buildPreamble(PathRef FileName, CompilerInvocation CI, }); auto VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory); llvm::IntrusiveRefCntPtr PreambleDiagsEngine = - CompilerInstance::createDiagnostics(*VFS, &CI.getDiagnosticOpts(), + CompilerInstance::createDiagnostics(*VFS, CI.getDiagnosticOpts(), &PreambleDiagnostics, /*ShouldOwnClient=*/false); const Config &Cfg = Config::current(); diff --git a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp index 6417bf8765622..0b067e8b0b2b2 100644 --- a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp +++ b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp @@ -253,7 +253,8 @@ namespace { bool isValidTarget(llvm::StringRef Triple) { std::shared_ptr TargetOpts(new TargetOptions); TargetOpts->Triple = Triple.str(); - DiagnosticsEngine Diags(new DiagnosticIDs, new DiagnosticOptions, + DiagnosticOptions DiagOpts; + DiagnosticsEngine Diags(new DiagnosticIDs, DiagOpts, new IgnoringDiagConsumer); llvm::IntrusiveRefCntPtr Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts); diff --git a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp index c3e484a1a79c4..75d0ff244038d 100644 --- a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp +++ b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp @@ -298,7 +298,8 @@ TEST_F(ConfigCompileTests, DiagnosticSuppression) { "unreachable-code", "unused-variable", "typecheck_bool_condition", "unexpected_friend", "warn_alloca")); - clang::DiagnosticsEngine DiagEngine(new DiagnosticIDs, nullptr, + clang::DiagnosticOptions DiagOpts; + clang::DiagnosticsEngine DiagEngine(new DiagnosticIDs, DiagOpts, new clang::IgnoringDiagConsumer); using Diag = clang::Diagnostic; diff --git a/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp index 8bd40c1429012..e39b70224d97c 100644 --- a/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp +++ b/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp @@ -44,7 +44,8 @@ TEST(FileEdits, AbsolutePath) { for (const auto *Path : RelPaths) MemFS->addFile(Path, 0, llvm::MemoryBuffer::getMemBuffer("", Path)); FileManager FM(FileSystemOptions(), MemFS); - DiagnosticsEngine DE(new DiagnosticIDs, new DiagnosticOptions); + DiagnosticOptions DiagOpts; + DiagnosticsEngine DE(new DiagnosticIDs, DiagOpts); SourceManager SM(DE, FM); for (const auto *Path : RelPaths) { diff --git a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp index a10c0d5a54a95..91d2697712b6e 100644 --- a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp @@ -618,8 +618,8 @@ TEST_F(PragmaIncludeTest, ExportInUnnamedBuffer) { llvm::MemoryBuffer::getMemBufferCopy(Extra.getValue(), /*BufferName=*/"")); - auto DiagOpts = llvm::makeIntrusiveRefCnt(); - auto Diags = CompilerInstance::createDiagnostics(*VFS, DiagOpts.get()); + DiagnosticOptions DiagOpts; + auto Diags = CompilerInstance::createDiagnostics(*VFS, DiagOpts); auto Invocation = std::make_unique(); ASSERT_TRUE(CompilerInvocation::CreateFromArgs(*Invocation, {Filename.data()}, *Diags, "clang")); diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp index e45ea36f7938e..5223eb563e4cb 100644 --- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp @@ -85,9 +85,9 @@ std::vector testWalk(llvm::StringRef TargetCode, // For each difference, show the target point in context, like a diagnostic. std::string DiagBuf; llvm::raw_string_ostream DiagOS(DiagBuf); - auto *DiagOpts = new DiagnosticOptions(); - DiagOpts->ShowLevel = 0; - DiagOpts->ShowNoteIncludeStack = 0; + DiagnosticOptions DiagOpts; + DiagOpts.ShowLevel = 0; + DiagOpts.ShowNoteIncludeStack = 0; TextDiagnostic Diag(DiagOS, AST.context().getLangOpts(), DiagOpts); auto DiagnosePoint = [&](llvm::StringRef Message, unsigned Offset) { Diag.emitDiagnostic( diff --git a/clang-tools-extra/modularize/ModularizeUtilities.cpp b/clang-tools-extra/modularize/ModularizeUtilities.cpp index 576e863c8a9d2..b04eb80a67717 100644 --- a/clang-tools-extra/modularize/ModularizeUtilities.cpp +++ b/clang-tools-extra/modularize/ModularizeUtilities.cpp @@ -48,10 +48,8 @@ ModularizeUtilities::ModularizeUtilities(... [truncated] ``````````
https://github.com/llvm/llvm-project/pull/139584 From lldb-commits at lists.llvm.org Mon May 12 10:11:26 2025 From: lldb-commits at lists.llvm.org (Vy Nguyen via lldb-commits) Date: Mon, 12 May 2025 10:11:26 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb]Make `list` command work with headers when possible. (PR #139002) In-Reply-To: Message-ID: <68222bbe.050a0220.1ed5ad.d903@mx.google.com> https://github.com/oontvoo updated https://github.com/llvm/llvm-project/pull/139002 >From 5746e997eea55c05cbbb63ad6f78ca225c9ac855 Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Wed, 7 May 2025 21:37:31 -0400 Subject: [PATCH 1/8] [lldb]Make `list` command work with headers when possible. --- lldb/source/Commands/CommandObjectSource.cpp | 36 +++++++++++- lldb/source/Core/ModuleList.cpp | 2 + lldb/test/Shell/Commands/list-header.test | 59 ++++++++++++++++++++ 3 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 lldb/test/Shell/Commands/list-header.test diff --git a/lldb/source/Commands/CommandObjectSource.cpp b/lldb/source/Commands/CommandObjectSource.cpp index c205813565d52..475317021255c 100644 --- a/lldb/source/Commands/CommandObjectSource.cpp +++ b/lldb/source/Commands/CommandObjectSource.cpp @@ -1104,6 +1104,7 @@ class CommandObjectSourceList : public CommandObjectParsed { bool check_inlines = false; SymbolContextList sc_list; size_t num_matches = 0; + uint32_t start_line = m_options.start_line; if (!m_options.modules.empty()) { ModuleList matching_modules; @@ -1114,7 +1115,7 @@ class CommandObjectSourceList : public CommandObjectParsed { matching_modules.Clear(); target.GetImages().FindModules(module_spec, matching_modules); num_matches += matching_modules.ResolveSymbolContextForFilePath( - filename, 0, check_inlines, + filename, start_line, check_inlines, SymbolContextItem(eSymbolContextModule | eSymbolContextCompUnit), sc_list); @@ -1122,7 +1123,7 @@ class CommandObjectSourceList : public CommandObjectParsed { } } else { num_matches = target.GetImages().ResolveSymbolContextForFilePath( - filename, 0, check_inlines, + filename, start_line, check_inlines, eSymbolContextModule | eSymbolContextCompUnit, sc_list); } @@ -1170,8 +1171,37 @@ class CommandObjectSourceList : public CommandObjectParsed { if (m_options.num_lines == 0) m_options.num_lines = 10; const uint32_t column = 0; + + // Headers aren't always in the DWARF but if they have + // executable code (eg., inlined-functions) then the callsite's file(s) + // will be found. + // So if a header was requested and we got a primary file, then look + // thru its support file(s) for the header. + lldb::SupportFileSP actual_file_sp = + sc.comp_unit->GetPrimarySupportFile(); + if (llvm::StringRef(m_options.file_name).ends_with(".h")) { + int support_matches_count = 0; + for (auto &file : sc.comp_unit->GetSupportFiles()) { + if (llvm::StringRef(file->GetSpecOnly().GetPath()).ends_with(filename)) { + actual_file_sp = file; + ++support_matches_count; + } + } + if (support_matches_count == 0) { + result.AppendErrorWithFormat( + "No file found for requested header: \"%s.\"\n", + m_options.file_name.c_str()); + return; + } else if (support_matches_count > 1) { + result.AppendErrorWithFormat( + "Multiple files found for requested header: \"%s.\"\n", + m_options.file_name.c_str()); + return; + } + } + target.GetSourceManager().DisplaySourceLinesWithLineNumbers( - sc.comp_unit->GetPrimarySupportFile(), + actual_file_sp, m_options.start_line, column, 0, m_options.num_lines, "", &result.GetOutputStream(), GetBreakpointLocations()); diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index d5ddf6e846112..90c6a62727734 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -714,6 +714,8 @@ uint32_t ModuleList::ResolveSymbolContextsForFileSpec( const FileSpec &file_spec, uint32_t line, bool check_inlines, SymbolContextItem resolve_scope, SymbolContextList &sc_list) const { std::lock_guard guard(m_modules_mutex); + // If we're looking for a header (not source), then need to check inline. + check_inlines = check_inlines || !file_spec.IsSourceImplementationFile(); for (const ModuleSP &module_sp : m_modules) { module_sp->ResolveSymbolContextsForFileSpec(file_spec, line, check_inlines, resolve_scope, sc_list); diff --git a/lldb/test/Shell/Commands/list-header.test b/lldb/test/Shell/Commands/list-header.test new file mode 100644 index 0000000000000..ca700cd2b2fb1 --- /dev/null +++ b/lldb/test/Shell/Commands/list-header.test @@ -0,0 +1,59 @@ +## Test that `list header.h:` works correctly when header is available. +## +# REQUIRES: x86 +# RUN: split-file %s %t + +# RUN: %clang_host -g %t/main_with_inlined.cc %t/foo.cc -o %t/main_with_inlined.out +# RUN: %clang_host -g %t/main_no_inlined.cc %t/foo.cc -o %t/main_no_inlined.out + +# RUN: %lldb %t/main_with_inlined.out -o "list foo.h:2" -o "exit" 2>&1 \ +# RUN: | FileCheck %s --check-prefix=CHECK-INLINED + +## Would be nice if this listed the header too - but probably not something +## we want to support right now. +# RUN: echo quit | %lldb %t/main_no_inlined.out -o "list foo.h:2" -o "exit" 2>&1 \ +# RUN: | FileCheck %s --check-prefix=CHECK-NO-INLINED + +# CHECK-INLINED: 2 extern int* ptr; +# CHECK-INLINED: 3 void f(int x); +# CHECK-INLINED: 4 +# CHECK-INLINED: 5 inline void g(int x) { +# CHECK-INLINED: 6 *ptr = x; // should raise a SIGILL +# CHECK-INLINED: 7 } + +# CHECK-NO-INLINED: error: Could not find source file "foo.h". + +#--- foo.h +// foo.h +extern int* ptr; +void f(int x); + +inline void g(int x) { + *ptr = x; // should raise a SIGILL +} + +#--- foo.cc +#include "foo.h" + +int* ptr; + +void f(int x) { + *ptr = x; +} + +#--- main_with_inlined.cc +#include "foo.h" + +int main() { + f(234); + g(123); // Call the inlined function + return 0; +} + +#--- main_no_inlined.cc +#include "foo.h" + +int main() { + f(234); + return 0; +} >From b0af06e7ea2f408691c25aab25dc3951f3ddd403 Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Wed, 7 May 2025 21:42:26 -0400 Subject: [PATCH 2/8] formatting --- lldb/source/Commands/CommandObjectSource.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lldb/source/Commands/CommandObjectSource.cpp b/lldb/source/Commands/CommandObjectSource.cpp index 475317021255c..4b0e47f4cc83f 100644 --- a/lldb/source/Commands/CommandObjectSource.cpp +++ b/lldb/source/Commands/CommandObjectSource.cpp @@ -1173,16 +1173,16 @@ class CommandObjectSourceList : public CommandObjectParsed { const uint32_t column = 0; // Headers aren't always in the DWARF but if they have - // executable code (eg., inlined-functions) then the callsite's file(s) - // will be found. - // So if a header was requested and we got a primary file, then look - // thru its support file(s) for the header. + // executable code (eg., inlined-functions) then the callsite's + // file(s) will be found. So if a header was requested and we got a + // primary file, then look thru its support file(s) for the header. lldb::SupportFileSP actual_file_sp = sc.comp_unit->GetPrimarySupportFile(); if (llvm::StringRef(m_options.file_name).ends_with(".h")) { int support_matches_count = 0; for (auto &file : sc.comp_unit->GetSupportFiles()) { - if (llvm::StringRef(file->GetSpecOnly().GetPath()).ends_with(filename)) { + if (llvm::StringRef(file->GetSpecOnly().GetPath()) + .ends_with(filename)) { actual_file_sp = file; ++support_matches_count; } @@ -1201,9 +1201,9 @@ class CommandObjectSourceList : public CommandObjectParsed { } target.GetSourceManager().DisplaySourceLinesWithLineNumbers( - actual_file_sp, - m_options.start_line, column, 0, m_options.num_lines, "", - &result.GetOutputStream(), GetBreakpointLocations()); + actual_file_sp, m_options.start_line, column, 0, + m_options.num_lines, "", &result.GetOutputStream(), + GetBreakpointLocations()); result.SetStatus(eReturnStatusSuccessFinishResult); } else { >From 0e823400669138776ed55f441ca8cb03e262f6e3 Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Thu, 8 May 2025 10:10:58 -0400 Subject: [PATCH 3/8] update test --- lldb/test/Shell/Commands/list-header.test | 1 - 1 file changed, 1 deletion(-) diff --git a/lldb/test/Shell/Commands/list-header.test b/lldb/test/Shell/Commands/list-header.test index ca700cd2b2fb1..204b704ebe2a2 100644 --- a/lldb/test/Shell/Commands/list-header.test +++ b/lldb/test/Shell/Commands/list-header.test @@ -45,7 +45,6 @@ void f(int x) { #include "foo.h" int main() { - f(234); g(123); // Call the inlined function return 0; } >From 692a387f56715e99fe33f6b5a840b2fa9f92d8c7 Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Thu, 8 May 2025 13:30:31 -0400 Subject: [PATCH 4/8] rework the logic to be more general --- lldb/source/Commands/CommandObjectSource.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lldb/source/Commands/CommandObjectSource.cpp b/lldb/source/Commands/CommandObjectSource.cpp index 4b0e47f4cc83f..c4c46bb33d0fc 100644 --- a/lldb/source/Commands/CommandObjectSource.cpp +++ b/lldb/source/Commands/CommandObjectSource.cpp @@ -1175,33 +1175,35 @@ class CommandObjectSourceList : public CommandObjectParsed { // Headers aren't always in the DWARF but if they have // executable code (eg., inlined-functions) then the callsite's // file(s) will be found. So if a header was requested and we got a - // primary file, then look thru its support file(s) for the header. - lldb::SupportFileSP actual_file_sp = + // primary file (ie., something with a different name), then look thru + // its support file(s) for the header. + lldb::SupportFileSP found_file_sp = sc.comp_unit->GetPrimarySupportFile(); - if (llvm::StringRef(m_options.file_name).ends_with(".h")) { + + if (!llvm::StringRef(found_file_sp->GetSpecOnly().GetPath()) + .ends_with(filename)) { int support_matches_count = 0; for (auto &file : sc.comp_unit->GetSupportFiles()) { if (llvm::StringRef(file->GetSpecOnly().GetPath()) .ends_with(filename)) { - actual_file_sp = file; + found_file_sp = file; ++support_matches_count; } } if (support_matches_count == 0) { result.AppendErrorWithFormat( - "No file found for requested header: \"%s.\"\n", - m_options.file_name.c_str()); + "No file found for requested header: \"%s.\"\n", filename); return; } else if (support_matches_count > 1) { result.AppendErrorWithFormat( "Multiple files found for requested header: \"%s.\"\n", - m_options.file_name.c_str()); + filename); return; } } target.GetSourceManager().DisplaySourceLinesWithLineNumbers( - actual_file_sp, m_options.start_line, column, 0, + found_file_sp, m_options.start_line, column, 0, m_options.num_lines, "", &result.GetOutputStream(), GetBreakpointLocations()); >From 11ef8875774418dd4122ebf5779dcd5ef6f26689 Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Thu, 8 May 2025 13:53:57 -0400 Subject: [PATCH 5/8] address review comments --- lldb/source/Commands/CommandObjectSource.cpp | 4 ++-- lldb/test/Shell/Commands/list-header.test | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lldb/source/Commands/CommandObjectSource.cpp b/lldb/source/Commands/CommandObjectSource.cpp index c4c46bb33d0fc..1f147fb08d5fa 100644 --- a/lldb/source/Commands/CommandObjectSource.cpp +++ b/lldb/source/Commands/CommandObjectSource.cpp @@ -1192,11 +1192,11 @@ class CommandObjectSourceList : public CommandObjectParsed { } if (support_matches_count == 0) { result.AppendErrorWithFormat( - "No file found for requested header: \"%s.\"\n", filename); + "No file found for requested file: \"%s.\"\n", filename); return; } else if (support_matches_count > 1) { result.AppendErrorWithFormat( - "Multiple files found for requested header: \"%s.\"\n", + "Multiple files found for requested file: \"%s.\"\n", filename); return; } diff --git a/lldb/test/Shell/Commands/list-header.test b/lldb/test/Shell/Commands/list-header.test index 204b704ebe2a2..d1dc261e8575e 100644 --- a/lldb/test/Shell/Commands/list-header.test +++ b/lldb/test/Shell/Commands/list-header.test @@ -1,6 +1,5 @@ ## Test that `list header.h:` works correctly when header is available. ## -# REQUIRES: x86 # RUN: split-file %s %t # RUN: %clang_host -g %t/main_with_inlined.cc %t/foo.cc -o %t/main_with_inlined.out >From 240b59ece6ae2531341c48b848f178410afa3cba Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Fri, 9 May 2025 11:05:56 -0400 Subject: [PATCH 6/8] updated comment --- lldb/test/Shell/Commands/list-header.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/test/Shell/Commands/list-header.test b/lldb/test/Shell/Commands/list-header.test index d1dc261e8575e..5937e2f3abc09 100644 --- a/lldb/test/Shell/Commands/list-header.test +++ b/lldb/test/Shell/Commands/list-header.test @@ -28,7 +28,7 @@ extern int* ptr; void f(int x); inline void g(int x) { - *ptr = x; // should raise a SIGILL + *ptr = x; // should crash here } #--- foo.cc >From 923b9b4276d80bda68f745f224f56096b9cec94d Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Mon, 12 May 2025 11:22:34 -0400 Subject: [PATCH 7/8] addressed review comments --- lldb/source/Commands/CommandObjectSource.cpp | 38 +++++--------------- lldb/test/Shell/Commands/list-header.test | 2 +- 2 files changed, 10 insertions(+), 30 deletions(-) diff --git a/lldb/source/Commands/CommandObjectSource.cpp b/lldb/source/Commands/CommandObjectSource.cpp index 1f147fb08d5fa..2fa36ebfb0686 100644 --- a/lldb/source/Commands/CommandObjectSource.cpp +++ b/lldb/source/Commands/CommandObjectSource.cpp @@ -1117,14 +1117,17 @@ class CommandObjectSourceList : public CommandObjectParsed { num_matches += matching_modules.ResolveSymbolContextForFilePath( filename, start_line, check_inlines, SymbolContextItem(eSymbolContextModule | - eSymbolContextCompUnit), + eSymbolContextCompUnit | + eSymbolContextLineEntry), sc_list); } } } else { num_matches = target.GetImages().ResolveSymbolContextForFilePath( filename, start_line, check_inlines, - eSymbolContextModule | eSymbolContextCompUnit, sc_list); + eSymbolContextModule | eSymbolContextCompUnit | + eSymbolContextLineEntry, + sc_list); } if (num_matches == 0) { @@ -1174,33 +1177,10 @@ class CommandObjectSourceList : public CommandObjectParsed { // Headers aren't always in the DWARF but if they have // executable code (eg., inlined-functions) then the callsite's - // file(s) will be found. So if a header was requested and we got a - // primary file (ie., something with a different name), then look thru - // its support file(s) for the header. - lldb::SupportFileSP found_file_sp = - sc.comp_unit->GetPrimarySupportFile(); - - if (!llvm::StringRef(found_file_sp->GetSpecOnly().GetPath()) - .ends_with(filename)) { - int support_matches_count = 0; - for (auto &file : sc.comp_unit->GetSupportFiles()) { - if (llvm::StringRef(file->GetSpecOnly().GetPath()) - .ends_with(filename)) { - found_file_sp = file; - ++support_matches_count; - } - } - if (support_matches_count == 0) { - result.AppendErrorWithFormat( - "No file found for requested file: \"%s.\"\n", filename); - return; - } else if (support_matches_count > 1) { - result.AppendErrorWithFormat( - "Multiple files found for requested file: \"%s.\"\n", - filename); - return; - } - } + // file(s) will be found and assigned to + // sc.comp_unit->GetPrimarySupportFile, which is NOT what we want to + // print. Instead, we want to print the one from the line entry. + lldb::SupportFileSP found_file_sp = sc.line_entry.file_sp; target.GetSourceManager().DisplaySourceLinesWithLineNumbers( found_file_sp, m_options.start_line, column, 0, diff --git a/lldb/test/Shell/Commands/list-header.test b/lldb/test/Shell/Commands/list-header.test index 5937e2f3abc09..08bcedd3fc946 100644 --- a/lldb/test/Shell/Commands/list-header.test +++ b/lldb/test/Shell/Commands/list-header.test @@ -17,7 +17,7 @@ # CHECK-INLINED: 3 void f(int x); # CHECK-INLINED: 4 # CHECK-INLINED: 5 inline void g(int x) { -# CHECK-INLINED: 6 *ptr = x; // should raise a SIGILL +# CHECK-INLINED: 6 *ptr = x; // should crash here # CHECK-INLINED: 7 } # CHECK-NO-INLINED: error: Could not find source file "foo.h". >From 7a2ab920937698a7bc6f7856842aece15e54b27c Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Mon, 12 May 2025 13:11:12 -0400 Subject: [PATCH 8/8] use line=1 while searching --- lldb/source/Commands/CommandObjectSource.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lldb/source/Commands/CommandObjectSource.cpp b/lldb/source/Commands/CommandObjectSource.cpp index 2fa36ebfb0686..4922a88b03334 100644 --- a/lldb/source/Commands/CommandObjectSource.cpp +++ b/lldb/source/Commands/CommandObjectSource.cpp @@ -1104,7 +1104,6 @@ class CommandObjectSourceList : public CommandObjectParsed { bool check_inlines = false; SymbolContextList sc_list; size_t num_matches = 0; - uint32_t start_line = m_options.start_line; if (!m_options.modules.empty()) { ModuleList matching_modules; @@ -1115,7 +1114,7 @@ class CommandObjectSourceList : public CommandObjectParsed { matching_modules.Clear(); target.GetImages().FindModules(module_spec, matching_modules); num_matches += matching_modules.ResolveSymbolContextForFilePath( - filename, start_line, check_inlines, + filename, 1, check_inlines, SymbolContextItem(eSymbolContextModule | eSymbolContextCompUnit | eSymbolContextLineEntry), @@ -1124,7 +1123,7 @@ class CommandObjectSourceList : public CommandObjectParsed { } } else { num_matches = target.GetImages().ResolveSymbolContextForFilePath( - filename, start_line, check_inlines, + filename, 1, check_inlines, eSymbolContextModule | eSymbolContextCompUnit | eSymbolContextLineEntry, sc_list); From lldb-commits at lists.llvm.org Mon May 12 10:11:55 2025 From: lldb-commits at lists.llvm.org (Vy Nguyen via lldb-commits) Date: Mon, 12 May 2025 10:11:55 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb]Make `list` command work with headers when possible. (PR #139002) In-Reply-To: Message-ID: <68222bdb.170a0220.9828a.11b9@mx.google.com> oontvoo wrote: > Maybe we should use line 1 than as that's the first real line number? done! thanks! https://github.com/llvm/llvm-project/pull/139002 From lldb-commits at lists.llvm.org Mon May 12 10:34:01 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Mon, 12 May 2025 10:34:01 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit tests for protocol types (PR #139502) In-Reply-To: Message-ID: <68223109.630a0220.b019c.44de@mx.google.com> ================ @@ -0,0 +1,268 @@ +//===-- ProtocolTypesTest.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 "Protocol/ProtocolTypes.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap::protocol; + +TEST(ProtocolTypesTest, ExceptionBreakpointsFilter) { + ExceptionBreakpointsFilter filter; + filter.filter = "testFilter"; + filter.label = "Test Filter"; + filter.description = "This is a test filter"; + filter.defaultState = true; + filter.supportsCondition = true; + filter.conditionDescription = "Condition for test filter"; + + llvm::json::Value value = toJSON(filter); + const json::Object *obj = value.getAsObject(); + ASSERT_NE(obj, nullptr); + + EXPECT_EQ(obj->getString("filter"), "testFilter"); + EXPECT_EQ(obj->getString("label"), "Test Filter"); + EXPECT_EQ(obj->getString("description"), "This is a test filter"); + EXPECT_EQ(obj->getBoolean("default"), true); + EXPECT_EQ(obj->getBoolean("supportsCondition"), true); + EXPECT_EQ(obj->getString("conditionDescription"), + "Condition for test filter"); ---------------- JDevlieghere wrote: Alright, if that's the direction, let me start by landing the `Source` test and we can support the other types in a similar fashion as we add support for serialization. https://github.com/llvm/llvm-project/pull/139502 From lldb-commits at lists.llvm.org Mon May 12 10:47:31 2025 From: lldb-commits at lists.llvm.org (Alex Langford via lldb-commits) Date: Mon, 12 May 2025 10:47:31 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream lldb-rpc-gen tool (PR #138031) In-Reply-To: Message-ID: <68223433.170a0220.19bfd0.97fc@mx.google.com> ================ @@ -0,0 +1,535 @@ +//===-- RPCCommon.cpp -----------------------------------------------------===// +// +// 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 "RPCCommon.h" + +#include "clang/AST/AST.h" +#include "clang/AST/Mangle.h" +#include "clang/Lex/Lexer.h" + +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +// We intentionally do not generate some classes because they are currently +// inconvenient, they aren't really used by most consumers, or we're not sure +// why they exist. +static constexpr llvm::StringRef DisallowedClasses[] = { + "SBCommunication", // What is this used for? + "SBInputReader", // What is this used for? + "SBCommandPluginInterface", // This is hard to support, we can do it if + // really needed though. + "SBCommand", // There's nothing too difficult about this one, but many of + // its methods take a SBCommandPluginInterface pointer so + // there's no reason to support this. +}; + +// We intentionally avoid generating certain methods either because they are +// difficult to support correctly or they aren't really used much from C++. +// FIXME: We should be able to annotate these methods instead of maintaining a +// list in the generator itself. +static constexpr llvm::StringRef DisallowedMethods[] = { + // The threading functionality in SBHostOS is deprecated and thus we do not + // generate them. It would be ideal to add the annotations to the methods + // and then support not generating deprecated methods. However, without + // annotations the generator generates most things correctly. This one is + // problematic because it returns a pointer to an "opaque" structure + // (thread_t) that is not `void *`, so special casing it is more effort than + // it's worth. + "_ZN4lldb8SBHostOS10ThreadJoinEP17_opaque_pthread_tPPvPNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadCancelEP17_opaque_pthread_tPNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadCreateEPKcPFPvS3_ES3_PNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadDetachEP17_opaque_pthread_tPNS_7SBErrorE", + "_ZN4lldb8SBHostOS13ThreadCreatedEPKc", +}; + +static constexpr llvm::StringRef ClassesWithoutDefaultCtor[] = { + "SBHostOS", + "SBReproducer", +}; + +static constexpr llvm::StringRef ClassesWithoutCopyOperations[] = { + "SBHostOS", + "SBReproducer", + "SBStream", + "SBProgress", +}; + +static constexpr llvm::StringRef MethodsWithPointerPlusLen[] = { ---------------- bulbazord wrote: So each method would get its own typedef? https://github.com/llvm/llvm-project/pull/138031 From lldb-commits at lists.llvm.org Mon May 12 10:47:55 2025 From: lldb-commits at lists.llvm.org (Med Ismail Bennani via lldb-commits) Date: Mon, 12 May 2025 10:47:55 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Restore ObjC incomplete type dereferencing fix (PR #139567) In-Reply-To: Message-ID: <6822344b.630a0220.1a93a4.30b5@mx.google.com> medismailben wrote: > @felipepiovezan I don't have a machine to run ObjC tests on, could you apply this patch and see if it fixes the issue in #135843 ? I'll try that for you. https://github.com/llvm/llvm-project/pull/139567 From lldb-commits at lists.llvm.org Mon May 12 10:51:01 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Mon, 12 May 2025 10:51:01 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit tests for protocol types (PR #139502) In-Reply-To: Message-ID: <68223505.170a0220.19c31d.9955@mx.google.com> https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/139502 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Mon May 12 10:51:54 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Mon, 12 May 2025 10:51:54 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit tests for protocol types (PR #139502) In-Reply-To: Message-ID: <6822353a.170a0220.32f084.8e83@mx.google.com> JDevlieghere wrote: Updated the PR and settled on the roundtrip approach for `Source` and `ExceptionBreakpointsFilter`. https://github.com/llvm/llvm-project/pull/139502 From lldb-commits at lists.llvm.org Mon May 12 10:56:00 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Mon, 12 May 2025 10:56:00 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] While handling events, grab the APIMutex for consistency. (PR #139596) Message-ID: https://github.com/ashgti created https://github.com/llvm/llvm-project/pull/139596 A number of unit tests are unstable at the moment and I believe this is due to event handling between the event thread and the DAP::Loop. One way this manifests is the 'disconnect' request terminating the SBTarget while the event handler is still handling module events. This is causing a SIGPIPE between the debugserver and the lldb-dap process. I have some additional follow up patches to address test event synchronization, since many tests seem to be under specified in terms of their expected state that I think is contributing to these kinds of races. >From 028af82dabf91276c6c77eeecb4292e5930b7cf9 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 12 May 2025 10:51:06 -0700 Subject: [PATCH] [lldb-dap] While handling events, grab the APIMutext for consistency. A number of unit tests are unstable at the moment and I believe this is due to event handling between the event thread and the DAP::Loop. One way this manifests is the 'disconnect' request terminating the SBTarget while the event handler is still handling module events. This is causing a SIGPIPE between the debugserver and the lldb-dap process. I have some additional follow up patches to address test event synchronization, since many tests seem to be under specified in terms of their expected state that I think is contributing to these kinds of races. --- lldb/tools/lldb-dap/DAP.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 4feca1253be20..e84d3d9e7eed8 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1504,6 +1504,11 @@ void DAP::EventThread() { bool done = false; while (!done) { if (listener.WaitForEvent(1, event)) { + // Once we get an event, make sure we finish handling it before the main + // thread handles the next DAP request. + lldb::SBMutex lock = GetAPIMutex(); + std::lock_guard guard(lock); + const auto event_mask = event.GetType(); if (lldb::SBProcess::EventIsProcessEvent(event)) { lldb::SBProcess process = lldb::SBProcess::GetProcessFromEvent(event); From lldb-commits at lists.llvm.org Mon May 12 10:56:34 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 10:56:34 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] While handling events, grab the APIMutex for consistency. (PR #139596) In-Reply-To: Message-ID: <68223652.a70a0220.2484f.cd62@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: John Harrison (ashgti)
Changes A number of unit tests are unstable at the moment and I believe this is due to event handling between the event thread and the DAP::Loop. One way this manifests is the 'disconnect' request terminating the SBTarget while the event handler is still handling module events. This is causing a SIGPIPE between the debugserver and the lldb-dap process. I have some additional follow up patches to address test event synchronization, since many tests seem to be under specified in terms of their expected state that I think is contributing to these kinds of races. --- Full diff: https://github.com/llvm/llvm-project/pull/139596.diff 1 Files Affected: - (modified) lldb/tools/lldb-dap/DAP.cpp (+5) ``````````diff diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 4feca1253be20..e84d3d9e7eed8 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1504,6 +1504,11 @@ void DAP::EventThread() { bool done = false; while (!done) { if (listener.WaitForEvent(1, event)) { + // Once we get an event, make sure we finish handling it before the main + // thread handles the next DAP request. + lldb::SBMutex lock = GetAPIMutex(); + std::lock_guard guard(lock); + const auto event_mask = event.GetType(); if (lldb::SBProcess::EventIsProcessEvent(event)) { lldb::SBProcess process = lldb::SBProcess::GetProcessFromEvent(event); ``````````
https://github.com/llvm/llvm-project/pull/139596 From lldb-commits at lists.llvm.org Mon May 12 10:56:39 2025 From: lldb-commits at lists.llvm.org (Med Ismail Bennani via lldb-commits) Date: Mon, 12 May 2025 10:56:39 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Restore ObjC incomplete type dereferencing fix (PR #139567) In-Reply-To: Message-ID: <68223657.170a0220.e1ca8.aae6@mx.google.com> medismailben wrote: > @felipepiovezan I don't have a machine to run ObjC tests on, could you apply this patch and see if it fixes the issue in #135843 ? The test pass after applying this patch. Feel free to land this whenever :) https://github.com/llvm/llvm-project/pull/139567 From lldb-commits at lists.llvm.org Mon May 12 10:57:07 2025 From: lldb-commits at lists.llvm.org (Med Ismail Bennani via lldb-commits) Date: Mon, 12 May 2025 10:57:07 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Restore ObjC incomplete type dereferencing fix (PR #139567) In-Reply-To: Message-ID: <68223673.a70a0220.269590.be5e@mx.google.com> https://github.com/medismailben approved this pull request. https://github.com/llvm/llvm-project/pull/139567 From lldb-commits at lists.llvm.org Mon May 12 10:58:07 2025 From: lldb-commits at lists.llvm.org (Ilia Kuklin via lldb-commits) Date: Mon, 12 May 2025 10:58:07 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Restore ObjC incomplete type dereferencing fix (PR #139567) In-Reply-To: Message-ID: <682236af.630a0220.1d31d0.46fc@mx.google.com> https://github.com/kuilpd ready_for_review https://github.com/llvm/llvm-project/pull/139567 From lldb-commits at lists.llvm.org Mon May 12 10:59:06 2025 From: lldb-commits at lists.llvm.org (Ilia Kuklin via lldb-commits) Date: Mon, 12 May 2025 10:59:06 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Restore ObjC incomplete type dereferencing fix (PR #139567) In-Reply-To: Message-ID: <682236ea.630a0220.1b980.fcf0@mx.google.com> kuilpd wrote: Thank you! https://github.com/llvm/llvm-project/pull/139567 From lldb-commits at lists.llvm.org Mon May 12 10:59:44 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 10:59:44 -0700 (PDT) Subject: [Lldb-commits] [lldb] c8a0513 - [lldb] Restore ObjC incomplete type dereferencing fix (#139567) Message-ID: <68223710.170a0220.2a6287.dc25@mx.google.com> Author: Ilia Kuklin Date: 2025-05-12T22:59:40+05:00 New Revision: c8a0513a1a694078e5ea927faf8249ce77084d80 URL: https://github.com/llvm/llvm-project/commit/c8a0513a1a694078e5ea927faf8249ce77084d80 DIFF: https://github.com/llvm/llvm-project/commit/c8a0513a1a694078e5ea927faf8249ce77084d80.diff LOG: [lldb] Restore ObjC incomplete type dereferencing fix (#139567) Attempt an ObjC incomplete type fix even if `GetDereferencedType` returns an error. Added: Modified: lldb/source/ValueObject/ValueObject.cpp Removed: ################################################################################ diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp index 6f0fe9a5b83f9..46426ae499be9 100644 --- a/lldb/source/ValueObject/ValueObject.cpp +++ b/lldb/source/ValueObject/ValueObject.cpp @@ -2810,46 +2810,47 @@ ValueObjectSP ValueObject::Dereference(Status &error) { std::string deref_error; if (deref_compiler_type_or_err) { deref_compiler_type = *deref_compiler_type_or_err; - if (deref_compiler_type && deref_byte_size) { - ConstString deref_name; - if (!deref_name_str.empty()) - deref_name.SetCString(deref_name_str.c_str()); - - m_deref_valobj = - new ValueObjectChild(*this, deref_compiler_type, deref_name, - deref_byte_size, deref_byte_offset, 0, 0, false, - true, eAddressTypeInvalid, language_flags); - } - - // In case of incomplete deref compiler type, use the pointee type and try - // to recreate a new ValueObjectChild using it. - if (!m_deref_valobj) { - // FIXME(#59012): C++ stdlib formatters break with incomplete types (e.g. - // `std::vector &`). Remove ObjC restriction once that's resolved. - if (Language::LanguageIsObjC(GetPreferredDisplayLanguage()) && - HasSyntheticValue()) { - deref_compiler_type = compiler_type.GetPointeeType(); - - if (deref_compiler_type) { - ConstString deref_name; - if (!deref_name_str.empty()) - deref_name.SetCString(deref_name_str.c_str()); - - m_deref_valobj = new ValueObjectChild( - *this, deref_compiler_type, deref_name, deref_byte_size, - deref_byte_offset, 0, 0, false, true, eAddressTypeInvalid, - language_flags); - } - } - } } else { deref_error = llvm::toString(deref_compiler_type_or_err.takeError()); LLDB_LOG(GetLog(LLDBLog::Types), "could not find child: {0}", deref_error); - if (IsSynthetic()) { - m_deref_valobj = GetChildMemberWithName("$$dereference$$").get(); + } + + if (deref_compiler_type && deref_byte_size) { + ConstString deref_name; + if (!deref_name_str.empty()) + deref_name.SetCString(deref_name_str.c_str()); + + m_deref_valobj = + new ValueObjectChild(*this, deref_compiler_type, deref_name, + deref_byte_size, deref_byte_offset, 0, 0, false, + true, eAddressTypeInvalid, language_flags); + } + + // In case of incomplete deref compiler type, use the pointee type and try + // to recreate a new ValueObjectChild using it. + if (!m_deref_valobj) { + // FIXME(#59012): C++ stdlib formatters break with incomplete types (e.g. + // `std::vector &`). Remove ObjC restriction once that's resolved. + if (Language::LanguageIsObjC(GetPreferredDisplayLanguage()) && + HasSyntheticValue()) { + deref_compiler_type = compiler_type.GetPointeeType(); + + if (deref_compiler_type) { + ConstString deref_name; + if (!deref_name_str.empty()) + deref_name.SetCString(deref_name_str.c_str()); + + m_deref_valobj = new ValueObjectChild( + *this, deref_compiler_type, deref_name, deref_byte_size, + deref_byte_offset, 0, 0, false, true, eAddressTypeInvalid, + language_flags); + } } } + if (!m_deref_valobj && IsSynthetic()) + m_deref_valobj = GetChildMemberWithName("$$dereference$$").get(); + if (m_deref_valobj) { error.Clear(); return m_deref_valobj->GetSP(); From lldb-commits at lists.llvm.org Mon May 12 10:59:46 2025 From: lldb-commits at lists.llvm.org (Ilia Kuklin via lldb-commits) Date: Mon, 12 May 2025 10:59:46 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Restore ObjC incomplete type dereferencing fix (PR #139567) In-Reply-To: Message-ID: <68223712.170a0220.279afb.9290@mx.google.com> https://github.com/kuilpd closed https://github.com/llvm/llvm-project/pull/139567 From lldb-commits at lists.llvm.org Mon May 12 11:00:18 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Mon, 12 May 2025 11:00:18 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] While handling events, grab the APIMutex for consistency. (PR #139596) In-Reply-To: Message-ID: <68223732.170a0220.2e4c97.92fe@mx.google.com> JDevlieghere wrote: I too have been contemplating this for a while... Given that the request handlers currently lock the API mutex and now the event thread does the same, this patch means that the two are essentially fully synchronized. That begs the question: Should these be separate threads at all? We could sidestep all the synchronization issues by handling request and events on the same thread using the `MainLoop`. https://github.com/llvm/llvm-project/pull/139596 From lldb-commits at lists.llvm.org Mon May 12 11:03:05 2025 From: lldb-commits at lists.llvm.org (Chelsea Cassanova via lldb-commits) Date: Mon, 12 May 2025 11:03:05 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream lldb-rpc-gen tool (PR #138031) In-Reply-To: Message-ID: <682237d9.170a0220.167f10.b607@mx.google.com> ================ @@ -0,0 +1,535 @@ +//===-- RPCCommon.cpp -----------------------------------------------------===// +// +// 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 "RPCCommon.h" + +#include "clang/AST/AST.h" +#include "clang/AST/Mangle.h" +#include "clang/Lex/Lexer.h" + +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +// We intentionally do not generate some classes because they are currently +// inconvenient, they aren't really used by most consumers, or we're not sure +// why they exist. +static constexpr llvm::StringRef DisallowedClasses[] = { + "SBCommunication", // What is this used for? + "SBInputReader", // What is this used for? + "SBCommandPluginInterface", // This is hard to support, we can do it if + // really needed though. + "SBCommand", // There's nothing too difficult about this one, but many of + // its methods take a SBCommandPluginInterface pointer so + // there's no reason to support this. +}; + +// We intentionally avoid generating certain methods either because they are +// difficult to support correctly or they aren't really used much from C++. +// FIXME: We should be able to annotate these methods instead of maintaining a +// list in the generator itself. +static constexpr llvm::StringRef DisallowedMethods[] = { + // The threading functionality in SBHostOS is deprecated and thus we do not + // generate them. It would be ideal to add the annotations to the methods + // and then support not generating deprecated methods. However, without + // annotations the generator generates most things correctly. This one is + // problematic because it returns a pointer to an "opaque" structure + // (thread_t) that is not `void *`, so special casing it is more effort than + // it's worth. + "_ZN4lldb8SBHostOS10ThreadJoinEP17_opaque_pthread_tPPvPNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadCancelEP17_opaque_pthread_tPNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadCreateEPKcPFPvS3_ES3_PNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadDetachEP17_opaque_pthread_tPNS_7SBErrorE", + "_ZN4lldb8SBHostOS13ThreadCreatedEPKc", +}; + +static constexpr llvm::StringRef ClassesWithoutDefaultCtor[] = { + "SBHostOS", + "SBReproducer", +}; + +static constexpr llvm::StringRef ClassesWithoutCopyOperations[] = { + "SBHostOS", + "SBReproducer", + "SBStream", + "SBProgress", +}; + +static constexpr llvm::StringRef MethodsWithPointerPlusLen[] = { ---------------- chelcassanova wrote: I misspoke here, it wouldn't be a typedef but a new SB class that holds a struct that would be used in place of pointer + lens. This class could then be picked up by the tool (i.e. if one of the function params uses this class) to know if it's a pointer + len method without using this list. https://github.com/llvm/llvm-project/pull/138031 From lldb-commits at lists.llvm.org Mon May 12 11:03:27 2025 From: lldb-commits at lists.llvm.org (Igor Kudrin via lldb-commits) Date: Mon, 12 May 2025 11:03:27 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][core] Fix getting summary of a variable pointing to r/o memory (PR #139196) In-Reply-To: Message-ID: <682237ef.170a0220.184388.f742@mx.google.com> https://github.com/igorkudrin updated https://github.com/llvm/llvm-project/pull/139196 >From 499f723c3f974ff53deb8f354d879e0baaa7a9e8 Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Wed, 7 May 2025 19:55:07 -0700 Subject: [PATCH 1/4] [lldb][core] Fix getting summary of a variable pointing to r/o memory Motivation example: ``` > lldb -c altmain2.core ... (lldb) var F (const char *) F = 0x0804a000 "" ``` The variable `F` points to a read-only memory page not dumped to the core file, so `Process::ReadMemory()` cannot read the data. The patch switches to `Target::ReadMemory()`, which can read data both from the process memory and the application binary. --- lldb/source/ValueObject/ValueObject.cpp | 13 ++++++++- .../postmortem/elf-core/TestLinuxCore.py | 27 ++++++++++++++++++ .../postmortem/elf-core/altmain2.core | Bin 0 -> 40960 bytes .../postmortem/elf-core/altmain2.out | Bin 0 -> 9776 bytes 4 files changed, 39 insertions(+), 1 deletion(-) create mode 100755 lldb/test/API/functionalities/postmortem/elf-core/altmain2.core create mode 100755 lldb/test/API/functionalities/postmortem/elf-core/altmain2.out diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp index e1c66763ff0b8..aab78428d9103 100644 --- a/lldb/source/ValueObject/ValueObject.cpp +++ b/lldb/source/ValueObject/ValueObject.cpp @@ -735,7 +735,7 @@ size_t ValueObject::GetPointeeData(DataExtractor &data, uint32_t item_idx, case eAddressTypeLoad: { ExecutionContext exe_ctx(GetExecutionContextRef()); Process *process = exe_ctx.GetProcessPtr(); - if (process) { + if (process && process->IsLiveDebugSession()) { heap_buf_ptr->SetByteSize(bytes); size_t bytes_read = process->ReadMemory( addr + offset, heap_buf_ptr->GetBytes(), bytes, error); @@ -743,6 +743,17 @@ size_t ValueObject::GetPointeeData(DataExtractor &data, uint32_t item_idx, data.SetData(data_sp); return bytes_read; } + } else if (Target *target = exe_ctx.GetTargetPtr()) { + Address target_addr; + target_addr.SetLoadAddress(addr + offset, target); + heap_buf_ptr->SetByteSize(bytes); + size_t bytes_read = + target->ReadMemory(target_addr, heap_buf_ptr->GetBytes(), bytes, + error, /*force_live_memory=*/true); + if (error.Success() || bytes_read > 0) { + data.SetData(data_sp); + return bytes_read; + } } } break; case eAddressTypeHost: { diff --git a/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py b/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py index a287fd19ba352..d1e065a32efdc 100644 --- a/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py +++ b/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py @@ -977,6 +977,33 @@ def test_get_core_file_api(self): self.assertEqual(process.GetCoreFile().GetFilename(), core_file_name) self.dbg.DeleteTarget(target) + @skipIfLLVMTargetMissing("X86") + def test_ro_cstring(self): + """ + Test that we can show the summary for a cstring variable that points + to a r/o memory page which is not dumped to a core file. + """ + target = self.dbg.CreateTarget("altmain2.out") + process = target.LoadCore("altmain2.core") + self.assertTrue(process, PROCESS_IS_VALID) + + frame = process.GetSelectedThread().GetFrameAtIndex(0) + self.assertEqual(frame.GetFunctionName(), "_start") + + var = frame.FindVariable("F") + + # The variable points to a RO segment that is not dumped to the core + # file and thus process.ReadCStringFromMemory() cannot get the value. + error = lldb.SBError() + cstr = process.ReadCStringFromMemory(var.GetValueAsUnsigned(), 256, error) + self.assertFailure(error, error_str="core file does not contain 0x804a000") + self.assertEqual(cstr, "") + + # Nevertheless, when getting the summary, the value can be read from the + # application binary. + cstr = var.GetSummary() + self.assertEqual(cstr, '"_start"') + def check_memory_regions(self, process, region_count): region_list = process.GetMemoryRegions() self.assertEqual(region_list.GetSize(), region_count) diff --git a/lldb/test/API/functionalities/postmortem/elf-core/altmain2.core b/lldb/test/API/functionalities/postmortem/elf-core/altmain2.core new file mode 100755 index 0000000000000000000000000000000000000000..b9dd8de08b813442037fcb5bedd08e8bbabfdc0b GIT binary patch literal 40960 zcmeHQ4^&jwnSa9!I!%cK#cib0IB9HSqA(1g2 at tXp8Ij5$Wtd=M$vDi6Fme86<_(|; z6+_tg`VJeLbo*!1-R7KixAr7yY1h*llO~{6F(sCWr_zMokd!oo(v~!T)FyTI_ucp2 z%tOtlZMJ8(-FH3T-0yz(yZ3(gcfb4H_udT89k#l)I-QPFl7Z86N~u&4A}{64oKY?t zsH`Y~&;E#9A!n>A8-*T&)P#5twWFNXo5Amv>t%VSoTus^om+oN`+>Rj^Db^b`}?yb z;#NyEr~PKgiY`d?X7Hdn>?ZQ1?fSGja(xN^Hy`G^{4fU zJxcBl at IkjfR9qO2^U&f7EozCGL?0 at VJw2e>np%fqkAf4~`@fOMrU4MGt74NG{OXk# z&R&C@{G$ZfEEM3jT=HFUiQ)q}D0 at MKZz=qoe9H`?K8djGEGc`2Z4s;$&G|GMWy$%K za=t*$uR=~K5A?|0$C95w4)@`ffTnjGOPY{B201d8XslfzTV3s1We#KuGnn?Dvd1XL zeqvZ7=LQT$>X&kEP~t6oFk-RJS$OWl$jG(;h{jQD+o4awcJf at xIgWgn(sIZo?tku+ ztrZ5}vHX{7>uT$r8`1R+TCmHco+V_}Whyk$Ulju66RY6^8So3uC;qCIHZ>U~_ND|M zz_2*@0XkZ>hJc2EhJc2EhQMDF0y{3c|Iff34ZBCc{Q}+pkINV6bpM~pE#pkw0;!%r zp!*BZNw7r9eFtk#H%xTT0V)7XME3)8?*HjN1VraGk-ELn%yCBCn-I~x5|MK6^|{x0 zFN&8Ws;6PKq#>Xopdp|kpdp|kpdp|kpdp|kpdp|kpdp|kpdp|kpdp|kpdp|kpdp|k zpdp|kpdp|kpdp|kpdp|kpdp|kpdp|kpdp|kpdp|kpdp|kpdp|kpdp|kpdp|kpdp|k zpdp|kpdp|kpdp|kpdp|kpdp|kpdp|kpdp|kpdp|kpdp|kpdp|kpdp|kpdp|kpdp|k zpdp|kpds*o4S|c_|EHJV|F;@1>!bJoZT`4qF}?rKfcO99;0=51{eG&6?EM>#BU0Y) zNAJ_k$2*o4qW6;%(fj=r8bG~5O^_2Qbq#pGp8*AhmZFYGsYg at xzJ2ySK=A7Se&7m} zX?)TleX at z{rS}Ue?_#Gql93+uG5<#6HLH#JJ&GRnvG4wlZ*k8p9%y{9sQuQ_{a5~S zr01b4|NiRxcHMB~Gp8Ty`cmG%tO<$Wp*kl~AA}vf*ZpI7YvIkvBN*fn3`%9ffm zKg!8liKq3H{(WioxC!ub`JiurC`oIr7D%4hw at HI z@~3^Ew=X2aZy_h&nnefXL#vUK-wcB29sktky<{>x4C8)}oP2H;`2ZRFM<&`wN}{pI z4oY=|7xHhJGMNoD7n-ahry}XnoT-bNdM8)0^p)@JUH$C`H$5`(nYSvgJ9pMy-K$%y zuQ1CxH>3T{;5Q+^7x`A?3FOoVCEfN$PIs?Sw>ZmS*oC at fkmZBUfyn2%ss+ZK8C46i z?$cK-$nG=L{CGiD)xibEs-Xo21xNJZkUHVGb~IT8It60;*reyp^Rl at Nz9?Il!LP{9 z$l#Y{>ofSJ*_j!9e)hZ!eo^-P41Qs at F@wMPR%qul?G>cGjI@`MwwbgSk at iB;&L-`f zsxij>pnE{HUpSM2e_Ds;dVWNgt<&?vy6g-+e^{5T*YktA>`XnsUza^k&+pS^&)4$< zx@@DKAIGFs>2r-v;Wbm~^F1wh+*m`W ziSzKaorm%+B$K@}D|*lA;#Zn<=eO+cJ-lMmovxNcz323N)_(dw6AsYFnb*aC|NKNU z+4l~ATI}_L6CZBJr(jEny#ZpJGvdP$CYcnRQ>-sxNH`_-QnRun at n?nMv%Z8dEd1=O zZw58a3E>?J)t`;+9z^OfteNKqdC8`Cao_Cqt+8NpzS0^ zL(NdmnC=ZRp2&Gu?4Hpb&v{vx)!QZolt%g&R^&RTrVC+uVm at Y?X~C9YGw)wH at pLlj z=$&a2Y%`+G*f(gp|6L#?qO_Z;gj0fZwD)zL(48>#{g!H~=NSNysqgnFu!;4ZFztGq zYPx5{x?7fspTA{=U>^r-6j~-w$`bFrWl`CX&^;-y`r*76g%?cU{ps1) zbCP#!mux7rjhg!Ig7Knr!uk?05n;>|qhqJv z88Vw}2cJwH`^O5CZLDnQNm#+dFq~{Ve(`>r1-s z$()uc(LO0UjlvZN#_X-xXI~XYQ5s6j6K*w#&MfO---&od at 8Kr4_`qW4z4Hthe~0OQ z+MjRko}M62fm76q_N at K&7*%*tY%wN6z*QJK^JCFDv-7|tOs7Wu_t7Nc^N`PA4!b9z zE_P=LSBX7S)Uw849X#`p5FZ!gGvYrpzj}%PmiTw%R{}&|A=eV0A$Jmgz`ToLBRdtX zR1fp2L-A*X?tSp7Q)hjX!k7>r5QfG0_*vhS;2ejK!NGv(UcvS_u~UL=k1#H_JTBOW zMLXQ=QR at l4ZTP5d1U7NG&Jm$yP;VPNYCBA2(Y80&c^FRDGKCN4B>ZhS2UFf7wCva0 z_KWsMkJ_G=8a at rLgSTM;MP{eoHqgKDid^Tu=`o=^)-MkHZ55p)-B0`#xm>{6pezNZ5HP!3X8;+lcIgJ!agaCFSbp^ zK8^JiMwi=1#g?hXEhhz(u;wjOrtiK86m&1jK8I~ueO10#ca at pUW$RNmYwBykvSCvR z$Kh-G at 4xqS65Gx61M--O%lIAa*7q8IluYJ6Y{X~E4VgE_7BgRDo=AQ;1V4O=fXW+- zzNUL)x)YedpUz;4{rqRR-HA4wVwn$~XZzCur`)+e|)acc>o*pF!q0+de~3Uk4*{(cfQ(- zaBRB&1_%%Xh9(WVS&A&T2g&K-r1$;F%ix~^{14st*n70+1e3DEX(z9vo%|6XAnoKm08kiH6n1_=-u at 9NV7Xqw za_!w5_W)T#{D^29?H?Gy(oa7FIX1G;J#uEH_yF6$-J{}H*#`b0ZC&x%OHKu}RyHsn z5TX7}DFnoynf7Du{h72 at LVS|NdLvGV-oXqU5?H1F{2~$F|3y-GXGj$0_P{WZJ3=x zdsxUAr;sr$*azi!p~MFS2PqPy!+;zo$OG&n6t?#qwb9iZr$fAXl!C{&&@zDNfY5MB z$k at w5#^cjp$Myg~LVT2TvXhP6Z?y_S4+fu3}jTyh{obQS1oh%vVdmqIvSC2-1S_tT>0or^8D4l-+Z z9-(8m_f)d?pswsq;ZWYY(br+iELqy~9t(GkSPN{UJITN2UauwEa8;lA;9K(bNh*Bd z65xSru&OM44UmT)K#3c}$^B_5dX> zU`vEfgV3C%M5)vT$-|hh6vqAoKwc({-3JBWKaOSSeN~BLKTgN7eW>^_ajbi89BXG$ z$k_i$7Rqc1M6>?w8Nzv?dmIjnt5ynuRJT_bFA%NbHo6ECiiPb4 at ouBIElY?Rh3#3? z=T}*58;w729h}ajUTp|$dO5I7v00t at -d{ps`@)|V*q$IyMqsnOnGS4MV6px at f$hkL z32ZDzlnqPKVVq^LWl~T(K;dKO5DODy$=*R-*>eZ56S=$>qf=5;qifMbE&?;o>iO{W zW`nT7D7dnwvkA9uggV?CA+k;my^eraPLYd553$JSO!U5raJP##cdoeJfa_J!fy>1y zaeWqD3fm`esVEAhTVYS&{I-wxFT4?*iQQBB;@s^9{b!A0%S7%SS*kzmW#@OVyAI4Q%Jb&+I-n_r(D_`UKUgAG; zls&2t))+Qf2k&e-B;J=m_h()ce!l+-788Uw6VKr>h%mN^Y7I*di3>sbOAkE-=}G8@ z at zn3T;OQJo^Gp2{%i1iWcjP$|4EiN z!ePHG%h!VMm*qcvJDI#+mOlo*TbBRg9bD?l@>Af0vfTE&WYR0k%fPqD at _XJ*CYxk= z7`$DU)58Jbc~hq8I|-8&asN-vYu2nOH!s5zoa at b2YhiI=5&nzLSbL0*^6plyuq_lX zY9pC6O+rPlK>u*tqlzkBAgVfBiDWXf1-YWP z3__wT639u>i=a$mnhQPmCR#^}DJR01QU^%sZ`VS69{?I>HPVOD^#igV^|u*|NVM)U zdbF>pO_5wj-#>ipB0Z`nBJ7lO0DAwX6p$<9sze&AA)q0kA)q0kA)q0kA)q0kA)q0k zA)q0kA)q0kA)q0kA)q0kA)q0kA at KhefsgJs(AN{`^r%#(=joq_9!pZi^~lRWYeAbk zjwN}}mqFhIJqdaRbRMMZJeK?vs1URsvEcvgXAAwGSUIvjJX3*-D7tUTog`x{*OOVat3kLdbBKfYkguZK_LJl%7h`ui< z?J*eXI}S65zLz4R?^h@(6KB6y1`hO{)M@#98OpDe%lM@$lV63LQXc4$yN at M5ft!wvM{D8l%s=lUjO`)@CZNW`kLsiqdN=rNzwcxk^?tmrM>JOEx z%BfyxP)B=C2r85?=1pKY#mSBjtcq|Ru`1Ww9#9Cr;c%uFYAG2Iq zqeze6?>a-!;>5DqreSv_b!&+FBvO*a% z)!BxKFXV8nODQx&!)^Gc)x6dp at Wsr_fb8`axsiFjAM>#mrOFMy=$3Fa=ni>&=B98s zu+`6Bz8`8~_eI-$irI5Uu{6Z7j2E}8#@D|VPkY!C4&bjZwprMU$RMk2v^0gIeAplJ z)nN4ZRq}@UknjDhTVr=`^}T;v>ev(XUf%X<{9%bNYLPSi$w)XJ_4s1y-kNLct2Z<| zE?s9yuJo&@rIu#SI?H{eD?ebJFV??!ot-g!18?!Sg`-<7RgnloyN+!XyWbNH$HH59 zWt~xt9Uwvf{>|hijagFd&9^zsYr at _+$g0~H%8SCoby5Q~lRqK1T-CLWm6m8cgkXV{wH6f>Te#|4M?+oJ?Um(4Tyxd!2sG7DlSG~F zZ2@=4TTsL`IO`lXm&4Y0o2{`j9`bidRwG2flz1TKbNHh8;RDy~s4I5WIBQ*14Gj*L zt-k8kI$L$6mE^Yi+bSt{)z-tz4GoeZ5Lik|N?raCtPV%G`YOAvvUa__sRX)-OvT}--B9l$zN)&q5k+ZU5jWp{F-EQN80T15cUxU$G1t&sU1{Ni5sQ`EP*=@L zALKtxKBxn#0#6jb8o{4lHI%J)Aud#g176Oh6f9m}hlRpwF?WXp at jW#)OJTUZAh at l7 zY;UNl!88%SVq6`WT+qnXIo52b+tBE!tm)d)<>~TvwRZX1d|r2}yUp!!dr|L_6{4}q zqH?dlvdCIdQd%AeF=kbHu)VUVs667YEG?=iDJhSInS5orS7BPcQdLEfwcMlP!%-%; zl01lRi^^m1%90x^O0DIww#t&CiqevDkDKItCo2}0hryIqloprAc&1re?(1U16_?*o z$h)JAw-VpBJ;l4D9uG$Lvz_U|NX}q#N^HDt@~(ZDz!c zY58`4B-K$`>P at pMg9FjDST#&Q)wOEG?Z84YkyjU5w-=`>TGKu9bNRFmpVsmET2oD< zkzk6yO9gSKiubAbn2L|8c(-aQ_~lWm&+XwfVxEXUT~MK?0>tA^o7U-1n-=R#^IjG2 zi+NK+xjXz at SYaiW`L0Ntiua`pL3IrZs;V|s`_`beqSRNURT`Y}Z7N>Ij^uosaJk;f~ZygQ{5v)l&-=tCY5;`A(n8 zRus~c4yz^_j7WQi4Og0O4SBlI5tf#Yl5-PAO<1k`-G&$d8H#hYfkJn50TIwgOh9=EA1^QdO)3#RqMZRy^_ZE4WmZdith zxQZ-`r`Rp{)m^F(ET!-!=>+{4H_cN#lqqpb-oo?7Bi^Jr8 z3Ll9hmdk}$1V+nzS1f{=Nrf*EQ&v=d!?g-i*y`Sz;yqDZqK5)uH#3{`3cZo7Z3SLG z#UrVuBnkOC=L&Fc%@yE0ObOJL;i#X at i}fCHN7EfgeTd`oAP7+EAyAyt4&|7;1Mx;y zk9DR8Qx6>XY?*633Dg}^Ic=SE^5O=89mT5C*Cn6tmW%Gm>}y<2_6BwdMdyFeQ^2k; aAa>MNSFS9>wE at m`bXZx$UDQ;$dHgS6POs$v literal 0 HcmV?d00001 diff --git a/lldb/test/API/functionalities/postmortem/elf-core/altmain2.out b/lldb/test/API/functionalities/postmortem/elf-core/altmain2.out new file mode 100755 index 0000000000000000000000000000000000000000..e930c3d8055e11ea8256faf244a208ff5a7bc033 GIT binary patch literal 9776 zcmeHNOK%%h6h3!6;~J)M?4%Nn3S>eHG$2o2R$BTXB*BRa77?OBV#6>VPizx=#u|@l ziV9RhNUaJ|x?{nDpTK{p0I`Av3;sYQ7D#~DL;@7fH=Y|g77MmW_bBI{*LUa6{qD_d zd_JmFH-r!*MWYNQ(Y~H5bMmLNgG!k!GUz;wQ+`lK`nH~f{>Uy=N3KAFI$PprKuhdG z4c4Q&#r~IEXFb6#ba;M_>$$J=9P}jDpjlSTfBj)xhdU~$V_7AN0mXn~Krx^gPz)#r z6a$I@#eiZ!F`yVw3>;@*`|iV!e<}R at BxjAkr-?qheemny;oZt#-&PKQyjMB+hUWIa zdvH%b_u%+c6)6T31BwB~fMP%~pcqgLC#cmWIf7#9T^-I?I z?OH#G`_{sey=2dqmitM#_~ByNo-fa)X?mPzYRT;6$NS_b|Jk9Zwb?gFB*g^x1d5Mh z;Kl%n%yc;xA}e#^i?=wTZ;;3o;c53{V;2zJd^ZWZBz$(VB71|)iMLV1Kw_NC8U5NM z&nb$h^OI&~`pk4uOk at j>5oK(#GL^|+GB2Ain9oij{nF|8rv#(*GG%gu!nH~5G`}<_ zQsf|!Jx8YbqM6C_de0D6pjTN9?pk;b3k&gQehdcP6Rhk^3v5&q)7toeBaV26AVb4W zCynAChIzklh=#^Z7b59hIAjqdZsktu`W=1 at 2u>uWYc-$yL|Yp({I40n1 at uKgX1R`d z^R;bjec?iSK31u-w8%r;5B#eQKk%cL$Dtc}&8w~Di_2E2VU>1*u;lh`23|7?gRtK# z^@AI&pk9jITHEh&ov(h8;@pkJoe~a@%poZ3VVRb8)9T zw~)Np$N+Yv==A%c^kEU3Y|-<9Sa2`O3|s6C at q{Mm3Y?US2}WGt at KlN~Fn)a`eq|&c zdP!%qy0x}ib+$G(-l$x6uCK0DD-Jo%-o<6R;m1zbbK+({*tOj~&enRpbgzzIcVm|v zKd2Mgy_+2-iftSXY*Tu%zZa7og$dejgt6UibHWQd9Y0{F?$`Pa$Bo>e;rC?N3U)&2 zyR};6zbB)1EAXYi6SQzGmOKTB)v7 at nHy-(t0P687tR5Ga*@%u zV-0$CMsfI;1}?*jb3`AHyrY~-dVFwC7g>RuXN8=yh at MZp!GId{a%u-zq7{pX|BeJ0 z2+mphh#iXvUll2`_9iE!kJ|SZQ3p;cvc^Yy40mOQXiI{IYRQ*tDE}$rULK0ESI7sf zc(&Z{4~)BoLMo_1 at 1$1Zs!tIWQw)s6!47>?=pDxGb8d_kYeEaGkFeq_r2NLXf7=Jv R7{;xfCHh=WVvF at 4{{Sg@>kj|` literal 0 HcmV?d00001 >From ff536ae4a96612fb18165d22acecf74043290476 Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Fri, 9 May 2025 16:15:25 -0700 Subject: [PATCH 2/4] fixup: ro -> read-only --- .../functionalities/postmortem/elf-core/TestLinuxCore.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py b/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py index d1e065a32efdc..a68175dc4e4d7 100644 --- a/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py +++ b/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py @@ -978,10 +978,10 @@ def test_get_core_file_api(self): self.dbg.DeleteTarget(target) @skipIfLLVMTargetMissing("X86") - def test_ro_cstring(self): + def test_read_only_cstring(self): """ Test that we can show the summary for a cstring variable that points - to a r/o memory page which is not dumped to a core file. + to a read-only memory page which is not dumped to a core file. """ target = self.dbg.CreateTarget("altmain2.out") process = target.LoadCore("altmain2.core") @@ -992,8 +992,9 @@ def test_ro_cstring(self): var = frame.FindVariable("F") - # The variable points to a RO segment that is not dumped to the core - # file and thus process.ReadCStringFromMemory() cannot get the value. + # The variable points to a read-only segment that is not dumped to + # the core file and thus 'process.ReadCStringFromMemory()' cannot get + # the value. error = lldb.SBError() cstr = process.ReadCStringFromMemory(var.GetValueAsUnsigned(), 256, error) self.assertFailure(error, error_str="core file does not contain 0x804a000") >From 17210b1357f5544145c9dcb8d4677e116bf538a5 Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Fri, 9 May 2025 16:13:58 -0700 Subject: [PATCH 3/4] fixup: Factor out the common code --- lldb/source/ValueObject/ValueObject.cpp | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp index aab78428d9103..1375b67d72ff6 100644 --- a/lldb/source/ValueObject/ValueObject.cpp +++ b/lldb/source/ValueObject/ValueObject.cpp @@ -734,26 +734,22 @@ size_t ValueObject::GetPointeeData(DataExtractor &data, uint32_t item_idx, } break; case eAddressTypeLoad: { ExecutionContext exe_ctx(GetExecutionContextRef()); - Process *process = exe_ctx.GetProcessPtr(); - if (process && process->IsLiveDebugSession()) { - heap_buf_ptr->SetByteSize(bytes); - size_t bytes_read = process->ReadMemory( + heap_buf_ptr->SetByteSize(bytes); + size_t bytes_read = 0; + if (Process *process = exe_ctx.GetProcessPtr(); + process && process->IsLiveDebugSession()) { + bytes_read = process->ReadMemory( addr + offset, heap_buf_ptr->GetBytes(), bytes, error); - if (error.Success() || bytes_read > 0) { - data.SetData(data_sp); - return bytes_read; - } } else if (Target *target = exe_ctx.GetTargetPtr()) { Address target_addr; target_addr.SetLoadAddress(addr + offset, target); - heap_buf_ptr->SetByteSize(bytes); - size_t bytes_read = + bytes_read = target->ReadMemory(target_addr, heap_buf_ptr->GetBytes(), bytes, error, /*force_live_memory=*/true); - if (error.Success() || bytes_read > 0) { - data.SetData(data_sp); - return bytes_read; - } + } + if (error.Success() || bytes_read > 0) { + data.SetData(data_sp); + return bytes_read; } } break; case eAddressTypeHost: { >From 6fde782f6e44d98b3ef03081daa8fe421a5259ef Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Mon, 12 May 2025 11:02:45 -0700 Subject: [PATCH 4/4] fixup: Use 'Target::ReadMemory()' for live debug sessions --- lldb/source/ValueObject/ValueObject.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp index 1375b67d72ff6..671f72286a1de 100644 --- a/lldb/source/ValueObject/ValueObject.cpp +++ b/lldb/source/ValueObject/ValueObject.cpp @@ -734,22 +734,17 @@ size_t ValueObject::GetPointeeData(DataExtractor &data, uint32_t item_idx, } break; case eAddressTypeLoad: { ExecutionContext exe_ctx(GetExecutionContextRef()); - heap_buf_ptr->SetByteSize(bytes); - size_t bytes_read = 0; - if (Process *process = exe_ctx.GetProcessPtr(); - process && process->IsLiveDebugSession()) { - bytes_read = process->ReadMemory( - addr + offset, heap_buf_ptr->GetBytes(), bytes, error); - } else if (Target *target = exe_ctx.GetTargetPtr()) { + if (Target *target = exe_ctx.GetTargetPtr()) { + heap_buf_ptr->SetByteSize(bytes); Address target_addr; target_addr.SetLoadAddress(addr + offset, target); - bytes_read = + size_t bytes_read = target->ReadMemory(target_addr, heap_buf_ptr->GetBytes(), bytes, error, /*force_live_memory=*/true); - } - if (error.Success() || bytes_read > 0) { - data.SetData(data_sp); - return bytes_read; + if (error.Success() || bytes_read > 0) { + data.SetData(data_sp); + return bytes_read; + } } } break; case eAddressTypeHost: { From lldb-commits at lists.llvm.org Mon May 12 11:06:54 2025 From: lldb-commits at lists.llvm.org (Nico Weber via lldb-commits) Date: Mon, 12 May 2025 11:06:54 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Split lldb-dap into library and tool (NFC) (PR #139402) In-Reply-To: Message-ID: <682238be.170a0220.11ca71.9b87@mx.google.com> ================ @@ -1,20 +1,11 @@ -if(APPLE) - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/lldb-dap-Info.plist.in - ${CMAKE_CURRENT_BINARY_DIR}/lldb-dap-Info.plist - ) - # Inline info plist in binary (use target_link_options for this as soon as CMake 3.13 is available) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_BINARY_DIR}/lldb-dap-Info.plist") -endif() - # We need to include the llvm components we depend on manually, as liblldb does # not re-export those. set(LLVM_LINK_COMPONENTS Support) set(LLVM_TARGET_DEFINITIONS Options.td) ---------------- nico wrote: Should this move too? The .inc file is only used in lldb-dap.cpp. https://github.com/llvm/llvm-project/pull/139402 From lldb-commits at lists.llvm.org Mon May 12 11:14:40 2025 From: lldb-commits at lists.llvm.org (Alex Langford via lldb-commits) Date: Mon, 12 May 2025 11:14:40 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream lldb-rpc-gen tool (PR #138031) In-Reply-To: Message-ID: <68223a90.170a0220.30c4eb.abf6@mx.google.com> ================ @@ -0,0 +1,535 @@ +//===-- RPCCommon.cpp -----------------------------------------------------===// +// +// 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 "RPCCommon.h" + +#include "clang/AST/AST.h" +#include "clang/AST/Mangle.h" +#include "clang/Lex/Lexer.h" + +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +// We intentionally do not generate some classes because they are currently +// inconvenient, they aren't really used by most consumers, or we're not sure +// why they exist. +static constexpr llvm::StringRef DisallowedClasses[] = { + "SBCommunication", // What is this used for? + "SBInputReader", // What is this used for? + "SBCommandPluginInterface", // This is hard to support, we can do it if + // really needed though. + "SBCommand", // There's nothing too difficult about this one, but many of + // its methods take a SBCommandPluginInterface pointer so + // there's no reason to support this. +}; + +// We intentionally avoid generating certain methods either because they are +// difficult to support correctly or they aren't really used much from C++. +// FIXME: We should be able to annotate these methods instead of maintaining a +// list in the generator itself. +static constexpr llvm::StringRef DisallowedMethods[] = { + // The threading functionality in SBHostOS is deprecated and thus we do not + // generate them. It would be ideal to add the annotations to the methods + // and then support not generating deprecated methods. However, without + // annotations the generator generates most things correctly. This one is + // problematic because it returns a pointer to an "opaque" structure + // (thread_t) that is not `void *`, so special casing it is more effort than + // it's worth. + "_ZN4lldb8SBHostOS10ThreadJoinEP17_opaque_pthread_tPPvPNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadCancelEP17_opaque_pthread_tPNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadCreateEPKcPFPvS3_ES3_PNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadDetachEP17_opaque_pthread_tPNS_7SBErrorE", + "_ZN4lldb8SBHostOS13ThreadCreatedEPKc", +}; + +static constexpr llvm::StringRef ClassesWithoutDefaultCtor[] = { + "SBHostOS", + "SBReproducer", +}; + +static constexpr llvm::StringRef ClassesWithoutCopyOperations[] = { + "SBHostOS", + "SBReproducer", + "SBStream", + "SBProgress", +}; + +static constexpr llvm::StringRef MethodsWithPointerPlusLen[] = { ---------------- bulbazord wrote: I'm still not sure what this would look like. Do you have some pseudocode or a sketch of the idea? I'm hesitant to add an entire new class just for RPC's sake, but it's hard to evaluate without more details. https://github.com/llvm/llvm-project/pull/138031 From lldb-commits at lists.llvm.org Mon May 12 11:17:25 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Mon, 12 May 2025 11:17:25 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Support for XCOFF Sections (PR #131304) In-Reply-To: Message-ID: <68223b35.050a0220.298afc.afea@mx.google.com> ================ @@ -7,6 +7,9 @@ # CHECK: Stripped: false # CHECK: Type: executable # CHECK: Strata: unknown +# CHECK: Name: .text +# CHECK-NEXT: code +# CHECK-NEXT: r-x ---------------- DhruvSrivastavaX wrote: Right, thats reasonable! Will increment accordingly in upcoming additions. https://github.com/llvm/llvm-project/pull/131304 From lldb-commits at lists.llvm.org Mon May 12 11:18:03 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Mon, 12 May 2025 11:18:03 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] While handling events, grab the APIMutex for consistency. (PR #139596) In-Reply-To: Message-ID: <68223b5b.170a0220.17ea02.9d07@mx.google.com> ashgti wrote: I've been thinking about that as well. I wasn't sure if there was an easy way to integrate the event system into a MainLoop helper but that would definitely help. https://github.com/llvm/llvm-project/pull/139596 From lldb-commits at lists.llvm.org Mon May 12 11:19:25 2025 From: lldb-commits at lists.llvm.org (Jacques Pienaar via lldb-commits) Date: Mon, 12 May 2025 11:19:25 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][plugin] Clear in same thread as set (PR #139252) In-Reply-To: Message-ID: <68223bad.170a0220.a5bf0.c027@mx.google.com> https://github.com/jpienaar updated https://github.com/llvm/llvm-project/pull/139252 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Mon May 12 11:20:38 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Mon, 12 May 2025 11:20:38 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit tests for protocol types (PR #139502) In-Reply-To: Message-ID: <68223bf6.170a0220.3bf523.d5ed@mx.google.com> https://github.com/ashgti approved this pull request. https://github.com/llvm/llvm-project/pull/139502 From lldb-commits at lists.llvm.org Mon May 12 11:20:38 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Mon, 12 May 2025 11:20:38 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit tests for protocol types (PR #139502) In-Reply-To: Message-ID: <68223bf6.050a0220.1f17d4.ab44@mx.google.com> ================ @@ -0,0 +1,62 @@ +//===-- ProtocolTypesTest.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 "Protocol/ProtocolTypes.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" + +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap::protocol; + +template static llvm::Expected roundtrip(const T &input) { + llvm::json::Value value = toJSON(input); + llvm::json::Path::Root root; + T output; + if (!fromJSON(value, output, root)) + return root.getError(); + return output; +} + +TEST(ProtocolTypesTest, ExceptionBreakpointsFilter) { + ExceptionBreakpointsFilter filter; + filter.filter = "testFilter"; + filter.label = "Test Filter"; + filter.description = "This is a test filter"; + filter.defaultState = true; + filter.supportsCondition = true; + filter.conditionDescription = "Condition for test filter"; + + llvm::Expected deserialized_filter = + roundtrip(filter); + ASSERT_THAT_EXPECTED(deserialized_filter, llvm::Succeeded()); + + EXPECT_EQ(filter.filter, deserialized_filter->filter); + EXPECT_EQ(filter.label, deserialized_filter->label); + EXPECT_EQ(filter.description, deserialized_filter->description); + EXPECT_EQ(filter.defaultState, deserialized_filter->defaultState); + EXPECT_EQ(filter.supportsCondition, deserialized_filter->supportsCondition); + EXPECT_EQ(filter.conditionDescription, + deserialized_filter->conditionDescription); ---------------- ashgti wrote: I think `json::Value` has a `==` operator, if you want to just compare the two `json::Value` objects, it would mean we wouldn't need to compare each field directly. https://github.com/llvm/llvm-project/pull/139502 From lldb-commits at lists.llvm.org Mon May 12 11:56:02 2025 From: lldb-commits at lists.llvm.org (Chelsea Cassanova via lldb-commits) Date: Mon, 12 May 2025 11:56:02 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream lldb-rpc-gen tool (PR #138031) In-Reply-To: Message-ID: <68224442.050a0220.1fa9bd.e5d6@mx.google.com> ================ @@ -0,0 +1,535 @@ +//===-- RPCCommon.cpp -----------------------------------------------------===// +// +// 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 "RPCCommon.h" + +#include "clang/AST/AST.h" +#include "clang/AST/Mangle.h" +#include "clang/Lex/Lexer.h" + +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +// We intentionally do not generate some classes because they are currently +// inconvenient, they aren't really used by most consumers, or we're not sure +// why they exist. +static constexpr llvm::StringRef DisallowedClasses[] = { + "SBCommunication", // What is this used for? + "SBInputReader", // What is this used for? + "SBCommandPluginInterface", // This is hard to support, we can do it if + // really needed though. + "SBCommand", // There's nothing too difficult about this one, but many of + // its methods take a SBCommandPluginInterface pointer so + // there's no reason to support this. +}; + +// We intentionally avoid generating certain methods either because they are +// difficult to support correctly or they aren't really used much from C++. +// FIXME: We should be able to annotate these methods instead of maintaining a +// list in the generator itself. +static constexpr llvm::StringRef DisallowedMethods[] = { + // The threading functionality in SBHostOS is deprecated and thus we do not + // generate them. It would be ideal to add the annotations to the methods + // and then support not generating deprecated methods. However, without + // annotations the generator generates most things correctly. This one is + // problematic because it returns a pointer to an "opaque" structure + // (thread_t) that is not `void *`, so special casing it is more effort than + // it's worth. + "_ZN4lldb8SBHostOS10ThreadJoinEP17_opaque_pthread_tPPvPNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadCancelEP17_opaque_pthread_tPNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadCreateEPKcPFPvS3_ES3_PNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadDetachEP17_opaque_pthread_tPNS_7SBErrorE", + "_ZN4lldb8SBHostOS13ThreadCreatedEPKc", +}; + +static constexpr llvm::StringRef ClassesWithoutDefaultCtor[] = { + "SBHostOS", + "SBReproducer", +}; + +static constexpr llvm::StringRef ClassesWithoutCopyOperations[] = { + "SBHostOS", + "SBReproducer", + "SBStream", + "SBProgress", +}; + +static constexpr llvm::StringRef MethodsWithPointerPlusLen[] = { ---------------- chelcassanova wrote: So you'd have a class called something like `SBBuffer` and it would have a struct: ``` struct Buffer { Buffer(void *buf, size_t size) {} }; ``` that covers a pointer + len. In a function that uses it (e.g. `size_t ReadRawData(lldb::SBError &error, lldb::offset_t offset, void *buf, size_t size`) becomes `size_t ReadRawData(lldb::SBError &error, lldb::offset_t offset, SBBuffer buf)`. The tool could see that the method has an `SBBuffer` parameter, so that could satisfy the "this method is using a pointer followed by a length". The older version of the original method would be marked as deprecated. Obviously the main task here is having a cleaner way of knowing this detail about methods without maintaining an ever growing list. Another path we could try is using Clang's `annotate` attribute to note this information on the API side. The tool should also be able to pick up on this, but it also means adding an attribute to the main APIs that isn't very meaningful if you're not using RPC. https://github.com/llvm/llvm-project/pull/138031 From lldb-commits at lists.llvm.org Mon May 12 11:57:11 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Mon, 12 May 2025 11:57:11 -0700 (PDT) Subject: [Lldb-commits] [lldb] 4086d5f - [lldb-dap] Unbreak lldb-dap Message-ID: <68224487.170a0220.1762c6.a9e7@mx.google.com> Author: Jonas Devlieghere Date: 2025-05-12T11:56:57-07:00 New Revision: 4086d5ff74729e655c3b29479845c35c971541d9 URL: https://github.com/llvm/llvm-project/commit/4086d5ff74729e655c3b29479845c35c971541d9 DIFF: https://github.com/llvm/llvm-project/commit/4086d5ff74729e655c3b29479845c35c971541d9.diff LOG: [lldb-dap] Unbreak lldb-dap Added: Modified: lldb/tools/lldb-dap/CMakeLists.txt Removed: ################################################################################ diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 224d64b83b7d4..5dedee8a87f41 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -84,3 +84,5 @@ if(LLDB_DAP_WELCOME_MESSAGE) PRIVATE -DLLDB_DAP_WELCOME_MESSAGE=\"${LLDB_DAP_WELCOME_MESSAGE}\") endif() + +add_subdirectory(tool) From lldb-commits at lists.llvm.org Mon May 12 12:05:11 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Mon, 12 May 2025 12:05:11 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] While handling events, grab the APIMutex for consistency. (PR #139596) In-Reply-To: Message-ID: <68224667.050a0220.11b1d9.dc60@mx.google.com> ashgti wrote: I'll take a look at refactoring the `DAP::Loop` and `EventThread`. https://github.com/llvm/llvm-project/pull/139596 From lldb-commits at lists.llvm.org Mon May 12 12:34:41 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Mon, 12 May 2025 12:34:41 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Migrate ScopesRequest to structured types (PR #138116) In-Reply-To: Message-ID: <68224d51.170a0220.24fcbf.a142@mx.google.com> https://github.com/da-viper updated https://github.com/llvm/llvm-project/pull/138116 >From 98659ed9520b5364092e72420aee5edea7cb7bba Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Tue, 29 Apr 2025 18:19:18 +0100 Subject: [PATCH 1/2] [lldb][lldb-dap] Migrate 'Scopes' to structured types. --- lldb/tools/lldb-dap/DAP.cpp | 11 -- lldb/tools/lldb-dap/DAP.h | 2 - lldb/tools/lldb-dap/Handler/RequestHandler.h | 10 +- .../lldb-dap/Handler/ScopesRequestHandler.cpp | 121 ++++++++---------- lldb/tools/lldb-dap/JSONUtils.h | 21 --- .../lldb-dap/Protocol/ProtocolRequests.cpp | 14 ++ .../lldb-dap/Protocol/ProtocolRequests.h | 13 ++ .../tools/lldb-dap/Protocol/ProtocolTypes.cpp | 71 ++++++++-- lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 81 +++++++++++- 9 files changed, 224 insertions(+), 120 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 4feca1253be20..baaf9950b79db 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -559,17 +559,6 @@ lldb::SBFrame DAP::GetLLDBFrame(const llvm::json::Object &arguments) { return GetLLDBFrame(frame_id); } -llvm::json::Value DAP::CreateTopLevelScopes() { - llvm::json::Array scopes; - scopes.emplace_back( - CreateScope("Locals", VARREF_LOCALS, variables.locals.GetSize(), false)); - scopes.emplace_back(CreateScope("Globals", VARREF_GLOBALS, - variables.globals.GetSize(), false)); - scopes.emplace_back(CreateScope("Registers", VARREF_REGS, - variables.registers.GetSize(), false)); - return llvm::json::Value(std::move(scopes)); -} - ReplMode DAP::DetectReplMode(lldb::SBFrame frame, std::string &expression, bool partial_expression) { // Check for the escape hatch prefix. diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c2e4c2dea582e..f66cb40451484 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -285,8 +285,6 @@ struct DAP { lldb::SBFrame GetLLDBFrame(uint64_t frame_id); lldb::SBFrame GetLLDBFrame(const llvm::json::Object &arguments); - llvm::json::Value CreateTopLevelScopes(); - void PopulateExceptionBreakpoints(); /// Attempt to determine if an expression is a variable expression or diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index b0002440cf72e..eaebaf6619bbd 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -452,11 +452,15 @@ class PauseRequestHandler : public LegacyRequestHandler { void operator()(const llvm::json::Object &request) const override; }; -class ScopesRequestHandler : public LegacyRequestHandler { +class ScopesRequestHandler final + : public RequestHandler> { public: - using LegacyRequestHandler::LegacyRequestHandler; + using RequestHandler::RequestHandler; static llvm::StringLiteral GetCommand() { return "scopes"; } - void operator()(const llvm::json::Object &request) const override; + + llvm::Expected + Run(const protocol::ScopesArguments &args) const override; }; class SetVariableRequestHandler final diff --git a/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp index 7d1608f59f9a4..d9dd29f7269f2 100644 --- a/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp @@ -7,69 +7,55 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" #include "RequestHandler.h" +using namespace lldb_dap::protocol; namespace lldb_dap { -// "ScopesRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Scopes request; value of command field is 'scopes'. The -// request returns the variable scopes for a given stackframe ID.", -// "properties": { -// "command": { -// "type": "string", -// "enum": [ "scopes" ] -// }, -// "arguments": { -// "$ref": "#/definitions/ScopesArguments" -// } -// }, -// "required": [ "command", "arguments" ] -// }] -// }, -// "ScopesArguments": { -// "type": "object", -// "description": "Arguments for 'scopes' request.", -// "properties": { -// "frameId": { -// "type": "integer", -// "description": "Retrieve the scopes for this stackframe." -// } -// }, -// "required": [ "frameId" ] -// }, -// "ScopesResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to 'scopes' request.", -// "properties": { -// "body": { -// "type": "object", -// "properties": { -// "scopes": { -// "type": "array", -// "items": { -// "$ref": "#/definitions/Scope" -// }, -// "description": "The scopes of the stackframe. If the array has -// length zero, there are no scopes available." -// } -// }, -// "required": [ "scopes" ] -// } -// }, -// "required": [ "body" ] -// }] -// } -void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - llvm::json::Object body; - const auto *arguments = request.getObject("arguments"); - lldb::SBFrame frame = dap.GetLLDBFrame(*arguments); +/// Creates a `protocol::Scope` struct. +/// +/// +/// \param[in] name +/// The value to place into the "name" key +/// +/// \param[in] variablesReference +/// The value to place into the "variablesReference" key +/// +/// \param[in] namedVariables +/// The value to place into the "namedVariables" key +/// +/// \param[in] expensive +/// The value to place into the "expensive" key +/// +/// \return +/// A `protocol::Scope` +static Scope CreateScope(const llvm::StringRef name, int64_t variablesReference, + int64_t namedVariables, bool expensive) { + Scope scope; + scope.name = name; + + // TODO: Support "arguments" and "return value" scope. + // At the moment lldb-dap includes the arguments and return_value into the + // "locals" scope. add presentation hint; + // vscode only expands the first non-expensive scope, this causes friction + // as the locals scope will not be expanded. It becomes more annoying when + // the scope has arguments, return_value and locals. + if (variablesReference == VARREF_LOCALS) + scope.presentationHint = Scope::ePresentationHintLocals; + else if (variablesReference == VARREF_REGS) + scope.presentationHint = Scope::ePresentationHintRegisters; + + scope.variablesReference = variablesReference; + scope.namedVariables = namedVariables; + scope.expensive = expensive; + + return scope; +} + +llvm::Expected +ScopesRequestHandler::Run(const ScopesArguments &args) const { + lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId); + // As the user selects different stack frames in the GUI, a "scopes" request // will be sent to the DAP. This is the only way we know that the user has // selected a frame in a thread. There are no other notifications that are @@ -78,9 +64,9 @@ void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { // are sent, this allows users to type commands in the debugger console // with a backtick character to run lldb commands and these lldb commands // will now have the right context selected as they are run. If the user - // types "`bt" into the debugger console and we had another thread selected + // types "`bt" into the debugger console, and we had another thread selected // in the LLDB library, we would show the wrong thing to the user. If the - // users switches threads with a lldb command like "`thread select 14", the + // users switch threads with a lldb command like "`thread select 14", the // GUI will not update as there are no "event" notification packets that // allow us to change the currently selected thread or frame in the GUI that // I am aware of. @@ -88,7 +74,6 @@ void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { frame.GetThread().GetProcess().SetSelectedThread(frame.GetThread()); frame.GetThread().SetSelectedFrame(frame.GetFrameID()); } - dap.variables.locals = frame.GetVariables(/*arguments=*/true, /*locals=*/true, /*statics=*/false, @@ -98,9 +83,15 @@ void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { /*statics=*/true, /*in_scope_only=*/true); dap.variables.registers = frame.GetRegisters(); - body.try_emplace("scopes", dap.CreateTopLevelScopes()); - response.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(response))); + + std::vector scopes = {CreateScope("Locals", VARREF_LOCALS, + dap.variables.locals.GetSize(), false), + CreateScope("Globals", VARREF_GLOBALS, + dap.variables.globals.GetSize(), false), + CreateScope("Registers", VARREF_REGS, + dap.variables.registers.GetSize(), false)}; + + return ScopesResponseBody{std::move(scopes)}; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h index 9c4dd0584bd21..783f291338d8c 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -238,27 +238,6 @@ llvm::json::Object CreateEventObject(const llvm::StringRef event_name); protocol::ExceptionBreakpointsFilter CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp); -/// Create a "Scope" JSON object as described in the debug adapter definition. -/// -/// \param[in] name -/// The value to place into the "name" key -// -/// \param[in] variablesReference -/// The value to place into the "variablesReference" key -// -/// \param[in] namedVariables -/// The value to place into the "namedVariables" key -// -/// \param[in] expensive -/// The value to place into the "expensive" key -/// -/// \return -/// A "Scope" JSON object with that follows the formal JSON -/// definition outlined by Microsoft. -llvm::json::Value CreateScope(const llvm::StringRef name, - int64_t variablesReference, - int64_t namedVariables, bool expensive); - /// Create a "Source" JSON object as described in the debug adapter definition. /// /// \param[in] file diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp index 316e146d43a0f..7efab87d39986 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp @@ -335,6 +335,20 @@ llvm::json::Value toJSON(const SetVariableResponseBody &SVR) { return llvm::json::Value(std::move(Body)); } +bool fromJSON(const llvm::json::Value &Params, ScopesArguments &SCA, + llvm::json::Path P) { + json::ObjectMapper O(Params, P); + return O && O.map("frameId", SCA.frameId); +} + +llvm::json::Value toJSON(const ScopesResponseBody &SCR) { + llvm::json::Array scopes; + for (const Scope &scope : SCR.scopes) { + scopes.emplace_back(toJSON(scope)); + } + + return llvm::json::Object{{"scopes", std::move(scopes)}}; +} bool fromJSON(const json::Value &Params, SourceArguments &SA, json::Path P) { json::ObjectMapper O(Params, P); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index c6456b4113320..79739d8fc4309 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -439,6 +439,19 @@ struct SetVariableResponseBody { }; llvm::json::Value toJSON(const SetVariableResponseBody &); +struct ScopesArguments { + /// Retrieve the scopes for the stack frame identified by `frameId`. The + /// `frameId` must have been obtained in the current suspended state. See + /// 'Lifetime of Object References' in the Overview section for details. + uint64_t frameId; +}; +bool fromJSON(const llvm::json::Value &, ScopesArguments &, llvm::json::Path); + +struct ScopesResponseBody { + std::vector scopes; +}; +llvm::json::Value toJSON(const ScopesResponseBody &); + /// Arguments for `source` request. struct SourceArguments { /// Specifies the source content to load. Either `source.path` or diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index 2b7419916268b..2536d93a286a6 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -16,17 +16,18 @@ using namespace llvm; namespace lldb_dap::protocol { -bool fromJSON(const json::Value &Params, PresentationHint &PH, json::Path P) { +bool fromJSON(const json::Value &Params, Source::PresentationHint &PH, + json::Path P) { auto rawHint = Params.getAsString(); if (!rawHint) { P.report("expected a string"); return false; } - std::optional hint = - StringSwitch>(*rawHint) - .Case("normal", ePresentationHintNormal) - .Case("emphasize", ePresentationHintEmphasize) - .Case("deemphasize", ePresentationHintDeemphasize) + std::optional hint = + StringSwitch>(*rawHint) + .Case("normal", Source::ePresentationHintNormal) + .Case("emphasize", Source::ePresentationHintEmphasize) + .Case("deemphasize", Source::ePresentationHintDeemphasize) .Default(std::nullopt); if (!hint) { P.report("unexpected value"); @@ -42,14 +43,13 @@ bool fromJSON(const json::Value &Params, Source &S, json::Path P) { O.map("presentationHint", S.presentationHint) && O.map("sourceReference", S.sourceReference); } - -llvm::json::Value toJSON(PresentationHint hint) { +llvm::json::Value toJSON(Source::PresentationHint hint) { switch (hint) { - case ePresentationHintNormal: + case Source::ePresentationHintNormal: return "normal"; - case ePresentationHintEmphasize: + case Source::ePresentationHintEmphasize: return "emphasize"; - case ePresentationHintDeemphasize: + case Source::ePresentationHintDeemphasize: return "deemphasize"; } llvm_unreachable("unhandled presentation hint."); @@ -259,6 +259,55 @@ json::Value toJSON(const Capabilities &C) { return result; } +llvm::json::Value toJSON(const Scope &SC) { + llvm::json::Object result{{"name", SC.name}, + {"variablesReference", SC.variablesReference}, + {"expensive", SC.expensive}}; + + if (SC.presentationHint.has_value()) { + llvm::StringRef presentationHint; + switch (*SC.presentationHint) { + case Scope::ePresentationHintArguments: + presentationHint = "arguments"; + break; + case Scope::ePresentationHintLocals: + presentationHint = "locals"; + break; + case Scope::ePresentationHintRegisters: + presentationHint = "registers"; + break; + case Scope::ePresentationHintReturnValue: + presentationHint = "returnValue"; + break; + } + + result.insert({"presentationHint", presentationHint}); + } + + if (SC.namedVariables.has_value()) + result.insert({"namedVariables", SC.namedVariables}); + + if (SC.indexedVariables.has_value()) + result.insert({"indexedVariables", SC.indexedVariables}); + + if (SC.source.has_value()) + result.insert({"source", SC.source}); + + if (SC.line.has_value()) + result.insert({"line", SC.line}); + + if (SC.column.has_value()) + result.insert({"column", SC.column}); + + if (SC.endLine.has_value()) + result.insert({"endLine", SC.endLine}); + + if (SC.endColumn.has_value()) + result.insert({"endColumn", SC.endColumn}); + + return result; +} + bool fromJSON(const llvm::json::Value &Params, SteppingGranularity &SG, llvm::json::Path P) { auto raw_granularity = Params.getAsString(); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index 1f0cb1e0b2d41..0fcde4c52ad19 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -269,17 +269,16 @@ struct Capabilities { }; llvm::json::Value toJSON(const Capabilities &); -enum PresentationHint : unsigned { - ePresentationHintNormal, - ePresentationHintEmphasize, - ePresentationHintDeemphasize, -}; -llvm::json::Value toJSON(PresentationHint hint); - /// A `Source` is a descriptor for source code. It is returned from the debug /// adapter as part of a `StackFrame` and it is used by clients when specifying /// breakpoints. struct Source { + enum PresentationHint : unsigned { + ePresentationHintNormal, + ePresentationHintEmphasize, + ePresentationHintDeemphasize, + }; + /// The short name of the source. Every source returned from the debug adapter /// has a name. When sending a source to the debug adapter this name is /// optional. @@ -303,9 +302,77 @@ struct Source { // unsupported keys: origin, sources, adapterData, checksums }; +llvm::json::Value toJSON(Source::PresentationHint); bool fromJSON(const llvm::json::Value &, Source &, llvm::json::Path); llvm::json::Value toJSON(const Source &); +/// A `Scope` is a named container for variables. Optionally a scope can map to +/// a source or a range within a source. +struct Scope { + enum PresentationHint : unsigned { + ePresentationHintArguments, + ePresentationHintLocals, + ePresentationHintRegisters, + ePresentationHintReturnValue + }; + /// Name of the scope such as 'Arguments', 'Locals', or 'Registers'. This + /// string is shown in the UI as is and can be translated. + //// + std::string name; + + /// A hint for how to present this scope in the UI. If this attribute is + /// missing, the scope is shown with a generic UI. + /// Values: + /// 'arguments': Scope contains method arguments. + /// 'locals': Scope contains local variables. + /// 'registers': Scope contains registers. Only a single `registers` scope + /// should be returned from a `scopes` request. + /// 'returnValue': Scope contains one or more return values. + /// etc. + std::optional presentationHint; + + /// The variables of this scope can be retrieved by passing the value of + /// `variablesReference` to the `variables` request as long as execution + /// remains suspended. See 'Lifetime of Object References' in the Overview + /// section for details. + //// + uint64_t variablesReference; + + /// The number of named variables in this scope. + /// The client can use this information to present the variables in a paged UI + /// and fetch them in chunks. + std::optional namedVariables; + + /// The number of indexed variables in this scope. + /// The client can use this information to present the variables in a paged UI + /// and fetch them in chunks. + std::optional indexedVariables; + + /// The source for this scope. + std::optional source; + + /// If true, the number of variables in this scope is large or expensive to + /// retrieve. + bool expensive; + + /// The start line of the range covered by this scope. + std::optional line; + + /// Start position of the range covered by the scope. It is measured in UTF-16 + /// code units and the client capability `columnsStartAt1` determines whether + /// it is 0- or 1-based. + std::optional column; + + /// The end line of the range covered by this scope. + std::optional endLine; + + /// End position of the range covered by the scope. It is measured in UTF-16 + /// code units and the client capability `columnsStartAt1` determines whether + /// it is 0- or 1-based. + std::optional endColumn; +}; +llvm::json::Value toJSON(const Scope &); + /// The granularity of one `step` in the stepping requests `next`, `stepIn`, /// `stepOut` and `stepBack`. enum SteppingGranularity : unsigned { >From 17828314bc80e4bf22db4d39f424eee45de6f0a2 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Mon, 12 May 2025 20:33:33 +0100 Subject: [PATCH 2/2] [lldb][lldb-dap] review changes --- lldb/tools/lldb-dap/Protocol/ProtocolRequests.h | 2 +- lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index 79739d8fc4309..f8d6b6a8581ea 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -443,7 +443,7 @@ struct ScopesArguments { /// Retrieve the scopes for the stack frame identified by `frameId`. The /// `frameId` must have been obtained in the current suspended state. See /// 'Lifetime of Object References' in the Overview section for details. - uint64_t frameId; + uint64_t frameId = LLDB_INVALID_FRAME_ID; }; bool fromJSON(const llvm::json::Value &, ScopesArguments &, llvm::json::Path); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index 0fcde4c52ad19..e60e092676a69 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -27,6 +27,8 @@ #include #include +#define LLDB_DAP_INVALID_VARRERF UINT64_MAX + namespace lldb_dap::protocol { /// An `ExceptionBreakpointsFilter` is shown in the UI as an filter option for @@ -336,7 +338,7 @@ struct Scope { /// remains suspended. See 'Lifetime of Object References' in the Overview /// section for details. //// - uint64_t variablesReference; + uint64_t variablesReference = LLDB_DAP_INVALID_VARRERF; /// The number of named variables in this scope. /// The client can use this information to present the variables in a paged UI @@ -353,7 +355,7 @@ struct Scope { /// If true, the number of variables in this scope is large or expensive to /// retrieve. - bool expensive; + bool expensive = false; /// The start line of the range covered by this scope. std::optional line; From lldb-commits at lists.llvm.org Mon May 12 12:36:44 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Mon, 12 May 2025 12:36:44 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Migrate ScopesRequest to structured types (PR #138116) In-Reply-To: Message-ID: <68224dcc.050a0220.38b529.b87f@mx.google.com> https://github.com/da-viper updated https://github.com/llvm/llvm-project/pull/138116 >From 98659ed9520b5364092e72420aee5edea7cb7bba Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Tue, 29 Apr 2025 18:19:18 +0100 Subject: [PATCH 1/3] [lldb][lldb-dap] Migrate 'Scopes' to structured types. --- lldb/tools/lldb-dap/DAP.cpp | 11 -- lldb/tools/lldb-dap/DAP.h | 2 - lldb/tools/lldb-dap/Handler/RequestHandler.h | 10 +- .../lldb-dap/Handler/ScopesRequestHandler.cpp | 121 ++++++++---------- lldb/tools/lldb-dap/JSONUtils.h | 21 --- .../lldb-dap/Protocol/ProtocolRequests.cpp | 14 ++ .../lldb-dap/Protocol/ProtocolRequests.h | 13 ++ .../tools/lldb-dap/Protocol/ProtocolTypes.cpp | 71 ++++++++-- lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 81 +++++++++++- 9 files changed, 224 insertions(+), 120 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 4feca1253be20..baaf9950b79db 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -559,17 +559,6 @@ lldb::SBFrame DAP::GetLLDBFrame(const llvm::json::Object &arguments) { return GetLLDBFrame(frame_id); } -llvm::json::Value DAP::CreateTopLevelScopes() { - llvm::json::Array scopes; - scopes.emplace_back( - CreateScope("Locals", VARREF_LOCALS, variables.locals.GetSize(), false)); - scopes.emplace_back(CreateScope("Globals", VARREF_GLOBALS, - variables.globals.GetSize(), false)); - scopes.emplace_back(CreateScope("Registers", VARREF_REGS, - variables.registers.GetSize(), false)); - return llvm::json::Value(std::move(scopes)); -} - ReplMode DAP::DetectReplMode(lldb::SBFrame frame, std::string &expression, bool partial_expression) { // Check for the escape hatch prefix. diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c2e4c2dea582e..f66cb40451484 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -285,8 +285,6 @@ struct DAP { lldb::SBFrame GetLLDBFrame(uint64_t frame_id); lldb::SBFrame GetLLDBFrame(const llvm::json::Object &arguments); - llvm::json::Value CreateTopLevelScopes(); - void PopulateExceptionBreakpoints(); /// Attempt to determine if an expression is a variable expression or diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index b0002440cf72e..eaebaf6619bbd 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -452,11 +452,15 @@ class PauseRequestHandler : public LegacyRequestHandler { void operator()(const llvm::json::Object &request) const override; }; -class ScopesRequestHandler : public LegacyRequestHandler { +class ScopesRequestHandler final + : public RequestHandler> { public: - using LegacyRequestHandler::LegacyRequestHandler; + using RequestHandler::RequestHandler; static llvm::StringLiteral GetCommand() { return "scopes"; } - void operator()(const llvm::json::Object &request) const override; + + llvm::Expected + Run(const protocol::ScopesArguments &args) const override; }; class SetVariableRequestHandler final diff --git a/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp index 7d1608f59f9a4..d9dd29f7269f2 100644 --- a/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp @@ -7,69 +7,55 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" #include "RequestHandler.h" +using namespace lldb_dap::protocol; namespace lldb_dap { -// "ScopesRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Scopes request; value of command field is 'scopes'. The -// request returns the variable scopes for a given stackframe ID.", -// "properties": { -// "command": { -// "type": "string", -// "enum": [ "scopes" ] -// }, -// "arguments": { -// "$ref": "#/definitions/ScopesArguments" -// } -// }, -// "required": [ "command", "arguments" ] -// }] -// }, -// "ScopesArguments": { -// "type": "object", -// "description": "Arguments for 'scopes' request.", -// "properties": { -// "frameId": { -// "type": "integer", -// "description": "Retrieve the scopes for this stackframe." -// } -// }, -// "required": [ "frameId" ] -// }, -// "ScopesResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to 'scopes' request.", -// "properties": { -// "body": { -// "type": "object", -// "properties": { -// "scopes": { -// "type": "array", -// "items": { -// "$ref": "#/definitions/Scope" -// }, -// "description": "The scopes of the stackframe. If the array has -// length zero, there are no scopes available." -// } -// }, -// "required": [ "scopes" ] -// } -// }, -// "required": [ "body" ] -// }] -// } -void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - llvm::json::Object body; - const auto *arguments = request.getObject("arguments"); - lldb::SBFrame frame = dap.GetLLDBFrame(*arguments); +/// Creates a `protocol::Scope` struct. +/// +/// +/// \param[in] name +/// The value to place into the "name" key +/// +/// \param[in] variablesReference +/// The value to place into the "variablesReference" key +/// +/// \param[in] namedVariables +/// The value to place into the "namedVariables" key +/// +/// \param[in] expensive +/// The value to place into the "expensive" key +/// +/// \return +/// A `protocol::Scope` +static Scope CreateScope(const llvm::StringRef name, int64_t variablesReference, + int64_t namedVariables, bool expensive) { + Scope scope; + scope.name = name; + + // TODO: Support "arguments" and "return value" scope. + // At the moment lldb-dap includes the arguments and return_value into the + // "locals" scope. add presentation hint; + // vscode only expands the first non-expensive scope, this causes friction + // as the locals scope will not be expanded. It becomes more annoying when + // the scope has arguments, return_value and locals. + if (variablesReference == VARREF_LOCALS) + scope.presentationHint = Scope::ePresentationHintLocals; + else if (variablesReference == VARREF_REGS) + scope.presentationHint = Scope::ePresentationHintRegisters; + + scope.variablesReference = variablesReference; + scope.namedVariables = namedVariables; + scope.expensive = expensive; + + return scope; +} + +llvm::Expected +ScopesRequestHandler::Run(const ScopesArguments &args) const { + lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId); + // As the user selects different stack frames in the GUI, a "scopes" request // will be sent to the DAP. This is the only way we know that the user has // selected a frame in a thread. There are no other notifications that are @@ -78,9 +64,9 @@ void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { // are sent, this allows users to type commands in the debugger console // with a backtick character to run lldb commands and these lldb commands // will now have the right context selected as they are run. If the user - // types "`bt" into the debugger console and we had another thread selected + // types "`bt" into the debugger console, and we had another thread selected // in the LLDB library, we would show the wrong thing to the user. If the - // users switches threads with a lldb command like "`thread select 14", the + // users switch threads with a lldb command like "`thread select 14", the // GUI will not update as there are no "event" notification packets that // allow us to change the currently selected thread or frame in the GUI that // I am aware of. @@ -88,7 +74,6 @@ void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { frame.GetThread().GetProcess().SetSelectedThread(frame.GetThread()); frame.GetThread().SetSelectedFrame(frame.GetFrameID()); } - dap.variables.locals = frame.GetVariables(/*arguments=*/true, /*locals=*/true, /*statics=*/false, @@ -98,9 +83,15 @@ void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { /*statics=*/true, /*in_scope_only=*/true); dap.variables.registers = frame.GetRegisters(); - body.try_emplace("scopes", dap.CreateTopLevelScopes()); - response.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(response))); + + std::vector scopes = {CreateScope("Locals", VARREF_LOCALS, + dap.variables.locals.GetSize(), false), + CreateScope("Globals", VARREF_GLOBALS, + dap.variables.globals.GetSize(), false), + CreateScope("Registers", VARREF_REGS, + dap.variables.registers.GetSize(), false)}; + + return ScopesResponseBody{std::move(scopes)}; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h index 9c4dd0584bd21..783f291338d8c 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -238,27 +238,6 @@ llvm::json::Object CreateEventObject(const llvm::StringRef event_name); protocol::ExceptionBreakpointsFilter CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp); -/// Create a "Scope" JSON object as described in the debug adapter definition. -/// -/// \param[in] name -/// The value to place into the "name" key -// -/// \param[in] variablesReference -/// The value to place into the "variablesReference" key -// -/// \param[in] namedVariables -/// The value to place into the "namedVariables" key -// -/// \param[in] expensive -/// The value to place into the "expensive" key -/// -/// \return -/// A "Scope" JSON object with that follows the formal JSON -/// definition outlined by Microsoft. -llvm::json::Value CreateScope(const llvm::StringRef name, - int64_t variablesReference, - int64_t namedVariables, bool expensive); - /// Create a "Source" JSON object as described in the debug adapter definition. /// /// \param[in] file diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp index 316e146d43a0f..7efab87d39986 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp @@ -335,6 +335,20 @@ llvm::json::Value toJSON(const SetVariableResponseBody &SVR) { return llvm::json::Value(std::move(Body)); } +bool fromJSON(const llvm::json::Value &Params, ScopesArguments &SCA, + llvm::json::Path P) { + json::ObjectMapper O(Params, P); + return O && O.map("frameId", SCA.frameId); +} + +llvm::json::Value toJSON(const ScopesResponseBody &SCR) { + llvm::json::Array scopes; + for (const Scope &scope : SCR.scopes) { + scopes.emplace_back(toJSON(scope)); + } + + return llvm::json::Object{{"scopes", std::move(scopes)}}; +} bool fromJSON(const json::Value &Params, SourceArguments &SA, json::Path P) { json::ObjectMapper O(Params, P); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index c6456b4113320..79739d8fc4309 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -439,6 +439,19 @@ struct SetVariableResponseBody { }; llvm::json::Value toJSON(const SetVariableResponseBody &); +struct ScopesArguments { + /// Retrieve the scopes for the stack frame identified by `frameId`. The + /// `frameId` must have been obtained in the current suspended state. See + /// 'Lifetime of Object References' in the Overview section for details. + uint64_t frameId; +}; +bool fromJSON(const llvm::json::Value &, ScopesArguments &, llvm::json::Path); + +struct ScopesResponseBody { + std::vector scopes; +}; +llvm::json::Value toJSON(const ScopesResponseBody &); + /// Arguments for `source` request. struct SourceArguments { /// Specifies the source content to load. Either `source.path` or diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index 2b7419916268b..2536d93a286a6 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -16,17 +16,18 @@ using namespace llvm; namespace lldb_dap::protocol { -bool fromJSON(const json::Value &Params, PresentationHint &PH, json::Path P) { +bool fromJSON(const json::Value &Params, Source::PresentationHint &PH, + json::Path P) { auto rawHint = Params.getAsString(); if (!rawHint) { P.report("expected a string"); return false; } - std::optional hint = - StringSwitch>(*rawHint) - .Case("normal", ePresentationHintNormal) - .Case("emphasize", ePresentationHintEmphasize) - .Case("deemphasize", ePresentationHintDeemphasize) + std::optional hint = + StringSwitch>(*rawHint) + .Case("normal", Source::ePresentationHintNormal) + .Case("emphasize", Source::ePresentationHintEmphasize) + .Case("deemphasize", Source::ePresentationHintDeemphasize) .Default(std::nullopt); if (!hint) { P.report("unexpected value"); @@ -42,14 +43,13 @@ bool fromJSON(const json::Value &Params, Source &S, json::Path P) { O.map("presentationHint", S.presentationHint) && O.map("sourceReference", S.sourceReference); } - -llvm::json::Value toJSON(PresentationHint hint) { +llvm::json::Value toJSON(Source::PresentationHint hint) { switch (hint) { - case ePresentationHintNormal: + case Source::ePresentationHintNormal: return "normal"; - case ePresentationHintEmphasize: + case Source::ePresentationHintEmphasize: return "emphasize"; - case ePresentationHintDeemphasize: + case Source::ePresentationHintDeemphasize: return "deemphasize"; } llvm_unreachable("unhandled presentation hint."); @@ -259,6 +259,55 @@ json::Value toJSON(const Capabilities &C) { return result; } +llvm::json::Value toJSON(const Scope &SC) { + llvm::json::Object result{{"name", SC.name}, + {"variablesReference", SC.variablesReference}, + {"expensive", SC.expensive}}; + + if (SC.presentationHint.has_value()) { + llvm::StringRef presentationHint; + switch (*SC.presentationHint) { + case Scope::ePresentationHintArguments: + presentationHint = "arguments"; + break; + case Scope::ePresentationHintLocals: + presentationHint = "locals"; + break; + case Scope::ePresentationHintRegisters: + presentationHint = "registers"; + break; + case Scope::ePresentationHintReturnValue: + presentationHint = "returnValue"; + break; + } + + result.insert({"presentationHint", presentationHint}); + } + + if (SC.namedVariables.has_value()) + result.insert({"namedVariables", SC.namedVariables}); + + if (SC.indexedVariables.has_value()) + result.insert({"indexedVariables", SC.indexedVariables}); + + if (SC.source.has_value()) + result.insert({"source", SC.source}); + + if (SC.line.has_value()) + result.insert({"line", SC.line}); + + if (SC.column.has_value()) + result.insert({"column", SC.column}); + + if (SC.endLine.has_value()) + result.insert({"endLine", SC.endLine}); + + if (SC.endColumn.has_value()) + result.insert({"endColumn", SC.endColumn}); + + return result; +} + bool fromJSON(const llvm::json::Value &Params, SteppingGranularity &SG, llvm::json::Path P) { auto raw_granularity = Params.getAsString(); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index 1f0cb1e0b2d41..0fcde4c52ad19 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -269,17 +269,16 @@ struct Capabilities { }; llvm::json::Value toJSON(const Capabilities &); -enum PresentationHint : unsigned { - ePresentationHintNormal, - ePresentationHintEmphasize, - ePresentationHintDeemphasize, -}; -llvm::json::Value toJSON(PresentationHint hint); - /// A `Source` is a descriptor for source code. It is returned from the debug /// adapter as part of a `StackFrame` and it is used by clients when specifying /// breakpoints. struct Source { + enum PresentationHint : unsigned { + ePresentationHintNormal, + ePresentationHintEmphasize, + ePresentationHintDeemphasize, + }; + /// The short name of the source. Every source returned from the debug adapter /// has a name. When sending a source to the debug adapter this name is /// optional. @@ -303,9 +302,77 @@ struct Source { // unsupported keys: origin, sources, adapterData, checksums }; +llvm::json::Value toJSON(Source::PresentationHint); bool fromJSON(const llvm::json::Value &, Source &, llvm::json::Path); llvm::json::Value toJSON(const Source &); +/// A `Scope` is a named container for variables. Optionally a scope can map to +/// a source or a range within a source. +struct Scope { + enum PresentationHint : unsigned { + ePresentationHintArguments, + ePresentationHintLocals, + ePresentationHintRegisters, + ePresentationHintReturnValue + }; + /// Name of the scope such as 'Arguments', 'Locals', or 'Registers'. This + /// string is shown in the UI as is and can be translated. + //// + std::string name; + + /// A hint for how to present this scope in the UI. If this attribute is + /// missing, the scope is shown with a generic UI. + /// Values: + /// 'arguments': Scope contains method arguments. + /// 'locals': Scope contains local variables. + /// 'registers': Scope contains registers. Only a single `registers` scope + /// should be returned from a `scopes` request. + /// 'returnValue': Scope contains one or more return values. + /// etc. + std::optional presentationHint; + + /// The variables of this scope can be retrieved by passing the value of + /// `variablesReference` to the `variables` request as long as execution + /// remains suspended. See 'Lifetime of Object References' in the Overview + /// section for details. + //// + uint64_t variablesReference; + + /// The number of named variables in this scope. + /// The client can use this information to present the variables in a paged UI + /// and fetch them in chunks. + std::optional namedVariables; + + /// The number of indexed variables in this scope. + /// The client can use this information to present the variables in a paged UI + /// and fetch them in chunks. + std::optional indexedVariables; + + /// The source for this scope. + std::optional source; + + /// If true, the number of variables in this scope is large or expensive to + /// retrieve. + bool expensive; + + /// The start line of the range covered by this scope. + std::optional line; + + /// Start position of the range covered by the scope. It is measured in UTF-16 + /// code units and the client capability `columnsStartAt1` determines whether + /// it is 0- or 1-based. + std::optional column; + + /// The end line of the range covered by this scope. + std::optional endLine; + + /// End position of the range covered by the scope. It is measured in UTF-16 + /// code units and the client capability `columnsStartAt1` determines whether + /// it is 0- or 1-based. + std::optional endColumn; +}; +llvm::json::Value toJSON(const Scope &); + /// The granularity of one `step` in the stepping requests `next`, `stepIn`, /// `stepOut` and `stepBack`. enum SteppingGranularity : unsigned { >From 17828314bc80e4bf22db4d39f424eee45de6f0a2 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Mon, 12 May 2025 20:33:33 +0100 Subject: [PATCH 2/3] [lldb][lldb-dap] review changes --- lldb/tools/lldb-dap/Protocol/ProtocolRequests.h | 2 +- lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index 79739d8fc4309..f8d6b6a8581ea 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -443,7 +443,7 @@ struct ScopesArguments { /// Retrieve the scopes for the stack frame identified by `frameId`. The /// `frameId` must have been obtained in the current suspended state. See /// 'Lifetime of Object References' in the Overview section for details. - uint64_t frameId; + uint64_t frameId = LLDB_INVALID_FRAME_ID; }; bool fromJSON(const llvm::json::Value &, ScopesArguments &, llvm::json::Path); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index 0fcde4c52ad19..e60e092676a69 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -27,6 +27,8 @@ #include #include +#define LLDB_DAP_INVALID_VARRERF UINT64_MAX + namespace lldb_dap::protocol { /// An `ExceptionBreakpointsFilter` is shown in the UI as an filter option for @@ -336,7 +338,7 @@ struct Scope { /// remains suspended. See 'Lifetime of Object References' in the Overview /// section for details. //// - uint64_t variablesReference; + uint64_t variablesReference = LLDB_DAP_INVALID_VARRERF; /// The number of named variables in this scope. /// The client can use this information to present the variables in a paged UI @@ -353,7 +355,7 @@ struct Scope { /// If true, the number of variables in this scope is large or expensive to /// retrieve. - bool expensive; + bool expensive = false; /// The start line of the range covered by this scope. std::optional line; >From 8112ecd6a70b07507d49e48d0a509e3ae87a2909 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Mon, 12 May 2025 20:36:21 +0100 Subject: [PATCH 3/3] [lldb][lldb-dap] review changes --- lldb/tools/lldb-dap/DAP.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index f66cb40451484..9065995f5d722 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -283,6 +283,8 @@ struct DAP { lldb::SBThread GetLLDBThread(const llvm::json::Object &arguments); lldb::SBFrame GetLLDBFrame(uint64_t frame_id); + /// TODO: remove this function when we finish migrating to the + /// new protocol types. lldb::SBFrame GetLLDBFrame(const llvm::json::Object &arguments); void PopulateExceptionBreakpoints(); From lldb-commits at lists.llvm.org Mon May 12 12:40:22 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Mon, 12 May 2025 12:40:22 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Migrate ScopesRequest to structured types (PR #138116) In-Reply-To: Message-ID: <68224ea6.170a0220.274bf7.dcdf@mx.google.com> ================ @@ -98,9 +83,15 @@ void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { /*statics=*/true, /*in_scope_only=*/true); dap.variables.registers = frame.GetRegisters(); - body.try_emplace("scopes", dap.CreateTopLevelScopes()); - response.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(response))); + + std::vector scopes = {CreateScope("Locals", VARREF_LOCALS, + dap.variables.locals.GetSize(), false), + CreateScope("Globals", VARREF_GLOBALS, + dap.variables.globals.GetSize(), false), + CreateScope("Registers", VARREF_REGS, + dap.variables.registers.GetSize(), false)}; + + return ScopesResponseBody{std::move(scopes)}; ---------------- da-viper wrote: I think it should be only in the scoped request since nothing outside is using the functionality. would be worth it to move it to the variables if there was another request that depends on getting all the scopes. https://github.com/llvm/llvm-project/pull/138116 From lldb-commits at lists.llvm.org Mon May 12 12:56:17 2025 From: lldb-commits at lists.llvm.org (David Peixotto via lldb-commits) Date: Mon, 12 May 2025 12:56:17 -0700 (PDT) Subject: [Lldb-commits] [lldb] Add commands to list/enable/disable plugins (PR #134418) In-Reply-To: Message-ID: <68225261.050a0220.1ed5ad.ed89@mx.google.com> dmpots wrote: ping @clayborg @JDevlieghere @jimingham. Please take a look when you get a chance. Thanks! https://github.com/llvm/llvm-project/pull/134418 From lldb-commits at lists.llvm.org Mon May 12 13:00:24 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Mon, 12 May 2025 13:00:24 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit tests for protocol types (PR #139502) In-Reply-To: Message-ID: <68225358.170a0220.247a23.012e@mx.google.com> ================ @@ -0,0 +1,62 @@ +//===-- ProtocolTypesTest.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 "Protocol/ProtocolTypes.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" + +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap::protocol; + +template static llvm::Expected roundtrip(const T &input) { + llvm::json::Value value = toJSON(input); + llvm::json::Path::Root root; + T output; + if (!fromJSON(value, output, root)) + return root.getError(); + return output; +} + +TEST(ProtocolTypesTest, ExceptionBreakpointsFilter) { + ExceptionBreakpointsFilter filter; + filter.filter = "testFilter"; + filter.label = "Test Filter"; + filter.description = "This is a test filter"; + filter.defaultState = true; + filter.supportsCondition = true; + filter.conditionDescription = "Condition for test filter"; + + llvm::Expected deserialized_filter = + roundtrip(filter); + ASSERT_THAT_EXPECTED(deserialized_filter, llvm::Succeeded()); + + EXPECT_EQ(filter.filter, deserialized_filter->filter); + EXPECT_EQ(filter.label, deserialized_filter->label); + EXPECT_EQ(filter.description, deserialized_filter->description); + EXPECT_EQ(filter.defaultState, deserialized_filter->defaultState); + EXPECT_EQ(filter.supportsCondition, deserialized_filter->supportsCondition); + EXPECT_EQ(filter.conditionDescription, + deserialized_filter->conditionDescription); ---------------- JDevlieghere wrote: That sounds appealing, but how would you get the second `json::Value`? If you write it by hand you're back to the original state of this PR, and if you serialize the deserialized object again, and you have a bug in your serializer, it wouldn't be caught, right? https://github.com/llvm/llvm-project/pull/139502 From lldb-commits at lists.llvm.org Mon May 12 13:10:26 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Mon, 12 May 2025 13:10:26 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Migrate ScopesRequest to structured types (PR #138116) In-Reply-To: Message-ID: <682255b2.170a0220.8f373.c4fa@mx.google.com> https://github.com/ashgti edited https://github.com/llvm/llvm-project/pull/138116 From lldb-commits at lists.llvm.org Mon May 12 13:10:27 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Mon, 12 May 2025 13:10:27 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Migrate ScopesRequest to structured types (PR #138116) In-Reply-To: Message-ID: <682255b3.170a0220.5b497.9bd0@mx.google.com> https://github.com/ashgti approved this pull request. One style nit question but otherwise LGTM https://github.com/llvm/llvm-project/pull/138116 From lldb-commits at lists.llvm.org Mon May 12 13:10:27 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Mon, 12 May 2025 13:10:27 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Migrate ScopesRequest to structured types (PR #138116) In-Reply-To: Message-ID: <682255b3.170a0220.2b6b2.856f@mx.google.com> ================ @@ -269,17 +271,16 @@ struct Capabilities { }; llvm::json::Value toJSON(const Capabilities &); -enum PresentationHint : unsigned { - ePresentationHintNormal, - ePresentationHintEmphasize, - ePresentationHintDeemphasize, -}; -llvm::json::Value toJSON(PresentationHint hint); - /// A `Source` is a descriptor for source code. It is returned from the debug /// adapter as part of a `StackFrame` and it is used by clients when specifying /// breakpoints. struct Source { + enum PresentationHint : unsigned { + ePresentationHintNormal, + ePresentationHintEmphasize, + ePresentationHintDeemphasize, + }; ---------------- ashgti wrote: style nit: I think in lldb enums are usually kept in the same namespace and we should make the type more specific like `ScopePresentationHint` and `eScopePresentationHintNormal`, but I'll defer @JDevlieghere this. https://github.com/llvm/llvm-project/pull/138116 From lldb-commits at lists.llvm.org Mon May 12 13:16:44 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Mon, 12 May 2025 13:16:44 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit tests for protocol types (PR #139502) In-Reply-To: Message-ID: <6822572c.630a0220.d3eed.3e41@mx.google.com> ================ @@ -0,0 +1,62 @@ +//===-- ProtocolTypesTest.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 "Protocol/ProtocolTypes.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" + +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap::protocol; + +template static llvm::Expected roundtrip(const T &input) { + llvm::json::Value value = toJSON(input); + llvm::json::Path::Root root; + T output; + if (!fromJSON(value, output, root)) + return root.getError(); + return output; +} + +TEST(ProtocolTypesTest, ExceptionBreakpointsFilter) { + ExceptionBreakpointsFilter filter; + filter.filter = "testFilter"; + filter.label = "Test Filter"; + filter.description = "This is a test filter"; + filter.defaultState = true; + filter.supportsCondition = true; + filter.conditionDescription = "Condition for test filter"; + + llvm::Expected deserialized_filter = + roundtrip(filter); + ASSERT_THAT_EXPECTED(deserialized_filter, llvm::Succeeded()); + + EXPECT_EQ(filter.filter, deserialized_filter->filter); + EXPECT_EQ(filter.label, deserialized_filter->label); + EXPECT_EQ(filter.description, deserialized_filter->description); + EXPECT_EQ(filter.defaultState, deserialized_filter->defaultState); + EXPECT_EQ(filter.supportsCondition, deserialized_filter->supportsCondition); + EXPECT_EQ(filter.conditionDescription, + deserialized_filter->conditionDescription); ---------------- ashgti wrote: Yea, your right https://github.com/llvm/llvm-project/pull/139502 From lldb-commits at lists.llvm.org Mon May 12 13:23:53 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 13:23:53 -0700 (PDT) Subject: [Lldb-commits] [lldb] 8bec5e5 - [lldb-dap] Add unit tests for protocol types (#139502) Message-ID: <682258d9.170a0220.b6a2b.a8c1@mx.google.com> Author: Jonas Devlieghere Date: 2025-05-12T13:23:50-07:00 New Revision: 8bec5e5b88de6cfa7cd979b73eafdc2ba69ee053 URL: https://github.com/llvm/llvm-project/commit/8bec5e5b88de6cfa7cd979b73eafdc2ba69ee053 DIFF: https://github.com/llvm/llvm-project/commit/8bec5e5b88de6cfa7cd979b73eafdc2ba69ee053.diff LOG: [lldb-dap] Add unit tests for protocol types (#139502) Add unit tests for serializing and deserializing protocol types. Added: lldb/unittests/DAP/ProtocolTypesTest.cpp Modified: lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp lldb/tools/lldb-dap/Protocol/ProtocolTypes.h lldb/unittests/DAP/CMakeLists.txt Removed: ################################################################################ diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index 2b7419916268b..c9cab350f9f12 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -69,6 +69,16 @@ llvm::json::Value toJSON(const Source &S) { return result; } +bool fromJSON(const llvm::json::Value &Params, ExceptionBreakpointsFilter &EBF, + llvm::json::Path P) { + json::ObjectMapper O(Params, P); + return O && O.map("filter", EBF.filter) && O.map("label", EBF.label) && + O.mapOptional("description", EBF.description) && + O.mapOptional("default", EBF.defaultState) && + O.mapOptional("supportsCondition", EBF.supportsCondition) && + O.mapOptional("conditionDescription", EBF.conditionDescription); +} + json::Value toJSON(const ExceptionBreakpointsFilter &EBF) { json::Object result{{"filter", EBF.filter}, {"label", EBF.label}}; diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index 1f0cb1e0b2d41..d1e86b0897675 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -55,6 +55,8 @@ struct ExceptionBreakpointsFilter { /// shown as the placeholder text for a text box and can be translated. std::optional conditionDescription; }; +bool fromJSON(const llvm::json::Value &, ExceptionBreakpointsFilter &, + llvm::json::Path); llvm::json::Value toJSON(const ExceptionBreakpointsFilter &); enum ColumnType : unsigned { diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index 4bbb552be9f34..8b240654046e2 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -1,9 +1,11 @@ add_lldb_unittest(DAPTests JSONUtilsTest.cpp LLDBUtilsTest.cpp + ProtocolTypesTest.cpp LINK_LIBS lldbDAP + LLVMTestingSupport LINK_COMPONENTS Support ) diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp new file mode 100644 index 0000000000000..fa46816ca4a10 --- /dev/null +++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp @@ -0,0 +1,62 @@ +//===-- ProtocolTypesTest.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 "Protocol/ProtocolTypes.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" + +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap::protocol; + +template static llvm::Expected roundtrip(const T &input) { + llvm::json::Value value = toJSON(input); + llvm::json::Path::Root root; + T output; + if (!fromJSON(value, output, root)) + return root.getError(); + return output; +} + +TEST(ProtocolTypesTest, ExceptionBreakpointsFilter) { + ExceptionBreakpointsFilter filter; + filter.filter = "testFilter"; + filter.label = "Test Filter"; + filter.description = "This is a test filter"; + filter.defaultState = true; + filter.supportsCondition = true; + filter.conditionDescription = "Condition for test filter"; + + llvm::Expected deserialized_filter = + roundtrip(filter); + ASSERT_THAT_EXPECTED(deserialized_filter, llvm::Succeeded()); + + EXPECT_EQ(filter.filter, deserialized_filter->filter); + EXPECT_EQ(filter.label, deserialized_filter->label); + EXPECT_EQ(filter.description, deserialized_filter->description); + EXPECT_EQ(filter.defaultState, deserialized_filter->defaultState); + EXPECT_EQ(filter.supportsCondition, deserialized_filter->supportsCondition); + EXPECT_EQ(filter.conditionDescription, + deserialized_filter->conditionDescription); +} + +TEST(ProtocolTypesTest, Source) { + Source source; + source.name = "testName"; + source.path = "/path/to/source"; + source.sourceReference = 12345; + source.presentationHint = ePresentationHintEmphasize; + + llvm::Expected deserialized_source = roundtrip(source); + ASSERT_THAT_EXPECTED(deserialized_source, llvm::Succeeded()); + + EXPECT_EQ(source.name, deserialized_source->name); + EXPECT_EQ(source.path, deserialized_source->path); + EXPECT_EQ(source.sourceReference, deserialized_source->sourceReference); + EXPECT_EQ(source.presentationHint, deserialized_source->presentationHint); +} From lldb-commits at lists.llvm.org Mon May 12 13:23:56 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Mon, 12 May 2025 13:23:56 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit tests for protocol types (PR #139502) In-Reply-To: Message-ID: <682258dc.170a0220.e44e5.a3eb@mx.google.com> https://github.com/JDevlieghere closed https://github.com/llvm/llvm-project/pull/139502 From lldb-commits at lists.llvm.org Mon May 12 13:36:20 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Mon, 12 May 2025 13:36:20 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Don't create instance of `SymbolFileDWARFDebugMap` for non-Mach-O files (PR #139170) In-Reply-To: Message-ID: <68225bc4.050a0220.1417f5.cc03@mx.google.com> JDevlieghere wrote: > FWIW, I completely agree @royitaqi. I'm not saying inter-plugin dependencies should be a free-for-all (*), but I think that some kinds of dependencies make sense and I definitely think this is one of them. The debug map format is intimately tied to the MachO and darwin ecosystems and I think there's approximately zero chance that it will be implemented elsewhere. Using the debug map requires MachO files, so why not just admit that? To answer your last question: because the plugins (which is really a misnomer), as I understand it, are there to provide abstraction: the caller shouldn't have to know what concrete instance an `ObjectFile` is. The no-plugins-dependency enforces that at compile/link time. I'll be the first to admit that the current approach has shortcomings (like it does here, I totally agree with that). However we should also remember that it exists for a reason and that a lot of time and effort has been spent on detangling the plugins to fix layering issues and reduce binary sizes. The current rule is easy to understand and easy to enforce which makes it appealing and ensures we don't make things worse as we're still working on this. IMHO, the downsides being listed here don't outweigh the benefits, especially since we have a bunch of examples of those "moral dependencies". That said, if there's a way to enforce the DAG described in the asterisk, I'm totally fine with changing the rule to allow inter-plugin dependencies "where it makes sense" (which is still subjective). I made a similar argument in another PR a while ago, but I don't think we can expect reviewers to mentally verify this DAG every time someone tries to introduce a new inter-plugin dependencies. TL;DR: My stance is that if there's a way to enforce the DAG, I'm totally fine with allowing inter-plugin dependencies where they make sense. Barring that I think the current rule, albeit overly strict, is the easiest way to enforce we don't regress inter-plugin dependencies in general. PS: I'm actually glad we're having this discussion. Whatever the outcome, I'd like to [document it on the website](https://lldb.llvm.org/resources/contributing.html) so contributors can know what to expect going forward. This comes up periodically and there's no reason this should be a surprise for existing or new contributors. https://github.com/llvm/llvm-project/pull/139170 From lldb-commits at lists.llvm.org Mon May 12 13:41:59 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Mon, 12 May 2025 13:41:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Remove the lldb-vscode symlink (NFC) (PR #139621) Message-ID: https://github.com/JDevlieghere created https://github.com/llvm/llvm-project/pull/139621 Remove the `lldb-vscode` -> `lldb-dap` symlink in the `tools` directory. I initially created the symlink when we renamed the tool to make migration easier. I think enough time has passed that we don't need it anymore. My personal motivation is that the symlink causes every file in the `lldb-dap` directory to show up twice (once under `lldb-dap` and once under `lldb-vscode`) in Quick Open in VS Code. >From de8cfd54b4d3c177872e8c9fbfbf5f3e779167ac Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Mon, 12 May 2025 13:37:53 -0700 Subject: [PATCH] [lldb-dap] Remove the lldb-vscode symlink (NFC) Remove the lldb-vscode -> lldb-dap symlink in the tools directory. I initially created the symlink when we renamed the tool to make migration easier. I think enough time has passed that we don't need it anymore. My personal motivation is that the symlink causes every file in the lldb-dap directory to show up twice (once under lldb-dap and once under lldb-vscode) in Quick Open in VS Code. --- lldb/tools/lldb-vscode | 1 - 1 file changed, 1 deletion(-) delete mode 120000 lldb/tools/lldb-vscode diff --git a/lldb/tools/lldb-vscode b/lldb/tools/lldb-vscode deleted file mode 120000 index 46b40044086c9..0000000000000 --- a/lldb/tools/lldb-vscode +++ /dev/null @@ -1 +0,0 @@ -lldb-dap \ No newline at end of file From lldb-commits at lists.llvm.org Mon May 12 13:42:28 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 13:42:28 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Remove the lldb-vscode symlink (NFC) (PR #139621) In-Reply-To: Message-ID: <68225d34.170a0220.bf47b.b25d@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Jonas Devlieghere (JDevlieghere)
Changes Remove the `lldb-vscode` -> `lldb-dap` symlink in the `tools` directory. I initially created the symlink when we renamed the tool to make migration easier. I think enough time has passed that we don't need it anymore. My personal motivation is that the symlink causes every file in the `lldb-dap` directory to show up twice (once under `lldb-dap` and once under `lldb-vscode`) in Quick Open in VS Code. --- Full diff: https://github.com/llvm/llvm-project/pull/139621.diff 1 Files Affected: - (removed) lldb/tools/lldb-vscode (-1) ``````````diff diff --git a/lldb/tools/lldb-vscode b/lldb/tools/lldb-vscode deleted file mode 120000 index 46b40044086c9..0000000000000 --- a/lldb/tools/lldb-vscode +++ /dev/null @@ -1 +0,0 @@ -lldb-dap \ No newline at end of file ``````````
https://github.com/llvm/llvm-project/pull/139621 From lldb-commits at lists.llvm.org Mon May 12 13:43:58 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Mon, 12 May 2025 13:43:58 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Remove the lldb-vscode symlink (NFC) (PR #139621) In-Reply-To: Message-ID: <68225d8e.170a0220.1761f3.b08a@mx.google.com> https://github.com/ashgti approved this pull request. https://github.com/llvm/llvm-project/pull/139621 From lldb-commits at lists.llvm.org Mon May 12 13:57:50 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Mon, 12 May 2025 13:57:50 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Migrate ScopesRequest to structured types (PR #138116) In-Reply-To: Message-ID: <682260ce.050a0220.2b6a53.07d5@mx.google.com> ================ @@ -269,17 +271,16 @@ struct Capabilities { }; llvm::json::Value toJSON(const Capabilities &); -enum PresentationHint : unsigned { - ePresentationHintNormal, - ePresentationHintEmphasize, - ePresentationHintDeemphasize, -}; -llvm::json::Value toJSON(PresentationHint hint); - /// A `Source` is a descriptor for source code. It is returned from the debug /// adapter as part of a `StackFrame` and it is used by clients when specifying /// breakpoints. struct Source { + enum PresentationHint : unsigned { + ePresentationHintNormal, + ePresentationHintEmphasize, + ePresentationHintDeemphasize, + }; ---------------- JDevlieghere wrote: I'm slightly leaning towards that too, because that would be most consistent with the other enums which are potentially shared across types. https://github.com/llvm/llvm-project/pull/138116 From lldb-commits at lists.llvm.org Mon May 12 14:58:10 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Mon, 12 May 2025 14:58:10 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Migrate ScopesRequest to structured types (PR #138116) In-Reply-To: Message-ID: <68226ef2.170a0220.3d8973.adba@mx.google.com> https://github.com/JDevlieghere approved this pull request. LGTM modulo the enum nit. Please add a unit test for `Scope` now that that's possible :-) https://github.com/llvm/llvm-project/pull/138116 From lldb-commits at lists.llvm.org Mon May 12 15:52:21 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 15:52:21 -0700 (PDT) Subject: [Lldb-commits] [lldb] Support stepping through Darwin "branch islands" (PR #139301) In-Reply-To: Message-ID: <68227ba5.a70a0220.2c83dd.f0d3@mx.google.com> https://github.com/jimingham updated https://github.com/llvm/llvm-project/pull/139301 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Mon May 12 16:56:58 2025 From: lldb-commits at lists.llvm.org (Chelsea Cassanova via lldb-commits) Date: Mon, 12 May 2025 16:56:58 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream lldb-rpc-gen tool (PR #138031) In-Reply-To: Message-ID: <68228aca.170a0220.d71f2.c15e@mx.google.com> ================ @@ -0,0 +1,546 @@ +//===-- RPCCommon.cpp -----------------------------------------------------===// +// +// 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 "RPCCommon.h" + +#include "clang/AST/AST.h" +#include "clang/AST/Attr.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/Mangle.h" +#include "clang/Lex/Lexer.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +// We intentionally do not generate some classes because they are currently +// inconvenient, they aren't really used by most consumers, or we're not sure +// why they exist. +static constexpr llvm::StringRef DisallowedClasses[] = { + "SBCommunication", // What is this used for? + "SBInputReader", // What is this used for? ---------------- chelcassanova wrote: @DavidSpickett On the original and larger patch that I had up for this, you asked if we could answer what these files are used for. I think Greg Clayton might know? But otherwise, these comments should be changed to better clarify that we just don't need these classes in RPC for now. https://github.com/llvm/llvm-project/pull/138031 From lldb-commits at lists.llvm.org Mon May 12 20:01:51 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 20:01:51 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add field member operators to DIL (PR #138093) In-Reply-To: Message-ID: <6822b61f.170a0220.10d9a1.bd90@mx.google.com> ================ @@ -272,4 +272,66 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const MemberOfNode *node) { + Status error; + auto base_or_err = Evaluate(node->GetBase()); + if (!base_or_err) { + return base_or_err; + } + lldb::ValueObjectSP base = *base_or_err; + + // Perform basic type checking. + CompilerType base_type = base->GetCompilerType(); + // When using an arrow, make sure the base is a pointer or array type. + // When using a period, make sure the base type is NOT a pointer type. + if (node->GetIsArrow() && !base_type.IsPointerType() && + !base_type.IsArrayType()) { ---------------- cmtice wrote: Why? The current "frame var" implementation does perform these checks and return these errors... https://github.com/llvm/llvm-project/pull/138093 From lldb-commits at lists.llvm.org Mon May 12 20:02:15 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 20:02:15 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add field member operators to DIL (PR #138093) In-Reply-To: Message-ID: <6822b637.170a0220.272ffa.d836@mx.google.com> ================ @@ -272,4 +272,66 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const MemberOfNode *node) { + Status error; + auto base_or_err = Evaluate(node->GetBase()); + if (!base_or_err) { + return base_or_err; + } + lldb::ValueObjectSP base = *base_or_err; + + // Perform basic type checking. + CompilerType base_type = base->GetCompilerType(); + // When using an arrow, make sure the base is a pointer or array type. + // When using a period, make sure the base type is NOT a pointer type. + if (node->GetIsArrow() && !base_type.IsPointerType() && + !base_type.IsArrayType()) { + lldb::ValueObjectSP deref_sp = base->Dereference(error); + if (error.Success()) { + base = deref_sp; + base_type = deref_sp->GetCompilerType().GetPointerType(); + } else { + std::string errMsg = + llvm::formatv("member reference type {0} is not a pointer; " + "did you mean to use '.'?", + base_type.TypeDescription()); + return llvm::make_error( + m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); + } + } else if (!node->GetIsArrow() && base_type.IsPointerType()) { ---------------- cmtice wrote: Same question/response as before. https://github.com/llvm/llvm-project/pull/138093 From lldb-commits at lists.llvm.org Mon May 12 20:46:17 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 20:46:17 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add field member operators to DIL (PR #138093) In-Reply-To: Message-ID: <6822c089.170a0220.1d5bdb.b768@mx.google.com> ================ @@ -272,4 +272,66 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const MemberOfNode *node) { + Status error; + auto base_or_err = Evaluate(node->GetBase()); + if (!base_or_err) { + return base_or_err; + } + lldb::ValueObjectSP base = *base_or_err; + + // Perform basic type checking. + CompilerType base_type = base->GetCompilerType(); + // When using an arrow, make sure the base is a pointer or array type. + // When using a period, make sure the base type is NOT a pointer type. + if (node->GetIsArrow() && !base_type.IsPointerType() && + !base_type.IsArrayType()) { + lldb::ValueObjectSP deref_sp = base->Dereference(error); + if (error.Success()) { + base = deref_sp; + base_type = deref_sp->GetCompilerType().GetPointerType(); + } else { + std::string errMsg = + llvm::formatv("member reference type {0} is not a pointer; " + "did you mean to use '.'?", + base_type.TypeDescription()); + return llvm::make_error( + m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); + } + } else if (!node->GetIsArrow() && base_type.IsPointerType()) { + std::string errMsg = + llvm::formatv("member reference type {0} is a pointer; " + "did you mean to use '->'?", + base_type.TypeDescription()); + return llvm::make_error( + m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); + } + + // User specified array->elem; need to get to element[0] to look for fields. + if (node->GetIsArrow() && base_type.IsArrayType()) + base = base->GetChildAtIndex(0); + + // Now look for the member with the specified name. + lldb::ValueObjectSP field_obj = + base->GetChildMemberWithName(llvm::StringRef(node->GetFieldName())); + if (field_obj && field_obj->GetName().GetString() == node->GetFieldName()) { + if (field_obj->GetCompilerType().IsReferenceType()) { + lldb::ValueObjectSP tmp_obj = field_obj->Dereference(error); + if (error.Fail()) + return error.ToError(); + return tmp_obj; + } + return field_obj; + } + + if (node->GetIsArrow() && base_type.IsPointerType()) + base_type = base_type.GetPointeeType(); + std::string errMsg = + llvm::formatv("no member named '{0}' in {1}", node->GetFieldName(), ---------------- cmtice wrote: We don't get an error from GetChildMemberWithName. Either it returns a ValueObjectSP, or it returns a nullptr. https://github.com/llvm/llvm-project/pull/138093 From lldb-commits at lists.llvm.org Mon May 12 20:55:26 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 20:55:26 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add field member operators to DIL (PR #138093) In-Reply-To: Message-ID: <6822c2ae.170a0220.326dc.bd9d@mx.google.com> https://github.com/cmtice updated https://github.com/llvm/llvm-project/pull/138093 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Mon May 12 22:49:03 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Mon, 12 May 2025 22:49:03 -0700 (PDT) Subject: [Lldb-commits] [lldb] Extending LLDB to work on AIX (PR #102601) In-Reply-To: Message-ID: <6822dd4f.170a0220.2069a8.e170@mx.google.com> https://github.com/ravindra-shinde2 updated https://github.com/llvm/llvm-project/pull/102601 >From 39d395f75c306a0d932a783eef039fd93d66e246 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 7 Aug 2024 12:10:43 -0500 Subject: [PATCH 01/47] LLDB Support for AIX --- clang/lib/CodeGen/CGObjCMac.cpp | 6 +- lldb/CMakeLists.txt | 4 + lldb/cmake/modules/LLDBConfig.cmake | 2 +- lldb/include/lldb/Core/Module.h | 3 + lldb/include/lldb/Core/ModuleSpec.h | 23 +- lldb/include/lldb/Host/HostGetOpt.h | 2 +- lldb/include/lldb/Host/HostInfo.h | 3 + lldb/include/lldb/Host/HostInfoBase.h | 2 +- lldb/include/lldb/Host/XML.h | 5 + lldb/include/lldb/Host/aix/AbstractSocket.h | 25 + lldb/include/lldb/Host/aix/Host.h | 22 + lldb/include/lldb/Host/aix/HostInfoAIX.h | 42 + lldb/include/lldb/Host/aix/Ptrace.h | 62 + lldb/include/lldb/Host/aix/Support.h | 29 + lldb/include/lldb/Host/aix/Uio.h | 23 + lldb/include/lldb/Host/common/GetOptInc.h | 6 +- lldb/include/lldb/Symbol/ObjectFile.h | 5 + lldb/include/lldb/Target/ABI.h | 6 + lldb/include/lldb/Target/DynamicLoader.h | 6 + lldb/include/lldb/Target/Process.h | 14 + .../lldb/Target/RegisterContextUnwind.h | 4 + .../lldb/Target/ThreadPlanCallFunction.h | 6 + .../lldb/Utility/StringExtractorGDBRemote.h | 1 + lldb/include/lldb/lldb-private-enumerations.h | 1 + lldb/source/API/CMakeLists.txt | 108 + lldb/source/API/SBBreakpoint.cpp | 6 +- lldb/source/API/SBBreakpointLocation.cpp | 6 +- lldb/source/API/SBBreakpointName.cpp | 4 +- lldb/source/Core/DynamicLoader.cpp | 10 + lldb/source/Core/Mangled.cpp | 2 + lldb/source/Core/Module.cpp | 12 + lldb/source/Core/Section.cpp | 4 + lldb/source/Expression/DWARFExpression.cpp | 10 +- lldb/source/Host/CMakeLists.txt | 13 + lldb/source/Host/aix/AbstractSocket.cpp | 21 + lldb/source/Host/aix/Host.cpp | 304 +++ lldb/source/Host/aix/HostInfoAIX.cpp | 215 ++ lldb/source/Host/aix/Support.cpp | 44 + lldb/source/Host/common/GetOptInc.cpp | 2 +- lldb/source/Host/common/Host.cpp | 180 +- .../source/Host/common/LICENSE.aix-netbsd.txt | 125 + lldb/source/Host/common/XML.cpp | 3 + .../posix/ConnectionFileDescriptorPosix.cpp | 2 + lldb/source/Host/posix/FileSystemPosix.cpp | 2 + lldb/source/Host/posix/MainLoopPosix.cpp | 17 + .../Host/posix/ProcessLauncherPosixFork.cpp | 5 + lldb/source/Initialization/CMakeLists.txt | 2 +- .../SystemInitializerCommon.cpp | 4 +- .../Plugins/ABI/PowerPC/ABISysV_ppc64.cpp | 131 +- .../Plugins/ABI/PowerPC/ABISysV_ppc64.h | 6 + .../DynamicLoader/AIX-DYLD/CMakeLists.txt | 11 + .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 272 +++ .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 55 + .../Plugins/DynamicLoader/CMakeLists.txt | 1 + .../DynamicLoaderDarwinKernel.cpp | 4 +- .../MacOSX-DYLD/DynamicLoaderDarwin.cpp | 2 +- .../PPC64/EmulateInstructionPPC64.cpp | 196 +- .../PPC64/EmulateInstructionPPC64.h | 14 + ...nstrumentationRuntimeMainThreadChecker.cpp | 2 +- .../TSan/InstrumentationRuntimeTSan.cpp | 14 +- .../UBSan/InstrumentationRuntimeUBSan.cpp | 2 +- .../Plugins/JITLoader/GDB/JITLoaderGDB.cpp | 4 + lldb/source/Plugins/Language/ObjC/Cocoa.cpp | 2 + .../MemoryHistory/asan/MemoryHistoryASan.cpp | 2 +- .../BSD-Archive/ObjectContainerBSDArchive.cpp | 2 +- .../Big-Archive/CMakeLists.txt | 10 + .../Big-Archive/ObjectContainerBigArchive.cpp | 522 +++++ .../Big-Archive/ObjectContainerBigArchive.h | 177 ++ .../Plugins/ObjectContainer/CMakeLists.txt | 1 + lldb/source/Plugins/ObjectFile/CMakeLists.txt | 1 + .../ObjectFile/Mach-O/ObjectFileMachO.cpp | 6 +- .../Minidump/ObjectFileMinidump.cpp | 2 + .../Plugins/ObjectFile/PDB/ObjectFilePDB.cpp | 15 +- .../ObjectFile/PECOFF/ObjectFilePECOFF.cpp | 18 +- .../Plugins/ObjectFile/XCOFF/CMakeLists.txt | 13 + .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 780 +++++++ .../ObjectFile/XCOFF/ObjectFileXCOFF.h | 243 ++ .../Python/OperatingSystemPython.cpp | 2 +- .../Plugins/Platform/AIX/CMakeLists.txt | 13 + .../Plugins/Platform/AIX/PlatformAIX.cpp | 471 ++++ .../source/Plugins/Platform/AIX/PlatformAIX.h | 74 + lldb/source/Plugins/Platform/CMakeLists.txt | 1 + .../source/Plugins/Process/AIX/CMakeLists.txt | 19 + .../Plugins/Process/AIX/NativeProcessAIX.cpp | 2048 +++++++++++++++++ .../Plugins/Process/AIX/NativeProcessAIX.h | 283 +++ .../Process/AIX/NativeRegisterContextAIX.cpp | 157 ++ .../Process/AIX/NativeRegisterContextAIX.h | 133 ++ .../AIX/NativeRegisterContextAIX_ppc64.cpp | 744 ++++++ .../AIX/NativeRegisterContextAIX_ppc64.h | 138 ++ .../Plugins/Process/AIX/NativeThreadAIX.cpp | 526 +++++ .../Plugins/Process/AIX/NativeThreadAIX.h | 126 + lldb/source/Plugins/Process/CMakeLists.txt | 3 + .../Process/Utility/InferiorCallPOSIX.cpp | 33 + .../Utility/RegisterInfoPOSIX_ppc64le.cpp | 4 + .../Plugins/Process/Utility/ThreadMemory.cpp | 2 +- .../Plugins/Process/gdb-remote/CMakeLists.txt | 5 + .../GDBRemoteCommunicationClient.cpp | 30 + .../gdb-remote/GDBRemoteCommunicationClient.h | 7 + .../GDBRemoteCommunicationServerLLGS.cpp | 28 + .../GDBRemoteCommunicationServerLLGS.h | 2 + .../Process/gdb-remote/ProcessGDBRemote.cpp | 13 +- .../Process/gdb-remote/ProcessGDBRemote.h | 8 + .../Process/mach-core/ProcessMachCore.cpp | 8 +- .../ScriptInterpreter/Python/CMakeLists.txt | 5 + .../SymbolFile/DWARF/DWARFFormValue.cpp | 4 + .../Plugins/SymbolFile/DWARF/DWARFUnit.cpp | 12 +- .../MacOSX/AppleGetThreadItemInfoHandler.cpp | 2 +- lldb/source/Symbol/DWARFCallFrameInfo.cpp | 4 +- lldb/source/Target/ABI.cpp | 9 + lldb/source/Target/CMakeLists.txt | 5 + lldb/source/Target/Process.cpp | 10 + lldb/source/Target/RegisterContextUnwind.cpp | 46 + lldb/source/Target/ThreadPlanCallFunction.cpp | 34 + lldb/source/Target/UnwindLLDB.cpp | 15 + lldb/source/Utility/ArchSpec.cpp | 18 +- .../Utility/StringExtractorGDBRemote.cpp | 2 + lldb/test/CMakeLists.txt | 2 +- lldb/test/Shell/Expr/TestIRMemoryMap.test | 2 +- lldb/test/Shell/Process/TestEnvironment.test | 2 +- lldb/tools/driver/CMakeLists.txt | 5 + lldb/tools/driver/Driver.cpp | 5 +- lldb/tools/lldb-dap/CMakeLists.txt | 4 + lldb/tools/lldb-server/CMakeLists.txt | 7 + .../lldb-server/SystemInitializerLLGS.cpp | 15 + lldb/tools/lldb-server/lldb-gdbserver.cpp | 4 + lldb/unittests/Host/FileSystemTest.cpp | 2 +- lldb/unittests/Host/posix/TerminalTest.cpp | 4 + llvm/include/llvm/Object/XCOFFObjectFile.h | 4 +- llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 15 +- 129 files changed, 8950 insertions(+), 76 deletions(-) create mode 100644 lldb/include/lldb/Host/aix/AbstractSocket.h create mode 100644 lldb/include/lldb/Host/aix/Host.h create mode 100644 lldb/include/lldb/Host/aix/HostInfoAIX.h create mode 100644 lldb/include/lldb/Host/aix/Ptrace.h create mode 100644 lldb/include/lldb/Host/aix/Support.h create mode 100644 lldb/include/lldb/Host/aix/Uio.h create mode 100644 lldb/source/Host/aix/AbstractSocket.cpp create mode 100644 lldb/source/Host/aix/Host.cpp create mode 100644 lldb/source/Host/aix/HostInfoAIX.cpp create mode 100644 lldb/source/Host/aix/Support.cpp create mode 100644 lldb/source/Host/common/LICENSE.aix-netbsd.txt create mode 100644 lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt create mode 100644 lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp create mode 100644 lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h create mode 100644 lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt create mode 100644 lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp create mode 100644 lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h create mode 100644 lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt create mode 100644 lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp create mode 100644 lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h create mode 100644 lldb/source/Plugins/Platform/AIX/CMakeLists.txt create mode 100644 lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp create mode 100644 lldb/source/Plugins/Platform/AIX/PlatformAIX.h create mode 100644 lldb/source/Plugins/Process/AIX/CMakeLists.txt create mode 100644 lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeProcessAIX.h create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h create mode 100644 lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeThreadAIX.h diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index 30f3911a8b03c..fc91981db68c1 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -5052,10 +5052,14 @@ std::string CGObjCCommonMac::GetSectionName(StringRef Section, case llvm::Triple::COFF: assert(Section.starts_with("__") && "expected the name to begin with __"); return ("." + Section.substr(2) + "$B").str(); + case llvm::Triple::XCOFF: + // Hack to allow "p 10+1" on AIX for lldb + assert(Section.substr(0, 2) == "__" && + "expected the name to begin with __"); + return Section.substr(2).str(); case llvm::Triple::Wasm: case llvm::Triple::GOFF: case llvm::Triple::SPIRV: - case llvm::Triple::XCOFF: case llvm::Triple::DXContainer: llvm::report_fatal_error( "Objective-C support is unimplemented for object file format"); diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt index 59cdc4593463c..2e9ae0d0b3221 100644 --- a/lldb/CMakeLists.txt +++ b/lldb/CMakeLists.txt @@ -38,6 +38,10 @@ endif() include(LLDBConfig) include(AddLLDB) +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + add_definitions("-D__AIX__") +endif() + # Define the LLDB_CONFIGURATION_xxx matching the build type. if(uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" ) add_definitions(-DLLDB_CONFIGURATION_DEBUG) diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake index a60921990cf77..a0f118a11984c 100644 --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -299,7 +299,7 @@ endif() # Figure out if lldb could use lldb-server. If so, then we'll # ensure we build lldb-server when an lldb target is being built. -if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD|Windows") +if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD|Windows|AIX") set(LLDB_CAN_USE_LLDB_SERVER ON) else() set(LLDB_CAN_USE_LLDB_SERVER OFF) diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 5589c1c9a350d..3829386562795 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -196,6 +196,9 @@ class Module : public std::enable_shared_from_this, bool SetLoadAddress(Target &target, lldb::addr_t value, bool value_is_offset, bool &changed); + bool SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, bool &changed, int type_id); + /// \copydoc SymbolContextScope::CalculateSymbolContext(SymbolContext*) /// /// \see SymbolContextScope diff --git a/lldb/include/lldb/Core/ModuleSpec.h b/lldb/include/lldb/Core/ModuleSpec.h index 4cbbbfa8a26e1..4fe06412b6b0b 100644 --- a/lldb/include/lldb/Core/ModuleSpec.h +++ b/lldb/include/lldb/Core/ModuleSpec.h @@ -21,6 +21,7 @@ #include #include +#include namespace lldb_private { @@ -41,8 +42,26 @@ class ModuleSpec { } ModuleSpec(const FileSpec &file_spec, const ArchSpec &arch) - : m_file(file_spec), m_arch(arch), m_object_offset(0), - m_object_size(FileSystem::Instance().GetByteSize(file_spec)) {} + : m_arch(arch), m_object_offset(0) { + // parse object inside module format for example: /usr/ccs/lib/libc.a(shr_64.o) + llvm::SmallString<256> path_with_object; + file_spec.GetPath(path_with_object); + if (strstr(path_with_object.c_str(), "(") != nullptr) { + char *part; + char *str = (char *)path_with_object.c_str(); + part = strtok(str, "()"); + assert(part); + llvm::StringRef file_name(part); + part = strtok(nullptr, "()"); + assert(part); + m_object_name = ConstString(part); + m_file = FileSpec(file_name); + m_object_size = FileSystem::Instance().GetByteSize(m_file); + } else { + m_file = file_spec; + m_object_size = FileSystem::Instance().GetByteSize(file_spec); + } + } FileSpec *GetFileSpecPtr() { return (m_file ? &m_file : nullptr); } diff --git a/lldb/include/lldb/Host/HostGetOpt.h b/lldb/include/lldb/Host/HostGetOpt.h index 52cfdf4dbb89c..f450e561d6afb 100644 --- a/lldb/include/lldb/Host/HostGetOpt.h +++ b/lldb/include/lldb/Host/HostGetOpt.h @@ -9,7 +9,7 @@ #ifndef LLDB_HOST_HOSTGETOPT_H #define LLDB_HOST_HOSTGETOPT_H -#if !defined(_MSC_VER) && !defined(__NetBSD__) +#if !defined(_MSC_VER) && !defined(__NetBSD__) && !defined(__AIX__) #include #include diff --git a/lldb/include/lldb/Host/HostInfo.h b/lldb/include/lldb/Host/HostInfo.h index b7010d69d88e7..156df8cf6901d 100644 --- a/lldb/include/lldb/Host/HostInfo.h +++ b/lldb/include/lldb/Host/HostInfo.h @@ -55,6 +55,9 @@ #elif defined(__APPLE__) #include "lldb/Host/macosx/HostInfoMacOSX.h" #define HOST_INFO_TYPE HostInfoMacOSX +#elif defined(__AIX__) +#include "lldb/Host/aix/HostInfoAIX.h" +#define HOST_INFO_TYPE HostInfoAIX #else #include "lldb/Host/posix/HostInfoPosix.h" #define HOST_INFO_TYPE HostInfoPosix diff --git a/lldb/include/lldb/Host/HostInfoBase.h b/lldb/include/lldb/Host/HostInfoBase.h index 705aad559f3b7..29e6acf39bfb2 100644 --- a/lldb/include/lldb/Host/HostInfoBase.h +++ b/lldb/include/lldb/Host/HostInfoBase.h @@ -149,6 +149,7 @@ class HostInfoBase { return {}; } + static bool ComputeSharedLibraryDirectory(FileSpec &file_spec); /// Returns the distribution id of the host /// /// This will be something like "ubuntu", "fedora", etc. on Linux. @@ -158,7 +159,6 @@ class HostInfoBase { static llvm::StringRef GetDistributionId() { return llvm::StringRef(); } protected: - static bool ComputeSharedLibraryDirectory(FileSpec &file_spec); static bool ComputeSupportExeDirectory(FileSpec &file_spec); static bool ComputeProcessTempFileDirectory(FileSpec &file_spec); static bool ComputeGlobalTempFileDirectory(FileSpec &file_spec); diff --git a/lldb/include/lldb/Host/XML.h b/lldb/include/lldb/Host/XML.h index da0f9cd7aa8c0..cf359f7726d5d 100644 --- a/lldb/include/lldb/Host/XML.h +++ b/lldb/include/lldb/Host/XML.h @@ -11,6 +11,11 @@ #include "lldb/Host/Config.h" +#if defined(__AIX__) +//FIXME for AIX +#undef LLDB_ENABLE_LIBXML2 +#endif + #if LLDB_ENABLE_LIBXML2 #include #endif diff --git a/lldb/include/lldb/Host/aix/AbstractSocket.h b/lldb/include/lldb/Host/aix/AbstractSocket.h new file mode 100644 index 0000000000000..78a567a6b9095 --- /dev/null +++ b/lldb/include/lldb/Host/aix/AbstractSocket.h @@ -0,0 +1,25 @@ +//===-- AbstractSocket.h ----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_AbstractSocket_h_ +#define liblldb_AbstractSocket_h_ + +#include "lldb/Host/posix/DomainSocket.h" + +namespace lldb_private { +class AbstractSocket : public DomainSocket { +public: + AbstractSocket(bool child_processes_inherit); + +protected: + size_t GetNameOffset() const override; + void DeleteSocketFile(llvm::StringRef name) override; +}; +} + +#endif // ifndef liblldb_AbstractSocket_h_ diff --git a/lldb/include/lldb/Host/aix/Host.h b/lldb/include/lldb/Host/aix/Host.h new file mode 100644 index 0000000000000..1e3487752995f --- /dev/null +++ b/lldb/include/lldb/Host/aix/Host.h @@ -0,0 +1,22 @@ +//===-- Host.h --------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_HOST_AIX_HOST_H +#define LLDB_HOST_AIX_HOST_H + +#include "lldb/lldb-types.h" +#include + +namespace lldb_private { + +// Get PID (i.e. the primary thread ID) corresponding to the specified TID. +std::optional getPIDForTID(lldb::pid_t tid); + +} // namespace lldb_private + +#endif // #ifndef LLDB_HOST_AIX_HOST_H diff --git a/lldb/include/lldb/Host/aix/HostInfoAIX.h b/lldb/include/lldb/Host/aix/HostInfoAIX.h new file mode 100644 index 0000000000000..ced4cf34d38a8 --- /dev/null +++ b/lldb/include/lldb/Host/aix/HostInfoAIX.h @@ -0,0 +1,42 @@ +//===-- HostInfoAIX.h -----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_Host_aix_HostInfoAIX_h_ +#define lldb_Host_aix_HostInfoAIX_h_ + +#include "lldb/Host/posix/HostInfoPosix.h" +#include "lldb/Utility/FileSpec.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VersionTuple.h" + +#include + +namespace lldb_private { + +class HostInfoAIX : public HostInfoPosix { + friend class HostInfoBase; + +public: + static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr); + static void Terminate(); + + static llvm::VersionTuple GetOSVersion(); + static std::optional GetOSBuildString(); + static llvm::StringRef GetDistributionId(); + static FileSpec GetProgramFileSpec(); + +protected: + static bool ComputeSupportExeDirectory(FileSpec &file_spec); + static bool ComputeSystemPluginsDirectory(FileSpec &file_spec); + static bool ComputeUserPluginsDirectory(FileSpec &file_spec); + static void ComputeHostArchitectureSupport(ArchSpec &arch_32, + ArchSpec &arch_64); +}; +} + +#endif diff --git a/lldb/include/lldb/Host/aix/Ptrace.h b/lldb/include/lldb/Host/aix/Ptrace.h new file mode 100644 index 0000000000000..88928f18102d7 --- /dev/null +++ b/lldb/include/lldb/Host/aix/Ptrace.h @@ -0,0 +1,62 @@ +//===-- Ptrace.h ------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +// This file defines ptrace functions & structures + +#ifndef liblldb_Host_aix_Ptrace_h_ +#define liblldb_Host_aix_Ptrace_h_ + +#include + +#define DEBUG_PTRACE_MAXBYTES 20 + +// Support ptrace extensions even when compiled without required kernel support +#ifndef PTRACE_GETREGS +#define PTRACE_GETREGS (PT_COMMAND_MAX+1) +#endif +#ifndef PTRACE_SETREGS +#define PTRACE_SETREGS (PT_COMMAND_MAX+2) +#endif +#ifndef PTRACE_GETFPREGS +#define PTRACE_GETFPREGS (PT_COMMAND_MAX+3) +#endif +#ifndef PTRACE_SETFPREGS +#define PTRACE_SETFPREGS (PT_COMMAND_MAX+4) +#endif +#ifndef PTRACE_GETREGSET +#define PTRACE_GETREGSET 0x4204 +#endif +#ifndef PTRACE_SETREGSET +#define PTRACE_SETREGSET 0x4205 +#endif +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA (PT_COMMAND_MAX+5) +#endif +#ifndef PTRACE_ARCH_PRCTL +#define PTRACE_ARCH_PRCTL (PT_COMMAND_MAX+6) +#endif +#ifndef ARCH_GET_FS +#define ARCH_SET_GS 0x1001 +#define ARCH_SET_FS 0x1002 +#define ARCH_GET_FS 0x1003 +#define ARCH_GET_GS 0x1004 +#endif +#ifndef PTRACE_PEEKMTETAGS +#define PTRACE_PEEKMTETAGS (PT_COMMAND_MAX+7) +#endif +#ifndef PTRACE_POKEMTETAGS +#define PTRACE_POKEMTETAGS (PT_COMMAND_MAX+8) +#endif +#ifndef PTRACE_GETVRREGS +#define PTRACE_GETVRREGS (PT_COMMAND_MAX+9) +#endif +#ifndef PTRACE_GETVSRREGS +#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+10) +#endif + +#endif // liblldb_Host_aix_Ptrace_h_ diff --git a/lldb/include/lldb/Host/aix/Support.h b/lldb/include/lldb/Host/aix/Support.h new file mode 100644 index 0000000000000..27d6c2b50a35b --- /dev/null +++ b/lldb/include/lldb/Host/aix/Support.h @@ -0,0 +1,29 @@ +//===-- Support.h -----------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_HOST_AIX_SUPPORT_H +#define LLDB_HOST_AIX_SUPPORT_H + +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MemoryBuffer.h" +#include + +namespace lldb_private { + +llvm::ErrorOr> +getProcFile(::pid_t pid, ::pid_t tid, const llvm::Twine &file); + +llvm::ErrorOr> +getProcFile(::pid_t pid, const llvm::Twine &file); + +llvm::ErrorOr> +getProcFile(const llvm::Twine &file); + +} // namespace lldb_private + +#endif // #ifndef LLDB_HOST_AIX_SUPPORT_H diff --git a/lldb/include/lldb/Host/aix/Uio.h b/lldb/include/lldb/Host/aix/Uio.h new file mode 100644 index 0000000000000..acf79ecc6a1d0 --- /dev/null +++ b/lldb/include/lldb/Host/aix/Uio.h @@ -0,0 +1,23 @@ +//===-- Uio.h ---------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Host_aix_Uio_h_ +#define liblldb_Host_aix_Uio_h_ + +#include "lldb/Host/Config.h" +#include + +// We shall provide our own implementation of process_vm_readv if it is not +// present +#if !HAVE_PROCESS_VM_READV +ssize_t process_vm_readv(::pid_t pid, const struct iovec *local_iov, + unsigned long liovcnt, const struct iovec *remote_iov, + unsigned long riovcnt, unsigned long flags); +#endif + +#endif // liblldb_Host_aix_Uio_h_ diff --git a/lldb/include/lldb/Host/common/GetOptInc.h b/lldb/include/lldb/Host/common/GetOptInc.h index 3fb9add479541..ebb475bfaf6b8 100644 --- a/lldb/include/lldb/Host/common/GetOptInc.h +++ b/lldb/include/lldb/Host/common/GetOptInc.h @@ -11,11 +11,11 @@ #include "lldb/lldb-defines.h" -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__AIX__) #define REPLACE_GETOPT #define REPLACE_GETOPT_LONG #endif -#if defined(_MSC_VER) || defined(__NetBSD__) +#if defined(_MSC_VER) || defined(__NetBSD__) || defined(__AIX__) #define REPLACE_GETOPT_LONG_ONLY #endif @@ -35,7 +35,7 @@ struct option { int val; }; -int getopt(int argc, char *const argv[], const char *optstring); +int getopt(int argc, char *const argv[], const char *optstring) throw(); // from getopt.h extern char *optarg; diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h index 8592323322e38..bf66ccec263d2 100644 --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/lldb/include/lldb/Symbol/ObjectFile.h @@ -401,6 +401,11 @@ class ObjectFile : public std::enable_shared_from_this, return false; } + virtual bool SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) { + return false; + } + /// Gets whether endian swapping should occur when extracting data from this /// object file. /// diff --git a/lldb/include/lldb/Target/ABI.h b/lldb/include/lldb/Target/ABI.h index 7b646d743346b..281a89951ef88 100644 --- a/lldb/include/lldb/Target/ABI.h +++ b/lldb/include/lldb/Target/ABI.h @@ -47,6 +47,12 @@ class ABI : public PluginInterface { lldb::addr_t returnAddress, llvm::ArrayRef args) const = 0; + virtual bool PrepareTrivialCall(lldb_private::Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t tocAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef args) const; + // Prepare trivial call used from ThreadPlanFunctionCallUsingABI // AD: // . Because i don't want to change other ABI's this is not declared pure diff --git a/lldb/include/lldb/Target/DynamicLoader.h b/lldb/include/lldb/Target/DynamicLoader.h index 0629e2faae7e9..7dccd317c2dca 100644 --- a/lldb/include/lldb/Target/DynamicLoader.h +++ b/lldb/include/lldb/Target/DynamicLoader.h @@ -359,6 +359,12 @@ class DynamicLoader : public PluginInterface { lldb::addr_t base_addr, bool base_addr_is_offset); + virtual void UpdateLoadedSectionsByType(lldb::ModuleSP module, + lldb::addr_t link_map_addr, + lldb::addr_t base_addr, + bool base_addr_is_offset, + int type_id); + // Utility method so base classes can share implementation of // UpdateLoadedSections void UpdateLoadedSectionsCommon(lldb::ModuleSP module, lldb::addr_t base_addr, diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index cf16fbc812aa4..886ca766112c8 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -63,6 +63,10 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/VersionTuple.h" +#if defined(__AIX__) +struct ld_xinfo; +#endif + namespace lldb_private { template struct Range; @@ -1915,6 +1919,10 @@ class Process : public std::enable_shared_from_this, Status GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &range_info); +#if defined(__AIX__) + Status GetLDXINFO(struct ld_xinfo *info_ptr); +#endif + /// Obtain all the mapped memory regions within this process. /// /// \param[out] region_list @@ -2855,6 +2863,12 @@ void PruneThreadPlans(); return Status("Process::DoGetMemoryRegionInfo() not supported"); } +#if defined(__AIX__) + virtual Status DoGetLDXINFO(struct ld_xinfo *info_ptr) { + return Status("Process::DoGetLDXINFO() not supported"); + } +#endif + /// Provide an override value in the subclass for lldb's /// CPU-based logic for whether watchpoint exceptions are /// received before or after an instruction executes. diff --git a/lldb/include/lldb/Target/RegisterContextUnwind.h b/lldb/include/lldb/Target/RegisterContextUnwind.h index ef8ae88403866..00a95853800ed 100644 --- a/lldb/include/lldb/Target/RegisterContextUnwind.h +++ b/lldb/include/lldb/Target/RegisterContextUnwind.h @@ -67,6 +67,10 @@ class RegisterContextUnwind : public lldb_private::RegisterContext { bool ReadPC(lldb::addr_t &start_pc); +#ifdef __AIX__ + bool ReadLR(lldb::addr_t &lr); +#endif + // Indicates whether this frame *behaves* like frame zero -- the currently // executing frame -- or not. This can be true in the middle of the stack // above asynchronous trap handlers (sigtramp) for instance. diff --git a/lldb/include/lldb/Target/ThreadPlanCallFunction.h b/lldb/include/lldb/Target/ThreadPlanCallFunction.h index cb6e7caebb4ad..7880db1592e04 100644 --- a/lldb/include/lldb/Target/ThreadPlanCallFunction.h +++ b/lldb/include/lldb/Target/ThreadPlanCallFunction.h @@ -27,6 +27,12 @@ class ThreadPlanCallFunction : public ThreadPlan { llvm::ArrayRef args, const EvaluateExpressionOptions &options); + ThreadPlanCallFunction(Thread &thread, const Address &function, + const Address &toc, + const CompilerType &return_type, + llvm::ArrayRef args, + const EvaluateExpressionOptions &options); + ThreadPlanCallFunction(Thread &thread, const Address &function, const EvaluateExpressionOptions &options); diff --git a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h index dd468ef5bddef..9953bd6c24588 100644 --- a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h +++ b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h @@ -61,6 +61,7 @@ class StringExtractorGDBRemote : public StringExtractor { eServerPacketType_qQueryGDBServer, eServerPacketType_qKillSpawnedProcess, eServerPacketType_qLaunchSuccess, + eServerPacketType_qLDXINFO, eServerPacketType_qModuleInfo, eServerPacketType_qProcessInfoPID, eServerPacketType_qSpeedTest, diff --git a/lldb/include/lldb/lldb-private-enumerations.h b/lldb/include/lldb/lldb-private-enumerations.h index c24a3538f58da..98c1e956bf8f7 100644 --- a/lldb/include/lldb/lldb-private-enumerations.h +++ b/lldb/include/lldb/lldb-private-enumerations.h @@ -65,6 +65,7 @@ enum ArchitectureType { eArchTypeMachO, eArchTypeELF, eArchTypeCOFF, + eArchTypeXCOFF, kNumArchTypes }; diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index a32bc58507d8e..3ecdb11daef7d 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -40,6 +40,113 @@ add_custom_target(lldb-sbapi-dwarf-enums DEPENDS ${sb_languages_file}) set_target_properties(lldb-sbapi-dwarf-enums PROPERTIES FOLDER "LLDB/Tablegenning") +if(CMAKE_SYSTEM_NAME MATCHES "AIX") +add_lldb_library(liblldb STATIC ${option_framework} + SBAddress.cpp + SBAddressRange.cpp + SBAddressRangeList.cpp + SBAttachInfo.cpp + SBBlock.cpp + SBBreakpoint.cpp + SBBreakpointLocation.cpp + SBBreakpointName.cpp + SBBreakpointOptionCommon.cpp + SBBroadcaster.cpp + SBCommandInterpreter.cpp + SBCommandInterpreterRunOptions.cpp + SBCommandReturnObject.cpp + SBCommunication.cpp + SBCompileUnit.cpp + SBSaveCoreOptions.cpp + SBData.cpp + SBDebugger.cpp + SBDeclaration.cpp + SBEnvironment.cpp + SBError.cpp + SBEvent.cpp + SBExecutionContext.cpp + SBExpressionOptions.cpp + SBFileSpec.cpp + SBFile.cpp + SBFileSpecList.cpp + SBFormat.cpp + SBFrame.cpp + SBFunction.cpp + SBHostOS.cpp + SBInstruction.cpp + SBInstructionList.cpp + SBLanguageRuntime.cpp + SBLaunchInfo.cpp + SBLineEntry.cpp + SBListener.cpp + SBMemoryRegionInfo.cpp + SBMemoryRegionInfoList.cpp + SBModule.cpp + SBModuleSpec.cpp + SBPlatform.cpp + SBProcess.cpp + SBProcessInfo.cpp + SBProcessInfoList.cpp + SBQueue.cpp + SBQueueItem.cpp + SBReproducer.cpp + SBScriptObject.cpp + SBSection.cpp + SBSourceManager.cpp + SBStatisticsOptions.cpp + SBStream.cpp + SBStringList.cpp + SBStructuredData.cpp + SBSymbol.cpp + SBSymbolContext.cpp + SBSymbolContextList.cpp + SBTarget.cpp + SBThread.cpp + SBThreadCollection.cpp + SBThreadPlan.cpp + SBTrace.cpp + SBTraceCursor.cpp + SBType.cpp + SBTypeCategory.cpp + SBTypeEnumMember.cpp + SBTypeFilter.cpp + SBTypeFormat.cpp + SBTypeNameSpecifier.cpp + SBTypeSummary.cpp + SBTypeSynthetic.cpp + SBValue.cpp + SBValueList.cpp + SBVariablesOptions.cpp + SBWatchpoint.cpp + SBWatchpointOptions.cpp + SBUnixSignals.cpp + SystemInitializerFull.cpp + ${lldb_python_wrapper} + ${lldb_lua_wrapper} + + DEPENDS + lldb-sbapi-dwarf-enums + + LINK_LIBS + lldbBreakpoint + lldbCore + lldbDataFormatters + lldbExpression + lldbHost + lldbInitialization + lldbInterpreter + lldbSymbol + lldbTarget + lldbUtility + lldbVersion + ${LLDB_ALL_PLUGINS} + LINK_COMPONENTS + Support + + ${option_install_prefix} +) + +else() add_lldb_library(liblldb SHARED ${option_framework} SBAddress.cpp SBAddressRange.cpp @@ -144,6 +251,7 @@ add_lldb_library(liblldb SHARED ${option_framework} ${option_install_prefix} ) +endif() # lib/pythonX.Y/dist-packages/lldb/_lldb.so is a symlink to lib/liblldb.so, # which depends on lib/libLLVM*.so (BUILD_SHARED_LIBS) or lib/libLLVM-10git.so diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp index 3d908047f9455..728fe04d14d92 100644 --- a/lldb/source/API/SBBreakpoint.cpp +++ b/lldb/source/API/SBBreakpoint.cpp @@ -342,7 +342,7 @@ uint32_t SBBreakpoint::GetIgnoreCount() const { return count; } -void SBBreakpoint::SetThreadID(tid_t tid) { +void SBBreakpoint::SetThreadID(lldb::tid_t tid) { LLDB_INSTRUMENT_VA(this, tid); BreakpointSP bkpt_sp = GetSP(); @@ -353,10 +353,10 @@ void SBBreakpoint::SetThreadID(tid_t tid) { } } -tid_t SBBreakpoint::GetThreadID() { +lldb::tid_t SBBreakpoint::GetThreadID() { LLDB_INSTRUMENT_VA(this); - tid_t tid = LLDB_INVALID_THREAD_ID; + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; BreakpointSP bkpt_sp = GetSP(); if (bkpt_sp) { std::lock_guard guard( diff --git a/lldb/source/API/SBBreakpointLocation.cpp b/lldb/source/API/SBBreakpointLocation.cpp index 75b66364d4f1a..fad9a4076a54f 100644 --- a/lldb/source/API/SBBreakpointLocation.cpp +++ b/lldb/source/API/SBBreakpointLocation.cpp @@ -302,7 +302,7 @@ bool SBBreakpointLocation::GetCommandLineCommands(SBStringList &commands) { return has_commands; } -void SBBreakpointLocation::SetThreadID(tid_t thread_id) { +void SBBreakpointLocation::SetThreadID(lldb::tid_t thread_id) { LLDB_INSTRUMENT_VA(this, thread_id); BreakpointLocationSP loc_sp = GetSP(); @@ -313,10 +313,10 @@ void SBBreakpointLocation::SetThreadID(tid_t thread_id) { } } -tid_t SBBreakpointLocation::GetThreadID() { +lldb::tid_t SBBreakpointLocation::GetThreadID() { LLDB_INSTRUMENT_VA(this); - tid_t tid = LLDB_INVALID_THREAD_ID; + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; BreakpointLocationSP loc_sp = GetSP(); if (loc_sp) { std::lock_guard guard( diff --git a/lldb/source/API/SBBreakpointName.cpp b/lldb/source/API/SBBreakpointName.cpp index 7f63aaf6fa7d5..5c7c0a8f6504b 100644 --- a/lldb/source/API/SBBreakpointName.cpp +++ b/lldb/source/API/SBBreakpointName.cpp @@ -347,7 +347,7 @@ bool SBBreakpointName::GetAutoContinue() { return bp_name->GetOptions().IsAutoContinue(); } -void SBBreakpointName::SetThreadID(tid_t tid) { +void SBBreakpointName::SetThreadID(lldb::tid_t tid) { LLDB_INSTRUMENT_VA(this, tid); BreakpointName *bp_name = GetBreakpointName(); @@ -361,7 +361,7 @@ void SBBreakpointName::SetThreadID(tid_t tid) { UpdateName(*bp_name); } -tid_t SBBreakpointName::GetThreadID() { +lldb::tid_t SBBreakpointName::GetThreadID() { LLDB_INSTRUMENT_VA(this); BreakpointName *bp_name = GetBreakpointName(); diff --git a/lldb/source/Core/DynamicLoader.cpp b/lldb/source/Core/DynamicLoader.cpp index 7758a87403b5a..ea43a7f98b69f 100644 --- a/lldb/source/Core/DynamicLoader.cpp +++ b/lldb/source/Core/DynamicLoader.cpp @@ -113,6 +113,16 @@ void DynamicLoader::UpdateLoadedSections(ModuleSP module, addr_t link_map_addr, UpdateLoadedSectionsCommon(module, base_addr, base_addr_is_offset); } +void DynamicLoader::UpdateLoadedSectionsByType(lldb::ModuleSP module, + lldb::addr_t link_map_addr, + lldb::addr_t base_addr, + bool base_addr_is_offset, + int type_id) { + bool changed; + module->SetLoadAddressByType(m_process->GetTarget(), base_addr, base_addr_is_offset, + changed, type_id); +} + void DynamicLoader::UpdateLoadedSectionsCommon(ModuleSP module, addr_t base_addr, bool base_addr_is_offset) { diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp index 387c4fac6b0f8..43c5b043ef7a2 100644 --- a/lldb/source/Core/Mangled.cpp +++ b/lldb/source/Core/Mangled.cpp @@ -167,12 +167,14 @@ static char *GetItaniumDemangledStr(const char *M) { "Expected demangled_size to return length including trailing null"); } +#if !defined(__AIX__) if (Log *log = GetLog(LLDBLog::Demangle)) { if (demangled_cstr) LLDB_LOGF(log, "demangled itanium: %s -> \"%s\"", M, demangled_cstr); else LLDB_LOGF(log, "demangled itanium: %s -> error: failed to demangle", M); } +#endif return demangled_cstr; } diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index f9d7832254f46..044a5d29978e8 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -1510,6 +1510,18 @@ bool Module::SetLoadAddress(Target &target, lldb::addr_t value, return false; } +bool Module::SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, bool &changed, int type_id) { + ObjectFile *object_file = GetObjectFile(); + if (object_file != nullptr) { + changed = object_file->SetLoadAddressByType(target, value, value_is_offset, type_id); + return true; + } else { + changed = false; + } + return false; +} + bool Module::MatchesModuleSpec(const ModuleSpec &module_ref) { const UUID &uuid = module_ref.GetUUID(); diff --git a/lldb/source/Core/Section.cpp b/lldb/source/Core/Section.cpp index 0763e88d4608f..9ed55853930a6 100644 --- a/lldb/source/Core/Section.cpp +++ b/lldb/source/Core/Section.cpp @@ -263,6 +263,10 @@ bool Section::ResolveContainedAddress(addr_t offset, Address &so_addr, bool Section::ContainsFileAddress(addr_t vm_addr) const { const addr_t file_addr = GetFileAddress(); +#ifdef __AIX__ + if (file_addr == 0) + return false; +#endif if (file_addr != LLDB_INVALID_ADDRESS && !IsThreadSpecific()) { if (file_addr <= vm_addr) { const addr_t offset = (vm_addr - file_addr) * m_target_byte_size; diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index 444e44b392891..c1feec990f989 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -130,7 +130,7 @@ static llvm::Error ReadRegisterValueAsScalar(RegisterContext *reg_ctx, /// Return the length in bytes of the set of operands for \p op. No guarantees /// are made on the state of \p data after this call. -static offset_t GetOpcodeDataSize(const DataExtractor &data, +static lldb::offset_t GetOpcodeDataSize(const DataExtractor &data, const lldb::offset_t data_offset, const uint8_t op, const DWARFUnit *dwarf_cu) { lldb::offset_t offset = data_offset; @@ -358,7 +358,7 @@ lldb::addr_t DWARFExpression::GetLocation_DW_OP_addr(const DWARFUnit *dwarf_cu, error = true; break; } - const offset_t op_arg_size = + const lldb::offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op, dwarf_cu); if (op_arg_size == LLDB_INVALID_OFFSET) { error = true; @@ -418,7 +418,7 @@ bool DWARFExpression::Update_DW_OP_addr(const DWARFUnit *dwarf_cu, m_data.SetData(encoder.GetDataBuffer()); return true; } - const offset_t op_arg_size = + const lldb::offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op, dwarf_cu); if (op_arg_size == LLDB_INVALID_OFFSET) break; @@ -435,7 +435,7 @@ bool DWARFExpression::ContainsThreadLocalStorage( if (op == DW_OP_form_tls_address || op == DW_OP_GNU_push_tls_address) return true; - const offset_t op_arg_size = + const lldb::offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op, dwarf_cu); if (op_arg_size == LLDB_INVALID_OFFSET) return false; @@ -515,7 +515,7 @@ bool DWARFExpression::LinkThreadLocalStorage( } if (!decoded_data) { - const offset_t op_arg_size = + const lldb::offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op, dwarf_cu); if (op_arg_size == LLDB_INVALID_OFFSET) return false; diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index c2e091ee8555b..5374b16881950 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -7,6 +7,11 @@ if (APPLE AND LLVM_ENABLE_LOCAL_SUBMODULE_VISIBILITY) endif() endif() +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + macro(add_host_subdirectory group) list(APPEND HOST_SOURCES ${ARGN}) source_group(${group} FILES ${ARGN}) @@ -133,6 +138,14 @@ else() openbsd/Host.cpp openbsd/HostInfoOpenBSD.cpp ) + + elseif (CMAKE_SYSTEM_NAME MATCHES "AIX") + add_host_subdirectory(aix + aix/AbstractSocket.cpp + aix/Host.cpp + aix/HostInfoAIX.cpp + aix/Support.cpp + ) endif() endif() diff --git a/lldb/source/Host/aix/AbstractSocket.cpp b/lldb/source/Host/aix/AbstractSocket.cpp new file mode 100644 index 0000000000000..bfb67d452f7ec --- /dev/null +++ b/lldb/source/Host/aix/AbstractSocket.cpp @@ -0,0 +1,21 @@ +//===-- AbstractSocket.cpp ------------------------------------------------===// +// +// 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 "lldb/Host/aix/AbstractSocket.h" + +#include "llvm/ADT/StringRef.h" + +using namespace lldb; +using namespace lldb_private; + +AbstractSocket::AbstractSocket(bool child_processes_inherit) + : DomainSocket(ProtocolUnixAbstract, child_processes_inherit) {} + +size_t AbstractSocket::GetNameOffset() const { return 1; } + +void AbstractSocket::DeleteSocketFile(llvm::StringRef name) {} diff --git a/lldb/source/Host/aix/Host.cpp b/lldb/source/Host/aix/Host.cpp new file mode 100644 index 0000000000000..d82cb9049d389 --- /dev/null +++ b/lldb/source/Host/aix/Host.cpp @@ -0,0 +1,304 @@ +//===-- source/Host/aix/Host.cpp ----------------------------------------===// +// +// 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/ScopedPrinter.h" + +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/ProcessInfo.h" +#include "lldb/Utility/Status.h" + +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Host/aix/Host.h" +#include "lldb/Host/aix/Support.h" +#include "lldb/Utility/DataExtractor.h" +#include "llvm/BinaryFormat/XCOFF.h" + +#include +#include + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; + +namespace { +enum class ProcessState { + Unknown, + Dead, + DiskSleep, + Idle, + Paging, + Parked, + Running, + Sleeping, + TracedOrStopped, + Zombie, +}; +} + +namespace lldb_private { +class ProcessLaunchInfo; +} + +static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo, + ProcessState &State, ::pid_t &TracerPid, + ::pid_t &Tgid) { + Log *log = GetLog(LLDBLog::Host); + + auto BufferOrError = getProcFile(Pid, "status"); + if (!BufferOrError) + return false; + + llvm::StringRef Rest = BufferOrError.get()->getBuffer(); + while (!Rest.empty()) { + llvm::StringRef Line; + std::tie(Line, Rest) = Rest.split('\n'); + + if (Line.consume_front("Gid:")) { + // Real, effective, saved set, and file system GIDs. Read the first two. + Line = Line.ltrim(); + uint32_t RGid, EGid; + Line.consumeInteger(10, RGid); + Line = Line.ltrim(); + Line.consumeInteger(10, EGid); + + ProcessInfo.SetGroupID(RGid); + ProcessInfo.SetEffectiveGroupID(EGid); + } else if (Line.consume_front("Uid:")) { + // Real, effective, saved set, and file system UIDs. Read the first two. + Line = Line.ltrim(); + uint32_t RUid, EUid; + Line.consumeInteger(10, RUid); + Line = Line.ltrim(); + Line.consumeInteger(10, EUid); + + ProcessInfo.SetUserID(RUid); + ProcessInfo.SetEffectiveUserID(EUid); + } else if (Line.consume_front("PPid:")) { + ::pid_t PPid; + Line.ltrim().consumeInteger(10, PPid); + ProcessInfo.SetParentProcessID(PPid); + } else if (Line.consume_front("State:")) { + State = llvm::StringSwitch(Line.ltrim().take_front(1)) + .Case("D", ProcessState::DiskSleep) + .Case("I", ProcessState::Idle) + .Case("R", ProcessState::Running) + .Case("S", ProcessState::Sleeping) + .CaseLower("T", ProcessState::TracedOrStopped) + .Case("W", ProcessState::Paging) + .Case("P", ProcessState::Parked) + .Case("X", ProcessState::Dead) + .Case("Z", ProcessState::Zombie) + .Default(ProcessState::Unknown); + if (State == ProcessState::Unknown) { + LLDB_LOG(log, "Unknown process state {0}", Line); + } + } else if (Line.consume_front("TracerPid:")) { + Line = Line.ltrim(); + Line.consumeInteger(10, TracerPid); + } else if (Line.consume_front("Tgid:")) { + Line = Line.ltrim(); + Line.consumeInteger(10, Tgid); + } + } + return true; +} + +static bool IsDirNumeric(const char *dname) { + for (; *dname; dname++) { + if (!isdigit(*dname)) + return false; + } + return true; +} + +static void GetProcessArgs(::pid_t pid, ProcessInstanceInfo &process_info) { + auto BufferOrError = getProcFile(pid, "cmdline"); + if (!BufferOrError) + return; + std::unique_ptr Cmdline = std::move(*BufferOrError); + + llvm::StringRef Arg0, Rest; + std::tie(Arg0, Rest) = Cmdline->getBuffer().split('\0'); + process_info.SetArg0(Arg0); + while (!Rest.empty()) { + llvm::StringRef Arg; + std::tie(Arg, Rest) = Rest.split('\0'); + process_info.GetArguments().AppendArgument(Arg); + } +} + +static void GetExePathAndArch(::pid_t pid, ProcessInstanceInfo &process_info) { + Log *log = GetLog(LLDBLog::Process); + std::string ExePath(PATH_MAX, '\0'); + std::string Basename(PATH_MAX, '\0'); + struct psinfo psinfoData; + + // We can't use getProcFile here because proc/[pid]/exe is a symbolic link. + llvm::SmallString<64> ProcExe; + (llvm::Twine("/proc/") + llvm::Twine(pid) + "/cwd").toVector(ProcExe); + + ssize_t len = readlink(ProcExe.c_str(), &ExePath[0], PATH_MAX); + if (len > 0) { + ExePath.resize(len); + + //FIXME: hack to get basename + struct stat statData; + + std::ostringstream oss; + + oss << "/proc/" << std::dec << pid << "/psinfo"; + assert(stat(oss.str().c_str(), &statData) == 0); + + const int fd = open(oss.str().c_str(), O_RDONLY); + assert (fd >= 0); + + ssize_t readNum = read(fd, &psinfoData, sizeof(psinfoData)); + assert (readNum >= 0); + + close (fd); + } else { + LLDB_LOG(log, "failed to read link exe link for {0}: {1}", pid, + Status(errno, eErrorTypePOSIX)); + ExePath.resize(0); + } + + llvm::StringRef PathRef = std::string(&(psinfoData.pr_psargs[0])); + + if (!PathRef.empty()) { + process_info.GetExecutableFile().SetFile(PathRef, FileSpec::Style::native); + ArchSpec arch_spec = ArchSpec(); + arch_spec.SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX); + process_info.SetArchitecture(arch_spec); + } +} + +static void GetProcessEnviron(::pid_t pid, ProcessInstanceInfo &process_info) { + // Get the process environment. + auto BufferOrError = getProcFile(pid, "environ"); + if (!BufferOrError) + return; + + std::unique_ptr Environ = std::move(*BufferOrError); + llvm::StringRef Rest = Environ->getBuffer(); + while (!Rest.empty()) { + llvm::StringRef Var; + std::tie(Var, Rest) = Rest.split('\0'); + process_info.GetEnvironment().insert(Var); + } +} + +static bool GetProcessAndStatInfo(::pid_t pid, + ProcessInstanceInfo &process_info, + ProcessState &State, ::pid_t &tracerpid) { + ::pid_t tgid; + tracerpid = 0; + process_info.Clear(); + + process_info.SetProcessID(pid); + + GetExePathAndArch(pid, process_info); + GetProcessArgs(pid, process_info); + GetProcessEnviron(pid, process_info); + + // Get User and Group IDs and get tracer pid. + if (!GetStatusInfo(pid, process_info, State, tracerpid, tgid)) + return false; + + return true; +} + +uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { + static const char procdir[] = "/proc/"; + + DIR *dirproc = opendir(procdir); + if (dirproc) { + struct dirent *direntry = nullptr; + const uid_t our_uid = getuid(); + const lldb::pid_t our_pid = getpid(); + bool all_users = match_info.GetMatchAllUsers(); + + while ((direntry = readdir(dirproc)) != nullptr) { + /* + if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name)) + continue; + */ + + lldb::pid_t pid = atoi(direntry->d_name); + + // Skip this process. + if (pid == our_pid) + continue; + + ::pid_t tracerpid; + ProcessState State; + ProcessInstanceInfo process_info; + + if (!GetProcessAndStatInfo(pid, process_info, State, tracerpid)) + continue; + + // Skip if process is being debugged. + if (tracerpid != 0) + continue; + + if (State == ProcessState::Zombie) + continue; + + // Check for user match if we're not matching all users and not running + // as root. + if (!all_users && (our_uid != 0) && (process_info.GetUserID() != our_uid)) + continue; + + if (match_info.Matches(process_info)) { + process_infos.push_back(process_info); + } + } + + closedir(dirproc); + } + + return process_infos.size(); +} + +bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { + ::pid_t tracerpid; + ProcessState State; + return GetProcessAndStatInfo(pid, process_info, State, tracerpid); +} + +Environment Host::GetEnvironment() { return Environment(environ); } + +Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) { + return Status("unimplemented"); +} + +std::optional lldb_private::getPIDForTID(lldb::pid_t tid) { + ::pid_t tracerpid, tgid = LLDB_INVALID_PROCESS_ID; + ProcessInstanceInfo process_info; + ProcessState state; + + if (!GetStatusInfo(tid, process_info, state, tracerpid, tgid) || + tgid == LLDB_INVALID_PROCESS_ID) + return std::nullopt; + return tgid; +} diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp new file mode 100644 index 0000000000000..8bda09e01741b --- /dev/null +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -0,0 +1,215 @@ +//===-- HostInfoAIX.cpp -------------------------------------------------===// +// +// 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 "lldb/Host/aix/HostInfoAIX.h" +#include "lldb/Host/Config.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" + +#include "llvm/Support/Threading.h" + +#include +#include +#include +#include +#include + +#include +#include + +using namespace lldb_private; + +namespace { +struct HostInfoAIXFields { + llvm::once_flag m_distribution_once_flag; + std::string m_distribution_id; + llvm::once_flag m_os_version_once_flag; + llvm::VersionTuple m_os_version; +}; +} // namespace + +static HostInfoAIXFields *g_fields = nullptr; + +void HostInfoAIX::Initialize(SharedLibraryDirectoryHelper *helper) { + HostInfoPosix::Initialize(helper); + + g_fields = new HostInfoAIXFields(); +} + +void HostInfoAIX::Terminate() { + assert(g_fields && "Missing call to Initialize?"); + delete g_fields; + g_fields = nullptr; + HostInfoBase::Terminate(); +} + +llvm::VersionTuple HostInfoAIX::GetOSVersion() { + assert(g_fields && "Missing call to Initialize?"); + llvm::call_once(g_fields->m_os_version_once_flag, []() { + struct utsname un; + if (uname(&un) != 0) + return; + + llvm::StringRef release = un.release; + // The kernel release string can include a lot of stuff (e.g. + // 4.9.0-6-amd64). We're only interested in the numbered prefix. + release = release.substr(0, release.find_first_not_of("0123456789.")); + g_fields->m_os_version.tryParse(release); + }); + + return g_fields->m_os_version; +} + +std::optional HostInfoAIX::GetOSBuildString() { + struct utsname un; + ::memset(&un, 0, sizeof(utsname)); + + if (uname(&un) < 0) + return std::nullopt; + + return std::string(un.release); +} + +llvm::StringRef HostInfoAIX::GetDistributionId() { + assert(g_fields && "Missing call to Initialize?"); + // Try to run 'lbs_release -i', and use that response for the distribution + // id. + llvm::call_once(g_fields->m_distribution_once_flag, []() { + Log *log = GetLog(LLDBLog::Host); + LLDB_LOGF(log, "attempting to determine AIX distribution..."); + + // check if the lsb_release command exists at one of the following paths + const char *const exe_paths[] = {"/bin/lsb_release", + "/usr/bin/lsb_release"}; + + for (size_t exe_index = 0; + exe_index < sizeof(exe_paths) / sizeof(exe_paths[0]); ++exe_index) { + const char *const get_distribution_info_exe = exe_paths[exe_index]; + if (access(get_distribution_info_exe, F_OK)) { + // this exe doesn't exist, move on to next exe + LLDB_LOGF(log, "executable doesn't exist: %s", + get_distribution_info_exe); + continue; + } + + // execute the distribution-retrieval command, read output + std::string get_distribution_id_command(get_distribution_info_exe); + get_distribution_id_command += " -i"; + + FILE *file = popen(get_distribution_id_command.c_str(), "r"); + if (!file) { + LLDB_LOGF(log, + "failed to run command: \"%s\", cannot retrieve " + "platform information", + get_distribution_id_command.c_str()); + break; + } + + // retrieve the distribution id string. + char distribution_id[256] = {'\0'}; + if (fgets(distribution_id, sizeof(distribution_id) - 1, file) != + nullptr) { + LLDB_LOGF(log, "distribution id command returned \"%s\"", + distribution_id); + + const char *const distributor_id_key = "Distributor ID:\t"; + if (strstr(distribution_id, distributor_id_key)) { + // strip newlines + std::string id_string(distribution_id + strlen(distributor_id_key)); + id_string.erase(std::remove(id_string.begin(), id_string.end(), '\n'), + id_string.end()); + + // lower case it and convert whitespace to underscores + std::transform( + id_string.begin(), id_string.end(), id_string.begin(), + [](char ch) { return tolower(isspace(ch) ? '_' : ch); }); + + g_fields->m_distribution_id = id_string; + LLDB_LOGF(log, "distribution id set to \"%s\"", + g_fields->m_distribution_id.c_str()); + } else { + LLDB_LOGF(log, "failed to find \"%s\" field in \"%s\"", + distributor_id_key, distribution_id); + } + } else { + LLDB_LOGF(log, + "failed to retrieve distribution id, \"%s\" returned no" + " lines", + get_distribution_id_command.c_str()); + } + + // clean up the file + pclose(file); + } + }); + + return g_fields->m_distribution_id; +} + +FileSpec HostInfoAIX::GetProgramFileSpec() { + static FileSpec g_program_filespec; + + if (!g_program_filespec) { + char exe_path[PATH_MAX]; + ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); + if (len > 0) { + exe_path[len] = 0; + g_program_filespec.SetFile(exe_path, FileSpec::Style::native); + } + } + + return g_program_filespec; +} + +bool HostInfoAIX::ComputeSupportExeDirectory(FileSpec &file_spec) { + if (HostInfoPosix::ComputeSupportExeDirectory(file_spec) && + file_spec.IsAbsolute() && FileSystem::Instance().Exists(file_spec)) + return true; + file_spec.SetDirectory(GetProgramFileSpec().GetDirectory()); + return !file_spec.GetDirectory().IsEmpty(); +} + +bool HostInfoAIX::ComputeSystemPluginsDirectory(FileSpec &file_spec) { + FileSpec temp_file("/usr/" LLDB_INSTALL_LIBDIR_BASENAME "/lldb/plugins"); + FileSystem::Instance().Resolve(temp_file); + file_spec.SetDirectory(temp_file.GetPath()); + return true; +} + +bool HostInfoAIX::ComputeUserPluginsDirectory(FileSpec &file_spec) { + // XDG Base Directory Specification + // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html If + // XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb. + const char *xdg_data_home = getenv("XDG_DATA_HOME"); + if (xdg_data_home && xdg_data_home[0]) { + std::string user_plugin_dir(xdg_data_home); + user_plugin_dir += "/lldb"; + file_spec.SetDirectory(user_plugin_dir.c_str()); + } else + file_spec.SetDirectory("~/.local/share/lldb"); + return true; +} + +void HostInfoAIX::ComputeHostArchitectureSupport(ArchSpec &arch_32, + ArchSpec &arch_64) { + HostInfoPosix::ComputeHostArchitectureSupport(arch_32, arch_64); + + const char *distribution_id = GetDistributionId().data(); + + // On Linux, "unknown" in the vendor slot isn't what we want for the default + // triple. It's probably an artifact of config.guess. + if (arch_32.IsValid()) { + if (arch_32.GetTriple().getVendor() == llvm::Triple::UnknownVendor) + arch_32.GetTriple().setVendorName(llvm::StringRef()); + } + if (arch_64.IsValid()) { + if (arch_64.GetTriple().getVendor() == llvm::Triple::UnknownVendor) + arch_64.GetTriple().setVendorName(llvm::StringRef()); + } +} diff --git a/lldb/source/Host/aix/Support.cpp b/lldb/source/Host/aix/Support.cpp new file mode 100644 index 0000000000000..1bf2662190127 --- /dev/null +++ b/lldb/source/Host/aix/Support.cpp @@ -0,0 +1,44 @@ +//===-- Support.cpp -------------------------------------------------------===// +// +// 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 "lldb/Host/aix/Support.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "llvm/Support/MemoryBuffer.h" + +llvm::ErrorOr> +lldb_private::getProcFile(::pid_t pid, ::pid_t tid, const llvm::Twine &file) { + Log *log = GetLog(LLDBLog::Host); + std::string File = + ("/proc/" + llvm::Twine(pid) + "/task/" + llvm::Twine(tid) + "/" + file) + .str(); + auto Ret = llvm::MemoryBuffer::getFileAsStream(File); + if (!Ret) + LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message()); + return Ret; +} + +llvm::ErrorOr> +lldb_private::getProcFile(::pid_t pid, const llvm::Twine &file) { + Log *log = GetLog(LLDBLog::Host); + std::string File = ("/proc/" + llvm::Twine(pid) + "/" + file).str(); + auto Ret = llvm::MemoryBuffer::getFileAsStream(File); + if (!Ret) + LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message()); + return Ret; +} + +llvm::ErrorOr> +lldb_private::getProcFile(const llvm::Twine &file) { + Log *log = GetLog(LLDBLog::Host); + std::string File = ("/proc/" + file).str(); + auto Ret = llvm::MemoryBuffer::getFileAsStream(File); + if (!Ret) + LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message()); + return Ret; +} diff --git a/lldb/source/Host/common/GetOptInc.cpp b/lldb/source/Host/common/GetOptInc.cpp index c2044b6873221..e0ae2aa1774b3 100644 --- a/lldb/source/Host/common/GetOptInc.cpp +++ b/lldb/source/Host/common/GetOptInc.cpp @@ -409,7 +409,7 @@ static int getopt_internal(int nargc, char *const *nargv, const char *options, * [eventually this will replace the BSD getopt] */ #if defined(REPLACE_GETOPT) -int getopt(int nargc, char *const *nargv, const char *options) { +int getopt(int nargc, char *const *nargv, const char *options) throw() { /* * We don't pass FLAG_PERMUTE to getopt_internal() since diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index e03d36e9cad4a..2fd7111a94fb2 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -357,9 +357,183 @@ bool Host::ResolveExecutableInBundle(FileSpec &file) { return false; } #ifndef _WIN32 +#if defined(__AIX__) + +#include +extern char **p_xargv; + +/* Fix missing Dl_info & dladdr in AIX + * The code is taken from netbsd.org (src/crypto/external/bsd/openssl/dist/crypto/dso/dso_dlfcn.c) + * except strlcpy & strlcat (those are taken from openbsd.org (src/lib/libc/string)) + */ +/*- + * See IBM's AIX Version 7.2, Technical Reference: + * Base Operating System and Extensions, Volume 1 and 2 + * https://www.ibm.com/support/knowledgecenter/ssw_aix_72/com.ibm.aix.base/technicalreferences.htm + */ +#include +#include + +/* strlcpy: + * Copy string src to buffer dst of size dsize. At most dsize-1 + * chars will be copied. Always NUL terminates (unless dsize == 0). + * Returns strlen(src); if retval >= dsize, truncation occurred. + */ +size_t strlcpy(char *dst, const char *src, size_t dsize) +{ + const char *osrc = src; + size_t nleft = dsize; + + /* Copy as many bytes as will fit. */ + if (nleft != 0) { + while (--nleft != 0) { + if ((*dst++ = *src++) == '\0') { + break; + } + } + } + + /* Not enough room in dst, add NUL and traverse rest of src. */ + if (nleft == 0) { + if (dsize != 0) { + *dst = '\0'; /* NUL-terminate dst */ + } + while (*src++) { + ; + } + } + + return src - osrc - 1; /* count does not include NUL */ +} + +/* strlcat: + * Appends src to string dst of size dsize (unlike strncat, dsize is the + * full size of dst, not space left). At most dsize-1 characters + * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). + * Returns strlen(src) + MIN(dsize, strlen(initial dst)). + * If retval >= dsize, truncation occurred. + */ +size_t strlcat(char *dst, const char *src, size_t dsize) +{ + const char *odst = dst; + const char *osrc = src; + size_t n = dsize; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end. */ + while (n-- != 0 && *dst != '\0') { + dst++; + } + dlen = dst - odst; + n = dsize - dlen; + + if (n-- == 0) { + return dlen + strlen(src); + } + while (*src != '\0') { + if (n != 0) { + *dst++ = *src; + n--; + } + src++; + } + *dst = '\0'; + + return dlen + src - osrc; /* count does not include NUL */ +} + +/* ~ 64 * (sizeof(struct ld_info) + _XOPEN_PATH_MAX + _XOPEN_NAME_MAX) */ +# define DLFCN_LDINFO_SIZE 86976 +typedef struct Dl_info { + const char *dli_fname; +} Dl_info; +/* + * This dladdr()-implementation will also find the ptrgl (Pointer Glue) virtual + * address of a function, which is just located in the DATA segment instead of + * the TEXT segment. + */ +static int dladdr(const void *ptr, Dl_info *dl) +{ + uintptr_t addr = (uintptr_t)ptr; + struct ld_info *ldinfos; + struct ld_info *next_ldi; + struct ld_info *this_ldi; + + if ((ldinfos = (struct ld_info *)malloc(DLFCN_LDINFO_SIZE)) == NULL) { + dl->dli_fname = NULL; + return 0; + } + + if ((loadquery(L_GETINFO, (void *)ldinfos, DLFCN_LDINFO_SIZE)) < 0) { + /*- + * Error handling is done through errno and dlerror() reading errno: + * ENOMEM (ldinfos buffer is too small), + * EINVAL (invalid flags), + * EFAULT (invalid ldinfos ptr) + */ + free((void *)ldinfos); + dl->dli_fname = NULL; + return 0; + } + next_ldi = ldinfos; + + do { + this_ldi = next_ldi; + if (((addr >= (uintptr_t)this_ldi->ldinfo_textorg) + && (addr < ((uintptr_t)this_ldi->ldinfo_textorg + + this_ldi->ldinfo_textsize))) + || ((addr >= (uintptr_t)this_ldi->ldinfo_dataorg) + && (addr < ((uintptr_t)this_ldi->ldinfo_dataorg + + this_ldi->ldinfo_datasize)))) { + char *buffer = NULL; + char *member = NULL; + size_t buffer_sz; + size_t member_len; + + buffer_sz = strlen(this_ldi->ldinfo_filename) + 1; + member = this_ldi->ldinfo_filename + buffer_sz; + if ((member_len = strlen(member)) > 0) { + buffer_sz += 1 + member_len + 1; + } + if ((buffer = (char *)malloc(buffer_sz)) != NULL) { + strlcpy(buffer, this_ldi->ldinfo_filename, buffer_sz); + if (member_len > 0) { + /* + * Need to respect a possible member name and not just + * returning the path name in this case. See docs: + * sys/ldr.h, loadquery() and dlopen()/RTLD_MEMBER. + */ + strlcat(buffer, "(", buffer_sz); + strlcat(buffer, member, buffer_sz); + strlcat(buffer, ")", buffer_sz); + } + dl->dli_fname = buffer; + } + break; + } else { + next_ldi = (struct ld_info *)((uintptr_t)this_ldi + + this_ldi->ldinfo_next); + } + } while (this_ldi->ldinfo_next); + free((void *)ldinfos); + return dl->dli_fname != NULL; +} + +#endif + FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSpec module_filespec; #if !defined(__ANDROID__) +#ifdef __AIX__ + if (host_addr == reinterpret_cast(HostInfoBase::ComputeSharedLibraryDirectory)) { + // FIXME: AIX dladdr return "lldb" for this case + if (p_xargv[0]) { + module_filespec.SetFile(p_xargv[0], FileSpec::Style::native); + FileSystem::Instance().Resolve(module_filespec); + return module_filespec; + } + } +#endif Dl_info info; if (::dladdr(host_addr, &info)) { if (info.dli_fname) { @@ -373,12 +547,6 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { #endif -#if !defined(__linux__) -bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) { - return false; -} -#endif - struct ShellInfo { ShellInfo() : process_reaped(false) {} diff --git a/lldb/source/Host/common/LICENSE.aix-netbsd.txt b/lldb/source/Host/common/LICENSE.aix-netbsd.txt new file mode 100644 index 0000000000000..9601ab43575f9 --- /dev/null +++ b/lldb/source/Host/common/LICENSE.aix-netbsd.txt @@ -0,0 +1,125 @@ + + LICENSE ISSUES + ============== + + The OpenSSL toolkit stays under a double license, i.e. both the conditions of + the OpenSSL License and the original SSLeay license apply to the toolkit. + See below for the actual license texts. + + OpenSSL License + --------------- + +/* ==================================================================== + * Copyright (c) 1998-2019 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core at openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay at cryptsoft.com). This product includes software written by Tim + * Hudson (tjh at cryptsoft.com). + * + */ + + Original SSLeay License + ----------------------- + +/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay at cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh at cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay at cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh at cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + diff --git a/lldb/source/Host/common/XML.cpp b/lldb/source/Host/common/XML.cpp index f480ef3166a44..62cac78aaac23 100644 --- a/lldb/source/Host/common/XML.cpp +++ b/lldb/source/Host/common/XML.cpp @@ -10,6 +10,9 @@ #include "lldb/Host/XML.h" #include "llvm/ADT/StringExtras.h" +#if defined(__AIX__) +#undef LLDB_ENABLE_LIBXML2 +#endif using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index fceeff08ed9d3..143254bb12901 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -721,6 +721,7 @@ ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, ConnectionStatus ConnectionFileDescriptor::ConnectFile( llvm::StringRef s, socket_id_callback_type socket_id_callback, Status *error_ptr) { +#if !defined(__AIX__) #if LLDB_ENABLE_POSIX std::string addr_str = s.str(); // file:///PATH @@ -753,6 +754,7 @@ ConnectionStatus ConnectionFileDescriptor::ConnectFile( m_io_sp = std::make_shared(fd, File::eOpenOptionReadWrite, true); return eConnectionStatusSuccess; #endif // LLDB_ENABLE_POSIX +#endif llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX"); } diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index cdb76da626bc9..a7c50f6a3c835 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,7 +11,9 @@ // C includes #include #include +#if !defined(__AIX__) #include +#endif #include #include #include diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp index 5fe4d015251c8..e5be0db4cf19b 100644 --- a/lldb/source/Host/posix/MainLoopPosix.cpp +++ b/lldb/source/Host/posix/MainLoopPosix.cpp @@ -179,9 +179,21 @@ Status MainLoopPosix::RunImpl::Poll() { read_fds.push_back(pfd); } +#if defined(__AIX__) + sigset_t origmask; + int timeout; + + timeout = -1; + pthread_sigmask(SIG_SETMASK, &sigmask, &origmask); + int ready = poll(read_fds.data(), read_fds.size(), timeout); + pthread_sigmask(SIG_SETMASK, &origmask, nullptr); + if (ready == -1 && errno != EINTR) + return Status(errno, eErrorTypePOSIX); +#else if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 && errno != EINTR) return Status(errno, eErrorTypePOSIX); +#endif return Status(); } @@ -312,8 +324,13 @@ MainLoopPosix::RegisterSignal(int signo, const Callback &callback, // If we're using kqueue, the signal needs to be unblocked in order to // receive it. If using pselect/ppoll, we need to block it, and later unblock // it as a part of the system call. +#if defined(__AIX__) + //FIXME: where is signal unblocked? + ret = pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, &old_set); +#else ret = pthread_sigmask(HAVE_SYS_EVENT_H ? SIG_UNBLOCK : SIG_BLOCK, &new_action.sa_mask, &old_set); +#endif assert(ret == 0 && "pthread_sigmask failed"); info.was_blocked = sigismember(&old_set, signo); auto insert_ret = m_signals.insert({signo, info}); diff --git a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp index 0a832ebad13a7..cd106f605b1f4 100644 --- a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp +++ b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp @@ -193,8 +193,13 @@ struct ForkLaunchInfo { } // Start tracing this child that is about to exec. +#if !defined(__AIX__) if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1) ExitWithError(error_fd, "ptrace"); +#else + if (ptrace64(PT_TRACE_ME, 0, 0, 0, nullptr) == -1) + ExitWithError(error_fd, "ptrace"); +#endif } // Execute. We should never return... diff --git a/lldb/source/Initialization/CMakeLists.txt b/lldb/source/Initialization/CMakeLists.txt index c1a167826f76f..9f94830c8509f 100644 --- a/lldb/source/Initialization/CMakeLists.txt +++ b/lldb/source/Initialization/CMakeLists.txt @@ -1,4 +1,4 @@ -if ( CMAKE_SYSTEM_NAME MATCHES "Linux|Android|FreeBSD|NetBSD" ) +if ( CMAKE_SYSTEM_NAME MATCHES "Linux|Android|FreeBSD|NetBSD|AIX" ) list(APPEND EXTRA_PLUGINS lldbPluginProcessPOSIX) endif() diff --git a/lldb/source/Initialization/SystemInitializerCommon.cpp b/lldb/source/Initialization/SystemInitializerCommon.cpp index 1a172a95aa147..4b01442a94bac 100644 --- a/lldb/source/Initialization/SystemInitializerCommon.cpp +++ b/lldb/source/Initialization/SystemInitializerCommon.cpp @@ -19,7 +19,7 @@ #include "lldb/Version/Version.h" #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__OpenBSD__) + defined(__OpenBSD__) || defined(__AIX__) #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" #endif @@ -79,7 +79,7 @@ llvm::Error SystemInitializerCommon::Initialize() { process_gdb_remote::ProcessGDBRemoteLog::Initialize(); #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__OpenBSD__) + defined(__OpenBSD__) || defined(__AIX__) ProcessPOSIXLog::Initialize(); #endif #if defined(_WIN32) diff --git a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp index eac058701313b..feb0d7c0e09be 100644 --- a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp +++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp @@ -156,6 +156,9 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) return false; +#if defined(__AIX__) + assert(0); +#else // Read TOC pointer value. reg_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0); @@ -171,6 +174,132 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, (uint64_t)reg_value); if (!process_sp->WritePointerToMemory(sp + stack_offset, reg_value, error)) return false; +#endif + + // Read the current SP value. + reg_value = reg_ctx->ReadRegisterAsUnsigned(sp_reg_info, 0); + + // Save current SP onto the stack. + LLDB_LOGF(log, "Writing SP at SP(0x%" PRIx64 ")+0: 0x%" PRIx64, (uint64_t)sp, + (uint64_t)reg_value); + if (!process_sp->WritePointerToMemory(sp, reg_value, error)) + return false; + + // %r1 is set to the actual stack value. + LLDB_LOGF(log, "Writing SP: 0x%" PRIx64, (uint64_t)sp); + + if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_info, sp)) + return false; + + // %pc is set to the address of the called function. + + LLDB_LOGF(log, "Writing IP: 0x%" PRIx64, (uint64_t)func_addr); + + if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_info, func_addr)) + return false; + + return true; +} + +bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, + addr_t func_addr, addr_t toc_addr, + addr_t return_addr, + llvm::ArrayRef args) const { + Log *log = GetLog(LLDBLog::Expressions); + + if (log) { + StreamString s; + s.Printf("ABISysV_ppc64::PrepareTrivialCall (tid = 0x%" PRIx64 + ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 + ", return_addr = 0x%" PRIx64, + thread.GetID(), (uint64_t)sp, (uint64_t)func_addr, + (uint64_t)return_addr); + + for (size_t i = 0; i < args.size(); ++i) + s.Printf(", arg%" PRIu64 " = 0x%" PRIx64, static_cast(i + 1), + args[i]); + s.PutCString(")"); + log->PutString(s.GetString()); + } + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return false; + + const RegisterInfo *reg_info = nullptr; + + if (args.size() > 8) // TODO handle more than 8 arguments + return false; + + for (size_t i = 0; i < args.size(); ++i) { + reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_ARG1 + i); + LLDB_LOGF(log, "About to write arg%" PRIu64 " (0x%" PRIx64 ") into %s", + static_cast(i + 1), args[i], reg_info->name); + if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) + return false; + } + + // First, align the SP + + LLDB_LOGF(log, "16-byte aligning SP: 0x%" PRIx64 " to 0x%" PRIx64, + (uint64_t)sp, (uint64_t)(sp & ~0xfull)); + + sp &= ~(0xfull); // 16-byte alignment + + sp -= 544; // allocate frame to save TOC, RA and SP. + + Status error; + uint64_t reg_value; + const RegisterInfo *pc_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + const RegisterInfo *sp_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); + ProcessSP process_sp(thread.GetProcess()); + const RegisterInfo *lr_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); + const RegisterInfo *r2_reg_info = reg_ctx->GetRegisterInfoAtIndex(2); + const RegisterInfo *r12_reg_info = reg_ctx->GetRegisterInfoAtIndex(12); + + // Save return address onto the stack. + LLDB_LOGF(log, + "Pushing the return address onto the stack: 0x%" PRIx64 + "(+16): 0x%" PRIx64, + (uint64_t)sp, (uint64_t)return_addr); + if (!process_sp->WritePointerToMemory(sp + 16, return_addr, error)) + return false; + + // Write the return address to link register. + LLDB_LOGF(log, "Writing LR: 0x%" PRIx64, (uint64_t)return_addr); + if (!reg_ctx->WriteRegisterFromUnsigned(lr_reg_info, return_addr)) + return false; + + // Write target address to %r12 register. + LLDB_LOGF(log, "Writing R12: 0x%" PRIx64, (uint64_t)func_addr); + if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) + return false; + +#if defined(__AIX__) + LLDB_LOGF(log, "Writing R2: 0x%" PRIx64, (uint64_t)toc_addr); + if (!reg_ctx->WriteRegisterFromUnsigned(r2_reg_info, toc_addr)) + return false; +#else + // Read TOC pointer value. + reg_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0); + + // Write TOC pointer onto the stack. + uint64_t stack_offset; + if (GetByteOrder() == lldb::eByteOrderLittle) + stack_offset = 24; + else + stack_offset = 40; + + LLDB_LOGF(log, "Writing R2 (TOC) at SP(0x%" PRIx64 ")+%d: 0x%" PRIx64, + (uint64_t)(sp + stack_offset), (int)stack_offset, + (uint64_t)reg_value); + if (!process_sp->WritePointerToMemory(sp + stack_offset, reg_value, error)) + return false; +#endif // Read the current SP value. reg_value = reg_ctx->ReadRegisterAsUnsigned(sp_reg_info, 0); @@ -641,7 +770,7 @@ class ReturnValueExtractor { DataExtractor de(&raw_data, sizeof(raw_data), m_byte_order, m_addr_size); - offset_t offset = 0; + lldb::offset_t offset = 0; std::optional byte_size = type.GetByteSize(m_process_sp.get()); if (!byte_size) return {}; diff --git a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h index bfa96cc0df703..d752a8ded9748 100644 --- a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h +++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h @@ -23,6 +23,12 @@ class ABISysV_ppc64 : public lldb_private::RegInfoBasedABI { lldb::addr_t returnAddress, llvm::ArrayRef args) const override; + bool PrepareTrivialCall(lldb_private::Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t tocAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef args) const override; + bool GetArgumentValues(lldb_private::Thread &thread, lldb_private::ValueList &values) const override; diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt new file mode 100644 index 0000000000000..02fe0d617955a --- /dev/null +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt @@ -0,0 +1,11 @@ +add_definitions("-D_ALL_SOURCE") + +add_lldb_library(lldbPluginDynamicLoaderAIXDYLD PLUGIN + DynamicLoaderAIXDYLD.cpp + + LINK_LIBS + lldbCore + lldbTarget + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp new file mode 100644 index 0000000000000..62663974134b0 --- /dev/null +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -0,0 +1,272 @@ +//===-- DynamicLoaderAIXDYLD.cpp --------------------------------------===// +// +// 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 "DynamicLoaderAIXDYLD.h" + +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Platform.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/ThreadPlanStepInstruction.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#if defined(__AIX__) +#include +#endif + +/*#include "llvm/ADT/Triple.h" +*/ + +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(DynamicLoaderAIXDYLD) + +DynamicLoaderAIXDYLD::DynamicLoaderAIXDYLD(Process *process) + : DynamicLoader(process) {} + +DynamicLoaderAIXDYLD::~DynamicLoaderAIXDYLD() = default; + +void DynamicLoaderAIXDYLD::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); +} + +void DynamicLoaderAIXDYLD::Terminate() {} + +llvm::StringRef DynamicLoaderAIXDYLD::GetPluginDescriptionStatic() { + return "Dynamic loader plug-in that watches for shared library " + "loads/unloads in AIX processes."; +} + +DynamicLoader *DynamicLoaderAIXDYLD::CreateInstance(Process *process, + bool force) { + bool should_create = force; + if (!should_create) { + const llvm::Triple &triple_ref = + process->GetTarget().GetArchitecture().GetTriple(); + if (triple_ref.getOS() == llvm::Triple::AIX) + should_create = true; + } + + if (should_create) + return new DynamicLoaderAIXDYLD(process); + + return nullptr; +} + +void DynamicLoaderAIXDYLD::OnLoadModule(lldb::ModuleSP module_sp, + const ModuleSpec module_spec, + lldb::addr_t module_addr) { + + // Resolve the module unless we already have one. + if (!module_sp) { + Status error; + module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, + true /* notify */, &error); + if (error.Fail()) + return; + } + + m_loaded_modules[module_sp] = module_addr; + UpdateLoadedSectionsCommon(module_sp, module_addr, false); + ModuleList module_list; + module_list.Append(module_sp); + m_process->GetTarget().ModulesDidLoad(module_list); +} + +void DynamicLoaderAIXDYLD::OnUnloadModule(lldb::addr_t module_addr) { + Address resolved_addr; + if (!m_process->GetTarget().ResolveLoadAddress(module_addr, resolved_addr)) + return; + + ModuleSP module_sp = resolved_addr.GetModule(); + if (module_sp) { + m_loaded_modules.erase(module_sp); + UnloadSectionsCommon(module_sp); + ModuleList module_list; + module_list.Append(module_sp); + m_process->GetTarget().ModulesDidUnload(module_list, false); + } +} + +lldb::addr_t DynamicLoaderAIXDYLD::GetLoadAddress(ModuleSP executable) { + // First, see if the load address is already cached. + auto it = m_loaded_modules.find(executable); + if (it != m_loaded_modules.end() && it->second != LLDB_INVALID_ADDRESS) + return it->second; + + lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; + + // Second, try to get it through the process plugins. For a remote process, + // the remote platform will be responsible for providing it. + FileSpec file_spec(executable->GetPlatformFileSpec()); + bool is_loaded = false; + Status status = + m_process->GetFileLoadAddress(file_spec, is_loaded, load_addr); + // Servers other than lldb server could respond with a bogus address. + if (status.Success() && is_loaded && load_addr != LLDB_INVALID_ADDRESS) { + m_loaded_modules[executable] = load_addr; + return load_addr; + } + + //// Hack to try set breakpoint + //Breakpoint *dyld_break = m_process->GetTarget().CreateBreakpoint(0x100000638, true, false).get(); + //dyld_break->SetCallback(DynamicLoaderAIXDYLD::NotifyBreakpointHit, this, true); + //dyld_break->SetBreakpointKind("hack-debug"); + + return LLDB_INVALID_ADDRESS; +} + +bool DynamicLoaderAIXDYLD::NotifyBreakpointHit( + void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, + lldb::user_id_t break_loc_id) { +} + +void DynamicLoaderAIXDYLD::DidAttach() { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); + + ModuleSP executable = GetTargetExecutable(); + + if (!executable.get()) + return; + + // Try to fetch the load address of the file from the process, since there + // could be randomization of the load address. + lldb::addr_t load_addr = GetLoadAddress(executable); + if (load_addr == LLDB_INVALID_ADDRESS) + return; + + // Request the process base address. + lldb::addr_t image_base = m_process->GetImageInfoAddress(); + if (image_base == load_addr) + return; + + // Rebase the process's modules if there is a mismatch. + UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_addr, false); + + ModuleList module_list; + module_list.Append(executable); + m_process->GetTarget().ModulesDidLoad(module_list); + auto error = m_process->LoadModules(); + LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}"); + +#if defined(__AIX__) + // Get struct ld_xinfo (FIXME) + struct ld_xinfo ldinfo[64]; + Status status = m_process->GetLDXINFO(&(ldinfo[0])); + if (status.Fail()) { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOG(log, "LDXINFO failed: {0}", status); + return; + } + struct ld_xinfo *ptr = &(ldinfo[0]); + bool skip_current = true; + while (ptr != nullptr) { + char *pathName = (char *)ptr + ptr->ldinfo_filename; + char *memberName = pathName + (strlen(pathName) + 1); + if (!skip_current) { + // FIXME: buffer size + char pathWithMember[128] = {0}; + if (strlen(memberName) > 0) { + sprintf(pathWithMember, "%s(%s)", pathName, memberName); + } else { + sprintf(pathWithMember, "%s", pathName); + } + FileSpec file(pathWithMember); + ModuleSpec module_spec(file, m_process->GetTarget().GetArchitecture()); + if (ModuleSP module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, true /* notify */)) { + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_textorg, false, 1); + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_dataorg, false, 2); + // FIXME: .tdata, .bss + } + } else { + skip_current = false; + } + if (ptr->ldinfo_next == 0) { + ptr = nullptr; + } else { + ptr = (struct ld_xinfo *)((char *)ptr + ptr->ldinfo_next); + } + } +#endif +} + +void DynamicLoaderAIXDYLD::DidLaunch() { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); + + ModuleSP executable = GetTargetExecutable(); + if (!executable.get()) + return; + + lldb::addr_t load_addr = GetLoadAddress(executable); + if (load_addr != LLDB_INVALID_ADDRESS) { + // Update the loaded sections so that the breakpoints can be resolved. + UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_addr, false); + + ModuleList module_list; + module_list.Append(executable); + m_process->GetTarget().ModulesDidLoad(module_list); + auto error = m_process->LoadModules(); + LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}"); + } + +#if defined(__AIX__) + // Get struct ld_xinfo (FIXME) + struct ld_xinfo ldinfo[64]; + Status status = m_process->GetLDXINFO(&(ldinfo[0])); + if (status.Fail()) { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOG(log, "LDXINFO failed: {0}", status); + return; + } + struct ld_xinfo *ptr = &(ldinfo[0]); + bool skip_current = true; + while (ptr != nullptr) { + char *pathName = (char *)ptr + ptr->ldinfo_filename; + char *memberName = pathName + (strlen(pathName) + 1); + if (!skip_current) { + // FIXME: buffer size + char pathWithMember[128] = {0}; + if (strlen(memberName) > 0) { + sprintf(pathWithMember, "%s(%s)", pathName, memberName); + } else { + sprintf(pathWithMember, "%s", pathName); + } + FileSpec file(pathWithMember); + ModuleSpec module_spec(file, m_process->GetTarget().GetArchitecture()); + if (ModuleSP module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, true /* notify */)) { + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_textorg, false, 1); + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_dataorg, false, 2); + // FIXME: .tdata, .bss + } + } else { + skip_current = false; + } + if (ptr->ldinfo_next == 0) { + ptr = nullptr; + } else { + ptr = (struct ld_xinfo *)((char *)ptr + ptr->ldinfo_next); + } + } +#endif +} + +Status DynamicLoaderAIXDYLD::CanLoadImage() { return Status(); } + +ThreadPlanSP +DynamicLoaderAIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, + bool stop) { + //FIXME + return ThreadPlanSP(); +} diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h new file mode 100644 index 0000000000000..ae4b7aca66dcc --- /dev/null +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -0,0 +1,55 @@ +//===-- DynamicLoaderAIXDYLD.h ------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_DYNAMICLOADER_AIX_DYLD_DYNAMICLOADERAIXDYLD_H +#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_AIX_DYLD_DYNAMICLOADERAIXDYLD_H + +#include "lldb/Target/DynamicLoader.h" +#include "lldb/lldb-forward.h" + +#include + +namespace lldb_private { + +class DynamicLoaderAIXDYLD : public DynamicLoader { +public: + DynamicLoaderAIXDYLD(Process *process); + + ~DynamicLoaderAIXDYLD() override; + + static void Initialize(); + static void Terminate(); + static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; } + static llvm::StringRef GetPluginDescriptionStatic(); + + static DynamicLoader *CreateInstance(Process *process, bool force); + + void OnLoadModule(lldb::ModuleSP module_sp, const ModuleSpec module_spec, + lldb::addr_t module_addr); + void OnUnloadModule(lldb::addr_t module_addr); + + void DidAttach() override; + void DidLaunch() override; + Status CanLoadImage() override; + lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread, + bool stop) override; + + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + static bool NotifyBreakpointHit(void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id); + +protected: + lldb::addr_t GetLoadAddress(lldb::ModuleSP executable); + +private: + std::map m_loaded_modules; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_AIX_DYLD_DYNAMICLOADERWAIXDYLD_H diff --git a/lldb/source/Plugins/DynamicLoader/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/CMakeLists.txt index 30607159acdc0..4f3fb693faae1 100644 --- a/lldb/source/Plugins/DynamicLoader/CMakeLists.txt +++ b/lldb/source/Plugins/DynamicLoader/CMakeLists.txt @@ -5,4 +5,5 @@ add_subdirectory(POSIX-DYLD) add_subdirectory(Static) add_subdirectory(Hexagon-DYLD) add_subdirectory(Windows-DYLD) +add_subdirectory(AIX-DYLD) add_subdirectory(wasm-DYLD) diff --git a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp index 20e5652c65bf8..26abea0fdd24d 100644 --- a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp +++ b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp @@ -256,7 +256,7 @@ DynamicLoaderDarwinKernel::SearchForKernelWithDebugHints(Process *process) { if (process->ReadMemoryFromInferior (kernel_addresses_64[i], uval, 8, read_err) == 8) { DataExtractor data (&uval, 8, process->GetByteOrder(), process->GetAddressByteSize()); - offset_t offset = 0; + lldb::offset_t offset = 0; uint64_t addr = data.GetU64 (&offset); if (CheckForKernelImageAtAddress(addr, process).IsValid()) { return addr; @@ -270,7 +270,7 @@ DynamicLoaderDarwinKernel::SearchForKernelWithDebugHints(Process *process) { if (process->ReadMemoryFromInferior (kernel_addresses_32[i], uval, 4, read_err) == 4) { DataExtractor data (&uval, 4, process->GetByteOrder(), process->GetAddressByteSize()); - offset_t offset = 0; + lldb::offset_t offset = 0; uint32_t addr = data.GetU32 (&offset); if (CheckForKernelImageAtAddress(addr, process).IsValid()) { return addr; diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp index 3863b6b3520db..624848dee6ec3 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp @@ -1151,7 +1151,7 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp, // TLS data for the pthread_key on a specific thread yet. If we have we // can re-use it since its location will not change unless the process // execs. - const tid_t tid = thread_sp->GetID(); + const lldb::tid_t tid = thread_sp->GetID(); auto tid_pos = m_tid_to_tls_map.find(tid); if (tid_pos != m_tid_to_tls_map.end()) { auto tls_pos = tid_pos->second.find(key); diff --git a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp index 3035c51341778..d14ae2daeb47d 100644 --- a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp +++ b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp @@ -146,7 +146,25 @@ EmulateInstructionPPC64::GetOpcodeForInstruction(uint32_t opcode) { {0xfc000000, 0x38000000, &EmulateInstructionPPC64::EmulateADDI, "addi RT, RA, SI"}, {0xfc000003, 0xe8000000, &EmulateInstructionPPC64::EmulateLD, - "ld RT, DS(RA)"}}; + "ld RT, DS(RA)"}, +// {0xffff0003, 0x40820000, &EmulateInstructionPPC64::EmulateBNE, +// "bne TARGET"}, + {0xfc000002, 0x48000000, &EmulateInstructionPPC64::EmulateB, + "b TARGET"}, + {0xfc000003, 0x48000002, &EmulateInstructionPPC64::EmulateBA, + "ba TARGET"}, + {0xfc000003, 0x48000003, &EmulateInstructionPPC64::EmulateBLA, + "bla TARGET"}, + {0xfc000002, 0x40000000, &EmulateInstructionPPC64::EmulateBC, + "bc BO,BI,TARGET"}, + {0xfc000002, 0x40000002, &EmulateInstructionPPC64::EmulateBCA, + "bca BO,BI,TARGET"}, + {0xfc0007fe, 0x4c000020, &EmulateInstructionPPC64::EmulateBCLR, + "bclr BO,BI,BH"}, + {0xfc0007fe, 0x4c000420, &EmulateInstructionPPC64::EmulateBCCTR, + "bcctr BO,BI,BH"}, + {0xfc0007fe, 0x4c000460, &EmulateInstructionPPC64::EmulateBCTAR, + "bctar BO,BI,BH"}}; static const size_t k_num_ppc_opcodes = std::size(g_opcodes); for (size_t i = 0; i < k_num_ppc_opcodes; ++i) { @@ -169,12 +187,13 @@ bool EmulateInstructionPPC64::EvaluateInstruction(uint32_t evaluate_options) { bool success = false; - uint32_t orig_pc_value = 0; + uint64_t orig_pc_value = 0; if (auto_advance_pc) { orig_pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); if (!success) return false; + LLDB_LOG(GetLog(LLDBLog::Unwind), "orig_pc_value:{0}", orig_pc_value); } // Call the Emulate... function. @@ -183,11 +202,13 @@ bool EmulateInstructionPPC64::EvaluateInstruction(uint32_t evaluate_options) { return false; if (auto_advance_pc) { - uint32_t new_pc_value = + uint64_t new_pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); if (!success) return false; + LLDB_LOG(GetLog(LLDBLog::Unwind), "new_pc_value:{0}", new_pc_value); + if (new_pc_value == orig_pc_value) { EmulateInstruction::Context context; context.type = eContextAdvancePC; @@ -389,5 +410,174 @@ bool EmulateInstructionPPC64::EmulateADDI(uint32_t opcode) { return false; WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_r1_ppc64le, r1 + si_val); LLDB_LOG(log, "EmulateADDI: success!"); + + // FIX the next-pc + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + + return true; +} + +bool EmulateInstructionPPC64::EmulateBC(uint32_t opcode) { + // FIXME:32bit M + uint32_t M = 0; + uint32_t target32 = Bits32(opcode, 15, 2) << 2; + uint64_t target = (uint64_t)target32 + ((target32 & 0x8000) ? 0xffffffffffff0000UL : 0); + uint32_t BO = Bits32(opcode, 25, 21); + bool success; + uint64_t ctr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success); + if ((~BO) & (1U << 2)) + ctr_value = ctr_value - 1; + bool ctr_ok = (bool)(BO & (1U << 2)) | ((bool)(ctr_value != 0) ^ (bool)(BO & (1U << 1))); + uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success); + uint32_t BI = Bits32(opcode, 20, 16); + bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U)); + + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + if (ctr_ok & cond_ok) + next_pc = pc_value + target; + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + Log *log = GetLog(LLDBLog::Unwind); + LLDB_LOG(log, "EmulateBC: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBCA(uint32_t opcode) { + // FIXME:32bit M + uint32_t M = 0; + uint32_t target32 = Bits32(opcode, 15, 2) << 2; + uint64_t target = (uint64_t)target32 + ((target32 & 0x8000) ? 0xffffffffffff0000UL : 0); + uint32_t BO = Bits32(opcode, 25, 21); + bool success; + uint64_t ctr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success); + if ((~BO) & (1U << 2)) + ctr_value = ctr_value - 1; + bool ctr_ok = (bool)(BO & (1U << 2)) | ((bool)(ctr_value != 0) ^ (bool)(BO & (1U << 1))); + uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success); + uint32_t BI = Bits32(opcode, 20, 16); + bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U)); + + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + if (ctr_ok & cond_ok) + next_pc = target; + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + Log *log = GetLog(LLDBLog::Unwind); + LLDB_LOG(log, "EmulateBCA: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBCLR(uint32_t opcode) { + // FIXME:32bit M + uint32_t M = 0; + uint32_t BO = Bits32(opcode, 25, 21); + bool success; + uint64_t ctr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success); + if ((~BO) & (1U << 2)) + ctr_value = ctr_value - 1; + bool ctr_ok = (bool)(BO & (1U << 2)) | ((bool)(ctr_value != 0) ^ (bool)(BO & (1U << 1))); + uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success); + uint32_t BI = Bits32(opcode, 20, 16); + bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U)); + + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + if (ctr_ok & cond_ok) { + next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success); + next_pc &= ~((1UL << 2) - 1); + } + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + Log *log = GetLog(LLDBLog::Unwind); + LLDB_LOG(log, "EmulateBCLR: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBCCTR(uint32_t opcode) { + // FIXME:32bit M + uint32_t M = 0; + uint32_t BO = Bits32(opcode, 25, 21); + bool success; + uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success); + uint32_t BI = Bits32(opcode, 20, 16); + bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U)); + + Log *log = GetLog(LLDBLog::Unwind); + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + if (cond_ok) { + next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success); + next_pc &= ~((1UL << 2) - 1); + if (next_pc < 0x4000000) { + LLDB_LOGF(log, "EmulateBCCTR: next address %lx out of range, emulate by goto LR!"); + next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success); + } + } + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + LLDB_LOG(log, "EmulateBCCTR: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBCTAR(uint32_t opcode) { + // Not supported yet. + LLDB_LOG(GetLog(LLDBLog::Unwind), "EmulateBCTAR: not supported!"); + assert(0); + return false; +} + +bool EmulateInstructionPPC64::EmulateB(uint32_t opcode) { + uint32_t target32 = Bits32(opcode, 25, 2) << 2; + uint64_t target = (uint64_t)target32 + ((target32 & 0x2000000) ? 0xfffffffffc000000UL : 0); + + bool success; + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + target; + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + Log *log = GetLog(LLDBLog::Unwind); + LLDB_LOG(log, "EmulateB: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBA(uint32_t opcode) { + Log *log = GetLog(LLDBLog::Unwind); + + bool success; + uint64_t next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success); + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + LLDB_LOG(log, "EmulateBA: emulate by branch to lr!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBLA(uint32_t opcode) { + Log *log = GetLog(LLDBLog::Unwind); + + bool success; + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + LLDB_LOG(log, "EmulateBLA: emulate by branch to lr!"); return true; } diff --git a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h index a9424f16b0ad0..1576c9700e557 100644 --- a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h +++ b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h @@ -39,6 +39,12 @@ class EmulateInstructionPPC64 : public EmulateInstruction { return true; case eInstructionTypePCModifying: +#if defined(__AIX__) + return true; +#else + return false; +#endif + case eInstructionTypeAll: return false; } @@ -84,6 +90,14 @@ class EmulateInstructionPPC64 : public EmulateInstruction { bool EmulateSTD(uint32_t opcode); bool EmulateOR(uint32_t opcode); bool EmulateADDI(uint32_t opcode); + bool EmulateB(uint32_t opcode); + bool EmulateBA(uint32_t opcode); + bool EmulateBLA(uint32_t opcode); + bool EmulateBC(uint32_t opcode); + bool EmulateBCA(uint32_t opcode); + bool EmulateBCLR(uint32_t opcode); + bool EmulateBCCTR(uint32_t opcode); + bool EmulateBCTAR(uint32_t opcode); }; } // namespace lldb_private diff --git a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp index b7cd2b1ac6bf6..876e74056face 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp @@ -261,7 +261,7 @@ InstrumentationRuntimeMainThreadChecker::GetBacktracesFromExtendedStopInfo( StructuredData::ObjectSP thread_id_obj = info->GetObjectForDotSeparatedPath("tid"); - tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; + lldb::tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; // We gather symbolication addresses above, so no need for HistoryThread to // try to infer the call addresses. diff --git a/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp b/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp index b2781aa5e7db1..7a827a3ea76f9 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp @@ -770,13 +770,13 @@ std::string InstrumentationRuntimeTSan::GetLocationDescription( Sprintf("Location is a %ld-byte heap object at 0x%llx", size, addr); } } else if (type == "stack") { - tid_t tid = loc->GetAsDictionary() + lldb::tid_t tid = loc->GetAsDictionary() ->GetValueForKey("thread_id") ->GetUnsignedIntegerValue(); result = Sprintf("Location is stack of thread %d", tid); } else if (type == "tls") { - tid_t tid = loc->GetAsDictionary() + lldb::tid_t tid = loc->GetAsDictionary() ->GetValueForKey("thread_id") ->GetUnsignedIntegerValue(); @@ -948,7 +948,7 @@ static std::string GenerateThreadName(const std::string &path, if (path == "mops") { size_t size = o->GetObjectForDotSeparatedPath("size")->GetUnsignedIntegerValue(); - tid_t thread_id = + lldb::tid_t thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); bool is_write = o->GetObjectForDotSeparatedPath("is_write")->GetBooleanValue(); @@ -979,7 +979,7 @@ static std::string GenerateThreadName(const std::string &path, } if (path == "threads") { - tid_t thread_id = + lldb::tid_t thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); result = Sprintf("Thread %zu created", thread_id); } @@ -987,7 +987,7 @@ static std::string GenerateThreadName(const std::string &path, if (path == "locs") { std::string type = std::string( o->GetAsDictionary()->GetValueForKey("type")->GetStringValue()); - tid_t thread_id = + lldb::tid_t thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); int fd = o->GetObjectForDotSeparatedPath("file_descriptor") ->GetSignedIntegerValue(); @@ -1007,7 +1007,7 @@ static std::string GenerateThreadName(const std::string &path, } if (path == "stacks") { - tid_t thread_id = + lldb::tid_t thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); result = Sprintf("Thread %" PRIu64, thread_id); } @@ -1034,7 +1034,7 @@ static void AddThreadsForPath(const std::string &path, StructuredData::ObjectSP thread_id_obj = o->GetObjectForDotSeparatedPath("thread_os_id"); - tid_t tid = + lldb::tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; ThreadSP new_thread_sp = diff --git a/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp index 1c58922e8d36c..de9719ad4a89e 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp @@ -321,7 +321,7 @@ InstrumentationRuntimeUBSan::GetBacktracesFromExtendedStopInfo( StructuredData::ObjectSP thread_id_obj = info->GetObjectForDotSeparatedPath("tid"); - tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; + lldb::tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; // We gather symbolication addresses above, so no need for HistoryThread to // try to infer the call addresses. diff --git a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp index 1688fb27430a7..690fb0d60a09a 100644 --- a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp +++ b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp @@ -194,6 +194,10 @@ void JITLoaderGDB::SetJITBreakpoint(lldb_private::ModuleList &module_list) { if (jit_addr == LLDB_INVALID_ADDRESS) return; +#if defined(__AIX__) + return; +#endif + m_jit_descriptor_addr = GetSymbolAddress( module_list, ConstString("__jit_debug_descriptor"), eSymbolTypeData); if (m_jit_descriptor_addr == LLDB_INVALID_ADDRESS) { diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index 341923108e321..fb5bc2c58e6fb 100644 --- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -1227,6 +1227,7 @@ bool lldb_private::formatters::ObjCSELSummaryProvider( time_t lldb_private::formatters::GetOSXEpoch() { static time_t epoch = 0; if (!epoch) { +#if !defined(__AIX__) #ifndef _WIN32 tzset(); tm tm_epoch; @@ -1240,6 +1241,7 @@ time_t lldb_private::formatters::GetOSXEpoch() { tm_epoch.tm_gmtoff = 0; tm_epoch.tm_zone = nullptr; epoch = timegm(&tm_epoch); +#endif #endif } return epoch; diff --git a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp index 6efd2516578ff..fe6c5a0544be3 100644 --- a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp +++ b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp @@ -107,7 +107,7 @@ static void CreateHistoryThreadFromValueObject(ProcessSP process_sp, return; int count = count_sp->GetValueAsUnsigned(0); - tid_t tid = tid_sp->GetValueAsUnsigned(0) + 1; + lldb::tid_t tid = tid_sp->GetValueAsUnsigned(0) + 1; if (count <= 0) return; diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 7aa5b8d81890a..5ea55772c3aba 100644 --- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -8,7 +8,7 @@ #include "ObjectContainerBSDArchive.h" -#if defined(_WIN32) || defined(__ANDROID__) +#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__) // Defines from ar, missing on Windows #define SARMAG 8 #define ARFMAG "`\n" diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt b/lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt new file mode 100644 index 0000000000000..612a36265b536 --- /dev/null +++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt @@ -0,0 +1,10 @@ +add_lldb_library(lldbPluginObjectContainerBigArchive PLUGIN + ObjectContainerBigArchive.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp new file mode 100644 index 0000000000000..050ad73f1d19a --- /dev/null +++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp @@ -0,0 +1,522 @@ +//===-- ObjectContainerBigArchive.cpp -------------------------------------===// +// +// 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 "ObjectContainerBigArchive.h" + +#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__) +// Defines from ar, missing on Windows +#define ARMAG "!\n" +#define SARMAG 8 +#define ARFMAG "`\n" + +typedef struct ar_hdr { + char ar_name[16]; + char ar_date[12]; + char ar_uid[6], ar_gid[6]; + char ar_mode[8]; + char ar_size[10]; + char ar_fmag[2]; +} ar_hdr; +#else +#include +#endif + +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/Timer.h" + +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Object/Archive.h" +#include "llvm/Support/Chrono.h" + +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ObjectContainerBigArchive) + +ObjectContainerBigArchive::Object::Object() : ar_name() {} + +void ObjectContainerBigArchive::Object::Clear() { + ar_name.Clear(); + modification_time = 0; + uid = 0; + gid = 0; + mode = 0; + size = 0; + file_offset = 0; + file_size = 0; +} + +lldb::offset_t +ObjectContainerBigArchive::Object::Extract(const DataExtractor &data, + lldb::offset_t offset) { + size_t ar_name_len = 0; + std::string str; + char *err; + + // File header + // + // The common format is as follows. + // + // Offset Length Name Format + // 0 16 File name ASCII right padded with spaces (no spaces + // allowed in file name) + // 16 12 File mod Decimal as cstring right padded with + // spaces + // 28 6 Owner ID Decimal as cstring right padded with + // spaces + // 34 6 Group ID Decimal as cstring right padded with + // spaces + // 40 8 File mode Octal as cstring right padded with + // spaces + // 48 10 File byte size Decimal as cstring right padded with + // spaces + // 58 2 File magic 0x60 0x0A + + // Make sure there is enough data for the file header and bail if not + if (!data.ValidOffsetForDataOfSize(offset, 60)) + return LLDB_INVALID_OFFSET; + + str.assign((const char *)data.GetData(&offset, 16), 16); + if (llvm::StringRef(str).starts_with("#1/")) { + // If the name is longer than 16 bytes, or contains an embedded space then + // it will use this format where the length of the name is here and the + // name characters are after this header. + ar_name_len = strtoul(str.c_str() + 3, &err, 10); + } else { + // Strip off any trailing spaces. + const size_t last_pos = str.find_last_not_of(' '); + if (last_pos != std::string::npos) { + if (last_pos + 1 < 16) + str.erase(last_pos + 1); + } + ar_name.SetCString(str.c_str()); + } + + str.assign((const char *)data.GetData(&offset, 12), 12); + modification_time = strtoul(str.c_str(), &err, 10); + + str.assign((const char *)data.GetData(&offset, 6), 6); + uid = strtoul(str.c_str(), &err, 10); + + str.assign((const char *)data.GetData(&offset, 6), 6); + gid = strtoul(str.c_str(), &err, 10); + + str.assign((const char *)data.GetData(&offset, 8), 8); + mode = strtoul(str.c_str(), &err, 8); + + str.assign((const char *)data.GetData(&offset, 10), 10); + size = strtoul(str.c_str(), &err, 10); + + str.assign((const char *)data.GetData(&offset, 2), 2); + if (str == ARFMAG) { + if (ar_name_len > 0) { + const void *ar_name_ptr = data.GetData(&offset, ar_name_len); + // Make sure there was enough data for the string value and bail if not + if (ar_name_ptr == nullptr) + return LLDB_INVALID_OFFSET; + str.assign((const char *)ar_name_ptr, ar_name_len); + ar_name.SetCString(str.c_str()); + } + file_offset = offset; + file_size = size - ar_name_len; + return offset; + } + return LLDB_INVALID_OFFSET; +} + +ObjectContainerBigArchive::Archive::Archive(const lldb_private::ArchSpec &arch, + const llvm::sys::TimePoint<> &time, + lldb::offset_t file_offset, + lldb_private::DataExtractor &data) + : m_arch(arch), m_modification_time(time), m_file_offset(file_offset), + m_objects(), m_data(data) {} + +ObjectContainerBigArchive::Archive::~Archive() = default; + +size_t ObjectContainerBigArchive::Archive::ParseObjects() { + DataExtractor &data = m_data; + std::string str; + lldb::offset_t offset = 0; + str.assign((const char *)data.GetData(&offset, (sizeof(llvm::object::BigArchiveMagic) - 1)), + (sizeof(llvm::object::BigArchiveMagic) - 1)); + if (str == llvm::object::BigArchiveMagic) { + llvm::Error err = llvm::Error::success(); + llvm::object::BigArchive bigAr(llvm::MemoryBufferRef(toStringRef(m_data.GetData()), llvm::StringRef("")), err); + if (err) + return 0; + + for (const llvm::object::Archive::Child &child : bigAr.children(err)) { + if (err) + continue; + if (!child.getParent()) + continue; + Object obj; + obj.Clear(); + // FIXME: check errors + llvm::Expected childNameOrErr = child.getName(); + if (!childNameOrErr) + continue; + obj.ar_name.SetCString(childNameOrErr->str().c_str()); + llvm::Expected> lastModifiedOrErr = child.getLastModified(); + if (!lastModifiedOrErr) + continue; + obj.modification_time = (uint32_t)llvm::sys::toTimeT(*(lastModifiedOrErr)); + llvm::Expected getUIDOrErr = child.getUID(); + if (!getUIDOrErr) + continue; + obj.uid = (uint16_t)*getUIDOrErr; + llvm::Expected getGIDOrErr = child.getGID(); + if (!getGIDOrErr) + continue; + obj.gid = (uint16_t)*getGIDOrErr; + llvm::Expected getAccessModeOrErr = child.getAccessMode(); + if (!getAccessModeOrErr) + continue; + obj.mode = (uint16_t)*getAccessModeOrErr; + llvm::Expected getRawSizeOrErr = child.getRawSize(); + if (!getRawSizeOrErr) + continue; + obj.size = (uint32_t)*getRawSizeOrErr; + + obj.file_offset = (lldb::offset_t)child.getDataOffset(); + + llvm::Expected getSizeOrErr = child.getSize(); + if (!getSizeOrErr) + continue; + obj.file_size = (lldb::offset_t)*getSizeOrErr; + + size_t obj_idx = m_objects.size(); + m_objects.push_back(obj); + // Insert all of the C strings out of order for now... + m_object_name_to_index_map.Append(obj.ar_name, obj_idx); + } + if (err) + return 0; + + // Now sort all of the object name pointers + m_object_name_to_index_map.Sort(); + } + return m_objects.size(); +} + +ObjectContainerBigArchive::Object * +ObjectContainerBigArchive::Archive::FindObject( + ConstString object_name, const llvm::sys::TimePoint<> &object_mod_time) { + const ObjectNameToIndexMap::Entry *match = + m_object_name_to_index_map.FindFirstValueForName(object_name); + if (!match) + return nullptr; + if (object_mod_time == llvm::sys::TimePoint<>()) + return &m_objects[match->value]; + + const uint64_t object_modification_date = llvm::sys::toTimeT(object_mod_time); + if (m_objects[match->value].modification_time == object_modification_date) + return &m_objects[match->value]; + + const ObjectNameToIndexMap::Entry *next_match = + m_object_name_to_index_map.FindNextValueForName(match); + while (next_match) { + if (m_objects[next_match->value].modification_time == + object_modification_date) + return &m_objects[next_match->value]; + next_match = m_object_name_to_index_map.FindNextValueForName(next_match); + } + + return nullptr; +} + +ObjectContainerBigArchive::Archive::shared_ptr +ObjectContainerBigArchive::Archive::FindCachedArchive( + const FileSpec &file, const ArchSpec &arch, + const llvm::sys::TimePoint<> &time, lldb::offset_t file_offset) { + std::lock_guard guard(Archive::GetArchiveCacheMutex()); + shared_ptr archive_sp; + Archive::Map &archive_map = Archive::GetArchiveCache(); + Archive::Map::iterator pos = archive_map.find(file); + // Don't cache a value for "archive_map.end()" below since we might delete an + // archive entry... + while (pos != archive_map.end() && pos->first == file) { + bool match = true; + if (arch.IsValid() && + !pos->second->GetArchitecture().IsCompatibleMatch(arch)) + match = false; + else if (file_offset != LLDB_INVALID_OFFSET && + pos->second->GetFileOffset() != file_offset) + match = false; + if (match) { + if (pos->second->GetModificationTime() == time) { + return pos->second; + } else { + // We have a file at the same path with the same architecture whose + // modification time doesn't match. It doesn't make sense for us to + // continue to use this Big archive since we cache only the object info + // which consists of file time info and also the file offset and file + // size of any contained objects. Since this information is now out of + // date, we won't get the correct information if we go and extract the + // file data, so we should remove the old and outdated entry. + archive_map.erase(pos); + pos = archive_map.find(file); + continue; // Continue to next iteration so we don't increment pos + // below... + } + } + ++pos; + } + return archive_sp; +} + +ObjectContainerBigArchive::Archive::shared_ptr +ObjectContainerBigArchive::Archive::ParseAndCacheArchiveForFile( + const FileSpec &file, const ArchSpec &arch, + const llvm::sys::TimePoint<> &time, lldb::offset_t file_offset, + DataExtractor &data) { + shared_ptr archive_sp(new Archive(arch, time, file_offset, data)); + if (archive_sp) { + const size_t num_objects = archive_sp->ParseObjects(); + if (num_objects > 0) { + std::lock_guard guard( + Archive::GetArchiveCacheMutex()); + Archive::GetArchiveCache().insert(std::make_pair(file, archive_sp)); + } else { + archive_sp.reset(); + } + } + return archive_sp; +} + +ObjectContainerBigArchive::Archive::Map & +ObjectContainerBigArchive::Archive::GetArchiveCache() { + static Archive::Map g_archive_map; + return g_archive_map; +} + +std::recursive_mutex & +ObjectContainerBigArchive::Archive::GetArchiveCacheMutex() { + static std::recursive_mutex g_archive_map_mutex; + return g_archive_map_mutex; +} + +void ObjectContainerBigArchive::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + GetModuleSpecifications); +} + +void ObjectContainerBigArchive::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ObjectContainer *ObjectContainerBigArchive::CreateInstance( + const lldb::ModuleSP &module_sp, DataBufferSP &data_sp, + lldb::offset_t data_offset, const FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length) { + ConstString object_name(module_sp->GetObjectName()); + if (!object_name) + return nullptr; + + if (data_sp) { + // We have data, which means this is the first 512 bytes of the file Check + // to see if the magic bytes match and if they do, read the entire table of + // contents for the archive and cache it + DataExtractor data; + data.SetData(data_sp, data_offset, length); + if (file && data_sp && ObjectContainerBigArchive::MagicBytesMatch(data)) { + LLDB_SCOPED_TIMERF( + "ObjectContainerBigArchive::CreateInstance (module = %s, file = " + "%p, file_offset = 0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")", + module_sp->GetFileSpec().GetPath().c_str(), + static_cast(file), static_cast(file_offset), + static_cast(length)); + + // Map the entire .a file to be sure that we don't lose any data if the + // file gets updated by a new build while this .a file is being used for + // debugging + DataBufferSP archive_data_sp = + FileSystem::Instance().CreateDataBuffer(*file, length, file_offset); + if (!archive_data_sp) + return nullptr; + + lldb::offset_t archive_data_offset = 0; + + Archive::shared_ptr archive_sp(Archive::FindCachedArchive( + *file, module_sp->GetArchitecture(), module_sp->GetModificationTime(), + file_offset)); + std::unique_ptr container_up( + new ObjectContainerBigArchive(module_sp, archive_data_sp, + archive_data_offset, file, file_offset, + length)); + + if (container_up) { + if (archive_sp) { + // We already have this archive in our cache, use it + container_up->SetArchive(archive_sp); + return container_up.release(); + } else if (container_up->ParseHeader()) + return container_up.release(); + } + } + } else { + // No data, just check for a cached archive + Archive::shared_ptr archive_sp(Archive::FindCachedArchive( + *file, module_sp->GetArchitecture(), module_sp->GetModificationTime(), + file_offset)); + if (archive_sp) { + std::unique_ptr container_up( + new ObjectContainerBigArchive(module_sp, data_sp, data_offset, file, + file_offset, length)); + + if (container_up) { + // We already have this archive in our cache, use it + container_up->SetArchive(archive_sp); + return container_up.release(); + } + } + } + return nullptr; +} + +bool ObjectContainerBigArchive::MagicBytesMatch(const DataExtractor &data) { + uint32_t offset = 0; + const char *armag = (const char *)data.PeekData(offset, (sizeof(llvm::object::BigArchiveMagic) - 1)); + if (armag && ::strncmp(armag, llvm::object::BigArchiveMagic, (sizeof(llvm::object::BigArchiveMagic) - 1)) == 0) + return true; + return false; +} + +ObjectContainerBigArchive::ObjectContainerBigArchive( + const lldb::ModuleSP &module_sp, DataBufferSP &data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t size) + : ObjectContainer(module_sp, file, file_offset, size, data_sp, data_offset), + m_archive_sp() {} +void ObjectContainerBigArchive::SetArchive(Archive::shared_ptr &archive_sp) { + m_archive_sp = archive_sp; +} + +ObjectContainerBigArchive::~ObjectContainerBigArchive() = default; + +bool ObjectContainerBigArchive::ParseHeader() { + if (m_archive_sp.get() == nullptr) { + if (m_data.GetByteSize() > 0) { + ModuleSP module_sp(GetModule()); + if (module_sp) { + m_archive_sp = Archive::ParseAndCacheArchiveForFile( + m_file, module_sp->GetArchitecture(), + module_sp->GetModificationTime(), m_offset, m_data); + } + // Clear the m_data that contains the entire archive data and let our + // m_archive_sp hold onto the data. + m_data.Clear(); + } + } + return m_archive_sp.get() != nullptr; +} + +void ObjectContainerBigArchive::Object::Dump(Stream *s) const { + printf("name = \"%s\"\n", ar_name.GetCString()); + printf("mtime = 0x%8.8" PRIx32 "\n", modification_time); + printf("size = 0x%8.8" PRIx32 " (%" PRIu32 ")\n", size, size); + printf("file_offset = 0x%16.16" PRIx64 " (%" PRIu64 ")\n", file_offset, + file_offset); + printf("file_size = 0x%16.16" PRIx64 " (%" PRIu64 ")\n\n", file_size, + file_size); +} + +ObjectFileSP ObjectContainerBigArchive::GetObjectFile(const FileSpec *file) { + ModuleSP module_sp(GetModule()); + if (module_sp) { + if (module_sp->GetObjectName() && m_archive_sp) { + Object *object = m_archive_sp->FindObject( + module_sp->GetObjectName(), module_sp->GetObjectModificationTime()); + if (object) { + lldb::offset_t data_offset = object->file_offset; + return ObjectFile::FindPlugin( + module_sp, file, m_offset + object->file_offset, object->file_size, + m_archive_sp->GetData().GetSharedDataBuffer(), data_offset); + } + } + } + return ObjectFileSP(); +} + +size_t ObjectContainerBigArchive::GetModuleSpecifications( + const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, lldb::offset_t file_offset, + lldb::offset_t file_size, lldb_private::ModuleSpecList &specs) { + + // We have data, which means this is the first 512 bytes of the file Check to + // see if the magic bytes match and if they do, read the entire table of + // contents for the archive and cache it + DataExtractor data; + data.SetData(data_sp, data_offset, data_sp->GetByteSize()); + if (!file || !data_sp || !ObjectContainerBigArchive::MagicBytesMatch(data)) + return 0; + + const size_t initial_count = specs.GetSize(); + llvm::sys::TimePoint<> file_mod_time = FileSystem::Instance().GetModificationTime(file); + Archive::shared_ptr archive_sp( + Archive::FindCachedArchive(file, ArchSpec(), file_mod_time, file_offset)); + bool set_archive_arch = false; + if (!archive_sp) { + set_archive_arch = true; + data_sp = + FileSystem::Instance().CreateDataBuffer(file, file_size, file_offset); + if (data_sp) { + data.SetData(data_sp, 0, data_sp->GetByteSize()); + archive_sp = Archive::ParseAndCacheArchiveForFile( + file, ArchSpec(), file_mod_time, file_offset, data); + } + } + + if (archive_sp) { + const size_t num_objects = archive_sp->GetNumObjects(); + for (size_t idx = 0; idx < num_objects; ++idx) { + const Object *object = archive_sp->GetObjectAtIndex(idx); + if (object) { + 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( + file, object_file_offset, file_size - object_file_offset, + specs)) { + ModuleSpec &spec = + specs.GetModuleSpecRefAtIndex(specs.GetSize() - 1); + llvm::sys::TimePoint<> object_mod_time( + std::chrono::seconds(object->modification_time)); + spec.GetObjectName() = object->ar_name; + spec.SetObjectOffset(object_file_offset); + spec.SetObjectSize(file_size - object_file_offset); + spec.GetObjectModificationTime() = object_mod_time; + } + } + } + } + } + const size_t end_count = specs.GetSize(); + size_t num_specs_added = end_count - initial_count; + if (set_archive_arch && num_specs_added > 0) { + // The archive was created but we didn't have an architecture so we need to + // set it + for (size_t i = initial_count; i < end_count; ++i) { + ModuleSpec module_spec; + if (specs.GetModuleSpecAtIndex(i, module_spec)) { + if (module_spec.GetArchitecture().IsValid()) { + archive_sp->SetArchitecture(module_spec.GetArchitecture()); + break; + } + } + } + } + return num_specs_added; +} diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h new file mode 100644 index 0000000000000..ad9b814048a87 --- /dev/null +++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h @@ -0,0 +1,177 @@ +//===-- ObjectContainerBigArchive.h -----------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BIG_ARCHIVE_OBJECTCONTAINERBIGARCHIVE_H +#define LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BIG_ARCHIVE_OBJECTCONTAINERBIGARCHIVE_H + +#include "lldb/Core/UniqueCStringMap.h" +#include "lldb/Symbol/ObjectContainer.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/FileSpec.h" + +#include "llvm/Support/Chrono.h" + +#include +#include +#include + +class ObjectContainerBigArchive : public lldb_private::ObjectContainer { +public: + ObjectContainerBigArchive(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + ~ObjectContainerBigArchive() override; + + // Static Functions + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "big-archive"; } + + static llvm::StringRef GetPluginDescriptionStatic() { + return "Big Archive object container reader."; + } + + static lldb_private::ObjectContainer * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + static size_t GetModuleSpecifications(const lldb_private::FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + lldb_private::ModuleSpecList &specs); + + static bool MagicBytesMatch(const lldb_private::DataExtractor &data); + + // Member Functions + bool ParseHeader() override; + + size_t GetNumObjects() const override { + if (m_archive_sp) + return m_archive_sp->GetNumObjects(); + return 0; + } + + lldb::ObjectFileSP GetObjectFile(const lldb_private::FileSpec *file) override; + + // PluginInterface protocol + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + +protected: + struct Object { + Object(); + + void Clear(); + + lldb::offset_t Extract(const lldb_private::DataExtractor &data, + lldb::offset_t offset); + /// Object name in the archive. + lldb_private::ConstString ar_name; + + /// Object modification time in the archive. + uint32_t modification_time = 0; + + /// Object user id in the archive. + uint16_t uid = 0; + + /// Object group id in the archive. + uint16_t gid = 0; + + /// Object octal file permissions in the archive. + uint16_t mode = 0; + + /// Object size in bytes in the archive. + uint32_t size = 0; + + /// File offset in bytes from the beginning of the file of the object data. + lldb::offset_t file_offset = 0; + + /// Length of the object data. + lldb::offset_t file_size = 0; + + void Dump(lldb_private::Stream *s) const; + }; + + class Archive { + public: + typedef std::shared_ptr shared_ptr; + typedef std::multimap Map; + + Archive(const lldb_private::ArchSpec &arch, + const llvm::sys::TimePoint<> &mod_time, lldb::offset_t file_offset, + lldb_private::DataExtractor &data); + + ~Archive(); + + static Map &GetArchiveCache(); + + static std::recursive_mutex &GetArchiveCacheMutex(); + + static Archive::shared_ptr FindCachedArchive( + const lldb_private::FileSpec &file, const lldb_private::ArchSpec &arch, + const llvm::sys::TimePoint<> &mod_time, lldb::offset_t file_offset); + + static Archive::shared_ptr ParseAndCacheArchiveForFile( + const lldb_private::FileSpec &file, const lldb_private::ArchSpec &arch, + const llvm::sys::TimePoint<> &mod_time, lldb::offset_t file_offset, + lldb_private::DataExtractor &data); + + size_t GetNumObjects() const { return m_objects.size(); } + + const Object *GetObjectAtIndex(size_t idx) { + if (idx < m_objects.size()) + return &m_objects[idx]; + return nullptr; + } + + size_t ParseObjects(); + + Object *FindObject(lldb_private::ConstString object_name, + const llvm::sys::TimePoint<> &object_mod_time); + + lldb::offset_t GetFileOffset() const { return m_file_offset; } + + const llvm::sys::TimePoint<> &GetModificationTime() { + return m_modification_time; + } + + const lldb_private::ArchSpec &GetArchitecture() const { return m_arch; } + + void SetArchitecture(const lldb_private::ArchSpec &arch) { m_arch = arch; } + + bool HasNoExternalReferences() const; + + lldb_private::DataExtractor &GetData() { return m_data; } + + protected: + typedef lldb_private::UniqueCStringMap ObjectNameToIndexMap; + // Member Variables + lldb_private::ArchSpec m_arch; + llvm::sys::TimePoint<> m_modification_time; + lldb::offset_t m_file_offset; + std::vector m_objects; + ObjectNameToIndexMap m_object_name_to_index_map; + lldb_private::DataExtractor m_data; ///< The data for this object container + ///so we don't lose data if the .a files + ///gets modified + }; + + void SetArchive(Archive::shared_ptr &archive_sp); + + Archive::shared_ptr m_archive_sp; +}; + +#endif // LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BIG_ARCHIVE_OBJECTCONTAINERBIGARCHIVE_H diff --git a/lldb/source/Plugins/ObjectContainer/CMakeLists.txt b/lldb/source/Plugins/ObjectContainer/CMakeLists.txt index cda0c8151dd8a..2492798bb13ef 100644 --- a/lldb/source/Plugins/ObjectContainer/CMakeLists.txt +++ b/lldb/source/Plugins/ObjectContainer/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(BSD-Archive) +add_subdirectory(Big-Archive) add_subdirectory(Universal-Mach-O) add_subdirectory(Mach-O-Fileset) diff --git a/lldb/source/Plugins/ObjectFile/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/CMakeLists.txt index 773241c8944c8..7abd0c96f4fd7 100644 --- a/lldb/source/Plugins/ObjectFile/CMakeLists.txt +++ b/lldb/source/Plugins/ObjectFile/CMakeLists.txt @@ -6,5 +6,6 @@ add_subdirectory(Mach-O) add_subdirectory(Minidump) add_subdirectory(PDB) add_subdirectory(PECOFF) +add_subdirectory(XCOFF) add_subdirectory(Placeholder) add_subdirectory(wasm) diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index ce095bcc48374..bcb6330cbb1f9 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -5673,7 +5673,7 @@ bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &value, return false; } -bool ObjectFileMachO::GetCorefileThreadExtraInfos(std::vector &tids) { +bool ObjectFileMachO::GetCorefileThreadExtraInfos(std::vector &tids) { tids.clear(); ModuleSP module_sp(GetModule()); if (module_sp) { @@ -5724,8 +5724,8 @@ bool ObjectFileMachO::GetCorefileThreadExtraInfos(std::vector &tids) { return false; } StructuredData::Dictionary *thread = *maybe_thread; - tid_t tid = LLDB_INVALID_THREAD_ID; - if (thread->GetValueForKeyAsInteger("thread_id", tid)) + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; + if (thread->GetValueForKeyAsInteger("thread_id", tid)) if (tid == 0) tid = LLDB_INVALID_THREAD_ID; tids.push_back(tid); diff --git a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp index faa144bfb5f6a..d27cdfc60de85 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp +++ b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp @@ -51,7 +51,9 @@ size_t ObjectFileMinidump::GetModuleSpecifications( const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, lldb_private::ModuleSpecList &specs) { +#if !defined(__AIX__) specs.Clear(); +#endif return 0; } diff --git a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp index f0832dbf07347..75cc54e4f0d48 100644 --- a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp +++ b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp @@ -116,18 +116,31 @@ size_t ObjectFilePDB::GetModuleSpecifications( ModuleSpec module_spec(file); llvm::BumpPtrAllocator allocator; std::unique_ptr pdb_file = loadPDBFile(file.GetPath(), allocator); - if (!pdb_file) + if (!pdb_file){ +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif + } auto info_stream = pdb_file->getPDBInfoStream(); if (!info_stream) { llvm::consumeError(info_stream.takeError()); +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif } auto dbi_stream = pdb_file->getPDBDbiStream(); if (!dbi_stream) { llvm::consumeError(dbi_stream.takeError()); +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif } lldb_private::UUID &uuid = module_spec.GetUUID(); diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index bda691ade8af0..db8fa78043fdc 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -252,8 +252,13 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, lldb_private::ModuleSpecList &specs) { const size_t initial_count = specs.GetSize(); - if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp)) + if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp)){ +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif + } Log *log = GetLog(LLDBLog::Object); @@ -266,12 +271,21 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( if (!binary) { LLDB_LOG_ERROR(log, binary.takeError(), "Failed to create binary for file ({1}): {0}", file); +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif } auto *COFFObj = llvm::dyn_cast(binary->get()); - if (!COFFObj) + if (!COFFObj){ +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif + } ModuleSpec module_spec(file); ArchSpec &spec = module_spec.GetArchitecture(); diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt new file mode 100644 index 0000000000000..8840248574c88 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt @@ -0,0 +1,13 @@ +add_lldb_library(lldbPluginObjectFileXCOFF PLUGIN + ObjectFileXCOFF.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + lldbTarget + LINK_COMPONENTS + BinaryFormat + Object + Support + ) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp new file mode 100644 index 0000000000000..a4d9ea295b4c3 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -0,0 +1,780 @@ +//===-- ObjectFileXCOFF.cpp -------------------------------------------------===// +// +// 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 "ObjectFileXCOFF.h" + +#include +#include +#include +#include + +#include "lldb/Utility/FileSpecList.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Progress.h" +#include "lldb/Core/Section.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/LZMA.h" +#include "lldb/Symbol/DWARFCallFrameInfo.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RangeMap.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/Timer.h" +#include "llvm/ADT/IntervalMap.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/Object/Decompressor.h" +#include "llvm/Support/CRC.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Object/XCOFFObjectFile.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ObjectFileXCOFF) + +char ObjectFileXCOFF::ID; + +// FIXME: target 64bit at this moment. + +// Static methods. +void ObjectFileXCOFF::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + CreateMemoryInstance, GetModuleSpecifications); +} + +void ObjectFileXCOFF::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; + +ObjectFile *ObjectFileXCOFF::CreateInstance(const lldb::ModuleSP &module_sp, + DataBufferSP data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t file_offset, + lldb::offset_t length) { + if (!data_sp) { + data_sp = MapFileData(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + } + + if (!ObjectFileXCOFF::MagicBytesMatch(data_sp, data_offset, length)) + return nullptr; + + // Update the data to contain the entire file if it doesn't already + if (data_sp->GetByteSize() < length) { + data_sp = MapFileData(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + } + auto objfile_up = std::make_unique( + module_sp, data_sp, data_offset, file, file_offset, length); + if (!objfile_up) + return nullptr; + + // Cache xcoff binary. + if (!objfile_up->CreateBinary()) + return nullptr; + + if (!objfile_up->ParseHeader()) + //FIXME objfile leak + return nullptr; + + UGLY_FLAG_FOR_AIX = true; + return objfile_up.release(); +} + +bool ObjectFileXCOFF::CreateBinary() { + if (m_binary) + return true; + + Log *log = GetLog(LLDBLog::Object); + + auto binary = llvm::object::XCOFFObjectFile::createObjectFile(llvm::MemoryBufferRef( + toStringRef(m_data.GetData()), m_file.GetFilename().GetStringRef()), + file_magic::xcoff_object_64); + if (!binary) { + LLDB_LOG_ERROR(log, binary.takeError(), + "Failed to create binary for file ({1}): {0}", m_file); + return false; + } + + // Make sure we only handle COFF format. + m_binary = + llvm::unique_dyn_cast(std::move(*binary)); + if (!m_binary) + return false; + + LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}", + this, GetModule().get(), GetModule()->GetSpecificationDescription(), + m_file.GetPath(), m_binary.get()); + return true; +} + +ObjectFile *ObjectFileXCOFF::CreateMemoryInstance( + const lldb::ModuleSP &module_sp, WritableDataBufferSP data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) { + return nullptr; +} + +size_t ObjectFileXCOFF::GetModuleSpecifications( + const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, lldb::offset_t file_offset, + lldb::offset_t length, lldb_private::ModuleSpecList &specs) { + const size_t initial_count = specs.GetSize(); + + if (ObjectFileXCOFF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) { + ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + ModuleSpec spec(file, arch_spec); + spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX); + specs.Append(spec); + } + return specs.GetSize() - initial_count; +} + +static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) { + switch (magic) { + /* TODO: 32bit not supported yet + case XCOFF::XCOFF32: + return sizeof(struct llvm::object::XCOFFFileHeader32); + */ + + case XCOFF::XCOFF64: + return sizeof(struct llvm::object::XCOFFFileHeader64); + break; + + default: + break; + } + return 0; +} + +bool ObjectFileXCOFF::MagicBytesMatch(DataBufferSP &data_sp, + lldb::addr_t data_offset, + lldb::addr_t data_length) { + lldb_private::DataExtractor data; + data.SetData(data_sp, data_offset, data_length); + lldb::offset_t offset = 0; + uint16_t magic = data.GetU16(&offset); + return XCOFFHeaderSizeFromMagic(magic) != 0; +} + +bool ObjectFileXCOFF::ParseHeader() { + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard guard(module_sp->GetMutex()); + m_sect_headers.clear(); + lldb::offset_t offset = 0; + + if (ParseXCOFFHeader(m_data, &offset, m_xcoff_header)) { + m_data.SetAddressByteSize(GetAddressByteSize()); + if (m_xcoff_header.auxhdrsize > 0) + ParseXCOFFOptionalHeader(m_data, &offset); + ParseSectionHeaders(offset); + } + return true; + } + + return false; +} + +bool ObjectFileXCOFF::ParseXCOFFHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + xcoff_header_t &xcoff_header) { + //FIXME: data.ValidOffsetForDataOfSize + xcoff_header.magic = data.GetU16(offset_ptr); + xcoff_header.nsects = data.GetU16(offset_ptr); + xcoff_header.modtime = data.GetU32(offset_ptr); + xcoff_header.symoff = data.GetU64(offset_ptr); + xcoff_header.auxhdrsize = data.GetU16(offset_ptr); + xcoff_header.flags = data.GetU16(offset_ptr); + xcoff_header.nsyms = data.GetU32(offset_ptr); + return true; +} + +bool ObjectFileXCOFF::ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr) { + lldb::offset_t init_offset = *offset_ptr; + //FIXME: data.ValidOffsetForDataOfSize + m_xcoff_aux_header.AuxMagic = data.GetU16(offset_ptr); + m_xcoff_aux_header.Version = data.GetU16(offset_ptr); + m_xcoff_aux_header.ReservedForDebugger = data.GetU32(offset_ptr); + m_xcoff_aux_header.TextStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.DataStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.TOCAnchorAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfEntryPoint = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTOC = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfLoader = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.ModuleType = data.GetU16(offset_ptr); + m_xcoff_aux_header.CpuFlag = data.GetU8(offset_ptr); + m_xcoff_aux_header.CpuType = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.DataPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.StackPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.FlagAndTDataAlignment = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.InitDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.BssDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.EntryPointAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxStackSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfTData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.XCOFF64Flag = data.GetU16(offset_ptr); + lldb::offset_t last_offset = *offset_ptr; + if ((last_offset - init_offset) < m_xcoff_header.auxhdrsize) + *offset_ptr += (m_xcoff_header.auxhdrsize - (last_offset - init_offset)); + return true; +} + +bool ObjectFileXCOFF::ParseSectionHeaders( + uint32_t section_header_data_offset) { + const uint32_t nsects = m_xcoff_header.nsects; + m_sect_headers.clear(); + + if (nsects > 0) { + const size_t section_header_byte_size = nsects * m_binary->getSectionHeaderSize(); + lldb_private::DataExtractor section_header_data = + ReadImageData(section_header_data_offset, section_header_byte_size); + + lldb::offset_t offset = 0; + //FIXME: section_header_data.ValidOffsetForDataOfSize + m_sect_headers.resize(nsects); + + for (uint32_t idx = 0; idx < nsects; ++idx) { + const void *name_data = section_header_data.GetData(&offset, 8); + if (name_data) { + memcpy(m_sect_headers[idx].name, name_data, 8); + m_sect_headers[idx].phyaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].vmaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].size = section_header_data.GetU64(&offset); + m_sect_headers[idx].offset = section_header_data.GetU64(&offset); + m_sect_headers[idx].reloff = section_header_data.GetU64(&offset); + m_sect_headers[idx].lineoff = section_header_data.GetU64(&offset); + m_sect_headers[idx].nreloc = section_header_data.GetU32(&offset); + m_sect_headers[idx].nline = section_header_data.GetU32(&offset); + m_sect_headers[idx].flags = section_header_data.GetU32(&offset); + offset += 4; + } else { + offset += (m_binary->getSectionHeaderSize() - 8); + } + } + } + + return !m_sect_headers.empty(); +} + +lldb_private::DataExtractor ObjectFileXCOFF::ReadImageData(uint32_t offset, size_t size) { + if (!size) + return {}; + + if (m_data.ValidOffsetForDataOfSize(offset, size)) + return lldb_private::DataExtractor(m_data, offset, size); + + assert(0); + ProcessSP process_sp(m_process_wp.lock()); + lldb_private::DataExtractor data; + if (process_sp) { + auto data_up = std::make_unique(size, 0); + Status readmem_error; + size_t bytes_read = + process_sp->ReadMemory(offset, data_up->GetBytes(), + data_up->GetByteSize(), readmem_error); + if (bytes_read == size) { + DataBufferSP buffer_sp(data_up.release()); + data.SetData(buffer_sp, 0, buffer_sp->GetByteSize()); + } + } + return data; +} + +bool ObjectFileXCOFF::SetLoadAddress(Target &target, lldb::addr_t value, + bool value_is_offset) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (section_sp && !section_sp->IsThreadSpecific()) { + bool use_offset = false; + if (strcmp(section_sp->GetName().AsCString(), ".text") == 0 || + strcmp(section_sp->GetName().AsCString(), ".data") == 0 || + strcmp(section_sp->GetName().AsCString(), ".bss") == 0) + use_offset = true; + + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, (use_offset ? + (section_sp->GetFileOffset() + value) : (section_sp->GetFileAddress() + value)))) + ++num_loaded_sections; + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (type_id == 1 && section_sp && strcmp(section_sp->GetName().AsCString(), ".text") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileOffset() + value)) + ++num_loaded_sections; + } + } else if (type_id == 2 && section_sp && strcmp(section_sp->GetName().AsCString(), ".data") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileAddress() + value)) + ++num_loaded_sections; + } + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +ByteOrder ObjectFileXCOFF::GetByteOrder() const { + return eByteOrderBig; +} + +bool ObjectFileXCOFF::IsExecutable() const { + return true; +} + +uint32_t ObjectFileXCOFF::GetAddressByteSize() const { + if (m_xcoff_header.magic == XCOFF::XCOFF64) + return 8; + else if (m_xcoff_header.magic == XCOFF::XCOFF32) + return 4; + return 4; +} + +AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) { + return AddressClass::eUnknown; +} + +lldb::SymbolType ObjectFileXCOFF::MapSymbolType(llvm::object::SymbolRef::Type sym_type) { + if (sym_type == llvm::object::SymbolRef::ST_Function) + return lldb::eSymbolTypeCode; + else if (sym_type == llvm::object::SymbolRef::ST_Data) + return lldb::eSymbolTypeData; + return lldb::eSymbolTypeInvalid; +} + +void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) { + SectionList *sect_list = GetSectionList(); + const uint32_t num_syms = m_xcoff_header.nsyms; + uint32_t sidx = 0; + if (num_syms > 0 && m_xcoff_header.symoff > 0) { + const uint32_t symbol_size = XCOFF::SymbolTableEntrySize; + const size_t symbol_data_size = num_syms * symbol_size; + lldb_private::DataExtractor symtab_data = + ReadImageData(m_xcoff_header.symoff, symbol_data_size); + + lldb::offset_t offset = 0; + std::string symbol_name; + Symbol *symbols = lldb_symtab.Resize(num_syms); + llvm::object::symbol_iterator SI = m_binary->symbol_begin(); + for (uint32_t i = 0; i < num_syms; ++i, ++SI) { + xcoff_symbol_t symbol; + const uint32_t symbol_offset = offset; + symbol.value = symtab_data.GetU64(&offset); + symbol.offset = symtab_data.GetU32(&offset); + Expected symbol_name_or_err = m_binary->getStringTableEntry(symbol.offset); + if (!symbol_name_or_err) { + consumeError(symbol_name_or_err.takeError()); + return; + } + StringRef symbol_name_str = symbol_name_or_err.get(); + symbol_name.assign(symbol_name_str.data()); + symbol.sect = symtab_data.GetU16(&offset); + symbol.type = symtab_data.GetU16(&offset); + symbol.storage = symtab_data.GetU8(&offset); + symbol.naux = symtab_data.GetU8(&offset); + // Allow C_HIDEXT TOC symbol, and check others. + if (symbol.storage == XCOFF::C_HIDEXT && strcmp(symbol_name.c_str(), "TOC") != 0) { + if (symbol.naux == 0) + continue; + if (symbol.naux > 1) { + i += symbol.naux; + offset += symbol.naux * symbol_size; + continue; + } + /* Allow XCOFF::C_HIDEXT with following SMC and AT: + StorageMappingClass: XMC_PR (0x0) + Auxiliary Type: AUX_CSECT (0xFB) + */ + xcoff_sym_csect_aux_entry_t symbol_aux; + symbol_aux.section_or_len_low_byte = symtab_data.GetU32(&offset); + symbol_aux.parameter_hash_index = symtab_data.GetU32(&offset); + symbol_aux.type_check_sect_num = symtab_data.GetU16(&offset); + symbol_aux.symbol_alignment_and_type = symtab_data.GetU8(&offset); + symbol_aux.storage_mapping_class = symtab_data.GetU8(&offset); + symbol_aux.section_or_len_high_byte = symtab_data.GetU32(&offset); + symbol_aux.pad = symtab_data.GetU8(&offset); + symbol_aux.aux_type = symtab_data.GetU8(&offset); + offset -= symbol.naux * symbol_size; + if (symbol_aux.storage_mapping_class != XCOFF::XMC_PR || symbol_aux.aux_type != XCOFF::AUX_CSECT) { + i += symbol.naux; + offset += symbol.naux * symbol_size; + continue; + } + } + // Remove the dot prefix for demangle + if (symbol_name_str.size() > 1 && symbol_name_str.data()[0] == '.') { + symbols[sidx].GetMangled().SetValue(ConstString(symbol_name.c_str() + 1)); + } else { + symbols[sidx].GetMangled().SetValue(ConstString(symbol_name.c_str())); + } + if ((int16_t)symbol.sect >= 1) { + Address symbol_addr(sect_list->GetSectionAtIndex((size_t)(symbol.sect - 1)), + (symbol.value - sect_list->GetSectionAtIndex((size_t)(symbol.sect - 1))->GetFileAddress())); + symbols[sidx].GetAddressRef() = symbol_addr; + + Expected sym_type_or_err = SI->getType(); + if (!sym_type_or_err) { + consumeError(sym_type_or_err.takeError()); + return; + } + symbols[sidx].SetType(MapSymbolType(sym_type_or_err.get())); + } + ++sidx; + + if (symbol.naux > 0) { + i += symbol.naux; + offset += symbol.naux * symbol_size; + } + } + lldb_symtab.Resize(sidx); + } +} + +bool ObjectFileXCOFF::IsStripped() { + return false; +} + +void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) { + if (m_sections_up) + return; + m_sections_up = std::make_unique(); + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard guard(module_sp->GetMutex()); + + const uint32_t nsects = m_sect_headers.size(); + ModuleSP module_sp(GetModule()); + for (uint32_t idx = 0; idx < nsects; ++idx) { + llvm::StringRef sect_name = GetSectionName(m_sect_headers[idx]); + ConstString const_sect_name(sect_name); + SectionType section_type = GetSectionType(sect_name, m_sect_headers[idx]); + + SectionSP section_sp(new Section( + module_sp, // Module to which this section belongs + this, // Object file to which this section belongs + idx + 1, // Section ID is the 1 based section index. + const_sect_name, // Name of this section + section_type, + m_sect_headers[idx].vmaddr, // File VM address == addresses as + // they are found in the object file + m_sect_headers[idx].size, // VM size in bytes of this section + m_sect_headers[idx].offset, // Offset to the data for this section in the file + m_sect_headers[idx].size, // Size in bytes of this section as found in the file + 0, // FIXME: alignment + m_sect_headers[idx].flags)); // Flags for this section + + // FIXME + uint32_t permissions = 0; + permissions |= ePermissionsReadable; + if (m_sect_headers[idx].flags & (XCOFF::STYP_DATA | XCOFF::STYP_BSS)) + permissions |= ePermissionsWritable; + if (m_sect_headers[idx].flags & XCOFF::STYP_TEXT) + permissions |= ePermissionsExecutable; + section_sp->SetPermissions(permissions); + + m_sections_up->AddSection(section_sp); + unified_section_list.AddSection(section_sp); + } + } +} + +llvm::StringRef ObjectFileXCOFF::GetSectionName(const section_header_t §) { + llvm::StringRef hdr_name(sect.name, std::size(sect.name)); + hdr_name = hdr_name.split('\0').first; + if (hdr_name.consume_front("/")) { + lldb::offset_t stroff; + if (!to_integer(hdr_name, stroff, 10)) + return ""; + lldb::offset_t string_file_offset = + m_xcoff_header.symoff + (m_xcoff_header.nsyms * static_cast(XCOFF::SymbolTableEntrySize)) + stroff; + if (const char *name = m_data.GetCStr(&string_file_offset)) + return name; + return ""; + } + return hdr_name; +} + +SectionType ObjectFileXCOFF::GetSectionType(llvm::StringRef sect_name, + const section_header_t §) { + if (sect.flags & XCOFF::STYP_TEXT) + return eSectionTypeCode; + if (sect.flags & XCOFF::STYP_DATA) + return eSectionTypeData; + if (sect.flags & XCOFF::STYP_BSS) + return eSectionTypeZeroFill; + if (sect.flags & XCOFF::STYP_DWARF) { + SectionType section_type = + llvm::StringSwitch(sect_name) + .Case(".dwinfo", eSectionTypeDWARFDebugInfo) + .Case(".dwline", eSectionTypeDWARFDebugLine) + .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev) + .Default(eSectionTypeInvalid); + + if (section_type != eSectionTypeInvalid) + return section_type; + } + return eSectionTypeOther; +} + +void ObjectFileXCOFF::Dump(Stream *s) { +} + +ArchSpec ObjectFileXCOFF::GetArchitecture() { + ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + return arch_spec; +} + +UUID ObjectFileXCOFF::GetUUID() { + return UUID(); +} + +std::optional ObjectFileXCOFF::GetDebugLink() { + return std::nullopt; +} + +uint32_t ObjectFileXCOFF::ParseDependentModules() { + ModuleSP module_sp(GetModule()); + if (!module_sp) + return 0; + + std::lock_guard guard(module_sp->GetMutex()); + if (m_deps_filespec) + return m_deps_filespec->GetSize(); + + // Cache coff binary if it is not done yet. + if (!CreateBinary()) + return 0; + + Log *log = GetLog(LLDBLog::Object); + LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}", + this, GetModule().get(), GetModule()->GetSpecificationDescription(), + m_file.GetPath(), m_binary.get()); + + m_deps_filespec = FileSpecList(); + + auto ImportFilesOrError = m_binary->getImportFileTable(); + if (!ImportFilesOrError) { + consumeError(ImportFilesOrError.takeError()); + return 0; + } + +#if 0 + StringRef ImportFileTable = ImportFilesOrError.get(); + const char *CurrentStr = ImportFileTable.data(); + const char *TableEnd = ImportFileTable.end(); + const char *Basename = nullptr; + + for (size_t StrIndex = 0; CurrentStr < TableEnd; + ++StrIndex, CurrentStr += strlen(CurrentStr) + 1) { + if (StrIndex >= 3 && StrIndex % 3 == 1) { + // base_name + llvm::StringRef dll_name(CurrentStr); + Basename = CurrentStr; + + // At this moment we only have the base name of the DLL. The full path can + // only be seen after the dynamic loading. Our best guess is Try to get it + // with the help of the object file's directory. + llvm::SmallString<128> dll_fullpath; + FileSpec dll_specs(dll_name); + // FIXME: hack to get libc.a loaded + if (strcmp(CurrentStr, "libc.a") == 0) { + dll_specs.GetDirectory().SetString("/usr/lib"); + } else { + dll_specs.GetDirectory().SetString(m_file.GetDirectory().GetCString()); + } + + if (!llvm::sys::fs::real_path(dll_specs.GetPath(), dll_fullpath)) + //m_deps_filespec->EmplaceBack(dll_fullpath); + m_deps_filespec->EmplaceBack("/usr/lib/libc.a(shr_64.o)"); + else { + // Known DLLs or DLL not found in the object file directory. + m_deps_filespec->EmplaceBack(dll_name); + } + } else if (StrIndex >= 3 && StrIndex % 3 == 2) { + // archive_member_name + if (strcmp(CurrentStr, "") == 0) { + continue; + } + assert(strcmp(Basename, "") != 0); + std::map>::iterator iter = m_deps_base_members.find(std::string(Basename)); + if (iter == m_deps_base_members.end()) { + m_deps_base_members[std::string(Basename)] = std::vector(); + iter = m_deps_base_members.find(std::string(Basename)); + } + iter->second.push_back(std::string(CurrentStr)); + } + } +#endif + return m_deps_filespec->GetSize(); +} + +uint32_t ObjectFileXCOFF::GetDependentModules(FileSpecList &files) { + auto num_modules = ParseDependentModules(); + auto original_size = files.GetSize(); + + for (unsigned i = 0; i < num_modules; ++i) + files.AppendIfUnique(m_deps_filespec->GetFileSpecAtIndex(i)); + + return files.GetSize() - original_size; +} + +Address ObjectFileXCOFF::GetImageInfoAddress(Target *target) { + return Address(); +} + +lldb_private::Address ObjectFileXCOFF::GetEntryPointAddress() { + if (m_entry_point_address.IsValid()) + return m_entry_point_address; + + if (!ParseHeader() || !IsExecutable()) + return m_entry_point_address; + + SectionList *section_list = GetSectionList(); + addr_t vm_addr = m_xcoff_aux_header.EntryPointAddr; + SectionSP section_sp( + section_list->FindSectionContainingFileAddress(vm_addr)); + if (section_sp) { + lldb::offset_t offset_ptr = section_sp->GetFileOffset() + (vm_addr - section_sp->GetFileAddress()); + vm_addr = m_data.GetU64(&offset_ptr); + } + + if (!section_list) + m_entry_point_address.SetOffset(vm_addr); + else + m_entry_point_address.ResolveAddressUsingFileSections(vm_addr, + section_list); + + return m_entry_point_address; +} + +lldb_private::Address ObjectFileXCOFF::GetBaseAddress() { + return lldb_private::Address(); +} + +ObjectFile::Type ObjectFileXCOFF::CalculateType() { + if (m_xcoff_header.flags & XCOFF::F_EXEC) + return eTypeExecutable; + else if (m_xcoff_header.flags & XCOFF::F_SHROBJ) + return eTypeSharedLibrary; + return eTypeUnknown; +} + +ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { + return eStrataUnknown; +} + +llvm::StringRef +ObjectFileXCOFF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const { + return llvm::StringRef(); +} + +void ObjectFileXCOFF::RelocateSection(lldb_private::Section *section) +{ +} + +std::vector +ObjectFileXCOFF::GetLoadableData(Target &target) { + std::vector loadables; + return loadables; +} + +lldb::WritableDataBufferSP +ObjectFileXCOFF::MapFileDataWritable(const FileSpec &file, uint64_t Size, + uint64_t Offset) { + return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size, + Offset); +} + +ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp, + DataBufferSP data_sp, lldb::offset_t data_offset, + const FileSpec *file, lldb::offset_t file_offset, + lldb::offset_t length) + : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset), + m_xcoff_header(), m_sect_headers(), m_deps_filespec(), m_deps_base_members(), + m_entry_point_address() { + ::memset(&m_xcoff_header, 0, sizeof(m_xcoff_header)); + if (file) + m_file = *file; +} + +ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp, + DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, + addr_t header_addr) + : ObjectFile(module_sp, process_sp, header_addr, header_data_sp), + m_xcoff_header(), m_sect_headers(), m_deps_filespec(), m_deps_base_members(), + m_entry_point_address() { + ::memset(&m_xcoff_header, 0, sizeof(m_xcoff_header)); +} diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h new file mode 100644 index 0000000000000..5a12d16886489 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h @@ -0,0 +1,243 @@ +//===-- ObjectFileXCOFF.h --------------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H + +#include + +#include + +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/UUID.h" +#include "lldb/lldb-private.h" +#include "llvm/Object/XCOFFObjectFile.h" + +/// \class ObjectFileXCOFF +/// Generic XCOFF object file reader. +/// +/// This class provides a generic XCOFF (32/64 bit) reader plugin implementing +/// the ObjectFile protocol. +class ObjectFileXCOFF : public lldb_private::ObjectFile { +public: + // Static Functions + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "xcoff"; } + + static llvm::StringRef GetPluginDescriptionStatic() { + return "XCOFF object file reader."; + } + + static lldb_private::ObjectFile * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length); + + static lldb_private::ObjectFile *CreateMemoryInstance( + const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + + static size_t GetModuleSpecifications(const lldb_private::FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + lldb_private::ModuleSpecList &specs); + + static bool MagicBytesMatch(lldb::DataBufferSP &data_sp, lldb::addr_t offset, + lldb::addr_t length); + + static lldb::SymbolType MapSymbolType(llvm::object::SymbolRef::Type sym_type); + + // PluginInterface protocol + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + // LLVM RTTI support + static char ID; + bool isA(const void *ClassID) const override { + return ClassID == &ID || ObjectFile::isA(ClassID); + } + static bool classof(const ObjectFile *obj) { return obj->isA(&ID); } + + // ObjectFile Protocol. + bool ParseHeader() override; + + bool SetLoadAddress(lldb_private::Target &target, lldb::addr_t value, + bool value_is_offset) override; + + bool SetLoadAddressByType(lldb_private::Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) override; + + lldb::ByteOrder GetByteOrder() const override; + + bool IsExecutable() const override; + + uint32_t GetAddressByteSize() const override; + + lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override; + + void ParseSymtab(lldb_private::Symtab &symtab) override; + + bool IsStripped() override; + + void CreateSections(lldb_private::SectionList &unified_section_list) override; + + void Dump(lldb_private::Stream *s) override; + + lldb_private::ArchSpec GetArchitecture() override; + + lldb_private::UUID GetUUID() override; + + /// Return the contents of the .gnu_debuglink section, if the object file + /// contains it. + std::optional GetDebugLink(); + + uint32_t GetDependentModules(lldb_private::FileSpecList &files) override; + + lldb_private::Address + GetImageInfoAddress(lldb_private::Target *target) override; + + lldb_private::Address GetEntryPointAddress() override; + + lldb_private::Address GetBaseAddress() override; + + ObjectFile::Type CalculateType() override; + + ObjectFile::Strata CalculateStrata() override; + + llvm::StringRef + StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const override; + + void RelocateSection(lldb_private::Section *section) override; + + lldb_private::DataExtractor ReadImageData(uint32_t offset, size_t size); + + ObjectFileXCOFF(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + ObjectFileXCOFF(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + +protected: + + typedef struct xcoff_header { + uint16_t magic; + uint16_t nsects; + uint32_t modtime; + uint64_t symoff; + uint32_t nsyms; + uint16_t auxhdrsize; + uint16_t flags; + } xcoff_header_t; + + typedef struct xcoff_aux_header { + uint16_t AuxMagic; + uint16_t Version; + uint32_t ReservedForDebugger; + uint64_t TextStartAddr; + uint64_t DataStartAddr; + uint64_t TOCAnchorAddr; + uint16_t SecNumOfEntryPoint; + uint16_t SecNumOfText; + uint16_t SecNumOfData; + uint16_t SecNumOfTOC; + uint16_t SecNumOfLoader; + uint16_t SecNumOfBSS; + uint16_t MaxAlignOfText; + uint16_t MaxAlignOfData; + uint16_t ModuleType; + uint8_t CpuFlag; + uint8_t CpuType; + uint8_t TextPageSize; + uint8_t DataPageSize; + uint8_t StackPageSize; + uint8_t FlagAndTDataAlignment; + uint64_t TextSize; + uint64_t InitDataSize; + uint64_t BssDataSize; + uint64_t EntryPointAddr; + uint64_t MaxStackSize; + uint64_t MaxDataSize; + uint16_t SecNumOfTData; + uint16_t SecNumOfTBSS; + uint16_t XCOFF64Flag; + } xcoff_aux_header_t; + + typedef struct section_header { + char name[8]; + uint64_t phyaddr; // Physical Addr + uint64_t vmaddr; // Virtual Addr + uint64_t size; // Section size + uint64_t offset; // File offset to raw data + uint64_t reloff; // Offset to relocations + uint64_t lineoff; // Offset to line table entries + uint32_t nreloc; // Number of relocation entries + uint32_t nline; // Number of line table entries + uint32_t flags; + } section_header_t; + + typedef struct xcoff_symbol { + uint64_t value; + uint32_t offset; + uint16_t sect; + uint16_t type; + uint8_t storage; + uint8_t naux; + } xcoff_symbol_t; + + typedef struct xcoff_sym_csect_aux_entry { + uint32_t section_or_len_low_byte; + uint32_t parameter_hash_index; + uint16_t type_check_sect_num; + uint8_t symbol_alignment_and_type; + uint8_t storage_mapping_class; + uint32_t section_or_len_high_byte; + uint8_t pad; + uint8_t aux_type; + } xcoff_sym_csect_aux_entry_t; + + static bool ParseXCOFFHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + xcoff_header_t &xcoff_header); + bool ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr); + bool ParseSectionHeaders(uint32_t offset); + + std::vector + GetLoadableData(lldb_private::Target &target) override; + + static lldb::WritableDataBufferSP + MapFileDataWritable(const lldb_private::FileSpec &file, uint64_t Size, + uint64_t Offset); + llvm::StringRef GetSectionName(const section_header_t §); + static lldb::SectionType GetSectionType(llvm::StringRef sect_name, + const section_header_t §); + + uint32_t ParseDependentModules(); + typedef std::vector SectionHeaderColl; + +private: + bool CreateBinary(); + + xcoff_header_t m_xcoff_header; + xcoff_aux_header_t m_xcoff_aux_header; + SectionHeaderColl m_sect_headers; + std::unique_ptr m_binary; + lldb_private::Address m_entry_point_address; + std::optional m_deps_filespec; + std::map> m_deps_base_members; +}; + +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H diff --git a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp index e026ffefd645e..106e38b6e25ae 100644 --- a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp +++ b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp @@ -227,7 +227,7 @@ ThreadSP OperatingSystemPython::CreateThreadFromThreadInfo( ThreadList &old_thread_list, std::vector &core_used_map, bool *did_create_ptr) { ThreadSP thread_sp; - tid_t tid = LLDB_INVALID_THREAD_ID; + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; if (!thread_dict.GetValueForKeyAsInteger("tid", tid)) return ThreadSP(); diff --git a/lldb/source/Plugins/Platform/AIX/CMakeLists.txt b/lldb/source/Plugins/Platform/AIX/CMakeLists.txt new file mode 100644 index 0000000000000..85ff0a315eabd --- /dev/null +++ b/lldb/source/Plugins/Platform/AIX/CMakeLists.txt @@ -0,0 +1,13 @@ +add_definitions("-D_ALL_SOURCE") + +add_lldb_library(lldbPluginPlatformAIX PLUGIN + PlatformAIX.cpp + + LINK_LIBS + lldbBreakpoint + lldbCore + lldbHost + lldbInterpreter + lldbTarget + lldbPluginPlatformPOSIX + ) diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp new file mode 100644 index 0000000000000..b6b08b73bec41 --- /dev/null +++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp @@ -0,0 +1,471 @@ +//===-- PlatformAIX.cpp -------------------------------------------------===// +// +// 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 "PlatformAIX.h" +#include "lldb/Host/Config.h" + +#include +#if LLDB_ENABLE_POSIX +#include +#endif + +#include "Utility/ARM64_DWARF_Registers.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/StreamString.h" + +// Define these constants from AIX mman.h for use when targeting remote aix +// systems even when host has different values. + +#if defined(__AIX__) +#include +#endif + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::platform_aix; + +LLDB_PLUGIN_DEFINE(PlatformAIX) + +static uint32_t g_initialize_count = 0; + + +PlatformSP PlatformAIX::CreateInstance(bool force, const ArchSpec *arch) { + Log *log = GetLog(LLDBLog::Platform); + LLDB_LOG(log, "force = {0}, arch=({1}, {2})", force, + arch ? arch->GetArchitectureName() : "", + arch ? arch->GetTriple().getTriple() : ""); + + bool create = force; + if (!create && arch && arch->IsValid()) { + const llvm::Triple &triple = arch->GetTriple(); + switch (triple.getOS()) { + case llvm::Triple::AIX: + create = true; + break; + + default: + break; + } + } + + LLDB_LOG(log, "create = {0}", create); + if (create) { + return PlatformSP(new PlatformAIX(false)); + } + return PlatformSP(); +} + +llvm::StringRef PlatformAIX::GetPluginDescriptionStatic(bool is_host) { + if (is_host) + return "Local AIX user platform plug-in."; + return "Remote AIX user platform plug-in."; +} + +void PlatformAIX::Initialize() { + PlatformPOSIX::Initialize(); + + if (g_initialize_count++ == 0) { +#if defined(__AIX__) + PlatformSP default_platform_sp(new PlatformAIX(true)); + default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); + Platform::SetHostPlatform(default_platform_sp); +#endif + PluginManager::RegisterPlugin( + PlatformAIX::GetPluginNameStatic(false), + PlatformAIX::GetPluginDescriptionStatic(false), + PlatformAIX::CreateInstance, nullptr); + } +} + +void PlatformAIX::Terminate() { + if (g_initialize_count > 0) { + if (--g_initialize_count == 0) { + PluginManager::UnregisterPlugin(PlatformAIX::CreateInstance); + } + } + + PlatformPOSIX::Terminate(); +} + +/// Default Constructor +PlatformAIX::PlatformAIX(bool is_host) + : PlatformPOSIX(is_host) // This is the local host platform +{ + if (is_host) { + ArchSpec hostArch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault); + m_supported_architectures.push_back(hostArch); + if (hostArch.GetTriple().isArch64Bit()) { + m_supported_architectures.push_back( + HostInfo::GetArchitecture(HostInfo::eArchKind32)); + } + } else { + m_supported_architectures = CreateArchList( + {llvm::Triple::x86_64, llvm::Triple::x86, llvm::Triple::arm, + llvm::Triple::aarch64, llvm::Triple::mips64, llvm::Triple::mips64, + llvm::Triple::hexagon, llvm::Triple::mips, llvm::Triple::mips64el, + llvm::Triple::mipsel, llvm::Triple::systemz}, + llvm::Triple::AIX); + } +} + +std::vector +PlatformAIX::GetSupportedArchitectures(const ArchSpec &process_host_arch) { + if (m_remote_platform_sp) + return m_remote_platform_sp->GetSupportedArchitectures(process_host_arch); + return m_supported_architectures; +} + +void PlatformAIX::GetStatus(Stream &strm) { + Platform::GetStatus(strm); + +#if LLDB_ENABLE_POSIX + // Display local kernel information only when we are running in host mode. + // Otherwise, we would end up printing non-AIX information (when running on + // Mac OS for example). + if (IsHost()) { + struct utsname un; + + if (uname(&un)) + return; + + strm.Printf(" Kernel: %s\n", un.sysname); + strm.Printf(" Release: %s\n", un.release); + strm.Printf(" Version: %s\n", un.version); + } +#endif +} + +uint32_t +PlatformAIX::GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) { + uint32_t resume_count = 0; + + // Always resume past the initial stop when we use eLaunchFlagDebug + if (launch_info.GetFlags().Test(eLaunchFlagDebug)) { + // Resume past the stop for the final exec into the true inferior. + ++resume_count; + } + + // If we're not launching a shell, we're done. + const FileSpec &shell = launch_info.GetShell(); + if (!shell) + return resume_count; + + std::string shell_string = shell.GetPath(); + // We're in a shell, so for sure we have to resume past the shell exec. + ++resume_count; + + // Figure out what shell we're planning on using. + const char *shell_name = strrchr(shell_string.c_str(), '/'); + if (shell_name == nullptr) + shell_name = shell_string.c_str(); + else + shell_name++; + + if (strcmp(shell_name, "csh") == 0 || strcmp(shell_name, "tcsh") == 0 || + strcmp(shell_name, "zsh") == 0 || strcmp(shell_name, "sh") == 0) { + // These shells seem to re-exec themselves. Add another resume. + ++resume_count; + } + + return resume_count; +} + +bool PlatformAIX::CanDebugProcess() { + if (IsHost()) { + return true; + } else { + // If we're connected, we can debug. + return IsConnected(); + } +} + +void PlatformAIX::CalculateTrapHandlerSymbolNames() { + m_trap_handlers.push_back(ConstString("_sigtramp")); + m_trap_handlers.push_back(ConstString("__kernel_rt_sigreturn")); + m_trap_handlers.push_back(ConstString("__restore_rt")); +} + +static lldb::UnwindPlanSP GetAArch64TrapHanlderUnwindPlan(ConstString name) { + UnwindPlanSP unwind_plan_sp; + if (name != "__kernel_rt_sigreturn") + return unwind_plan_sp; + + UnwindPlan::RowSP row = std::make_shared(); + row->SetOffset(0); + + // In the signal trampoline frame, sp points to an rt_sigframe[1], which is: + // - 128-byte siginfo struct + // - ucontext struct: + // - 8-byte long (uc_flags) + // - 8-byte pointer (uc_link) + // - 24-byte stack_t + // - 128-byte signal set + // - 8 bytes of padding because sigcontext has 16-byte alignment + // - sigcontext/mcontext_t + // [1] + // https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/signal.c + int32_t offset = 128 + 8 + 8 + 24 + 128 + 8; + // Then sigcontext[2] is: + // - 8 byte fault address + // - 31 8 byte registers + // - 8 byte sp + // - 8 byte pc + // [2] + // https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/sigcontext.h + + // Skip fault address + offset += 8; + row->GetCFAValue().SetIsRegisterPlusOffset(arm64_dwarf::sp, offset); + + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x0, 0 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x1, 1 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x2, 2 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x3, 3 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x4, 4 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x5, 5 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x6, 6 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x7, 7 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x8, 8 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x9, 9 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x10, 10 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x11, 11 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x12, 12 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x13, 13 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x14, 14 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x15, 15 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x16, 16 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x17, 17 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x18, 18 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x19, 19 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x20, 20 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x21, 21 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x22, 22 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x23, 23 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x24, 24 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x25, 25 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x26, 26 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x27, 27 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x28, 28 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::fp, 29 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x30, 30 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::sp, 31 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::pc, 32 * 8, false); + + // The sigcontext may also contain floating point and SVE registers. + // However this would require a dynamic unwind plan so they are not included + // here. + + unwind_plan_sp = std::make_shared(eRegisterKindDWARF); + unwind_plan_sp->AppendRow(row); + unwind_plan_sp->SetSourceName("AArch64 AIX sigcontext"); + unwind_plan_sp->SetSourcedFromCompiler(eLazyBoolYes); + // Because sp is the same throughout the function + unwind_plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolYes); + unwind_plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolYes); + + return unwind_plan_sp; +} + +lldb::UnwindPlanSP +PlatformAIX::GetTrapHandlerUnwindPlan(const llvm::Triple &triple, + ConstString name) { + if (triple.isAArch64()) + return GetAArch64TrapHanlderUnwindPlan(name); + + return {}; +} + +MmapArgList PlatformAIX::GetMmapArgumentList(const ArchSpec &arch, + addr_t addr, addr_t length, + unsigned prot, unsigned flags, + addr_t fd, addr_t offset) { +#if defined(__AIX__) + unsigned flags_platform = MAP_VARIABLE | MAP_PRIVATE | MAP_ANONYMOUS; +#else + unsigned flags_platform = 0; +#endif + MmapArgList args({addr, length, prot, flags_platform, fd, offset}); + return args; +} + +CompilerType PlatformAIX::GetSiginfoType(const llvm::Triple &triple) { + if (!m_type_system_up) + m_type_system_up.reset(new TypeSystemClang("siginfo", triple)); + TypeSystemClang *ast = m_type_system_up.get(); + + bool si_errno_then_code = true; + + switch (triple.getArch()) { + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + // mips has si_code and si_errno swapped + si_errno_then_code = false; + break; + default: + break; + } + + // generic types + CompilerType int_type = ast->GetBasicType(eBasicTypeInt); + CompilerType uint_type = ast->GetBasicType(eBasicTypeUnsignedInt); + CompilerType short_type = ast->GetBasicType(eBasicTypeShort); + CompilerType long_type = ast->GetBasicType(eBasicTypeLong); + CompilerType voidp_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); + + // platform-specific types + CompilerType &pid_type = int_type; + CompilerType &uid_type = uint_type; + CompilerType &clock_type = long_type; + CompilerType &band_type = long_type; + + CompilerType sigval_type = ast->CreateRecordType( + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_sigval_t", + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); + ast->StartTagDeclarationDefinition(sigval_type); + ast->AddFieldToRecordType(sigval_type, "sival_int", int_type, + lldb::eAccessPublic, 0); + ast->AddFieldToRecordType(sigval_type, "sival_ptr", voidp_type, + lldb::eAccessPublic, 0); + ast->CompleteTagDeclarationDefinition(sigval_type); + + CompilerType sigfault_bounds_type = ast->CreateRecordType( + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); + ast->StartTagDeclarationDefinition(sigfault_bounds_type); + ast->AddFieldToRecordType(sigfault_bounds_type, "_addr_bnd", + ast->CreateStructForIdentifier(ConstString(), + { + {"_lower", voidp_type}, + {"_upper", voidp_type}, + }), + lldb::eAccessPublic, 0); + ast->AddFieldToRecordType(sigfault_bounds_type, "_pkey", uint_type, + lldb::eAccessPublic, 0); + ast->CompleteTagDeclarationDefinition(sigfault_bounds_type); + + // siginfo_t + CompilerType siginfo_type = ast->CreateRecordType( + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_siginfo_t", + llvm::to_underlying(clang::TagTypeKind::Struct), lldb::eLanguageTypeC); + ast->StartTagDeclarationDefinition(siginfo_type); + ast->AddFieldToRecordType(siginfo_type, "si_signo", int_type, + lldb::eAccessPublic, 0); + + if (si_errno_then_code) { + ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type, + lldb::eAccessPublic, 0); + ast->AddFieldToRecordType(siginfo_type, "si_code", int_type, + lldb::eAccessPublic, 0); + } else { + ast->AddFieldToRecordType(siginfo_type, "si_code", int_type, + lldb::eAccessPublic, 0); + ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type, + lldb::eAccessPublic, 0); + } + + // the structure is padded on 64-bit arches to fix alignment + if (triple.isArch64Bit()) + ast->AddFieldToRecordType(siginfo_type, "__pad0", int_type, + lldb::eAccessPublic, 0); + + // union used to hold the signal data + CompilerType union_type = ast->CreateRecordType( + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); + ast->StartTagDeclarationDefinition(union_type); + + ast->AddFieldToRecordType( + union_type, "_kill", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_pid", pid_type}, + {"si_uid", uid_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_timer", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_tid", int_type}, + {"si_overrun", int_type}, + {"si_sigval", sigval_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_rt", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_pid", pid_type}, + {"si_uid", uid_type}, + {"si_sigval", sigval_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_sigchld", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_pid", pid_type}, + {"si_uid", uid_type}, + {"si_status", int_type}, + {"si_utime", clock_type}, + {"si_stime", clock_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_sigfault", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_addr", voidp_type}, + {"si_addr_lsb", short_type}, + {"_bounds", sigfault_bounds_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_sigpoll", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_band", band_type}, + {"si_fd", int_type}, + }), + lldb::eAccessPublic, 0); + + // NB: SIGSYS is not present on ia64 but we don't seem to support that + ast->AddFieldToRecordType( + union_type, "_sigsys", + ast->CreateStructForIdentifier(ConstString(), + { + {"_call_addr", voidp_type}, + {"_syscall", int_type}, + {"_arch", uint_type}, + }), + lldb::eAccessPublic, 0); + + ast->CompleteTagDeclarationDefinition(union_type); + ast->AddFieldToRecordType(siginfo_type, "_sifields", union_type, + lldb::eAccessPublic, 0); + + ast->CompleteTagDeclarationDefinition(siginfo_type); + return siginfo_type; +} diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.h b/lldb/source/Plugins/Platform/AIX/PlatformAIX.h new file mode 100644 index 0000000000000..3ae8089a48d71 --- /dev/null +++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.h @@ -0,0 +1,74 @@ +//===-- PlatformAIX.h -----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PLATFORM_AIX_PLATFORMAIX_H +#define LLDB_SOURCE_PLUGINS_PLATFORM_AIX_PLATFORMAIX_H + +#include "Plugins/Platform/POSIX/PlatformPOSIX.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" + +namespace lldb_private { +namespace platform_aix { + +class PlatformAIX : public PlatformPOSIX { +public: + PlatformAIX(bool is_host); + + static void Initialize(); + + static void Terminate(); + + // lldb_private::PluginInterface functions + static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch); + + static llvm::StringRef GetPluginNameStatic(bool is_host) { + return is_host ? Platform::GetHostPlatformName() : "remote-AIX"; + } + + static llvm::StringRef GetPluginDescriptionStatic(bool is_host); + + llvm::StringRef GetPluginName() override { + return GetPluginNameStatic(IsHost()); + } + + // lldb_private::Platform functions + llvm::StringRef GetDescription() override { + return GetPluginDescriptionStatic(IsHost()); + } + + void GetStatus(Stream &strm) override; + + std::vector + GetSupportedArchitectures(const ArchSpec &process_host_arch) override; + + uint32_t GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) override; + + bool CanDebugProcess() override; + + void CalculateTrapHandlerSymbolNames() override; + + lldb::UnwindPlanSP GetTrapHandlerUnwindPlan(const llvm::Triple &triple, + ConstString name) override; + + MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr, + lldb::addr_t length, unsigned prot, + unsigned flags, lldb::addr_t fd, + lldb::addr_t offset) override; + + CompilerType GetSiginfoType(const llvm::Triple &triple) override; + + std::vector m_supported_architectures; + +private: + std::unique_ptr m_type_system_up; +}; + +} // namespace platform_AIX +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_PLATFORM_AIX_PLATFORMAIX_H diff --git a/lldb/source/Plugins/Platform/CMakeLists.txt b/lldb/source/Plugins/Platform/CMakeLists.txt index 6869587f917eb..9d0afd97cff85 100644 --- a/lldb/source/Plugins/Platform/CMakeLists.txt +++ b/lldb/source/Plugins/Platform/CMakeLists.txt @@ -8,3 +8,4 @@ add_subdirectory(OpenBSD) add_subdirectory(POSIX) add_subdirectory(QemuUser) add_subdirectory(Windows) +add_subdirectory(AIX) diff --git a/lldb/source/Plugins/Process/AIX/CMakeLists.txt b/lldb/source/Plugins/Process/AIX/CMakeLists.txt new file mode 100644 index 0000000000000..e9d83266f5857 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/CMakeLists.txt @@ -0,0 +1,19 @@ +add_definitions("-D_ALL_SOURCE") + +add_lldb_library(lldbPluginProcessAIX + NativeProcessAIX.cpp + NativeRegisterContextAIX.cpp + NativeRegisterContextAIX_ppc64.cpp + NativeThreadAIX.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + lldbTarget + lldbUtility + lldbPluginProcessPOSIX + lldbPluginProcessUtility + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp new file mode 100644 index 0000000000000..882f20d30a3bf --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -0,0 +1,2048 @@ +//===-- NativeProcessAIX.cpp --------------------------------------------===// +// +// 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 "NativeProcessAIX.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "NativeThreadAIX.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +//#include "Plugins/Process/Utility/LinuxProcMaps.h" +//#include "Procfs.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/HostProcess.h" +#include "lldb/Host/ProcessLaunchInfo.h" +#include "lldb/Host/PseudoTerminal.h" +#include "lldb/Host/ThreadLauncher.h" +#include "lldb/Host/common/NativeRegisterContext.h" +#include "lldb/Host/aix/Ptrace.h" +//#include "lldb/Host/linux/Host.h" +//#include "lldb/Host/linux/Uio.h" +#include "lldb/Host/posix/ProcessLauncherPosixFork.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/State.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/StringExtractor.h" +#include "llvm/ADT/ScopeExit.h" +#include "llvm/Support/Errno.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Threading.h" + +#include +#include +#include +#include +//#include +#include +#include +#include +#include + +#ifdef __aarch64__ +#include +#include +#endif + +// Support hardware breakpoints in case it has not been defined +#ifndef TRAP_HWBKPT +#define TRAP_HWBKPT 4 +#endif + +#ifndef HWCAP2_MTE +#define HWCAP2_MTE (1 << 18) +#endif + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; +using namespace llvm; + +// Private bits we only need internally. + +static bool ProcessVmReadvSupported() { + static bool is_supported; + static llvm::once_flag flag; + + llvm::call_once(flag, [] { + Log *log = GetLog(POSIXLog::Process); + + uint32_t source = 0x47424742; + uint32_t dest = 0; + + struct iovec local, remote; + remote.iov_base = &source; + local.iov_base = &dest; + remote.iov_len = local.iov_len = sizeof source; + +#if 0 + // We shall try if cross-process-memory reads work by attempting to read a + // value from our own process. + ssize_t res = process_vm_readv(getpid(), &local, 1, &remote, 1, 0); + is_supported = (res == sizeof(source) && source == dest); + if (is_supported) + LLDB_LOG(log, + "Detected kernel support for process_vm_readv syscall. " + "Fast memory reads enabled."); + else + LLDB_LOG(log, + "syscall process_vm_readv failed (error: {0}). Fast memory " + "reads disabled.", + llvm::sys::StrError()); +#endif + }); + + return is_supported; +} + +static void MaybeLogLaunchInfo(const ProcessLaunchInfo &info) { + Log *log = GetLog(POSIXLog::Process); + if (!log) + return; + + if (const FileAction *action = info.GetFileActionForFD(STDIN_FILENO)) + LLDB_LOG(log, "setting STDIN to '{0}'", action->GetFileSpec()); + else + LLDB_LOG(log, "leaving STDIN as is"); + + if (const FileAction *action = info.GetFileActionForFD(STDOUT_FILENO)) + LLDB_LOG(log, "setting STDOUT to '{0}'", action->GetFileSpec()); + else + LLDB_LOG(log, "leaving STDOUT as is"); + + if (const FileAction *action = info.GetFileActionForFD(STDERR_FILENO)) + LLDB_LOG(log, "setting STDERR to '{0}'", action->GetFileSpec()); + else + LLDB_LOG(log, "leaving STDERR as is"); + + int i = 0; + for (const char **args = info.GetArguments().GetConstArgumentVector(); *args; + ++args, ++i) + LLDB_LOG(log, "arg {0}: '{1}'", i, *args); +} + +static void DisplayBytes(StreamString &s, void *bytes, uint32_t count) { + uint8_t *ptr = (uint8_t *)bytes; + const uint32_t loop_count = std::min(DEBUG_PTRACE_MAXBYTES, count); + for (uint32_t i = 0; i < loop_count; i++) { + s.Printf("[%x]", *ptr); + ptr++; + } +} + +static void PtraceDisplayBytes(int &req, void *data, size_t data_size) { + Log *log = GetLog(POSIXLog::Ptrace); + if (!log) + return; + StreamString buf; + + switch (req) { + case PTRACE_POKETEXT: { + DisplayBytes(buf, &data, 8); + LLDB_LOGV(log, "PTRACE_POKETEXT {0}", buf.GetData()); + break; + } + case PTRACE_POKEDATA: { + DisplayBytes(buf, &data, 8); + LLDB_LOGV(log, "PTRACE_POKEDATA {0}", buf.GetData()); + break; + } + case PTRACE_POKEUSER: { + DisplayBytes(buf, &data, 8); + LLDB_LOGV(log, "PTRACE_POKEUSER {0}", buf.GetData()); + break; + } + case PTRACE_SETREGS: { + DisplayBytes(buf, data, data_size); + LLDB_LOGV(log, "PTRACE_SETREGS {0}", buf.GetData()); + break; + } + case PTRACE_SETFPREGS: { + DisplayBytes(buf, data, data_size); + LLDB_LOGV(log, "PTRACE_SETFPREGS {0}", buf.GetData()); + break; + } +#if 0 + case PTRACE_SETSIGINFO: { + DisplayBytes(buf, data, sizeof(siginfo_t)); + LLDB_LOGV(log, "PTRACE_SETSIGINFO {0}", buf.GetData()); + break; + } +#endif + case PTRACE_SETREGSET: { + // Extract iov_base from data, which is a pointer to the struct iovec + DisplayBytes(buf, *(void **)data, data_size); + LLDB_LOGV(log, "PTRACE_SETREGSET {0}", buf.GetData()); + break; + } + default: {} + } +} + +static constexpr unsigned k_ptrace_word_size = sizeof(void *); +static_assert(sizeof(long) >= k_ptrace_word_size, + "Size of long must be larger than ptrace word size"); + +// Simple helper function to ensure flags are enabled on the given file +// descriptor. +static Status EnsureFDFlags(int fd, int flags) { + Status error; + + int status = fcntl(fd, F_GETFL); + if (status == -1) { + error.SetErrorToErrno(); + return error; + } + + if (fcntl(fd, F_SETFL, status | flags) == -1) { + error.SetErrorToErrno(); + return error; + } + + return error; +} + +#if 0 +static llvm::Error AddPtraceScopeNote(llvm::Error original_error) { + Expected ptrace_scope = GetPtraceScope(); + if (auto E = ptrace_scope.takeError()) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "error reading value of ptrace_scope: {0}", E); + + // The original error is probably more interesting than not being able to + // read or interpret ptrace_scope. + return original_error; + } + + // We only have suggestions to provide for 1-3. + switch (*ptrace_scope) { + case 1: + case 2: + return llvm::createStringError( + std::error_code(errno, std::generic_category()), + "The current value of ptrace_scope is %d, which can cause ptrace to " + "fail to attach to a running process. To fix this, run:\n" + "\tsudo sysctl -w kernel.yama.ptrace_scope=0\n" + "For more information, see: " + "https://www.kernel.org/doc/Documentation/security/Yama.txt.", + *ptrace_scope); + case 3: + return llvm::createStringError( + std::error_code(errno, std::generic_category()), + "The current value of ptrace_scope is 3, which will cause ptrace to " + "fail to attach to a running process. This value cannot be changed " + "without rebooting.\n" + "For more information, see: " + "https://www.kernel.org/doc/Documentation/security/Yama.txt."); + case 0: + default: + return original_error; + } +} +#endif + +NativeProcessAIX::Manager::Manager(MainLoop &mainloop) + : NativeProcessProtocol::Manager(mainloop) { + Status status; + m_sigchld_handle = mainloop.RegisterSignal( + SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status); + assert(m_sigchld_handle && status.Success()); +} + +// Public Static Methods + +llvm::Expected> +NativeProcessAIX::Manager::Launch(ProcessLaunchInfo &launch_info, + NativeDelegate &native_delegate) { + Log *log = GetLog(POSIXLog::Process); + + MaybeLogLaunchInfo(launch_info); + + Status status; + ::pid_t pid = ProcessLauncherPosixFork() + .LaunchProcess(launch_info, status) + .GetProcessId(); + LLDB_LOG(log, "pid = {0:x}", pid); + if (status.Fail()) { + LLDB_LOG(log, "failed to launch process: {0}", status); + return status.ToError(); + } + + // Wait for the child process to trap on its call to execve. + int wstatus = 0; + ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0); + assert(wpid == pid); + UNUSED_IF_ASSERT_DISABLED(wpid); + if (!WIFSTOPPED(wstatus)) { + LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}", + WaitStatus::Decode(wstatus)); + return llvm::make_error("Could not sync with inferior process", + llvm::inconvertibleErrorCode()); + } + LLDB_LOG(log, "inferior started, now in stopped state"); + + ProcessInstanceInfo Info; + if (!Host::GetProcessInfo(pid, Info)) { + return llvm::make_error("Cannot get process architectrue", + llvm::inconvertibleErrorCode()); + } + /*llvm::Expected arch_or = + NativeRegisterContextAIX::DetermineArchitecture(pid); + if (!arch_or) + return arch_or.takeError();*/ + + // Set the architecture to the exe architecture. + LLDB_LOG(log, "pid = {0}, detected architecture {1}", pid, + Info.GetArchitecture().GetArchitectureName()); + + return std::unique_ptr(new NativeProcessAIX( + pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate, + Info.GetArchitecture(), *this, {pid})); +} + +llvm::Expected> +NativeProcessAIX::Manager::Attach( + lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "pid = {0:x}", pid); + + ProcessInstanceInfo Info; + if (!Host::GetProcessInfo(pid, Info)) { + return llvm::make_error("Cannot get process architectrue", + llvm::inconvertibleErrorCode()); + } + auto tids_or = NativeProcessAIX::Attach(pid); + if (!tids_or) + return tids_or.takeError(); +#if 0 + ArrayRef<::pid_t> tids = *tids_or; + llvm::Expected arch_or = + NativeRegisterContextAIX::DetermineArchitecture(tids[0]); + if (!arch_or) + return arch_or.takeError(); +#endif + + return std::unique_ptr( + new NativeProcessAIX(pid, -1, native_delegate, Info.GetArchitecture(), *this, *tids_or)); +} + +lldb::addr_t NativeProcessAIX::GetSharedLibraryInfoAddress() { + // punt on this for now + return LLDB_INVALID_ADDRESS; +} + +NativeProcessAIX::Extension +NativeProcessAIX::Manager::GetSupportedExtensions() const { + NativeProcessAIX::Extension supported = + Extension::multiprocess | Extension::fork | Extension::vfork | + Extension::pass_signals | Extension::auxv | Extension::libraries_svr4 | + Extension::siginfo_read; + +#ifdef __aarch64__ + // At this point we do not have a process so read auxv directly. + if ((getauxval(AT_HWCAP2) & HWCAP2_MTE)) + supported |= Extension::memory_tagging; +#endif + + return supported; +} + +static std::optional> WaitPid() { + Log *log = GetLog(POSIXLog::Process); + + int status; + ::pid_t wait_pid = llvm::sys::RetryAfterSignal( + -1, ::waitpid, -1, &status, /*__WALL | __WNOTHREAD |*/ WNOHANG); + + if (wait_pid == 0) + return std::nullopt; + + if (wait_pid == -1) { + Status error(errno, eErrorTypePOSIX); + LLDB_LOG(log, "waitpid(-1, &status, _) failed: {1}", error); + return std::nullopt; + } + + WaitStatus wait_status = WaitStatus::Decode(status); + + LLDB_LOG(log, "waitpid(-1, &status, _) = {0}, status = {1}", wait_pid, + wait_status); + return std::make_pair(wait_pid, wait_status); +} + +void NativeProcessAIX::Manager::SigchldHandler() { + Log *log = GetLog(POSIXLog::Process); + while (true) { + auto wait_result = WaitPid(); + if (!wait_result) + return; + lldb::pid_t pid = wait_result->first; + WaitStatus status = wait_result->second; + + // Ask each process whether it wants to handle the event. Each event should + // be handled by exactly one process, but thread creation events require + // special handling. + // Thread creation consists of two events (one on the parent and one on the + // child thread) and they can arrive in any order nondeterministically. The + // parent event carries the information about the child thread, but not + // vice-versa. This means that if the child event arrives first, it may not + // be handled by any process (because it doesn't know the thread belongs to + // it). + bool handled = llvm::any_of(m_processes, [&](NativeProcessAIX *process) { + return process->TryHandleWaitStatus(pid, status); + }); + if (!handled) { + if (status.type == WaitStatus::Stop && status.status == SIGSTOP) { + // Store the thread creation event for later collection. + m_unowned_threads.insert(pid); + } else { + LLDB_LOG(log, "Ignoring waitpid event {0} for pid {1}", status, pid); + } + } + } +} + +void NativeProcessAIX::Manager::CollectThread(::pid_t tid) { + Log *log = GetLog(POSIXLog::Process); + + if (m_unowned_threads.erase(tid)) + return; // We've encountered this thread already. + + // The TID is not tracked yet, let's wait for it to appear. + int status = -1; + LLDB_LOG(log, + "received clone event for tid {0}. tid not tracked yet, " + "waiting for it to appear...", + tid); + ::pid_t wait_pid = + llvm::sys::RetryAfterSignal(-1, ::waitpid, tid, &status, P_ALL/*__WALL*/); + + // It's theoretically possible to get other events if the entire process was + // SIGKILLed before we got a chance to check this. In that case, we'll just + // clean everything up when we get the process exit event. + + LLDB_LOG(log, + "waitpid({0}, &status, __WALL) => {1} (errno: {2}, status = {3})", + tid, wait_pid, errno, WaitStatus::Decode(status)); +} + +// Public Instance Methods + +NativeProcessAIX::NativeProcessAIX(::pid_t pid, int terminal_fd, + NativeDelegate &delegate, + const ArchSpec &arch, Manager &manager, + llvm::ArrayRef<::pid_t> tids) + : NativeProcessProtocol(pid, terminal_fd, delegate), m_manager(manager), + m_arch(arch) { + manager.AddProcess(*this); + if (m_terminal_fd != -1) { + Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK); + assert(status.Success()); + } + + for (const auto &tid : tids) { + NativeThreadAIX &thread = AddThread(tid, /*resume*/ false); + ThreadWasCreated(thread); + } + + // Let our process instance know the thread has stopped. + SetCurrentThreadID(tids[0]); + SetState(StateType::eStateStopped, false); +} + +llvm::Expected> NativeProcessAIX::Attach(::pid_t pid) { + Log *log = GetLog(POSIXLog::Process); + + Status status; + if ((status = PtraceWrapper(PT_ATTACH, pid)).Fail()) { + return status.ToError(); + } + + int wpid = + llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, nullptr, WNOHANG); + if (wpid <= 0) { + return llvm::errorCodeToError( + std::error_code(errno, std::generic_category())); + } + + LLDB_LOG(log, "adding pid = {0}", pid); + + std::vector<::pid_t> tids; + tids.push_back(pid); + return std::move(tids); +} + +bool NativeProcessAIX::TryHandleWaitStatus(lldb::pid_t pid, + WaitStatus status) { + if (pid == GetID() && + (status.type == WaitStatus::Exit || status.type == WaitStatus::Signal)) { + // The process exited. We're done monitoring. Report to delegate. + SetExitStatus(status, true); + return true; + } + if (NativeThreadAIX *thread = GetThreadByID(pid)) { + MonitorCallback(*thread, status); + return true; + } + return false; +} + +// Handles all waitpid events from the inferior process. +void NativeProcessAIX::MonitorCallback(NativeThreadAIX &thread, + WaitStatus status) { + Log *log = GetLog(LLDBLog::Process); + + // Certain activities differ based on whether the pid is the tid of the main + // thread. + const bool is_main_thread = (thread.GetID() == GetID()); + + // Handle when the thread exits. + if (status.type == WaitStatus::Exit || status.type == WaitStatus::Signal) { + LLDB_LOG(log, + "got exit status({0}) , tid = {1} ({2} main thread), process " + "state = {3}", + status, thread.GetID(), is_main_thread ? "is" : "is not", + GetState()); + + // This is a thread that exited. Ensure we're not tracking it anymore. + StopTrackingThread(thread); + + assert(!is_main_thread && "Main thread exits handled elsewhere"); + return; + } + + int8_t signo = GetSignalInfo(status); + + // Get details on the signal raised. + if (signo) { + // We have retrieved the signal info. Dispatch appropriately. + if (signo == SIGTRAP) + MonitorSIGTRAP(status, thread); + else + MonitorSignal(status, thread); + } else { + assert(0); + } +} + + +void NativeProcessAIX::MonitorSIGTRAP(const WaitStatus status, + NativeThreadAIX &thread) { + Log *log = GetLog(POSIXLog::Process); + const bool is_main_thread = (thread.GetID() == GetID()); + + NativeRegisterContextAIX ®_ctx = thread.GetRegisterContext(); + const RegisterInfo *pc_info = reg_ctx.GetRegisterInfoByName("pc", 0); + RegisterValue pc_value; + + switch (status.status) { + case SIGTRAP: + // Determine the source of SIGTRAP by checking current instruction: + // if that is trap instruction, then this is breakpoint, otherwise + // this is watchpoint. + reg_ctx.ReadRegister(pc_info, pc_value); + + MonitorBreakpoint(thread); + break; + default: + LLDB_LOG(log, "received unknown SIGTRAP stop event ({0}, pid {1} tid {2}", + status.status, GetID(), thread.GetID()); + MonitorSignal(status, thread); + break; + } +} + +void NativeProcessAIX::MonitorTrace(NativeThreadAIX &thread) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "received trace event, pid = {0}", thread.GetID()); + + // This thread is currently stopped. + thread.SetStoppedByTrace(); + + StopRunningThreads(thread.GetID()); +} + +void NativeProcessAIX::MonitorBreakpoint(NativeThreadAIX &thread) { + Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints); + LLDB_LOG(log, "received breakpoint event, pid = {0}", thread.GetID()); + + // Mark the thread as stopped at breakpoint. + thread.SetStoppedByBreakpoint(); + FixupBreakpointPCAsNeeded(thread); + + if (m_threads_stepping_with_breakpoint.find(thread.GetID()) != + m_threads_stepping_with_breakpoint.end()) + thread.SetStoppedByTrace(); + + StopRunningThreads(thread.GetID()); +} + +void NativeProcessAIX::MonitorWatchpoint(NativeThreadAIX &thread, + uint32_t wp_index) { + Log *log = GetLog(LLDBLog::Process | LLDBLog::Watchpoints); + LLDB_LOG(log, "received watchpoint event, pid = {0}, wp_index = {1}", + thread.GetID(), wp_index); + + // Mark the thread as stopped at watchpoint. The address is at + // (lldb::addr_t)info->si_addr if we need it. + thread.SetStoppedByWatchpoint(wp_index); + + // We need to tell all other running threads before we notify the delegate + // about this stop. + StopRunningThreads(thread.GetID()); +} + +void NativeProcessAIX::MonitorSignal(const WaitStatus status, + NativeThreadAIX &thread) { + int8_t signo = GetSignalInfo(status); +#if 0 + const bool is_from_llgs = info.si_pid == getpid(); +#endif + + Log *log = GetLog(POSIXLog::Process); + + // POSIX says that process behaviour is undefined after it ignores a SIGFPE, + // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a kill(2) + // or raise(3). Similarly for tgkill(2) on AIX. + // + // IOW, user generated signals never generate what we consider to be a + // "crash". + // + // Similarly, ACK signals generated by this monitor. + + // Handle the signal. + LLDB_LOG(log, + "received signal {0} ({1}) with code NA, (siginfo pid = {2}, " + "waitpid pid = {3})", + Host::GetSignalAsCString(signo), signo, thread.GetID(), GetID()); + +#if 0 + // Check for thread stop notification. + // FIXME + if (is_from_llgs /*&& (info.si_code == SI_TKILL)*/ && (signo == SIGSTOP)) { + // This is a tgkill()-based stop. + LLDB_LOG(log, "pid {0} tid {1}, thread stopped", GetID(), thread.GetID()); + + // Check that we're not already marked with a stop reason. Note this thread + // really shouldn't already be marked as stopped - if we were, that would + // imply that the kernel signaled us with the thread stopping which we + // handled and marked as stopped, and that, without an intervening resume, + // we received another stop. It is more likely that we are missing the + // marking of a run state somewhere if we find that the thread was marked + // as stopped. + const StateType thread_state = thread.GetState(); + if (!StateIsStoppedState(thread_state, false)) { + // An inferior thread has stopped because of a SIGSTOP we have sent it. + // Generally, these are not important stops and we don't want to report + // them as they are just used to stop other threads when one thread (the + // one with the *real* stop reason) hits a breakpoint (watchpoint, + // etc...). However, in the case of an asynchronous Interrupt(), this + // *is* the real stop reason, so we leave the signal intact if this is + // the thread that was chosen as the triggering thread. + if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID) { + if (m_pending_notification_tid == thread.GetID()) + thread.SetStoppedBySignal(SIGSTOP, &info); + else + thread.SetStoppedWithNoReason(); + + SetCurrentThreadID(thread.GetID()); + SignalIfAllThreadsStopped(); + } else { + // We can end up here if stop was initiated by LLGS but by this time a + // thread stop has occurred - maybe initiated by another event. + Status error = ResumeThread(thread, thread.GetState(), 0); + if (error.Fail()) + LLDB_LOG(log, "failed to resume thread {0}: {1}", thread.GetID(), + error); + } + } else { + LLDB_LOG(log, + "pid {0} tid {1}, thread was already marked as a stopped " + "state (state={2}), leaving stop signal as is", + GetID(), thread.GetID(), thread_state); + SignalIfAllThreadsStopped(); + } + + // Done handling. + return; + } +#endif + + // Check if debugger should stop at this signal or just ignore it and resume + // the inferior. + if (m_signals_to_ignore.contains(signo) || signo == SIGCHLD) { + ResumeThread(thread, thread.GetState(), signo); + return; + } + + // This thread is stopped. + LLDB_LOG(log, "received signal {0}", Host::GetSignalAsCString(signo)); + thread.SetStoppedBySignal(signo); + + // Send a stop to the debugger after we get all other threads to stop. + StopRunningThreads(thread.GetID()); +} + +bool NativeProcessAIX::MonitorClone(NativeThreadAIX &parent, + lldb::pid_t child_pid, int event) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "parent_tid={0}, child_pid={1}, event={2}", parent.GetID(), + child_pid, event); + + // WaitForCloneNotification(child_pid); + + switch (event) { +#if 0 + case PTRACE_EVENT_CLONE: { + // PTRACE_EVENT_CLONE can either mean a new thread or a new process. + // Try to grab the new process' PGID to figure out which one it is. + // If PGID is the same as the PID, then it's a new process. Otherwise, + // it's a thread. + auto tgid_ret = getPIDForTID(child_pid); + if (tgid_ret != child_pid) { + // A new thread should have PGID matching our process' PID. + assert(!tgid_ret || tgid_ret.getValue() == GetID()); + + NativeThreadAIX &child_thread = AddThread(child_pid, /*resume*/ true); + ThreadWasCreated(child_thread); + + // Resume the parent. + ResumeThread(parent, parent.GetState(), LLDB_INVALID_SIGNAL_NUMBER); + break; + } + } + LLVM_FALLTHROUGH; + case PTRACE_EVENT_FORK: + case PTRACE_EVENT_VFORK: { + bool is_vfork = event == PTRACE_EVENT_VFORK; + std::unique_ptr child_process{new NativeProcessAIX( + static_cast<::pid_t>(child_pid), m_terminal_fd, m_delegate, m_arch, + m_main_loop, {static_cast<::pid_t>(child_pid)})}; + if (!is_vfork) + child_process->m_software_breakpoints = m_software_breakpoints; + + Extension expected_ext = is_vfork ? Extension::vfork : Extension::fork; + if (bool(m_enabled_extensions & expected_ext)) { + m_delegate.NewSubprocess(this, std::move(child_process)); + // NB: non-vfork clone() is reported as fork + parent.SetStoppedByFork(is_vfork, child_pid); + StopRunningThreads(parent.GetID()); + } else { + child_process->Detach(); + ResumeThread(parent, parent.GetState(), LLDB_INVALID_SIGNAL_NUMBER); + } + break; + } +#endif + default: + llvm_unreachable("unknown clone_info.event"); + } + + return true; +} + +bool NativeProcessAIX::SupportHardwareSingleStepping() const { + return false; +} + +Status NativeProcessAIX::Resume(const ResumeActionList &resume_actions) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "pid {0}", GetID()); + + bool software_single_step = !SupportHardwareSingleStepping(); + + if (software_single_step) { + for (const auto &thread : m_threads) { + assert(thread && "thread list should not contain NULL threads"); + + const ResumeAction *const action = + resume_actions.GetActionForThread(thread->GetID(), true); + if (action == nullptr) + continue; + + if (action->state == eStateStepping) { + Status error = SetupSoftwareSingleStepping( + static_cast(*thread)); + if (error.Fail()) + return error; + } + } + } + + for (const auto &thread : m_threads) { + assert(thread && "thread list should not contain NULL threads"); + + const ResumeAction *const action = + resume_actions.GetActionForThread(thread->GetID(), true); + + if (action == nullptr) { + LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(), + thread->GetID()); + continue; + } + + LLDB_LOG(log, "processing resume action state {0} for pid {1} tid {2}", + action->state, GetID(), thread->GetID()); + + switch (action->state) { + case eStateRunning: + case eStateStepping: { + // Run the thread, possibly feeding it the signal. + const int signo = action->signal; + Status error = ResumeThread(static_cast(*thread), + action->state, signo); + if (error.Fail()) + return Status("NativeProcessAIX::%s: failed to resume thread " + "for pid %" PRIu64 ", tid %" PRIu64 ", error = %s", + __FUNCTION__, GetID(), thread->GetID(), + error.AsCString()); + + break; + } + + case eStateSuspended: + case eStateStopped: + break; + + default: + return Status("NativeProcessAIX::%s (): unexpected state %s specified " + "for pid %" PRIu64 ", tid %" PRIu64, + __FUNCTION__, StateAsCString(action->state), GetID(), + thread->GetID()); + } + } + + return Status(); +} + +Status NativeProcessAIX::Halt() { + Status error; + + if (kill(GetID(), SIGSTOP) != 0) + error.SetErrorToErrno(); + + return error; +} + +Status NativeProcessAIX::Detach() { + Status error; + + // Tell ptrace to detach from the process. + if (GetID() == LLDB_INVALID_PROCESS_ID) + return error; + + // Cancel out any SIGSTOPs we may have sent while stopping the process. + // Otherwise, the process may stop as soon as we detach from it. + kill(GetID(), SIGCONT); + + for (const auto &thread : m_threads) { + Status e = Detach(thread->GetID()); + if (e.Fail()) + error = + e; // Save the error, but still attempt to detach from other threads. + } + + return error; +} + +Status NativeProcessAIX::Signal(int signo) { + Status error; + + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "sending signal {0} ({1}) to pid {1}", signo, + Host::GetSignalAsCString(signo), GetID()); + + if (kill(GetID(), signo)) + error.SetErrorToErrno(); + + return error; +} + +Status NativeProcessAIX::Interrupt() { + // Pick a running thread (or if none, a not-dead stopped thread) as the + // chosen thread that will be the stop-reason thread. + Log *log = GetLog(POSIXLog::Process); + + NativeThreadProtocol *running_thread = nullptr; + NativeThreadProtocol *stopped_thread = nullptr; + + LLDB_LOG(log, "selecting running thread for interrupt target"); + for (const auto &thread : m_threads) { + // If we have a running or stepping thread, we'll call that the target of + // the interrupt. + const auto thread_state = thread->GetState(); + if (thread_state == eStateRunning || thread_state == eStateStepping) { + running_thread = thread.get(); + break; + } else if (!stopped_thread && StateIsStoppedState(thread_state, true)) { + // Remember the first non-dead stopped thread. We'll use that as a + // backup if there are no running threads. + stopped_thread = thread.get(); + } + } + + if (!running_thread && !stopped_thread) { + Status error("found no running/stepping or live stopped threads as target " + "for interrupt"); + LLDB_LOG(log, "skipping due to error: {0}", error); + + return error; + } + + NativeThreadProtocol *deferred_signal_thread = + running_thread ? running_thread : stopped_thread; + + LLDB_LOG(log, "pid {0} {1} tid {2} chosen for interrupt target", GetID(), + running_thread ? "running" : "stopped", + deferred_signal_thread->GetID()); + + StopRunningThreads(deferred_signal_thread->GetID()); + + return Status(); +} + +Status NativeProcessAIX::Kill() { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "pid {0}", GetID()); + + Status error; + + switch (m_state) { + case StateType::eStateInvalid: + case StateType::eStateExited: + case StateType::eStateCrashed: + case StateType::eStateDetached: + case StateType::eStateUnloaded: + // Nothing to do - the process is already dead. + LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(), + m_state); + return error; + + case StateType::eStateConnected: + case StateType::eStateAttaching: + case StateType::eStateLaunching: + case StateType::eStateStopped: + case StateType::eStateRunning: + case StateType::eStateStepping: + case StateType::eStateSuspended: + // We can try to kill a process in these states. + break; + } + + if (kill(GetID(), SIGKILL) != 0) { + error.SetErrorToErrno(); + return error; + } + + return error; +} + +Status NativeProcessAIX::GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info) { + // FIXME review that the final memory region returned extends to the end of + // the virtual address space, + // with no perms if it is not mapped. + + // Use an approach that reads memory regions from /proc/{pid}/maps. Assume + // proc maps entries are in ascending order. + // FIXME assert if we find differently. + + if (m_supports_mem_region == LazyBool::eLazyBoolNo) { + // We're done. + return Status("unsupported"); + } + + Status error = PopulateMemoryRegionCache(); + if (error.Fail()) { + return error; + } + + lldb::addr_t prev_base_address = 0; + + // FIXME start by finding the last region that is <= target address using + // binary search. Data is sorted. + // There can be a ton of regions on pthreads apps with lots of threads. + for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end(); + ++it) { + MemoryRegionInfo &proc_entry_info = it->first; + + // Sanity check assumption that /proc/{pid}/maps entries are ascending. + assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) && + "descending /proc/pid/maps entries detected, unexpected"); + prev_base_address = proc_entry_info.GetRange().GetRangeBase(); + UNUSED_IF_ASSERT_DISABLED(prev_base_address); + + // If the target address comes before this entry, indicate distance to next + // region. + if (load_addr < proc_entry_info.GetRange().GetRangeBase()) { + range_info.GetRange().SetRangeBase(load_addr); + range_info.GetRange().SetByteSize( + proc_entry_info.GetRange().GetRangeBase() - load_addr); + range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); + + return error; + } else if (proc_entry_info.GetRange().Contains(load_addr)) { + // The target address is within the memory region we're processing here. + range_info = proc_entry_info; + return error; + } + + // The target memory address comes somewhere after the region we just + // parsed. + } + + // If we made it here, we didn't find an entry that contained the given + // address. Return the load_addr as start and the amount of bytes betwwen + // load address and the end of the memory as size. + range_info.GetRange().SetRangeBase(load_addr); + range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS); + range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); + return error; +} + +Status NativeProcessAIX::PopulateMemoryRegionCache() { + Log *log = GetLog(POSIXLog::Process); + + // If our cache is empty, pull the latest. There should always be at least + // one memory region if memory region handling is supported. + if (!m_mem_region_cache.empty()) { + LLDB_LOG(log, "reusing {0} cached memory region entries", + m_mem_region_cache.size()); + return Status(); + } + + Status Result; +#if 0 + AIXMapCallback callback = [&](llvm::Expected Info) { + if (Info) { + FileSpec file_spec(Info->GetName().GetCString()); + FileSystem::Instance().Resolve(file_spec); + m_mem_region_cache.emplace_back(*Info, file_spec); + return true; + } + + Result = Info.takeError(); + m_supports_mem_region = LazyBool::eLazyBoolNo; + LLDB_LOG(log, "failed to parse proc maps: {0}", Result); + return false; + }; + + // AIX kernel since 2.6.14 has /proc/{pid}/smaps + // if CONFIG_PROC_PAGE_MONITOR is enabled + auto BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "smaps"); + if (BufferOrError) + ParseAIXSMapRegions(BufferOrError.get()->getBuffer(), callback); + else { + BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "maps"); + if (!BufferOrError) { + m_supports_mem_region = LazyBool::eLazyBoolNo; + return BufferOrError.getError(); + } + + ParseAIXMapRegions(BufferOrError.get()->getBuffer(), callback); + } + + if (Result.Fail()) + return Result; + + if (m_mem_region_cache.empty()) { + // No entries after attempting to read them. This shouldn't happen if + // /proc/{pid}/maps is supported. Assume we don't support map entries via + // procfs. + m_supports_mem_region = LazyBool::eLazyBoolNo; + LLDB_LOG(log, + "failed to find any procfs maps entries, assuming no support " + "for memory region metadata retrieval"); + return Status("not supported"); + } + + LLDB_LOG(log, "read {0} memory region entries from /proc/{1}/maps", + m_mem_region_cache.size(), GetID()); + + // We support memory retrieval, remember that. + m_supports_mem_region = LazyBool::eLazyBoolYes; +#endif + return Status(); +} + +void NativeProcessAIX::DoStopIDBumped(uint32_t newBumpId) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "newBumpId={0}", newBumpId); + LLDB_LOG(log, "clearing {0} entries from memory region cache", + m_mem_region_cache.size()); + m_mem_region_cache.clear(); +} + +llvm::Expected +NativeProcessAIX::Syscall(llvm::ArrayRef args) { + PopulateMemoryRegionCache(); + auto region_it = llvm::find_if(m_mem_region_cache, [](const auto &pair) { + return pair.first.GetExecutable() == MemoryRegionInfo::eYes && + pair.first.GetShared() != MemoryRegionInfo::eYes; + }); + if (region_it == m_mem_region_cache.end()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "No executable memory region found!"); + + addr_t exe_addr = region_it->first.GetRange().GetRangeBase(); + + NativeThreadAIX &thread = *GetCurrentThread(); + assert(thread.GetState() == eStateStopped); + NativeRegisterContextAIX ®_ctx = thread.GetRegisterContext(); + + NativeRegisterContextAIX::SyscallData syscall_data = + *reg_ctx.GetSyscallData(); + + WritableDataBufferSP registers_sp; + if (llvm::Error Err = reg_ctx.ReadAllRegisterValues(registers_sp).ToError()) + return std::move(Err); + auto restore_regs = llvm::make_scope_exit( + [&] { reg_ctx.WriteAllRegisterValues(registers_sp); }); + + llvm::SmallVector memory(syscall_data.Insn.size()); + size_t bytes_read; + if (llvm::Error Err = + ReadMemory(exe_addr, memory.data(), memory.size(), bytes_read) + .ToError()) { + return std::move(Err); + } + + auto restore_mem = llvm::make_scope_exit( + [&] { WriteMemory(exe_addr, memory.data(), memory.size(), bytes_read); }); + + if (llvm::Error Err = reg_ctx.SetPC(exe_addr).ToError()) + return std::move(Err); + + for (const auto &zip : llvm::zip_first(args, syscall_data.Args)) { + if (llvm::Error Err = + reg_ctx + .WriteRegisterFromUnsigned(std::get<1>(zip), std::get<0>(zip)) + .ToError()) { + return std::move(Err); + } + } + if (llvm::Error Err = WriteMemory(exe_addr, syscall_data.Insn.data(), + syscall_data.Insn.size(), bytes_read) + .ToError()) + return std::move(Err); + + m_mem_region_cache.clear(); + + // With software single stepping the syscall insn buffer must also include a + // trap instruction to stop the process. + int req = SupportHardwareSingleStepping() ? PTRACE_SINGLESTEP : PTRACE_CONT; + if (llvm::Error Err = + PtraceWrapper(req, thread.GetID(), nullptr, nullptr).ToError()) + return std::move(Err); + + //FIXME + int status; + ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, ::waitpid, thread.GetID(), + &status, P_ALL/*__WALL*/); + if (wait_pid == -1) { + return llvm::errorCodeToError( + std::error_code(errno, std::generic_category())); + } + assert((unsigned)wait_pid == thread.GetID()); + + uint64_t result = reg_ctx.ReadRegisterAsUnsigned(syscall_data.Result, -ESRCH); + + // Values larger than this are actually negative errno numbers. + uint64_t errno_threshold = + (uint64_t(-1) >> (64 - 8 * m_arch.GetAddressByteSize())) - 0x1000; + if (result > errno_threshold) { + return llvm::errorCodeToError( + std::error_code(-result & 0xfff, std::generic_category())); + } + + return result; +} + +llvm::Expected +NativeProcessAIX::AllocateMemory(size_t size, uint32_t permissions) { + + std::optional mmap_data = + GetCurrentThread()->GetRegisterContext().GetMmapData(); + if (!mmap_data) + return llvm::make_error(); + + unsigned prot = PROT_NONE; + assert((permissions & (ePermissionsReadable | ePermissionsWritable | + ePermissionsExecutable)) == permissions && + "Unknown permission!"); + if (permissions & ePermissionsReadable) + prot |= PROT_READ; + if (permissions & ePermissionsWritable) + prot |= PROT_WRITE; + if (permissions & ePermissionsExecutable) + prot |= PROT_EXEC; + + llvm::Expected Result = + Syscall({mmap_data->SysMmap, 0, size, prot, MAP_ANONYMOUS | MAP_PRIVATE, + uint64_t(-1), 0}); + if (Result) + m_allocated_memory.try_emplace(*Result, size); + return Result; +} + +llvm::Error NativeProcessAIX::DeallocateMemory(lldb::addr_t addr) { + std::optional mmap_data = + GetCurrentThread()->GetRegisterContext().GetMmapData(); + if (!mmap_data) + return llvm::make_error(); + + auto it = m_allocated_memory.find(addr); + if (it == m_allocated_memory.end()) + return llvm::createStringError(llvm::errc::invalid_argument, + "Memory not allocated by the debugger."); + + llvm::Expected Result = + Syscall({mmap_data->SysMunmap, addr, it->second}); + if (!Result) + return Result.takeError(); + + m_allocated_memory.erase(it); + return llvm::Error::success(); +} + +Status NativeProcessAIX::ReadMemoryTags(int32_t type, lldb::addr_t addr, + size_t len, + std::vector &tags) { + llvm::Expected details = + GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); + if (!details) + return Status(details.takeError()); + + // Ignore 0 length read + if (!len) + return Status(); + + // lldb will align the range it requests but it is not required to by + // the protocol so we'll do it again just in case. + // Remove tag bits too. Ptrace calls may work regardless but that + // is not a guarantee. + MemoryTagManager::TagRange range(details->manager->RemoveTagBits(addr), len); + range = details->manager->ExpandToGranule(range); + + // Allocate enough space for all tags to be read + size_t num_tags = range.GetByteSize() / details->manager->GetGranuleSize(); + tags.resize(num_tags * details->manager->GetTagSizeInBytes()); + + struct iovec tags_iovec; + uint8_t *dest = tags.data(); + lldb::addr_t read_addr = range.GetRangeBase(); + + // This call can return partial data so loop until we error or + // get all tags back. + while (num_tags) { + tags_iovec.iov_base = dest; + tags_iovec.iov_len = num_tags; + + Status error = NativeProcessAIX::PtraceWrapper( + details->ptrace_read_req, GetCurrentThreadID(), + reinterpret_cast(read_addr), static_cast(&tags_iovec), + 0, nullptr); + + if (error.Fail()) { + // Discard partial reads + tags.resize(0); + return error; + } + + size_t tags_read = tags_iovec.iov_len; + assert(tags_read && (tags_read <= num_tags)); + + dest += tags_read * details->manager->GetTagSizeInBytes(); + read_addr += details->manager->GetGranuleSize() * tags_read; + num_tags -= tags_read; + } + + return Status(); +} + +Status NativeProcessAIX::WriteMemoryTags(int32_t type, lldb::addr_t addr, + size_t len, + const std::vector &tags) { + llvm::Expected details = + GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); + if (!details) + return Status(details.takeError()); + + // Ignore 0 length write + if (!len) + return Status(); + + // lldb will align the range it requests but it is not required to by + // the protocol so we'll do it again just in case. + // Remove tag bits too. Ptrace calls may work regardless but that + // is not a guarantee. + MemoryTagManager::TagRange range(details->manager->RemoveTagBits(addr), len); + range = details->manager->ExpandToGranule(range); + + // Not checking number of tags here, we may repeat them below + llvm::Expected> unpacked_tags_or_err = + details->manager->UnpackTagsData(tags); + if (!unpacked_tags_or_err) + return Status(unpacked_tags_or_err.takeError()); + + llvm::Expected> repeated_tags_or_err = + details->manager->RepeatTagsForRange(*unpacked_tags_or_err, range); + if (!repeated_tags_or_err) + return Status(repeated_tags_or_err.takeError()); + + // Repack them for ptrace to use + llvm::Expected> final_tag_data = + details->manager->PackTags(*repeated_tags_or_err); + if (!final_tag_data) + return Status(final_tag_data.takeError()); + + struct iovec tags_vec; + uint8_t *src = final_tag_data->data(); + lldb::addr_t write_addr = range.GetRangeBase(); + // unpacked tags size because the number of bytes per tag might not be 1 + size_t num_tags = repeated_tags_or_err->size(); + + // This call can partially write tags, so we loop until we + // error or all tags have been written. + while (num_tags > 0) { + tags_vec.iov_base = src; + tags_vec.iov_len = num_tags; + + Status error = NativeProcessAIX::PtraceWrapper( + details->ptrace_write_req, GetCurrentThreadID(), + reinterpret_cast(write_addr), static_cast(&tags_vec), 0, + nullptr); + + if (error.Fail()) { + // Don't attempt to restore the original values in the case of a partial + // write + return error; + } + + size_t tags_written = tags_vec.iov_len; + assert(tags_written && (tags_written <= num_tags)); + + src += tags_written * details->manager->GetTagSizeInBytes(); + write_addr += details->manager->GetGranuleSize() * tags_written; + num_tags -= tags_written; + } + + return Status(); +} + +size_t NativeProcessAIX::UpdateThreads() { + // The NativeProcessAIX monitoring threads are always up to date with + // respect to thread state and they keep the thread list populated properly. + // All this method needs to do is return the thread count. + return m_threads.size(); +} + +Status NativeProcessAIX::SetBreakpoint(lldb::addr_t addr, uint32_t size, + bool hardware) { + if (hardware) + return SetHardwareBreakpoint(addr, size); + else + return SetSoftwareBreakpoint(addr, size); +} + +Status NativeProcessAIX::RemoveBreakpoint(lldb::addr_t addr, bool hardware) { + if (hardware) + return RemoveHardwareBreakpoint(addr); + else + return NativeProcessProtocol::RemoveBreakpoint(addr); +} + +llvm::Expected> +NativeProcessAIX::GetSoftwareBreakpointTrapOpcode(size_t size_hint) { + // The ARM reference recommends the use of 0xe7fddefe and 0xdefe but the + // linux kernel does otherwise. + static const uint8_t g_arm_opcode[] = {0xf0, 0x01, 0xf0, 0xe7}; + static const uint8_t g_thumb_opcode[] = {0x01, 0xde}; + + switch (GetArchitecture().GetMachine()) { + case llvm::Triple::arm: + switch (size_hint) { + case 2: + return llvm::ArrayRef(g_thumb_opcode); + case 4: + return llvm::ArrayRef(g_arm_opcode); + default: + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Unrecognised trap opcode size hint!"); + } + default: + return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint); + } +} + +Status NativeProcessAIX::ReadMemory(lldb::addr_t addr, void *buf, size_t size, + size_t &bytes_read) { + unsigned char *dst = static_cast(buf); + size_t remainder; + long data; + + Log *log = GetLog(POSIXLog::Memory); + LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); + + for (bytes_read = 0; bytes_read < size; bytes_read += remainder) { + Status error = NativeProcessAIX::PtraceWrapper( + PT_READ_BLOCK, GetCurrentThreadID(), (void *)addr, nullptr, sizeof(data), &data); + if (error.Fail()) + return error; + + remainder = size - bytes_read; + remainder = remainder > k_ptrace_word_size ? k_ptrace_word_size : remainder; + + // Copy the data into our buffer + memcpy(dst, &data, remainder); + + LLDB_LOG(log, "[{0:x}]:{1:x}", addr, data); + addr += k_ptrace_word_size; + dst += k_ptrace_word_size; + } + return Status(); +} + +Status NativeProcessAIX::WriteMemory(lldb::addr_t addr, const void *buf, + size_t size, size_t &bytes_written) { + const unsigned char *src = static_cast(buf); + size_t remainder; + Status error; + + Log *log = GetLog(POSIXLog::Memory); + LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); + + error = NativeProcessAIX::PtraceWrapper( + PT_WRITE_BLOCK, GetCurrentThreadID(), (void *)addr, nullptr, (int)size, (long *)buf); + if (error.Fail()) + return error; + + bytes_written = size; + return error; +} + +int8_t NativeProcessAIX::GetSignalInfo(WaitStatus wstatus) const { + return wstatus.status; +} + +Status NativeProcessAIX::GetEventMessage(lldb::tid_t tid, + unsigned long *message) { + //FIXME + return PtraceWrapper(PT_CLEAR/*PTRACE_GETEVENTMSG*/, tid, nullptr, message); +} + +Status NativeProcessAIX::Detach(lldb::tid_t tid) { + if (tid == LLDB_INVALID_THREAD_ID) + return Status(); + + return PtraceWrapper(PT_DETACH, tid); +} + +bool NativeProcessAIX::HasThreadNoLock(lldb::tid_t thread_id) { + for (const auto &thread : m_threads) { + assert(thread && "thread list should not contain NULL threads"); + if (thread->GetID() == thread_id) { + // We have this thread. + return true; + } + } + + // We don't have this thread. + return false; +} + +void NativeProcessAIX::StopTrackingThread(NativeThreadAIX &thread) { + Log *const log = GetLog(POSIXLog::Thread); + lldb::tid_t thread_id = thread.GetID(); + LLDB_LOG(log, "tid: {0}", thread_id); + + auto it = llvm::find_if(m_threads, [&](const auto &thread_up) { + return thread_up.get() == &thread; + }); + assert(it != m_threads.end()); + m_threads.erase(it); + + NotifyTracersOfThreadDestroyed(thread_id); + SignalIfAllThreadsStopped(); +} + +void NativeProcessAIX::NotifyTracersProcessDidStop() { +} + +void NativeProcessAIX::NotifyTracersProcessWillResume() { +} + +Status NativeProcessAIX::NotifyTracersOfNewThread(lldb::tid_t tid) { + Log *log = GetLog(POSIXLog::Thread); + Status error; + return error; +} + +Status NativeProcessAIX::NotifyTracersOfThreadDestroyed(lldb::tid_t tid) { + Log *log = GetLog(POSIXLog::Thread); + Status error; + return error; +} + +NativeThreadAIX &NativeProcessAIX::AddThread(lldb::tid_t thread_id, + bool resume) { + Log *log = GetLog(POSIXLog::Thread); + LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id); + + assert(!HasThreadNoLock(thread_id) && + "attempted to add a thread by id that already exists"); + + // If this is the first thread, save it as the current thread + if (m_threads.empty()) + SetCurrentThreadID(thread_id); + + m_threads.push_back(std::make_unique(*this, thread_id)); + NativeThreadAIX &thread = + static_cast(*m_threads.back()); + + Status tracing_error = NotifyTracersOfNewThread(thread.GetID()); + if (tracing_error.Fail()) { + thread.SetStoppedByProcessorTrace(tracing_error.AsCString()); + StopRunningThreads(thread.GetID()); + } else if (resume) + ResumeThread(thread, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); + else + thread.SetStoppedBySignal(SIGSTOP); + + return thread; +} + +Status NativeProcessAIX::GetLoadedModuleFileSpec(const char *module_path, + FileSpec &file_spec) { + Status error = PopulateMemoryRegionCache(); + if (error.Fail()) + return error; + + FileSpec module_file_spec(module_path); + FileSystem::Instance().Resolve(module_file_spec); + + file_spec.Clear(); + for (const auto &it : m_mem_region_cache) { + if (it.second.GetFilename() == module_file_spec.GetFilename()) { + file_spec = it.second; + return Status(); + } + } + return Status("Module file (%s) not found in /proc/%" PRIu64 "/maps file!", + module_file_spec.GetFilename().AsCString(), GetID()); +} + +Status NativeProcessAIX::GetFileLoadAddress(const llvm::StringRef &file_name, + lldb::addr_t &load_addr) { + load_addr = LLDB_INVALID_ADDRESS; + + NativeThreadAIX &thread = *GetCurrentThread(); + NativeRegisterContextAIX ®_ctx = thread.GetRegisterContext(); + + // FIXME: buffer size + struct ld_xinfo info[64]; + if (ptrace64(PT_LDXINFO, reg_ctx.GetThread().GetID(), (long long)&(info[0]), sizeof(info), nullptr) == 0) { + load_addr = (unsigned long)info[0].ldinfo_textorg; + return Status(); + } + return Status("No load address found for specified file."); +} + +NativeThreadAIX *NativeProcessAIX::GetThreadByID(lldb::tid_t tid) { + return static_cast( + NativeProcessProtocol::GetThreadByID(tid)); +} + +NativeThreadAIX *NativeProcessAIX::GetCurrentThread() { + return static_cast( + NativeProcessProtocol::GetCurrentThread()); +} + +Status NativeProcessAIX::ResumeThread(NativeThreadAIX &thread, + lldb::StateType state, int signo) { + Log *const log = GetLog(POSIXLog::Thread); + LLDB_LOG(log, "tid: {0}", thread.GetID()); + + // Before we do the resume below, first check if we have a pending stop + // notification that is currently waiting for all threads to stop. This is + // potentially a buggy situation since we're ostensibly waiting for threads + // to stop before we send out the pending notification, and here we are + // resuming one before we send out the pending stop notification. + if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID) { + LLDB_LOG(log, + "about to resume tid {0} per explicit request but we have a " + "pending stop notification (tid {1}) that is actively " + "waiting for this thread to stop. Valid sequence of events?", + thread.GetID(), m_pending_notification_tid); + } + + // Request a resume. We expect this to be synchronous and the system to + // reflect it is running after this completes. + switch (state) { + case eStateRunning: { + const auto resume_result = thread.Resume(signo); + if (resume_result.Success()) + SetState(eStateRunning, true); + return resume_result; + } + case eStateStepping: { + const auto step_result = thread.SingleStep(signo); + if (step_result.Success()) + SetState(eStateRunning, true); + return step_result; + } + default: + LLDB_LOG(log, "Unhandled state {0}.", state); + llvm_unreachable("Unhandled state for resume"); + } +} + +//===----------------------------------------------------------------------===// + +void NativeProcessAIX::StopRunningThreads(const lldb::tid_t triggering_tid) { + Log *const log = GetLog(POSIXLog::Thread); + LLDB_LOG(log, "about to process event: (triggering_tid: {0})", + triggering_tid); + + m_pending_notification_tid = triggering_tid; + + // Request a stop for all the thread stops that need to be stopped and are + // not already known to be stopped. + for (const auto &thread : m_threads) { + if (StateIsRunningState(thread->GetState())) + static_cast(thread.get())->RequestStop(); + } + + SignalIfAllThreadsStopped(); + LLDB_LOG(log, "event processing done"); +} + +void NativeProcessAIX::SignalIfAllThreadsStopped() { + if (m_pending_notification_tid == LLDB_INVALID_THREAD_ID) + return; // No pending notification. Nothing to do. + + for (const auto &thread_sp : m_threads) { + if (StateIsRunningState(thread_sp->GetState())) + return; // Some threads are still running. Don't signal yet. + } + + // We have a pending notification and all threads have stopped. + Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints); + + // Clear any temporary breakpoints we used to implement software single + // stepping. + for (const auto &thread_info : m_threads_stepping_with_breakpoint) { + Status error = RemoveBreakpoint(thread_info.second); + if (error.Fail()) + LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}", + thread_info.first, error); + } + m_threads_stepping_with_breakpoint.clear(); + + // Notify the delegate about the stop + SetCurrentThreadID(m_pending_notification_tid); + SetState(StateType::eStateStopped, true); + m_pending_notification_tid = LLDB_INVALID_THREAD_ID; +} + +void NativeProcessAIX::ThreadWasCreated(NativeThreadAIX &thread) { + Log *const log = GetLog(POSIXLog::Thread); + LLDB_LOG(log, "tid: {0}", thread.GetID()); + + if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID && + StateIsRunningState(thread.GetState())) { + // We will need to wait for this new thread to stop as well before firing + // the notification. + thread.RequestStop(); + } +} + +#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT +#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h" +#undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT + +static void GetRegister(lldb::pid_t pid, long long addr, void *buf) { + uint64_t val = 0; + ptrace64(PT_READ_GPR, pid, addr, 0, (int *)&val); + *(uint64_t *)buf = llvm::byteswap(val); +} + +static void SetRegister(lldb::pid_t pid, long long addr, void *buf) { + uint64_t val = llvm::byteswap(*(uint64_t *)buf); + ptrace64(PT_WRITE_GPR, pid, addr, 0, (int *)&val); +} + +static void GetFPRegister(lldb::pid_t pid, long long addr, void *buf) { + uint64_t val = 0; + ptrace64(PT_READ_FPR, pid, addr, 0, (int *)&val); + *(uint64_t *)buf = llvm::byteswap(val); +} + +static void GetVMRegister(lldb::tid_t tid, long long addr, void *buf) { + uint64_t val = 0; + ptrace64(PTT_READ_VEC, tid, addr, 0, (int *)&val); + //*(uint64_t *)buf = llvm::byteswap(val); +} + +static void GetVSRegister(lldb::tid_t tid, long long addr, void *buf) { + uint64_t val = 0; + ptrace64(PTT_READ_VSX, tid, addr, 0, (int *)&val); + //*(uint64_t *)buf = llvm::byteswap(val); +} + +// Wrapper for ptrace to catch errors and log calls. Note that ptrace sets +// errno on error because -1 can be a valid result (i.e. for PTRACE_PEEK*) +Status NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid, void *addr, + void *data, size_t data_size, + long *result) { + Status error; + long int ret; + + Log *log = GetLog(POSIXLog::Ptrace); + + PtraceDisplayBytes(req, data, data_size); + + errno = 0; + + // for PTT_* + const char procdir[] = "/proc/"; + const char lwpdir[] = "/lwp/"; + std::string process_task_dir = procdir + std::to_string(pid) + lwpdir; + DIR *dirproc = opendir(process_task_dir.c_str()); + + lldb::tid_t tid = 0; + if (dirproc) { + struct dirent *direntry = nullptr; + while ((direntry = readdir(dirproc)) != nullptr) { + if (strcmp(direntry->d_name, ".") == 0 || strcmp(direntry->d_name, "..") == 0) { + continue; + } + tid = atoi(direntry->d_name); + break; + } + closedir(dirproc); + } + + if (req == PTRACE_GETREGS) { + GetRegister(pid, GPR0, &(((GPR *)data)->r0)); + GetRegister(pid, GPR1, &(((GPR *)data)->r1)); + GetRegister(pid, GPR2, &(((GPR *)data)->r2)); + GetRegister(pid, GPR3, &(((GPR *)data)->r3)); + GetRegister(pid, GPR4, &(((GPR *)data)->r4)); + GetRegister(pid, GPR5, &(((GPR *)data)->r5)); + GetRegister(pid, GPR6, &(((GPR *)data)->r6)); + GetRegister(pid, GPR7, &(((GPR *)data)->r7)); + GetRegister(pid, GPR8, &(((GPR *)data)->r8)); + GetRegister(pid, GPR9, &(((GPR *)data)->r9)); + GetRegister(pid, GPR10, &(((GPR *)data)->r10)); + GetRegister(pid, GPR11, &(((GPR *)data)->r11)); + GetRegister(pid, GPR12, &(((GPR *)data)->r12)); + GetRegister(pid, GPR13, &(((GPR *)data)->r13)); + GetRegister(pid, GPR14, &(((GPR *)data)->r14)); + GetRegister(pid, GPR15, &(((GPR *)data)->r15)); + GetRegister(pid, GPR16, &(((GPR *)data)->r16)); + GetRegister(pid, GPR17, &(((GPR *)data)->r17)); + GetRegister(pid, GPR18, &(((GPR *)data)->r18)); + GetRegister(pid, GPR19, &(((GPR *)data)->r19)); + GetRegister(pid, GPR20, &(((GPR *)data)->r20)); + GetRegister(pid, GPR21, &(((GPR *)data)->r21)); + GetRegister(pid, GPR22, &(((GPR *)data)->r22)); + GetRegister(pid, GPR23, &(((GPR *)data)->r23)); + GetRegister(pid, GPR24, &(((GPR *)data)->r24)); + GetRegister(pid, GPR25, &(((GPR *)data)->r25)); + GetRegister(pid, GPR26, &(((GPR *)data)->r26)); + GetRegister(pid, GPR27, &(((GPR *)data)->r27)); + GetRegister(pid, GPR28, &(((GPR *)data)->r28)); + GetRegister(pid, GPR29, &(((GPR *)data)->r29)); + GetRegister(pid, GPR30, &(((GPR *)data)->r30)); + GetRegister(pid, GPR31, &(((GPR *)data)->r31)); + GetRegister(pid, IAR, &(((GPR *)data)->pc)); + GetRegister(pid, MSR, &(((GPR *)data)->msr)); + //FIXME: origr3/softe/trap on AIX? + GetRegister(pid, CTR, &(((GPR *)data)->ctr)); + GetRegister(pid, LR, &(((GPR *)data)->lr)); + GetRegister(pid, XER, &(((GPR *)data)->xer)); + GetRegister(pid, CR, &(((GPR *)data)->cr)); + } else if (req == PTRACE_SETREGS) { + SetRegister(pid, GPR0, &(((GPR *)data)->r0)); + SetRegister(pid, GPR1, &(((GPR *)data)->r1)); + SetRegister(pid, GPR2, &(((GPR *)data)->r2)); + SetRegister(pid, GPR3, &(((GPR *)data)->r3)); + SetRegister(pid, GPR4, &(((GPR *)data)->r4)); + SetRegister(pid, GPR5, &(((GPR *)data)->r5)); + SetRegister(pid, GPR6, &(((GPR *)data)->r6)); + SetRegister(pid, GPR7, &(((GPR *)data)->r7)); + SetRegister(pid, GPR8, &(((GPR *)data)->r8)); + SetRegister(pid, GPR9, &(((GPR *)data)->r9)); + SetRegister(pid, GPR10, &(((GPR *)data)->r10)); + SetRegister(pid, GPR11, &(((GPR *)data)->r11)); + SetRegister(pid, GPR12, &(((GPR *)data)->r12)); + SetRegister(pid, GPR13, &(((GPR *)data)->r13)); + SetRegister(pid, GPR14, &(((GPR *)data)->r14)); + SetRegister(pid, GPR15, &(((GPR *)data)->r15)); + SetRegister(pid, GPR16, &(((GPR *)data)->r16)); + SetRegister(pid, GPR17, &(((GPR *)data)->r17)); + SetRegister(pid, GPR18, &(((GPR *)data)->r18)); + SetRegister(pid, GPR19, &(((GPR *)data)->r19)); + SetRegister(pid, GPR20, &(((GPR *)data)->r20)); + SetRegister(pid, GPR21, &(((GPR *)data)->r21)); + SetRegister(pid, GPR22, &(((GPR *)data)->r22)); + SetRegister(pid, GPR23, &(((GPR *)data)->r23)); + SetRegister(pid, GPR24, &(((GPR *)data)->r24)); + SetRegister(pid, GPR25, &(((GPR *)data)->r25)); + SetRegister(pid, GPR26, &(((GPR *)data)->r26)); + SetRegister(pid, GPR27, &(((GPR *)data)->r27)); + SetRegister(pid, GPR28, &(((GPR *)data)->r28)); + SetRegister(pid, GPR29, &(((GPR *)data)->r29)); + SetRegister(pid, GPR30, &(((GPR *)data)->r30)); + SetRegister(pid, GPR31, &(((GPR *)data)->r31)); + SetRegister(pid, IAR, &(((GPR *)data)->pc)); + SetRegister(pid, MSR, &(((GPR *)data)->msr)); + //FIXME: origr3/softe/trap on AIX? + SetRegister(pid, CTR, &(((GPR *)data)->ctr)); + SetRegister(pid, LR, &(((GPR *)data)->lr)); + SetRegister(pid, XER, &(((GPR *)data)->xer)); + SetRegister(pid, CR, &(((GPR *)data)->cr)); + } else if (req == PTRACE_GETFPREGS) { + GetFPRegister(pid, FPR0, &(((FPR *)data)->f0)); + GetFPRegister(pid, FPR1, &(((FPR *)data)->f1)); + GetFPRegister(pid, FPR2, &(((FPR *)data)->f2)); + GetFPRegister(pid, FPR3, &(((FPR *)data)->f3)); + GetFPRegister(pid, FPR4, &(((FPR *)data)->f4)); + GetFPRegister(pid, FPR5, &(((FPR *)data)->f5)); + GetFPRegister(pid, FPR6, &(((FPR *)data)->f6)); + GetFPRegister(pid, FPR7, &(((FPR *)data)->f7)); + GetFPRegister(pid, FPR8, &(((FPR *)data)->f8)); + GetFPRegister(pid, FPR9, &(((FPR *)data)->f9)); + GetFPRegister(pid, FPR10, &(((FPR *)data)->f10)); + GetFPRegister(pid, FPR11, &(((FPR *)data)->f11)); + GetFPRegister(pid, FPR12, &(((FPR *)data)->f12)); + GetFPRegister(pid, FPR13, &(((FPR *)data)->f13)); + GetFPRegister(pid, FPR14, &(((FPR *)data)->f14)); + GetFPRegister(pid, FPR15, &(((FPR *)data)->f15)); + GetFPRegister(pid, FPR16, &(((FPR *)data)->f16)); + GetFPRegister(pid, FPR17, &(((FPR *)data)->f17)); + GetFPRegister(pid, FPR18, &(((FPR *)data)->f18)); + GetFPRegister(pid, FPR19, &(((FPR *)data)->f19)); + GetFPRegister(pid, FPR20, &(((FPR *)data)->f20)); + GetFPRegister(pid, FPR21, &(((FPR *)data)->f21)); + GetFPRegister(pid, FPR22, &(((FPR *)data)->f22)); + GetFPRegister(pid, FPR23, &(((FPR *)data)->f23)); + GetFPRegister(pid, FPR24, &(((FPR *)data)->f24)); + GetFPRegister(pid, FPR25, &(((FPR *)data)->f25)); + GetFPRegister(pid, FPR26, &(((FPR *)data)->f26)); + GetFPRegister(pid, FPR27, &(((FPR *)data)->f27)); + GetFPRegister(pid, FPR28, &(((FPR *)data)->f28)); + GetFPRegister(pid, FPR29, &(((FPR *)data)->f29)); + GetFPRegister(pid, FPR30, &(((FPR *)data)->f30)); + GetFPRegister(pid, FPR31, &(((FPR *)data)->f31)); + GetFPRegister(pid, FPSCR, &(((FPR *)data)->fpscr)); + } else if (req == PTRACE_GETVRREGS && tid) { + GetVMRegister(tid, VR0, &(((VMX *)data)->vr0[0])); + GetVMRegister(tid, VR1, &(((VMX *)data)->vr1[0])); + GetVMRegister(tid, VR2, &(((VMX *)data)->vr2[0])); + GetVMRegister(tid, VR3, &(((VMX *)data)->vr3[0])); + GetVMRegister(tid, VR4, &(((VMX *)data)->vr4[0])); + GetVMRegister(tid, VR5, &(((VMX *)data)->vr5[0])); + GetVMRegister(tid, VR6, &(((VMX *)data)->vr6[0])); + GetVMRegister(tid, VR7, &(((VMX *)data)->vr7[0])); + GetVMRegister(tid, VR8, &(((VMX *)data)->vr8[0])); + GetVMRegister(tid, VR9, &(((VMX *)data)->vr9[0])); + GetVMRegister(tid, VR10, &(((VMX *)data)->vr10[0])); + GetVMRegister(tid, VR11, &(((VMX *)data)->vr11[0])); + GetVMRegister(tid, VR12, &(((VMX *)data)->vr12[0])); + GetVMRegister(tid, VR13, &(((VMX *)data)->vr13[0])); + GetVMRegister(tid, VR14, &(((VMX *)data)->vr14[0])); + GetVMRegister(tid, VR15, &(((VMX *)data)->vr15[0])); + GetVMRegister(tid, VR16, &(((VMX *)data)->vr16[0])); + GetVMRegister(tid, VR17, &(((VMX *)data)->vr17[0])); + GetVMRegister(tid, VR18, &(((VMX *)data)->vr18[0])); + GetVMRegister(tid, VR19, &(((VMX *)data)->vr19[0])); + GetVMRegister(tid, VR20, &(((VMX *)data)->vr20[0])); + GetVMRegister(tid, VR21, &(((VMX *)data)->vr21[0])); + GetVMRegister(tid, VR22, &(((VMX *)data)->vr22[0])); + GetVMRegister(tid, VR23, &(((VMX *)data)->vr23[0])); + GetVMRegister(tid, VR24, &(((VMX *)data)->vr24[0])); + GetVMRegister(tid, VR25, &(((VMX *)data)->vr25[0])); + GetVMRegister(tid, VR26, &(((VMX *)data)->vr26[0])); + GetVMRegister(tid, VR27, &(((VMX *)data)->vr27[0])); + GetVMRegister(tid, VR28, &(((VMX *)data)->vr28[0])); + GetVMRegister(tid, VR29, &(((VMX *)data)->vr29[0])); + GetVMRegister(tid, VR30, &(((VMX *)data)->vr30[0])); + GetVMRegister(tid, VR31, &(((VMX *)data)->vr31[0])); + GetVMRegister(tid, VSCR, &(((VMX *)data)->vscr[0])); + GetVMRegister(tid, VRSAVE, &(((VMX *)data)->vrsave)); + } else if (req == PTRACE_GETVSRREGS && tid) { + GetVSRegister(tid, VSR0, &(((VSX *)data)->vs0[0])); + GetVSRegister(tid, VSR1, &(((VSX *)data)->vs1[0])); + GetVSRegister(tid, VSR2, &(((VSX *)data)->vs2[0])); + GetVSRegister(tid, VSR3, &(((VSX *)data)->vs3[0])); + GetVSRegister(tid, VSR4, &(((VSX *)data)->vs4[0])); + GetVSRegister(tid, VSR5, &(((VSX *)data)->vs5[0])); + GetVSRegister(tid, VSR6, &(((VSX *)data)->vs6[0])); + GetVSRegister(tid, VSR7, &(((VSX *)data)->vs7[0])); + GetVSRegister(tid, VSR8, &(((VSX *)data)->vs8[0])); + GetVSRegister(tid, VSR9, &(((VSX *)data)->vs9[0])); + GetVSRegister(tid, VSR10, &(((VSX *)data)->vs10[0])); + GetVSRegister(tid, VSR11, &(((VSX *)data)->vs11[0])); + GetVSRegister(tid, VSR12, &(((VSX *)data)->vs12[0])); + GetVSRegister(tid, VSR13, &(((VSX *)data)->vs13[0])); + GetVSRegister(tid, VSR14, &(((VSX *)data)->vs14[0])); + GetVSRegister(tid, VSR15, &(((VSX *)data)->vs15[0])); + GetVSRegister(tid, VSR16, &(((VSX *)data)->vs16[0])); + GetVSRegister(tid, VSR17, &(((VSX *)data)->vs17[0])); + GetVSRegister(tid, VSR18, &(((VSX *)data)->vs18[0])); + GetVSRegister(tid, VSR19, &(((VSX *)data)->vs19[0])); + GetVSRegister(tid, VSR20, &(((VSX *)data)->vs20[0])); + GetVSRegister(tid, VSR21, &(((VSX *)data)->vs21[0])); + GetVSRegister(tid, VSR22, &(((VSX *)data)->vs22[0])); + GetVSRegister(tid, VSR23, &(((VSX *)data)->vs23[0])); + GetVSRegister(tid, VSR24, &(((VSX *)data)->vs24[0])); + GetVSRegister(tid, VSR25, &(((VSX *)data)->vs25[0])); + GetVSRegister(tid, VSR26, &(((VSX *)data)->vs26[0])); + GetVSRegister(tid, VSR27, &(((VSX *)data)->vs27[0])); + GetVSRegister(tid, VSR28, &(((VSX *)data)->vs28[0])); + GetVSRegister(tid, VSR29, &(((VSX *)data)->vs29[0])); + GetVSRegister(tid, VSR30, &(((VSX *)data)->vs30[0])); + GetVSRegister(tid, VSR31, &(((VSX *)data)->vs31[0])); + GetVSRegister(tid, VSR32, &(((VSX *)data)->vs32[0])); + GetVSRegister(tid, VSR33, &(((VSX *)data)->vs33[0])); + GetVSRegister(tid, VSR34, &(((VSX *)data)->vs34[0])); + GetVSRegister(tid, VSR35, &(((VSX *)data)->vs35[0])); + GetVSRegister(tid, VSR36, &(((VSX *)data)->vs36[0])); + GetVSRegister(tid, VSR37, &(((VSX *)data)->vs37[0])); + GetVSRegister(tid, VSR38, &(((VSX *)data)->vs38[0])); + GetVSRegister(tid, VSR39, &(((VSX *)data)->vs39[0])); + GetVSRegister(tid, VSR40, &(((VSX *)data)->vs40[0])); + GetVSRegister(tid, VSR41, &(((VSX *)data)->vs41[0])); + GetVSRegister(tid, VSR42, &(((VSX *)data)->vs42[0])); + GetVSRegister(tid, VSR43, &(((VSX *)data)->vs43[0])); + GetVSRegister(tid, VSR44, &(((VSX *)data)->vs44[0])); + GetVSRegister(tid, VSR45, &(((VSX *)data)->vs45[0])); + GetVSRegister(tid, VSR46, &(((VSX *)data)->vs46[0])); + GetVSRegister(tid, VSR47, &(((VSX *)data)->vs47[0])); + GetVSRegister(tid, VSR48, &(((VSX *)data)->vs48[0])); + GetVSRegister(tid, VSR49, &(((VSX *)data)->vs49[0])); + GetVSRegister(tid, VSR50, &(((VSX *)data)->vs50[0])); + GetVSRegister(tid, VSR51, &(((VSX *)data)->vs51[0])); + GetVSRegister(tid, VSR52, &(((VSX *)data)->vs52[0])); + GetVSRegister(tid, VSR53, &(((VSX *)data)->vs53[0])); + GetVSRegister(tid, VSR54, &(((VSX *)data)->vs54[0])); + GetVSRegister(tid, VSR55, &(((VSX *)data)->vs55[0])); + GetVSRegister(tid, VSR56, &(((VSX *)data)->vs56[0])); + GetVSRegister(tid, VSR57, &(((VSX *)data)->vs57[0])); + GetVSRegister(tid, VSR58, &(((VSX *)data)->vs58[0])); + GetVSRegister(tid, VSR59, &(((VSX *)data)->vs59[0])); + GetVSRegister(tid, VSR60, &(((VSX *)data)->vs60[0])); + GetVSRegister(tid, VSR61, &(((VSX *)data)->vs61[0])); + GetVSRegister(tid, VSR62, &(((VSX *)data)->vs62[0])); + GetVSRegister(tid, VSR63, &(((VSX *)data)->vs63[0])); + } else if (req < PT_COMMAND_MAX) { + if (req == PT_CONTINUE) { +#if 0 + // Use PTT_CONTINUE + const char procdir[] = "/proc/"; + const char lwpdir[] = "/lwp/"; + std::string process_task_dir = procdir + std::to_string(pid) + lwpdir; + DIR *dirproc = opendir(process_task_dir.c_str()); + + struct ptthreads64 pts; + int idx = 0; + lldb::tid_t tid = 0; + if (dirproc) { + struct dirent *direntry = nullptr; + while ((direntry = readdir(dirproc)) != nullptr) { + if (strcmp(direntry->d_name, ".") == 0 || strcmp(direntry->d_name, "..") == 0) { + continue; + } + tid = atoi(direntry->d_name); + pts.th[idx++] = tid; + } + closedir(dirproc); + } + pts.th[idx] = 0; + ret = ptrace64(PTT_CONTINUE, tid, (long long)1, (int)(size_t)data, (int *)&pts); +#else + int buf; + ptrace64(req, pid, 1, (int)(size_t)data, &buf); +#endif + } else if (req == PT_READ_BLOCK) { + ptrace64(req, pid, (long long)addr, (int)data_size, (int *)result); + } else if (req == PT_WRITE_BLOCK) { + ptrace64(req, pid, (long long)addr, (int)data_size, (int *)result); + } else if (req == PT_ATTACH) { + ptrace64(req, pid, 0, 0, nullptr); + } else if (req == PT_WATCH) { + ptrace64(req, pid, (long long)addr, (int)data_size, nullptr); + } else if (req == PT_DETACH) { + ptrace64(req, pid, 0, 0, nullptr); + } else { + assert(0 && "Not supported yet."); + } + } else { + assert(0 && "Not supported yet."); + } + + if (errno) { + error.SetErrorToErrno(); + ret = -1; + } + + LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3}, {4})={5:x}", req, pid, addr, data, + data_size, ret); + + PtraceDisplayBytes(req, data, data_size); + + if (error.Fail()) + LLDB_LOG(log, "ptrace() failed: {0}", error); + + return error; +} + +llvm::Expected NativeProcessAIX::TraceSupported() { + return NativeProcessProtocol::TraceSupported(); +} + +Error NativeProcessAIX::TraceStart(StringRef json_request, StringRef type) { + return NativeProcessProtocol::TraceStart(json_request, type); +} + +Error NativeProcessAIX::TraceStop(const TraceStopRequest &request) { + return NativeProcessProtocol::TraceStop(request); +} + +Expected NativeProcessAIX::TraceGetState(StringRef type) { + return NativeProcessProtocol::TraceGetState(type); +} + +Expected> NativeProcessAIX::TraceGetBinaryData( + const TraceGetBinaryDataRequest &request) { + return NativeProcessProtocol::TraceGetBinaryData(request); +} diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h new file mode 100644 index 0000000000000..bdb6f7c500885 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h @@ -0,0 +1,283 @@ +//===-- NativeProcessAIX.h ---------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeProcessAIX_H_ +#define liblldb_NativeProcessAIX_H_ + +#include +#include + +#include "lldb/Host/Debug.h" +#include "lldb/Host/HostThread.h" +#include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/lldb-types.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "lldb/Host/aix/Support.h" + +#include "NativeThreadAIX.h" +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h" + +namespace lldb_private { +class Status; +class Scalar; + +namespace process_aix { +/// \class NativeProcessAIX +/// Manages communication with the inferior (debugee) process. +/// +/// Upon construction, this class prepares and launches an inferior process +/// for debugging. +/// +/// Changes in the inferior process state are broadcasted. +class NativeProcessAIX : public NativeProcessProtocol, + private NativeProcessSoftwareSingleStep { +public: + class Manager : public NativeProcessProtocol::Manager { + public: + Manager(MainLoop &mainloop); + + llvm::Expected> + Launch(ProcessLaunchInfo &launch_info, + NativeDelegate &native_delegate) override; + + llvm::Expected> + Attach(lldb::pid_t pid, NativeDelegate &native_delegate) override; + + Extension GetSupportedExtensions() const override; + + void AddProcess(NativeProcessAIX &process) { + m_processes.insert(&process); + } + + void RemoveProcess(NativeProcessAIX &process) { + m_processes.erase(&process); + } + + // Collect an event for the given tid, waiting for it if necessary. + void CollectThread(::pid_t tid); + + private: + MainLoop::SignalHandleUP m_sigchld_handle; + + llvm::SmallPtrSet m_processes; + + // Threads (events) which haven't been claimed by any process. + llvm::DenseSet<::pid_t> m_unowned_threads; + + void SigchldHandler(); + }; + + // NativeProcessProtocol Interface + + ~NativeProcessAIX() override { m_manager.RemoveProcess(*this); } + + Status Resume(const ResumeActionList &resume_actions) override; + + Status Halt() override; + + Status Detach() override; + + Status Signal(int signo) override; + + Status Interrupt() override; + + Status Kill() override; + + lldb::addr_t GetSharedLibraryInfoAddress() override; + + Status GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info) override; + + Status ReadMemory(lldb::addr_t addr, void *buf, size_t size, + size_t &bytes_read) override; + + Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, + size_t &bytes_written) override; + + llvm::Expected AllocateMemory(size_t size, + uint32_t permissions) override; + + llvm::Error DeallocateMemory(lldb::addr_t addr) override; + + Status ReadMemoryTags(int32_t type, lldb::addr_t addr, size_t len, + std::vector &tags) override; + + Status WriteMemoryTags(int32_t type, lldb::addr_t addr, size_t len, + const std::vector &tags) override; + + size_t UpdateThreads() override; + + const ArchSpec &GetArchitecture() const override { return m_arch; } + + Status SetBreakpoint(lldb::addr_t addr, uint32_t size, + bool hardware) override; + + Status RemoveBreakpoint(lldb::addr_t addr, bool hardware = false) override; + + void DoStopIDBumped(uint32_t newBumpId) override; + + Status GetLoadedModuleFileSpec(const char *module_path, + FileSpec &file_spec) override; + + Status GetFileLoadAddress(const llvm::StringRef &file_name, + lldb::addr_t &load_addr) override; + + NativeThreadAIX *GetThreadByID(lldb::tid_t id); + NativeThreadAIX *GetCurrentThread(); + + llvm::ErrorOr> + GetAuxvData() const override { + // Not available on this target. + return llvm::errc::not_supported; + } + + /// Tracing + /// These methods implement the jLLDBTrace packets + /// \{ + llvm::Error TraceStart(llvm::StringRef json_request, + llvm::StringRef type) override; + + llvm::Error TraceStop(const TraceStopRequest &request) override; + + llvm::Expected + TraceGetState(llvm::StringRef type) override; + + llvm::Expected> + TraceGetBinaryData(const TraceGetBinaryDataRequest &request) override; + + llvm::Expected TraceSupported() override; + /// } + + // Interface used by NativeRegisterContext-derived classes. + static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr, + void *data = nullptr, size_t data_size = 0, + long *result = nullptr); + + bool SupportHardwareSingleStepping() const; + + /// Writes a siginfo_t structure corresponding to the given thread ID to the + /// memory region pointed to by \p siginfo. + int8_t GetSignalInfo(WaitStatus wstatus) const; + +protected: + llvm::Expected> + GetSoftwareBreakpointTrapOpcode(size_t size_hint) override; + + llvm::Expected Syscall(llvm::ArrayRef args); + +private: + Manager &m_manager; + /*MainLoop::SignalHandleUP m_sigchld_handle;*/ + ArchSpec m_arch; + /*MainLoop& m_main_loop;*/ + + LazyBool m_supports_mem_region = eLazyBoolCalculate; + std::vector> m_mem_region_cache; + + lldb::tid_t m_pending_notification_tid = LLDB_INVALID_THREAD_ID; + + /// Inferior memory (allocated by us) and its size. + llvm::DenseMap m_allocated_memory; + + // Private Instance Methods + NativeProcessAIX(::pid_t pid, int terminal_fd, NativeDelegate &delegate, + const ArchSpec &arch, Manager &manager, + llvm::ArrayRef<::pid_t> tids); + + // Returns a list of process threads that we have attached to. + static llvm::Expected> Attach(::pid_t pid); + + static Status SetDefaultPtraceOpts(const lldb::pid_t); + + bool TryHandleWaitStatus(lldb::pid_t pid, WaitStatus status); + + void MonitorCallback(NativeThreadAIX &thread, WaitStatus status); + + void MonitorSIGTRAP(const WaitStatus status, NativeThreadAIX &thread); + + void MonitorTrace(NativeThreadAIX &thread); + + void MonitorBreakpoint(NativeThreadAIX &thread); + + void MonitorWatchpoint(NativeThreadAIX &thread, uint32_t wp_index); + + void MonitorSignal(const WaitStatus status, NativeThreadAIX &thread); + + bool HasThreadNoLock(lldb::tid_t thread_id); + + void StopTrackingThread(NativeThreadAIX &thread); + + /// Create a new thread. + /// + /// If process tracing is enabled and the thread can't be traced, then the + /// thread is left stopped with a \a eStopReasonProcessorTrace status, and + /// then the process is stopped. + /// + /// \param[in] resume + /// If a tracing error didn't happen, then resume the thread after + /// creation if \b true, or leave it stopped with SIGSTOP if \b false. + NativeThreadAIX &AddThread(lldb::tid_t thread_id, bool resume); + + /// Start tracing a new thread if process tracing is enabled. + /// + /// Trace mechanisms should modify this method to provide automatic tracing + /// for new threads. + Status NotifyTracersOfNewThread(lldb::tid_t tid); + + /// Stop tracing threads upon a destroy event. + /// + /// Trace mechanisms should modify this method to provide automatic trace + /// stopping for threads being destroyed. + Status NotifyTracersOfThreadDestroyed(lldb::tid_t tid); + + void NotifyTracersProcessWillResume() override; + + void NotifyTracersProcessDidStop() override; + /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG) + /// corresponding to the given thread ID to the memory pointed to by @p + /// message. + Status GetEventMessage(lldb::tid_t tid, unsigned long *message); + + void NotifyThreadDeath(lldb::tid_t tid); + + Status Detach(lldb::tid_t tid); + + // This method is requests a stop on all threads which are still running. It + // sets up a + // deferred delegate notification, which will fire once threads report as + // stopped. The + // triggerring_tid will be set as the current thread (main stop reason). + void StopRunningThreads(lldb::tid_t triggering_tid); + + // Notify the delegate if all threads have stopped. + void SignalIfAllThreadsStopped(); + + // Resume the given thread, optionally passing it the given signal. The type + // of resume + // operation (continue, single-step) depends on the state parameter. + Status ResumeThread(NativeThreadAIX &thread, lldb::StateType state, + int signo); + + void ThreadWasCreated(NativeThreadAIX &thread); + + void SigchldHandler(); + + Status PopulateMemoryRegionCache(); + + // Handle a clone()-like event. + bool MonitorClone(NativeThreadAIX &parent, lldb::pid_t child_pid, + int event); +}; + +} // namespace process_aix +} // namespace lldb_private + +#endif // #ifndef liblldb_NativeProcessAIX_H_ diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp new file mode 100644 index 0000000000000..0859f9501c1b6 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp @@ -0,0 +1,157 @@ +//===-- NativeRegisterContextAIX.cpp ------------------------------------===// +// +// 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 "NativeRegisterContextAIX.h" + +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/Utility/RegisterValue.h" + +#include "Plugins/Process/AIX/NativeProcessAIX.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "lldb/Host/aix/Ptrace.h" + +using namespace lldb_private; +using namespace lldb_private::process_aix; + +lldb::ByteOrder NativeRegisterContextAIX::GetByteOrder() const { + return m_thread.GetProcess().GetByteOrder(); +} + +Status NativeRegisterContextAIX::ReadRegisterRaw(uint32_t reg_index, + RegisterValue ®_value) { + const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); + if (!reg_info) + return Status("register %" PRIu32 " not found", reg_index); + + return DoReadRegisterValue(GetPtraceOffset(reg_index), reg_info->name, + reg_info->byte_size, reg_value); +} + +Status +NativeRegisterContextAIX::WriteRegisterRaw(uint32_t reg_index, + const RegisterValue ®_value) { + uint32_t reg_to_write = reg_index; + RegisterValue value_to_write = reg_value; + + // Check if this is a subregister of a full register. + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index); + if (reg_info->invalidate_regs && + (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) { + Status error; + + RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + error = ReadRegister(full_reg_info, full_value); + if (error.Fail()) + return error; + + lldb::ByteOrder byte_order = GetByteOrder(); + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData( + *full_reg_info, dst, sizeof(dst), byte_order, error); + if (error.Success() && dest_size) { + uint8_t src[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = reg_value.GetAsMemoryData( + *reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) { + // Copy the src bytes to the destination. + memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(*full_reg_info); + reg_to_write = full_reg; + } + } + } + + const RegisterInfo *const register_to_write_info_p = + GetRegisterInfoAtIndex(reg_to_write); + assert(register_to_write_info_p && + "register to write does not have valid RegisterInfo"); + if (!register_to_write_info_p) + return Status("NativeRegisterContextAIX::%s failed to get RegisterInfo " + "for write register index %" PRIu32, + __FUNCTION__, reg_to_write); + + return DoWriteRegisterValue(GetPtraceOffset(reg_index), reg_info->name, + reg_value); +} + +Status NativeRegisterContextAIX::ReadGPR() { + return NativeProcessAIX::PtraceWrapper( + PTRACE_GETREGS, m_thread.GetID(), nullptr, GetGPRBuffer(), GetGPRSize()); +} + +Status NativeRegisterContextAIX::WriteGPR() { + return NativeProcessAIX::PtraceWrapper( + PTRACE_SETREGS, m_thread.GetID(), nullptr, GetGPRBuffer(), GetGPRSize()); +} + +Status NativeRegisterContextAIX::ReadFPR() { + return NativeProcessAIX::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(), + nullptr, GetFPRBuffer(), + GetFPRSize()); +} + +Status NativeRegisterContextAIX::WriteFPR() { + return NativeProcessAIX::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(), + nullptr, GetFPRBuffer(), + GetFPRSize()); +} + +Status NativeRegisterContextAIX::ReadRegisterSet(void *buf, size_t buf_size, + unsigned int regset) { + return NativeProcessAIX::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), + static_cast(®set), buf, + buf_size); +} + +Status NativeRegisterContextAIX::WriteRegisterSet(void *buf, size_t buf_size, + unsigned int regset) { + return NativeProcessAIX::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), + static_cast(®set), buf, + buf_size); +} + +Status NativeRegisterContextAIX::DoReadRegisterValue(uint32_t offset, + const char *reg_name, + uint32_t size, + RegisterValue &value) { + Log *log = GetLog(POSIXLog::Registers); + + long data; + Status error = NativeProcessAIX::PtraceWrapper( + PTRACE_PEEKUSER, m_thread.GetID(), reinterpret_cast(offset), + nullptr, 0, &data); + + if (error.Success()) + // First cast to an unsigned of the same size to avoid sign extension. + value.SetUInt(static_cast(data), size); + + LLDB_LOG(log, "{0}: {1:x}", reg_name, data); + return error; +} + +Status NativeRegisterContextAIX::DoWriteRegisterValue( + uint32_t offset, const char *reg_name, const RegisterValue &value) { + Log *log = GetLog(POSIXLog::Registers); + + void *buf = reinterpret_cast(value.GetAsUInt64()); + LLDB_LOG(log, "{0}: {1}", reg_name, buf); + + return NativeProcessAIX::PtraceWrapper( + PTRACE_POKEUSER, m_thread.GetID(), reinterpret_cast(offset), buf); +} diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h new file mode 100644 index 0000000000000..9c2a326856c0b --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h @@ -0,0 +1,133 @@ +//===-- NativeRegisterContextAIX.h ----------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_NativeRegisterContextAIX_h +#define lldb_NativeRegisterContextAIX_h + +#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h" +#include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/Target/MemoryTagManager.h" +#include "llvm/Support/Error.h" + +namespace lldb_private { +namespace process_aix { + +class NativeThreadAIX; + +class NativeRegisterContextAIX + : public virtual NativeRegisterContextRegisterInfo { +public: + // This function is implemented in the NativeRegisterContextAIX_* subclasses + // to create a new instance of the host specific NativeRegisterContextAIX. + // The implementations can't collide as only one NativeRegisterContextAIX_* + // variant should be compiled into the final executable. + static std::unique_ptr + CreateHostNativeRegisterContextAIX(const ArchSpec &target_arch, + NativeThreadAIX &native_thread); + + // Invalidates cached values in register context data structures + virtual void InvalidateAllRegisters(){} + + struct SyscallData { + /// The syscall instruction. If the architecture uses software + /// single-stepping, the instruction should also be followed by a trap to + /// ensure the process is stopped after the syscall. + llvm::ArrayRef Insn; + + /// Registers used for syscall arguments. The first register is used to + /// store the syscall number. + llvm::ArrayRef Args; + + uint32_t Result; ///< Register containing the syscall result. + }; + /// Return architecture-specific data needed to make inferior syscalls, if + /// they are supported. + virtual std::optional GetSyscallData() { return std::nullopt; } + + struct MmapData { + // Syscall numbers can be found (e.g.) in /usr/include/asm/unistd.h for the + // relevant architecture. + unsigned SysMmap; ///< mmap syscall number. + unsigned SysMunmap; ///< munmap syscall number + }; + /// Return the architecture-specific data needed to make mmap syscalls, if + /// they are supported. + virtual std::optional GetMmapData() { return std::nullopt; } + + struct MemoryTaggingDetails { + /// Object with tag handling utilities. If the function below returns + /// a valid structure, you can assume that this pointer is valid. + std::unique_ptr manager; + int ptrace_read_req; /// ptrace operation number for memory tag read + int ptrace_write_req; /// ptrace operation number for memory tag write + }; + /// Return architecture specific data needed to use memory tags, + /// if they are supported. + virtual llvm::Expected + GetMemoryTaggingDetails(int32_t type) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Architecture does not support memory tagging"); + } + +protected: + // NB: This constructor is here only because gcc<=6.5 requires a virtual base + // class initializer on abstract class (even though it is never used). It can + // be deleted once we move to gcc>=7.0. + NativeRegisterContextAIX(NativeThreadProtocol &thread) + : NativeRegisterContextRegisterInfo(thread, nullptr) {} + + lldb::ByteOrder GetByteOrder() const; + + virtual Status ReadRegisterRaw(uint32_t reg_index, RegisterValue ®_value); + + virtual Status WriteRegisterRaw(uint32_t reg_index, + const RegisterValue ®_value); + + virtual Status ReadRegisterSet(void *buf, size_t buf_size, + unsigned int regset); + + virtual Status WriteRegisterSet(void *buf, size_t buf_size, + unsigned int regset); + + virtual Status ReadGPR(); + + virtual Status WriteGPR(); + + virtual Status ReadFPR(); + + virtual Status WriteFPR(); + + virtual void *GetGPRBuffer() = 0; + + virtual size_t GetGPRSize() const { + return GetRegisterInfoInterface().GetGPRSize(); + } + + virtual void *GetFPRBuffer() = 0; + + virtual size_t GetFPRSize() = 0; + + virtual uint32_t GetPtraceOffset(uint32_t reg_index) { + return GetRegisterInfoAtIndex(reg_index)->byte_offset; + } + + // The Do*** functions are executed on the privileged thread and can perform + // ptrace + // operations directly. + virtual Status DoReadRegisterValue(uint32_t offset, const char *reg_name, + uint32_t size, RegisterValue &value); + + virtual Status DoWriteRegisterValue(uint32_t offset, const char *reg_name, + const RegisterValue &value); +}; + +} // namespace process_aix +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextAIX_h diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp new file mode 100644 index 0000000000000..1996373791748 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp @@ -0,0 +1,744 @@ +//===-- NativeRegisterContextAIX_ppc64.cpp ----------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// This implementation is related to the OpenPOWER ABI for Power Architecture +// 64-bit ELF V2 ABI + +#if defined(__powerpc64__) + +#include "NativeRegisterContextAIX_ppc64.h" + +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Status.h" +#include "lldb/Host/aix/Ptrace.h" + +#include "Plugins/Process/AIX/NativeProcessAIX.h" +#include "Plugins/Process/Linux/Procfs.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h" + +// System includes - They have to be included after framework includes because +// they define some macros which collide with variable names in other modules +#include +#include +#include +#include + +#define REG_CONTEXT_SIZE \ + (GetGPRSize() + GetFPRSize() + sizeof(m_vmx_ppc64le) + sizeof(m_vsx_ppc64le)) +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; + +static const uint32_t g_gpr_regnums_ppc64le[] = { + gpr_r0_ppc64le, gpr_r1_ppc64le, gpr_r2_ppc64le, gpr_r3_ppc64le, + gpr_r4_ppc64le, gpr_r5_ppc64le, gpr_r6_ppc64le, gpr_r7_ppc64le, + gpr_r8_ppc64le, gpr_r9_ppc64le, gpr_r10_ppc64le, gpr_r11_ppc64le, + gpr_r12_ppc64le, gpr_r13_ppc64le, gpr_r14_ppc64le, gpr_r15_ppc64le, + gpr_r16_ppc64le, gpr_r17_ppc64le, gpr_r18_ppc64le, gpr_r19_ppc64le, + gpr_r20_ppc64le, gpr_r21_ppc64le, gpr_r22_ppc64le, gpr_r23_ppc64le, + gpr_r24_ppc64le, gpr_r25_ppc64le, gpr_r26_ppc64le, gpr_r27_ppc64le, + gpr_r28_ppc64le, gpr_r29_ppc64le, gpr_r30_ppc64le, gpr_r31_ppc64le, + gpr_pc_ppc64le, gpr_msr_ppc64le, gpr_origr3_ppc64le, gpr_ctr_ppc64le, + gpr_lr_ppc64le, gpr_xer_ppc64le, gpr_cr_ppc64le, gpr_softe_ppc64le, + gpr_trap_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +static const uint32_t g_fpr_regnums_ppc64le[] = { + fpr_f0_ppc64le, fpr_f1_ppc64le, fpr_f2_ppc64le, fpr_f3_ppc64le, + fpr_f4_ppc64le, fpr_f5_ppc64le, fpr_f6_ppc64le, fpr_f7_ppc64le, + fpr_f8_ppc64le, fpr_f9_ppc64le, fpr_f10_ppc64le, fpr_f11_ppc64le, + fpr_f12_ppc64le, fpr_f13_ppc64le, fpr_f14_ppc64le, fpr_f15_ppc64le, + fpr_f16_ppc64le, fpr_f17_ppc64le, fpr_f18_ppc64le, fpr_f19_ppc64le, + fpr_f20_ppc64le, fpr_f21_ppc64le, fpr_f22_ppc64le, fpr_f23_ppc64le, + fpr_f24_ppc64le, fpr_f25_ppc64le, fpr_f26_ppc64le, fpr_f27_ppc64le, + fpr_f28_ppc64le, fpr_f29_ppc64le, fpr_f30_ppc64le, fpr_f31_ppc64le, + fpr_fpscr_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +static const uint32_t g_vmx_regnums_ppc64le[] = { + vmx_vr0_ppc64le, vmx_vr1_ppc64le, vmx_vr2_ppc64le, vmx_vr3_ppc64le, + vmx_vr4_ppc64le, vmx_vr5_ppc64le, vmx_vr6_ppc64le, vmx_vr7_ppc64le, + vmx_vr8_ppc64le, vmx_vr9_ppc64le, vmx_vr10_ppc64le, vmx_vr11_ppc64le, + vmx_vr12_ppc64le, vmx_vr13_ppc64le, vmx_vr14_ppc64le, vmx_vr15_ppc64le, + vmx_vr16_ppc64le, vmx_vr17_ppc64le, vmx_vr18_ppc64le, vmx_vr19_ppc64le, + vmx_vr20_ppc64le, vmx_vr21_ppc64le, vmx_vr22_ppc64le, vmx_vr23_ppc64le, + vmx_vr24_ppc64le, vmx_vr25_ppc64le, vmx_vr26_ppc64le, vmx_vr27_ppc64le, + vmx_vr28_ppc64le, vmx_vr29_ppc64le, vmx_vr30_ppc64le, vmx_vr31_ppc64le, + vmx_vscr_ppc64le, vmx_vrsave_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +static const uint32_t g_vsx_regnums_ppc64le[] = { + vsx_vs0_ppc64le, vsx_vs1_ppc64le, vsx_vs2_ppc64le, vsx_vs3_ppc64le, + vsx_vs4_ppc64le, vsx_vs5_ppc64le, vsx_vs6_ppc64le, vsx_vs7_ppc64le, + vsx_vs8_ppc64le, vsx_vs9_ppc64le, vsx_vs10_ppc64le, vsx_vs11_ppc64le, + vsx_vs12_ppc64le, vsx_vs13_ppc64le, vsx_vs14_ppc64le, vsx_vs15_ppc64le, + vsx_vs16_ppc64le, vsx_vs17_ppc64le, vsx_vs18_ppc64le, vsx_vs19_ppc64le, + vsx_vs20_ppc64le, vsx_vs21_ppc64le, vsx_vs22_ppc64le, vsx_vs23_ppc64le, + vsx_vs24_ppc64le, vsx_vs25_ppc64le, vsx_vs26_ppc64le, vsx_vs27_ppc64le, + vsx_vs28_ppc64le, vsx_vs29_ppc64le, vsx_vs30_ppc64le, vsx_vs31_ppc64le, + vsx_vs32_ppc64le, vsx_vs33_ppc64le, vsx_vs34_ppc64le, vsx_vs35_ppc64le, + vsx_vs36_ppc64le, vsx_vs37_ppc64le, vsx_vs38_ppc64le, vsx_vs39_ppc64le, + vsx_vs40_ppc64le, vsx_vs41_ppc64le, vsx_vs42_ppc64le, vsx_vs43_ppc64le, + vsx_vs44_ppc64le, vsx_vs45_ppc64le, vsx_vs46_ppc64le, vsx_vs47_ppc64le, + vsx_vs48_ppc64le, vsx_vs49_ppc64le, vsx_vs50_ppc64le, vsx_vs51_ppc64le, + vsx_vs52_ppc64le, vsx_vs53_ppc64le, vsx_vs54_ppc64le, vsx_vs55_ppc64le, + vsx_vs56_ppc64le, vsx_vs57_ppc64le, vsx_vs58_ppc64le, vsx_vs59_ppc64le, + vsx_vs60_ppc64le, vsx_vs61_ppc64le, vsx_vs62_ppc64le, vsx_vs63_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +// Number of register sets provided by this context. +static constexpr int k_num_register_sets = 4; + +static const RegisterSet g_reg_sets_ppc64le[k_num_register_sets] = { + {"General Purpose Registers", "gpr", k_num_gpr_registers_ppc64le, + g_gpr_regnums_ppc64le}, + {"Floating Point Registers", "fpr", k_num_fpr_registers_ppc64le, + g_fpr_regnums_ppc64le}, + {"AltiVec/VMX Registers", "vmx", k_num_vmx_registers_ppc64le, + g_vmx_regnums_ppc64le}, + {"VSX Registers", "vsx", k_num_vsx_registers_ppc64le, + g_vsx_regnums_ppc64le}, +}; + +std::unique_ptr +NativeRegisterContextAIX::CreateHostNativeRegisterContextAIX( + const ArchSpec &target_arch, NativeThreadAIX &native_thread) { + switch (target_arch.GetMachine()) { + case llvm::Triple::ppc64: + return std::make_unique(target_arch, + native_thread); + default: + llvm_unreachable("have no register context for architecture"); + } +} + +NativeRegisterContextAIX_ppc64::NativeRegisterContextAIX_ppc64( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + : NativeRegisterContextRegisterInfo( + native_thread, new RegisterInfoPOSIX_ppc64le(target_arch)), + NativeRegisterContextAIX(native_thread) { + if (target_arch.GetMachine() != llvm::Triple::ppc64) { + llvm_unreachable("Unhandled target architecture."); + } + + ::memset(&m_gpr_ppc64le, 0, sizeof(m_gpr_ppc64le)); + ::memset(&m_fpr_ppc64le, 0, sizeof(m_fpr_ppc64le)); + ::memset(&m_vmx_ppc64le, 0, sizeof(m_vmx_ppc64le)); + ::memset(&m_vsx_ppc64le, 0, sizeof(m_vsx_ppc64le)); + ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); +} + +uint32_t NativeRegisterContextAIX_ppc64::GetRegisterSetCount() const { + return k_num_register_sets; +} + +const RegisterSet * +NativeRegisterContextAIX_ppc64::GetRegisterSet(uint32_t set_index) const { + if (set_index < k_num_register_sets) + return &g_reg_sets_ppc64le[set_index]; + + return nullptr; +} + +uint32_t NativeRegisterContextAIX_ppc64::GetUserRegisterCount() const { + uint32_t count = 0; + for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) + count += g_reg_sets_ppc64le[set_index].num_registers; + return count; +} + +Status NativeRegisterContextAIX_ppc64::ReadRegister( + const RegisterInfo *reg_info, RegisterValue ®_value) { + Status error; + + if (!reg_info) { + error.SetErrorString("reg_info NULL"); + return error; + } + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (IsFPR(reg)) { + error = ReadFPR(); + if (error.Fail()) + return error; + + // Get pointer to m_fpr_ppc64le variable and set the data from it. + uint32_t fpr_offset = CalculateFprOffset(reg_info); + assert(fpr_offset < sizeof m_fpr_ppc64le); + uint8_t *src = (uint8_t *)&m_fpr_ppc64le + fpr_offset; + reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } else if (IsVSX(reg)) { + uint32_t vsx_offset = CalculateVsxOffset(reg_info); + assert(vsx_offset < sizeof(m_vsx_ppc64le)); + + if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) { + error = ReadVSX(); + if (error.Fail()) + return error; + + error = ReadFPR(); + if (error.Fail()) + return error; + + uint64_t value[2]; + uint8_t *dst, *src; + dst = (uint8_t *)&value; + src = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + dst += 8; + src = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + reg_value.SetFromMemoryData(*reg_info, &value, reg_info->byte_size, + eByteOrderLittle, error); + } else { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data from it. + uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2; + uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } + } else if (IsVMX(reg)) { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data from it. + uint32_t vmx_offset = CalculateVmxOffset(reg_info); + assert(vmx_offset < sizeof m_vmx_ppc64le); + uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } else if (IsGPR(reg)) { + error = ReadGPR(); + if (error.Fail()) + return error; + + uint8_t *src = (uint8_t *) &m_gpr_ppc64le + reg_info->byte_offset; + reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } else { + return Status("failed - register wasn't recognized to be a GPR, FPR, VSX " + "or VMX, read strategy unknown"); + } + + return error; +} + +Status NativeRegisterContextAIX_ppc64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue ®_value) { + Status error; + if (!reg_info) + return Status("reg_info NULL"); + + const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; + if (reg_index == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : ""); + + if (IsGPR(reg_index)) { + error = ReadGPR(); + if (error.Fail()) + return error; + + uint8_t *dst = (uint8_t *)&m_gpr_ppc64le + reg_info->byte_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + *(uint64_t *)dst = llvm::byteswap(*(uint64_t *)dst); + + error = WriteGPR(); + if (error.Fail()) + return error; + + return Status(); + } + + if (IsFPR(reg_index)) { + error = ReadFPR(); + if (error.Fail()) + return error; + + // Get pointer to m_fpr_ppc64le variable and set the data to it. + uint32_t fpr_offset = CalculateFprOffset(reg_info); + assert(fpr_offset < GetFPRSize()); + uint8_t *dst = (uint8_t *)&m_fpr_ppc64le + fpr_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + + error = WriteFPR(); + if (error.Fail()) + return error; + + return Status(); + } + + if (IsVMX(reg_index)) { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data to it. + uint32_t vmx_offset = CalculateVmxOffset(reg_info); + assert(vmx_offset < sizeof(m_vmx_ppc64le)); + uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + + error = WriteVMX(); + if (error.Fail()) + return error; + + return Status(); + } + + if (IsVSX(reg_index)) { + uint32_t vsx_offset = CalculateVsxOffset(reg_info); + assert(vsx_offset < sizeof(m_vsx_ppc64le)); + + if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) { + error = ReadVSX(); + if (error.Fail()) + return error; + + error = ReadFPR(); + if (error.Fail()) + return error; + + uint64_t value[2]; + ::memcpy(value, reg_value.GetBytes(), 16); + uint8_t *dst, *src; + src = (uint8_t *)value; + dst = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + src += 8; + dst = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + + WriteVSX(); + WriteFPR(); + } else { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data from it. + uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2; + uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + WriteVMX(); + } + + return Status(); + } + + return Status("failed - register wasn't recognized to be a GPR, FPR, VSX " + "or VMX, write strategy unknown"); +} + +Status NativeRegisterContextAIX_ppc64::ReadAllRegisterValues( + lldb::WritableDataBufferSP &data_sp) { + Status error; + + data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); + error = ReadGPR(); + if (error.Fail()) + return error; + + error = ReadFPR(); + if (error.Fail()) + return error; + + error = ReadVMX(); + if (error.Fail()) + return error; + + error = ReadVSX(); + if (error.Fail()) + return error; + + uint8_t *dst = data_sp->GetBytes(); + ::memcpy(dst, &m_gpr_ppc64le, GetGPRSize()); + dst += GetGPRSize(); + ::memcpy(dst, &m_fpr_ppc64le, GetFPRSize()); + dst += GetFPRSize(); + ::memcpy(dst, &m_vmx_ppc64le, sizeof(m_vmx_ppc64le)); + dst += sizeof(m_vmx_ppc64le); + ::memcpy(dst, &m_vsx_ppc64le, sizeof(m_vsx_ppc64le)); + + return error; +} + +Status NativeRegisterContextAIX_ppc64::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + Status error; + + if (!data_sp) { + error.SetErrorStringWithFormat( + "NativeRegisterContextAIX_ppc64::%s invalid data_sp provided", + __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { + error.SetErrorStringWithFormat( + "NativeRegisterContextAIX_ppc64::%s data_sp contained mismatched " + "data size, expected %" PRIu64 ", actual %" PRIu64, + __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); + return error; + } + + const uint8_t *src = data_sp->GetBytes(); + if (src == nullptr) { + error.SetErrorStringWithFormat("NativeRegisterContextAIX_ppc64::%s " + "DataBuffer::GetBytes() returned a null " + "pointer", + __FUNCTION__); + return error; + } + + ::memcpy(&m_gpr_ppc64le, src, GetGPRSize()); + error = WriteGPR(); + + if (error.Fail()) + return error; + + src += GetGPRSize(); + ::memcpy(&m_fpr_ppc64le, src, GetFPRSize()); + + error = WriteFPR(); + if (error.Fail()) + return error; + + src += GetFPRSize(); + ::memcpy(&m_vmx_ppc64le, src, sizeof(m_vmx_ppc64le)); + + error = WriteVMX(); + if (error.Fail()) + return error; + + src += sizeof(m_vmx_ppc64le); + ::memcpy(&m_vsx_ppc64le, src, sizeof(m_vsx_ppc64le)); + error = WriteVSX(); + + return error; +} + +bool NativeRegisterContextAIX_ppc64::IsGPR(unsigned reg) const { + return reg <= k_last_gpr_ppc64le; // GPR's come first. +} + +bool NativeRegisterContextAIX_ppc64::IsFPR(unsigned reg) const { + return (k_first_fpr_ppc64le <= reg && reg <= k_last_fpr_ppc64le); +} + +uint32_t NativeRegisterContextAIX_ppc64::CalculateFprOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - + GetRegisterInfoAtIndex(k_first_fpr_ppc64le)->byte_offset; +} + +uint32_t NativeRegisterContextAIX_ppc64::CalculateVmxOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - + GetRegisterInfoAtIndex(k_first_vmx_ppc64le)->byte_offset; +} + +uint32_t NativeRegisterContextAIX_ppc64::CalculateVsxOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - + GetRegisterInfoAtIndex(k_first_vsx_ppc64le)->byte_offset; +} + +Status NativeRegisterContextAIX_ppc64::ReadVMX() { + return NativeProcessAIX::PtraceWrapper(PTRACE_GETVRREGS, m_thread.GetID(), + nullptr, &m_vmx_ppc64le, + sizeof(m_vmx_ppc64le)); +} + +Status NativeRegisterContextAIX_ppc64::WriteVMX() { + //FIXME + int regset = 0/*NT_PPC_VMX*/; + return NativeProcessAIX::PtraceWrapper(PT_CLEAR/*PTRACE_SETVRREGS*/, m_thread.GetID(), + ®set, &m_vmx_ppc64le, + sizeof(m_vmx_ppc64le)); +} + +Status NativeRegisterContextAIX_ppc64::ReadVSX() { + return NativeProcessAIX::PtraceWrapper(PTRACE_GETVSRREGS, m_thread.GetID(), + nullptr, &m_vsx_ppc64le, + sizeof(m_vsx_ppc64le)); +} + +Status NativeRegisterContextAIX_ppc64::WriteVSX() { + //FIXME + int regset = 0/*NT_PPC_VSX*/; + return NativeProcessAIX::PtraceWrapper(PT_CLEAR/*PTRACE_SETVSRREGS*/, m_thread.GetID(), + ®set, &m_vsx_ppc64le, + sizeof(m_vsx_ppc64le)); +} + +bool NativeRegisterContextAIX_ppc64::IsVMX(unsigned reg) { + return (reg >= k_first_vmx_ppc64le) && (reg <= k_last_vmx_ppc64le); +} + +bool NativeRegisterContextAIX_ppc64::IsVSX(unsigned reg) { + return (reg >= k_first_vsx_ppc64le) && (reg <= k_last_vsx_ppc64le); +} + +uint32_t NativeRegisterContextAIX_ppc64::NumSupportedHardwareWatchpoints() { + Log *log = GetLog(POSIXLog::Watchpoints); + + // Read hardware breakpoint and watchpoint information. + Status error = ReadHardwareDebugInfo(); + + if (error.Fail()) + return 0; + + LLDB_LOG(log, "{0}", m_max_hwp_supported); + return m_max_hwp_supported; +} + +uint32_t NativeRegisterContextAIX_ppc64::SetHardwareWatchpoint( + lldb::addr_t addr, size_t size, uint32_t watch_flags) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size, + watch_flags); + + // Read hardware breakpoint and watchpoint information. + Status error = ReadHardwareDebugInfo(); + + if (error.Fail()) + return LLDB_INVALID_INDEX32; + + uint32_t control_value = 0, wp_index = 0; + lldb::addr_t real_addr = addr; + uint32_t rw_mode = 0; + + // Check if we are setting watchpoint other than read/write/access Update + // watchpoint flag to match ppc64le write-read bit configuration. + switch (watch_flags) { + case eWatchpointKindWrite: + //FIXME + //rw_mode = 0/*PPC_BREAKPOINT_TRIGGER_WRITE*/; + watch_flags = 2; + break; + // Watchpoint read not supported + case eWatchpointKindRead: + case (eWatchpointKindRead | eWatchpointKindWrite): + default: + return LLDB_INVALID_INDEX32; + } + + // Check if size has a valid hardware watchpoint length. + if (size != 8) + return LLDB_INVALID_INDEX32; + + // Check 8-byte alignment for hardware watchpoint target address. Below is a + // hack to recalculate address and size in order to make sure we can watch + // non 8-byte aligned addresses as well. + if (addr & 0x07) { + + addr_t begin = llvm::alignDown(addr, 8); + addr_t end = llvm::alignTo(addr + size, 8); + size = llvm::PowerOf2Ceil(end - begin); + + addr = addr & (~0x07); + } + + // Setup control value + control_value = watch_flags << 3; + control_value |= ((1 << size) - 1) << 5; + control_value |= (2 << 1) | 1; + + // Iterate over stored watchpoints and find a free wp_index + wp_index = LLDB_INVALID_INDEX32; + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + if ((m_hwp_regs[i].control & 1) == 0) { + wp_index = i; // Mark last free slot + } else if (m_hwp_regs[i].address == addr) { + return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints. + } + } + + if (wp_index == LLDB_INVALID_INDEX32) + return LLDB_INVALID_INDEX32; + + // Update watchpoint in local cache + m_hwp_regs[wp_index].real_addr = real_addr; + m_hwp_regs[wp_index].address = addr; + m_hwp_regs[wp_index].control = control_value; + //m_hwp_regs[wp_index].mode = rw_mode; + + // PTRACE call to set corresponding watchpoint register. + error = WriteHardwareDebugRegs(); + + if (error.Fail()) { + m_hwp_regs[wp_index].address = 0; + m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros(1); + + return LLDB_INVALID_INDEX32; + } + + return wp_index; +} + +bool NativeRegisterContextAIX_ppc64::ClearHardwareWatchpoint( + uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + // Read hardware breakpoint and watchpoint information. + Status error = ReadHardwareDebugInfo(); + + if (error.Fail()) + return false; + + if (wp_index >= m_max_hwp_supported) + return false; + + // Create a backup we can revert to in case of failure. + lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; + uint32_t tempControl = m_hwp_regs[wp_index].control; + long *tempSlot = reinterpret_cast(m_hwp_regs[wp_index].slot); + + // Update watchpoint in local cache + m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros(1); + m_hwp_regs[wp_index].address = 0; + m_hwp_regs[wp_index].slot = 0; + m_hwp_regs[wp_index].mode = 0; + + // Ptrace call to update hardware debug registers + //FIXME + error = NativeProcessAIX::PtraceWrapper(PT_CLEAR/*PPC_PTRACE_DELHWDEBUG*/, + m_thread.GetID(), 0, tempSlot); + + if (error.Fail()) { + m_hwp_regs[wp_index].control = tempControl; + m_hwp_regs[wp_index].address = tempAddr; + m_hwp_regs[wp_index].slot = reinterpret_cast(tempSlot); + + return false; + } + + return true; +} + +uint32_t +NativeRegisterContextAIX_ppc64::GetWatchpointSize(uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + unsigned control = (m_hwp_regs[wp_index].control >> 5) & 0xff; + if (llvm::isPowerOf2_32(control + 1)) { + return llvm::popcount(control); + } + + return 0; +} + +bool NativeRegisterContextAIX_ppc64::WatchpointIsEnabled( + uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + return !!((m_hwp_regs[wp_index].control & 0x1) == 0x1); +} + +Status NativeRegisterContextAIX_ppc64::GetWatchpointHitIndex( + uint32_t &wp_index, lldb::addr_t trap_addr) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr); + + uint32_t watch_size; + lldb::addr_t watch_addr; + + for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) { + watch_size = GetWatchpointSize(wp_index); + watch_addr = m_hwp_regs[wp_index].address; + + if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr && + trap_addr <= watch_addr + watch_size) { + m_hwp_regs[wp_index].hit_addr = trap_addr; + return Status(); + } + } + + wp_index = LLDB_INVALID_INDEX32; + return Status(); +} + +lldb::addr_t +NativeRegisterContextAIX_ppc64::GetWatchpointAddress(uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + if (wp_index >= m_max_hwp_supported) + return LLDB_INVALID_ADDRESS; + + if (WatchpointIsEnabled(wp_index)) + return m_hwp_regs[wp_index].real_addr; + else + return LLDB_INVALID_ADDRESS; +} + +lldb::addr_t +NativeRegisterContextAIX_ppc64::GetWatchpointHitAddress(uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + if (wp_index >= m_max_hwp_supported) + return LLDB_INVALID_ADDRESS; + + if (WatchpointIsEnabled(wp_index)) + return m_hwp_regs[wp_index].hit_addr; + + return LLDB_INVALID_ADDRESS; +} + +Status NativeRegisterContextAIX_ppc64::ReadHardwareDebugInfo() { + if (!m_refresh_hwdebug_info) { + return Status(); + } + + m_max_hwp_supported = 1; + m_max_hbp_supported = 0; + m_refresh_hwdebug_info = false; + + return Status(); +} + +Status NativeRegisterContextAIX_ppc64::WriteHardwareDebugRegs() { + Status error; + long ret; + + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + if ((m_hwp_regs[i].control & 1) == 0) + continue; + + error = NativeProcessAIX::PtraceWrapper(PT_WATCH, m_thread.GetID(), (void *)m_hwp_regs[i].address, nullptr, 8, &ret); + + if (error.Fail()) + return error; + + m_hwp_regs[i].slot = ret; + } + return error; +} + +#endif // defined(__powerpc64__) diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h new file mode 100644 index 0000000000000..a29f786f2313a --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h @@ -0,0 +1,138 @@ +//===-- NativeRegisterContextAIX_ppc64.h --------------------*- 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 +// +//===----------------------------------------------------------------------===// + +// This implementation is related to the OpenPOWER ABI for Power Architecture +// 64-bit ELF V2 ABI + +#if defined(__powerpc64__) + +#ifndef lldb_NativeRegisterContextAIX_ppc64_h +#define lldb_NativeRegisterContextAIX_ppc64_h + +#include "Plugins/Process/AIX/NativeRegisterContextAIX.h" +#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" + +#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT +#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h" +#undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT + +namespace lldb_private { +namespace process_aix { + +class NativeProcessAIX; + +class NativeRegisterContextAIX_ppc64 : public NativeRegisterContextAIX { +public: + NativeRegisterContextAIX_ppc64(const ArchSpec &target_arch, + NativeThreadProtocol &native_thread); + + uint32_t GetRegisterSetCount() const override; + + uint32_t GetUserRegisterCount() const override; + + const RegisterSet *GetRegisterSet(uint32_t set_index) const override; + + Status ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + + Status WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + + Status ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override; + + Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + // Hardware watchpoint management functions + + uint32_t NumSupportedHardwareWatchpoints() override; + + uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags) override; + + bool ClearHardwareWatchpoint(uint32_t hw_index) override; + + Status GetWatchpointHitIndex(uint32_t &wp_index, + lldb::addr_t trap_addr) override; + + lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override; + + lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; + + uint32_t GetWatchpointSize(uint32_t wp_index); + + bool WatchpointIsEnabled(uint32_t wp_index); + +protected: + bool IsVMX(unsigned reg); + + bool IsVSX(unsigned reg); + + Status ReadVMX(); + + Status WriteVMX(); + + Status ReadVSX(); + + Status WriteVSX(); + + void *GetGPRBuffer() override { return &m_gpr_ppc64le; } + + void *GetFPRBuffer() override { return &m_fpr_ppc64le; } + + size_t GetFPRSize() override { return sizeof(m_fpr_ppc64le); } + +private: + GPR m_gpr_ppc64le; // 64-bit general purpose registers. + FPR m_fpr_ppc64le; // floating-point registers including extended register. + VMX m_vmx_ppc64le; // VMX registers. + VSX m_vsx_ppc64le; // Last lower bytes from first VSX registers. + + bool IsGPR(unsigned reg) const; + + bool IsFPR(unsigned reg) const; + + bool IsVMX(unsigned reg) const; + + bool IsVSX(unsigned reg) const; + + uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const; + + uint32_t CalculateVmxOffset(const RegisterInfo *reg_info) const; + + uint32_t CalculateVsxOffset(const RegisterInfo *reg_info) const; + + Status ReadHardwareDebugInfo(); + + Status WriteHardwareDebugRegs(); + + // Debug register info for hardware watchpoints management. + struct DREG { + lldb::addr_t address; // Breakpoint/watchpoint address value. + lldb::addr_t hit_addr; // Address at which last watchpoint trigger + // exception occurred. + lldb::addr_t real_addr; // Address value that should cause target to stop. + uint32_t control; // Breakpoint/watchpoint control value. + uint32_t refcount; // Serves as enable/disable and reference counter. + long slot; // Saves the value returned from PTRACE_SETHWDEBUG. + int mode; // Defines if watchpoint is read/write/access. + }; + + std::array m_hwp_regs; + + // 16 is just a maximum value, query hardware for actual watchpoint count + uint32_t m_max_hwp_supported = 16; + uint32_t m_max_hbp_supported = 16; + bool m_refresh_hwdebug_info = true; +}; + +} // namespace process_aix +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextAIX_ppc64_h + +#endif // defined(__powerpc64__) diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp new file mode 100644 index 0000000000000..e07daccdff550 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp @@ -0,0 +1,526 @@ +//===-- NativeThreadAIX.cpp ---------------------------------------------===// +// +// 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 "NativeThreadAIX.h" + +#include +#include + +#include "NativeProcessAIX.h" +#include "NativeRegisterContextAIX.h" + +#include "lldb/Host/HostNativeThread.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" +#include "lldb/lldb-enumerations.h" + +#include "llvm/ADT/SmallString.h" + +#include "Plugins/Process/POSIX/CrashReason.h" + +#include +#include +#include + +#if 0 +#include +// Try to define a macro to encapsulate the tgkill syscall +#define tgkill(pid, tid, sig) \ + syscall(__NR_tgkill, static_cast<::pid_t>(pid), static_cast<::pid_t>(tid), \ + sig) +#endif + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; + +namespace { +void LogThreadStopInfo(Log &log, const ThreadStopInfo &stop_info, + const char *const header) { + switch (stop_info.reason) { + case eStopReasonNone: + log.Printf("%s: %s no stop reason", __FUNCTION__, header); + return; + case eStopReasonTrace: + log.Printf("%s: %s trace, stopping signal 0x%" PRIx32, __FUNCTION__, header, + stop_info.signo); + return; + case eStopReasonBreakpoint: + log.Printf("%s: %s breakpoint, stopping signal 0x%" PRIx32, __FUNCTION__, + header, stop_info.signo); + return; + case eStopReasonWatchpoint: + log.Printf("%s: %s watchpoint, stopping signal 0x%" PRIx32, __FUNCTION__, + header, stop_info.signo); + return; + case eStopReasonSignal: + log.Printf("%s: %s signal 0x%02" PRIx32, __FUNCTION__, header, + stop_info.signo); + return; + case eStopReasonException: + log.Printf("%s: %s exception type 0x%02" PRIx64, __FUNCTION__, header, + stop_info.details.exception.type); + return; + case eStopReasonExec: + log.Printf("%s: %s exec, stopping signal 0x%" PRIx32, __FUNCTION__, header, + stop_info.signo); + return; + case eStopReasonPlanComplete: + log.Printf("%s: %s plan complete", __FUNCTION__, header); + return; + case eStopReasonThreadExiting: + log.Printf("%s: %s thread exiting", __FUNCTION__, header); + return; + case eStopReasonInstrumentation: + log.Printf("%s: %s instrumentation", __FUNCTION__, header); + return; + case eStopReasonProcessorTrace: + log.Printf("%s: %s processor trace", __FUNCTION__, header); + return; + default: + log.Printf("%s: %s invalid stop reason %" PRIu32, __FUNCTION__, header, + static_cast(stop_info.reason)); + } +} +} + +NativeThreadAIX::NativeThreadAIX(NativeProcessAIX &process, + lldb::tid_t tid) + : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid), + m_stop_info(), + m_reg_context_up( + NativeRegisterContextAIX::CreateHostNativeRegisterContextAIX( + process.GetArchitecture(), *this)), + m_stop_description() {} + +std::string NativeThreadAIX::GetName() { + NativeProcessAIX &process = GetProcess(); + + auto BufferOrError = getProcFile(process.GetID(), GetID(), "comm"); + if (!BufferOrError) + return ""; + return std::string(BufferOrError.get()->getBuffer().rtrim('\n')); +} + +lldb::StateType NativeThreadAIX::GetState() { return m_state; } + +bool NativeThreadAIX::GetStopReason(ThreadStopInfo &stop_info, + std::string &description) { + Log *log = GetLog(LLDBLog::Thread); + + description.clear(); + + switch (m_state) { + case eStateStopped: + case eStateCrashed: + case eStateExited: + case eStateSuspended: + case eStateUnloaded: + if (log) + LogThreadStopInfo(*log, m_stop_info, "m_stop_info in thread:"); + stop_info = m_stop_info; + description = m_stop_description; + if (log) + LogThreadStopInfo(*log, stop_info, "returned stop_info:"); + + return true; + + case eStateInvalid: + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + case eStateRunning: + case eStateStepping: + case eStateDetached: + if (log) { + LLDB_LOGF(log, + "NativeThreadAIX::%s tid %" PRIu64 + " in state %s cannot answer stop reason", + __FUNCTION__, GetID(), StateAsCString(m_state)); + } + return false; + } + llvm_unreachable("unhandled StateType!"); +} + +Status NativeThreadAIX::SetWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags, bool hardware) { + if (!hardware) + return Status("not implemented"); + if (m_state == eStateLaunching) + return Status(); + Status error = RemoveWatchpoint(addr); + if (error.Fail()) + return error; + uint32_t wp_index = + m_reg_context_up->SetHardwareWatchpoint(addr, size, watch_flags); + if (wp_index == LLDB_INVALID_INDEX32) + return Status("Setting hardware watchpoint failed."); + m_watchpoint_index_map.insert({addr, wp_index}); + return Status(); +} + +Status NativeThreadAIX::RemoveWatchpoint(lldb::addr_t addr) { + auto wp = m_watchpoint_index_map.find(addr); + if (wp == m_watchpoint_index_map.end()) + return Status(); + uint32_t wp_index = wp->second; + m_watchpoint_index_map.erase(wp); + if (m_reg_context_up->ClearHardwareWatchpoint(wp_index)) + return Status(); + return Status("Clearing hardware watchpoint failed."); +} + +Status NativeThreadAIX::SetHardwareBreakpoint(lldb::addr_t addr, + size_t size) { + if (m_state == eStateLaunching) + return Status(); + + Status error = RemoveHardwareBreakpoint(addr); + if (error.Fail()) + return error; + + uint32_t bp_index = m_reg_context_up->SetHardwareBreakpoint(addr, size); + + if (bp_index == LLDB_INVALID_INDEX32) + return Status("Setting hardware breakpoint failed."); + + m_hw_break_index_map.insert({addr, bp_index}); + return Status(); +} + +Status NativeThreadAIX::RemoveHardwareBreakpoint(lldb::addr_t addr) { + auto bp = m_hw_break_index_map.find(addr); + if (bp == m_hw_break_index_map.end()) + return Status(); + + uint32_t bp_index = bp->second; + if (m_reg_context_up->ClearHardwareBreakpoint(bp_index)) { + m_hw_break_index_map.erase(bp); + return Status(); + } + + return Status("Clearing hardware breakpoint failed."); +} + +Status NativeThreadAIX::Resume(uint32_t signo) { + const StateType new_state = StateType::eStateRunning; + MaybeLogStateChange(new_state); + m_state = new_state; + + m_stop_info.reason = StopReason::eStopReasonNone; + m_stop_description.clear(); + + // If watchpoints have been set, but none on this thread, then this is a new + // thread. So set all existing watchpoints. + if (m_watchpoint_index_map.empty()) { + NativeProcessAIX &process = GetProcess(); + + const auto &watchpoint_map = process.GetWatchpointMap(); + m_reg_context_up->ClearAllHardwareWatchpoints(); + for (const auto &pair : watchpoint_map) { + const auto &wp = pair.second; + SetWatchpoint(wp.m_addr, wp.m_size, wp.m_watch_flags, wp.m_hardware); + } + } + + // Set all active hardware breakpoint on all threads. + if (m_hw_break_index_map.empty()) { + NativeProcessAIX &process = GetProcess(); + + const auto &hw_breakpoint_map = process.GetHardwareBreakpointMap(); + m_reg_context_up->ClearAllHardwareBreakpoints(); + for (const auto &pair : hw_breakpoint_map) { + const auto &bp = pair.second; + SetHardwareBreakpoint(bp.m_addr, bp.m_size); + } + } + + intptr_t data = 0; + + if (signo != LLDB_INVALID_SIGNAL_NUMBER) + data = signo; + + return NativeProcessAIX::PtraceWrapper(PT_CONTINUE, GetID(), nullptr, + reinterpret_cast(data)); +} + +Status NativeThreadAIX::SingleStep(uint32_t signo) { + const StateType new_state = StateType::eStateStepping; + MaybeLogStateChange(new_state); + m_state = new_state; + m_stop_info.reason = StopReason::eStopReasonNone; + + intptr_t data = 0; + if (signo != LLDB_INVALID_SIGNAL_NUMBER) + data = signo; + + // If hardware single-stepping is not supported, we just do a continue. The + // breakpoint on the next instruction has been setup in + // NativeProcessAIX::Resume. + return NativeProcessAIX::PtraceWrapper( + GetProcess().SupportHardwareSingleStepping() ? PT_STEP : PT_CONTINUE, + m_tid, nullptr, reinterpret_cast(data)); +} + +void NativeThreadAIX::SetStoppedBySignal(uint32_t signo, + const siginfo_t *info) { + Log *log = GetLog(LLDBLog::Thread); + LLDB_LOGF(log, "NativeThreadAIX::%s called with signal 0x%02" PRIx32, + __FUNCTION__, signo); + + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonSignal; + m_stop_info.signo = signo; + + m_stop_description.clear(); + switch (signo) { + case SIGSEGV: + case SIGBUS: + case SIGFPE: + case SIGILL: + break; + } +} + +void NativeThreadAIX::AnnotateSyncTagCheckFault(const siginfo_t *info) { + int32_t allocation_tag_type = 0; + switch (GetProcess().GetArchitecture().GetMachine()) { + default: + return; + } + + auto details = + GetRegisterContext().GetMemoryTaggingDetails(allocation_tag_type); + if (!details) { + llvm::consumeError(details.takeError()); + return; + } + + // We assume that the stop description is currently: + // signal SIGSEGV: sync tag check fault (fault address: ) + // Remove the closing ) + m_stop_description.pop_back(); + + std::stringstream ss; + lldb::addr_t fault_addr = reinterpret_cast(info->si_addr); + std::unique_ptr manager(std::move(details->manager)); + + ss << " logical tag: 0x" << std::hex << manager->GetLogicalTag(fault_addr); + + std::vector allocation_tag_data; + // The fault address may not be granule aligned. ReadMemoryTags will granule + // align any range you give it, potentially making it larger. + // To prevent this set len to 1. This always results in a range that is at + // most 1 granule in size and includes fault_addr. + Status status = GetProcess().ReadMemoryTags(allocation_tag_type, fault_addr, + 1, allocation_tag_data); + + if (status.Success()) { + llvm::Expected> allocation_tag = + manager->UnpackTagsData(allocation_tag_data, 1); + if (allocation_tag) { + ss << " allocation tag: 0x" << std::hex << allocation_tag->front() << ")"; + } else { + llvm::consumeError(allocation_tag.takeError()); + ss << ")"; + } + } else + ss << ")"; + + m_stop_description += ss.str(); +} + +bool NativeThreadAIX::IsStopped(int *signo) { + if (!StateIsStoppedState(m_state, false)) + return false; + + // If we are stopped by a signal, return the signo. + if (signo && m_state == StateType::eStateStopped && + m_stop_info.reason == StopReason::eStopReasonSignal) { + *signo = m_stop_info.signo; + } + + // Regardless, we are stopped. + return true; +} + +void NativeThreadAIX::SetStopped() { + // On every stop, clear any cached register data structures + GetRegisterContext().InvalidateAllRegisters(); + + const StateType new_state = StateType::eStateStopped; + MaybeLogStateChange(new_state); + m_state = new_state; + m_stop_description.clear(); +} + +void NativeThreadAIX::SetStoppedByExec() { + Log *log = GetLog(LLDBLog::Thread); + LLDB_LOGF(log, "NativeThreadAIX::%s()", __FUNCTION__); + + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonExec; + m_stop_info.signo = SIGSTOP; +} + +void NativeThreadAIX::SetStoppedByBreakpoint() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonBreakpoint; + m_stop_info.signo = SIGTRAP; + m_stop_description.clear(); +} + +void NativeThreadAIX::SetStoppedByWatchpoint(uint32_t wp_index) { + SetStopped(); + + lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); + + std::ostringstream ostr; + ostr << m_reg_context_up->GetWatchpointAddress(wp_index) << " "; + ostr << wp_index; + + /* + * MIPS: Last 3bits of the watchpoint address are masked by the kernel. For + * example: + * 'n' is at 0x120010d00 and 'm' is 0x120010d04. When a watchpoint is set at + * 'm', then + * watch exception is generated even when 'n' is read/written. To handle this + * case, + * find the base address of the load/store instruction and append it in the + * stop-info + * packet. + */ + ostr << " " << m_reg_context_up->GetWatchpointHitAddress(wp_index); + + m_stop_description = ostr.str(); + + m_stop_info.reason = StopReason::eStopReasonWatchpoint; + m_stop_info.signo = SIGTRAP; +} + +bool NativeThreadAIX::IsStoppedAtBreakpoint() { + return GetState() == StateType::eStateStopped && + m_stop_info.reason == StopReason::eStopReasonBreakpoint; +} + +bool NativeThreadAIX::IsStoppedAtWatchpoint() { + return GetState() == StateType::eStateStopped && + m_stop_info.reason == StopReason::eStopReasonWatchpoint; +} + +void NativeThreadAIX::SetStoppedByTrace() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonTrace; + m_stop_info.signo = SIGTRAP; +} + +void NativeThreadAIX::SetStoppedByFork(bool is_vfork, lldb::pid_t child_pid) { + SetStopped(); + + m_stop_info.reason = + is_vfork ? StopReason::eStopReasonVFork : StopReason::eStopReasonFork; + m_stop_info.details.fork.child_pid = child_pid; + m_stop_info.details.fork.child_tid = child_pid; +} + +void NativeThreadAIX::SetStoppedByVForkDone() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonVForkDone; +} + +void NativeThreadAIX::SetStoppedWithNoReason() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonNone; + m_stop_info.signo = 0; +} + +void NativeThreadAIX::SetStoppedByProcessorTrace( + llvm::StringRef description) { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonProcessorTrace; + m_stop_info.signo = 0; + m_stop_description = description.str(); +} + +void NativeThreadAIX::SetExited() { + const StateType new_state = StateType::eStateExited; + MaybeLogStateChange(new_state); + m_state = new_state; + + m_stop_info.reason = StopReason::eStopReasonThreadExiting; +} + +Status NativeThreadAIX::RequestStop() { + Log *log = GetLog(LLDBLog::Thread); + + NativeProcessAIX &process = GetProcess(); + + lldb::pid_t pid = process.GetID(); + lldb::tid_t tid = GetID(); + + LLDB_LOGF(log, + "NativeThreadAIX::%s requesting thread stop(pid: %" PRIu64 + ", tid: %" PRIu64 ")", + __FUNCTION__, pid, tid); + + Status err; + errno = 0; + if (::kill(pid, SIGSTOP) != 0) { + err.SetErrorToErrno(); + LLDB_LOGF(log, + "NativeThreadAIX::%s kill(%" PRIu64 ", SIGSTOP) failed: %s", + __FUNCTION__, pid, err.AsCString()); + } + return err; +} + +void NativeThreadAIX::MaybeLogStateChange(lldb::StateType new_state) { + Log *log = GetLog(LLDBLog::Thread); + // If we're not logging, we're done. + if (!log) + return; + + // If this is a state change to the same state, we're done. + lldb::StateType old_state = m_state; + if (new_state == old_state) + return; + + LLDB_LOG(log, "pid={0}, tid={1}: changing from state {2} to {3}", + m_process.GetID(), GetID(), old_state, new_state); +} + +NativeProcessAIX &NativeThreadAIX::GetProcess() { + return static_cast(m_process); +} + +const NativeProcessAIX &NativeThreadAIX::GetProcess() const { + return static_cast(m_process); +} + +llvm::Expected> +NativeThreadAIX::GetSiginfo() const { + auto siginfo_buf = + llvm::WritableMemoryBuffer::getNewUninitMemBuffer(sizeof(siginfo_t)); +#if 0 + Status error = + GetProcess().GetSignalInfo(GetID(), siginfo_buf->getBufferStart()); + if (!error.Success()) + return error.ToError(); +#endif + return std::move(siginfo_buf); +} diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h new file mode 100644 index 0000000000000..706a7ce69da8e --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h @@ -0,0 +1,126 @@ +//===-- NativeThreadAIX.h ----------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeThreadAIX_H_ +#define liblldb_NativeThreadAIX_H_ + +#include "Plugins/Process/AIX/NativeRegisterContextAIX.h" +#include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/lldb-private-forward.h" + +#include "llvm/ADT/StringRef.h" + +#include +#include +#include +#include + +namespace lldb_private { +namespace process_aix { + +class NativeProcessAIX; + +class NativeThreadAIX : public NativeThreadProtocol { + friend class NativeProcessAIX; + +public: + NativeThreadAIX(NativeProcessAIX &process, lldb::tid_t tid); + + // NativeThreadProtocol Interface + std::string GetName() override; + + lldb::StateType GetState() override; + + bool GetStopReason(ThreadStopInfo &stop_info, + std::string &description) override; + + NativeRegisterContextAIX &GetRegisterContext() override { + return *m_reg_context_up; + } + + Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, + bool hardware) override; + + Status RemoveWatchpoint(lldb::addr_t addr) override; + + Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override; + + Status RemoveHardwareBreakpoint(lldb::addr_t addr) override; + + NativeProcessAIX &GetProcess(); + + const NativeProcessAIX &GetProcess() const; + + llvm::Expected> + GetSiginfo() const override; + +private: + // Interface for friend classes + + /// Resumes the thread. If \p signo is anything but + /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. + Status Resume(uint32_t signo); + + /// Single steps the thread. If \p signo is anything but + /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. + Status SingleStep(uint32_t signo); + + void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr); + + /// Return true if the thread is stopped. + /// If stopped by a signal, indicate the signo in the signo argument. + /// Otherwise, return LLDB_INVALID_SIGNAL_NUMBER. + bool IsStopped(int *signo); + + void SetStoppedByExec(); + + void SetStoppedByBreakpoint(); + + void SetStoppedByWatchpoint(uint32_t wp_index); + + bool IsStoppedAtBreakpoint(); + + bool IsStoppedAtWatchpoint(); + + void SetStoppedByTrace(); + + void SetStoppedByFork(bool is_vfork, lldb::pid_t child_pid); + + void SetStoppedByVForkDone(); + + void SetStoppedWithNoReason(); + + void SetStoppedByProcessorTrace(llvm::StringRef description); + + void SetExited(); + + Status RequestStop(); + + // Private interface + void MaybeLogStateChange(lldb::StateType new_state); + + void SetStopped(); + + /// Extend m_stop_description with logical and allocation tag values. + /// If there is an error along the way just add the information we were able + /// to get. + void AnnotateSyncTagCheckFault(const siginfo_t *info); + + // Member Variables + lldb::StateType m_state; + ThreadStopInfo m_stop_info; + std::unique_ptr m_reg_context_up; + std::string m_stop_description; + using WatchpointIndexMap = std::map; + WatchpointIndexMap m_watchpoint_index_map; + WatchpointIndexMap m_hw_break_index_map; +}; +} // namespace process_aix +} // namespace lldb_private + +#endif // #ifndef liblldb_NativeThreadAIX_H_ diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt index a51d0f7afd175..01bb5f462eba4 100644 --- a/lldb/source/Plugins/Process/CMakeLists.txt +++ b/lldb/source/Plugins/Process/CMakeLists.txt @@ -7,6 +7,9 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD") add_subdirectory(NetBSD) add_subdirectory(POSIX) +elseif (CMAKE_SYSTEM_NAME MATCHES "AIX") + add_subdirectory(AIX) + add_subdirectory(POSIX) elseif (CMAKE_SYSTEM_NAME MATCHES "Windows") add_subdirectory(Windows/Common) elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin") diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 32c71d87c7f58..db271357d792a 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -46,8 +46,34 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, function_options.include_inlines = false; SymbolContextList sc_list; +#if !defined(__AIX__) process->GetTarget().GetImages().FindFunctions( ConstString("mmap"), eFunctionNameTypeFull, function_options, sc_list); +#else + process->GetTarget().GetImages().FindFunctions( + ConstString("mmap64"), eFunctionNameTypeFull, function_options, sc_list); + SymbolContextList toc_list; + process->GetTarget().GetImages().FindSymbolsWithNameAndType( + ConstString("TOC"), lldb::eSymbolTypeAny, toc_list); + + AddressRange toc_range; + if (sc_list.GetSize() > 0) { + SymbolContext sc; + if (sc_list.GetContextAtIndex(0, sc)) { + for (int i = 0; i < toc_list.GetSize(); ++i) { + SymbolContext tocSC; + if (toc_list.GetContextAtIndex(i, tocSC)) { + if (tocSC.module_sp == sc.module_sp) { + if (tocSC.GetAddressRange(eSymbolContextSymbol, 0, false, + toc_range)) { + break; + } + } + } + } + } + } +#endif const uint32_t count = sc_list.GetSize(); if (count > 0) { SymbolContext sc; @@ -96,9 +122,16 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, MmapArgList args = process->GetTarget().GetPlatform()->GetMmapArgumentList( arch, addr, length, prot_arg, flags, fd, offset); +#if defined(__AIX__) + lldb::ThreadPlanSP call_plan_sp( + new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(), + toc_range.GetBaseAddress(), + void_ptr_type, args, options)); +#else lldb::ThreadPlanSP call_plan_sp( new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(), void_ptr_type, args, options)); +#endif if (call_plan_sp) { DiagnosticManager diagnostics; diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp index 159fd2856443c..d9b41d595147f 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp @@ -23,6 +23,8 @@ static const lldb_private::RegisterInfo * GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { + //HH + case llvm::Triple::ppc64: case llvm::Triple::ppc64le: return g_register_infos_ppc64le; default: @@ -34,6 +36,8 @@ GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) { static uint32_t GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { + //HitchHike + case llvm::Triple::ppc64: case llvm::Triple::ppc64le: return static_cast(sizeof(g_register_infos_ppc64le) / sizeof(g_register_infos_ppc64le[0])); diff --git a/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp b/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp index 89ecc757a68f5..550b53688fd39 100644 --- a/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp +++ b/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp @@ -20,7 +20,7 @@ using namespace lldb; using namespace lldb_private; -ThreadMemory::ThreadMemory(Process &process, tid_t tid, +ThreadMemory::ThreadMemory(Process &process, lldb::tid_t tid, const ValueObjectSP &thread_info_valobj_sp) : Thread(process, tid), m_backing_thread_sp(), m_thread_info_valobj_sp(thread_info_valobj_sp), m_name(), m_queue(), diff --git a/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt b/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt index 6755999b18185..4eddbb5ec4cfd 100644 --- a/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt +++ b/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt @@ -6,6 +6,11 @@ lldb_tablegen(ProcessGDBRemotePropertiesEnum.inc -gen-lldb-property-enum-defs SOURCE ProcessGDBRemoteProperties.td TARGET LLDBPluginProcessGDBRemotePropertiesEnumGen) +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + set(LLDB_PLUGINS lldbPluginProcessUtility ) diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 74e392249a94e..b7ecf7a5dc328 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -40,6 +40,10 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/JSON.h" +#if defined(__AIX__) +#include +#endif + #if defined(HAVE_LIBCOMPRESSION) #include #endif @@ -1710,6 +1714,32 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( return error; } +#if defined(__AIX__) +Status GDBRemoteCommunicationClient::GetLDXINFO(struct ld_xinfo *info_ptr) +{ + Status error; + + char packet[64]; + const int packet_len = ::snprintf(packet, sizeof(packet), "qLDXINFO"); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response) == + PacketResult::Success && + response.GetResponseType() == StringExtractorGDBRemote::eResponse) { + llvm::MutableArrayRef infoData((uint8_t *)info_ptr, sizeof(struct ld_xinfo)*64); + size_t got_bytes = response.GetHexBytesAvail(infoData); + if (got_bytes != sizeof(struct ld_xinfo)*64) { + error.SetErrorString("qLDXINFO ret bad size"); + return error; + } + } else { + error.SetErrorString("qLDXINFO is not supported"); + } + return error; +} +#endif + Status GDBRemoteCommunicationClient::GetQXferMemoryMapRegionInfo( lldb::addr_t addr, MemoryRegionInfo ®ion) { Status error = LoadQXferMemoryMap(); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 898d176abc346..520f37ac56716 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -32,6 +32,10 @@ #include "llvm/Support/VersionTuple.h" +#if defined(__AIX__) +struct ld_xinfo; +#endif + namespace lldb_private { namespace process_gdb_remote { @@ -196,6 +200,9 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase { Status GetMemoryRegionInfo(lldb::addr_t addr, MemoryRegionInfo &range_info); std::optional GetWatchpointSlotCount(); +#if defined(__AIX__) + Status GetLDXINFO(struct ld_xinfo *info_ptr); +#endif std::optional GetWatchpointReportedAfter(); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index a0b08a219ae14..f019062986925 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -48,6 +48,9 @@ #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "lldb/Utility/StringExtractorGDBRemote.h" +#if defined(__AIX__) +#include +#endif using namespace lldb; using namespace lldb_private; @@ -193,6 +196,8 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { &GDBRemoteCommunicationServerLLGS::Handle_Z); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_z, &GDBRemoteCommunicationServerLLGS::Handle_z); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLDXINFO, + &GDBRemoteCommunicationServerLLGS::Handle_qLDXINFO); RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_QPassSignals, &GDBRemoteCommunicationServerLLGS::Handle_QPassSignals); @@ -3006,6 +3011,29 @@ GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) { } } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_qLDXINFO(StringExtractorGDBRemote &packet) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { + Log *log = GetLog(LLDBLog::Process); + LLDB_LOG(log, "qLDXINFO failed, no process available"); + return SendErrorResponse(0xff); + } + +#if defined(__AIX__) + // FIXME: buffer size + struct ld_xinfo info[64]; + if (ptrace64(PT_LDXINFO, m_current_process->GetID(), (long long)&(info[0]), sizeof(info), nullptr) != 0) { + return SendErrorResponse(0xff); + } + StreamGDBRemote response; + response.PutBytesAsRawHex8(&(info[0]), sizeof(info)); + return SendPacketNoLock(response.GetString()); +#else + return SendErrorResponse(0xff); +#endif +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index 646b6a102abf6..a464479e178de 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -211,6 +211,8 @@ class GDBRemoteCommunicationServerLLGS PacketResult Handle_z(StringExtractorGDBRemote &packet); + PacketResult Handle_qLDXINFO(StringExtractorGDBRemote &packet); + PacketResult Handle_s(StringExtractorGDBRemote &packet); PacketResult Handle_qXfer(StringExtractorGDBRemote &packet); diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 6f9c2cc1e4b4e..10fbaa2b3c837 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -92,6 +92,10 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/raw_ostream.h" +#if defined(__AIX__) +#include +#endif + #define DEBUGSERVER_BASENAME "debugserver" using namespace lldb; using namespace lldb_private; @@ -1513,7 +1517,7 @@ bool ProcessGDBRemote::DoUpdateThreadList(ThreadList &old_thread_list, ThreadList old_thread_list_copy(old_thread_list); if (num_thread_ids > 0) { for (size_t i = 0; i < num_thread_ids; ++i) { - tid_t tid = m_thread_ids[i]; + lldb::tid_t tid = m_thread_ids[i]; ThreadSP thread_sp( old_thread_list_copy.RemoveThreadByProtocolID(tid, false)); if (!thread_sp) { @@ -2945,6 +2949,13 @@ Status ProcessGDBRemote::DoGetMemoryRegionInfo(addr_t load_addr, return error; } +#if defined(__AIX__) +Status ProcessGDBRemote::DoGetLDXINFO(struct ld_xinfo *info_ptr) { + Status error(m_gdb_comm.GetLDXINFO(info_ptr)); + return error; +} +#endif + std::optional ProcessGDBRemote::GetWatchpointSlotCount() { return m_gdb_comm.GetWatchpointSlotCount(); } diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 2492795851388..82200fbea21cd 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -37,6 +37,10 @@ #include "GDBRemoteCommunicationClient.h" #include "GDBRemoteRegisterContext.h" +#if defined(__AIX__) +struct ld_xinfo; +#endif + #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" @@ -423,6 +427,10 @@ class ProcessGDBRemote : public Process, Status DoGetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo ®ion_info) override; +#if defined(__AIX__) + Status DoGetLDXINFO(struct ld_xinfo *info_ptr) override; +#endif + private: // For ProcessGDBRemote only std::string m_partial_profile_data; diff --git a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp index 1da7696c9a352..930c707604bb3 100644 --- a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp +++ b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp @@ -593,19 +593,19 @@ bool ProcessMachCore::DoUpdateThreadList(ThreadList &old_thread_list, ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); if (core_objfile) { - std::set used_tids; + std::set used_tids; const uint32_t num_threads = core_objfile->GetNumThreadContexts(); - std::vector tids; + std::vector tids; if (core_objfile->GetCorefileThreadExtraInfos(tids)) { assert(tids.size() == num_threads); // Find highest tid value. - tid_t highest_tid = 0; + lldb::tid_t highest_tid = 0; for (uint32_t i = 0; i < num_threads; i++) { if (tids[i] != LLDB_INVALID_THREAD_ID && tids[i] > highest_tid) highest_tid = tids[i]; } - tid_t current_unused_tid = highest_tid + 1; + lldb::tid_t current_unused_tid = highest_tid + 1; for (uint32_t i = 0; i < num_threads; i++) { if (tids[i] == LLDB_INVALID_THREAD_ID) { tids[i] = current_unused_tid++; diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt index 7523d65abf0f8..1ce60a0b66154 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt +++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt @@ -20,6 +20,11 @@ if (LLDB_ENABLE_LIBEDIT) endif() add_subdirectory(Interfaces) +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + add_lldb_library(lldbPluginScriptInterpreterPython PLUGIN PythonDataObjects.cpp diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp index e1f73f1997e36..92882cfc3da31 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -500,6 +500,8 @@ dw_addr_t DWARFFormValue::Address() const { &offset, index_size); } +bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; + std::pair DWARFFormValue::ReferencedUnitAndOffset() const { uint64_t value = m_value.value.uval; @@ -512,6 +514,8 @@ DWARFFormValue::ReferencedUnitAndOffset() const { assert(m_unit); // Unit must be valid for DW_FORM_ref forms that are compile // unit relative or we will get this wrong value += m_unit->GetOffset(); + if (UGLY_FLAG_FOR_AIX) + value -= 8; if (!m_unit->ContainsDIEOffset(value)) { m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( "DW_FORM_ref* DIE reference {0:x16} is outside of its CU", value); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index 66a762bf9b685..6721c1895a576 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -924,6 +924,12 @@ const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() { return *m_func_aranges_up; } +/* AIX-NOTE - TODO: Removed conflicting code due to merge conflicts + * Refer Patches: 27,28,29,30,35 and 76 + * and modify the code accordingly. */ + +bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; + llvm::Expected DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid, const DWARFDataExtractor &debug_info, @@ -1002,6 +1008,10 @@ const lldb_private::DWARFDataExtractor &DWARFUnit::GetData() const { uint32_t DWARFUnit::GetHeaderByteSize() const { switch (m_header.getUnitType()) { case llvm::dwarf::DW_UT_compile: + if (UGLY_FLAG_FOR_AIX) + return 11 + 4/*GetDWARFSizeOfOffset*/; + else + return GetVersion() < 5 ? 11 : 12; case llvm::dwarf::DW_UT_partial: return GetVersion() < 5 ? 11 : 12; case llvm::dwarf::DW_UT_skeleton: @@ -1016,7 +1026,7 @@ uint32_t DWARFUnit::GetHeaderByteSize() const { std::optional DWARFUnit::GetStringOffsetSectionItem(uint32_t index) const { - offset_t offset = GetStrOffsetsBase() + index * 4; + lldb::offset_t offset = GetStrOffsetsBase() + index * 4; return m_dwarf.GetDWARFContext().getOrLoadStrOffsetsData().GetU32(&offset); } diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp index 2064b73dc3ea5..824528fc3acfa 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp @@ -216,7 +216,7 @@ lldb::addr_t AppleGetThreadItemInfoHandler::SetupGetThreadItemInfoFunction( AppleGetThreadItemInfoHandler::GetThreadItemInfoReturnInfo AppleGetThreadItemInfoHandler::GetThreadItemInfo(Thread &thread, - tid_t thread_id, + lldb::tid_t thread_id, addr_t page_to_free, uint64_t page_to_free_size, Status &error) { diff --git a/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/lldb/source/Symbol/DWARFCallFrameInfo.cpp index f3df8a2c27f5a..de244e372579d 100644 --- a/lldb/source/Symbol/DWARFCallFrameInfo.cpp +++ b/lldb/source/Symbol/DWARFCallFrameInfo.cpp @@ -33,7 +33,7 @@ using namespace lldb_private::dwarf; // Used for calls when the value type is specified by a DWARF EH Frame pointer // encoding. static uint64_t -GetGNUEHPointer(const DataExtractor &DE, offset_t *offset_ptr, +GetGNUEHPointer(const DataExtractor &DE, lldb::offset_t *offset_ptr, uint32_t eh_ptr_enc, addr_t pc_rel_addr, addr_t text_addr, addr_t data_addr) //, BSDRelocs *data_relocs) const { @@ -588,7 +588,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset, if (cie->augmentation[0] == 'z') { uint32_t aug_data_len = (uint32_t)m_cfi_data.GetULEB128(&offset); if (aug_data_len != 0 && cie->lsda_addr_encoding != DW_EH_PE_omit) { - offset_t saved_offset = offset; + lldb::offset_t saved_offset = offset; lsda_data_file_address = GetGNUEHPointer(m_cfi_data, &offset, cie->lsda_addr_encoding, pc_rel_addr, text_addr, data_addr); diff --git a/lldb/source/Target/ABI.cpp b/lldb/source/Target/ABI.cpp index 110b5c86fc425..6df03533cda29 100644 --- a/lldb/source/Target/ABI.cpp +++ b/lldb/source/Target/ABI.cpp @@ -208,6 +208,15 @@ bool ABI::PrepareTrivialCall(Thread &thread, lldb::addr_t sp, llvm_unreachable("Should never get here!"); } +bool ABI::PrepareTrivialCall(Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t tocAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef args) const { + // dummy prepare trivial call + llvm_unreachable("Should never get here!"); +} + bool ABI::GetFallbackRegisterLocation( const RegisterInfo *reg_info, UnwindPlan::Row::RegisterLocation &unwind_regloc) { diff --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt index a42c44b761dc5..833489b16dfd7 100644 --- a/lldb/source/Target/CMakeLists.txt +++ b/lldb/source/Target/CMakeLists.txt @@ -1,3 +1,8 @@ +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + lldb_tablegen(TargetProperties.inc -gen-lldb-property-defs SOURCE TargetProperties.td TARGET LLDBTargetPropertiesGen) diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index e3c4f2ee398cc..e31245178b2f2 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -75,6 +75,10 @@ #include "lldb/Utility/State.h" #include "lldb/Utility/Timer.h" +#if defined(__AIX__) +#include +#endif + using namespace lldb; using namespace lldb_private; using namespace std::chrono; @@ -6206,6 +6210,12 @@ Status Process::GetMemoryRegionInfo(lldb::addr_t load_addr, return DoGetMemoryRegionInfo(load_addr, range_info); } +#if defined(__AIX__) +Status Process::GetLDXINFO(struct ld_xinfo *info_ptr) { + return DoGetLDXINFO(info_ptr); +} +#endif + Status Process::GetMemoryRegions(lldb_private::MemoryRegionInfos ®ion_list) { Status error; diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index a61228d092d89..57f42ea56cb18 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -40,6 +40,9 @@ #include #include +#ifdef __AIX__ +#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" +#endif using namespace lldb; using namespace lldb_private; @@ -1257,6 +1260,10 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( // Answer the question: Where did THIS frame save the CALLER frame ("previous" // frame)'s register value? +#ifdef __AIX__ +extern bool UGLY_HACK_NULL_TOPFRAME; +#endif + enum UnwindLLDB::RegisterSearchResult RegisterContextUnwind::SavedLocationForRegister( uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc) { @@ -1517,6 +1524,11 @@ RegisterContextUnwind::SavedLocationForRegister( new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext; new_regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); +#ifdef __AIX__ + if (UGLY_HACK_NULL_TOPFRAME && new_regloc.location.register_number == 0x20) { + new_regloc.location.register_number = 0x24; + } +#endif m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; regloc = new_regloc; UnwindLogMsg("supplying caller's register %s (%d) from the live " @@ -2368,6 +2380,40 @@ bool RegisterContextUnwind::ReadPC(addr_t &pc) { } } +#ifdef __AIX__ +bool RegisterContextUnwind::ReadLR(addr_t &lr) { + if (!IsValid()) + return false; + + bool above_trap_handler = false; + if (GetNextFrame().get() && GetNextFrame()->IsValid() && + GetNextFrame()->IsTrapHandlerFrame()) + above_trap_handler = true; + + if (ReadGPRValue(eRegisterKindLLDB, gpr_lr_ppc64le, lr)) { + // A lr value of 0 or 1 is impossible in the middle of the stack -- it + // indicates the end of a stack walk. + // On the currently executing frame (or such a frame interrupted + // asynchronously by sigtramp et al) this may occur if code has jumped + // through a NULL pointer -- we want to be able to unwind past that frame + // to help find the bug. + + ProcessSP process_sp (m_thread.GetProcess()); + if (process_sp) + { + ABI *abi = process_sp->GetABI().get(); + if (abi) + lr = abi->FixCodeAddress(lr); + } + + return !(m_all_registers_available == false && + above_trap_handler == false && (lr == 0 || lr == 1)); + } else { + return false; + } +} +#endif + void RegisterContextUnwind::UnwindLogMsg(const char *fmt, ...) { Log *log = GetLog(LLDBLog::Unwind); if (!log) diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp index 50dcb66b9719f..0926579ea2930 100644 --- a/lldb/source/Target/ThreadPlanCallFunction.cpp +++ b/lldb/source/Target/ThreadPlanCallFunction.cpp @@ -127,6 +127,40 @@ ThreadPlanCallFunction::ThreadPlanCallFunction( m_valid = true; } +ThreadPlanCallFunction::ThreadPlanCallFunction( + Thread &thread, const Address &function, const Address &toc, + const CompilerType &return_type, + llvm::ArrayRef args, const EvaluateExpressionOptions &options) + : ThreadPlan(ThreadPlan::eKindCallFunction, "Call function plan", thread, + eVoteNoOpinion, eVoteNoOpinion), + m_valid(false), m_stop_other_threads(options.GetStopOthers()), + m_unwind_on_error(options.DoesUnwindOnError()), + m_ignore_breakpoints(options.DoesIgnoreBreakpoints()), + m_debug_execution(options.GetDebug()), + m_trap_exceptions(options.GetTrapExceptions()), m_function_addr(function), + m_function_sp(0), m_takedown_done(false), + m_should_clear_objc_exception_bp(false), + m_should_clear_cxx_exception_bp(false), + m_stop_address(LLDB_INVALID_ADDRESS), m_return_type(return_type) { + lldb::addr_t start_load_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t function_load_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t toc_addr = LLDB_INVALID_ADDRESS; + ABI *abi = nullptr; + + if (!ConstructorSetup(thread, abi, start_load_addr, function_load_addr)) + return; + + toc_addr = toc.GetLoadAddress(&GetTarget()); + + if (!abi->PrepareTrivialCall(thread, m_function_sp, function_load_addr, + toc_addr, start_load_addr, args)) + return; + + ReportRegisterState("Function call was set up. Register state was:"); + + m_valid = true; +} + ThreadPlanCallFunction::ThreadPlanCallFunction( Thread &thread, const Address &function, const EvaluateExpressionOptions &options) diff --git a/lldb/source/Target/UnwindLLDB.cpp b/lldb/source/Target/UnwindLLDB.cpp index f43e940492b09..255b829738ba2 100644 --- a/lldb/source/Target/UnwindLLDB.cpp +++ b/lldb/source/Target/UnwindLLDB.cpp @@ -68,6 +68,10 @@ uint32_t UnwindLLDB::DoGetFrameCount() { return m_frames.size(); } +#ifdef __AIX__ +bool UGLY_HACK_NULL_TOPFRAME = false; +#endif + bool UnwindLLDB::AddFirstFrame() { if (m_frames.size() > 0) return true; @@ -91,6 +95,17 @@ bool UnwindLLDB::AddFirstFrame() { if (!reg_ctx_sp->ReadPC(first_cursor_sp->start_pc)) goto unwind_done; +#ifdef __AIX__ + lldb::addr_t lr; + if (!reg_ctx_sp->ReadLR(lr)) + goto unwind_done; + + if (first_cursor_sp->start_pc == 0) { + first_cursor_sp->start_pc = lr; + UGLY_HACK_NULL_TOPFRAME = true; + } +#endif + // Everything checks out, so release the auto pointer value and let the // cursor own it in its shared pointer first_cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp; diff --git a/lldb/source/Utility/ArchSpec.cpp b/lldb/source/Utility/ArchSpec.cpp index 07ef435ef451d..3868f77169cc6 100644 --- a/lldb/source/Utility/ArchSpec.cpp +++ b/lldb/source/Utility/ArchSpec.cpp @@ -14,6 +14,7 @@ #include "lldb/lldb-defines.h" #include "llvm/ADT/STLExtras.h" #include "llvm/BinaryFormat/COFF.h" +#include "llvm/BinaryFormat/XCOFF.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Compiler.h" @@ -459,10 +460,22 @@ static const ArchDefinition g_coff_arch_def = { "pe-coff", }; +static const ArchDefinitionEntry g_xcoff_arch_entries[] = { + {ArchSpec::eCore_ppc_generic, llvm::XCOFF::TCPU_COM, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, + {ArchSpec::eCore_ppc64_generic, llvm::XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu} +}; + +static const ArchDefinition g_xcoff_arch_def = { + eArchTypeXCOFF, + std::size(g_xcoff_arch_entries), + g_xcoff_arch_entries, + "xcoff", +}; + //===----------------------------------------------------------------------===// // Table of all ArchDefinitions static const ArchDefinition *g_arch_definitions[] = { - &g_macho_arch_def, &g_elf_arch_def, &g_coff_arch_def}; + &g_macho_arch_def, &g_elf_arch_def, &g_coff_arch_def, &g_xcoff_arch_def}; //===----------------------------------------------------------------------===// // Static helper functions. @@ -903,6 +916,9 @@ bool ArchSpec::SetArchitecture(ArchitectureType arch_type, uint32_t cpu, } else if (arch_type == eArchTypeCOFF && os == llvm::Triple::Win32) { m_triple.setVendor(llvm::Triple::PC); m_triple.setOS(llvm::Triple::Win32); + } else if (arch_type == eArchTypeXCOFF && os == llvm::Triple::AIX) { + m_triple.setVendor(llvm::Triple::IBM); + m_triple.setOS(llvm::Triple::AIX); } else { m_triple.setVendor(llvm::Triple::UnknownVendor); m_triple.setOS(llvm::Triple::UnknownOS); diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp index 9f79d2271b1e6..dbd3236536f8c 100644 --- a/lldb/source/Utility/StringExtractorGDBRemote.cpp +++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -227,6 +227,8 @@ StringExtractorGDBRemote::GetServerPacketType() const { return eServerPacketType_qLaunchGDBServer; if (PACKET_MATCHES("qLaunchSuccess")) return eServerPacketType_qLaunchSuccess; + if (PACKET_MATCHES("qLDXINFO")) + return eServerPacketType_qLDXINFO; break; case 'M': diff --git a/lldb/test/CMakeLists.txt b/lldb/test/CMakeLists.txt index 5ac474736eb63..413a1e5120288 100644 --- a/lldb/test/CMakeLists.txt +++ b/lldb/test/CMakeLists.txt @@ -155,7 +155,7 @@ if(TARGET clang) add_lldb_test_dependency(clang) # TestFullLtoStepping depends on LTO, and only runs when the compiler is clang. - add_lldb_test_dependency(LTO) + #add_lldb_test_dependency(LTO) if (TARGET libcxx OR ("libcxx" IN_LIST LLVM_ENABLE_RUNTIMES)) set(LLDB_HAS_LIBCXX ON) diff --git a/lldb/test/Shell/Expr/TestIRMemoryMap.test b/lldb/test/Shell/Expr/TestIRMemoryMap.test index 9dd0413be14cf..5ed61ad33ffc4 100644 --- a/lldb/test/Shell/Expr/TestIRMemoryMap.test +++ b/lldb/test/Shell/Expr/TestIRMemoryMap.test @@ -1,6 +1,6 @@ # UNSUPPORTED: system-windows -# RUN: %clangxx_host %p/Inputs/call-function.cpp -g -o %t +# RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t # RUN: lldb-test ir-memory-map %t %S/Inputs/ir-memory-map-basic # RUN: lldb-test ir-memory-map -host-only %t %S/Inputs/ir-memory-map-basic diff --git a/lldb/test/Shell/Process/TestEnvironment.test b/lldb/test/Shell/Process/TestEnvironment.test index e6d6e56fc9203..2ead258719f32 100644 --- a/lldb/test/Shell/Process/TestEnvironment.test +++ b/lldb/test/Shell/Process/TestEnvironment.test @@ -3,7 +3,7 @@ UNSUPPORTED: lldb-repro The double quotes around "BAR" ensure we don't match the command. -RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t +RUN: %clangxx_host -std=c++11 -I/compgpfs/build/xlcit/rings/openxlC/aix/wyvern_dev/ring0/latest/opt/IBM/openxlC/17.1.2/include/c++/v1/ %p/Inputs/env.cpp -o %t RUN: %lldb %t -o 'process launch --environment FOO="BAR"' | FileCheck %s RUN: %lldb %t -o 'env FOO="BAR"' -o 'process launch' | FileCheck %s diff --git a/lldb/tools/driver/CMakeLists.txt b/lldb/tools/driver/CMakeLists.txt index cd304a047dea6..78617be24f780 100644 --- a/lldb/tools/driver/CMakeLists.txt +++ b/lldb/tools/driver/CMakeLists.txt @@ -11,6 +11,11 @@ if(APPLE) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_BINARY_DIR}/lldb-Info.plist") endif() +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + add_lldb_tool(lldb Driver.cpp Platform.cpp diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp index 14371da64f2f2..f7eaf56738d7d 100644 --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -639,7 +639,7 @@ void sigwinch_handler(int signo) { } void sigint_handler(int signo) { -#ifdef _WIN32 // Restore handler as it is not persistent on Windows +#if defined(_WIN32) || defined(__AIX__) // Restore handler as it is not persistent on Windows signal(SIGINT, sigint_handler); #endif static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT; @@ -727,8 +727,11 @@ static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) { int main(int argc, char const *argv[]) { // Editline uses for example iswprint which is dependent on LC_CTYPE. + // FIXME: this caused unexpected SIGTRAP on AIX +#ifndef __AIX__ std::setlocale(LC_ALL, ""); std::setlocale(LC_CTYPE, ""); +#endif // Setup LLVM signal handlers and make sure we call llvm_shutdown() on // destruction. diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index f8f0d86453f58..2fa6f6c9a5369 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -6,6 +6,10 @@ if (HAVE_LIBPTHREAD) list(APPEND extra_libs pthread) endif () +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + add_definitions("-D_AIX") + add_definitions("-D_ALL_SOURCE") +endif() if(APPLE) configure_file( diff --git a/lldb/tools/lldb-server/CMakeLists.txt b/lldb/tools/lldb-server/CMakeLists.txt index 9030ed709a647..0d69ae32a008f 100644 --- a/lldb/tools/lldb-server/CMakeLists.txt +++ b/lldb/tools/lldb-server/CMakeLists.txt @@ -8,6 +8,10 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux|Android") list(APPEND LLDB_PLUGINS lldbPluginProcessLinux) endif() +if(CMAKE_SYSTEM_NAME MATCHES "AIX") + list(APPEND LLDB_PLUGINS lldbPluginProcessAIX) +endif() + if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") list(APPEND LLDB_PLUGINS lldbPluginProcessFreeBSD) endif() @@ -20,6 +24,8 @@ if(CMAKE_SYSTEM_NAME MATCHES "Darwin") list(APPEND LLDB_PLUGINS lldbPluginObjectFileMachO) elseif(CMAKE_SYSTEM_NAME MATCHES "Windows") list(APPEND LLDB_PLUGINS lldbPluginObjectFilePECOFF) +elseif(CMAKE_SYSTEM_NAME MATCHES "AIX") + list(APPEND LLDB_PLUGINS lldbPluginObjectFileXCOFF) else() list(APPEND LLDB_PLUGINS lldbPluginObjectFileELF) endif() @@ -54,6 +60,7 @@ add_lldb_tool(lldb-server lldbPluginInstructionMIPS lldbPluginInstructionMIPS64 lldbPluginInstructionRISCV + lldbPluginInstructionPPC64 ${LLDB_SYSTEM_LIBS} LINK_COMPONENTS diff --git a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp index 4233252a84dfc..91bb2083a88b5 100644 --- a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp +++ b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp @@ -14,6 +14,9 @@ using HostObjectFile = ObjectFileMachO; #elif defined(_WIN32) #include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" using HostObjectFile = ObjectFilePECOFF; +#elif defined(__AIX__) +#include "Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h" +using HostObjectFile = ObjectFileXCOFF; #else #include "Plugins/ObjectFile/ELF/ObjectFileELF.h" using HostObjectFile = ObjectFileELF; @@ -46,6 +49,10 @@ using HostObjectFile = ObjectFileELF; #include "Plugins/Instruction/MIPS/EmulateInstructionMIPS.h" #endif +#if defined(__AIX__) +#include "Plugins/Instruction/PPC64/EmulateInstructionPPC64.h" +#endif + #if defined(__riscv) #define LLDB_TARGET_RISCV #include "Plugins/Instruction/RISCV/EmulateInstructionRISCV.h" @@ -75,6 +82,10 @@ llvm::Error SystemInitializerLLGS::Initialize() { EmulateInstructionRISCV::Initialize(); #endif +#if defined(__AIX__) + EmulateInstructionPPC64::Initialize(); +#endif + return llvm::Error::success(); } @@ -97,5 +108,9 @@ void SystemInitializerLLGS::Terminate() { EmulateInstructionRISCV::Terminate(); #endif +#if defined(__AIX__) + EmulateInstructionPPC64::Terminate(); +#endif + SystemInitializerCommon::Terminate(); } diff --git a/lldb/tools/lldb-server/lldb-gdbserver.cpp b/lldb/tools/lldb-server/lldb-gdbserver.cpp index 563284730bc70..2a14f4f9c82aa 100644 --- a/lldb/tools/lldb-server/lldb-gdbserver.cpp +++ b/lldb/tools/lldb-server/lldb-gdbserver.cpp @@ -45,6 +45,8 @@ #include "Plugins/Process/NetBSD/NativeProcessNetBSD.h" #elif defined(_WIN32) #include "Plugins/Process/Windows/Common/NativeProcessWindows.h" +#elif defined(__AIX__) +#include "Plugins/Process/AIX/NativeProcessAIX.h" #endif #ifndef LLGS_PROGRAM_NAME @@ -70,6 +72,8 @@ typedef process_freebsd::NativeProcessFreeBSD::Manager NativeProcessManager; typedef process_netbsd::NativeProcessNetBSD::Manager NativeProcessManager; #elif defined(_WIN32) typedef NativeProcessWindows::Manager NativeProcessManager; +#elif defined(__AIX__) +typedef process_aix::NativeProcessAIX::Manager NativeProcessManager; #else // Dummy implementation to make sure the code compiles class NativeProcessManager : public NativeProcessProtocol::Manager { diff --git a/lldb/unittests/Host/FileSystemTest.cpp b/lldb/unittests/Host/FileSystemTest.cpp index 58887f6b2467e..89d0f5b87171a 100644 --- a/lldb/unittests/Host/FileSystemTest.cpp +++ b/lldb/unittests/Host/FileSystemTest.cpp @@ -59,7 +59,7 @@ class DummyFileSystem : public vfs::FileSystem { return I->second; } ErrorOr> - openFileForRead(const Twine &Path) override { + openFileForRead(const Twine &Path, bool IsText) override { auto S = status(Path); if (S) return std::unique_ptr(new DummyFile{*S}); diff --git a/lldb/unittests/Host/posix/TerminalTest.cpp b/lldb/unittests/Host/posix/TerminalTest.cpp index 5187a0c20a68b..f3de92c0852b1 100644 --- a/lldb/unittests/Host/posix/TerminalTest.cpp +++ b/lldb/unittests/Host/posix/TerminalTest.cpp @@ -94,15 +94,19 @@ TEST_F(TerminalTest, SetRaw) { TEST_F(TerminalTest, SetBaudRate) { struct termios terminfo; +#if (defined(__AIX__) && defined(B38400)) || !defined(__AIX__) ASSERT_THAT_ERROR(m_term.SetBaudRate(38400), llvm::Succeeded()); ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0); EXPECT_EQ(cfgetispeed(&terminfo), static_cast(B38400)); EXPECT_EQ(cfgetospeed(&terminfo), static_cast(B38400)); +#endif +#if (defined(__AIX__) && defined(B115200)) || !defined(__AIX__) ASSERT_THAT_ERROR(m_term.SetBaudRate(115200), llvm::Succeeded()); ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0); EXPECT_EQ(cfgetispeed(&terminfo), static_cast(B115200)); EXPECT_EQ(cfgetospeed(&terminfo), static_cast(B115200)); +#endif // uncommon value #if defined(B153600) diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h index 5a7cd8e38f2b7..fa9c6781e24f5 100644 --- a/llvm/include/llvm/Object/XCOFFObjectFile.h +++ b/llvm/include/llvm/Object/XCOFFObjectFile.h @@ -542,7 +542,6 @@ class XCOFFObjectFile : public ObjectFile { template const T *sectionHeaderTable() const; size_t getFileHeaderSize() const; - size_t getSectionHeaderSize() const; const XCOFFSectionHeader32 *toSection32(DataRefImpl Ref) const; const XCOFFSectionHeader64 *toSection64(DataRefImpl Ref) const; @@ -578,6 +577,9 @@ class XCOFFObjectFile : public ObjectFile { void checkSectionAddress(uintptr_t Addr, uintptr_t TableAddr) const; public: + size_t getSectionHeaderSize() const; + Expected getLoaderSectionAddress() const; + static constexpr uint64_t InvalidRelocOffset = std::numeric_limits::max(); diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp index bdd04b00f557b..9c96df1bbdc54 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -251,10 +251,16 @@ Expected DWARFUnit::getStringOffsetSectionItem(uint32_t Index) const { return DA.getRelocatedValue(ItemSize, &Offset); } +bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; + Error DWARFUnitHeader::extract(DWARFContext &Context, const DWARFDataExtractor &debug_info, uint64_t *offset_ptr, DWARFSectionKind SectionKind) { + if (UGLY_FLAG_FOR_AIX) { + // FIXME: hack to get version + *offset_ptr += 8; + } Offset = *offset_ptr; Error Err = Error::success(); IndexEntry = nullptr; @@ -267,8 +273,13 @@ Error DWARFUnitHeader::extract(DWARFContext &Context, AbbrOffset = debug_info.getRelocatedValue( FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err); } else { - AbbrOffset = debug_info.getRelocatedValue( - FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err); + if (UGLY_FLAG_FOR_AIX) { + AbbrOffset = debug_info.getRelocatedValue( + 8, offset_ptr, nullptr, &Err); + } else { + AbbrOffset = debug_info.getRelocatedValue( + FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err); + } FormParams.AddrSize = debug_info.getU8(offset_ptr, &Err); // Fake a unit type based on the section type. This isn't perfect, // but distinguishing compile and type units is generally enough. >From b1da5b1cf35829fcbf4ad6564c6005c755012e47 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 7 Aug 2024 12:18:45 -0500 Subject: [PATCH 02/47] Code license notice --- lldb/NOTICE.TXT | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 lldb/NOTICE.TXT diff --git a/lldb/NOTICE.TXT b/lldb/NOTICE.TXT new file mode 100644 index 0000000000000..d814272967476 --- /dev/null +++ b/lldb/NOTICE.TXT @@ -0,0 +1,7 @@ + +This product contains small piece of code to support AIX, taken from netbsd. + + * LICENSE: + * lldb/source/Host/common/LICENSE.aix-netbsd.txt (OpenSSL License) + * HOMEPAGE: + * https://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/crypto/external/bsd/openssl/dist >From 50ad673a78029fd6c47d90317e2c61ca2b59d5c5 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 7 Aug 2024 13:27:20 -0500 Subject: [PATCH 03/47] Reverting .tests --- lldb/test/Shell/Expr/TestIRMemoryMap.test | 2 +- lldb/test/Shell/Process/TestEnvironment.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/test/Shell/Expr/TestIRMemoryMap.test b/lldb/test/Shell/Expr/TestIRMemoryMap.test index 5ed61ad33ffc4..9dd0413be14cf 100644 --- a/lldb/test/Shell/Expr/TestIRMemoryMap.test +++ b/lldb/test/Shell/Expr/TestIRMemoryMap.test @@ -1,6 +1,6 @@ # UNSUPPORTED: system-windows -# RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t +# RUN: %clangxx_host %p/Inputs/call-function.cpp -g -o %t # RUN: lldb-test ir-memory-map %t %S/Inputs/ir-memory-map-basic # RUN: lldb-test ir-memory-map -host-only %t %S/Inputs/ir-memory-map-basic diff --git a/lldb/test/Shell/Process/TestEnvironment.test b/lldb/test/Shell/Process/TestEnvironment.test index 2ead258719f32..e6d6e56fc9203 100644 --- a/lldb/test/Shell/Process/TestEnvironment.test +++ b/lldb/test/Shell/Process/TestEnvironment.test @@ -3,7 +3,7 @@ UNSUPPORTED: lldb-repro The double quotes around "BAR" ensure we don't match the command. -RUN: %clangxx_host -std=c++11 -I/compgpfs/build/xlcit/rings/openxlC/aix/wyvern_dev/ring0/latest/opt/IBM/openxlC/17.1.2/include/c++/v1/ %p/Inputs/env.cpp -o %t +RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t RUN: %lldb %t -o 'process launch --environment FOO="BAR"' | FileCheck %s RUN: %lldb %t -o 'env FOO="BAR"' -o 'process launch' | FileCheck %s >From c1967be8fe14d469cb5ae9d41d115a7003ff39b6 Mon Sep 17 00:00:00 2001 From: Lakshmi Surekha Kovvuri Date: Thu, 22 Aug 2024 08:49:50 -0500 Subject: [PATCH 04/47] For TestSuite Run --- lldb/unittests/Host/FileSystemTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/unittests/Host/FileSystemTest.cpp b/lldb/unittests/Host/FileSystemTest.cpp index 89d0f5b87171a..58887f6b2467e 100644 --- a/lldb/unittests/Host/FileSystemTest.cpp +++ b/lldb/unittests/Host/FileSystemTest.cpp @@ -59,7 +59,7 @@ class DummyFileSystem : public vfs::FileSystem { return I->second; } ErrorOr> - openFileForRead(const Twine &Path, bool IsText) override { + openFileForRead(const Twine &Path) override { auto S = status(Path); if (S) return std::unique_ptr(new DummyFile{*S}); >From 758ab642d0974e799ac902d8ad240a3a90aeb24d Mon Sep 17 00:00:00 2001 From: Lakshmi Surekha Kovvuri Date: Fri, 30 Aug 2024 08:33:32 -0500 Subject: [PATCH 05/47] Changes made to AIX-specific files to eliminate errors encountered during CI when updating LLDB. --- .../Plugins/Process/AIX/NativeProcessAIX.cpp | 20 ++++++++++--------- .../Process/AIX/NativeRegisterContextAIX.cpp | 4 ++-- .../AIX/NativeRegisterContextAIX_ppc64.cpp | 10 +++++----- .../Plugins/Process/AIX/NativeThreadAIX.cpp | 2 +- .../GDBRemoteCommunicationClient.cpp | 4 ++-- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp index 882f20d30a3bf..5b01a66b0453f 100644 --- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -211,12 +211,14 @@ static Status EnsureFDFlags(int fd, int flags) { int status = fcntl(fd, F_GETFL); if (status == -1) { - error.SetErrorToErrno(); + error = Status::FromErrno(); + // error.SetErrorToErrno(); return error; } if (fcntl(fd, F_SETFL, status | flags) == -1) { - error.SetErrorToErrno(); + error = Status::FromErrno(); + // error.SetErrorToErrno(); return error; } @@ -813,7 +815,7 @@ Status NativeProcessAIX::Resume(const ResumeActionList &resume_actions) { Status error = ResumeThread(static_cast(*thread), action->state, signo); if (error.Fail()) - return Status("NativeProcessAIX::%s: failed to resume thread " + return Status::FromErrorStringWithFormat("NativeProcessAIX::%s: failed to resume thread " "for pid %" PRIu64 ", tid %" PRIu64 ", error = %s", __FUNCTION__, GetID(), thread->GetID(), error.AsCString()); @@ -826,7 +828,7 @@ Status NativeProcessAIX::Resume(const ResumeActionList &resume_actions) { break; default: - return Status("NativeProcessAIX::%s (): unexpected state %s specified " + return Status::FromErrorStringWithFormat("NativeProcessAIX::%s (): unexpected state %s specified " "for pid %" PRIu64 ", tid %" PRIu64, __FUNCTION__, StateAsCString(action->state), GetID(), thread->GetID()); @@ -840,7 +842,7 @@ Status NativeProcessAIX::Halt() { Status error; if (kill(GetID(), SIGSTOP) != 0) - error.SetErrorToErrno(); + error = Status::FromErrno(); return error; } @@ -874,7 +876,7 @@ Status NativeProcessAIX::Signal(int signo) { Host::GetSignalAsCString(signo), GetID()); if (kill(GetID(), signo)) - error.SetErrorToErrno(); + error = Status::FromErrno(); return error; } @@ -951,7 +953,7 @@ Status NativeProcessAIX::Kill() { } if (kill(GetID(), SIGKILL) != 0) { - error.SetErrorToErrno(); + error = Status::FromErrno(); return error; } @@ -1555,7 +1557,7 @@ Status NativeProcessAIX::GetLoadedModuleFileSpec(const char *module_path, return Status(); } } - return Status("Module file (%s) not found in /proc/%" PRIu64 "/maps file!", + return Status::FromErrorStringWithFormat("Module file (%s) not found in /proc/%" PRIu64 "/maps file!", module_file_spec.GetFilename().AsCString(), GetID()); } @@ -2011,7 +2013,7 @@ Status NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid, void *addr, } if (errno) { - error.SetErrorToErrno(); + error = Status::FromErrno(); ret = -1; } diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp index 0859f9501c1b6..071e55543cc3c 100644 --- a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp @@ -27,7 +27,7 @@ Status NativeRegisterContextAIX::ReadRegisterRaw(uint32_t reg_index, RegisterValue ®_value) { const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); if (!reg_info) - return Status("register %" PRIu32 " not found", reg_index); + return Status::FromErrorStringWithFormat("register %" PRIu32 " not found", reg_index); return DoReadRegisterValue(GetPtraceOffset(reg_index), reg_info->name, reg_info->byte_size, reg_value); @@ -82,7 +82,7 @@ NativeRegisterContextAIX::WriteRegisterRaw(uint32_t reg_index, assert(register_to_write_info_p && "register to write does not have valid RegisterInfo"); if (!register_to_write_info_p) - return Status("NativeRegisterContextAIX::%s failed to get RegisterInfo " + return Status::FromErrorStringWithFormat("NativeRegisterContextAIX::%s failed to get RegisterInfo " "for write register index %" PRIu32, __FUNCTION__, reg_to_write); diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp index 1996373791748..0132b52dec6f2 100644 --- a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp @@ -165,7 +165,7 @@ Status NativeRegisterContextAIX_ppc64::ReadRegister( Status error; if (!reg_info) { - error.SetErrorString("reg_info NULL"); + error.FromErrorString("reg_info NULL"); return error; } @@ -251,7 +251,7 @@ Status NativeRegisterContextAIX_ppc64::WriteRegister( const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; if (reg_index == LLDB_INVALID_REGNUM) - return Status("no lldb regnum for %s", reg_info && reg_info->name + return Status::FromErrorStringWithFormat("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : ""); @@ -389,14 +389,14 @@ Status NativeRegisterContextAIX_ppc64::WriteAllRegisterValues( Status error; if (!data_sp) { - error.SetErrorStringWithFormat( + error = Status::FromErrorStringWithFormat( "NativeRegisterContextAIX_ppc64::%s invalid data_sp provided", __FUNCTION__); return error; } if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { - error.SetErrorStringWithFormat( + error = Status::FromErrorStringWithFormat( "NativeRegisterContextAIX_ppc64::%s data_sp contained mismatched " "data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); @@ -405,7 +405,7 @@ Status NativeRegisterContextAIX_ppc64::WriteAllRegisterValues( const uint8_t *src = data_sp->GetBytes(); if (src == nullptr) { - error.SetErrorStringWithFormat("NativeRegisterContextAIX_ppc64::%s " + error = Status::FromErrorStringWithFormat("NativeRegisterContextAIX_ppc64::%s " "DataBuffer::GetBytes() returned a null " "pointer", __FUNCTION__); diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp index e07daccdff550..bb14b6ab4a05e 100644 --- a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp @@ -481,7 +481,7 @@ Status NativeThreadAIX::RequestStop() { Status err; errno = 0; if (::kill(pid, SIGSTOP) != 0) { - err.SetErrorToErrno(); + err = Status::FromErrno(); LLDB_LOGF(log, "NativeThreadAIX::%s kill(%" PRIu64 ", SIGSTOP) failed: %s", __FUNCTION__, pid, err.AsCString()); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 17926f8e4ab53..0aa68a4a09cbe 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -1728,11 +1728,11 @@ Status GDBRemoteCommunicationClient::GetLDXINFO(struct ld_xinfo *info_ptr) llvm::MutableArrayRef infoData((uint8_t *)info_ptr, sizeof(struct ld_xinfo)*64); size_t got_bytes = response.GetHexBytesAvail(infoData); if (got_bytes != sizeof(struct ld_xinfo)*64) { - error.SetErrorString("qLDXINFO ret bad size"); + error.FromErrorString("qLDXINFO ret bad size"); return error; } } else { - error.SetErrorString("qLDXINFO is not supported"); + error.FromErrorString("qLDXINFO is not supported"); } return error; } >From 33d561f4bb74a2efd0da163ebde416c9ad1c2925 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Tue, 10 Sep 2024 02:00:09 -0500 Subject: [PATCH 06/47] Removed non-required PTRACE defs --- lldb/include/lldb/Host/aix/Ptrace.h | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/lldb/include/lldb/Host/aix/Ptrace.h b/lldb/include/lldb/Host/aix/Ptrace.h index 88928f18102d7..393928a89add3 100644 --- a/lldb/include/lldb/Host/aix/Ptrace.h +++ b/lldb/include/lldb/Host/aix/Ptrace.h @@ -34,29 +34,11 @@ #ifndef PTRACE_SETREGSET #define PTRACE_SETREGSET 0x4205 #endif -#ifndef PTRACE_GET_THREAD_AREA -#define PTRACE_GET_THREAD_AREA (PT_COMMAND_MAX+5) -#endif -#ifndef PTRACE_ARCH_PRCTL -#define PTRACE_ARCH_PRCTL (PT_COMMAND_MAX+6) -#endif -#ifndef ARCH_GET_FS -#define ARCH_SET_GS 0x1001 -#define ARCH_SET_FS 0x1002 -#define ARCH_GET_FS 0x1003 -#define ARCH_GET_GS 0x1004 -#endif -#ifndef PTRACE_PEEKMTETAGS -#define PTRACE_PEEKMTETAGS (PT_COMMAND_MAX+7) -#endif -#ifndef PTRACE_POKEMTETAGS -#define PTRACE_POKEMTETAGS (PT_COMMAND_MAX+8) -#endif #ifndef PTRACE_GETVRREGS -#define PTRACE_GETVRREGS (PT_COMMAND_MAX+9) +#define PTRACE_GETVRREGS (PT_COMMAND_MAX+5) #endif #ifndef PTRACE_GETVSRREGS -#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+10) +#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+6) #endif #endif // liblldb_Host_aix_Ptrace_h_ >From 450793d7270999ecdd6714c4222663517dab3928 Mon Sep 17 00:00:00 2001 From: Lakshmi Surekha Kovvuri Date: Wed, 11 Sep 2024 02:52:41 -0500 Subject: [PATCH 07/47] Patch for running of unit testcases without hang --- lldb/unittests/Host/MainLoopTest.cpp | 4 +++- lldb/unittests/Host/PipeTest.cpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lldb/unittests/Host/MainLoopTest.cpp b/lldb/unittests/Host/MainLoopTest.cpp index 4084e90782fd5..9e92ec1470d4d 100644 --- a/lldb/unittests/Host/MainLoopTest.cpp +++ b/lldb/unittests/Host/MainLoopTest.cpp @@ -183,7 +183,7 @@ TEST_F(MainLoopTest, PendingCallbackAfterLoopExited) { loop.AddPendingCallback([&](MainLoopBase &loop) {}); } -#ifdef LLVM_ON_UNIX +#if defined(LLVM_ON_UNIX) && !defined(__AIX__) TEST_F(MainLoopTest, DetectsEOF) { PseudoTerminal term; @@ -202,7 +202,9 @@ TEST_F(MainLoopTest, DetectsEOF) { ASSERT_TRUE(loop.Run().Success()); ASSERT_EQ(1u, callback_count); } +// #endif +// #ifdef LLVM_ON_UNIX TEST_F(MainLoopTest, Signal) { MainLoop loop; Status error; diff --git a/lldb/unittests/Host/PipeTest.cpp b/lldb/unittests/Host/PipeTest.cpp index 506f3d225a21e..c1013aa7a7e4e 100644 --- a/lldb/unittests/Host/PipeTest.cpp +++ b/lldb/unittests/Host/PipeTest.cpp @@ -55,6 +55,7 @@ TEST_F(PipeTest, OpenAsReader) { } #endif +#if !defined(__AIX__) TEST_F(PipeTest, WriteWithTimeout) { Pipe pipe; ASSERT_THAT_ERROR(pipe.CreateNew(false).ToError(), llvm::Succeeded()); @@ -150,3 +151,4 @@ TEST_F(PipeTest, WriteWithTimeout) { .ToError(), llvm::Succeeded()); } +#endif >From 61e7843b431ff3657e3c4b39d1559401ff3de891 Mon Sep 17 00:00:00 2001 From: Lakshmi Surekha Kovvuri Date: Thu, 12 Sep 2024 13:22:03 -0500 Subject: [PATCH 08/47] changes applied to NativeProcessAIX.cpp file to solve build errors while making LLDB up to date --- .../Plugins/Process/AIX/NativeProcessAIX.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp index 5b01a66b0453f..fc84763857453 100644 --- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -862,7 +862,7 @@ Status NativeProcessAIX::Detach() { Status e = Detach(thread->GetID()); if (e.Fail()) error = - e; // Save the error, but still attempt to detach from other threads. + e.Clone(); // Save the error, but still attempt to detach from other threads. } return error; @@ -1240,7 +1240,7 @@ Status NativeProcessAIX::ReadMemoryTags(int32_t type, lldb::addr_t addr, llvm::Expected details = GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); if (!details) - return Status(details.takeError()); + return Status::FromError(details.takeError()); // Ignore 0 length read if (!len) @@ -1295,7 +1295,7 @@ Status NativeProcessAIX::WriteMemoryTags(int32_t type, lldb::addr_t addr, llvm::Expected details = GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); if (!details) - return Status(details.takeError()); + return Status::FromError(details.takeError()); // Ignore 0 length write if (!len) @@ -1312,18 +1312,18 @@ Status NativeProcessAIX::WriteMemoryTags(int32_t type, lldb::addr_t addr, llvm::Expected> unpacked_tags_or_err = details->manager->UnpackTagsData(tags); if (!unpacked_tags_or_err) - return Status(unpacked_tags_or_err.takeError()); + return Status::FromError(unpacked_tags_or_err.takeError()); llvm::Expected> repeated_tags_or_err = details->manager->RepeatTagsForRange(*unpacked_tags_or_err, range); if (!repeated_tags_or_err) - return Status(repeated_tags_or_err.takeError()); + return Status::FromError(repeated_tags_or_err.takeError()); // Repack them for ptrace to use llvm::Expected> final_tag_data = details->manager->PackTags(*repeated_tags_or_err); if (!final_tag_data) - return Status(final_tag_data.takeError()); + return Status::FromError(final_tag_data.takeError()); struct iovec tags_vec; uint8_t *src = final_tag_data->data(); @@ -1609,13 +1609,13 @@ Status NativeProcessAIX::ResumeThread(NativeThreadAIX &thread, // reflect it is running after this completes. switch (state) { case eStateRunning: { - const auto resume_result = thread.Resume(signo); + Status resume_result = thread.Resume(signo); if (resume_result.Success()) SetState(eStateRunning, true); return resume_result; } case eStateStepping: { - const auto step_result = thread.SingleStep(signo); + Status step_result = thread.SingleStep(signo); if (step_result.Success()) SetState(eStateRunning, true); return step_result; >From 627a5427daba3fc5ea03ae481874f4aa1b4d2ed0 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Fri, 13 Sep 2024 16:25:47 +0530 Subject: [PATCH 09/47] Revert "Removed non-required PTRACE defs" --- lldb/include/lldb/Host/aix/Ptrace.h | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/lldb/include/lldb/Host/aix/Ptrace.h b/lldb/include/lldb/Host/aix/Ptrace.h index 393928a89add3..88928f18102d7 100644 --- a/lldb/include/lldb/Host/aix/Ptrace.h +++ b/lldb/include/lldb/Host/aix/Ptrace.h @@ -34,11 +34,29 @@ #ifndef PTRACE_SETREGSET #define PTRACE_SETREGSET 0x4205 #endif +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA (PT_COMMAND_MAX+5) +#endif +#ifndef PTRACE_ARCH_PRCTL +#define PTRACE_ARCH_PRCTL (PT_COMMAND_MAX+6) +#endif +#ifndef ARCH_GET_FS +#define ARCH_SET_GS 0x1001 +#define ARCH_SET_FS 0x1002 +#define ARCH_GET_FS 0x1003 +#define ARCH_GET_GS 0x1004 +#endif +#ifndef PTRACE_PEEKMTETAGS +#define PTRACE_PEEKMTETAGS (PT_COMMAND_MAX+7) +#endif +#ifndef PTRACE_POKEMTETAGS +#define PTRACE_POKEMTETAGS (PT_COMMAND_MAX+8) +#endif #ifndef PTRACE_GETVRREGS -#define PTRACE_GETVRREGS (PT_COMMAND_MAX+5) +#define PTRACE_GETVRREGS (PT_COMMAND_MAX+9) #endif #ifndef PTRACE_GETVSRREGS -#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+6) +#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+10) #endif #endif // liblldb_Host_aix_Ptrace_h_ >From ea34b15d8568b4639b4e850ef032e684d82dd971 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Thu, 10 Oct 2024 00:38:18 -0500 Subject: [PATCH 10/47] Replaced __AIX__ with _AIX --- clang/test/SemaCXX/class-layout.cpp | 2 +- lldb/CMakeLists.txt | 2 +- lldb/include/lldb/Host/HostGetOpt.h | 2 +- lldb/include/lldb/Host/HostInfo.h | 2 +- lldb/include/lldb/Host/XML.h | 2 +- lldb/include/lldb/Host/common/GetOptInc.h | 4 ++-- lldb/include/lldb/Target/Process.h | 6 +++--- lldb/include/lldb/Target/RegisterContextUnwind.h | 2 +- lldb/source/Core/Mangled.cpp | 2 +- lldb/source/Core/Section.cpp | 2 +- lldb/source/Host/common/Host.cpp | 4 ++-- lldb/source/Host/common/XML.cpp | 2 +- lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp | 2 +- lldb/source/Host/posix/FileSystemPosix.cpp | 2 +- lldb/source/Host/posix/MainLoopPosix.cpp | 4 ++-- lldb/source/Host/posix/ProcessLauncherPosixFork.cpp | 2 +- lldb/source/Initialization/SystemInitializerCommon.cpp | 4 ++-- lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp | 4 ++-- .../DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 6 +++--- .../Plugins/Instruction/PPC64/EmulateInstructionPPC64.h | 2 +- lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp | 2 +- lldb/source/Plugins/Language/ObjC/Cocoa.cpp | 2 +- .../BSD-Archive/ObjectContainerBSDArchive.cpp | 2 +- .../Big-Archive/ObjectContainerBigArchive.cpp | 2 +- .../Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp | 2 +- lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp | 6 +++--- .../source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp | 6 +++--- lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp | 6 +++--- lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp | 4 ++-- .../Process/gdb-remote/GDBRemoteCommunicationClient.cpp | 4 ++-- .../Process/gdb-remote/GDBRemoteCommunicationClient.h | 4 ++-- .../gdb-remote/GDBRemoteCommunicationServerLLGS.cpp | 4 ++-- .../Plugins/Process/gdb-remote/ProcessGDBRemote.cpp | 4 ++-- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h | 4 ++-- lldb/source/Target/Process.cpp | 4 ++-- lldb/source/Target/RegisterContextUnwind.cpp | 8 ++++---- lldb/source/Target/UnwindLLDB.cpp | 4 ++-- lldb/tools/driver/Driver.cpp | 4 ++-- lldb/tools/lldb-server/SystemInitializerLLGS.cpp | 8 ++++---- lldb/tools/lldb-server/lldb-gdbserver.cpp | 4 ++-- lldb/unittests/Host/MainLoopTest.cpp | 2 +- lldb/unittests/Host/PipeTest.cpp | 2 +- lldb/unittests/Host/posix/TerminalTest.cpp | 4 ++-- 43 files changed, 75 insertions(+), 75 deletions(-) diff --git a/clang/test/SemaCXX/class-layout.cpp b/clang/test/SemaCXX/class-layout.cpp index 22fb34b8419c5..0931d905a9749 100644 --- a/clang/test/SemaCXX/class-layout.cpp +++ b/clang/test/SemaCXX/class-layout.cpp @@ -639,7 +639,7 @@ namespace PR37275 { #pragma pack(pop) } -#endif // !defined(__MVS__) && !defined(__AIX__) +#endif // !defined(__MVS__) && !defined(_AIX) namespace non_pod { struct t1 { diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt index 2e9ae0d0b3221..a4fd8bccf056d 100644 --- a/lldb/CMakeLists.txt +++ b/lldb/CMakeLists.txt @@ -39,7 +39,7 @@ include(LLDBConfig) include(AddLLDB) if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") - add_definitions("-D__AIX__") + add_definitions("-D_AIX") endif() # Define the LLDB_CONFIGURATION_xxx matching the build type. diff --git a/lldb/include/lldb/Host/HostGetOpt.h b/lldb/include/lldb/Host/HostGetOpt.h index f450e561d6afb..b2b436e64a692 100644 --- a/lldb/include/lldb/Host/HostGetOpt.h +++ b/lldb/include/lldb/Host/HostGetOpt.h @@ -9,7 +9,7 @@ #ifndef LLDB_HOST_HOSTGETOPT_H #define LLDB_HOST_HOSTGETOPT_H -#if !defined(_MSC_VER) && !defined(__NetBSD__) && !defined(__AIX__) +#if !defined(_MSC_VER) && !defined(__NetBSD__) && !defined(_AIX) #include #include diff --git a/lldb/include/lldb/Host/HostInfo.h b/lldb/include/lldb/Host/HostInfo.h index 156df8cf6901d..0f7ec0e0aa0d2 100644 --- a/lldb/include/lldb/Host/HostInfo.h +++ b/lldb/include/lldb/Host/HostInfo.h @@ -55,7 +55,7 @@ #elif defined(__APPLE__) #include "lldb/Host/macosx/HostInfoMacOSX.h" #define HOST_INFO_TYPE HostInfoMacOSX -#elif defined(__AIX__) +#elif defined(_AIX) #include "lldb/Host/aix/HostInfoAIX.h" #define HOST_INFO_TYPE HostInfoAIX #else diff --git a/lldb/include/lldb/Host/XML.h b/lldb/include/lldb/Host/XML.h index cf359f7726d5d..483589f1abc75 100644 --- a/lldb/include/lldb/Host/XML.h +++ b/lldb/include/lldb/Host/XML.h @@ -11,7 +11,7 @@ #include "lldb/Host/Config.h" -#if defined(__AIX__) +#if defined(_AIX) //FIXME for AIX #undef LLDB_ENABLE_LIBXML2 #endif diff --git a/lldb/include/lldb/Host/common/GetOptInc.h b/lldb/include/lldb/Host/common/GetOptInc.h index ebb475bfaf6b8..652e6174ff8b6 100644 --- a/lldb/include/lldb/Host/common/GetOptInc.h +++ b/lldb/include/lldb/Host/common/GetOptInc.h @@ -11,11 +11,11 @@ #include "lldb/lldb-defines.h" -#if defined(_MSC_VER) || defined(__AIX__) +#if defined(_MSC_VER) || defined(_AIX) #define REPLACE_GETOPT #define REPLACE_GETOPT_LONG #endif -#if defined(_MSC_VER) || defined(__NetBSD__) || defined(__AIX__) +#if defined(_MSC_VER) || defined(__NetBSD__) || defined(_AIX) #define REPLACE_GETOPT_LONG_ONLY #endif diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index 4a47ffd8d779d..d1527d316d678 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -65,7 +65,7 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/VersionTuple.h" -#if defined(__AIX__) +#if defined(_AIX) struct ld_xinfo; #endif @@ -1884,7 +1884,7 @@ class Process : public std::enable_shared_from_this, Status GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &range_info); -#if defined(__AIX__) +#if defined(_AIX) Status GetLDXINFO(struct ld_xinfo *info_ptr); #endif @@ -2823,7 +2823,7 @@ void PruneThreadPlans(); "Process::DoGetMemoryRegionInfo() not supported"); } -#if defined(__AIX__) +#if defined(_AIX) virtual Status DoGetLDXINFO(struct ld_xinfo *info_ptr) { return Status("Process::DoGetLDXINFO() not supported"); } diff --git a/lldb/include/lldb/Target/RegisterContextUnwind.h b/lldb/include/lldb/Target/RegisterContextUnwind.h index 46c06cb422caf..b6176f8e5727f 100644 --- a/lldb/include/lldb/Target/RegisterContextUnwind.h +++ b/lldb/include/lldb/Target/RegisterContextUnwind.h @@ -67,7 +67,7 @@ class RegisterContextUnwind : public lldb_private::RegisterContext { bool ReadPC(lldb::addr_t &start_pc); -#ifdef __AIX__ +#ifdef _AIX bool ReadLR(lldb::addr_t &lr); #endif diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp index 43c5b043ef7a2..8f2e3562f6577 100644 --- a/lldb/source/Core/Mangled.cpp +++ b/lldb/source/Core/Mangled.cpp @@ -167,7 +167,7 @@ static char *GetItaniumDemangledStr(const char *M) { "Expected demangled_size to return length including trailing null"); } -#if !defined(__AIX__) +#if !defined(_AIX) if (Log *log = GetLog(LLDBLog::Demangle)) { if (demangled_cstr) LLDB_LOGF(log, "demangled itanium: %s -> \"%s\"", M, demangled_cstr); diff --git a/lldb/source/Core/Section.cpp b/lldb/source/Core/Section.cpp index 9ed55853930a6..e0a9f7fcc7135 100644 --- a/lldb/source/Core/Section.cpp +++ b/lldb/source/Core/Section.cpp @@ -263,7 +263,7 @@ bool Section::ResolveContainedAddress(addr_t offset, Address &so_addr, bool Section::ContainsFileAddress(addr_t vm_addr) const { const addr_t file_addr = GetFileAddress(); -#ifdef __AIX__ +#ifdef _AIX if (file_addr == 0) return false; #endif diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 94b1d0fd57d07..dc48cb87b5ce6 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -358,7 +358,7 @@ bool Host::ResolveExecutableInBundle(FileSpec &file) { return false; } #ifndef _WIN32 -#if defined(__AIX__) +#if defined(_AIX) #include extern char **p_xargv; @@ -525,7 +525,7 @@ static int dladdr(const void *ptr, Dl_info *dl) FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSpec module_filespec; #if !defined(__ANDROID__) -#ifdef __AIX__ +#ifdef _AIX if (host_addr == reinterpret_cast(HostInfoBase::ComputeSharedLibraryDirectory)) { // FIXME: AIX dladdr return "lldb" for this case if (p_xargv[0]) { diff --git a/lldb/source/Host/common/XML.cpp b/lldb/source/Host/common/XML.cpp index 62cac78aaac23..fbc409105fe60 100644 --- a/lldb/source/Host/common/XML.cpp +++ b/lldb/source/Host/common/XML.cpp @@ -10,7 +10,7 @@ #include "lldb/Host/XML.h" #include "llvm/ADT/StringExtras.h" -#if defined(__AIX__) +#if defined(_AIX) #undef LLDB_ENABLE_LIBXML2 #endif diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index bd204c812b7e3..09c3fd2af6d3e 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -722,7 +722,7 @@ ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, ConnectionStatus ConnectionFileDescriptor::ConnectFile( llvm::StringRef s, socket_id_callback_type socket_id_callback, Status *error_ptr) { -#if !defined(__AIX__) +#if !defined(_AIX) #if LLDB_ENABLE_POSIX std::string addr_str = s.str(); // file:///PATH diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index 866fd8ac96c7b..21da5612ff6b8 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,7 +11,7 @@ // C includes #include #include -#if !defined(__AIX__) +#if !defined(_AIX) #include #endif #include diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp index d1eba52791a78..015570236b9d3 100644 --- a/lldb/source/Host/posix/MainLoopPosix.cpp +++ b/lldb/source/Host/posix/MainLoopPosix.cpp @@ -179,7 +179,7 @@ Status MainLoopPosix::RunImpl::Poll() { read_fds.push_back(pfd); } -#if defined(__AIX__) +#if defined(_AIX) sigset_t origmask; int timeout; @@ -325,7 +325,7 @@ MainLoopPosix::RegisterSignal(int signo, const Callback &callback, // If we're using kqueue, the signal needs to be unblocked in order to // receive it. If using pselect/ppoll, we need to block it, and later unblock // it as a part of the system call. -#if defined(__AIX__) +#if defined(_AIX) //FIXME: where is signal unblocked? ret = pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, &old_set); #else diff --git a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp index b8a96fbd19f02..f9f99decd39c2 100644 --- a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp +++ b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp @@ -193,7 +193,7 @@ struct ForkLaunchInfo { } // Start tracing this child that is about to exec. -#if !defined(__AIX__) +#if !defined(_AIX) if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1) ExitWithError(error_fd, "ptrace"); #else diff --git a/lldb/source/Initialization/SystemInitializerCommon.cpp b/lldb/source/Initialization/SystemInitializerCommon.cpp index 4b01442a94bac..2e2d622d9981c 100644 --- a/lldb/source/Initialization/SystemInitializerCommon.cpp +++ b/lldb/source/Initialization/SystemInitializerCommon.cpp @@ -19,7 +19,7 @@ #include "lldb/Version/Version.h" #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__OpenBSD__) || defined(__AIX__) + defined(__OpenBSD__) || defined(_AIX) #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" #endif @@ -79,7 +79,7 @@ llvm::Error SystemInitializerCommon::Initialize() { process_gdb_remote::ProcessGDBRemoteLog::Initialize(); #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__OpenBSD__) || defined(__AIX__) + defined(__OpenBSD__) || defined(_AIX) ProcessPOSIXLog::Initialize(); #endif #if defined(_WIN32) diff --git a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp index 88a82f4a0d20c..a3abb15ee625b 100644 --- a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp +++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp @@ -156,7 +156,7 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) return false; -#if defined(__AIX__) +#if defined(_AIX) assert(0); #else // Read TOC pointer value. @@ -279,7 +279,7 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) return false; -#if defined(__AIX__) +#if defined(_AIX) LLDB_LOGF(log, "Writing R2: 0x%" PRIx64, (uint64_t)toc_addr); if (!reg_ctx->WriteRegisterFromUnsigned(r2_reg_info, toc_addr)) return false; diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 62663974134b0..7f3a638d5b028 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -18,7 +18,7 @@ #include "lldb/Target/ThreadPlanStepInstruction.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -160,7 +160,7 @@ void DynamicLoaderAIXDYLD::DidAttach() { auto error = m_process->LoadModules(); LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}"); -#if defined(__AIX__) +#if defined(_AIX) // Get struct ld_xinfo (FIXME) struct ld_xinfo ldinfo[64]; Status status = m_process->GetLDXINFO(&(ldinfo[0])); @@ -221,7 +221,7 @@ void DynamicLoaderAIXDYLD::DidLaunch() { LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}"); } -#if defined(__AIX__) +#if defined(_AIX) // Get struct ld_xinfo (FIXME) struct ld_xinfo ldinfo[64]; Status status = m_process->GetLDXINFO(&(ldinfo[0])); diff --git a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h index 1576c9700e557..d98b2880ca3b4 100644 --- a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h +++ b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h @@ -39,7 +39,7 @@ class EmulateInstructionPPC64 : public EmulateInstruction { return true; case eInstructionTypePCModifying: -#if defined(__AIX__) +#if defined(_AIX) return true; #else return false; diff --git a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp index 690fb0d60a09a..9a52fb2f2adc5 100644 --- a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp +++ b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp @@ -194,7 +194,7 @@ void JITLoaderGDB::SetJITBreakpoint(lldb_private::ModuleList &module_list) { if (jit_addr == LLDB_INVALID_ADDRESS) return; -#if defined(__AIX__) +#if defined(_AIX) return; #endif diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index fb5bc2c58e6fb..71f2b127afb12 100644 --- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -1227,7 +1227,7 @@ bool lldb_private::formatters::ObjCSELSummaryProvider( time_t lldb_private::formatters::GetOSXEpoch() { static time_t epoch = 0; if (!epoch) { -#if !defined(__AIX__) +#if !defined(_AIX) #ifndef _WIN32 tzset(); tm tm_epoch; diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 5ea55772c3aba..4f747ab20c9ef 100644 --- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -8,7 +8,7 @@ #include "ObjectContainerBSDArchive.h" -#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__) +#if defined(_WIN32) || defined(__ANDROID__) || defined(_AIX) // Defines from ar, missing on Windows #define SARMAG 8 #define ARFMAG "`\n" diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp index 050ad73f1d19a..38756a0dd2969 100644 --- a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp @@ -8,7 +8,7 @@ #include "ObjectContainerBigArchive.h" -#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__) +#if defined(_WIN32) || defined(__ANDROID__) || defined(_AIX) // Defines from ar, missing on Windows #define ARMAG "!\n" #define SARMAG 8 diff --git a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp index d8834af2c33ef..9aab76c6c48ba 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp +++ b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp @@ -51,7 +51,7 @@ size_t ObjectFileMinidump::GetModuleSpecifications( const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, lldb_private::ModuleSpecList &specs) { -#if !defined(__AIX__) +#if !defined(_AIX) specs.Clear(); #endif return 0; diff --git a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp index 75cc54e4f0d48..d76d6adb1be2c 100644 --- a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp +++ b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp @@ -117,7 +117,7 @@ size_t ObjectFilePDB::GetModuleSpecifications( llvm::BumpPtrAllocator allocator; std::unique_ptr pdb_file = loadPDBFile(file.GetPath(), allocator); if (!pdb_file){ -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; @@ -127,7 +127,7 @@ size_t ObjectFilePDB::GetModuleSpecifications( auto info_stream = pdb_file->getPDBInfoStream(); if (!info_stream) { llvm::consumeError(info_stream.takeError()); -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; @@ -136,7 +136,7 @@ size_t ObjectFilePDB::GetModuleSpecifications( auto dbi_stream = pdb_file->getPDBDbiStream(); if (!dbi_stream) { llvm::consumeError(dbi_stream.takeError()); -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index 519ce2ca4a0b2..02a86234bd363 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -254,7 +254,7 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( lldb::offset_t length, lldb_private::ModuleSpecList &specs) { const size_t initial_count = specs.GetSize(); if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp)){ -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; @@ -272,7 +272,7 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( if (!binary) { LLDB_LOG_ERROR(log, binary.takeError(), "Failed to create binary for file ({1}): {0}", file); -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; @@ -281,7 +281,7 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( auto *COFFObj = llvm::dyn_cast(binary->get()); if (!COFFObj){ -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp index b6b08b73bec41..5c94477002978 100644 --- a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp +++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp @@ -31,7 +31,7 @@ // Define these constants from AIX mman.h for use when targeting remote aix // systems even when host has different values. -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -80,7 +80,7 @@ void PlatformAIX::Initialize() { PlatformPOSIX::Initialize(); if (g_initialize_count++ == 0) { -#if defined(__AIX__) +#if defined(_AIX) PlatformSP default_platform_sp(new PlatformAIX(true)); default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); Platform::SetHostPlatform(default_platform_sp); @@ -294,7 +294,7 @@ MmapArgList PlatformAIX::GetMmapArgumentList(const ArchSpec &arch, addr_t addr, addr_t length, unsigned prot, unsigned flags, addr_t fd, addr_t offset) { -#if defined(__AIX__) +#if defined(_AIX) unsigned flags_platform = MAP_VARIABLE | MAP_PRIVATE | MAP_ANONYMOUS; #else unsigned flags_platform = 0; diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index db271357d792a..ea758caa653a1 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -46,7 +46,7 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, function_options.include_inlines = false; SymbolContextList sc_list; -#if !defined(__AIX__) +#if !defined(_AIX) process->GetTarget().GetImages().FindFunctions( ConstString("mmap"), eFunctionNameTypeFull, function_options, sc_list); #else @@ -122,7 +122,7 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, MmapArgList args = process->GetTarget().GetPlatform()->GetMmapArgumentList( arch, addr, length, prot_arg, flags, fd, offset); -#if defined(__AIX__) +#if defined(_AIX) lldb::ThreadPlanSP call_plan_sp( new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(), toc_range.GetBaseAddress(), diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 443b7c7b2c7fb..fa0a3b5d4dc38 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -41,7 +41,7 @@ #include "llvm/Config/llvm-config.h" // for LLVM_ENABLE_ZLIB #include "llvm/Support/JSON.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -1715,7 +1715,7 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( return error; } -#if defined(__AIX__) +#if defined(_AIX) Status GDBRemoteCommunicationClient::GetLDXINFO(struct ld_xinfo *info_ptr) { Status error; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 520f37ac56716..1812fc9b7ca65 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -32,7 +32,7 @@ #include "llvm/Support/VersionTuple.h" -#if defined(__AIX__) +#if defined(_AIX) struct ld_xinfo; #endif @@ -200,7 +200,7 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase { Status GetMemoryRegionInfo(lldb::addr_t addr, MemoryRegionInfo &range_info); std::optional GetWatchpointSlotCount(); -#if defined(__AIX__) +#if defined(_AIX) Status GetLDXINFO(struct ld_xinfo *info_ptr); #endif diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 4f1ef0898ba08..27be61a474238 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -48,7 +48,7 @@ #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "lldb/Utility/StringExtractorGDBRemote.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -3011,7 +3011,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qLDXINFO(StringExtractorGDBRemote &pack return SendErrorResponse(0xff); } -#if defined(__AIX__) +#if defined(_AIX) // FIXME: buffer size struct ld_xinfo info[64]; if (ptrace64(PT_LDXINFO, m_current_process->GetID(), (long long)&(info[0]), sizeof(info), nullptr) != 0) { diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index ca381290d0e9f..5b7ce5f1424d9 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -92,7 +92,7 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/raw_ostream.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -2963,7 +2963,7 @@ Status ProcessGDBRemote::DoGetMemoryRegionInfo(addr_t load_addr, return error; } -#if defined(__AIX__) +#if defined(_AIX) Status ProcessGDBRemote::DoGetLDXINFO(struct ld_xinfo *info_ptr) { Status error(m_gdb_comm.GetLDXINFO(info_ptr)); return error; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 82200fbea21cd..2bf3a04d213d4 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -37,7 +37,7 @@ #include "GDBRemoteCommunicationClient.h" #include "GDBRemoteRegisterContext.h" -#if defined(__AIX__) +#if defined(_AIX) struct ld_xinfo; #endif @@ -427,7 +427,7 @@ class ProcessGDBRemote : public Process, Status DoGetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo ®ion_info) override; -#if defined(__AIX__) +#if defined(_AIX) Status DoGetLDXINFO(struct ld_xinfo *info_ptr) override; #endif diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index a9aef7ef21855..e6ae7fc559ef4 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -75,7 +75,7 @@ #include "lldb/Utility/State.h" #include "lldb/Utility/Timer.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -6188,7 +6188,7 @@ Status Process::GetMemoryRegionInfo(lldb::addr_t load_addr, return DoGetMemoryRegionInfo(load_addr, range_info); } -#if defined(__AIX__) +#if defined(_AIX) Status Process::GetLDXINFO(struct ld_xinfo *info_ptr) { return DoGetLDXINFO(info_ptr); } diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index fbdbc8c63a5d0..fdf269a3d3653 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -40,7 +40,7 @@ #include #include -#ifdef __AIX__ +#ifdef _AIX #include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" #endif @@ -1260,7 +1260,7 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( // Answer the question: Where did THIS frame save the CALLER frame ("previous" // frame)'s register value? -#ifdef __AIX__ +#ifdef _AIX extern bool UGLY_HACK_NULL_TOPFRAME; #endif @@ -1525,7 +1525,7 @@ RegisterContextUnwind::SavedLocationForRegister( new_regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterInLiveRegisterContext; new_regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); -#ifdef __AIX__ +#ifdef _AIX if (UGLY_HACK_NULL_TOPFRAME && new_regloc.location.register_number == 0x20) { new_regloc.location.register_number = 0x24; } @@ -2390,7 +2390,7 @@ bool RegisterContextUnwind::ReadPC(addr_t &pc) { } } -#ifdef __AIX__ +#ifdef _AIX bool RegisterContextUnwind::ReadLR(addr_t &lr) { if (!IsValid()) return false; diff --git a/lldb/source/Target/UnwindLLDB.cpp b/lldb/source/Target/UnwindLLDB.cpp index 8edf359cac497..764bea5bf86c6 100644 --- a/lldb/source/Target/UnwindLLDB.cpp +++ b/lldb/source/Target/UnwindLLDB.cpp @@ -68,7 +68,7 @@ uint32_t UnwindLLDB::DoGetFrameCount() { return m_frames.size(); } -#ifdef __AIX__ +#ifdef _AIX bool UGLY_HACK_NULL_TOPFRAME = false; #endif @@ -95,7 +95,7 @@ bool UnwindLLDB::AddFirstFrame() { if (!reg_ctx_sp->ReadPC(first_cursor_sp->start_pc)) goto unwind_done; -#ifdef __AIX__ +#ifdef _AIX lldb::addr_t lr; if (!reg_ctx_sp->ReadLR(lr)) goto unwind_done; diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp index 45837503e8b73..d17ed77485d31 100644 --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -640,7 +640,7 @@ void sigwinch_handler(int signo) { } void sigint_handler(int signo) { -#if defined(_WIN32) || defined(__AIX__) // Restore handler as it is not persistent on Windows +#if defined(_WIN32) || defined(_AIX) // Restore handler as it is not persistent on Windows signal(SIGINT, sigint_handler); #endif static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT; @@ -729,7 +729,7 @@ static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) { int main(int argc, char const *argv[]) { // Editline uses for example iswprint which is dependent on LC_CTYPE. // FIXME: this caused unexpected SIGTRAP on AIX -#ifndef __AIX__ +#ifndef _AIX std::setlocale(LC_ALL, ""); std::setlocale(LC_CTYPE, ""); #endif diff --git a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp index 91bb2083a88b5..52c2eae0c9033 100644 --- a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp +++ b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp @@ -14,7 +14,7 @@ using HostObjectFile = ObjectFileMachO; #elif defined(_WIN32) #include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" using HostObjectFile = ObjectFilePECOFF; -#elif defined(__AIX__) +#elif defined(_AIX) #include "Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h" using HostObjectFile = ObjectFileXCOFF; #else @@ -49,7 +49,7 @@ using HostObjectFile = ObjectFileELF; #include "Plugins/Instruction/MIPS/EmulateInstructionMIPS.h" #endif -#if defined(__AIX__) +#if defined(_AIX) #include "Plugins/Instruction/PPC64/EmulateInstructionPPC64.h" #endif @@ -82,7 +82,7 @@ llvm::Error SystemInitializerLLGS::Initialize() { EmulateInstructionRISCV::Initialize(); #endif -#if defined(__AIX__) +#if defined(_AIX) EmulateInstructionPPC64::Initialize(); #endif @@ -108,7 +108,7 @@ void SystemInitializerLLGS::Terminate() { EmulateInstructionRISCV::Terminate(); #endif -#if defined(__AIX__) +#if defined(_AIX) EmulateInstructionPPC64::Terminate(); #endif diff --git a/lldb/tools/lldb-server/lldb-gdbserver.cpp b/lldb/tools/lldb-server/lldb-gdbserver.cpp index 844a6370bdb2e..dcbb421a73e25 100644 --- a/lldb/tools/lldb-server/lldb-gdbserver.cpp +++ b/lldb/tools/lldb-server/lldb-gdbserver.cpp @@ -45,7 +45,7 @@ #include "Plugins/Process/NetBSD/NativeProcessNetBSD.h" #elif defined(_WIN32) #include "Plugins/Process/Windows/Common/NativeProcessWindows.h" -#elif defined(__AIX__) +#elif defined(_AIX) #include "Plugins/Process/AIX/NativeProcessAIX.h" #endif @@ -72,7 +72,7 @@ typedef process_freebsd::NativeProcessFreeBSD::Manager NativeProcessManager; typedef process_netbsd::NativeProcessNetBSD::Manager NativeProcessManager; #elif defined(_WIN32) typedef NativeProcessWindows::Manager NativeProcessManager; -#elif defined(__AIX__) +#elif defined(_AIX) typedef process_aix::NativeProcessAIX::Manager NativeProcessManager; #else // Dummy implementation to make sure the code compiles diff --git a/lldb/unittests/Host/MainLoopTest.cpp b/lldb/unittests/Host/MainLoopTest.cpp index c76476c947054..5c042261b9ef2 100644 --- a/lldb/unittests/Host/MainLoopTest.cpp +++ b/lldb/unittests/Host/MainLoopTest.cpp @@ -223,7 +223,7 @@ TEST_F(MainLoopTest, PendingCallbackAfterLoopExited) { loop.AddPendingCallback([&](MainLoopBase &loop) {}); } -#if defined(LLVM_ON_UNIX) && !defined(__AIX__) +#if defined(LLVM_ON_UNIX) && !defined(_AIX) TEST_F(MainLoopTest, DetectsEOF) { PseudoTerminal term; diff --git a/lldb/unittests/Host/PipeTest.cpp b/lldb/unittests/Host/PipeTest.cpp index c1013aa7a7e4e..00ffd33d68f7a 100644 --- a/lldb/unittests/Host/PipeTest.cpp +++ b/lldb/unittests/Host/PipeTest.cpp @@ -55,7 +55,7 @@ TEST_F(PipeTest, OpenAsReader) { } #endif -#if !defined(__AIX__) +#if !defined(_AIX) TEST_F(PipeTest, WriteWithTimeout) { Pipe pipe; ASSERT_THAT_ERROR(pipe.CreateNew(false).ToError(), llvm::Succeeded()); diff --git a/lldb/unittests/Host/posix/TerminalTest.cpp b/lldb/unittests/Host/posix/TerminalTest.cpp index f3de92c0852b1..64e6be64db80c 100644 --- a/lldb/unittests/Host/posix/TerminalTest.cpp +++ b/lldb/unittests/Host/posix/TerminalTest.cpp @@ -94,14 +94,14 @@ TEST_F(TerminalTest, SetRaw) { TEST_F(TerminalTest, SetBaudRate) { struct termios terminfo; -#if (defined(__AIX__) && defined(B38400)) || !defined(__AIX__) +#if (defined(_AIX) && defined(B38400)) || !defined(_AIX) ASSERT_THAT_ERROR(m_term.SetBaudRate(38400), llvm::Succeeded()); ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0); EXPECT_EQ(cfgetispeed(&terminfo), static_cast(B38400)); EXPECT_EQ(cfgetospeed(&terminfo), static_cast(B38400)); #endif -#if (defined(__AIX__) && defined(B115200)) || !defined(__AIX__) +#if (defined(_AIX) && defined(B115200)) || !defined(_AIX) ASSERT_THAT_ERROR(m_term.SetBaudRate(115200), llvm::Succeeded()); ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0); EXPECT_EQ(cfgetispeed(&terminfo), static_cast(B115200)); >From a8020a6a8692f059679195ae1a0ef5e0eeee94c8 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Thu, 10 Oct 2024 04:52:08 -0500 Subject: [PATCH 11/47] Removed from lldb/CMakeLists --- lldb/CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt index a4fd8bccf056d..59cdc4593463c 100644 --- a/lldb/CMakeLists.txt +++ b/lldb/CMakeLists.txt @@ -38,10 +38,6 @@ endif() include(LLDBConfig) include(AddLLDB) -if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") - add_definitions("-D_AIX") -endif() - # Define the LLDB_CONFIGURATION_xxx matching the build type. if(uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" ) add_definitions(-DLLDB_CONFIGURATION_DEBUG) >From 7609ad339bfab48412221be54edc2d2d146279c3 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Thu, 14 Nov 2024 13:23:59 -0600 Subject: [PATCH 12/47] Patch for the Merge conflict of xcoff first merge with llvm --- .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 253 +++++++++++++++++- 1 file changed, 252 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index 395a126a01fce..a4d9ea295b4c3 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -188,7 +188,258 @@ bool ObjectFileXCOFF::ParseHeader() { if (module_sp) { std::lock_guard guard(module_sp->GetMutex()); m_sect_headers.clear(); - lldb::offs + lldb::offset_t offset = 0; + + if (ParseXCOFFHeader(m_data, &offset, m_xcoff_header)) { + m_data.SetAddressByteSize(GetAddressByteSize()); + if (m_xcoff_header.auxhdrsize > 0) + ParseXCOFFOptionalHeader(m_data, &offset); + ParseSectionHeaders(offset); + } + return true; + } + + return false; +} + +bool ObjectFileXCOFF::ParseXCOFFHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + xcoff_header_t &xcoff_header) { + //FIXME: data.ValidOffsetForDataOfSize + xcoff_header.magic = data.GetU16(offset_ptr); + xcoff_header.nsects = data.GetU16(offset_ptr); + xcoff_header.modtime = data.GetU32(offset_ptr); + xcoff_header.symoff = data.GetU64(offset_ptr); + xcoff_header.auxhdrsize = data.GetU16(offset_ptr); + xcoff_header.flags = data.GetU16(offset_ptr); + xcoff_header.nsyms = data.GetU32(offset_ptr); + return true; +} + +bool ObjectFileXCOFF::ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr) { + lldb::offset_t init_offset = *offset_ptr; + //FIXME: data.ValidOffsetForDataOfSize + m_xcoff_aux_header.AuxMagic = data.GetU16(offset_ptr); + m_xcoff_aux_header.Version = data.GetU16(offset_ptr); + m_xcoff_aux_header.ReservedForDebugger = data.GetU32(offset_ptr); + m_xcoff_aux_header.TextStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.DataStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.TOCAnchorAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfEntryPoint = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTOC = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfLoader = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.ModuleType = data.GetU16(offset_ptr); + m_xcoff_aux_header.CpuFlag = data.GetU8(offset_ptr); + m_xcoff_aux_header.CpuType = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.DataPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.StackPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.FlagAndTDataAlignment = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.InitDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.BssDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.EntryPointAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxStackSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfTData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.XCOFF64Flag = data.GetU16(offset_ptr); + lldb::offset_t last_offset = *offset_ptr; + if ((last_offset - init_offset) < m_xcoff_header.auxhdrsize) + *offset_ptr += (m_xcoff_header.auxhdrsize - (last_offset - init_offset)); + return true; +} + +bool ObjectFileXCOFF::ParseSectionHeaders( + uint32_t section_header_data_offset) { + const uint32_t nsects = m_xcoff_header.nsects; + m_sect_headers.clear(); + + if (nsects > 0) { + const size_t section_header_byte_size = nsects * m_binary->getSectionHeaderSize(); + lldb_private::DataExtractor section_header_data = + ReadImageData(section_header_data_offset, section_header_byte_size); + + lldb::offset_t offset = 0; + //FIXME: section_header_data.ValidOffsetForDataOfSize + m_sect_headers.resize(nsects); + + for (uint32_t idx = 0; idx < nsects; ++idx) { + const void *name_data = section_header_data.GetData(&offset, 8); + if (name_data) { + memcpy(m_sect_headers[idx].name, name_data, 8); + m_sect_headers[idx].phyaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].vmaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].size = section_header_data.GetU64(&offset); + m_sect_headers[idx].offset = section_header_data.GetU64(&offset); + m_sect_headers[idx].reloff = section_header_data.GetU64(&offset); + m_sect_headers[idx].lineoff = section_header_data.GetU64(&offset); + m_sect_headers[idx].nreloc = section_header_data.GetU32(&offset); + m_sect_headers[idx].nline = section_header_data.GetU32(&offset); + m_sect_headers[idx].flags = section_header_data.GetU32(&offset); + offset += 4; + } else { + offset += (m_binary->getSectionHeaderSize() - 8); + } + } + } + + return !m_sect_headers.empty(); +} + +lldb_private::DataExtractor ObjectFileXCOFF::ReadImageData(uint32_t offset, size_t size) { + if (!size) + return {}; + + if (m_data.ValidOffsetForDataOfSize(offset, size)) + return lldb_private::DataExtractor(m_data, offset, size); + + assert(0); + ProcessSP process_sp(m_process_wp.lock()); + lldb_private::DataExtractor data; + if (process_sp) { + auto data_up = std::make_unique(size, 0); + Status readmem_error; + size_t bytes_read = + process_sp->ReadMemory(offset, data_up->GetBytes(), + data_up->GetByteSize(), readmem_error); + if (bytes_read == size) { + DataBufferSP buffer_sp(data_up.release()); + data.SetData(buffer_sp, 0, buffer_sp->GetByteSize()); + } + } + return data; +} + +bool ObjectFileXCOFF::SetLoadAddress(Target &target, lldb::addr_t value, + bool value_is_offset) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (section_sp && !section_sp->IsThreadSpecific()) { + bool use_offset = false; + if (strcmp(section_sp->GetName().AsCString(), ".text") == 0 || + strcmp(section_sp->GetName().AsCString(), ".data") == 0 || + strcmp(section_sp->GetName().AsCString(), ".bss") == 0) + use_offset = true; + + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, (use_offset ? + (section_sp->GetFileOffset() + value) : (section_sp->GetFileAddress() + value)))) + ++num_loaded_sections; + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (type_id == 1 && section_sp && strcmp(section_sp->GetName().AsCString(), ".text") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileOffset() + value)) + ++num_loaded_sections; + } + } else if (type_id == 2 && section_sp && strcmp(section_sp->GetName().AsCString(), ".data") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileAddress() + value)) + ++num_loaded_sections; + } + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +ByteOrder ObjectFileXCOFF::GetByteOrder() const { + return eByteOrderBig; +} + +bool ObjectFileXCOFF::IsExecutable() const { + return true; +} + +uint32_t ObjectFileXCOFF::GetAddressByteSize() const { + if (m_xcoff_header.magic == XCOFF::XCOFF64) + return 8; + else if (m_xcoff_header.magic == XCOFF::XCOFF32) + return 4; + return 4; +} + +AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) { + return AddressClass::eUnknown; +} + +lldb::SymbolType ObjectFileXCOFF::MapSymbolType(llvm::object::SymbolRef::Type sym_type) { + if (sym_type == llvm::object::SymbolRef::ST_Function) + return lldb::eSymbolTypeCode; + else if (sym_type == llvm::object::SymbolRef::ST_Data) + return lldb::eSymbolTypeData; + return lldb::eSymbolTypeInvalid; +} + +void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) { + SectionList *sect_list = GetSectionList(); + const uint32_t num_syms = m_xcoff_header.nsyms; + uint32_t sidx = 0; + if (num_syms > 0 && m_xcoff_header.symoff > 0) { + const uint32_t symbol_size = XCOFF::SymbolTableEntrySize; + const size_t symbol_data_size = num_syms * symbol_size; + lldb_private::DataExtractor symtab_data = + ReadImageData(m_xcoff_header.symoff, symbol_data_size); + + lldb::offset_t offset = 0; + std::string symbol_name; + Symbol *symbols = lldb_symtab.Resize(num_syms); + llvm::object::symbol_iterator SI = m_binary->symbol_begin(); + for (uint32_t i = 0; i < num_syms; ++i, ++SI) { + xcoff_symbol_t symbol; + const uint32_t symbol_offset = offset; + symbol.value = symtab_data.GetU64(&offset); + symbol.offset = symtab_data.GetU32(&offset); + Expected symbol_name_or_err = m_binary->getStringTableEntry(symbol.offset); + if (!symbol_name_or_err) { + consumeError(symbol_name_or_err.takeError()); + return; + } + StringRef symbol_name_str = symbol_name_or_err.get(); + symbol_name.assign(symbol_name_str.data()); symbol.sect = symtab_data.GetU16(&offset); symbol.type = symtab_data.GetU16(&offset); symbol.storage = symtab_data.GetU8(&offset); >From dd56fce276b60b40e1997292b3f554a20157661a Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 17 Nov 2024 00:15:01 -0600 Subject: [PATCH 13/47] Attach fix for AIX --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 130 ++++++++++++++++++ .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 5 +- 2 files changed, 134 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 7f3a638d5b028..acaa6a72edded 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -18,8 +18,13 @@ #include "lldb/Target/ThreadPlanStepInstruction.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" +#include "llvm/Support/FileSystem.h" #if defined(_AIX) #include +#include +#include +#include +#include #endif /*#include "llvm/ADT/Triple.h" @@ -131,14 +136,139 @@ bool DynamicLoaderAIXDYLD::NotifyBreakpointHit( lldb::user_id_t break_loc_id) { } + +void DynamicLoaderAIXDYLD::ResolveExecutableModule( + lldb::ModuleSP &module_sp) { + Log *log = GetLog(LLDBLog::DynamicLoader); + + if (m_process == nullptr) + return; + + auto &target = m_process->GetTarget(); + const auto platform_sp = target.GetPlatform(); + + ProcessInstanceInfo process_info; + if (!m_process->GetProcessInfo(process_info)) { + LLDB_LOGF(log, + "DynamicLoaderPOSIXDYLD::%s - failed to get process info for " + "pid %" PRIu64, + __FUNCTION__, m_process->GetID()); + return; + } + + char procinfo_path[64], exe_path[PATH_MAX], arg_buffer[8192]; + struct procsinfo64 procs_info; + int32long64_t pid = m_process->GetID(); + std::string proc_file = "/proc/" + std::to_string(pid) + "/psinfo"; + std::string cwd_link = "/proc/" + std::to_string(pid) + "/cwd"; + psinfo_t psinfo; + std::ifstream file(proc_file, std::ios::binary); + if(!file.is_open()) + { + LLDB_LOGF(log, "Error psinfo "); + } + file.read(reinterpret_cast(&psinfo), sizeof(psinfo_t)); + if(!file) + LLDB_LOGF(log, "Error psinfo: Failed to read "); + + std::string relative_path(psinfo.pr_fname); + LLDB_LOGF(log, "relative path %s",relative_path.c_str()); + + char cwd[PATH_MAX]; + char resolved_path[PATH_MAX]; + std::string executable_name; + bool found = 0; + if(readlink(cwd_link.c_str(), cwd, sizeof(cwd)) != -1){ + std::filesystem::path full_path = std::filesystem::path(cwd)/relative_path; + if(realpath(full_path.c_str(), resolved_path)) { + LLDB_LOGF(log, " RESOLVED PATH: %s", resolved_path); + found = 1; + } + else + perror("realpath error");} + + executable_name = resolved_path; + if(found == 0) { + std::string command_line(psinfo.pr_psargs); + LLDB_LOGF(log, "command line %s",command_line.c_str()); + if (!command_line.empty()) { + size_t space1 = command_line.find(' '); + executable_name = command_line.substr(0, space1); + LLDB_LOGF(log, "executable name %s",executable_name.c_str()); + } + } + + LLDB_LOGF(log, "executable name %s",executable_name.c_str()); + /*target.SetExecutableModule(target.GetOrCreateModule(lldb_private::FileSpec(resolved_path), + true),true);*/ + process_info.SetExecutableFile(lldb_private::FileSpec(executable_name), + true); + +/* snprintf(procinfo_path, sizeof(procinfo_path), "/proc/%d/object/a.out", pid); + ssize_t len = readlink(procinfo_path, exe_path, sizeof(exe_path) - 1); + exe_path[len] = '\0'; + int num_procs = getprocs64(&procs_info, sizeof(struct procsinfo64), NULL, 0, + &pid, + 1); + int result = getargs(pid, arg_buffer, sizeof(arg_buffer)); + std::vector args; + char *arg_start = arg_buffer; + while(*arg_start != '\0') { + args.emplace_back(arg_start); + arg_start += strlen(arg_start) + 1; + } + + LLDB_LOGF( + log, "1. DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s" + ", pid: %d, current_path: %s", + __FUNCTION__, m_process->GetID(), + args[0], pid, current_path.c_str()); + LLDB_LOGF( + log, "1. DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s" + "num_procs: %d, pid: %d", + __FUNCTION__, m_process->GetID(), + std::string(procs_info.pi_comm).c_str(), num_procs, pid); + if(num_procs <= 0) + perror("getprocs64 failed"); */ + + LLDB_LOGF( + log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s", + __FUNCTION__, m_process->GetID(), + process_info.GetExecutableFile().GetPath().c_str()); + + ModuleSpec module_spec(process_info.GetExecutableFile(), + process_info.GetArchitecture()); + if (module_sp && module_sp->MatchesModuleSpec(module_spec)) + return; + + const auto executable_search_paths(Target::GetDefaultExecutableSearchPaths()); + auto error = platform_sp->ResolveExecutable( + module_spec, module_sp, + !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr); + if (error.Fail()) { + StreamString stream; + module_spec.Dump(stream); + + LLDB_LOGF(log, + "DynamicLoaderPOSIXDYLD::%s - failed to resolve executable " + "with module spec \"%s\": %s", + __FUNCTION__, stream.GetData(), error.AsCString()); + return; + } + + target.SetExecutableModule(module_sp, eLoadDependentsNo); +} + void DynamicLoaderAIXDYLD::DidAttach() { Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); ModuleSP executable = GetTargetExecutable(); + ResolveExecutableModule(executable); if (!executable.get()) return; + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); // Try to fetch the load address of the file from the process, since there // could be randomization of the load address. diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h index ae4b7aca66dcc..0ffbe688e0069 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -24,7 +24,7 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { static void Initialize(); static void Terminate(); - static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; } + static llvm::StringRef GetPluginNameStatic() { return "aix-dyld"; } static llvm::StringRef GetPluginDescriptionStatic(); static DynamicLoader *CreateInstance(Process *process, bool force); @@ -46,6 +46,9 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { protected: lldb::addr_t GetLoadAddress(lldb::ModuleSP executable); + /// Loads Module from inferior process. + void ResolveExecutableModule(lldb::ModuleSP &module_sp); + private: std::map m_loaded_modules; }; >From 48b8b1b6532181acab0ee1710d5f4ab92903ae78 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 18 Nov 2024 02:56:31 -0600 Subject: [PATCH 14/47] Cleanup --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 65 +++++-------------- 1 file changed, 17 insertions(+), 48 deletions(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index acaa6a72edded..1a98bb9334043 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -156,81 +156,50 @@ void DynamicLoaderAIXDYLD::ResolveExecutableModule( return; } - char procinfo_path[64], exe_path[PATH_MAX], arg_buffer[8192]; - struct procsinfo64 procs_info; int32long64_t pid = m_process->GetID(); + char cwd[PATH_MAX], resolved_path[PATH_MAX]; + std::string executable_name; + bool path_resolved = false; + psinfo_t psinfo; + std::string proc_file = "/proc/" + std::to_string(pid) + "/psinfo"; std::string cwd_link = "/proc/" + std::to_string(pid) + "/cwd"; - psinfo_t psinfo; std::ifstream file(proc_file, std::ios::binary); if(!file.is_open()) - { - LLDB_LOGF(log, "Error psinfo "); - } + LLDB_LOGF(log, "Error: Unable to access process info "); + file.read(reinterpret_cast(&psinfo), sizeof(psinfo_t)); if(!file) - LLDB_LOGF(log, "Error psinfo: Failed to read "); + LLDB_LOGF(log, "Process info error: Failed to read "); std::string relative_path(psinfo.pr_fname); - LLDB_LOGF(log, "relative path %s",relative_path.c_str()); + LLDB_LOGF(log, "Relative path %s",relative_path.c_str()); - char cwd[PATH_MAX]; - char resolved_path[PATH_MAX]; - std::string executable_name; - bool found = 0; if(readlink(cwd_link.c_str(), cwd, sizeof(cwd)) != -1){ std::filesystem::path full_path = std::filesystem::path(cwd)/relative_path; if(realpath(full_path.c_str(), resolved_path)) { - LLDB_LOGF(log, " RESOLVED PATH: %s", resolved_path); - found = 1; + LLDB_LOGF(log, "Resolved Path using process info : %s", resolved_path); + path_resolved = true; } else - perror("realpath error");} + LLDB_LOGF(log, "Realpath error: Unable to resolve. "); + } executable_name = resolved_path; - if(found == 0) { + if(path_resolved == false) { std::string command_line(psinfo.pr_psargs); - LLDB_LOGF(log, "command line %s",command_line.c_str()); + LLDB_LOGF(log, "Command line: %s",command_line.c_str()); if (!command_line.empty()) { size_t space1 = command_line.find(' '); executable_name = command_line.substr(0, space1); - LLDB_LOGF(log, "executable name %s",executable_name.c_str()); + LLDB_LOGF(log, "Resolved path using command line arg %s",executable_name.c_str()); } } - LLDB_LOGF(log, "executable name %s",executable_name.c_str()); - /*target.SetExecutableModule(target.GetOrCreateModule(lldb_private::FileSpec(resolved_path), - true),true);*/ + LLDB_LOGF(log, "Executable Name %s",executable_name.c_str()); process_info.SetExecutableFile(lldb_private::FileSpec(executable_name), true); -/* snprintf(procinfo_path, sizeof(procinfo_path), "/proc/%d/object/a.out", pid); - ssize_t len = readlink(procinfo_path, exe_path, sizeof(exe_path) - 1); - exe_path[len] = '\0'; - int num_procs = getprocs64(&procs_info, sizeof(struct procsinfo64), NULL, 0, - &pid, - 1); - int result = getargs(pid, arg_buffer, sizeof(arg_buffer)); - std::vector args; - char *arg_start = arg_buffer; - while(*arg_start != '\0') { - args.emplace_back(arg_start); - arg_start += strlen(arg_start) + 1; - } - - LLDB_LOGF( - log, "1. DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s" - ", pid: %d, current_path: %s", - __FUNCTION__, m_process->GetID(), - args[0], pid, current_path.c_str()); - LLDB_LOGF( - log, "1. DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s" - "num_procs: %d, pid: %d", - __FUNCTION__, m_process->GetID(), - std::string(procs_info.pi_comm).c_str(), num_procs, pid); - if(num_procs <= 0) - perror("getprocs64 failed"); */ - LLDB_LOGF( log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s", __FUNCTION__, m_process->GetID(), >From d410734184a681b3e95949d3953142995682d7f6 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Tue, 19 Nov 2024 09:44:42 -0600 Subject: [PATCH 15/47] Patch in MainLoopPosix.cpp for runtime issue --- lldb/source/Host/posix/MainLoopPosix.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp index f68268f114075..4c617cdde67ba 100644 --- a/lldb/source/Host/posix/MainLoopPosix.cpp +++ b/lldb/source/Host/posix/MainLoopPosix.cpp @@ -149,7 +149,7 @@ Status MainLoopPosix::RunImpl::Poll() { int timeout; timeout = -1; - pthread_sigmask(SIG_SETMASK, &sigmask, &origmask); + pthread_sigmask(SIG_SETMASK, nullptr, &origmask); int ready = poll(read_fds.data(), read_fds.size(), timeout); pthread_sigmask(SIG_SETMASK, &origmask, nullptr); if (ready == -1 && errno != EINTR) >From 48f39dadbbdb4874fbd9b6350933dc67e8823339 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Thu, 5 Dec 2024 05:13:14 -0600 Subject: [PATCH 16/47] Patch for compilation failure in DomainSocket.cpp, AbstractSocket.cpp and AbstractSocket.h --- lldb/include/lldb/Host/aix/AbstractSocket.h | 2 +- lldb/source/Host/aix/AbstractSocket.cpp | 3 +-- lldb/source/Host/posix/DomainSocket.cpp | 4 ++++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lldb/include/lldb/Host/aix/AbstractSocket.h b/lldb/include/lldb/Host/aix/AbstractSocket.h index 78a567a6b9095..accfd01457a5e 100644 --- a/lldb/include/lldb/Host/aix/AbstractSocket.h +++ b/lldb/include/lldb/Host/aix/AbstractSocket.h @@ -14,7 +14,7 @@ namespace lldb_private { class AbstractSocket : public DomainSocket { public: - AbstractSocket(bool child_processes_inherit); + AbstractSocket(); protected: size_t GetNameOffset() const override; diff --git a/lldb/source/Host/aix/AbstractSocket.cpp b/lldb/source/Host/aix/AbstractSocket.cpp index bfb67d452f7ec..fddf78f54f46d 100644 --- a/lldb/source/Host/aix/AbstractSocket.cpp +++ b/lldb/source/Host/aix/AbstractSocket.cpp @@ -13,8 +13,7 @@ using namespace lldb; using namespace lldb_private; -AbstractSocket::AbstractSocket(bool child_processes_inherit) - : DomainSocket(ProtocolUnixAbstract, child_processes_inherit) {} +AbstractSocket::AbstractSocket() : DomainSocket(ProtocolUnixAbstract) {} size_t AbstractSocket::GetNameOffset() const { return 1; } diff --git a/lldb/source/Host/posix/DomainSocket.cpp b/lldb/source/Host/posix/DomainSocket.cpp index 9a0b385d998bf..6cbffb2d9c4bd 100644 --- a/lldb/source/Host/posix/DomainSocket.cpp +++ b/lldb/source/Host/posix/DomainSocket.cpp @@ -17,6 +17,10 @@ #include #include +#if defined(_AIX) +#include +#endif + using namespace lldb; using namespace lldb_private; >From 97531f7bf6e385f0f51d860c6eea17aeb32f6594 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Thu, 19 Dec 2024 06:38:36 -0600 Subject: [PATCH 17/47] Patch for merge conflict in ObjectFileXCOFF.cpp & ObjectFileXCOFF.h --- .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 253 +++++++++++++++++- 1 file changed, 252 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index 395a126a01fce..a4d9ea295b4c3 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -188,7 +188,258 @@ bool ObjectFileXCOFF::ParseHeader() { if (module_sp) { std::lock_guard guard(module_sp->GetMutex()); m_sect_headers.clear(); - lldb::offs + lldb::offset_t offset = 0; + + if (ParseXCOFFHeader(m_data, &offset, m_xcoff_header)) { + m_data.SetAddressByteSize(GetAddressByteSize()); + if (m_xcoff_header.auxhdrsize > 0) + ParseXCOFFOptionalHeader(m_data, &offset); + ParseSectionHeaders(offset); + } + return true; + } + + return false; +} + +bool ObjectFileXCOFF::ParseXCOFFHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + xcoff_header_t &xcoff_header) { + //FIXME: data.ValidOffsetForDataOfSize + xcoff_header.magic = data.GetU16(offset_ptr); + xcoff_header.nsects = data.GetU16(offset_ptr); + xcoff_header.modtime = data.GetU32(offset_ptr); + xcoff_header.symoff = data.GetU64(offset_ptr); + xcoff_header.auxhdrsize = data.GetU16(offset_ptr); + xcoff_header.flags = data.GetU16(offset_ptr); + xcoff_header.nsyms = data.GetU32(offset_ptr); + return true; +} + +bool ObjectFileXCOFF::ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr) { + lldb::offset_t init_offset = *offset_ptr; + //FIXME: data.ValidOffsetForDataOfSize + m_xcoff_aux_header.AuxMagic = data.GetU16(offset_ptr); + m_xcoff_aux_header.Version = data.GetU16(offset_ptr); + m_xcoff_aux_header.ReservedForDebugger = data.GetU32(offset_ptr); + m_xcoff_aux_header.TextStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.DataStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.TOCAnchorAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfEntryPoint = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTOC = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfLoader = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.ModuleType = data.GetU16(offset_ptr); + m_xcoff_aux_header.CpuFlag = data.GetU8(offset_ptr); + m_xcoff_aux_header.CpuType = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.DataPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.StackPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.FlagAndTDataAlignment = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.InitDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.BssDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.EntryPointAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxStackSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfTData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.XCOFF64Flag = data.GetU16(offset_ptr); + lldb::offset_t last_offset = *offset_ptr; + if ((last_offset - init_offset) < m_xcoff_header.auxhdrsize) + *offset_ptr += (m_xcoff_header.auxhdrsize - (last_offset - init_offset)); + return true; +} + +bool ObjectFileXCOFF::ParseSectionHeaders( + uint32_t section_header_data_offset) { + const uint32_t nsects = m_xcoff_header.nsects; + m_sect_headers.clear(); + + if (nsects > 0) { + const size_t section_header_byte_size = nsects * m_binary->getSectionHeaderSize(); + lldb_private::DataExtractor section_header_data = + ReadImageData(section_header_data_offset, section_header_byte_size); + + lldb::offset_t offset = 0; + //FIXME: section_header_data.ValidOffsetForDataOfSize + m_sect_headers.resize(nsects); + + for (uint32_t idx = 0; idx < nsects; ++idx) { + const void *name_data = section_header_data.GetData(&offset, 8); + if (name_data) { + memcpy(m_sect_headers[idx].name, name_data, 8); + m_sect_headers[idx].phyaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].vmaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].size = section_header_data.GetU64(&offset); + m_sect_headers[idx].offset = section_header_data.GetU64(&offset); + m_sect_headers[idx].reloff = section_header_data.GetU64(&offset); + m_sect_headers[idx].lineoff = section_header_data.GetU64(&offset); + m_sect_headers[idx].nreloc = section_header_data.GetU32(&offset); + m_sect_headers[idx].nline = section_header_data.GetU32(&offset); + m_sect_headers[idx].flags = section_header_data.GetU32(&offset); + offset += 4; + } else { + offset += (m_binary->getSectionHeaderSize() - 8); + } + } + } + + return !m_sect_headers.empty(); +} + +lldb_private::DataExtractor ObjectFileXCOFF::ReadImageData(uint32_t offset, size_t size) { + if (!size) + return {}; + + if (m_data.ValidOffsetForDataOfSize(offset, size)) + return lldb_private::DataExtractor(m_data, offset, size); + + assert(0); + ProcessSP process_sp(m_process_wp.lock()); + lldb_private::DataExtractor data; + if (process_sp) { + auto data_up = std::make_unique(size, 0); + Status readmem_error; + size_t bytes_read = + process_sp->ReadMemory(offset, data_up->GetBytes(), + data_up->GetByteSize(), readmem_error); + if (bytes_read == size) { + DataBufferSP buffer_sp(data_up.release()); + data.SetData(buffer_sp, 0, buffer_sp->GetByteSize()); + } + } + return data; +} + +bool ObjectFileXCOFF::SetLoadAddress(Target &target, lldb::addr_t value, + bool value_is_offset) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (section_sp && !section_sp->IsThreadSpecific()) { + bool use_offset = false; + if (strcmp(section_sp->GetName().AsCString(), ".text") == 0 || + strcmp(section_sp->GetName().AsCString(), ".data") == 0 || + strcmp(section_sp->GetName().AsCString(), ".bss") == 0) + use_offset = true; + + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, (use_offset ? + (section_sp->GetFileOffset() + value) : (section_sp->GetFileAddress() + value)))) + ++num_loaded_sections; + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (type_id == 1 && section_sp && strcmp(section_sp->GetName().AsCString(), ".text") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileOffset() + value)) + ++num_loaded_sections; + } + } else if (type_id == 2 && section_sp && strcmp(section_sp->GetName().AsCString(), ".data") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileAddress() + value)) + ++num_loaded_sections; + } + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +ByteOrder ObjectFileXCOFF::GetByteOrder() const { + return eByteOrderBig; +} + +bool ObjectFileXCOFF::IsExecutable() const { + return true; +} + +uint32_t ObjectFileXCOFF::GetAddressByteSize() const { + if (m_xcoff_header.magic == XCOFF::XCOFF64) + return 8; + else if (m_xcoff_header.magic == XCOFF::XCOFF32) + return 4; + return 4; +} + +AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) { + return AddressClass::eUnknown; +} + +lldb::SymbolType ObjectFileXCOFF::MapSymbolType(llvm::object::SymbolRef::Type sym_type) { + if (sym_type == llvm::object::SymbolRef::ST_Function) + return lldb::eSymbolTypeCode; + else if (sym_type == llvm::object::SymbolRef::ST_Data) + return lldb::eSymbolTypeData; + return lldb::eSymbolTypeInvalid; +} + +void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) { + SectionList *sect_list = GetSectionList(); + const uint32_t num_syms = m_xcoff_header.nsyms; + uint32_t sidx = 0; + if (num_syms > 0 && m_xcoff_header.symoff > 0) { + const uint32_t symbol_size = XCOFF::SymbolTableEntrySize; + const size_t symbol_data_size = num_syms * symbol_size; + lldb_private::DataExtractor symtab_data = + ReadImageData(m_xcoff_header.symoff, symbol_data_size); + + lldb::offset_t offset = 0; + std::string symbol_name; + Symbol *symbols = lldb_symtab.Resize(num_syms); + llvm::object::symbol_iterator SI = m_binary->symbol_begin(); + for (uint32_t i = 0; i < num_syms; ++i, ++SI) { + xcoff_symbol_t symbol; + const uint32_t symbol_offset = offset; + symbol.value = symtab_data.GetU64(&offset); + symbol.offset = symtab_data.GetU32(&offset); + Expected symbol_name_or_err = m_binary->getStringTableEntry(symbol.offset); + if (!symbol_name_or_err) { + consumeError(symbol_name_or_err.takeError()); + return; + } + StringRef symbol_name_str = symbol_name_or_err.get(); + symbol_name.assign(symbol_name_str.data()); symbol.sect = symtab_data.GetU16(&offset); symbol.type = symtab_data.GetU16(&offset); symbol.storage = symtab_data.GetU8(&offset); >From 71d2fcff8975831e7f0a657481220749b0a473dc Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Tue, 24 Dec 2024 02:05:35 -0600 Subject: [PATCH 18/47] Added upcoming clang-format and other merge changes --- .../posix/ConnectionFileDescriptorPosix.cpp | 9 ++-- lldb/source/Host/posix/DomainSocket.cpp | 5 ++- lldb/source/Host/posix/FileSystemPosix.cpp | 2 +- lldb/source/Host/posix/MainLoopPosix.cpp | 43 ++++++++----------- .../Host/posix/ProcessLauncherPosixFork.cpp | 2 +- lldb/source/Plugins/Language/ObjC/Cocoa.cpp | 17 +++----- .../BSD-Archive/ObjectContainerBSDArchive.cpp | 29 +++++++------ lldb/source/Utility/ArchSpec.cpp | 1 - 8 files changed, 49 insertions(+), 59 deletions(-) diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index 32d034e60d26c..e3d1300cf76ed 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -119,8 +119,7 @@ bool ConnectionFileDescriptor::IsConnected() const { ConnectionStatus ConnectionFileDescriptor::Connect(llvm::StringRef path, Status *error_ptr) { - return Connect( - path, [](llvm::StringRef) {}, error_ptr); + return Connect(path, [](llvm::StringRef) {}, error_ptr); } ConnectionStatus @@ -716,8 +715,7 @@ ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, ConnectionStatus ConnectionFileDescriptor::ConnectFile( llvm::StringRef s, socket_id_callback_type socket_id_callback, Status *error_ptr) { -#if !defined(_AIX) -#if LLDB_ENABLE_POSIX +#if LLDB_ENABLE_POSIX && !defined(_AIX) std::string addr_str = s.str(); // file:///PATH int fd = FileSystem::Instance().Open(addr_str.c_str(), O_RDWR); @@ -748,8 +746,7 @@ ConnectionStatus ConnectionFileDescriptor::ConnectFile( m_io_sp = std::make_shared(fd, File::eOpenOptionReadWrite, true); return eConnectionStatusSuccess; -#endif // LLDB_ENABLE_POSIX -#endif +#endif // LLDB_ENABLE_POSIX && !defined(_AIX) llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX"); } diff --git a/lldb/source/Host/posix/DomainSocket.cpp b/lldb/source/Host/posix/DomainSocket.cpp index 6cbffb2d9c4bd..28db5964a5a8a 100644 --- a/lldb/source/Host/posix/DomainSocket.cpp +++ b/lldb/source/Host/posix/DomainSocket.cpp @@ -89,8 +89,9 @@ Status DomainSocket::Connect(llvm::StringRef name) { m_socket = CreateSocket(kDomain, kType, 0, error); if (error.Fail()) return error; - if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(), - (struct sockaddr *)&saddr_un, saddr_un_len) < 0) + if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(), + (struct sockaddr *)&saddr_un, + saddr_un_len) < 0) SetLastError(error); return error; diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index 21da5612ff6b8..1a84f550662d7 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,7 +11,7 @@ // C includes #include #include -#if !defined(_AIX) +#ifndef _AIX #include #endif #include diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp index 125b954023dc0..e4ff928a58962 100644 --- a/lldb/source/Host/posix/MainLoopPosix.cpp +++ b/lldb/source/Host/posix/MainLoopPosix.cpp @@ -99,6 +99,7 @@ class MainLoopPosix::RunImpl { ~RunImpl() = default; Status Poll(); + int StartPoll(std::optional point); void ProcessReadEvents(); private: @@ -159,6 +160,22 @@ MainLoopPosix::RunImpl::RunImpl(MainLoopPosix &loop) : loop(loop) { read_fds.reserve(loop.m_read_fds.size()); } +int MainLoopPosix::RunImpl::StartPoll( + std::optional point) { +#if HAVE_PPOLL + return ppoll(read_fds.data(), read_fds.size(), ToTimeSpec(point), + /*sigmask=*/nullptr); +#else + using namespace std::chrono; + int timeout = -1; + if (point) { + nanoseconds dur = std::max(*point - steady_clock::now(), nanoseconds(0)); + timeout = ceil(dur).count(); + } + return poll(read_fds.data(), read_fds.size(), timeout); +#endif +} + Status MainLoopPosix::RunImpl::Poll() { read_fds.clear(); @@ -169,24 +186,10 @@ Status MainLoopPosix::RunImpl::Poll() { pfd.revents = 0; read_fds.push_back(pfd); } + int ready = StartPoll(loop.GetNextWakeupTime()); -#if defined(_AIX) - sigset_t origmask; - int timeout; - - timeout = -1; - pthread_sigmask(SIG_SETMASK, nullptr, &origmask); - int ready = poll(read_fds.data(), read_fds.size(), timeout); - pthread_sigmask(SIG_SETMASK, &origmask, nullptr); if (ready == -1 && errno != EINTR) return Status(errno, eErrorTypePOSIX); -#else - if (ppoll(read_fds.data(), read_fds.size(), - ToTimeSpec(loop.GetNextWakeupTime()), - /*sigmask=*/nullptr) == -1 && - errno != EINTR) - return Status(errno, eErrorTypePOSIX); -#endif return Status(); } @@ -291,16 +294,6 @@ MainLoopPosix::RegisterSignal(int signo, const Callback &callback, UNUSED_IF_ASSERT_DISABLED(ret); assert(ret == 0 && "sigaction failed"); -#if HAVE_SYS_EVENT_H - struct kevent ev; - EV_SET(&ev, signo, EVFILT_SIGNAL, EV_ADD, 0, 0, 0); - ret = kevent(m_kqueue, &ev, 1, nullptr, 0, nullptr); - assert(ret == 0); -#endif - - // If we're using kqueue, the signal needs to be unblocked in order to - // receive it. If using pselect/ppoll, we need to block it, and later unblock - // it as a part of the system call. ret = pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, &old_set); assert(ret == 0 && "pthread_sigmask failed"); info.was_blocked = sigismember(&old_set, signo); diff --git a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp index 52fc58aa21bf4..7b8b42a4b7fe0 100644 --- a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp +++ b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp @@ -197,7 +197,7 @@ struct ForkLaunchInfo { #else if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1) #endif - ExitWithError(error_fd, "ptrace"); + ExitWithError(error_fd, "ptrace"); } // Execute. We should never return... diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index 1d841a032aa6e..1d79edbede5d6 100644 --- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -31,7 +31,6 @@ #include "llvm/ADT/APInt.h" #include "llvm/ADT/bit.h" - using namespace lldb; using namespace lldb_private; using namespace lldb_private::formatters; @@ -267,21 +266,21 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider( if (class_name == "NSIndexSet" || class_name == "NSMutableIndexSet") { // Foundation version 2000 added a bitmask if the index set fit in 64 bits // and a Tagged Pointer version if the bitmask is small enough to fit in - // the tagged pointer payload. + // the tagged pointer payload. // It also changed the layout (but not the size) of the set descriptor. // First check whether this is a tagged pointer. The bitmask will be in // the payload of the tagged pointer. uint64_t payload; - if (runtime->GetFoundationVersion() >= 2000 - && descriptor->GetTaggedPointerInfo(nullptr, nullptr, &payload)) { + if (runtime->GetFoundationVersion() >= 2000 && + descriptor->GetTaggedPointerInfo(nullptr, nullptr, &payload)) { count = llvm::popcount(payload); break; } // The first 32 bits describe the index set in all cases: Status error; uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory( - valobj_addr + ptr_size, 4, 0, error); + valobj_addr + ptr_size, 4, 0, error); if (error.Fail()) return false; // Now check if the index is held in a bitmask in the object: @@ -292,7 +291,7 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider( if ((mode & 2) == 2) { // The bitfield is a 64 bit uint at the beginning of the data var. uint64_t bitfield = process_sp->ReadUnsignedIntegerFromMemory( - valobj_addr + 2 * ptr_size, 8, 0, error); + valobj_addr + 2 * ptr_size, 8, 0, error); if (error.Fail()) return false; count = llvm::popcount(bitfield); @@ -309,7 +308,7 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider( count = 0; break; } - + if ((mode & 2) == 2) mode = 1; // this means the set only has one range else @@ -1227,8 +1226,7 @@ bool lldb_private::formatters::ObjCSELSummaryProvider( time_t lldb_private::formatters::GetOSXEpoch() { static time_t epoch = 0; if (!epoch) { -#if !defined(_AIX) -#ifndef _WIN32 +#if !defined(_WIN32) && !defined(_AIX) tzset(); tm tm_epoch; tm_epoch.tm_sec = 0; @@ -1241,7 +1239,6 @@ time_t lldb_private::formatters::GetOSXEpoch() { tm_epoch.tm_gmtoff = 0; tm_epoch.tm_zone = nullptr; epoch = timegm(&tm_epoch); -#endif #endif } return epoch; diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 4f747ab20c9ef..b202898ff438a 100644 --- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -81,10 +81,10 @@ size_t ObjectContainerBSDArchive::Archive::ParseObjects() { std::unique_ptr mem_buffer = llvm::MemoryBuffer::getMemBuffer( - llvm::StringRef((const char *)data.GetDataStart(), - data.GetByteSize()), - llvm::StringRef(), - /*RequiresNullTerminator=*/false); + llvm::StringRef((const char *)data.GetDataStart(), + data.GetByteSize()), + llvm::StringRef(), + /*RequiresNullTerminator=*/false); auto exp_ar = llvm::object::Archive::create(mem_buffer->getMemBufferRef()); if (!exp_ar) { @@ -95,7 +95,7 @@ size_t ObjectContainerBSDArchive::Archive::ParseObjects() { llvm::Error iter_err = llvm::Error::success(); Object obj; - for (const auto &child: llvm_archive->children(iter_err)) { + for (const auto &child : llvm_archive->children(iter_err)) { obj.Clear(); auto exp_name = child.getName(); if (exp_name) { @@ -111,7 +111,9 @@ size_t ObjectContainerBSDArchive::Archive::ParseObjects() { obj.modification_time = std::chrono::duration_cast( std::chrono::time_point_cast( - exp_mtime.get()).time_since_epoch()).count(); + exp_mtime.get()) + .time_since_epoch()) + .count(); } else { LLDB_LOG_ERROR(l, exp_mtime.takeError(), "failed to get archive object time: {0}"); @@ -331,21 +333,21 @@ ObjectContainer *ObjectContainerBSDArchive::CreateInstance( ArchiveType ObjectContainerBSDArchive::MagicBytesMatch(const DataExtractor &data) { uint32_t offset = 0; - const char *armag = (const char *)data.PeekData(offset, - sizeof(ar_hdr) + SARMAG); + const char *armag = + (const char *)data.PeekData(offset, sizeof(ar_hdr) + SARMAG); if (armag == nullptr) return ArchiveType::Invalid; ArchiveType result = ArchiveType::Invalid; if (strncmp(armag, ArchiveMagic, SARMAG) == 0) - result = ArchiveType::Archive; + result = ArchiveType::Archive; else if (strncmp(armag, ThinArchiveMagic, SARMAG) == 0) - result = ArchiveType::ThinArchive; + result = ArchiveType::ThinArchive; else - return ArchiveType::Invalid; + return ArchiveType::Invalid; armag += offsetof(struct ar_hdr, ar_fmag) + SARMAG; if (strncmp(armag, ARFMAG, 2) == 0) - return result; + return result; return ArchiveType::Invalid; } @@ -443,7 +445,8 @@ size_t ObjectContainerBSDArchive::GetModuleSpecifications( return 0; const size_t initial_count = specs.GetSize(); - llvm::sys::TimePoint<> file_mod_time = FileSystem::Instance().GetModificationTime(file); + llvm::sys::TimePoint<> file_mod_time = + FileSystem::Instance().GetModificationTime(file); Archive::shared_ptr archive_sp( Archive::FindCachedArchive(file, ArchSpec(), file_mod_time, file_offset)); bool set_archive_arch = false; diff --git a/lldb/source/Utility/ArchSpec.cpp b/lldb/source/Utility/ArchSpec.cpp index ac91183a271cc..85bb85044ec15 100644 --- a/lldb/source/Utility/ArchSpec.cpp +++ b/lldb/source/Utility/ArchSpec.cpp @@ -14,7 +14,6 @@ #include "lldb/lldb-defines.h" #include "llvm/ADT/STLExtras.h" #include "llvm/BinaryFormat/COFF.h" -#include "llvm/BinaryFormat/XCOFF.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/BinaryFormat/XCOFF.h" >From 8fcf69ed77148f8b339b87f75ed97e5ce719b4ba Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Fri, 27 Dec 2024 06:50:27 -0600 Subject: [PATCH 19/47] Some Updates --- lldb/include/lldb/Host/aix/HostInfoAIX.h | 11 +-- lldb/source/Host/aix/HostInfoAIX.cpp | 65 +------------- .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 87 +++++++++---------- .../ObjectFile/XCOFF/ObjectFileXCOFF.h | 11 ++- 4 files changed, 50 insertions(+), 124 deletions(-) diff --git a/lldb/include/lldb/Host/aix/HostInfoAIX.h b/lldb/include/lldb/Host/aix/HostInfoAIX.h index ced4cf34d38a8..ba727e1d5f171 100644 --- a/lldb/include/lldb/Host/aix/HostInfoAIX.h +++ b/lldb/include/lldb/Host/aix/HostInfoAIX.h @@ -6,16 +6,14 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_Host_aix_HostInfoAIX_h_ -#define lldb_Host_aix_HostInfoAIX_h_ +#ifndef LLDB_HOST_AIX_HOSTINFOAIX_H_ +#define LLDB_HOST_AIX_HOSTINFOAIX_H_ #include "lldb/Host/posix/HostInfoPosix.h" #include "lldb/Utility/FileSpec.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/VersionTuple.h" -#include - namespace lldb_private { class HostInfoAIX : public HostInfoPosix { @@ -25,15 +23,10 @@ class HostInfoAIX : public HostInfoPosix { static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr); static void Terminate(); - static llvm::VersionTuple GetOSVersion(); - static std::optional GetOSBuildString(); static llvm::StringRef GetDistributionId(); static FileSpec GetProgramFileSpec(); protected: - static bool ComputeSupportExeDirectory(FileSpec &file_spec); - static bool ComputeSystemPluginsDirectory(FileSpec &file_spec); - static bool ComputeUserPluginsDirectory(FileSpec &file_spec); static void ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64); }; diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp index 8bda09e01741b..ef07b07c8cab2 100644 --- a/lldb/source/Host/aix/HostInfoAIX.cpp +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -29,8 +29,6 @@ namespace { struct HostInfoAIXFields { llvm::once_flag m_distribution_once_flag; std::string m_distribution_id; - llvm::once_flag m_os_version_once_flag; - llvm::VersionTuple m_os_version; }; } // namespace @@ -49,33 +47,6 @@ void HostInfoAIX::Terminate() { HostInfoBase::Terminate(); } -llvm::VersionTuple HostInfoAIX::GetOSVersion() { - assert(g_fields && "Missing call to Initialize?"); - llvm::call_once(g_fields->m_os_version_once_flag, []() { - struct utsname un; - if (uname(&un) != 0) - return; - - llvm::StringRef release = un.release; - // The kernel release string can include a lot of stuff (e.g. - // 4.9.0-6-amd64). We're only interested in the numbered prefix. - release = release.substr(0, release.find_first_not_of("0123456789.")); - g_fields->m_os_version.tryParse(release); - }); - - return g_fields->m_os_version; -} - -std::optional HostInfoAIX::GetOSBuildString() { - struct utsname un; - ::memset(&un, 0, sizeof(utsname)); - - if (uname(&un) < 0) - return std::nullopt; - - return std::string(un.release); -} - llvm::StringRef HostInfoAIX::GetDistributionId() { assert(g_fields && "Missing call to Initialize?"); // Try to run 'lbs_release -i', and use that response for the distribution @@ -122,8 +93,7 @@ llvm::StringRef HostInfoAIX::GetDistributionId() { if (strstr(distribution_id, distributor_id_key)) { // strip newlines std::string id_string(distribution_id + strlen(distributor_id_key)); - id_string.erase(std::remove(id_string.begin(), id_string.end(), '\n'), - id_string.end()); + llvm::erase(id_string, '\n'); // lower case it and convert whitespace to underscores std::transform( @@ -167,42 +137,11 @@ FileSpec HostInfoAIX::GetProgramFileSpec() { return g_program_filespec; } -bool HostInfoAIX::ComputeSupportExeDirectory(FileSpec &file_spec) { - if (HostInfoPosix::ComputeSupportExeDirectory(file_spec) && - file_spec.IsAbsolute() && FileSystem::Instance().Exists(file_spec)) - return true; - file_spec.SetDirectory(GetProgramFileSpec().GetDirectory()); - return !file_spec.GetDirectory().IsEmpty(); -} - -bool HostInfoAIX::ComputeSystemPluginsDirectory(FileSpec &file_spec) { - FileSpec temp_file("/usr/" LLDB_INSTALL_LIBDIR_BASENAME "/lldb/plugins"); - FileSystem::Instance().Resolve(temp_file); - file_spec.SetDirectory(temp_file.GetPath()); - return true; -} - -bool HostInfoAIX::ComputeUserPluginsDirectory(FileSpec &file_spec) { - // XDG Base Directory Specification - // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html If - // XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb. - const char *xdg_data_home = getenv("XDG_DATA_HOME"); - if (xdg_data_home && xdg_data_home[0]) { - std::string user_plugin_dir(xdg_data_home); - user_plugin_dir += "/lldb"; - file_spec.SetDirectory(user_plugin_dir.c_str()); - } else - file_spec.SetDirectory("~/.local/share/lldb"); - return true; -} - void HostInfoAIX::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64) { HostInfoPosix::ComputeHostArchitectureSupport(arch_32, arch_64); - const char *distribution_id = GetDistributionId().data(); - - // On Linux, "unknown" in the vendor slot isn't what we want for the default + // "unknown" in the vendor slot isn't what we want for the default // triple. It's probably an artifact of config.guess. if (arch_32.IsValid()) { if (arch_32.GetTriple().getVendor() == llvm::Triple::UnknownVendor) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index a4d9ea295b4c3..afd8027bab06c 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -1,4 +1,5 @@ -//===-- ObjectFileXCOFF.cpp -------------------------------------------------===// +//===-- ObjectFileXCOFF.cpp +//-------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,13 +8,6 @@ //===----------------------------------------------------------------------===// #include "ObjectFileXCOFF.h" - -#include -#include -#include -#include - -#include "lldb/Utility/FileSpecList.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" @@ -28,6 +22,7 @@ #include "lldb/Target/Target.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/FileSpecList.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RangeMap.h" @@ -38,12 +33,16 @@ #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/Object/XCOFFObjectFile.h" #include "llvm/Object/Decompressor.h" #include "llvm/Support/CRC.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Object/XCOFFObjectFile.h" +#include +#include +#include +#include using namespace llvm; using namespace lldb; @@ -69,21 +68,19 @@ void ObjectFileXCOFF::Terminate() { bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; ObjectFile *ObjectFileXCOFF::CreateInstance(const lldb::ModuleSP &module_sp, - DataBufferSP data_sp, - lldb::offset_t data_offset, - const lldb_private::FileSpec *file, - lldb::offset_t file_offset, - lldb::offset_t length) { + DataBufferSP data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t file_offset, + lldb::offset_t length) { if (!data_sp) { data_sp = MapFileData(*file, length, file_offset); if (!data_sp) return nullptr; data_offset = 0; } - if (!ObjectFileXCOFF::MagicBytesMatch(data_sp, data_offset, length)) return nullptr; - // Update the data to contain the entire file if it doesn't already if (data_sp->GetByteSize() < length) { data_sp = MapFileData(*file, length, file_offset); @@ -114,15 +111,15 @@ bool ObjectFileXCOFF::CreateBinary() { Log *log = GetLog(LLDBLog::Object); - auto binary = llvm::object::XCOFFObjectFile::createObjectFile(llvm::MemoryBufferRef( - toStringRef(m_data.GetData()), m_file.GetFilename().GetStringRef()), - file_magic::xcoff_object_64); + auto binary = llvm::object::ObjectFile::createObjectFile( + llvm::MemoryBufferRef(toStringRef(m_data.GetData()), + m_file.GetFilename().GetStringRef()), + file_magic::xcoff_object_64); if (!binary) { LLDB_LOG_ERROR(log, binary.takeError(), "Failed to create binary for file ({1}): {0}", m_file); return false; } - // Make sure we only handle COFF format. m_binary = llvm::unique_dyn_cast(std::move(*binary)); @@ -132,6 +129,7 @@ bool ObjectFileXCOFF::CreateBinary() { LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}", this, GetModule().get(), GetModule()->GetSpecificationDescription(), m_file.GetPath(), m_binary.get()); + return true; } @@ -148,9 +146,12 @@ size_t ObjectFileXCOFF::GetModuleSpecifications( const size_t initial_count = specs.GetSize(); if (ObjectFileXCOFF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) { - ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + ArchSpec arch_spec = + ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); ModuleSpec spec(file, arch_spec); - spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX); + spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, + LLDB_INVALID_CPUTYPE, + llvm::Triple::AIX); specs.Append(spec); } return specs.GetSize() - initial_count; @@ -158,11 +159,9 @@ size_t ObjectFileXCOFF::GetModuleSpecifications( static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) { switch (magic) { - /* TODO: 32bit not supported yet - case XCOFF::XCOFF32: - return sizeof(struct llvm::object::XCOFFFileHeader32); - */ - + // TODO: 32bit not supported. + // case XCOFF::XCOFF32: + // return sizeof(struct llvm::object::XCOFFFileHeader32); case XCOFF::XCOFF64: return sizeof(struct llvm::object::XCOFFFileHeader64); break; @@ -174,10 +173,12 @@ static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) { } bool ObjectFileXCOFF::MagicBytesMatch(DataBufferSP &data_sp, - lldb::addr_t data_offset, - lldb::addr_t data_length) { - lldb_private::DataExtractor data; + lldb::addr_t data_offset, + lldb::addr_t data_length) { + lldb_private::DataExtractor data; data.SetData(data_sp, data_offset, data_length); + // Need to set this as XCOFF is only compatible with Big Endian + data.SetByteOrder(eByteOrderBig); lldb::offset_t offset = 0; uint16_t magic = data.GetU16(&offset); return XCOFFHeaderSizeFromMagic(magic) != 0; @@ -386,13 +387,10 @@ bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, return changed; } -ByteOrder ObjectFileXCOFF::GetByteOrder() const { - return eByteOrderBig; -} -bool ObjectFileXCOFF::IsExecutable() const { - return true; -} +ByteOrder ObjectFileXCOFF::GetByteOrder() const { return eByteOrderBig; } + +bool ObjectFileXCOFF::IsExecutable() const { return true; } uint32_t ObjectFileXCOFF::GetAddressByteSize() const { if (m_xcoff_header.magic == XCOFF::XCOFF64) @@ -592,13 +590,12 @@ void ObjectFileXCOFF::Dump(Stream *s) { } ArchSpec ObjectFileXCOFF::GetArchitecture() { - ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + ArchSpec arch_spec = + ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); return arch_spec; } -UUID ObjectFileXCOFF::GetUUID() { - return UUID(); -} +UUID ObjectFileXCOFF::GetUUID() { return UUID(); } std::optional ObjectFileXCOFF::GetDebugLink() { return std::nullopt; @@ -724,16 +721,14 @@ lldb_private::Address ObjectFileXCOFF::GetBaseAddress() { } ObjectFile::Type ObjectFileXCOFF::CalculateType() { - if (m_xcoff_header.flags & XCOFF::F_EXEC) + if (m_binary->fileHeader64()->Flags & XCOFF::F_EXEC) return eTypeExecutable; - else if (m_xcoff_header.flags & XCOFF::F_SHROBJ) + else if (m_binary->fileHeader64()->Flags & XCOFF::F_SHROBJ) return eTypeSharedLibrary; return eTypeUnknown; } -ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { - return eStrataUnknown; -} +ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { return eStrataUnknown; } llvm::StringRef ObjectFileXCOFF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const { @@ -752,7 +747,7 @@ ObjectFileXCOFF::GetLoadableData(Target &target) { lldb::WritableDataBufferSP ObjectFileXCOFF::MapFileDataWritable(const FileSpec &file, uint64_t Size, - uint64_t Offset) { + uint64_t Offset) { return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size, Offset); } diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h index 5a12d16886489..f827fca3932f4 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h @@ -1,4 +1,5 @@ -//===-- ObjectFileXCOFF.h --------------------------------------- -*- C++ -*-===// +//===-- ObjectFileXCOFF.h --------------------------------------- -*- C++ +//-*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -9,16 +10,14 @@ #ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H #define LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H -#include - -#include - #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/UUID.h" #include "lldb/lldb-private.h" #include "llvm/Object/XCOFFObjectFile.h" +#include +#include /// \class ObjectFileXCOFF /// Generic XCOFF object file reader. @@ -240,4 +239,4 @@ class ObjectFileXCOFF : public lldb_private::ObjectFile { std::map> m_deps_base_members; }; -#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILE_H >From f8b05dfc9fc75177a63dfa2d6df4a9af143b09b8 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 5 Jan 2025 05:01:47 -0600 Subject: [PATCH 20/47] HostInfoAIX Cleanup --- lldb/include/lldb/Host/aix/HostInfoAIX.h | 4 - lldb/source/Host/aix/HostInfoAIX.cpp | 108 ----------------------- 2 files changed, 112 deletions(-) diff --git a/lldb/include/lldb/Host/aix/HostInfoAIX.h b/lldb/include/lldb/Host/aix/HostInfoAIX.h index ba727e1d5f171..5a52c42fa6199 100644 --- a/lldb/include/lldb/Host/aix/HostInfoAIX.h +++ b/lldb/include/lldb/Host/aix/HostInfoAIX.h @@ -23,12 +23,8 @@ class HostInfoAIX : public HostInfoPosix { static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr); static void Terminate(); - static llvm::StringRef GetDistributionId(); static FileSpec GetProgramFileSpec(); -protected: - static void ComputeHostArchitectureSupport(ArchSpec &arch_32, - ArchSpec &arch_64); }; } diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp index ef07b07c8cab2..2996fcb55f811 100644 --- a/lldb/source/Host/aix/HostInfoAIX.cpp +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -11,117 +11,25 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" - #include "llvm/Support/Threading.h" - #include #include #include #include #include - #include #include using namespace lldb_private; -namespace { -struct HostInfoAIXFields { - llvm::once_flag m_distribution_once_flag; - std::string m_distribution_id; -}; -} // namespace - -static HostInfoAIXFields *g_fields = nullptr; - void HostInfoAIX::Initialize(SharedLibraryDirectoryHelper *helper) { HostInfoPosix::Initialize(helper); - - g_fields = new HostInfoAIXFields(); } void HostInfoAIX::Terminate() { - assert(g_fields && "Missing call to Initialize?"); - delete g_fields; - g_fields = nullptr; HostInfoBase::Terminate(); } -llvm::StringRef HostInfoAIX::GetDistributionId() { - assert(g_fields && "Missing call to Initialize?"); - // Try to run 'lbs_release -i', and use that response for the distribution - // id. - llvm::call_once(g_fields->m_distribution_once_flag, []() { - Log *log = GetLog(LLDBLog::Host); - LLDB_LOGF(log, "attempting to determine AIX distribution..."); - - // check if the lsb_release command exists at one of the following paths - const char *const exe_paths[] = {"/bin/lsb_release", - "/usr/bin/lsb_release"}; - - for (size_t exe_index = 0; - exe_index < sizeof(exe_paths) / sizeof(exe_paths[0]); ++exe_index) { - const char *const get_distribution_info_exe = exe_paths[exe_index]; - if (access(get_distribution_info_exe, F_OK)) { - // this exe doesn't exist, move on to next exe - LLDB_LOGF(log, "executable doesn't exist: %s", - get_distribution_info_exe); - continue; - } - - // execute the distribution-retrieval command, read output - std::string get_distribution_id_command(get_distribution_info_exe); - get_distribution_id_command += " -i"; - - FILE *file = popen(get_distribution_id_command.c_str(), "r"); - if (!file) { - LLDB_LOGF(log, - "failed to run command: \"%s\", cannot retrieve " - "platform information", - get_distribution_id_command.c_str()); - break; - } - - // retrieve the distribution id string. - char distribution_id[256] = {'\0'}; - if (fgets(distribution_id, sizeof(distribution_id) - 1, file) != - nullptr) { - LLDB_LOGF(log, "distribution id command returned \"%s\"", - distribution_id); - - const char *const distributor_id_key = "Distributor ID:\t"; - if (strstr(distribution_id, distributor_id_key)) { - // strip newlines - std::string id_string(distribution_id + strlen(distributor_id_key)); - llvm::erase(id_string, '\n'); - - // lower case it and convert whitespace to underscores - std::transform( - id_string.begin(), id_string.end(), id_string.begin(), - [](char ch) { return tolower(isspace(ch) ? '_' : ch); }); - - g_fields->m_distribution_id = id_string; - LLDB_LOGF(log, "distribution id set to \"%s\"", - g_fields->m_distribution_id.c_str()); - } else { - LLDB_LOGF(log, "failed to find \"%s\" field in \"%s\"", - distributor_id_key, distribution_id); - } - } else { - LLDB_LOGF(log, - "failed to retrieve distribution id, \"%s\" returned no" - " lines", - get_distribution_id_command.c_str()); - } - - // clean up the file - pclose(file); - } - }); - - return g_fields->m_distribution_id; -} - FileSpec HostInfoAIX::GetProgramFileSpec() { static FileSpec g_program_filespec; @@ -136,19 +44,3 @@ FileSpec HostInfoAIX::GetProgramFileSpec() { return g_program_filespec; } - -void HostInfoAIX::ComputeHostArchitectureSupport(ArchSpec &arch_32, - ArchSpec &arch_64) { - HostInfoPosix::ComputeHostArchitectureSupport(arch_32, arch_64); - - // "unknown" in the vendor slot isn't what we want for the default - // triple. It's probably an artifact of config.guess. - if (arch_32.IsValid()) { - if (arch_32.GetTriple().getVendor() == llvm::Triple::UnknownVendor) - arch_32.GetTriple().setVendorName(llvm::StringRef()); - } - if (arch_64.IsValid()) { - if (arch_64.GetTriple().getVendor() == llvm::Triple::UnknownVendor) - arch_64.GetTriple().setVendorName(llvm::StringRef()); - } -} >From 57d080e44e80203a6ab848c362469954a7c9f067 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 5 Jan 2025 05:49:40 -0600 Subject: [PATCH 21/47] Cleanup HostInfoAIX Including the previous commit, Removed: GetDistributionID, ComputeHostArchitectureSupport and Reduced GetProgramFileSpec as it was not needed --- lldb/source/Host/aix/HostInfoAIX.cpp | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp index 2996fcb55f811..d09b9052668af 100644 --- a/lldb/source/Host/aix/HostInfoAIX.cpp +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -26,21 +26,9 @@ void HostInfoAIX::Initialize(SharedLibraryDirectoryHelper *helper) { HostInfoPosix::Initialize(helper); } -void HostInfoAIX::Terminate() { - HostInfoBase::Terminate(); -} +void HostInfoAIX::Terminate() { HostInfoBase::Terminate(); } FileSpec HostInfoAIX::GetProgramFileSpec() { static FileSpec g_program_filespec; - - if (!g_program_filespec) { - char exe_path[PATH_MAX]; - ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); - if (len > 0) { - exe_path[len] = 0; - g_program_filespec.SetFile(exe_path, FileSpec::Style::native); - } - } - return g_program_filespec; } >From 673713a9339de4e4ea395ee2e7f65dc1db43bcf9 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 5 Jan 2025 15:35:23 -0600 Subject: [PATCH 22/47] Removing headers --- lldb/include/lldb/Host/aix/HostInfoAIX.h | 2 -- lldb/source/Host/aix/HostInfoAIX.cpp | 12 ------------ 2 files changed, 14 deletions(-) diff --git a/lldb/include/lldb/Host/aix/HostInfoAIX.h b/lldb/include/lldb/Host/aix/HostInfoAIX.h index 5a52c42fa6199..331a274630850 100644 --- a/lldb/include/lldb/Host/aix/HostInfoAIX.h +++ b/lldb/include/lldb/Host/aix/HostInfoAIX.h @@ -11,8 +11,6 @@ #include "lldb/Host/posix/HostInfoPosix.h" #include "lldb/Utility/FileSpec.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/VersionTuple.h" namespace lldb_private { diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp index d09b9052668af..61b47462dd647 100644 --- a/lldb/source/Host/aix/HostInfoAIX.cpp +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -7,18 +7,6 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/aix/HostInfoAIX.h" -#include "lldb/Host/Config.h" -#include "lldb/Host/FileSystem.h" -#include "lldb/Utility/LLDBLog.h" -#include "lldb/Utility/Log.h" -#include "llvm/Support/Threading.h" -#include -#include -#include -#include -#include -#include -#include using namespace lldb_private; >From cdc31f3963365e4595247ff5a7155662df1ce1af Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 6 Jan 2025 09:28:56 -0600 Subject: [PATCH 23/47] Reverted merge blunder CMakeLists --- lldb/source/Host/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index f326bc07dc1f6..f4fca8acc4d83 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -141,7 +141,10 @@ else() elseif (CMAKE_SYSTEM_NAME MATCHES "AIX") add_host_subdirectory(aix + aix/AbstractSocket.cpp + aix/Host.cpp aix/HostInfoAIX.cpp + aix/Support.cpp ) endif() endif() >From 713a6cbbb97b9bc56b039ab050a1690eccc017e3 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 6 Jan 2025 09:39:36 -0600 Subject: [PATCH 24/47] Removed DomainSocket.cpp FileSystemPosix.cpp includes --- lldb/source/Host/posix/DomainSocket.cpp | 4 ---- lldb/source/Host/posix/FileSystemPosix.cpp | 3 --- 2 files changed, 7 deletions(-) diff --git a/lldb/source/Host/posix/DomainSocket.cpp b/lldb/source/Host/posix/DomainSocket.cpp index f30e84d83efca..be8fcdf2c8f2c 100644 --- a/lldb/source/Host/posix/DomainSocket.cpp +++ b/lldb/source/Host/posix/DomainSocket.cpp @@ -17,10 +17,6 @@ #include #include -#if defined(_AIX) -#include -#endif - using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index 1a84f550662d7..a631bb01209ec 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,9 +11,6 @@ // C includes #include #include -#ifndef _AIX -#include -#endif #include #include #include >From 0a706d29dabeefa62e354fc9358d650f89032048 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 6 Jan 2025 09:44:10 -0600 Subject: [PATCH 25/47] sys/mount.h --- lldb/source/Host/posix/FileSystemPosix.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index a631bb01209ec..945e2affc8371 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,6 +11,7 @@ // C includes #include #include +#include #include #include #include >From 84ebb4ec9b542c38fe1b60261a3253383e9fbf5d Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 6 Jan 2025 09:54:58 -0600 Subject: [PATCH 26/47] sys/mount.h --- lldb/source/Host/posix/FileSystemPosix.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index 945e2affc8371..1a84f550662d7 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,7 +11,9 @@ // C includes #include #include +#ifndef _AIX #include +#endif #include #include #include >From 844f7980040de9e13620e9d65a3fcaef56b6c8d6 Mon Sep 17 00:00:00 2001 From: Dhruv Srivastava Date: Thu, 9 Jan 2025 09:47:43 +0530 Subject: [PATCH 27/47] Removed _AIX from ConnectionFileDescriptorPosix.cpp --- lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index 2530c8fa353ba..0ed2016667162 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -715,7 +715,7 @@ ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, ConnectionStatus ConnectionFileDescriptor::ConnectFile( llvm::StringRef s, socket_id_callback_type socket_id_callback, Status *error_ptr) { -#if LLDB_ENABLE_POSIX && !defined(_AIX) +#if LLDB_ENABLE_POSIX std::string addr_str = s.str(); // file:///PATH int fd = FileSystem::Instance().Open(addr_str.c_str(), O_RDWR); @@ -756,7 +756,7 @@ ConnectionStatus ConnectionFileDescriptor::ConnectFile( m_io_sp = std::make_shared(fd, File::eOpenOptionReadWrite, true); return eConnectionStatusSuccess; -#endif // LLDB_ENABLE_POSIX && !defined(_AIX) +#endif // LLDB_ENABLE_POSIX llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX"); } >From 4fe42cda7c2f4990b18a39c1d6563094fb88775f Mon Sep 17 00:00:00 2001 From: ravindra shinde Date: Fri, 17 Jan 2025 13:58:13 +0530 Subject: [PATCH 28/47] [ObjectFileXCOFF] Fix access to protected member 'GetSectionLoadList' in Target - Added a public method to Target for accessing 'GetSectionLoadList' safely. - Updated ObjectFileXCOFF to use the new public method, ensuring compliance with encapsulation rules. This resolves the build error caused by direct access to the protected member. Signed-off-by: ravindra shinde --- lldb/include/lldb/Target/Target.h | 5 +++++ lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index f31ac381391b4..75f9c9c2e999c 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -522,6 +522,7 @@ class Target : public std::enable_shared_from_this, eBroadcastBitSymbolsChanged = (1 << 5), }; + // These two functions fill out the Broadcaster interface: static llvm::StringRef GetStaticBroadcasterClass(); @@ -1644,6 +1645,10 @@ class Target : public std::enable_shared_from_this, TargetStats &GetStatistics() { return m_stats; } +public: + SectionLoadList &GetSectionLoadListPublic() { + return GetSectionLoadList(); + } protected: /// Construct with optional file and arch. /// diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index afd8027bab06c..cf11e5fb8f5a3 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -340,7 +340,7 @@ bool ObjectFileXCOFF::SetLoadAddress(Target &target, lldb::addr_t value, strcmp(section_sp->GetName().AsCString(), ".bss") == 0) use_offset = true; - if (target.GetSectionLoadList().SetSectionLoadAddress( + if (target.GetSectionLoadListPublic().SetSectionLoadAddress( section_sp, (use_offset ? (section_sp->GetFileOffset() + value) : (section_sp->GetFileAddress() + value)))) ++num_loaded_sections; @@ -369,13 +369,13 @@ bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); if (type_id == 1 && section_sp && strcmp(section_sp->GetName().AsCString(), ".text") == 0) { if (!section_sp->IsThreadSpecific()) { - if (target.GetSectionLoadList().SetSectionLoadAddress( + if (target.GetSectionLoadListPublic().SetSectionLoadAddress( section_sp, section_sp->GetFileOffset() + value)) ++num_loaded_sections; } } else if (type_id == 2 && section_sp && strcmp(section_sp->GetName().AsCString(), ".data") == 0) { if (!section_sp->IsThreadSpecific()) { - if (target.GetSectionLoadList().SetSectionLoadAddress( + if (target.GetSectionLoadListPublic().SetSectionLoadAddress( section_sp, section_sp->GetFileAddress() + value)) ++num_loaded_sections; } >From e5ed4f21c5bbc709e5e2eff0f83995cc6d89de48 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 19 Jan 2025 03:43:11 -0600 Subject: [PATCH 29/47] Resolved cmake failure for SBProgress.cpp --- lldb/source/API/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index eb348e2b97232..0a03e000c0cae 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -85,6 +85,7 @@ add_lldb_library(liblldb STATIC ${option_framework} SBModuleSpec.cpp SBPlatform.cpp SBProcess.cpp + SBProgress.cpp SBProcessInfo.cpp SBProcessInfoList.cpp SBQueue.cpp >From 82dbcb0e776c438e5f40c9f8d8c8e8eb81b7febd Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 27 Jan 2025 06:35:19 -0600 Subject: [PATCH 30/47] Host.cpp ANDROID --- lldb/source/Host/common/Host.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 758e9f49ade2c..adf74df8aa90b 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -1,4 +1,4 @@ -//===-- Host.cpp ----------------------------------------------------------===// + // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -516,7 +516,6 @@ static int dladdr(const void *ptr, Dl_info *dl) FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSpec module_filespec; -#if !defined(__ANDROID__) #ifdef _AIX if (host_addr == reinterpret_cast(HostInfoBase::ComputeSharedLibraryDirectory)) { // FIXME: AIX dladdr return "lldb" for this case @@ -527,6 +526,7 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { } } #endif +#if !defined(__ANDROID__) Dl_info info; if (::dladdr(host_addr, &info)) { if (info.dli_fname) { @@ -534,6 +534,7 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSystem::Instance().Resolve(module_filespec); } } +#endif return module_filespec; } >From 60294eaa1611632afc94b9da503752e34ad2703d Mon Sep 17 00:00:00 2001 From: Ravindra Shinde Date: Tue, 4 Feb 2025 03:23:56 -0600 Subject: [PATCH 31/47] Resolving the fatal error while build Build is failing due to the fatal error: 'sys/syscall.h' file not found Signed-off-by: Ravindra Shinde --- lldb/source/Host/common/Host.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 40ce76d70d6e8..b5bd68b8539bd 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -18,8 +18,12 @@ #include #include #include + +#ifndef _AIX #include #include +#endif + #include #include #endif >From 2644be59b13a61c69cc635875c94b0b4645fe76c Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 10 Feb 2025 01:49:12 -0600 Subject: [PATCH 32/47] InferiorCallPOSIX.cpp --- lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index d1f9fe851119e..8e74cce097894 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -120,12 +120,13 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, arch, addr, length, prot_arg, flags, fd, offset); #if defined(_AIX) lldb::ThreadPlanSP call_plan_sp( - new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(), + new ThreadPlanCallFunction(*thread, mmap_addr, toc_range.GetBaseAddress(), void_ptr_type, args, options)); #else lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallFunction( *thread, mmap_addr, void_ptr_type, args, options)); +#endif if (call_plan_sp) { DiagnosticManager diagnostics; >From 4805b13cba964b58def39a66ad4c4309a9b2c501 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 12 Feb 2025 07:33:04 -0600 Subject: [PATCH 33/47] Merge branch gh-101657 --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 97 ------------------- .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 5 +- 2 files changed, 1 insertion(+), 101 deletions(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 1a98bb9334043..375d879c7a995 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -21,10 +21,6 @@ #include "llvm/Support/FileSystem.h" #if defined(_AIX) #include -#include -#include -#include -#include #endif /*#include "llvm/ADT/Triple.h" @@ -137,107 +133,14 @@ bool DynamicLoaderAIXDYLD::NotifyBreakpointHit( } -void DynamicLoaderAIXDYLD::ResolveExecutableModule( - lldb::ModuleSP &module_sp) { - Log *log = GetLog(LLDBLog::DynamicLoader); - - if (m_process == nullptr) - return; - - auto &target = m_process->GetTarget(); - const auto platform_sp = target.GetPlatform(); - - ProcessInstanceInfo process_info; - if (!m_process->GetProcessInfo(process_info)) { - LLDB_LOGF(log, - "DynamicLoaderPOSIXDYLD::%s - failed to get process info for " - "pid %" PRIu64, - __FUNCTION__, m_process->GetID()); - return; - } - - int32long64_t pid = m_process->GetID(); - char cwd[PATH_MAX], resolved_path[PATH_MAX]; - std::string executable_name; - bool path_resolved = false; - psinfo_t psinfo; - - std::string proc_file = "/proc/" + std::to_string(pid) + "/psinfo"; - std::string cwd_link = "/proc/" + std::to_string(pid) + "/cwd"; - std::ifstream file(proc_file, std::ios::binary); - if(!file.is_open()) - LLDB_LOGF(log, "Error: Unable to access process info "); - - file.read(reinterpret_cast(&psinfo), sizeof(psinfo_t)); - if(!file) - LLDB_LOGF(log, "Process info error: Failed to read "); - - std::string relative_path(psinfo.pr_fname); - LLDB_LOGF(log, "Relative path %s",relative_path.c_str()); - - if(readlink(cwd_link.c_str(), cwd, sizeof(cwd)) != -1){ - std::filesystem::path full_path = std::filesystem::path(cwd)/relative_path; - if(realpath(full_path.c_str(), resolved_path)) { - LLDB_LOGF(log, "Resolved Path using process info : %s", resolved_path); - path_resolved = true; - } - else - LLDB_LOGF(log, "Realpath error: Unable to resolve. "); - } - - executable_name = resolved_path; - if(path_resolved == false) { - std::string command_line(psinfo.pr_psargs); - LLDB_LOGF(log, "Command line: %s",command_line.c_str()); - if (!command_line.empty()) { - size_t space1 = command_line.find(' '); - executable_name = command_line.substr(0, space1); - LLDB_LOGF(log, "Resolved path using command line arg %s",executable_name.c_str()); - } - } - - LLDB_LOGF(log, "Executable Name %s",executable_name.c_str()); - process_info.SetExecutableFile(lldb_private::FileSpec(executable_name), - true); - - LLDB_LOGF( - log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s", - __FUNCTION__, m_process->GetID(), - process_info.GetExecutableFile().GetPath().c_str()); - - ModuleSpec module_spec(process_info.GetExecutableFile(), - process_info.GetArchitecture()); - if (module_sp && module_sp->MatchesModuleSpec(module_spec)) - return; - - const auto executable_search_paths(Target::GetDefaultExecutableSearchPaths()); - auto error = platform_sp->ResolveExecutable( - module_spec, module_sp, - !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr); - if (error.Fail()) { - StreamString stream; - module_spec.Dump(stream); - - LLDB_LOGF(log, - "DynamicLoaderPOSIXDYLD::%s - failed to resolve executable " - "with module spec \"%s\": %s", - __FUNCTION__, stream.GetData(), error.AsCString()); - return; - } - - target.SetExecutableModule(module_sp, eLoadDependentsNo); -} - void DynamicLoaderAIXDYLD::DidAttach() { Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); ModuleSP executable = GetTargetExecutable(); - ResolveExecutableModule(executable); if (!executable.get()) return; - LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); // Try to fetch the load address of the file from the process, since there // could be randomization of the load address. diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h index 0ffbe688e0069..ae4b7aca66dcc 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -24,7 +24,7 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { static void Initialize(); static void Terminate(); - static llvm::StringRef GetPluginNameStatic() { return "aix-dyld"; } + static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; } static llvm::StringRef GetPluginDescriptionStatic(); static DynamicLoader *CreateInstance(Process *process, bool force); @@ -46,9 +46,6 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { protected: lldb::addr_t GetLoadAddress(lldb::ModuleSP executable); - /// Loads Module from inferior process. - void ResolveExecutableModule(lldb::ModuleSP &module_sp); - private: std::map m_loaded_modules; }; >From cff574b36903e12385e5d6cddf4532ba279f47de Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 12 Feb 2025 07:52:04 -0600 Subject: [PATCH 34/47] Fix for Debugging Attach to AIX Process --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 97 +++++++++++++++++++ .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 5 +- 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 375d879c7a995..1a98bb9334043 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -21,6 +21,10 @@ #include "llvm/Support/FileSystem.h" #if defined(_AIX) #include +#include +#include +#include +#include #endif /*#include "llvm/ADT/Triple.h" @@ -133,14 +137,107 @@ bool DynamicLoaderAIXDYLD::NotifyBreakpointHit( } +void DynamicLoaderAIXDYLD::ResolveExecutableModule( + lldb::ModuleSP &module_sp) { + Log *log = GetLog(LLDBLog::DynamicLoader); + + if (m_process == nullptr) + return; + + auto &target = m_process->GetTarget(); + const auto platform_sp = target.GetPlatform(); + + ProcessInstanceInfo process_info; + if (!m_process->GetProcessInfo(process_info)) { + LLDB_LOGF(log, + "DynamicLoaderPOSIXDYLD::%s - failed to get process info for " + "pid %" PRIu64, + __FUNCTION__, m_process->GetID()); + return; + } + + int32long64_t pid = m_process->GetID(); + char cwd[PATH_MAX], resolved_path[PATH_MAX]; + std::string executable_name; + bool path_resolved = false; + psinfo_t psinfo; + + std::string proc_file = "/proc/" + std::to_string(pid) + "/psinfo"; + std::string cwd_link = "/proc/" + std::to_string(pid) + "/cwd"; + std::ifstream file(proc_file, std::ios::binary); + if(!file.is_open()) + LLDB_LOGF(log, "Error: Unable to access process info "); + + file.read(reinterpret_cast(&psinfo), sizeof(psinfo_t)); + if(!file) + LLDB_LOGF(log, "Process info error: Failed to read "); + + std::string relative_path(psinfo.pr_fname); + LLDB_LOGF(log, "Relative path %s",relative_path.c_str()); + + if(readlink(cwd_link.c_str(), cwd, sizeof(cwd)) != -1){ + std::filesystem::path full_path = std::filesystem::path(cwd)/relative_path; + if(realpath(full_path.c_str(), resolved_path)) { + LLDB_LOGF(log, "Resolved Path using process info : %s", resolved_path); + path_resolved = true; + } + else + LLDB_LOGF(log, "Realpath error: Unable to resolve. "); + } + + executable_name = resolved_path; + if(path_resolved == false) { + std::string command_line(psinfo.pr_psargs); + LLDB_LOGF(log, "Command line: %s",command_line.c_str()); + if (!command_line.empty()) { + size_t space1 = command_line.find(' '); + executable_name = command_line.substr(0, space1); + LLDB_LOGF(log, "Resolved path using command line arg %s",executable_name.c_str()); + } + } + + LLDB_LOGF(log, "Executable Name %s",executable_name.c_str()); + process_info.SetExecutableFile(lldb_private::FileSpec(executable_name), + true); + + LLDB_LOGF( + log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s", + __FUNCTION__, m_process->GetID(), + process_info.GetExecutableFile().GetPath().c_str()); + + ModuleSpec module_spec(process_info.GetExecutableFile(), + process_info.GetArchitecture()); + if (module_sp && module_sp->MatchesModuleSpec(module_spec)) + return; + + const auto executable_search_paths(Target::GetDefaultExecutableSearchPaths()); + auto error = platform_sp->ResolveExecutable( + module_spec, module_sp, + !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr); + if (error.Fail()) { + StreamString stream; + module_spec.Dump(stream); + + LLDB_LOGF(log, + "DynamicLoaderPOSIXDYLD::%s - failed to resolve executable " + "with module spec \"%s\": %s", + __FUNCTION__, stream.GetData(), error.AsCString()); + return; + } + + target.SetExecutableModule(module_sp, eLoadDependentsNo); +} + void DynamicLoaderAIXDYLD::DidAttach() { Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); ModuleSP executable = GetTargetExecutable(); + ResolveExecutableModule(executable); if (!executable.get()) return; + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); // Try to fetch the load address of the file from the process, since there // could be randomization of the load address. diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h index ae4b7aca66dcc..0ffbe688e0069 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -24,7 +24,7 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { static void Initialize(); static void Terminate(); - static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; } + static llvm::StringRef GetPluginNameStatic() { return "aix-dyld"; } static llvm::StringRef GetPluginDescriptionStatic(); static DynamicLoader *CreateInstance(Process *process, bool force); @@ -46,6 +46,9 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { protected: lldb::addr_t GetLoadAddress(lldb::ModuleSP executable); + /// Loads Module from inferior process. + void ResolveExecutableModule(lldb::ModuleSP &module_sp); + private: std::map m_loaded_modules; }; >From 303fa3bc078d7572702fb302726d4dd1bd13ddb2 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Fri, 21 Feb 2025 06:18:33 -0600 Subject: [PATCH 35/47] Merge branch 'llvm:main' into gh-101657 --- lldb/source/Plugins/Platform/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/lldb/source/Plugins/Platform/CMakeLists.txt b/lldb/source/Plugins/Platform/CMakeLists.txt index f5b0dbdd5e0a9..0220e734b36d1 100644 --- a/lldb/source/Plugins/Platform/CMakeLists.txt +++ b/lldb/source/Plugins/Platform/CMakeLists.txt @@ -9,4 +9,3 @@ add_subdirectory(OpenBSD) add_subdirectory(POSIX) add_subdirectory(QemuUser) add_subdirectory(Windows) -add_subdirectory(AIX) >From 6947dec02bb527f710c1bea3827b2c16d89f308a Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Fri, 21 Feb 2025 07:02:53 -0600 Subject: [PATCH 36/47] Merge branch 'llvm:main' into gh-101657 --- .../Plugins/Platform/AIX/PlatformAIX.cpp | 171 +----------------- 1 file changed, 1 insertion(+), 170 deletions(-) diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp index 0d66325d16267..21724d83133e9 100644 --- a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp +++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp @@ -130,12 +130,6 @@ void PlatformAIX::GetStatus(Stream &strm) { #endif } -void PlatformAIX::CalculateTrapHandlerSymbolNames() { - m_trap_handlers.push_back(ConstString("_sigtramp")); - m_trap_handlers.push_back(ConstString("__kernel_rt_sigreturn")); - m_trap_handlers.push_back(ConstString("__restore_rt")); -} - void PlatformAIX::CalculateTrapHandlerSymbolNames() {} lldb::UnwindPlanSP @@ -160,168 +154,5 @@ MmapArgList PlatformAIX::GetMmapArgumentList(const ArchSpec &arch, addr_t addr, } CompilerType PlatformAIX::GetSiginfoType(const llvm::Triple &triple) { - if (!m_type_system_up) - m_type_system_up.reset(new TypeSystemClang("siginfo", triple)); - TypeSystemClang *ast = m_type_system_up.get(); - - bool si_errno_then_code = true; - - switch (triple.getArch()) { - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - // mips has si_code and si_errno swapped - si_errno_then_code = false; - break; - default: - break; - } - - // generic types - CompilerType int_type = ast->GetBasicType(eBasicTypeInt); - CompilerType uint_type = ast->GetBasicType(eBasicTypeUnsignedInt); - CompilerType short_type = ast->GetBasicType(eBasicTypeShort); - CompilerType long_type = ast->GetBasicType(eBasicTypeLong); - CompilerType voidp_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); - - // platform-specific types - CompilerType &pid_type = int_type; - CompilerType &uid_type = uint_type; - CompilerType &clock_type = long_type; - CompilerType &band_type = long_type; - - CompilerType sigval_type = ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_sigval_t", - llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); - ast->StartTagDeclarationDefinition(sigval_type); - ast->AddFieldToRecordType(sigval_type, "sival_int", int_type, - lldb::eAccessPublic, 0); - ast->AddFieldToRecordType(sigval_type, "sival_ptr", voidp_type, - lldb::eAccessPublic, 0); - ast->CompleteTagDeclarationDefinition(sigval_type); - - CompilerType sigfault_bounds_type = ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", - llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); - ast->StartTagDeclarationDefinition(sigfault_bounds_type); - ast->AddFieldToRecordType(sigfault_bounds_type, "_addr_bnd", - ast->CreateStructForIdentifier(ConstString(), - { - {"_lower", voidp_type}, - {"_upper", voidp_type}, - }), - lldb::eAccessPublic, 0); - ast->AddFieldToRecordType(sigfault_bounds_type, "_pkey", uint_type, - lldb::eAccessPublic, 0); - ast->CompleteTagDeclarationDefinition(sigfault_bounds_type); - - // siginfo_t - CompilerType siginfo_type = ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_siginfo_t", - llvm::to_underlying(clang::TagTypeKind::Struct), lldb::eLanguageTypeC); - ast->StartTagDeclarationDefinition(siginfo_type); - ast->AddFieldToRecordType(siginfo_type, "si_signo", int_type, - lldb::eAccessPublic, 0); - - if (si_errno_then_code) { - ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type, - lldb::eAccessPublic, 0); - ast->AddFieldToRecordType(siginfo_type, "si_code", int_type, - lldb::eAccessPublic, 0); - } else { - ast->AddFieldToRecordType(siginfo_type, "si_code", int_type, - lldb::eAccessPublic, 0); - ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type, - lldb::eAccessPublic, 0); - } - - // the structure is padded on 64-bit arches to fix alignment - if (triple.isArch64Bit()) - ast->AddFieldToRecordType(siginfo_type, "__pad0", int_type, - lldb::eAccessPublic, 0); - - // union used to hold the signal data - CompilerType union_type = ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", - llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); - ast->StartTagDeclarationDefinition(union_type); - - ast->AddFieldToRecordType( - union_type, "_kill", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_pid", pid_type}, - {"si_uid", uid_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_timer", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_tid", int_type}, - {"si_overrun", int_type}, - {"si_sigval", sigval_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_rt", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_pid", pid_type}, - {"si_uid", uid_type}, - {"si_sigval", sigval_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_sigchld", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_pid", pid_type}, - {"si_uid", uid_type}, - {"si_status", int_type}, - {"si_utime", clock_type}, - {"si_stime", clock_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_sigfault", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_addr", voidp_type}, - {"si_addr_lsb", short_type}, - {"_bounds", sigfault_bounds_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_sigpoll", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_band", band_type}, - {"si_fd", int_type}, - }), - lldb::eAccessPublic, 0); - - // NB: SIGSYS is not present on ia64 but we don't seem to support that - ast->AddFieldToRecordType( - union_type, "_sigsys", - ast->CreateStructForIdentifier(ConstString(), - { - {"_call_addr", voidp_type}, - {"_syscall", int_type}, - {"_arch", uint_type}, - }), - lldb::eAccessPublic, 0); - - ast->CompleteTagDeclarationDefinition(union_type); - ast->AddFieldToRecordType(siginfo_type, "_sifields", union_type, - lldb::eAccessPublic, 0); - - ast->CompleteTagDeclarationDefinition(siginfo_type); - return siginfo_type; + return CompilerType(); } >From 24615119addcdf9fe5a8c5b2ebd0c15d75651279 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sat, 22 Feb 2025 03:42:26 -0600 Subject: [PATCH 37/47] Removed un-needed changes --- lldb/include/lldb/Host/aix/AbstractSocket.h | 25 --------------------- lldb/include/lldb/Host/aix/Uio.h | 23 ------------------- lldb/source/Host/CMakeLists.txt | 1 - lldb/source/Host/aix/AbstractSocket.cpp | 20 ----------------- 4 files changed, 69 deletions(-) delete mode 100644 lldb/include/lldb/Host/aix/AbstractSocket.h delete mode 100644 lldb/include/lldb/Host/aix/Uio.h delete mode 100644 lldb/source/Host/aix/AbstractSocket.cpp diff --git a/lldb/include/lldb/Host/aix/AbstractSocket.h b/lldb/include/lldb/Host/aix/AbstractSocket.h deleted file mode 100644 index accfd01457a5e..0000000000000 --- a/lldb/include/lldb/Host/aix/AbstractSocket.h +++ /dev/null @@ -1,25 +0,0 @@ -//===-- AbstractSocket.h ----------------------------------------*- 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 -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_AbstractSocket_h_ -#define liblldb_AbstractSocket_h_ - -#include "lldb/Host/posix/DomainSocket.h" - -namespace lldb_private { -class AbstractSocket : public DomainSocket { -public: - AbstractSocket(); - -protected: - size_t GetNameOffset() const override; - void DeleteSocketFile(llvm::StringRef name) override; -}; -} - -#endif // ifndef liblldb_AbstractSocket_h_ diff --git a/lldb/include/lldb/Host/aix/Uio.h b/lldb/include/lldb/Host/aix/Uio.h deleted file mode 100644 index acf79ecc6a1d0..0000000000000 --- a/lldb/include/lldb/Host/aix/Uio.h +++ /dev/null @@ -1,23 +0,0 @@ -//===-- Uio.h ---------------------------------------------------*- 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 -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_Host_aix_Uio_h_ -#define liblldb_Host_aix_Uio_h_ - -#include "lldb/Host/Config.h" -#include - -// We shall provide our own implementation of process_vm_readv if it is not -// present -#if !HAVE_PROCESS_VM_READV -ssize_t process_vm_readv(::pid_t pid, const struct iovec *local_iov, - unsigned long liovcnt, const struct iovec *remote_iov, - unsigned long riovcnt, unsigned long flags); -#endif - -#endif // liblldb_Host_aix_Uio_h_ diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index bb6b5befa16e4..5a14b4c629825 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -140,7 +140,6 @@ else() elseif (CMAKE_SYSTEM_NAME MATCHES "AIX") add_host_subdirectory(aix - aix/AbstractSocket.cpp aix/Host.cpp aix/HostInfoAIX.cpp aix/Support.cpp diff --git a/lldb/source/Host/aix/AbstractSocket.cpp b/lldb/source/Host/aix/AbstractSocket.cpp deleted file mode 100644 index fddf78f54f46d..0000000000000 --- a/lldb/source/Host/aix/AbstractSocket.cpp +++ /dev/null @@ -1,20 +0,0 @@ -//===-- AbstractSocket.cpp ------------------------------------------------===// -// -// 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 "lldb/Host/aix/AbstractSocket.h" - -#include "llvm/ADT/StringRef.h" - -using namespace lldb; -using namespace lldb_private; - -AbstractSocket::AbstractSocket() : DomainSocket(ProtocolUnixAbstract) {} - -size_t AbstractSocket::GetNameOffset() const { return 1; } - -void AbstractSocket::DeleteSocketFile(llvm::StringRef name) {} >From 25bea9ca48dc458c1dddd72f10a483e76926a04e Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Wed, 26 Feb 2025 01:10:15 -0600 Subject: [PATCH 38/47] Resolving coredump issue while attach with library calls --- lldb/include/lldb/Core/ModuleSpec.h | 2 ++ lldb/source/Core/ModuleList.cpp | 12 +++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lldb/include/lldb/Core/ModuleSpec.h b/lldb/include/lldb/Core/ModuleSpec.h index 4fe06412b6b0b..9d79992b48c7e 100644 --- a/lldb/include/lldb/Core/ModuleSpec.h +++ b/lldb/include/lldb/Core/ModuleSpec.h @@ -122,6 +122,8 @@ class ModuleSpec { ConstString &GetObjectName() { return m_object_name; } ConstString GetObjectName() const { return m_object_name; } + + void SetObjectName(ConstString objName) { m_object_name = objName; } uint64_t GetObjectOffset() const { return m_object_offset; } diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index 2b8ccab2406c6..862a2729c1afb 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -260,7 +260,17 @@ void ModuleList::ReplaceEquivalent( module_sp->GetArchitecture()); equivalent_module_spec.GetPlatformFileSpec() = module_sp->GetPlatformFileSpec(); - +#ifdef _AIX + // To remove the exact equivalent module, the object name must be + // specified. When the equivalent_module_spec object is created, its + // object name is initially set to NULL. This is because the module_sp's + // GetPath() returns a path in the format (/usr/ccs/libc.a), which does + // not include the object name. As a result, MatchesModuleSpec may return + // true even though the object name is NULL and doesn't match any loaded + // module. To fix this, set the object name of the equivalent_module_spec + // to be the same as the object name of the module_sp. */ + equivalent_module_spec.SetObjectName(module_sp->GetObjectName()); +#endif size_t idx = 0; while (idx < m_modules.size()) { ModuleSP test_module_sp(m_modules[idx]); >From 349ec0064668a0ee1d3af7c2f38fa7427b4b2d36 Mon Sep 17 00:00:00 2001 From: Dhruv Srivastava Date: Fri, 28 Feb 2025 23:44:40 +0530 Subject: [PATCH 39/47] [AIX][Coredump] AIX Coredump debugging Implementation (#25) Creates a general framework to be able to debug an AIX generated coredump file. At this point, we are only supporting 64-bit core files using this general framework. With this implementation, LLDB can recognise and debug any 64-bit AIX coredump file. Most of the generic debugging commands work after this: # bin/lldb --core /home/dhruv/LLDB/tests/core (lldb) target create --core "/home/dhruv/LLDB/tests/core" Core file '/home/dhruv/LLDB/tests/core' (powerpc64) was loaded. (lldb) bt * thread #1, stop reason = SIGSEGV * frame #0: 0x0000000100000940 coretest64`main at core.c:5 frame #1: 0x00000001000004ac coretest64`__start + 116 (lldb) process status Process 18446744071562067991 stopped * thread #1, stop reason = SIGSEGV frame #0: 0x0000000100000940 coretest64`main at core.c:5 2 char *str; 3 int a = 10; 4 str = "GfG"; -> 5 *(str+1) = 'n'; 6 return a; 7 } And others like memory read, image list, image dump sections, disassembly etc --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 62 ++++- .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 6 + .../Plugins/ObjectFile/AIXCore/CMakeLists.txt | 13 + .../ObjectFile/AIXCore/ObjectFileAIXCore.cpp | 254 ++++++++++++++++++ .../ObjectFile/AIXCore/ObjectFileAIXCore.h | 121 +++++++++ lldb/source/Plugins/ObjectFile/CMakeLists.txt | 1 + lldb/source/Plugins/Process/CMakeLists.txt | 1 + .../Plugins/Process/aix-core/AIXCore.cpp | 116 ++++++++ .../source/Plugins/Process/aix-core/AIXCore.h | 125 +++++++++ .../Plugins/Process/aix-core/CMakeLists.txt | 16 ++ .../Process/aix-core/ProcessAIXCore.cpp | 251 +++++++++++++++++ .../Plugins/Process/aix-core/ProcessAIXCore.h | 100 +++++++ .../aix-core/RegisterContextCoreAIX_ppc64.cpp | 136 ++++++++++ .../aix-core/RegisterContextCoreAIX_ppc64.h | 46 ++++ .../Process/aix-core/ThreadAIXCore.cpp | 127 +++++++++ .../Plugins/Process/aix-core/ThreadAIXCore.h | 110 ++++++++ 16 files changed, 1484 insertions(+), 1 deletion(-) create mode 100644 lldb/source/Plugins/ObjectFile/AIXCore/CMakeLists.txt create mode 100644 lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp create mode 100644 lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.h create mode 100644 lldb/source/Plugins/Process/aix-core/AIXCore.cpp create mode 100644 lldb/source/Plugins/Process/aix-core/AIXCore.h create mode 100644 lldb/source/Plugins/Process/aix-core/CMakeLists.txt create mode 100644 lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp create mode 100644 lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h create mode 100644 lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.cpp create mode 100644 lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.h create mode 100644 lldb/source/Plugins/Process/aix-core/ThreadAIXCore.cpp create mode 100644 lldb/source/Plugins/Process/aix-core/ThreadAIXCore.h diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 1a98bb9334043..7e44ffbb1c051 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -228,6 +228,65 @@ void DynamicLoaderAIXDYLD::ResolveExecutableModule( target.SetExecutableModule(module_sp, eLoadDependentsNo); } +bool DynamicLoaderAIXDYLD::IsCoreFile() const { + return !m_process->IsLiveDebugSession(); +} + +void DynamicLoaderAIXDYLD::FillCoreLoaderData(lldb_private::DataExtractor &data, + uint64_t loader_offset, uint64_t loader_size ) { + + static char *buffer = (char *)malloc(loader_size); + struct ld_info ldinfo[64]; + char *buffer_complete; + struct ld_info *ptr; + int i = 0; + + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); + ByteOrder byteorder = data.GetByteOrder(); + data.ExtractBytes(loader_offset, loader_size, eByteOrderBig, buffer); + buffer_complete = buffer + loader_size; + ldinfo[0].ldinfo_next = 1; + + while (ldinfo[i++].ldinfo_next != 0) { + + ptr = (struct ld_info *)buffer; + ldinfo[i].ldinfo_next = ptr->ldinfo_next; + ldinfo[i].ldinfo_flags = ptr->ldinfo_flags; + ldinfo[i].ldinfo_core = ptr->ldinfo_core; + ldinfo[i].ldinfo_textorg = ptr->ldinfo_textorg; + ldinfo[i].ldinfo_textsize = ptr->ldinfo_textsize; + ldinfo[i].ldinfo_dataorg = ptr->ldinfo_dataorg; + ldinfo[i].ldinfo_datasize = ptr->ldinfo_datasize; + + char *filename = &ptr->ldinfo_filename[0]; + char *membername = filename + (strlen(filename) + 1); + strcpy(ldinfo[i].ldinfo_filename, filename); + + buffer += ptr->ldinfo_next; + struct ld_info *ptr2 = &(ldinfo[i]); + char *pathName = ptr2->ldinfo_filename; + char pathWithMember[PATH_MAX] = {0}; + if (strlen(membername) > 0) { + sprintf(pathWithMember, "%s(%s)", pathName, membername); + } else { + sprintf(pathWithMember, "%s", pathName); + } + + FileSpec file(pathWithMember); + ModuleSpec module_spec(file, m_process->GetTarget().GetArchitecture()); + LLDB_LOGF(log, "Module :%s", pathWithMember); + if (ModuleSP module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, true /* notify */)) { + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr2->ldinfo_textorg, false, 1); + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr2->ldinfo_dataorg, false, 2); + // FIXME: .tdata, .bss + } + if (ptr2->ldinfo_next == 0) { + ptr2 = nullptr; + } + } +} + void DynamicLoaderAIXDYLD::DidAttach() { Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); @@ -361,7 +420,8 @@ void DynamicLoaderAIXDYLD::DidLaunch() { #endif } -Status DynamicLoaderAIXDYLD::CanLoadImage() { return Status(); } +Status DynamicLoaderAIXDYLD::CanLoadImage() { + return Status(); } ThreadPlanSP DynamicLoaderAIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h index 0ffbe688e0069..097f8d048b77f 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -33,6 +33,9 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { lldb::addr_t module_addr); void OnUnloadModule(lldb::addr_t module_addr); + void FillCoreLoaderData(lldb_private::DataExtractor &data, + uint64_t loader_offset, uint64_t loader_size); + void DidAttach() override; void DidLaunch() override; Status CanLoadImage() override; @@ -49,6 +52,9 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { /// Loads Module from inferior process. void ResolveExecutableModule(lldb::ModuleSP &module_sp); + /// Returns true if the process is for a core file. + bool IsCoreFile() const; + private: std::map m_loaded_modules; }; diff --git a/lldb/source/Plugins/ObjectFile/AIXCore/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/AIXCore/CMakeLists.txt new file mode 100644 index 0000000000000..5656b33a61726 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/AIXCore/CMakeLists.txt @@ -0,0 +1,13 @@ +add_lldb_library(lldbPluginObjectFileAIXCore PLUGIN + ObjectFileAIXCore.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + lldbTarget + lldbUtility + lldbPluginProcessUtility + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp new file mode 100644 index 0000000000000..5158fa4e25077 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp @@ -0,0 +1,254 @@ +//===-- ObjectFileAIXCore.cpp -------------------------------------------------===// +// +// 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 "ObjectFileAIXCore.h" + +#include +#include +#include +#include + +#include "lldb/Utility/FileSpecList.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Stream.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Object/XCOFFObjectFile.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ObjectFileAIXCore) + +enum CoreVersion : uint64_t {AIXCORE32 = 0xFEEDDB1, AIXCORE64 = 0xFEEDDB2}; + +bool m_is_core = false; + +// Static methods. +void ObjectFileAIXCore::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + CreateMemoryInstance, GetModuleSpecifications); +} + +void ObjectFileAIXCore::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ObjectFile *ObjectFileAIXCore::CreateInstance(const lldb::ModuleSP &module_sp, + DataBufferSP data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t file_offset, + lldb::offset_t length) { + + if(m_is_core) + { + + bool mapped_writable = false; + if (!data_sp) { + data_sp = MapFileDataWritable(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + mapped_writable = true; + } + + assert(data_sp); + + const uint8_t *magic = data_sp->GetBytes() + data_offset; + + // Update the data to contain the entire file if it doesn't already + if (data_sp->GetByteSize() < length) { + data_sp = MapFileDataWritable(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + mapped_writable = true; + magic = data_sp->GetBytes(); + } + + // If we didn't map the data as writable take ownership of the buffer. + if (!mapped_writable) { + data_sp = std::make_shared(data_sp->GetBytes(), + data_sp->GetByteSize()); + data_offset = 0; + magic = data_sp->GetBytes(); + } + + std::unique_ptr objfile_up(new ObjectFileAIXCore( + module_sp, data_sp, data_offset, file, file_offset, length)); + ArchSpec spec = objfile_up->GetArchitecture(); + objfile_up->SetModulesArchitecture(spec); + return objfile_up.release(); + + } +} + +ObjectFile *ObjectFileAIXCore::CreateMemoryInstance( + const lldb::ModuleSP &module_sp, WritableDataBufferSP data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) { + return nullptr; +} + +size_t ObjectFileAIXCore::GetModuleSpecifications( + const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, lldb::offset_t file_offset, + lldb::offset_t length, lldb_private::ModuleSpecList &specs) { + const size_t initial_count = specs.GetSize(); + + if (ObjectFileAIXCore::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) { + // Need new ArchType??? + ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + ModuleSpec spec(file, arch_spec); + spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX); + specs.Append(spec); + } + return specs.GetSize() - initial_count; +} + +static uint32_t AIXCoreHeaderCheckFromMagic(uint32_t magic) { + + Log *log = GetLog(LLDBLog::Modules); + switch (magic) { + case AIXCORE32: + LLDB_LOGF(log, "ObjectFileAIXCore: 32-bit not supported"); + break; + case AIXCORE64: + m_is_core = true; + return 1; + break; + } + return 0; +} + +bool ObjectFileAIXCore::MagicBytesMatch(DataBufferSP &data_sp, + lldb::addr_t data_offset, + lldb::addr_t data_length) { + lldb_private::DataExtractor data; + data.SetData(data_sp, data_offset, data_length); + lldb::offset_t offset = 0; + offset += 4; // Skipping to the coredump version + uint32_t magic = data.GetU32(&offset); + return AIXCoreHeaderCheckFromMagic(magic) != 0; +} + +bool ObjectFileAIXCore::ParseHeader() { + + return false; +} + +ByteOrder ObjectFileAIXCore::GetByteOrder() const { + return eByteOrderBig; +} + +bool ObjectFileAIXCore::IsExecutable() const { + return false; +} + +uint32_t ObjectFileAIXCore::GetAddressByteSize() const { + return 8; +} + +AddressClass ObjectFileAIXCore::GetAddressClass(addr_t file_addr) { + return AddressClass::eUnknown; +} + +lldb::SymbolType ObjectFileAIXCore::MapSymbolType(llvm::object::SymbolRef::Type sym_type) { + if (sym_type == llvm::object::SymbolRef::ST_Function) + return lldb::eSymbolTypeCode; + else if (sym_type == llvm::object::SymbolRef::ST_Data) + return lldb::eSymbolTypeData; + return lldb::eSymbolTypeInvalid; +} + +void ObjectFileAIXCore::ParseSymtab(Symtab &lldb_symtab) { +} + +bool ObjectFileAIXCore::IsStripped() { + return false; +} + +void ObjectFileAIXCore::CreateSections(SectionList &unified_section_list) { +} + +void ObjectFileAIXCore::Dump(Stream *s) { +} + +ArchSpec ObjectFileAIXCore::GetArchitecture() { + ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + return arch_spec; +} + +UUID ObjectFileAIXCore::GetUUID() { + return UUID(); +} + +uint32_t ObjectFileAIXCore::GetDependentModules(FileSpecList &files) { + + auto original_size = files.GetSize(); + return files.GetSize() - original_size; +} + +Address ObjectFileAIXCore::GetImageInfoAddress(Target *target) { + return Address(); +} + +lldb_private::Address ObjectFileAIXCore::GetBaseAddress() { + return lldb_private::Address(); +} +ObjectFile::Type ObjectFileAIXCore::CalculateType() { + return eTypeCoreFile; +} + +ObjectFile::Strata ObjectFileAIXCore::CalculateStrata() { + return eStrataUnknown; +} + +std::vector +ObjectFileAIXCore::GetLoadableData(Target &target) { + std::vector loadables; + return loadables; +} + +lldb::WritableDataBufferSP +ObjectFileAIXCore::MapFileDataWritable(const FileSpec &file, uint64_t Size, + uint64_t Offset) { + return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size, + Offset); +} + +ObjectFileAIXCore::ObjectFileAIXCore(const lldb::ModuleSP &module_sp, + DataBufferSP data_sp, lldb::offset_t data_offset, + const FileSpec *file, lldb::offset_t file_offset, + lldb::offset_t length) + : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset) + { + if (file) + m_file = *file; +} + +ObjectFileAIXCore::ObjectFileAIXCore(const lldb::ModuleSP &module_sp, + DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, + addr_t header_addr) + : ObjectFile(module_sp, process_sp, header_addr, header_data_sp) + { +} diff --git a/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.h b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.h new file mode 100644 index 0000000000000..5dbd78d919bb6 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.h @@ -0,0 +1,121 @@ +//===-- ObjectFileAIXCore.h --------------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_AIXCORE_OBJECTFILEAIXCORE_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_AIXCORE_OBJECTFILEAIXCORE_H + +#include + +#include + +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/UUID.h" +#include "lldb/lldb-private.h" +#include "llvm/Object/XCOFFObjectFile.h" + +/// \class ObjectFileAIXCore +/// Generic AIX CORE object file reader. +/// +/// This class provides a generic AIX Core (32/64 bit) reader plugin implementing +/// the ObjectFile protocol. +class ObjectFileAIXCore : public lldb_private::ObjectFile { +public: + // Static Functions + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "aix-core-obj"; } + + static llvm::StringRef GetPluginDescriptionStatic() { + return "AIX core object file reader."; + } + + static lldb_private::ObjectFile * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length); + + static lldb_private::ObjectFile *CreateMemoryInstance( + const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + + static size_t GetModuleSpecifications(const lldb_private::FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + lldb_private::ModuleSpecList &specs); + + static bool MagicBytesMatch(lldb::DataBufferSP &data_sp, lldb::addr_t offset, + lldb::addr_t length); + + static lldb::SymbolType MapSymbolType(llvm::object::SymbolRef::Type sym_type); + + // PluginInterface protocol + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + // ObjectFile Protocol. + bool ParseHeader() override; + + lldb::ByteOrder GetByteOrder() const override; + + bool IsExecutable() const override; + + uint32_t GetAddressByteSize() const override; + + lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override; + + void ParseSymtab(lldb_private::Symtab &symtab) override; + + bool IsStripped() override; + + void CreateSections(lldb_private::SectionList &unified_section_list) override; + + void Dump(lldb_private::Stream *s) override; + + lldb_private::ArchSpec GetArchitecture() override; + + lldb_private::UUID GetUUID() override; + + uint32_t GetDependentModules(lldb_private::FileSpecList &files) override; + + lldb_private::Address + GetImageInfoAddress(lldb_private::Target *target) override; + lldb_private::Address GetBaseAddress() override; + + ObjectFile::Type CalculateType() override; + + ObjectFile::Strata CalculateStrata() override; + + ObjectFileAIXCore(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + ObjectFileAIXCore(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + +protected: + + static bool ParseAIXCoreHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr + ); + + std::vector + GetLoadableData(lldb_private::Target &target) override; + + static lldb::WritableDataBufferSP + MapFileDataWritable(const lldb_private::FileSpec &file, uint64_t Size, + uint64_t Offset); + +}; + +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_AIXCORE_OBJECTFILEAIXCORE_H diff --git a/lldb/source/Plugins/ObjectFile/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/CMakeLists.txt index 7abd0c96f4fd7..1605356fdb7f1 100644 --- a/lldb/source/Plugins/ObjectFile/CMakeLists.txt +++ b/lldb/source/Plugins/ObjectFile/CMakeLists.txt @@ -9,3 +9,4 @@ add_subdirectory(PECOFF) add_subdirectory(XCOFF) add_subdirectory(Placeholder) add_subdirectory(wasm) +add_subdirectory(AIXCore) diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt index 058b4b9ad2157..0b66ea18c82ce 100644 --- a/lldb/source/Plugins/Process/CMakeLists.txt +++ b/lldb/source/Plugins/Process/CMakeLists.txt @@ -24,3 +24,4 @@ add_subdirectory(elf-core) add_subdirectory(mach-core) add_subdirectory(minidump) add_subdirectory(FreeBSDKernel) +add_subdirectory(aix-core) diff --git a/lldb/source/Plugins/Process/aix-core/AIXCore.cpp b/lldb/source/Plugins/Process/aix-core/AIXCore.cpp new file mode 100644 index 0000000000000..95e47b4d8be53 --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/AIXCore.cpp @@ -0,0 +1,116 @@ +//===-- AIXCore.cpp ------------------------------------------------===// +// +// 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 + +#include "lldb/Core/Section.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" + +#include "AIXCore.h" + +using namespace AIXCORE; +using namespace lldb; +using namespace lldb_private; + +AIXCore64Header::AIXCore64Header() { memset(this, 0, sizeof(AIXCore64Header)); } + + +bool AIXCore64Header::ParseRegisterContext(lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + // The data is arranged in this order in this coredump file + // so we have to fetch in this exact order. But need to change + // the context structure order according to Infos_ppc64 + for(int i = 0; i < 32; i++) + Fault.context.gpr[i] = data.GetU64(offset); + Fault.context.msr = data.GetU64(offset); + Fault.context.pc = data.GetU64(offset); + Fault.context.lr = data.GetU64(offset); + Fault.context.ctr = data.GetU64(offset); + Fault.context.cr = data.GetU32(offset); + Fault.context.xer = data.GetU32(offset); + Fault.context.fpscr = data.GetU32(offset); + Fault.context.fpscrx = data.GetU32(offset); + Fault.context.except[0] = data.GetU64(offset); + for(int i = 0; i < 32; i++) + Fault.context.fpr[i] = data.GetU64(offset); + Fault.context.fpeu = data.GetU8(offset); + Fault.context.fpinfo = data.GetU8(offset); + Fault.context.fpscr24_31 = data.GetU8(offset); + Fault.context.pad[0] = data.GetU8(offset); + Fault.context.excp_type = data.GetU32(offset); + + return true; +} +bool AIXCore64Header::ParseThreadContext(lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + + lldb::offset_t offset_to_regctx = *offset; + offset_to_regctx += sizeof(thrdentry64); + Fault.thread.ti_tid = data.GetU64(offset); + Fault.thread.ti_pid = data.GetU32(offset); + int ret = ParseRegisterContext(data, &offset_to_regctx); + return true; +} + +bool AIXCore64Header::ParseUserData(lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + User.process.pi_pid = data.GetU32(offset); + User.process.pi_ppid = data.GetU32(offset); + User.process.pi_sid = data.GetU32(offset); + User.process.pi_pgrp = data.GetU32(offset); + User.process.pi_uid = data.GetU32(offset); + User.process.pi_suid = data.GetU32(offset); + + *offset += 76; + + ByteOrder byteorder = data.GetByteOrder(); + size_t size = 33; + data.ExtractBytes(*offset, size, byteorder, User.process.pi_comm); + offset += size; + + return true; +} + +bool AIXCore64Header::ParseCoreHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + + SignalNum = data.GetU8(offset); + Flag = data.GetU8(offset); + Entries = data.GetU16(offset); + Version = data.GetU32(offset); + FDInfo = data.GetU64(offset); + + LoaderOffset = data.GetU64(offset); + LoaderSize = data.GetU64(offset); + NumberOfThreads = data.GetU32(offset); + Reserved0 = data.GetU32(offset); + ThreadContextOffset = data.GetU64(offset); + NumSegRegion = data.GetU64(offset); + SegRegionOffset = data.GetU64(offset); + StackOffset = data.GetU64(offset); + StackBaseAddr = data.GetU64(offset); + StackSize = data.GetU64(offset); + DataRegionOffset = data.GetU64(offset); + DataBaseAddr = data.GetU64(offset); + DataSize = data.GetU64(offset); + + *offset += 104; + lldb::offset_t offset_to_user = (*offset + sizeof(ThreadContext64)); + int ret = 0; + ret = ParseThreadContext(data, offset); + ret = ParseUserData(data, &offset_to_user); + + return true; + +} + diff --git a/lldb/source/Plugins/Process/aix-core/AIXCore.h b/lldb/source/Plugins/Process/aix-core/AIXCore.h new file mode 100644 index 0000000000000..3d78d5e92c7ab --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/AIXCore.h @@ -0,0 +1,125 @@ +//===-- AIXCore.h ----------------------------------------*- 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 +// +// Notes about AIX Process core dumps: +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_AIXCORE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_AIXCORE_H + +#include "llvm/ADT/StringRef.h" +#include +#include +#include + +#include +#include + +namespace AIXCORE { + +struct RegContext { + // The data is arranged in order as filled by AIXCore.cpp in this coredump file + // so we have to fetch in that exact order, refer there. + // But need to change + // the context structure in order according to Infos_ppc64 + uint64_t gpr[32]; /* 64-bit gprs */ + unsigned long pc; /* msr */ + unsigned long msr; /* iar */ + unsigned long origr3; /* iar */ + unsigned long ctr; /* CTR */ + unsigned long lr; /* LR */ + unsigned long xer; /* XER */ + unsigned long cr; /* CR */ + unsigned long softe; /* CR */ + unsigned long trap; /* CR */ + unsigned int fpscr; /* floating pt status reg */ + unsigned int fpscrx; /* software ext to fpscr */ + unsigned long except[1]; /* exception address */ + double fpr[32]; /* floating pt regs */ + char fpeu; /* floating pt ever used */ + char fpinfo; /* floating pt info */ + char fpscr24_31; /* bits 24-31 of 64-bit FPSCR */ + char pad[1]; + int excp_type; /* exception type */ +}; + + struct ThreadContext64 { + struct thrdentry64 thread; + struct RegContext context; + }; + + struct UserData { + + struct procentry64 process; + unsigned long long reserved[16]; + }; + + struct AIXCore64Header { + + int8_t SignalNum; /* signal number (cause of error) */ + int8_t Flag; /* flag to describe core dump type */ + uint16_t Entries; /* number of core dump modules */ + uint32_t Version; /* core file format number */ + uint64_t FDInfo; /* offset to fd region in file */ + + uint64_t LoaderOffset; /* offset to loader region in file */ + uint64_t LoaderSize; /* size of loader region */ + + uint32_t NumberOfThreads ; /* number of elements in thread table */ + uint32_t Reserved0; /* Padding */ + uint64_t ThreadContextOffset; /* offset to thread context table */ + + uint64_t NumSegRegion; /* n of elements in segregion */ + uint64_t SegRegionOffset; /* offset to start of segregion table */ + + uint64_t StackOffset; /* offset of user stack in file */ + uint64_t StackBaseAddr; /* base address of user stack region */ + uint64_t StackSize; /* size of user stack region */ + + uint64_t DataRegionOffset; /* offset to user data region */ + uint64_t DataBaseAddr; /* base address of user data region */ + uint64_t DataSize; /* size of user data region */ + uint64_t SDataBase; /* base address of sdata region */ + uint64_t SDataSize; /* size of sdata region */ + + uint64_t NumVMRegions; /* number of anonymously mapped areas */ + uint64_t VMOffset; /* offset to start of vm_infox table */ + + int32_t ProcessorImplementation; /* processor implementation */ + uint32_t NumElementsCTX; /* n of elements in extended ctx table*/ + uint64_t CPRSOffset; /* Checkpoint/Restart offset */ + uint64_t ExtendedContextOffset; /* extended context offset */ + uint64_t OffsetUserKey; /* Offset to user-key exception data */ + uint64_t OffsetLoaderTLS; /* offset to the loader region in file + when a process uses TLS data */ + uint64_t TLSLoaderSize; /* size of the above loader region */ + uint64_t ExtendedProcEntry; /* Extended procentry64 information */ + uint64_t Reserved[2]; + + struct ThreadContext64 Fault; + + struct UserData User; + + AIXCore64Header(); + + bool ParseCoreHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + bool ParseThreadContext(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + bool ParseUserData(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + bool ParseRegisterContext(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + bool ParseLoaderData(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + + }; + + +} + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_AIXCORE_H diff --git a/lldb/source/Plugins/Process/aix-core/CMakeLists.txt b/lldb/source/Plugins/Process/aix-core/CMakeLists.txt new file mode 100644 index 0000000000000..347717a362491 --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/CMakeLists.txt @@ -0,0 +1,16 @@ +add_definitions("-D_ALL_SOURCE") + +add_lldb_library(lldbPluginProcessAIXCore PLUGIN + ProcessAIXCore.cpp + AIXCore.cpp + ThreadAIXCore.cpp + RegisterContextCoreAIX_ppc64.cpp + + LINK_LIBS + lldbCore + lldbTarget + lldbPluginProcessUtility + LINK_COMPONENTS + BinaryFormat + Support + ) diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp new file mode 100644 index 0000000000000..9300aa14ac4db --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp @@ -0,0 +1,251 @@ +//===-- ProcessAIXCore.cpp ------------------------------------------------===// +// +// 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 + +#include +#include + +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Section.h" +#include "lldb/Target/ABI.h" +#include "lldb/Target/DynamicLoader.h" +#include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/UnixSignals.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" + +#include "llvm/Support/Threading.h" +#include "Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h" + +#include "ProcessAIXCore.h" +#include "AIXCore.h" +#include "ThreadAIXCore.h" + +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ProcessAIXCore) + +llvm::StringRef ProcessAIXCore::GetPluginDescriptionStatic() { + return "AIX core dump plug-in."; +} + +void ProcessAIXCore::Initialize() { + static llvm::once_flag g_once_flag; + + llvm::call_once(g_once_flag, []() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); + }); +} + +void ProcessAIXCore::Terminate() { + PluginManager::UnregisterPlugin(ProcessAIXCore::CreateInstance); +} + +lldb::ProcessSP ProcessAIXCore::CreateInstance(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const FileSpec *crash_file, + bool can_connect) { + lldb::ProcessSP process_sp; + if (crash_file && !can_connect) { + const size_t header_size = sizeof(AIXCORE::AIXCore64Header); + + auto data_sp = FileSystem::Instance().CreateDataBuffer( + crash_file->GetPath(), header_size, 0); + + if (data_sp && data_sp->GetByteSize() == header_size) { + AIXCORE::AIXCore64Header aixcore_header; + DataExtractor data(data_sp, lldb::eByteOrderBig, 4); + lldb::offset_t data_offset = 0; + if(aixcore_header.ParseCoreHeader(data, &data_offset)) { + process_sp = std::make_shared(target_sp, listener_sp, + *crash_file); + } + } + + } + return process_sp; +} + +// ProcessAIXCore constructor +ProcessAIXCore::ProcessAIXCore(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const FileSpec &core_file) + : PostMortemProcess(target_sp, listener_sp, core_file) {} + +// Destructor +ProcessAIXCore::~ProcessAIXCore() { + Clear(); + // We need to call finalize on the process before destroying ourselves to + // make sure all of the broadcaster cleanup goes as planned. If we destruct + // this class, then Process::~Process() might have problems trying to fully + // destroy the broadcaster. + Finalize(true /* destructing */); +} + +bool ProcessAIXCore::CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) { + + if (!m_core_module_sp && FileSystem::Instance().Exists(m_core_file)) { + ModuleSpec core_module_spec(m_core_file, target_sp->GetArchitecture()); + Status error(ModuleList::GetSharedModule(core_module_spec, m_core_module_sp, + nullptr, nullptr, nullptr)); + if (m_core_module_sp) { + ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); + if (core_objfile && core_objfile->GetType() == ObjectFile::eTypeCoreFile){ + return true; + } + } + } + return false; + +} + +ArchSpec ProcessAIXCore::GetArchitecture() { + + ArchSpec arch = m_core_module_sp->GetObjectFile()->GetArchitecture(); + + ArchSpec target_arch = GetTarget().GetArchitecture(); + arch.MergeFrom(target_arch); + + return arch; +} + +lldb_private::DynamicLoader *ProcessAIXCore::GetDynamicLoader() { + if (m_dyld_up.get() == nullptr) { + m_dyld_up.reset(DynamicLoader::FindPlugin( + this, DynamicLoaderAIXDYLD::GetPluginNameStatic())); + } + return m_dyld_up.get(); +} + +void ProcessAIXCore::ParseAIXCoreFile() { + + Log *log = GetLog(LLDBLog::Process); + AIXSigInfo siginfo; + ThreadData thread_data; + + const lldb_private::UnixSignals &unix_signals = *GetUnixSignals(); + const ArchSpec &arch = GetArchitecture(); + + siginfo.Parse(m_aixcore_header, arch, unix_signals); + thread_data.siginfo = siginfo; + SetID(m_aixcore_header.User.process.pi_pid); + + thread_data.name.assign (m_aixcore_header.User.process.pi_comm, + strnlen (m_aixcore_header.User.process.pi_comm, + sizeof (m_aixcore_header.User.process.pi_comm))); + + lldb::DataBufferSP data_buffer_sp(new lldb_private::DataBufferHeap(sizeof(m_aixcore_header.Fault.context), 0)); + + memcpy(static_cast(const_cast(data_buffer_sp->GetBytes())), + &m_aixcore_header.Fault.context, sizeof(m_aixcore_header.Fault.context)); + + lldb_private::DataExtractor data(data_buffer_sp, lldb::eByteOrderBig, 8); + + thread_data.gpregset = DataExtractor(data, 0, sizeof(m_aixcore_header.Fault.context)); + m_thread_data.push_back(thread_data); + LLDB_LOGF(log, "ProcessAIXCore: Parsing Complete!"); + +} + +// Process Control +Status ProcessAIXCore::DoLoadCore() { + + Status error; + if (!m_core_module_sp) { + error = Status::FromErrorString("invalid core module"); + return error; + } + + FileSpec file = m_core_module_sp->GetObjectFile()->GetFileSpec(); + + if (file) { + const size_t header_size = sizeof(AIXCORE::AIXCore64Header); + auto data_sp = FileSystem::Instance().CreateDataBuffer( + file.GetPath(), -1, 0); + if (data_sp && data_sp->GetByteSize() != 0) { + + DataExtractor data(data_sp, lldb::eByteOrderBig, 4); + lldb::offset_t data_offset = 0; + m_aixcore_header.ParseCoreHeader(data, &data_offset); + auto dyld = static_cast(GetDynamicLoader()); + dyld->FillCoreLoaderData(data, m_aixcore_header.LoaderOffset, + m_aixcore_header.LoaderSize); + + } else { + error = Status::FromErrorString("invalid data"); + return error; + } + } else { + error = Status::FromErrorString("invalid file"); + return error; + } + + m_thread_data_valid = true; + ParseAIXCoreFile(); + ArchSpec arch(m_core_module_sp->GetArchitecture()); + + ArchSpec target_arch = GetTarget().GetArchitecture(); + ArchSpec core_arch(m_core_module_sp->GetArchitecture()); + target_arch.MergeFrom(core_arch); + GetTarget().SetArchitecture(target_arch); + + lldb::ModuleSP exe_module_sp = GetTarget().GetExecutableModule(); + if (!exe_module_sp) { + ModuleSpec exe_module_spec; + exe_module_spec.GetArchitecture() = arch; + exe_module_spec.GetFileSpec().SetFile(m_aixcore_header.User.process.pi_comm, + FileSpec::Style::native); + exe_module_sp = GetTarget().GetOrCreateModule(exe_module_spec, true); + GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsNo); + } + + return error; +} + +bool ProcessAIXCore::DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) +{ + const ThreadData &td = m_thread_data[0]; + + lldb::ThreadSP thread_sp = + std::make_shared(*this, td); + new_thread_list.AddThread(thread_sp); + + return true; +} + +void ProcessAIXCore::RefreshStateAfterStop() {} + +// Process Memory +size_t ProcessAIXCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size, + Status &error) { + if (lldb::ABISP abi_sp = GetABI()) + addr = abi_sp->FixAnyAddress(addr); + + // Don't allow the caching that lldb_private::Process::ReadMemory does since + // in core files we have it all cached our our core file anyway. + return DoReadMemory(addr, buf, size, error); +} + +size_t ProcessAIXCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, + Status &error) { return 0; } + +Status ProcessAIXCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo ®ion_info) { + return Status(); +} + +Status ProcessAIXCore::DoDestroy() { return Status(); } diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h new file mode 100644 index 0000000000000..9880c491689ca --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h @@ -0,0 +1,100 @@ +//===-- ProcessAIXCore.h ----------------------------------------*- 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 +// +// Notes about AIX Process core dumps: +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_PROCESSAIXCORE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_PROCESSAIXCORE_H + +#include +#include + +#include "lldb/Target/PostMortemProcess.h" +#include "lldb/Utility/Status.h" +#include "lldb/Target/Process.h" +#include "AIXCore.h" +#include "ThreadAIXCore.h" + +struct ThreadData; + +class ProcessAIXCore : public lldb_private::PostMortemProcess { +public: + // Constructors and Destructors + static lldb::ProcessSP + CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, + const lldb_private::FileSpec *crash_file_path, + bool can_connect); + + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "aix-core"; } + + static llvm::StringRef GetPluginDescriptionStatic(); + + // Constructors and Destructors + ProcessAIXCore(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, + const lldb_private::FileSpec &core_file); + + ~ProcessAIXCore() override; + + // PluginInterface protocol + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + // Process Control + lldb_private::Status DoDestroy() override; + + lldb_private::Status WillResume() override { + return lldb_private::Status::FromErrorStringWithFormatv( + "error: {0} does not support resuming processes", GetPluginName()); + } + + bool WarnBeforeDetach() const override { return false; } + + lldb_private::ArchSpec GetArchitecture(); + + bool CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) override; + + // Creating a new process, or attaching to an existing one + lldb_private::Status DoLoadCore() override; + + bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list, + lldb_private::ThreadList &new_thread_list) override; + + lldb_private::Status + DoGetMemoryRegionInfo(lldb::addr_t load_addr, + lldb_private::MemoryRegionInfo ®ion_info) override; + + void RefreshStateAfterStop() override; + + lldb_private::DynamicLoader *GetDynamicLoader() override; + + // Process Memory + size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size, + lldb_private::Status &error) override; + + size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, + lldb_private::Status &error) override; + + void ParseAIXCoreFile(); + + +private: + lldb::ModuleSP m_core_module_sp; + std::string m_dyld_plugin_name; + + // True if m_thread_contexts contains valid entries + bool m_thread_data_valid = false; + AIXCORE::AIXCore64Header m_aixcore_header; + + std::vector m_thread_data; +}; + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_PROCESSAIXCORE_H diff --git a/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.cpp b/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.cpp new file mode 100644 index 0000000000000..b243017bf9a2a --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.cpp @@ -0,0 +1,136 @@ +//===-- RegisterContextCoreAIX_ppc64.cpp ------------------------------===// +// +// 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 "RegisterContextCoreAIX_ppc64.h" + +#include "lldb/Target/Thread.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" + +#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" +#include "Plugins/Process/elf-core/RegisterUtilities.h" + +#include + +using namespace lldb_private; + +RegisterContextCoreAIX_ppc64::RegisterContextCoreAIX_ppc64( + Thread &thread, RegisterInfoInterface *register_info, + const DataExtractor &gpregset) + : RegisterContextPOSIX_ppc64le(thread, 0, register_info) { + m_gpr_buffer = std::make_shared(gpregset.GetDataStart(), + gpregset.GetByteSize()); + m_gpr.SetData(m_gpr_buffer); + m_gpr.SetByteOrder(gpregset.GetByteOrder()); + + // This Code is for Registers like FPR, VSR, VMX and is disabled right now. + // It will be implemented as per need. + + /* ArchSpec arch = register_info->GetTargetArchitecture(); + DataExtractor fpregset;// = getRegset(notes, arch.GetTriple(), FPR_Desc); + m_fpr_buffer = std::make_shared(fpregset.GetDataStart(), + fpregset.GetByteSize()); + m_fpr.SetData(m_fpr_buffer); + m_fpr.SetByteOrder(fpregset.GetByteOrder()); + + DataExtractor vmxregset;// = getRegset(notes, arch.GetTriple(), PPC_VMX_Desc); + m_vmx_buffer = std::make_shared(vmxregset.GetDataStart(), + vmxregset.GetByteSize()); + m_vmx.SetData(m_vmx_buffer); + m_vmx.SetByteOrder(vmxregset.GetByteOrder()); + + DataExtractor vsxregset;// = getRegset(notes, arch.GetTriple(), PPC_VSX_Desc); + m_vsx_buffer = std::make_shared(vsxregset.GetDataStart(), + vsxregset.GetByteSize()); + m_vsx.SetData(m_vsx_buffer); + m_vsx.SetByteOrder(vsxregset.GetByteOrder());*/ +} + +size_t RegisterContextCoreAIX_ppc64::GetFPRSize() const { + return k_num_fpr_registers_ppc64le * sizeof(uint64_t); +} + +size_t RegisterContextCoreAIX_ppc64::GetVMXSize() const { + return (k_num_vmx_registers_ppc64le - 1) * sizeof(uint64_t) * 2 + + sizeof(uint32_t); +} + +size_t RegisterContextCoreAIX_ppc64::GetVSXSize() const { + return k_num_vsx_registers_ppc64le * sizeof(uint64_t) * 2; +} + +bool RegisterContextCoreAIX_ppc64::ReadRegister( + const RegisterInfo *reg_info, RegisterValue &value) { + lldb::offset_t offset = reg_info->byte_offset; + + if (IsFPR(reg_info->kinds[lldb::eRegisterKindLLDB])) { + uint64_t v; + offset -= GetGPRSize(); + offset = m_fpr.CopyData(offset, reg_info->byte_size, &v); + + if (offset == reg_info->byte_size) { + value.SetBytes(&v, reg_info->byte_size, m_fpr.GetByteOrder()); + return true; + } + } else if (IsVMX(reg_info->kinds[lldb::eRegisterKindLLDB])) { + uint32_t v[4]; + offset -= GetGPRSize() + GetFPRSize(); + offset = m_vmx.CopyData(offset, reg_info->byte_size, &v); + + if (offset == reg_info->byte_size) { + value.SetBytes(v, reg_info->byte_size, m_vmx.GetByteOrder()); + return true; + } + } else if (IsVSX(reg_info->kinds[lldb::eRegisterKindLLDB])) { + uint32_t v[4]; + lldb::offset_t tmp_offset; + offset -= GetGPRSize() + GetFPRSize() + GetVMXSize(); + + if (offset < GetVSXSize() / 2) { + tmp_offset = m_vsx.CopyData(offset / 2, reg_info->byte_size / 2, &v); + + if (tmp_offset != reg_info->byte_size / 2) { + return false; + } + + uint8_t *dst = (uint8_t *)&v + sizeof(uint64_t); + tmp_offset = m_fpr.CopyData(offset / 2, reg_info->byte_size / 2, dst); + + if (tmp_offset != reg_info->byte_size / 2) { + return false; + } + + value.SetBytes(&v, reg_info->byte_size, m_vsx.GetByteOrder()); + return true; + } else { + offset = + m_vmx.CopyData(offset - GetVSXSize() / 2, reg_info->byte_size, &v); + if (offset == reg_info->byte_size) { + value.SetBytes(v, reg_info->byte_size, m_vmx.GetByteOrder()); + return true; + } + } + } else { + uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); + + if (offset == reg_info->byte_offset + reg_info->byte_size) { + if (reg_info->byte_size < sizeof(v)) + value = (uint32_t)v; + else + value = v; + return true; + } + } + + return false; +} + +bool RegisterContextCoreAIX_ppc64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue &value) { + return false; +} diff --git a/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.h b/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.h new file mode 100644 index 0000000000000..8f1f71ce8d884 --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.h @@ -0,0 +1,46 @@ +//===-- RegisterContextCoreAIX_ppc64.h ----------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_REGISTERCONTEXTAIXCORE_PPC64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_REGISTERCONTEXTAIXCORE_PPC64_H + +#include "Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h" +#include "lldb/Utility/DataExtractor.h" + +class RegisterContextCoreAIX_ppc64 : public RegisterContextPOSIX_ppc64le { +public: + RegisterContextCoreAIX_ppc64( + lldb_private::Thread &thread, + lldb_private::RegisterInfoInterface *register_info, + const lldb_private::DataExtractor &gpregset); + + bool ReadRegister(const lldb_private::RegisterInfo *reg_info, + lldb_private::RegisterValue &value) override; + + bool WriteRegister(const lldb_private::RegisterInfo *reg_info, + const lldb_private::RegisterValue &value) override; + +protected: + size_t GetFPRSize() const; + + size_t GetVMXSize() const; + + size_t GetVSXSize() const; + +private: + lldb::DataBufferSP m_gpr_buffer; + lldb::DataBufferSP m_fpr_buffer; + lldb::DataBufferSP m_vmx_buffer; + lldb::DataBufferSP m_vsx_buffer; + lldb_private::DataExtractor m_gpr; + lldb_private::DataExtractor m_fpr; + lldb_private::DataExtractor m_vmx; + lldb_private::DataExtractor m_vsx; +}; + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_REGISTERCONTEXTAIXCORE_PPC64_H diff --git a/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.cpp b/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.cpp new file mode 100644 index 0000000000000..979e5199fe24d --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.cpp @@ -0,0 +1,127 @@ +//===-- ThreadAIXCore.cpp -------------------------------------------------===// +// +// 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 "lldb/Target/RegisterContext.h" +#include "lldb/Target/StopInfo.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/UnixSignals.h" +#include "lldb/Target/Unwind.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/ProcessInfo.h" + +#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h" +#include "Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h" +#include "RegisterContextCoreAIX_ppc64.h" + +#include "ProcessAIXCore.h" +#include "AIXCore.h" +#include "ThreadAIXCore.h" + +#include +#include + +using namespace lldb; +using namespace lldb_private; + +// Construct a Thread object with given data +ThreadAIXCore::ThreadAIXCore(Process &process, const ThreadData &td) + : Thread(process, td.tid), m_thread_name(td.name), m_thread_reg_ctx_sp(), + m_gpregset_data(td.gpregset), + m_siginfo(std::move(td.siginfo)) {} + +ThreadAIXCore::~ThreadAIXCore() { DestroyThread(); } + +void ThreadAIXCore::RefreshStateAfterStop() { + GetRegisterContext()->InvalidateIfNeeded(false); +} + +RegisterContextSP ThreadAIXCore::GetRegisterContext() { + if (!m_reg_context_sp) { + m_reg_context_sp = CreateRegisterContextForFrame(nullptr); + } + return m_reg_context_sp; +} + +RegisterContextSP +ThreadAIXCore::CreateRegisterContextForFrame(StackFrame *frame) { + RegisterContextSP reg_ctx_sp; + uint32_t concrete_frame_idx = 0; + + if (frame) + concrete_frame_idx = frame->GetConcreteFrameIndex(); + + bool is_linux = false; + if (concrete_frame_idx == 0) { + if (m_thread_reg_ctx_sp) + return m_thread_reg_ctx_sp; + + ProcessAIXCore *process = static_cast(GetProcess().get()); + ArchSpec arch = process->GetArchitecture(); + RegisterInfoInterface *reg_interface = nullptr; + + switch (arch.GetMachine()) { + case llvm::Triple::ppc64: + reg_interface = new RegisterInfoPOSIX_ppc64le(arch); + m_thread_reg_ctx_sp = std::make_shared( + *this, reg_interface, m_gpregset_data); + break; + default: + break; + } + reg_ctx_sp = m_thread_reg_ctx_sp; + } else { + reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame); + } + return reg_ctx_sp; +} + +bool ThreadAIXCore::CalculateStopInfo() { + ProcessSP process_sp(GetProcess()); + if (!process_sp) + return false; + + lldb::UnixSignalsSP unix_signals_sp(process_sp->GetUnixSignals()); + if (!unix_signals_sp) + return false; + + const char *sig_description; + std::string description = m_siginfo.GetDescription(*unix_signals_sp); + if (description.empty()) + sig_description = nullptr; + else + sig_description = description.c_str(); + + SetStopInfo(StopInfo::CreateStopReasonWithSignal( + *this, m_siginfo.si_signo, sig_description, m_siginfo.si_code)); + + SetStopInfo(m_stop_info_sp); + return true; +} + +void AIXSigInfo::Parse(const AIXCORE::AIXCore64Header data, const ArchSpec &arch, + const lldb_private::UnixSignals &unix_signals) { + si_signo = data.SignalNum; + sigfault.si_addr = data.Fault.context.pc; +} + +AIXSigInfo::AIXSigInfo() { memset(this, 0, sizeof(AIXSigInfo)); } + +size_t AIXSigInfo::GetSize(const lldb_private::ArchSpec &arch) { + return sizeof(AIXSigInfo); +} + +std::string AIXSigInfo::GetDescription( + const lldb_private::UnixSignals &unix_signals) const { + return unix_signals.GetSignalDescription(si_signo, 0, + sigfault.si_addr); + +} diff --git a/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.h b/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.h new file mode 100644 index 0000000000000..9ee157e9b2b9b --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.h @@ -0,0 +1,110 @@ +//===-- ThreadAIXCore.h -----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_THREADAIXCORE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_THREADAIXCORE_H + +#include "lldb/Target/Thread.h" +#include "lldb/Utility/DataExtractor.h" +#include "llvm/ADT/DenseMap.h" +#include +#include +#include "ProcessAIXCore.h" +#include "AIXCore.h" +#include "ThreadAIXCore.h" + +namespace lldb_private { +class ProcessInstanceInfo; +} + +struct AIXSigInfo { + + //COPY siginfo_t correctly for AIX version + int32_t si_signo; // Order matters for the first 3. + int32_t si_errno; + int32_t si_code; + struct alignas(8) { + lldb::addr_t si_addr; + int16_t si_addr_lsb; + union { + struct { + lldb::addr_t _lower; + lldb::addr_t _upper; + } _addr_bnd; + uint32_t _pkey; + } bounds; + } sigfault; + + enum SigInfoNoteType : uint8_t { eUnspecified, eNT_SIGINFO }; + SigInfoNoteType note_type; + + AIXSigInfo(); + + void Parse(const AIXCORE::AIXCore64Header data, + const lldb_private::ArchSpec &arch, + const lldb_private::UnixSignals &unix_signals); + + std::string + GetDescription(const lldb_private::UnixSignals &unix_signals) const; + + static size_t GetSize(const lldb_private::ArchSpec &arch); +}; + +struct ThreadData { + lldb_private::DataExtractor gpregset; + std::vector notes; + lldb::tid_t tid; + std::string name; + AIXSigInfo siginfo; + int prstatus_sig = 0; +}; + +class ThreadAIXCore : public lldb_private::Thread { +public: + ThreadAIXCore(lldb_private::Process &process, const ThreadData &td); + + ~ThreadAIXCore() override; + + void RefreshStateAfterStop() override; + + lldb::RegisterContextSP GetRegisterContext() override; + + lldb::RegisterContextSP + CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override; + + static bool ThreadIDIsValid(lldb::tid_t thread) { return thread != 0; } + + const char *GetName() override { + if (m_thread_name.empty()) + return nullptr; + return m_thread_name.c_str(); + } + + void SetName(const char *name) override { + if (name && name[0]) + m_thread_name.assign(name); + else + m_thread_name.clear(); + } + + void CreateStopFromSigInfo(const AIXSigInfo &siginfo, + const lldb_private::UnixSignals &unix_signals); + +protected: + // Member variables. + std::string m_thread_name; + lldb::RegisterContextSP m_thread_reg_ctx_sp; + + lldb_private::DataExtractor m_gpregset_data; + std::vector m_notes; + AIXSigInfo m_siginfo; + + bool CalculateStopInfo() override; +}; + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_THREADAIXCORE_H >From 57cb8058646103eeada1f92e039d9c54ccd4788f Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 17 Mar 2025 07:31:26 -0500 Subject: [PATCH 40/47] Merge branch 'llvm:main' into llvmgh-101657 --- lldb/cmake/modules/LLDBConfig.cmake | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake index 312791ce36fc7..9df71edd8b359 100644 --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -292,11 +292,7 @@ endif() # Figure out if lldb could use lldb-server. If so, then we'll # ensure we build lldb-server when an lldb target is being built. -<<<<<<< HEAD -if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD|OpenBSD|Windows|AIX") -======= if (CMAKE_SYSTEM_NAME MATCHES "AIX|Android|Darwin|FreeBSD|Linux|NetBSD|OpenBSD|Windows") ->>>>>>> upstream/main set(LLDB_CAN_USE_LLDB_SERVER ON) else() set(LLDB_CAN_USE_LLDB_SERVER OFF) >From 0767ef036d3f82d1429e04a319feb6627ea08158 Mon Sep 17 00:00:00 2001 From: Dhruv Srivastava Date: Tue, 18 Mar 2025 15:03:17 +0530 Subject: [PATCH 41/47] Error Handling (#32) * Error Handling for aix core module --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 12 +++++++----- .../ObjectFile/AIXCore/ObjectFileAIXCore.cpp | 15 +++++++-------- lldb/source/Plugins/Process/aix-core/AIXCore.cpp | 2 +- .../Plugins/Process/aix-core/ProcessAIXCore.cpp | 11 ++++++++--- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 7e44ffbb1c051..12f24c049f373 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -235,17 +235,19 @@ bool DynamicLoaderAIXDYLD::IsCoreFile() const { void DynamicLoaderAIXDYLD::FillCoreLoaderData(lldb_private::DataExtractor &data, uint64_t loader_offset, uint64_t loader_size ) { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); static char *buffer = (char *)malloc(loader_size); - struct ld_info ldinfo[64]; - char *buffer_complete; + if (buffer == NULL) { + LLDB_LOG(log, "Buffer allocation failed error: {0}", std::strerror(errno)); + return; + } + struct ld_info ldinfo[64] = {}; struct ld_info *ptr; int i = 0; - Log *log = GetLog(LLDBLog::DynamicLoader); - LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); ByteOrder byteorder = data.GetByteOrder(); data.ExtractBytes(loader_offset, loader_size, eByteOrderBig, buffer); - buffer_complete = buffer + loader_size; ldinfo[0].ldinfo_next = 1; while (ldinfo[i++].ldinfo_next != 0) { diff --git a/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp index 5158fa4e25077..0ba1056866937 100644 --- a/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp +++ b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp @@ -73,8 +73,6 @@ ObjectFile *ObjectFileAIXCore::CreateInstance(const lldb::ModuleSP &module_sp, assert(data_sp); - const uint8_t *magic = data_sp->GetBytes() + data_offset; - // Update the data to contain the entire file if it doesn't already if (data_sp->GetByteSize() < length) { data_sp = MapFileDataWritable(*file, length, file_offset); @@ -82,7 +80,6 @@ ObjectFile *ObjectFileAIXCore::CreateInstance(const lldb::ModuleSP &module_sp, return nullptr; data_offset = 0; mapped_writable = true; - magic = data_sp->GetBytes(); } // If we didn't map the data as writable take ownership of the buffer. @@ -90,7 +87,6 @@ ObjectFile *ObjectFileAIXCore::CreateInstance(const lldb::ModuleSP &module_sp, data_sp = std::make_shared(data_sp->GetBytes(), data_sp->GetByteSize()); data_offset = 0; - magic = data_sp->GetBytes(); } std::unique_ptr objfile_up(new ObjectFileAIXCore( @@ -124,19 +120,22 @@ size_t ObjectFileAIXCore::GetModuleSpecifications( return specs.GetSize() - initial_count; } -static uint32_t AIXCoreHeaderCheckFromMagic(uint32_t magic) { +static bool AIXCoreHeaderCheckFromMagic(uint32_t magic) { Log *log = GetLog(LLDBLog::Modules); + bool ret = false; switch (magic) { case AIXCORE32: LLDB_LOGF(log, "ObjectFileAIXCore: 32-bit not supported"); break; case AIXCORE64: m_is_core = true; - return 1; + ret = true; + break; + default: break; } - return 0; + return ret; } bool ObjectFileAIXCore::MagicBytesMatch(DataBufferSP &data_sp, @@ -147,7 +146,7 @@ bool ObjectFileAIXCore::MagicBytesMatch(DataBufferSP &data_sp, lldb::offset_t offset = 0; offset += 4; // Skipping to the coredump version uint32_t magic = data.GetU32(&offset); - return AIXCoreHeaderCheckFromMagic(magic) != 0; + return AIXCoreHeaderCheckFromMagic(magic); } bool ObjectFileAIXCore::ParseHeader() { diff --git a/lldb/source/Plugins/Process/aix-core/AIXCore.cpp b/lldb/source/Plugins/Process/aix-core/AIXCore.cpp index 95e47b4d8be53..bc496b5af273f 100644 --- a/lldb/source/Plugins/Process/aix-core/AIXCore.cpp +++ b/lldb/source/Plugins/Process/aix-core/AIXCore.cpp @@ -110,7 +110,7 @@ bool AIXCore64Header::ParseCoreHeader(lldb_private::DataExtractor &data, ret = ParseThreadContext(data, offset); ret = ParseUserData(data, &offset_to_user); - return true; + return ret; } diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp index 9300aa14ac4db..cfcbe1a216116 100644 --- a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp @@ -208,8 +208,10 @@ Status ProcessAIXCore::DoLoadCore() { exe_module_spec.GetArchitecture() = arch; exe_module_spec.GetFileSpec().SetFile(m_aixcore_header.User.process.pi_comm, FileSpec::Style::native); - exe_module_sp = GetTarget().GetOrCreateModule(exe_module_spec, true); - GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsNo); + exe_module_sp = + GetTarget().GetOrCreateModule(exe_module_spec, true /* notify */); + if (exe_module_sp) + GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsNo); } return error; @@ -232,8 +234,11 @@ void ProcessAIXCore::RefreshStateAfterStop() {} // Process Memory size_t ProcessAIXCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size, Status &error) { + if(addr == LLDB_INVALID_ADDRESS) + return 0; + if (lldb::ABISP abi_sp = GetABI()) - addr = abi_sp->FixAnyAddress(addr); + addr = abi_sp->FixAnyAddress(addr); // Don't allow the caching that lldb_private::Process::ReadMemory does since // in core files we have it all cached our our core file anyway. >From 8214e5d8cc52b486d3c3f5f4615848b1782cfcf8 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 26 Mar 2025 01:34:36 -0500 Subject: [PATCH 42/47] Merge branch 'llvm:main' into gh-101657 --- lldb/source/Host/common/Host.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 575bb46216d19..6cf1112511c3f 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -20,7 +20,6 @@ #include #include #include -#endif #include #endif >From d00d28ae68c731efe6f9392000be9822ee74ff0a Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Wed, 26 Mar 2025 04:08:23 -0500 Subject: [PATCH 43/47] First time attach resolution --- .../Plugins/Process/AIX/NativeProcessAIX.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp index fc84763857453..83b8ae5eb3258 100644 --- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -2000,7 +2000,21 @@ Status NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid, void *addr, } else if (req == PT_WRITE_BLOCK) { ptrace64(req, pid, (long long)addr, (int)data_size, (int *)result); } else if (req == PT_ATTACH) { + // Block SIGCHLD signal during attach to the process, + // to prevent interruptions. + // The ptrace operation may send SIGCHLD signals in certain cases + // during the attach, which can interfere. + static sigset_t signal_set; + sigemptyset (&signal_set); + sigaddset (&signal_set, SIGCHLD); + if(!pthread_sigmask( SIG_BLOCK, &signal_set, NULL)) + LLDB_LOG(log,"NativeProcessAIX::pthread_sigmask(SIG_BLOCK) Failed"); + ptrace64(req, pid, 0, 0, nullptr); + + //Unblocking the SIGCHLD after attach work. + if(!pthread_sigmask( SIG_UNBLOCK, &signal_set, NULL )) + LLDB_LOG(log,"NativeProcessAIX::pthread_sigmask(SIG_UNBLOCK) Failed"); } else if (req == PT_WATCH) { ptrace64(req, pid, (long long)addr, (int)data_size, nullptr); } else if (req == PT_DETACH) { >From 9ff945e62a906e9711022bf8f77b86a0aa05c64e Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Tue, 1 Apr 2025 04:54:51 -0500 Subject: [PATCH 44/47] Invalid DWARF rangelist --- lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index cf11e5fb8f5a3..65bd1ee9781d8 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -578,6 +578,7 @@ SectionType ObjectFileXCOFF::GetSectionType(llvm::StringRef sect_name, .Case(".dwinfo", eSectionTypeDWARFDebugInfo) .Case(".dwline", eSectionTypeDWARFDebugLine) .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev) + .Case(".dwrnges", eSectionTypeDWARFDebugRanges) .Default(eSectionTypeInvalid); if (section_type != eSectionTypeInvalid) >From b443dd5b26354da73cd4d785a093d9d1582b25a8 Mon Sep 17 00:00:00 2001 From: Dhruv Srivastava Date: Wed, 2 Apr 2025 11:57:28 +0530 Subject: [PATCH 45/47] Fix for stack memory access from core file (#40) * Fix for stack memory access in core file --- .../Process/aix-core/ProcessAIXCore.cpp | 74 ++++++++++++++++++- .../Plugins/Process/aix-core/ProcessAIXCore.h | 11 +++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp index cfcbe1a216116..bb2db66e2980e 100644 --- a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp @@ -94,6 +94,33 @@ ProcessAIXCore::~ProcessAIXCore() { Finalize(true /* destructing */); } +lldb::addr_t ProcessAIXCore::AddAddressRanges(AIXCORE::AIXCore64Header header) { + const lldb::addr_t addr = header.StackBaseAddr; + FileRange file_range(header.StackOffset, header.StackSize); + VMRangeToFileOffset::Entry range_entry(addr, header.StackSize, file_range); + + if (header.StackSize > 0) { + VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back(); + if (last_entry && + last_entry->GetRangeEnd() == range_entry.GetRangeBase() && + last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase() && + last_entry->GetByteSize() == last_entry->data.GetByteSize()) { + last_entry->SetRangeEnd(range_entry.GetRangeEnd()); + last_entry->data.SetRangeEnd(range_entry.data.GetRangeEnd()); + } else { + m_core_aranges.Append(range_entry); + } + } + + const uint32_t permissions = lldb::ePermissionsReadable | + lldb::ePermissionsWritable; + + m_core_range_infos.Append( + VMRangeToPermissions::Entry(addr, header.StackSize, permissions)); + + return addr; +} + bool ProcessAIXCore::CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) { @@ -170,6 +197,7 @@ Status ProcessAIXCore::DoLoadCore() { } FileSpec file = m_core_module_sp->GetObjectFile()->GetFileSpec(); + Log *log = GetLog(LLDBLog::Process); if (file) { const size_t header_size = sizeof(AIXCORE::AIXCore64Header); @@ -180,6 +208,9 @@ Status ProcessAIXCore::DoLoadCore() { DataExtractor data(data_sp, lldb::eByteOrderBig, 4); lldb::offset_t data_offset = 0; m_aixcore_header.ParseCoreHeader(data, &data_offset); + lldb::addr_t addr = AddAddressRanges(m_aixcore_header); + if (addr == LLDB_INVALID_ADDRESS) + LLDB_LOGF(log, "ProcessAIXCore: Invalid base address. Stack information will be limited"); auto dyld = static_cast(GetDynamicLoader()); dyld->FillCoreLoaderData(data, m_aixcore_header.LoaderOffset, m_aixcore_header.LoaderSize); @@ -246,7 +277,48 @@ size_t ProcessAIXCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size, } size_t ProcessAIXCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, - Status &error) { return 0; } + Status &error) { + ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); + if (core_objfile == nullptr) + return 0; + // Get the address range + const VMRangeToFileOffset::Entry *address_range = + m_core_aranges.FindEntryThatContains(addr); + if (address_range == nullptr || address_range->GetRangeEnd() < addr) { + error = Status::FromErrorStringWithFormat( + "core file does not contain 0x%" PRIx64, addr); + return 0; + } + + // Convert the address into core file offset + const lldb::addr_t offset = addr - address_range->GetRangeBase(); + const lldb::addr_t file_start = address_range->data.GetRangeBase(); + const lldb::addr_t file_end = address_range->data.GetRangeEnd(); + size_t bytes_to_read = size; // Number of bytes to read from the core file + size_t bytes_copied = 0; // Number of bytes actually read from the core file + // Number of bytes available in the core file from the given address + lldb::addr_t bytes_left = 0; + + // Don't proceed if core file doesn't contain the actual data for this + // address range. + if (file_start == file_end) + return 0; + + // Figure out how many on-disk bytes remain in this segment starting at the + // given offset + if (file_end > file_start + offset) + bytes_left = file_end - (file_start + offset); + + if (bytes_to_read > bytes_left) + bytes_to_read = bytes_left; + + // If there is data available on the core file read it + if (bytes_to_read) + bytes_copied = + core_objfile->CopyData(offset + file_start, bytes_to_read, buf); + + return bytes_copied; +} Status ProcessAIXCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo ®ion_info) { diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h index 9880c491689ca..ffd9e401ee192 100644 --- a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h @@ -85,11 +85,22 @@ class ProcessAIXCore : public lldb_private::PostMortemProcess { void ParseAIXCoreFile(); + lldb::addr_t AddAddressRanges(AIXCORE::AIXCore64Header header); private: lldb::ModuleSP m_core_module_sp; std::string m_dyld_plugin_name; + typedef lldb_private::Range FileRange; + typedef lldb_private::RangeDataVector + VMRangeToFileOffset; + typedef lldb_private::RangeDataVector + VMRangeToPermissions; + + // Address ranges found in the core + VMRangeToFileOffset m_core_aranges; + VMRangeToPermissions m_core_range_infos; + // True if m_thread_contexts contains valid entries bool m_thread_data_valid = false; AIXCORE::AIXCore64Header m_aixcore_header; >From 96db5e3257436a222ee38049528d682166421fa1 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 2 Apr 2025 01:46:46 -0500 Subject: [PATCH 46/47] Build fail: SBMutex --- lldb/source/API/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index 0045edf6743d1..2c8f2d583c054 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -83,6 +83,7 @@ add_lldb_library(liblldb STATIC ${option_framework} SBMemoryRegionInfoList.cpp SBModule.cpp SBModuleSpec.cpp + SBMutex.cpp SBPlatform.cpp SBProcess.cpp SBProgress.cpp >From d7a892ef207cde5430021b8705279cc08dc4e0f7 Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Wed, 30 Apr 2025 04:53:28 -0500 Subject: [PATCH 47/47] Added change for step command issue --- .../Plugins/Process/AIX/NativeProcessAIX.cpp | 87 +++++++++++++------ 1 file changed, 61 insertions(+), 26 deletions(-) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp index 83b8ae5eb3258..ace9e11927bee 100644 --- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -19,7 +19,7 @@ #include #include #include - +#include #include "NativeThreadAIX.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" //#include "Plugins/Process/Utility/LinuxProcMaps.h" @@ -79,6 +79,7 @@ using namespace lldb_private; using namespace lldb_private::process_aix; using namespace llvm; +typedef std::function)> AIXMapCallback; // Private bits we only need internally. static bool ProcessVmReadvSupported() { @@ -988,13 +989,6 @@ Status NativeProcessAIX::GetMemoryRegionInfo(lldb::addr_t load_addr, for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end(); ++it) { MemoryRegionInfo &proc_entry_info = it->first; - - // Sanity check assumption that /proc/{pid}/maps entries are ascending. - assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) && - "descending /proc/pid/maps entries detected, unexpected"); - prev_base_address = proc_entry_info.GetRange().GetRangeBase(); - UNUSED_IF_ASSERT_DISABLED(prev_base_address); - // If the target address comes before this entry, indicate distance to next // region. if (load_addr < proc_entry_info.GetRange().GetRangeBase()) { @@ -1029,9 +1023,59 @@ Status NativeProcessAIX::GetMemoryRegionInfo(lldb::addr_t load_addr, return error; } +// Parsing the AIX map file /proc/PID/map +// The map file contains an array of prmap structures +// which has all the information like size, startaddress, object name, permissions +bool ParseAIXMapRegions(const char *aix_map, AIXMapCallback const &callback) { + MemoryRegionInfo region; + struct prmap *prmapData = (struct prmap *)aix_map; + struct prmap *entry; + uint32_t perm_flag; + + for(entry = prmapData;!(entry->pr_size == 0 && entry->pr_vaddr == NULL); entry++) { + const char *o_name = aix_map + entry->pr_pathoff; + lldb::addr_t start_address = (lldb::addr_t )entry->pr_vaddr; + lldb::addr_t end_address = start_address + entry->pr_size; + region.GetRange().SetRangeBase(start_address); + region.GetRange().SetRangeEnd(end_address); + region.SetMapped(MemoryRegionInfo::OptionalBool::eYes); + perm_flag = entry->pr_mflags; + + if(perm_flag & MA_READ) + region.SetReadable(MemoryRegionInfo::OptionalBool::eYes); + else + region.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + + if(perm_flag & MA_WRITE) + region.SetWritable(MemoryRegionInfo::OptionalBool::eYes); + else + region.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + + if(perm_flag & MA_EXEC) + region.SetExecutable(MemoryRegionInfo::OptionalBool::eYes); + else + region.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + + if((perm_flag & MA_SLIBTEXT) || (perm_flag & MA_SLIBDATA)) + region.SetShared(MemoryRegionInfo::OptionalBool::eYes); + else if ((perm_flag & MA_PLIBTEXT) || (perm_flag & MA_PLIBDATA)) + region.SetShared(MemoryRegionInfo::OptionalBool::eNo); + else + region.SetShared(MemoryRegionInfo::OptionalBool::eDontKnow); + + if(o_name) + region.SetName(o_name); + + callback(region); + region.Clear(); + } + + return true; +} + + Status NativeProcessAIX::PopulateMemoryRegionCache() { Log *log = GetLog(POSIXLog::Process); - // If our cache is empty, pull the latest. There should always be at least // one memory region if memory region handling is supported. if (!m_mem_region_cache.empty()) { @@ -1041,7 +1085,7 @@ Status NativeProcessAIX::PopulateMemoryRegionCache() { } Status Result; -#if 0 + AIXMapCallback callback = [&](llvm::Expected Info) { if (Info) { FileSpec file_spec(Info->GetName().GetCString()); @@ -1050,26 +1094,17 @@ Status NativeProcessAIX::PopulateMemoryRegionCache() { return true; } - Result = Info.takeError(); + Result = Status::FromError(Info.takeError()); m_supports_mem_region = LazyBool::eLazyBoolNo; LLDB_LOG(log, "failed to parse proc maps: {0}", Result); return false; }; - // AIX kernel since 2.6.14 has /proc/{pid}/smaps - // if CONFIG_PROC_PAGE_MONITOR is enabled - auto BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "smaps"); - if (BufferOrError) - ParseAIXSMapRegions(BufferOrError.get()->getBuffer(), callback); - else { - BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "maps"); - if (!BufferOrError) { - m_supports_mem_region = LazyBool::eLazyBoolNo; - return BufferOrError.getError(); - } - - ParseAIXMapRegions(BufferOrError.get()->getBuffer(), callback); - } + auto BufferOrError = getProcFile(GetID(), "map"); + if (BufferOrError) { + std::unique_ptr MapBuffer = std::move(*BufferOrError); + ParseAIXMapRegions(MapBuffer->getBufferStart(), callback); + } if (Result.Fail()) return Result; @@ -1090,7 +1125,7 @@ Status NativeProcessAIX::PopulateMemoryRegionCache() { // We support memory retrieval, remember that. m_supports_mem_region = LazyBool::eLazyBoolYes; -#endif + return Status(); } From lldb-commits at lists.llvm.org Mon May 12 23:10:29 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Mon, 12 May 2025 23:10:29 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Refactor lldb-dap event handling. (PR #139669) Message-ID: https://github.com/ashgti created https://github.com/llvm/llvm-project/pull/139669 Refactor lldp-dap to use a `lldb_private::MainLoop` to handle events and protocol messages. This should ensure more uniform handling of debugger state by ensuring only one action is being performed at a time. The MainLoop handles both protocol messages and events. As a result, we can remove some API locks and mutex locks that are not needed. Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Mon May 12 23:12:20 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Mon, 12 May 2025 23:12:20 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] While handling events, grab the APIMutex for consistency. (PR #139596) In-Reply-To: Message-ID: <6822e2c4.170a0220.29a93d.d8f8@mx.google.com> https://github.com/ashgti closed https://github.com/llvm/llvm-project/pull/139596 From lldb-commits at lists.llvm.org Mon May 12 23:12:20 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Mon, 12 May 2025 23:12:20 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] While handling events, grab the APIMutex for consistency. (PR #139596) In-Reply-To: Message-ID: <6822e2c4.170a0220.271f4a.159f@mx.google.com> ashgti wrote: Okay, I got this working with a RunLoop instead in PR https://github.com/llvm/llvm-project/pull/139669. All the macOS tests are passing for me, but I'll let the CI run to check linux and fix any issues with that before making the PR ready for review. https://github.com/llvm/llvm-project/pull/139596 From lldb-commits at lists.llvm.org Mon May 12 23:14:17 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Mon, 12 May 2025 23:14:17 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Refactor lldb-dap event handling. (PR #139669) In-Reply-To: Message-ID: <6822e339.050a0220.1ed5ad.0b84@mx.google.com> ashgti wrote: The tests are passing for me locally on macOS, but I need to check Linux at least before this is fully ready for review. I'll let the CI job run and go from there. https://github.com/llvm/llvm-project/pull/139669 From lldb-commits at lists.llvm.org Mon May 12 23:18:49 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Mon, 12 May 2025 23:18:49 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Refactor lldb-dap event handling. (PR #139669) In-Reply-To: Message-ID: <6822e449.170a0220.215e02.e80c@mx.google.com> JDevlieghere wrote: I added @labath as a reviewer since he's the MainLoop architect and because we briefly discussed this at EuroLLVM. I only glanced at this and I'll take a more in-depth look tomorrow. One thing I remember form reading the MainLoop docs is that the class itself is not thread safe, so I think we may need our own synchronization when adding callbacks. This applies more broadly, but especially this patch might be worth building this with TSan and seeing if that catches anything. https://github.com/llvm/llvm-project/pull/139669 From lldb-commits at lists.llvm.org Mon May 12 23:46:14 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 23:46:14 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][SymbolFileDWARF] Don't search for DWP files on macOS (PR #139554) In-Reply-To: Message-ID: <6822eab6.a70a0220.32d686.dcf5@mx.google.com> ================ @@ -4211,6 +4211,9 @@ SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() { const std::shared_ptr &SymbolFileDWARF::GetDwpSymbolFile() { llvm::call_once(m_dwp_symfile_once_flag, [this]() { + if (m_objfile_sp->GetArchitecture().GetTriple().isAppleMachO()) ---------------- labath wrote: Yeah, this sounds like very much a dual problem to that, so it would be nice if they used the same approach. The thing that makes this fuzzier is that in this case you can't really say that SymbolFileDWARF *requires* ObjectFileMachO (or any other) because one can imagine a setup where someone knows they will only ever need to debug DWARF+ELF and so they want to strip out all of the other object file plugins. OTOH, I can also imagine us saying we don't want to support that. :P https://github.com/llvm/llvm-project/pull/139554 From lldb-commits at lists.llvm.org Mon May 12 23:51:38 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Mon, 12 May 2025 23:51:38 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][plugin] Clear in same thread as set (PR #139252) In-Reply-To: Message-ID: <6822ebfa.050a0220.29e4d3.e812@mx.google.com> https://github.com/labath approved this pull request. Thanks. https://github.com/llvm/llvm-project/pull/139252 From lldb-commits at lists.llvm.org Tue May 13 00:14:19 2025 From: lldb-commits at lists.llvm.org (Kazu Hirata via lldb-commits) Date: Tue, 13 May 2025 00:14:19 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use std:::string::find with a std::string_view (NFC) (PR #139679) Message-ID: https://github.com/kazutakahirata created https://github.com/llvm/llvm-project/pull/139679 std::string::find accepts anything that can be converted to std::string_view starting in C++17. Since StringRef can be converted to std::string_view, we do not need to create a temporary instance of std::string here. Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Tue May 13 00:14:54 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Tue, 13 May 2025 00:14:54 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use std:::string::find with a std::string_view (NFC) (PR #139679) In-Reply-To: Message-ID: <6822f16e.170a0220.10096a.d51c@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Kazu Hirata (kazutakahirata)
Changes std::string::find accepts anything that can be converted to std::string_view starting in C++17. Since StringRef can be converted to std::string_view, we do not need to create a temporary instance of std::string here. --- Full diff: https://github.com/llvm/llvm-project/pull/139679.diff 1 Files Affected: - (modified) lldb/source/Interpreter/Options.cpp (+1-1) ``````````diff diff --git a/lldb/source/Interpreter/Options.cpp b/lldb/source/Interpreter/Options.cpp index fdadba62987d3..4cf68db466158 100644 --- a/lldb/source/Interpreter/Options.cpp +++ b/lldb/source/Interpreter/Options.cpp @@ -1076,7 +1076,7 @@ llvm::Expected Options::ParseAlias(const Args &args, if (!input_line.empty()) { llvm::StringRef tmp_arg = args_copy[idx].ref(); - size_t pos = input_line.find(std::string(tmp_arg)); + size_t pos = input_line.find(tmp_arg); if (pos != std::string::npos) input_line.erase(pos, tmp_arg.size()); } ``````````
https://github.com/llvm/llvm-project/pull/139679 From lldb-commits at lists.llvm.org Tue May 13 00:34:59 2025 From: lldb-commits at lists.llvm.org (Jacques Pienaar via lldb-commits) Date: Tue, 13 May 2025 00:34:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][plugin] Clear in same thread as set (PR #139252) In-Reply-To: Message-ID: <6822f623.170a0220.e08d5.c8ca@mx.google.com> https://github.com/jpienaar updated https://github.com/llvm/llvm-project/pull/139252 >From c5ffbd84f8b68bae2112e8cec68803cefe571a72 Mon Sep 17 00:00:00 2001 From: Jacques Pienaar Date: Fri, 9 May 2025 05:23:00 -0700 Subject: [PATCH 1/5] [lldb][plugin] Clear in same thread as set Here we were initializing & locking a mutex in a thread, while releasing it in the parent which may/often turned out to be a different thread (shared_mutex::unlock_shared is undefined behavior if called from a thread that doesn't hold the lock). I'm not quite sure what the expectation is here as the variable is never used, so instead I've just reset in same thread as which it was set to ensure its freed in thread holding lock. --- lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index 523820874752a..0f0226ea9650c 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -121,6 +121,7 @@ void ManualDWARFIndex::Index() { units_to_index.size()); for_each_unit([&clear_cu_dies](size_t, size_t idx, DWARFUnit *unit) { clear_cu_dies[idx] = unit->ExtractDIEsScoped(); + ckear_cu_duex[idx].reset(); }); // Now index all DWARF unit in parallel. >From 5f5b8dc0deae4f63ddb83e0dfab96ab3a9e0cc80 Mon Sep 17 00:00:00 2001 From: Jacques Pienaar Date: Fri, 9 May 2025 08:15:26 -0700 Subject: [PATCH 2/5] Fix typo --- lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index 0f0226ea9650c..6139d005b4f2e 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -121,7 +121,7 @@ void ManualDWARFIndex::Index() { units_to_index.size()); for_each_unit([&clear_cu_dies](size_t, size_t idx, DWARFUnit *unit) { clear_cu_dies[idx] = unit->ExtractDIEsScoped(); - ckear_cu_duex[idx].reset(); + ckear_cu_dies[idx].reset(); }); // Now index all DWARF unit in parallel. >From 6d8c69c480ce214772cb84a27da645b428916ecb Mon Sep 17 00:00:00 2001 From: Jacques Pienaar Date: Mon, 12 May 2025 13:19:45 +0000 Subject: [PATCH 3/5] Use plain reader counter --- lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp | 12 +++++++++--- lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h | 4 +++- .../Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp | 1 - 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index 7d0afc04ac3b6..3a8409b1c3b66 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -189,17 +189,23 @@ DWARFUnit::ScopedExtractDIEs DWARFUnit::ExtractDIEsScoped() { } DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(DWARFUnit &cu) : m_cu(&cu) { - m_cu->m_die_array_scoped_mutex.lock_shared(); + llvm::sys::ScopedLock lock(m_cu->m_die_array_scoped_mutex); + ++m_cu->m_die_array_scoped_count; } DWARFUnit::ScopedExtractDIEs::~ScopedExtractDIEs() { if (!m_cu) return; - m_cu->m_die_array_scoped_mutex.unlock_shared(); + { + llvm::sys::ScopedLock lock(m_cu->m_die_array_scoped_mutex); + --m_cu->m_die_array_scoped_count; + if (m_cu->m_die_array_scoped_count == 0) + return; + } if (!m_clear_dies || m_cu->m_cancel_scopes) return; // Be sure no other ScopedExtractDIEs is running anymore. - llvm::sys::ScopedWriter lock_scoped(m_cu->m_die_array_scoped_mutex); + llvm::sys::ScopedLock lock_scoped(m_cu->m_die_array_scoped_mutex); llvm::sys::ScopedWriter lock(m_cu->m_die_array_mutex); if (m_cu->m_cancel_scopes) return; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index 75a003e0a663c..c05bba36ed74b 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -17,6 +17,7 @@ #include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" #include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h" +#include "llvm/Support/Mutex.h" #include "llvm/Support/RWMutex.h" #include #include @@ -328,7 +329,8 @@ class DWARFUnit : public DWARFExpression::Delegate, public UserID { DWARFDebugInfoEntry::collection m_die_array; mutable llvm::sys::RWMutex m_die_array_mutex; // It is used for tracking of ScopedExtractDIEs instances. - mutable llvm::sys::RWMutex m_die_array_scoped_mutex; + mutable llvm::sys::Mutex m_die_array_scoped_mutex; + mutable int m_die_array_scoped_count = 0; // ScopedExtractDIEs instances should not call ClearDIEsRWLocked() // as someone called ExtractDIEsIfNeeded(). std::atomic m_cancel_scopes; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index 6139d005b4f2e..523820874752a 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -121,7 +121,6 @@ void ManualDWARFIndex::Index() { units_to_index.size()); for_each_unit([&clear_cu_dies](size_t, size_t idx, DWARFUnit *unit) { clear_cu_dies[idx] = unit->ExtractDIEsScoped(); - ckear_cu_dies[idx].reset(); }); // Now index all DWARF unit in parallel. >From 180c82fa32c9a9ec3e03f92b14c76c1e736c7271 Mon Sep 17 00:00:00 2001 From: Jacques Pienaar Date: Mon, 12 May 2025 18:17:57 +0000 Subject: [PATCH 4/5] Simplify critical region --- .../Plugins/SymbolFile/DWARF/DWARFUnit.cpp | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index 3a8409b1c3b66..ffd6f1dd52aff 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -196,20 +196,13 @@ DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(DWARFUnit &cu) : m_cu(&cu) { DWARFUnit::ScopedExtractDIEs::~ScopedExtractDIEs() { if (!m_cu) return; - { - llvm::sys::ScopedLock lock(m_cu->m_die_array_scoped_mutex); - --m_cu->m_die_array_scoped_count; - if (m_cu->m_die_array_scoped_count == 0) - return; + llvm::sys::ScopedLock lock(m_cu->m_die_array_scoped_mutex); + --m_cu->m_die_array_scoped_count; + if (m_cu->m_die_array_scoped_count == 0 && m_clear_dies && + !m_cu->m_cancel_scopes) { + llvm::sys::ScopedWriter lock(m_cu->m_die_array_mutex); + m_cu->ClearDIEsRWLocked(); } - if (!m_clear_dies || m_cu->m_cancel_scopes) - return; - // Be sure no other ScopedExtractDIEs is running anymore. - llvm::sys::ScopedLock lock_scoped(m_cu->m_die_array_scoped_mutex); - llvm::sys::ScopedWriter lock(m_cu->m_die_array_mutex); - if (m_cu->m_cancel_scopes) - return; - m_cu->ClearDIEsRWLocked(); } DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(ScopedExtractDIEs &&rhs) >From a6ecf88ec6ec2bc83e700cabd8555f1fe2716fb7 Mon Sep 17 00:00:00 2001 From: Jacques Pienaar Date: Tue, 13 May 2025 07:34:00 +0000 Subject: [PATCH 5/5] Add timeout to diagnostics test Was flakey before this (1 in 15 in one test) and timeout seems to suffice in not returning none here. --- lldb/test/API/tools/lldb-dap/console/TestDAP_console.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py b/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py index 8642e317f9b3a..9cdb978368cc1 100644 --- a/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py +++ b/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py @@ -176,7 +176,7 @@ def test_diagnositcs(self): f"target create --core {core}", context="repl" ) - output = self.get_important() + output = self.get_important(timeout=2.0) self.assertIn( "warning: unable to retrieve process ID from minidump file", output, From lldb-commits at lists.llvm.org Tue May 13 00:39:32 2025 From: lldb-commits at lists.llvm.org (Jacques Pienaar via lldb-commits) Date: Tue, 13 May 2025 00:39:32 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][plugin] Clear in same thread as set (PR #139252) In-Reply-To: Message-ID: <6822f734.170a0220.311f7d.dfc0@mx.google.com> https://github.com/jpienaar edited https://github.com/llvm/llvm-project/pull/139252 From lldb-commits at lists.llvm.org Tue May 13 00:39:51 2025 From: lldb-commits at lists.llvm.org (Jacques Pienaar via lldb-commits) Date: Tue, 13 May 2025 00:39:51 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][plugin] Use counter directly for number of readers (PR #139252) In-Reply-To: Message-ID: <6822f747.a70a0220.ee352.0d35@mx.google.com> https://github.com/jpienaar edited https://github.com/llvm/llvm-project/pull/139252 From lldb-commits at lists.llvm.org Tue May 13 00:44:39 2025 From: lldb-commits at lists.llvm.org (Kazu Hirata via lldb-commits) Date: Tue, 13 May 2025 00:44:39 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use std:::string::find with std::string_view (NFC) (PR #139679) In-Reply-To: Message-ID: <6822f867.170a0220.dfa74.d136@mx.google.com> https://github.com/kazutakahirata edited https://github.com/llvm/llvm-project/pull/139679 From lldb-commits at lists.llvm.org Tue May 13 01:26:33 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Tue, 13 May 2025 01:26:33 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Don't create instance of `SymbolFileDWARFDebugMap` for non-Mach-O files (PR #139170) In-Reply-To: Message-ID: <68230239.170a0220.32f084.c9c2@mx.google.com> labath wrote: > To answer your last question: because the plugins (which is really a misnomer), as I understand it, are there to provide abstraction: the caller shouldn't have to know what concrete instance an `ObjectFile` is. The no-plugins-dependency enforces that at compile/link time. This is my problem with that. You're saying the "caller shouldn't have to *know*" -- which is a statement about his state of mind. We can't enforce the state of mind through syntactic restrictions. We can prevent the caller from *saying* he expects a specific subclass, but there's not way to prevent code from expecting that implicitly (perhaps even without it knowing). Functions like `SupportsDebugMap` make it worse because they encourage writing code like that and that makes the plugin system (the abstractions created by it) less useful as a whole. Like, if I now wanted to create a new symbol file plugin that works only with a specific object file, do I add `SupportsPsym` to every object file plugin? Or we don't have to look at new plugins, we have two good examples already: SymbolFileBreakpad and SymbolFileJSON. Both of these currently depend on the their respective object file plugin. Should that be replaced by something else (and would the result be better if we did)? Nonetheless, I agree that plugins should create abstractions, but I think it's important to think about who are those abstractions directed at. The core code definitely shouldn't need to "look behind the curtain" (ideally not even through calls like `SupportsDebugMap`), but I don't think that means that noone else isn't allowed to do that. This situation is really simple, so it doesn't demonstrate the full scope of the problem, which is why I want to go back to the ProcessCore->ObjectFile example. ProcessElfCore needs to extract a lot of detailed information from ObjectFileELF. Same goes for ProcessMachCore. At some level, the information these two pairs are exchanging is the same (threads, registers, ...), so one could imagine a generic interface to pass this -- but would that help anything? I say "no", because you still want to have the two plugins to work in pair -- if you didn't, then you wouldn't need separate process core plugins. This setup would make sense if we had a generic ProcessCore class (not a plugin) which works off of information provided by the object plugins -- but that's not the situation we're in now. You can make the same case for dynamic loaders -- should MacOSX-DYLD work with ObjectFilePECOFF? > TL;DR: My stance is that if there's a way to enforce the DAG, I'm totally fine with allowing inter-plugin dependencies where they make sense. Barring that I think the current rule, albeit overly strict, is the easiest way to enforce we don't regress inter-plugin dependencies in general. Enforcement is tricky, because "where it makes sense" is obviously a judgement call. It's also complicated by the fact that current graph is not a DAG. Linux linkers actually kind of enforce the graph implicitly, but since it's not a DAG now, we have a [workaround](https://github.com/llvm/llvm-project/blob/5c7bc6a0e6a5093812e6aa9719f7d98d14bb0015/lldb/source/Core/CMakeLists.txt#L92) and that prevents us catching any new bad deps. I guess it would be possible to do something similar to `NO_PLUGIN_DEPENDENCIES` in cmake, which only allows dependencies that we consider acceptable, though it's not foolproof: for example SymbolFileJSON doesn't list ObjectFileJSON in its cmake dependencies even though it definitely needs it. I think the best we can do is some cmake check plus some documentation about which dependencies we consider "okay". I don't think this can be foolproof though. Going by the examples above, I would say that we should permit dependencies on object file plugins from SymbolFiles, DynamicLoaders and Processes -- but there are still exceptions to that. For example, ProcessGdbRemote and DynamicLoaderStatic (and *maybe* SymbolFileDWARF) probably shouldn't depend on any specific ObjectFile plugin since they're meant to work with more than one (I guess that could be a general rule -- but it's not enforcable one). A rule like "there shall be no inter-plugin dependencies" is easy to enforce and that makes it appealing, but I think it will be very hard for us to come into compliance with that (and I don't think we'd like the result even if we did). If we say some deps are okay, then a lot of things become automatically compliant, and we can focus on the high-value high-complexity deps like SymbolFile<->TypeSystem. https://github.com/llvm/llvm-project/pull/139170 From lldb-commits at lists.llvm.org Tue May 13 01:39:16 2025 From: lldb-commits at lists.llvm.org (=?UTF-8?Q?Martin_Storsj=C3=B6?= via lldb-commits) Date: Tue, 13 May 2025 01:39:16 -0700 (PDT) Subject: [Lldb-commits] [lldb] Reapply "[lldb] Inherit DuplicateFileAction(HANDLE, HANDLE) handles on windows (#137978)" (PR #138896) In-Reply-To: Message-ID: <68230534.170a0220.e5844.d77c@mx.google.com> mstorsjo wrote: Hi Pavel! Unfortunately, it seems like this change has broken compilation of LLDB for mingw, on all architectures. With MSVC and clang-cl, it is broken for 32 bit platforms, while the issue only shows up as a warning for 64 bit architectures there. On 64 bit mingw: ``` llvm-project/llvm/tools/lldb/tools/lldb-server/lldb-platform.cpp:277:41: error: cast from pointer to smaller type 'int' loses information 277 | launch_info.AppendDuplicateFileAction((int)shared_socket.GetSendableFD(), | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ llvm-project/llvm/tools/lldb/tools/lldb-server/lldb-platform.cpp:278:41: error: cast from pointer to smaller type 'int' loses information 278 | (int)shared_socket.GetSendableFD()); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 errors generated. ``` On 32 bit mingw: ``` llvm-project/llvm/tools/lldb/source/Host/windows/ProcessLauncherWindows.cpp:103:3: error: no matching function for call to 'InitializeProcThreadAttributeList' 103 | InitializeProcThreadAttributeList(/*lpAttributeList=*/nullptr, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ llvm-mingw/i686-w64-mingw32/include/processthreadsapi.h:242:29: note: candidate function not viable: no known conversion from 'size_t *' (aka 'unsigned int *') to 'PSIZE_T' (aka 'unsigned long *') for 4th argument 242 | WINBASEAPI WINBOOL WINAPI InitializeProcThreadAttributeList (LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList, DWORD dwAttributeCount, DWORD dwFlags, PSIZE_T lpSize); | ^ ~~~~~~~~~~~~~~ llvm-project/llvm/tools/lldb/source/Host/windows/ProcessLauncherWindows.cpp:111:8: error: no matching function for call to 'InitializeProcThreadAttributeList' 111 | if (!InitializeProcThreadAttributeList(startupinfoex.lpAttributeList, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ llvm-mingw/i686-w64-mingw32/include/processthreadsapi.h:242:29: note: candidate function not viable: no known conversion from 'size_t *' (aka 'unsigned int *') to 'PSIZE_T' (aka 'unsigned long *') for 4th argument 242 | WINBASEAPI WINBOOL WINAPI InitializeProcThreadAttributeList (LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList, DWORD dwAttributeCount, DWORD dwFlags, PSIZE_T lpSize); | ^ ~~~~~~~~~~~~~~ 2 errors generated. ``` On 32 bit clang-cl: ``` llvm-project\lldb\source\Host\windows\ProcessLauncherWindows.cpp(103,3): error: no matching function for call to 'InitializeProcThreadAttributeList' InitializeProcThreadAttributeList(/*lpAttributeList=*/nullptr, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C:\Program Files (x86)\Windows Kits\10\\include\10.0.19041.0\\um\processthreadsapi.h(673,1): note: candidate function not viable: no known conversion from 'size_t *' (aka 'unsigned int *') to 'PSIZE_T' (aka 'unsigned long *') for 4th argument InitializeProcThreadAttributeList( ^ llvm-project\lldb\source\Host\windows\ProcessLauncherWindows.cpp(111,8): error: no matching function for call to 'InitializeProcThreadAttributeList' if (!InitializeProcThreadAttributeList(startupinfoex.lpAttributeList, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C:\Program Files (x86)\Windows Kits\10\\include\10.0.19041.0\\um\processthreadsapi.h(673,1): note: candidate function not viable: no known conversion from 'size_t *' (aka 'unsigned int *') to 'PSIZE_T' (aka 'unsigned long *') for 4th argument InitializeProcThreadAttributeList( ^ 2 errors generated. ``` 32 bit MSVC: ``` llvm-project\lldb\source\Host\windows\ProcessLauncherWindows.cpp(103): error C2664: 'BOOL InitializeProcThreadAttributeList(LPPROC_THREAD_ATTRIBUTE_LIST,DWORD,DWORD,PSIZE_T)': cannot convert argument 4 from 'size_t *' to 'PSIZE_T' llvm-project\lldb\source\Host\windows\ProcessLauncherWindows.cpp(105): note: Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or parenthesized function-style cast C:\Program Files (x86)\Windows Kits\10\\include\10.0.19041.0\\um\processthreadsapi.h(673): note: see declaration of 'InitializeProcThreadAttributeList' llvm-project\lldb\source\Host\windows\ProcessLauncherWindows.cpp(103): note: while trying to match the argument list '(nullptr, int, int, size_t *)' llvm-project\lldb\source\Host\windows\ProcessLauncherWindows.cpp(111): error C2664: 'BOOL InitializeProcThreadAttributeList(LPPROC_THREAD_ATTRIBUTE_LIST,DWORD,DWORD,PSIZE_T)': cannot convert argument 4 from 'size_t *' to 'PSIZE_T' llvm-project\lldb\source\Host\windows\ProcessLauncherWindows.cpp(113): note: Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or parenthesized function-style cast C:\Program Files (x86)\Windows Kits\10\\include\10.0.19041.0\\um\processthreadsapi.h(673): note: see declaration of 'InitializeProcThreadAttributeList' llvm-project\lldb\source\Host\windows\ProcessLauncherWindows.cpp(111): note: while trying to match the argument list '(LPPROC_THREAD_ATTRIBUTE_LIST, int, int, size_t *)' ninja: build stopped: cannot make progress due to previous errors. ``` On 64 bit clang-cl, it is only a warning: ``` llvm-project\lldb\source\Plugins\Process\gdb-remote\GDBRemoteCommunication.cpp(927,43): warning: cast to smaller integer type 'int' from 'void *' [-Wvoid-pointer-to-int-cast] launch_info.AppendDuplicateFileAction((int)pass_comm_fd, (int)pass_comm_fd); ^~~~~~~~~~~~~~~~~ llvm-project\lldb\source\Plugins\Process\gdb-remote\GDBRemoteCommunication.cpp(927,62): warning: cast to smaller integer type 'int' from 'void *' [-Wvoid-pointer-to-int-cast] launch_info.AppendDuplicateFileAction((int)pass_comm_fd, (int)pass_comm_fd); ^~~~~~~~~~~~~~~~~ 2 warnings generated. llvm-project\lldb\tools\lldb-server\lldb-platform.cpp(277,41): warning: cast to smaller integer type 'int' from 'void *' [-Wvoid-pointer-to-int-cast] launch_info.AppendDuplicateFileAction((int)shared_socket.GetSendableFD(), ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ llvm-project\lldb\tools\lldb-server\lldb-platform.cpp(278,41): warning: cast to smaller integer type 'int' from 'void *' [-Wvoid-pointer-to-int-cast] (int)shared_socket.GetSendableFD()); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 warnings generated. ``` And the same for 64 bit MSVC: ``` llvm-project\lldb\source\Plugins\Process\gdb-remote\GDBRemoteCommunication.cpp(927): warning C4311: 'type cast': pointer truncation from 'lldb_private::shared_fd_t' to 'int' llvm-project\lldb\source\Plugins\Process\gdb-remote\GDBRemoteCommunication.cpp(927): warning C4302: 'type cast': truncation from 'lldb_private::shared_fd_t' to 'int' llvm-project\lldb\source\Plugins\Process\gdb-remote\GDBRemoteCommunication.cpp(927): warning C4311: 'type cast': pointer truncation from 'lldb_private::shared_fd_t' to 'int' llvm-project\lldb\source\Plugins\Process\gdb-remote\GDBRemoteCommunication.cpp(927): warning C4302: 'type cast': truncation from 'lldb_private::shared_fd_t' to 'int' llvm-project\lldb\tools\lldb-server\lldb-platform.cpp(277): warning C4311: 'type cast': pointer truncation from 'lldb_private::shared_fd_t' to 'int' llvm-project\lldb\tools\lldb-server\lldb-platform.cpp(277): warning C4302: 'type cast': truncation from 'lldb_private::shared_fd_t' to 'int' llvm-project\lldb\tools\lldb-server\lldb-platform.cpp(278): warning C4311: 'type cast': pointer truncation from 'lldb_private::shared_fd_t' to 'int' llvm-project\lldb\tools\lldb-server\lldb-platform.cpp(278): warning C4302: 'type cast': truncation from 'lldb_private::shared_fd_t' to 'int' ``` https://github.com/llvm/llvm-project/pull/138896 From lldb-commits at lists.llvm.org Tue May 13 01:52:39 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Tue, 13 May 2025 01:52:39 -0700 (PDT) Subject: [Lldb-commits] [lldb] c78e65c - [lldb][plugin] Use counter directly for number of readers (#139252) Message-ID: <68230857.050a0220.18e5dd.0a9a@mx.google.com> Author: Jacques Pienaar Date: 2025-05-13T01:52:36-07:00 New Revision: c78e65cc980db9542b32049a5d96b00c64cbc47d URL: https://github.com/llvm/llvm-project/commit/c78e65cc980db9542b32049a5d96b00c64cbc47d DIFF: https://github.com/llvm/llvm-project/commit/c78e65cc980db9542b32049a5d96b00c64cbc47d.diff LOG: [lldb][plugin] Use counter directly for number of readers (#139252) Here we were initializing & locking a shared_mutex in a thread, while releasing it in the parent which may/often turned out to be a different thread (shared_mutex::unlock_shared is undefined behavior if called from a thread that doesn't hold the lock). Switch to counter to more simply keep track of number of readers and simply lock/unlock rather than utilizing reader mutex to verify last freed (and so requiring this matching thread init/destroy behavior). Added: Modified: lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h lldb/test/API/tools/lldb-dap/console/TestDAP_console.py Removed: ################################################################################ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index 7d0afc04ac3b6..ffd6f1dd52aff 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -189,21 +189,20 @@ DWARFUnit::ScopedExtractDIEs DWARFUnit::ExtractDIEsScoped() { } DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(DWARFUnit &cu) : m_cu(&cu) { - m_cu->m_die_array_scoped_mutex.lock_shared(); + llvm::sys::ScopedLock lock(m_cu->m_die_array_scoped_mutex); + ++m_cu->m_die_array_scoped_count; } DWARFUnit::ScopedExtractDIEs::~ScopedExtractDIEs() { if (!m_cu) return; - m_cu->m_die_array_scoped_mutex.unlock_shared(); - if (!m_clear_dies || m_cu->m_cancel_scopes) - return; - // Be sure no other ScopedExtractDIEs is running anymore. - llvm::sys::ScopedWriter lock_scoped(m_cu->m_die_array_scoped_mutex); - llvm::sys::ScopedWriter lock(m_cu->m_die_array_mutex); - if (m_cu->m_cancel_scopes) - return; - m_cu->ClearDIEsRWLocked(); + llvm::sys::ScopedLock lock(m_cu->m_die_array_scoped_mutex); + --m_cu->m_die_array_scoped_count; + if (m_cu->m_die_array_scoped_count == 0 && m_clear_dies && + !m_cu->m_cancel_scopes) { + llvm::sys::ScopedWriter lock(m_cu->m_die_array_mutex); + m_cu->ClearDIEsRWLocked(); + } } DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(ScopedExtractDIEs &&rhs) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index 75a003e0a663c..c05bba36ed74b 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -17,6 +17,7 @@ #include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" #include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h" +#include "llvm/Support/Mutex.h" #include "llvm/Support/RWMutex.h" #include #include @@ -328,7 +329,8 @@ class DWARFUnit : public DWARFExpression::Delegate, public UserID { DWARFDebugInfoEntry::collection m_die_array; mutable llvm::sys::RWMutex m_die_array_mutex; // It is used for tracking of ScopedExtractDIEs instances. - mutable llvm::sys::RWMutex m_die_array_scoped_mutex; + mutable llvm::sys::Mutex m_die_array_scoped_mutex; + mutable int m_die_array_scoped_count = 0; // ScopedExtractDIEs instances should not call ClearDIEsRWLocked() // as someone called ExtractDIEsIfNeeded(). std::atomic m_cancel_scopes; diff --git a/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py b/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py index 8642e317f9b3a..9cdb978368cc1 100644 --- a/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py +++ b/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py @@ -176,7 +176,7 @@ def test_diagnositcs(self): f"target create --core {core}", context="repl" ) - output = self.get_important() + output = self.get_important(timeout=2.0) self.assertIn( "warning: unable to retrieve process ID from minidump file", output, From lldb-commits at lists.llvm.org Tue May 13 01:52:44 2025 From: lldb-commits at lists.llvm.org (Jacques Pienaar via lldb-commits) Date: Tue, 13 May 2025 01:52:44 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][plugin] Use counter directly for number of readers (PR #139252) In-Reply-To: Message-ID: <6823085c.170a0220.2bc9cb.c8b0@mx.google.com> https://github.com/jpienaar closed https://github.com/llvm/llvm-project/pull/139252 From lldb-commits at lists.llvm.org Tue May 13 02:35:31 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Tue, 13 May 2025 02:35:31 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add field member operators to DIL (PR #138093) In-Reply-To: Message-ID: <68231263.170a0220.2e97cc.e474@mx.google.com> ================ @@ -272,4 +272,66 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const MemberOfNode *node) { + Status error; + auto base_or_err = Evaluate(node->GetBase()); + if (!base_or_err) { + return base_or_err; + } + lldb::ValueObjectSP base = *base_or_err; + + // Perform basic type checking. + CompilerType base_type = base->GetCompilerType(); + // When using an arrow, make sure the base is a pointer or array type. + // When using a period, make sure the base type is NOT a pointer type. + if (node->GetIsArrow() && !base_type.IsPointerType() && + !base_type.IsArrayType()) { ---------------- labath wrote: Because we want to let the values (and their type systems) decide whether they are dereferencable or not. That's what we did for the implementation of the `*` operator. I could be convinced by the "status quo" argument, but this doesn't look like an equivalent implementation to that (for one, you're adding support for dereferencing arrays), which is why I want to turn this around: if `*` does not check for types, then why should `->` (which is defined as `(*x).`) do that? What I can imagine is doing something on the error handling path -- if dereferencing failed, we look at the value to provide a better error message about why it failed. However, even in this case, I'd try to avoid looking at the type too much and instead try to reuse the error message from the Dereference operation (changing it, if needed) so that we can be sure it makes sense regardless of how the value depends to implement dereferencing. https://github.com/llvm/llvm-project/pull/138093 From lldb-commits at lists.llvm.org Tue May 13 02:42:41 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Tue, 13 May 2025 02:42:41 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add field member operators to DIL (PR #138093) In-Reply-To: Message-ID: <68231411.620a0220.2964ee.155a@mx.google.com> ================ @@ -272,4 +272,66 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const MemberOfNode *node) { + Status error; + auto base_or_err = Evaluate(node->GetBase()); + if (!base_or_err) { + return base_or_err; + } + lldb::ValueObjectSP base = *base_or_err; + + // Perform basic type checking. + CompilerType base_type = base->GetCompilerType(); + // When using an arrow, make sure the base is a pointer or array type. + // When using a period, make sure the base type is NOT a pointer type. + if (node->GetIsArrow() && !base_type.IsPointerType() && + !base_type.IsArrayType()) { + lldb::ValueObjectSP deref_sp = base->Dereference(error); + if (error.Success()) { + base = deref_sp; + base_type = deref_sp->GetCompilerType().GetPointerType(); + } else { + std::string errMsg = + llvm::formatv("member reference type {0} is not a pointer; " + "did you mean to use '.'?", + base_type.TypeDescription()); + return llvm::make_error( + m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); + } + } else if (!node->GetIsArrow() && base_type.IsPointerType()) { + std::string errMsg = + llvm::formatv("member reference type {0} is a pointer; " + "did you mean to use '->'?", + base_type.TypeDescription()); + return llvm::make_error( + m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); + } + + // User specified array->elem; need to get to element[0] to look for fields. + if (node->GetIsArrow() && base_type.IsArrayType()) + base = base->GetChildAtIndex(0); + + // Now look for the member with the specified name. + lldb::ValueObjectSP field_obj = + base->GetChildMemberWithName(llvm::StringRef(node->GetFieldName())); + if (field_obj && field_obj->GetName().GetString() == node->GetFieldName()) { + if (field_obj->GetCompilerType().IsReferenceType()) { + lldb::ValueObjectSP tmp_obj = field_obj->Dereference(error); + if (error.Fail()) + return error.ToError(); + return tmp_obj; + } + return field_obj; + } + + if (node->GetIsArrow() && base_type.IsPointerType()) + base_type = base_type.GetPointeeType(); + std::string errMsg = + llvm::formatv("no member named '{0}' in {1}", node->GetFieldName(), ---------------- labath wrote: Okay, sounds good then. https://github.com/llvm/llvm-project/pull/138093 From lldb-commits at lists.llvm.org Tue May 13 03:00:33 2025 From: lldb-commits at lists.llvm.org (David Spickett via lldb-commits) Date: Tue, 13 May 2025 03:00:33 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][test] Fix beginning/end of file test failed on Windows (PR #139278) In-Reply-To: Message-ID: <68231841.050a0220.266d37.073f@mx.google.com> DavidSpickett wrote: Seems fine, my only question is does the source actually need to be doing this much? Or in other words: the example should be as complex as it needs to be to show the bug. If that means just calling the same do-nothing function over and over to create more lines, that would be preferable. (but I see that you chose something generic that will compile everywhere, thank you for that and that aspect is spot on) https://github.com/llvm/llvm-project/pull/139278 From lldb-commits at lists.llvm.org Tue May 13 03:08:11 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Tue, 13 May 2025 03:08:11 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Refactor lldb-dap event handling. (PR #139669) In-Reply-To: Message-ID: <68231a0b.170a0220.1f9cb.ee85@mx.google.com> labath wrote: I also haven't looked at it in detail yet, but I think it makes sense overall. I'm not saying it has to be done -- it depends on where we want to take this. Doing everything on one thread makes it easy to avoid races and it's a strategy I generally like, but it also kind of goes against some of our other goals of making things faster by doing work in parallel. But then again, it's only "kind of" since it's still possible to introduce more controlled parallelism to -- I don't know -- fetch inferior threads in parallel if it makes sense. And that may actually be better in the long run. Since I'm not going to be doing this work, I'll let you figure out the direction here. I think the patch could use some splitting up. There's a bunch of typo fixes and other things that could go separately. And what's up with all the test changes -- shouldn't this be "NFC" ? Jonas is right that class isn't (completely) thread safe. That's because it originally started out as a completely single-process thing -- which means there are no threads to synchronise. It's grown beyond that now though, and now it has some synchronization. Specifically, `AddPendingCallback` is thread-safe (but not async-signal-safe -- I think that's the part that Jonas is remembering). The thing that's not thread-safe is `RegisterReadObject`. Right now it's possible to work around that by doing something like `loop.AddPendingCallback([&] { loop.RegisterReadObject(); });` but if you find yourself needing to do that, maybe we can add that directly to the MainLoop class. https://github.com/llvm/llvm-project/pull/139669 From lldb-commits at lists.llvm.org Tue May 13 04:04:24 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Tue, 13 May 2025 04:04:24 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Migrate ScopesRequest to structured types (PR #138116) In-Reply-To: Message-ID: <68232738.170a0220.206a00.f305@mx.google.com> https://github.com/da-viper updated https://github.com/llvm/llvm-project/pull/138116 >From 559eb1a020e94c09ccfeda0e4cb5e16df145d4aa Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Tue, 29 Apr 2025 18:19:18 +0100 Subject: [PATCH 1/4] [lldb][lldb-dap] Migrate 'Scopes' to structured types. --- lldb/tools/lldb-dap/DAP.cpp | 11 -- lldb/tools/lldb-dap/DAP.h | 2 - lldb/tools/lldb-dap/Handler/RequestHandler.h | 10 +- .../lldb-dap/Handler/ScopesRequestHandler.cpp | 121 ++++++++---------- lldb/tools/lldb-dap/JSONUtils.h | 21 --- .../lldb-dap/Protocol/ProtocolRequests.cpp | 14 ++ .../lldb-dap/Protocol/ProtocolRequests.h | 13 ++ .../tools/lldb-dap/Protocol/ProtocolTypes.cpp | 71 ++++++++-- lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 81 +++++++++++- 9 files changed, 224 insertions(+), 120 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 4feca1253be20..baaf9950b79db 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -559,17 +559,6 @@ lldb::SBFrame DAP::GetLLDBFrame(const llvm::json::Object &arguments) { return GetLLDBFrame(frame_id); } -llvm::json::Value DAP::CreateTopLevelScopes() { - llvm::json::Array scopes; - scopes.emplace_back( - CreateScope("Locals", VARREF_LOCALS, variables.locals.GetSize(), false)); - scopes.emplace_back(CreateScope("Globals", VARREF_GLOBALS, - variables.globals.GetSize(), false)); - scopes.emplace_back(CreateScope("Registers", VARREF_REGS, - variables.registers.GetSize(), false)); - return llvm::json::Value(std::move(scopes)); -} - ReplMode DAP::DetectReplMode(lldb::SBFrame frame, std::string &expression, bool partial_expression) { // Check for the escape hatch prefix. diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c2e4c2dea582e..f66cb40451484 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -285,8 +285,6 @@ struct DAP { lldb::SBFrame GetLLDBFrame(uint64_t frame_id); lldb::SBFrame GetLLDBFrame(const llvm::json::Object &arguments); - llvm::json::Value CreateTopLevelScopes(); - void PopulateExceptionBreakpoints(); /// Attempt to determine if an expression is a variable expression or diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index b0002440cf72e..eaebaf6619bbd 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -452,11 +452,15 @@ class PauseRequestHandler : public LegacyRequestHandler { void operator()(const llvm::json::Object &request) const override; }; -class ScopesRequestHandler : public LegacyRequestHandler { +class ScopesRequestHandler final + : public RequestHandler> { public: - using LegacyRequestHandler::LegacyRequestHandler; + using RequestHandler::RequestHandler; static llvm::StringLiteral GetCommand() { return "scopes"; } - void operator()(const llvm::json::Object &request) const override; + + llvm::Expected + Run(const protocol::ScopesArguments &args) const override; }; class SetVariableRequestHandler final diff --git a/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp index 7d1608f59f9a4..d9dd29f7269f2 100644 --- a/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp @@ -7,69 +7,55 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" #include "RequestHandler.h" +using namespace lldb_dap::protocol; namespace lldb_dap { -// "ScopesRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Scopes request; value of command field is 'scopes'. The -// request returns the variable scopes for a given stackframe ID.", -// "properties": { -// "command": { -// "type": "string", -// "enum": [ "scopes" ] -// }, -// "arguments": { -// "$ref": "#/definitions/ScopesArguments" -// } -// }, -// "required": [ "command", "arguments" ] -// }] -// }, -// "ScopesArguments": { -// "type": "object", -// "description": "Arguments for 'scopes' request.", -// "properties": { -// "frameId": { -// "type": "integer", -// "description": "Retrieve the scopes for this stackframe." -// } -// }, -// "required": [ "frameId" ] -// }, -// "ScopesResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to 'scopes' request.", -// "properties": { -// "body": { -// "type": "object", -// "properties": { -// "scopes": { -// "type": "array", -// "items": { -// "$ref": "#/definitions/Scope" -// }, -// "description": "The scopes of the stackframe. If the array has -// length zero, there are no scopes available." -// } -// }, -// "required": [ "scopes" ] -// } -// }, -// "required": [ "body" ] -// }] -// } -void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - llvm::json::Object body; - const auto *arguments = request.getObject("arguments"); - lldb::SBFrame frame = dap.GetLLDBFrame(*arguments); +/// Creates a `protocol::Scope` struct. +/// +/// +/// \param[in] name +/// The value to place into the "name" key +/// +/// \param[in] variablesReference +/// The value to place into the "variablesReference" key +/// +/// \param[in] namedVariables +/// The value to place into the "namedVariables" key +/// +/// \param[in] expensive +/// The value to place into the "expensive" key +/// +/// \return +/// A `protocol::Scope` +static Scope CreateScope(const llvm::StringRef name, int64_t variablesReference, + int64_t namedVariables, bool expensive) { + Scope scope; + scope.name = name; + + // TODO: Support "arguments" and "return value" scope. + // At the moment lldb-dap includes the arguments and return_value into the + // "locals" scope. add presentation hint; + // vscode only expands the first non-expensive scope, this causes friction + // as the locals scope will not be expanded. It becomes more annoying when + // the scope has arguments, return_value and locals. + if (variablesReference == VARREF_LOCALS) + scope.presentationHint = Scope::ePresentationHintLocals; + else if (variablesReference == VARREF_REGS) + scope.presentationHint = Scope::ePresentationHintRegisters; + + scope.variablesReference = variablesReference; + scope.namedVariables = namedVariables; + scope.expensive = expensive; + + return scope; +} + +llvm::Expected +ScopesRequestHandler::Run(const ScopesArguments &args) const { + lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId); + // As the user selects different stack frames in the GUI, a "scopes" request // will be sent to the DAP. This is the only way we know that the user has // selected a frame in a thread. There are no other notifications that are @@ -78,9 +64,9 @@ void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { // are sent, this allows users to type commands in the debugger console // with a backtick character to run lldb commands and these lldb commands // will now have the right context selected as they are run. If the user - // types "`bt" into the debugger console and we had another thread selected + // types "`bt" into the debugger console, and we had another thread selected // in the LLDB library, we would show the wrong thing to the user. If the - // users switches threads with a lldb command like "`thread select 14", the + // users switch threads with a lldb command like "`thread select 14", the // GUI will not update as there are no "event" notification packets that // allow us to change the currently selected thread or frame in the GUI that // I am aware of. @@ -88,7 +74,6 @@ void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { frame.GetThread().GetProcess().SetSelectedThread(frame.GetThread()); frame.GetThread().SetSelectedFrame(frame.GetFrameID()); } - dap.variables.locals = frame.GetVariables(/*arguments=*/true, /*locals=*/true, /*statics=*/false, @@ -98,9 +83,15 @@ void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { /*statics=*/true, /*in_scope_only=*/true); dap.variables.registers = frame.GetRegisters(); - body.try_emplace("scopes", dap.CreateTopLevelScopes()); - response.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(response))); + + std::vector scopes = {CreateScope("Locals", VARREF_LOCALS, + dap.variables.locals.GetSize(), false), + CreateScope("Globals", VARREF_GLOBALS, + dap.variables.globals.GetSize(), false), + CreateScope("Registers", VARREF_REGS, + dap.variables.registers.GetSize(), false)}; + + return ScopesResponseBody{std::move(scopes)}; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h index 9c4dd0584bd21..783f291338d8c 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -238,27 +238,6 @@ llvm::json::Object CreateEventObject(const llvm::StringRef event_name); protocol::ExceptionBreakpointsFilter CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp); -/// Create a "Scope" JSON object as described in the debug adapter definition. -/// -/// \param[in] name -/// The value to place into the "name" key -// -/// \param[in] variablesReference -/// The value to place into the "variablesReference" key -// -/// \param[in] namedVariables -/// The value to place into the "namedVariables" key -// -/// \param[in] expensive -/// The value to place into the "expensive" key -/// -/// \return -/// A "Scope" JSON object with that follows the formal JSON -/// definition outlined by Microsoft. -llvm::json::Value CreateScope(const llvm::StringRef name, - int64_t variablesReference, - int64_t namedVariables, bool expensive); - /// Create a "Source" JSON object as described in the debug adapter definition. /// /// \param[in] file diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp index 316e146d43a0f..7efab87d39986 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp @@ -335,6 +335,20 @@ llvm::json::Value toJSON(const SetVariableResponseBody &SVR) { return llvm::json::Value(std::move(Body)); } +bool fromJSON(const llvm::json::Value &Params, ScopesArguments &SCA, + llvm::json::Path P) { + json::ObjectMapper O(Params, P); + return O && O.map("frameId", SCA.frameId); +} + +llvm::json::Value toJSON(const ScopesResponseBody &SCR) { + llvm::json::Array scopes; + for (const Scope &scope : SCR.scopes) { + scopes.emplace_back(toJSON(scope)); + } + + return llvm::json::Object{{"scopes", std::move(scopes)}}; +} bool fromJSON(const json::Value &Params, SourceArguments &SA, json::Path P) { json::ObjectMapper O(Params, P); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index c6456b4113320..79739d8fc4309 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -439,6 +439,19 @@ struct SetVariableResponseBody { }; llvm::json::Value toJSON(const SetVariableResponseBody &); +struct ScopesArguments { + /// Retrieve the scopes for the stack frame identified by `frameId`. The + /// `frameId` must have been obtained in the current suspended state. See + /// 'Lifetime of Object References' in the Overview section for details. + uint64_t frameId; +}; +bool fromJSON(const llvm::json::Value &, ScopesArguments &, llvm::json::Path); + +struct ScopesResponseBody { + std::vector scopes; +}; +llvm::json::Value toJSON(const ScopesResponseBody &); + /// Arguments for `source` request. struct SourceArguments { /// Specifies the source content to load. Either `source.path` or diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index c9cab350f9f12..74f8f749abe4c 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -16,17 +16,18 @@ using namespace llvm; namespace lldb_dap::protocol { -bool fromJSON(const json::Value &Params, PresentationHint &PH, json::Path P) { +bool fromJSON(const json::Value &Params, Source::PresentationHint &PH, + json::Path P) { auto rawHint = Params.getAsString(); if (!rawHint) { P.report("expected a string"); return false; } - std::optional hint = - StringSwitch>(*rawHint) - .Case("normal", ePresentationHintNormal) - .Case("emphasize", ePresentationHintEmphasize) - .Case("deemphasize", ePresentationHintDeemphasize) + std::optional hint = + StringSwitch>(*rawHint) + .Case("normal", Source::ePresentationHintNormal) + .Case("emphasize", Source::ePresentationHintEmphasize) + .Case("deemphasize", Source::ePresentationHintDeemphasize) .Default(std::nullopt); if (!hint) { P.report("unexpected value"); @@ -42,14 +43,13 @@ bool fromJSON(const json::Value &Params, Source &S, json::Path P) { O.map("presentationHint", S.presentationHint) && O.map("sourceReference", S.sourceReference); } - -llvm::json::Value toJSON(PresentationHint hint) { +llvm::json::Value toJSON(Source::PresentationHint hint) { switch (hint) { - case ePresentationHintNormal: + case Source::ePresentationHintNormal: return "normal"; - case ePresentationHintEmphasize: + case Source::ePresentationHintEmphasize: return "emphasize"; - case ePresentationHintDeemphasize: + case Source::ePresentationHintDeemphasize: return "deemphasize"; } llvm_unreachable("unhandled presentation hint."); @@ -269,6 +269,55 @@ json::Value toJSON(const Capabilities &C) { return result; } +llvm::json::Value toJSON(const Scope &SC) { + llvm::json::Object result{{"name", SC.name}, + {"variablesReference", SC.variablesReference}, + {"expensive", SC.expensive}}; + + if (SC.presentationHint.has_value()) { + llvm::StringRef presentationHint; + switch (*SC.presentationHint) { + case Scope::ePresentationHintArguments: + presentationHint = "arguments"; + break; + case Scope::ePresentationHintLocals: + presentationHint = "locals"; + break; + case Scope::ePresentationHintRegisters: + presentationHint = "registers"; + break; + case Scope::ePresentationHintReturnValue: + presentationHint = "returnValue"; + break; + } + + result.insert({"presentationHint", presentationHint}); + } + + if (SC.namedVariables.has_value()) + result.insert({"namedVariables", SC.namedVariables}); + + if (SC.indexedVariables.has_value()) + result.insert({"indexedVariables", SC.indexedVariables}); + + if (SC.source.has_value()) + result.insert({"source", SC.source}); + + if (SC.line.has_value()) + result.insert({"line", SC.line}); + + if (SC.column.has_value()) + result.insert({"column", SC.column}); + + if (SC.endLine.has_value()) + result.insert({"endLine", SC.endLine}); + + if (SC.endColumn.has_value()) + result.insert({"endColumn", SC.endColumn}); + + return result; +} + bool fromJSON(const llvm::json::Value &Params, SteppingGranularity &SG, llvm::json::Path P) { auto raw_granularity = Params.getAsString(); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index d1e86b0897675..d1070d37e3ba3 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -271,17 +271,16 @@ struct Capabilities { }; llvm::json::Value toJSON(const Capabilities &); -enum PresentationHint : unsigned { - ePresentationHintNormal, - ePresentationHintEmphasize, - ePresentationHintDeemphasize, -}; -llvm::json::Value toJSON(PresentationHint hint); - /// A `Source` is a descriptor for source code. It is returned from the debug /// adapter as part of a `StackFrame` and it is used by clients when specifying /// breakpoints. struct Source { + enum PresentationHint : unsigned { + ePresentationHintNormal, + ePresentationHintEmphasize, + ePresentationHintDeemphasize, + }; + /// The short name of the source. Every source returned from the debug adapter /// has a name. When sending a source to the debug adapter this name is /// optional. @@ -305,9 +304,77 @@ struct Source { // unsupported keys: origin, sources, adapterData, checksums }; +llvm::json::Value toJSON(Source::PresentationHint); bool fromJSON(const llvm::json::Value &, Source &, llvm::json::Path); llvm::json::Value toJSON(const Source &); +/// A `Scope` is a named container for variables. Optionally a scope can map to +/// a source or a range within a source. +struct Scope { + enum PresentationHint : unsigned { + ePresentationHintArguments, + ePresentationHintLocals, + ePresentationHintRegisters, + ePresentationHintReturnValue + }; + /// Name of the scope such as 'Arguments', 'Locals', or 'Registers'. This + /// string is shown in the UI as is and can be translated. + //// + std::string name; + + /// A hint for how to present this scope in the UI. If this attribute is + /// missing, the scope is shown with a generic UI. + /// Values: + /// 'arguments': Scope contains method arguments. + /// 'locals': Scope contains local variables. + /// 'registers': Scope contains registers. Only a single `registers` scope + /// should be returned from a `scopes` request. + /// 'returnValue': Scope contains one or more return values. + /// etc. + std::optional presentationHint; + + /// The variables of this scope can be retrieved by passing the value of + /// `variablesReference` to the `variables` request as long as execution + /// remains suspended. See 'Lifetime of Object References' in the Overview + /// section for details. + //// + uint64_t variablesReference; + + /// The number of named variables in this scope. + /// The client can use this information to present the variables in a paged UI + /// and fetch them in chunks. + std::optional namedVariables; + + /// The number of indexed variables in this scope. + /// The client can use this information to present the variables in a paged UI + /// and fetch them in chunks. + std::optional indexedVariables; + + /// The source for this scope. + std::optional source; + + /// If true, the number of variables in this scope is large or expensive to + /// retrieve. + bool expensive; + + /// The start line of the range covered by this scope. + std::optional line; + + /// Start position of the range covered by the scope. It is measured in UTF-16 + /// code units and the client capability `columnsStartAt1` determines whether + /// it is 0- or 1-based. + std::optional column; + + /// The end line of the range covered by this scope. + std::optional endLine; + + /// End position of the range covered by the scope. It is measured in UTF-16 + /// code units and the client capability `columnsStartAt1` determines whether + /// it is 0- or 1-based. + std::optional endColumn; +}; +llvm::json::Value toJSON(const Scope &); + /// The granularity of one `step` in the stepping requests `next`, `stepIn`, /// `stepOut` and `stepBack`. enum SteppingGranularity : unsigned { >From 2165bfd9f949c50df123a7e0ac12efb5e31592e2 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Mon, 12 May 2025 20:33:33 +0100 Subject: [PATCH 2/4] [lldb][lldb-dap] review changes --- lldb/tools/lldb-dap/Protocol/ProtocolRequests.h | 2 +- lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index 79739d8fc4309..f8d6b6a8581ea 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -443,7 +443,7 @@ struct ScopesArguments { /// Retrieve the scopes for the stack frame identified by `frameId`. The /// `frameId` must have been obtained in the current suspended state. See /// 'Lifetime of Object References' in the Overview section for details. - uint64_t frameId; + uint64_t frameId = LLDB_INVALID_FRAME_ID; }; bool fromJSON(const llvm::json::Value &, ScopesArguments &, llvm::json::Path); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index d1070d37e3ba3..668c3d7682f3f 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -27,6 +27,8 @@ #include #include +#define LLDB_DAP_INVALID_VARRERF UINT64_MAX + namespace lldb_dap::protocol { /// An `ExceptionBreakpointsFilter` is shown in the UI as an filter option for @@ -338,7 +340,7 @@ struct Scope { /// remains suspended. See 'Lifetime of Object References' in the Overview /// section for details. //// - uint64_t variablesReference; + uint64_t variablesReference = LLDB_DAP_INVALID_VARRERF; /// The number of named variables in this scope. /// The client can use this information to present the variables in a paged UI @@ -355,7 +357,7 @@ struct Scope { /// If true, the number of variables in this scope is large or expensive to /// retrieve. - bool expensive; + bool expensive = false; /// The start line of the range covered by this scope. std::optional line; >From c3bffb542617bef10bb2cc814af9d8ec47ff12be Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Mon, 12 May 2025 20:36:21 +0100 Subject: [PATCH 3/4] [lldb][lldb-dap] review changes --- lldb/tools/lldb-dap/DAP.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index f66cb40451484..9065995f5d722 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -283,6 +283,8 @@ struct DAP { lldb::SBThread GetLLDBThread(const llvm::json::Object &arguments); lldb::SBFrame GetLLDBFrame(uint64_t frame_id); + /// TODO: remove this function when we finish migrating to the + /// new protocol types. lldb::SBFrame GetLLDBFrame(const llvm::json::Object &arguments); void PopulateExceptionBreakpoints(); >From 6fcf3c0089beccecd148676a0f3444d33f95d7c8 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Tue, 13 May 2025 12:03:02 +0100 Subject: [PATCH 4/4] [lldb][lldb-dap] add review changes --- .../lldb-dap/Handler/ScopesRequestHandler.cpp | 4 +- .../tools/lldb-dap/Protocol/ProtocolTypes.cpp | 56 +++++++++++++++---- lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 17 +++--- lldb/unittests/DAP/ProtocolTypesTest.cpp | 43 +++++++++++++- 4 files changed, 100 insertions(+), 20 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp index d9dd29f7269f2..e8ae25469d82f 100644 --- a/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp @@ -41,9 +41,9 @@ static Scope CreateScope(const llvm::StringRef name, int64_t variablesReference, // as the locals scope will not be expanded. It becomes more annoying when // the scope has arguments, return_value and locals. if (variablesReference == VARREF_LOCALS) - scope.presentationHint = Scope::ePresentationHintLocals; + scope.presentationHint = Scope::eScopePresentationHintLocals; else if (variablesReference == VARREF_REGS) - scope.presentationHint = Scope::ePresentationHintRegisters; + scope.presentationHint = Scope::eScopePresentationHintRegisters; scope.variablesReference = variablesReference; scope.namedVariables = namedVariables; diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index 74f8f749abe4c..09d383311a242 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -25,9 +25,9 @@ bool fromJSON(const json::Value &Params, Source::PresentationHint &PH, } std::optional hint = StringSwitch>(*rawHint) - .Case("normal", Source::ePresentationHintNormal) - .Case("emphasize", Source::ePresentationHintEmphasize) - .Case("deemphasize", Source::ePresentationHintDeemphasize) + .Case("normal", Source::eSourcePresentationHintNormal) + .Case("emphasize", Source::eSourcePresentationHintEmphasize) + .Case("deemphasize", Source::eSourcePresentationHintDeemphasize) .Default(std::nullopt); if (!hint) { P.report("unexpected value"); @@ -43,13 +43,14 @@ bool fromJSON(const json::Value &Params, Source &S, json::Path P) { O.map("presentationHint", S.presentationHint) && O.map("sourceReference", S.sourceReference); } + llvm::json::Value toJSON(Source::PresentationHint hint) { switch (hint) { - case Source::ePresentationHintNormal: + case Source::eSourcePresentationHintNormal: return "normal"; - case Source::ePresentationHintEmphasize: + case Source::eSourcePresentationHintEmphasize: return "emphasize"; - case Source::ePresentationHintDeemphasize: + case Source::eSourcePresentationHintDeemphasize: return "deemphasize"; } llvm_unreachable("unhandled presentation hint."); @@ -269,6 +270,41 @@ json::Value toJSON(const Capabilities &C) { return result; } +bool fromJSON(const json::Value &Params, Scope::PresentationHint &PH, + json::Path P) { + auto rawHint = Params.getAsString(); + if (!rawHint) { + P.report("expected a string"); + return false; + } + const std::optional hint = + StringSwitch>(*rawHint) + .Case("arguments", Scope::eScopePresentationHintArguments) + .Case("locals", Scope::eScopePresentationHintLocals) + .Case("registers", Scope::eScopePresentationHintRegisters) + .Case("returnValue", Scope::eScopePresentationHintReturnValue) + .Default(std::nullopt); + if (!hint) { + P.report("unexpected value"); + return false; + } + PH = *hint; + return true; +} + +bool fromJSON(const json::Value &Params, Scope &S, json::Path P) { + json::ObjectMapper O(Params, P); + return O && O.map("name", S.name) && + O.mapOptional("presentationHint", S.presentationHint) && + O.map("variablesReference", S.variablesReference) && + O.mapOptional("namedVariables", S.namedVariables) && + O.map("indexedVariables", S.indexedVariables) && + O.mapOptional("source", S.source) && O.map("expensive", S.expensive) && + O.mapOptional("line", S.line) && O.mapOptional("column", S.column) && + O.mapOptional("endLine", S.endLine) && + O.mapOptional("endColumn", S.endColumn); +} + llvm::json::Value toJSON(const Scope &SC) { llvm::json::Object result{{"name", SC.name}, {"variablesReference", SC.variablesReference}, @@ -277,16 +313,16 @@ llvm::json::Value toJSON(const Scope &SC) { if (SC.presentationHint.has_value()) { llvm::StringRef presentationHint; switch (*SC.presentationHint) { - case Scope::ePresentationHintArguments: + case Scope::eScopePresentationHintArguments: presentationHint = "arguments"; break; - case Scope::ePresentationHintLocals: + case Scope::eScopePresentationHintLocals: presentationHint = "locals"; break; - case Scope::ePresentationHintRegisters: + case Scope::eScopePresentationHintRegisters: presentationHint = "registers"; break; - case Scope::ePresentationHintReturnValue: + case Scope::eScopePresentationHintReturnValue: presentationHint = "returnValue"; break; } diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index 668c3d7682f3f..b42c2699b6248 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -278,9 +278,9 @@ llvm::json::Value toJSON(const Capabilities &); /// breakpoints. struct Source { enum PresentationHint : unsigned { - ePresentationHintNormal, - ePresentationHintEmphasize, - ePresentationHintDeemphasize, + eSourcePresentationHintNormal, + eSourcePresentationHintEmphasize, + eSourcePresentationHintDeemphasize, }; /// The short name of the source. Every source returned from the debug adapter @@ -314,10 +314,10 @@ llvm::json::Value toJSON(const Source &); /// a source or a range within a source. struct Scope { enum PresentationHint : unsigned { - ePresentationHintArguments, - ePresentationHintLocals, - ePresentationHintRegisters, - ePresentationHintReturnValue + eScopePresentationHintArguments, + eScopePresentationHintLocals, + eScopePresentationHintRegisters, + eScopePresentationHintReturnValue }; /// Name of the scope such as 'Arguments', 'Locals', or 'Registers'. This /// string is shown in the UI as is and can be translated. @@ -375,6 +375,9 @@ struct Scope { /// it is 0- or 1-based. std::optional endColumn; }; +bool fromJSON(const llvm::json::Value &Params, Scope::PresentationHint &PH, + llvm::json::Path); +bool fromJSON(const llvm::json::Value &, Scope &, llvm::json::Path); llvm::json::Value toJSON(const Scope &); /// The granularity of one `step` in the stepping requests `next`, `stepIn`, diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp index fa46816ca4a10..f330beef6e2a5 100644 --- a/lldb/unittests/DAP/ProtocolTypesTest.cpp +++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp @@ -50,7 +50,7 @@ TEST(ProtocolTypesTest, Source) { source.name = "testName"; source.path = "/path/to/source"; source.sourceReference = 12345; - source.presentationHint = ePresentationHintEmphasize; + source.presentationHint = Source::eSourcePresentationHintEmphasize; llvm::Expected deserialized_source = roundtrip(source); ASSERT_THAT_EXPECTED(deserialized_source, llvm::Succeeded()); @@ -60,3 +60,44 @@ TEST(ProtocolTypesTest, Source) { EXPECT_EQ(source.sourceReference, deserialized_source->sourceReference); EXPECT_EQ(source.presentationHint, deserialized_source->presentationHint); } + +TEST(ProtocolTypesTest, Scope) { + Scope scope; + scope.name = "Locals"; + scope.presentationHint = Scope::eScopePresentationHintLocals; + scope.variablesReference = 1; + scope.namedVariables = 2; + scope.indexedVariables = std::nullopt; + scope.expensive = false; + scope.line = 2; + scope.column = 3; + scope.endLine = 10; + scope.endColumn = 20; + + scope.source = + Source{.name = "testName", + .path = "/path/to/source", + .sourceReference = 12345, + .presentationHint = Source::eSourcePresentationHintNormal}; + + llvm::Expected deserialized_scope = roundtrip(scope); + ASSERT_THAT_EXPECTED(deserialized_scope, llvm::Succeeded()); + EXPECT_EQ(scope.name, deserialized_scope->name); + EXPECT_EQ(scope.presentationHint, deserialized_scope->presentationHint); + EXPECT_EQ(scope.variablesReference, deserialized_scope->variablesReference); + EXPECT_EQ(scope.namedVariables, deserialized_scope->namedVariables); + EXPECT_EQ(scope.indexedVariables, deserialized_scope->indexedVariables); + EXPECT_EQ(scope.expensive, deserialized_scope->expensive); + EXPECT_EQ(scope.line, deserialized_scope->line); + EXPECT_EQ(scope.column, deserialized_scope->column); + EXPECT_EQ(scope.endLine, deserialized_scope->endLine); + EXPECT_EQ(scope.endColumn, deserialized_scope->endColumn); + + EXPECT_THAT(deserialized_scope->source.has_value(), true); + const Source &source = scope.source.value(); + const Source &deserialized_source = deserialized_scope->source.value(); + + EXPECT_EQ(source.path, deserialized_source.path); + EXPECT_EQ(source.sourceReference, deserialized_source.sourceReference); + EXPECT_EQ(source.presentationHint, deserialized_source.presentationHint); +} From lldb-commits at lists.llvm.org Tue May 13 04:08:34 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Tue, 13 May 2025 04:08:34 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Migrate ScopesRequest to structured types (PR #138116) In-Reply-To: Message-ID: <68232832.a70a0220.285ae5.f8f1@mx.google.com> da-viper wrote: This means also adding serialisation or de-serialisation for types that do not use it except for test. https://github.com/llvm/llvm-project/pull/138116 From lldb-commits at lists.llvm.org Tue May 13 04:12:44 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Tue, 13 May 2025 04:12:44 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Migrate ScopesRequest to structured types (PR #138116) In-Reply-To: Message-ID: <6823292c.170a0220.d7223.e2b8@mx.google.com> https://github.com/da-viper updated https://github.com/llvm/llvm-project/pull/138116 >From 559eb1a020e94c09ccfeda0e4cb5e16df145d4aa Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Tue, 29 Apr 2025 18:19:18 +0100 Subject: [PATCH 1/5] [lldb][lldb-dap] Migrate 'Scopes' to structured types. --- lldb/tools/lldb-dap/DAP.cpp | 11 -- lldb/tools/lldb-dap/DAP.h | 2 - lldb/tools/lldb-dap/Handler/RequestHandler.h | 10 +- .../lldb-dap/Handler/ScopesRequestHandler.cpp | 121 ++++++++---------- lldb/tools/lldb-dap/JSONUtils.h | 21 --- .../lldb-dap/Protocol/ProtocolRequests.cpp | 14 ++ .../lldb-dap/Protocol/ProtocolRequests.h | 13 ++ .../tools/lldb-dap/Protocol/ProtocolTypes.cpp | 71 ++++++++-- lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 81 +++++++++++- 9 files changed, 224 insertions(+), 120 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 4feca1253be20..baaf9950b79db 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -559,17 +559,6 @@ lldb::SBFrame DAP::GetLLDBFrame(const llvm::json::Object &arguments) { return GetLLDBFrame(frame_id); } -llvm::json::Value DAP::CreateTopLevelScopes() { - llvm::json::Array scopes; - scopes.emplace_back( - CreateScope("Locals", VARREF_LOCALS, variables.locals.GetSize(), false)); - scopes.emplace_back(CreateScope("Globals", VARREF_GLOBALS, - variables.globals.GetSize(), false)); - scopes.emplace_back(CreateScope("Registers", VARREF_REGS, - variables.registers.GetSize(), false)); - return llvm::json::Value(std::move(scopes)); -} - ReplMode DAP::DetectReplMode(lldb::SBFrame frame, std::string &expression, bool partial_expression) { // Check for the escape hatch prefix. diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c2e4c2dea582e..f66cb40451484 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -285,8 +285,6 @@ struct DAP { lldb::SBFrame GetLLDBFrame(uint64_t frame_id); lldb::SBFrame GetLLDBFrame(const llvm::json::Object &arguments); - llvm::json::Value CreateTopLevelScopes(); - void PopulateExceptionBreakpoints(); /// Attempt to determine if an expression is a variable expression or diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index b0002440cf72e..eaebaf6619bbd 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -452,11 +452,15 @@ class PauseRequestHandler : public LegacyRequestHandler { void operator()(const llvm::json::Object &request) const override; }; -class ScopesRequestHandler : public LegacyRequestHandler { +class ScopesRequestHandler final + : public RequestHandler> { public: - using LegacyRequestHandler::LegacyRequestHandler; + using RequestHandler::RequestHandler; static llvm::StringLiteral GetCommand() { return "scopes"; } - void operator()(const llvm::json::Object &request) const override; + + llvm::Expected + Run(const protocol::ScopesArguments &args) const override; }; class SetVariableRequestHandler final diff --git a/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp index 7d1608f59f9a4..d9dd29f7269f2 100644 --- a/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp @@ -7,69 +7,55 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" #include "RequestHandler.h" +using namespace lldb_dap::protocol; namespace lldb_dap { -// "ScopesRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Scopes request; value of command field is 'scopes'. The -// request returns the variable scopes for a given stackframe ID.", -// "properties": { -// "command": { -// "type": "string", -// "enum": [ "scopes" ] -// }, -// "arguments": { -// "$ref": "#/definitions/ScopesArguments" -// } -// }, -// "required": [ "command", "arguments" ] -// }] -// }, -// "ScopesArguments": { -// "type": "object", -// "description": "Arguments for 'scopes' request.", -// "properties": { -// "frameId": { -// "type": "integer", -// "description": "Retrieve the scopes for this stackframe." -// } -// }, -// "required": [ "frameId" ] -// }, -// "ScopesResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to 'scopes' request.", -// "properties": { -// "body": { -// "type": "object", -// "properties": { -// "scopes": { -// "type": "array", -// "items": { -// "$ref": "#/definitions/Scope" -// }, -// "description": "The scopes of the stackframe. If the array has -// length zero, there are no scopes available." -// } -// }, -// "required": [ "scopes" ] -// } -// }, -// "required": [ "body" ] -// }] -// } -void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - llvm::json::Object body; - const auto *arguments = request.getObject("arguments"); - lldb::SBFrame frame = dap.GetLLDBFrame(*arguments); +/// Creates a `protocol::Scope` struct. +/// +/// +/// \param[in] name +/// The value to place into the "name" key +/// +/// \param[in] variablesReference +/// The value to place into the "variablesReference" key +/// +/// \param[in] namedVariables +/// The value to place into the "namedVariables" key +/// +/// \param[in] expensive +/// The value to place into the "expensive" key +/// +/// \return +/// A `protocol::Scope` +static Scope CreateScope(const llvm::StringRef name, int64_t variablesReference, + int64_t namedVariables, bool expensive) { + Scope scope; + scope.name = name; + + // TODO: Support "arguments" and "return value" scope. + // At the moment lldb-dap includes the arguments and return_value into the + // "locals" scope. add presentation hint; + // vscode only expands the first non-expensive scope, this causes friction + // as the locals scope will not be expanded. It becomes more annoying when + // the scope has arguments, return_value and locals. + if (variablesReference == VARREF_LOCALS) + scope.presentationHint = Scope::ePresentationHintLocals; + else if (variablesReference == VARREF_REGS) + scope.presentationHint = Scope::ePresentationHintRegisters; + + scope.variablesReference = variablesReference; + scope.namedVariables = namedVariables; + scope.expensive = expensive; + + return scope; +} + +llvm::Expected +ScopesRequestHandler::Run(const ScopesArguments &args) const { + lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId); + // As the user selects different stack frames in the GUI, a "scopes" request // will be sent to the DAP. This is the only way we know that the user has // selected a frame in a thread. There are no other notifications that are @@ -78,9 +64,9 @@ void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { // are sent, this allows users to type commands in the debugger console // with a backtick character to run lldb commands and these lldb commands // will now have the right context selected as they are run. If the user - // types "`bt" into the debugger console and we had another thread selected + // types "`bt" into the debugger console, and we had another thread selected // in the LLDB library, we would show the wrong thing to the user. If the - // users switches threads with a lldb command like "`thread select 14", the + // users switch threads with a lldb command like "`thread select 14", the // GUI will not update as there are no "event" notification packets that // allow us to change the currently selected thread or frame in the GUI that // I am aware of. @@ -88,7 +74,6 @@ void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { frame.GetThread().GetProcess().SetSelectedThread(frame.GetThread()); frame.GetThread().SetSelectedFrame(frame.GetFrameID()); } - dap.variables.locals = frame.GetVariables(/*arguments=*/true, /*locals=*/true, /*statics=*/false, @@ -98,9 +83,15 @@ void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { /*statics=*/true, /*in_scope_only=*/true); dap.variables.registers = frame.GetRegisters(); - body.try_emplace("scopes", dap.CreateTopLevelScopes()); - response.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(response))); + + std::vector scopes = {CreateScope("Locals", VARREF_LOCALS, + dap.variables.locals.GetSize(), false), + CreateScope("Globals", VARREF_GLOBALS, + dap.variables.globals.GetSize(), false), + CreateScope("Registers", VARREF_REGS, + dap.variables.registers.GetSize(), false)}; + + return ScopesResponseBody{std::move(scopes)}; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h index 9c4dd0584bd21..783f291338d8c 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -238,27 +238,6 @@ llvm::json::Object CreateEventObject(const llvm::StringRef event_name); protocol::ExceptionBreakpointsFilter CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp); -/// Create a "Scope" JSON object as described in the debug adapter definition. -/// -/// \param[in] name -/// The value to place into the "name" key -// -/// \param[in] variablesReference -/// The value to place into the "variablesReference" key -// -/// \param[in] namedVariables -/// The value to place into the "namedVariables" key -// -/// \param[in] expensive -/// The value to place into the "expensive" key -/// -/// \return -/// A "Scope" JSON object with that follows the formal JSON -/// definition outlined by Microsoft. -llvm::json::Value CreateScope(const llvm::StringRef name, - int64_t variablesReference, - int64_t namedVariables, bool expensive); - /// Create a "Source" JSON object as described in the debug adapter definition. /// /// \param[in] file diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp index 316e146d43a0f..7efab87d39986 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp @@ -335,6 +335,20 @@ llvm::json::Value toJSON(const SetVariableResponseBody &SVR) { return llvm::json::Value(std::move(Body)); } +bool fromJSON(const llvm::json::Value &Params, ScopesArguments &SCA, + llvm::json::Path P) { + json::ObjectMapper O(Params, P); + return O && O.map("frameId", SCA.frameId); +} + +llvm::json::Value toJSON(const ScopesResponseBody &SCR) { + llvm::json::Array scopes; + for (const Scope &scope : SCR.scopes) { + scopes.emplace_back(toJSON(scope)); + } + + return llvm::json::Object{{"scopes", std::move(scopes)}}; +} bool fromJSON(const json::Value &Params, SourceArguments &SA, json::Path P) { json::ObjectMapper O(Params, P); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index c6456b4113320..79739d8fc4309 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -439,6 +439,19 @@ struct SetVariableResponseBody { }; llvm::json::Value toJSON(const SetVariableResponseBody &); +struct ScopesArguments { + /// Retrieve the scopes for the stack frame identified by `frameId`. The + /// `frameId` must have been obtained in the current suspended state. See + /// 'Lifetime of Object References' in the Overview section for details. + uint64_t frameId; +}; +bool fromJSON(const llvm::json::Value &, ScopesArguments &, llvm::json::Path); + +struct ScopesResponseBody { + std::vector scopes; +}; +llvm::json::Value toJSON(const ScopesResponseBody &); + /// Arguments for `source` request. struct SourceArguments { /// Specifies the source content to load. Either `source.path` or diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index c9cab350f9f12..74f8f749abe4c 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -16,17 +16,18 @@ using namespace llvm; namespace lldb_dap::protocol { -bool fromJSON(const json::Value &Params, PresentationHint &PH, json::Path P) { +bool fromJSON(const json::Value &Params, Source::PresentationHint &PH, + json::Path P) { auto rawHint = Params.getAsString(); if (!rawHint) { P.report("expected a string"); return false; } - std::optional hint = - StringSwitch>(*rawHint) - .Case("normal", ePresentationHintNormal) - .Case("emphasize", ePresentationHintEmphasize) - .Case("deemphasize", ePresentationHintDeemphasize) + std::optional hint = + StringSwitch>(*rawHint) + .Case("normal", Source::ePresentationHintNormal) + .Case("emphasize", Source::ePresentationHintEmphasize) + .Case("deemphasize", Source::ePresentationHintDeemphasize) .Default(std::nullopt); if (!hint) { P.report("unexpected value"); @@ -42,14 +43,13 @@ bool fromJSON(const json::Value &Params, Source &S, json::Path P) { O.map("presentationHint", S.presentationHint) && O.map("sourceReference", S.sourceReference); } - -llvm::json::Value toJSON(PresentationHint hint) { +llvm::json::Value toJSON(Source::PresentationHint hint) { switch (hint) { - case ePresentationHintNormal: + case Source::ePresentationHintNormal: return "normal"; - case ePresentationHintEmphasize: + case Source::ePresentationHintEmphasize: return "emphasize"; - case ePresentationHintDeemphasize: + case Source::ePresentationHintDeemphasize: return "deemphasize"; } llvm_unreachable("unhandled presentation hint."); @@ -269,6 +269,55 @@ json::Value toJSON(const Capabilities &C) { return result; } +llvm::json::Value toJSON(const Scope &SC) { + llvm::json::Object result{{"name", SC.name}, + {"variablesReference", SC.variablesReference}, + {"expensive", SC.expensive}}; + + if (SC.presentationHint.has_value()) { + llvm::StringRef presentationHint; + switch (*SC.presentationHint) { + case Scope::ePresentationHintArguments: + presentationHint = "arguments"; + break; + case Scope::ePresentationHintLocals: + presentationHint = "locals"; + break; + case Scope::ePresentationHintRegisters: + presentationHint = "registers"; + break; + case Scope::ePresentationHintReturnValue: + presentationHint = "returnValue"; + break; + } + + result.insert({"presentationHint", presentationHint}); + } + + if (SC.namedVariables.has_value()) + result.insert({"namedVariables", SC.namedVariables}); + + if (SC.indexedVariables.has_value()) + result.insert({"indexedVariables", SC.indexedVariables}); + + if (SC.source.has_value()) + result.insert({"source", SC.source}); + + if (SC.line.has_value()) + result.insert({"line", SC.line}); + + if (SC.column.has_value()) + result.insert({"column", SC.column}); + + if (SC.endLine.has_value()) + result.insert({"endLine", SC.endLine}); + + if (SC.endColumn.has_value()) + result.insert({"endColumn", SC.endColumn}); + + return result; +} + bool fromJSON(const llvm::json::Value &Params, SteppingGranularity &SG, llvm::json::Path P) { auto raw_granularity = Params.getAsString(); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index d1e86b0897675..d1070d37e3ba3 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -271,17 +271,16 @@ struct Capabilities { }; llvm::json::Value toJSON(const Capabilities &); -enum PresentationHint : unsigned { - ePresentationHintNormal, - ePresentationHintEmphasize, - ePresentationHintDeemphasize, -}; -llvm::json::Value toJSON(PresentationHint hint); - /// A `Source` is a descriptor for source code. It is returned from the debug /// adapter as part of a `StackFrame` and it is used by clients when specifying /// breakpoints. struct Source { + enum PresentationHint : unsigned { + ePresentationHintNormal, + ePresentationHintEmphasize, + ePresentationHintDeemphasize, + }; + /// The short name of the source. Every source returned from the debug adapter /// has a name. When sending a source to the debug adapter this name is /// optional. @@ -305,9 +304,77 @@ struct Source { // unsupported keys: origin, sources, adapterData, checksums }; +llvm::json::Value toJSON(Source::PresentationHint); bool fromJSON(const llvm::json::Value &, Source &, llvm::json::Path); llvm::json::Value toJSON(const Source &); +/// A `Scope` is a named container for variables. Optionally a scope can map to +/// a source or a range within a source. +struct Scope { + enum PresentationHint : unsigned { + ePresentationHintArguments, + ePresentationHintLocals, + ePresentationHintRegisters, + ePresentationHintReturnValue + }; + /// Name of the scope such as 'Arguments', 'Locals', or 'Registers'. This + /// string is shown in the UI as is and can be translated. + //// + std::string name; + + /// A hint for how to present this scope in the UI. If this attribute is + /// missing, the scope is shown with a generic UI. + /// Values: + /// 'arguments': Scope contains method arguments. + /// 'locals': Scope contains local variables. + /// 'registers': Scope contains registers. Only a single `registers` scope + /// should be returned from a `scopes` request. + /// 'returnValue': Scope contains one or more return values. + /// etc. + std::optional presentationHint; + + /// The variables of this scope can be retrieved by passing the value of + /// `variablesReference` to the `variables` request as long as execution + /// remains suspended. See 'Lifetime of Object References' in the Overview + /// section for details. + //// + uint64_t variablesReference; + + /// The number of named variables in this scope. + /// The client can use this information to present the variables in a paged UI + /// and fetch them in chunks. + std::optional namedVariables; + + /// The number of indexed variables in this scope. + /// The client can use this information to present the variables in a paged UI + /// and fetch them in chunks. + std::optional indexedVariables; + + /// The source for this scope. + std::optional source; + + /// If true, the number of variables in this scope is large or expensive to + /// retrieve. + bool expensive; + + /// The start line of the range covered by this scope. + std::optional line; + + /// Start position of the range covered by the scope. It is measured in UTF-16 + /// code units and the client capability `columnsStartAt1` determines whether + /// it is 0- or 1-based. + std::optional column; + + /// The end line of the range covered by this scope. + std::optional endLine; + + /// End position of the range covered by the scope. It is measured in UTF-16 + /// code units and the client capability `columnsStartAt1` determines whether + /// it is 0- or 1-based. + std::optional endColumn; +}; +llvm::json::Value toJSON(const Scope &); + /// The granularity of one `step` in the stepping requests `next`, `stepIn`, /// `stepOut` and `stepBack`. enum SteppingGranularity : unsigned { >From 2165bfd9f949c50df123a7e0ac12efb5e31592e2 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Mon, 12 May 2025 20:33:33 +0100 Subject: [PATCH 2/5] [lldb][lldb-dap] review changes --- lldb/tools/lldb-dap/Protocol/ProtocolRequests.h | 2 +- lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index 79739d8fc4309..f8d6b6a8581ea 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -443,7 +443,7 @@ struct ScopesArguments { /// Retrieve the scopes for the stack frame identified by `frameId`. The /// `frameId` must have been obtained in the current suspended state. See /// 'Lifetime of Object References' in the Overview section for details. - uint64_t frameId; + uint64_t frameId = LLDB_INVALID_FRAME_ID; }; bool fromJSON(const llvm::json::Value &, ScopesArguments &, llvm::json::Path); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index d1070d37e3ba3..668c3d7682f3f 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -27,6 +27,8 @@ #include #include +#define LLDB_DAP_INVALID_VARRERF UINT64_MAX + namespace lldb_dap::protocol { /// An `ExceptionBreakpointsFilter` is shown in the UI as an filter option for @@ -338,7 +340,7 @@ struct Scope { /// remains suspended. See 'Lifetime of Object References' in the Overview /// section for details. //// - uint64_t variablesReference; + uint64_t variablesReference = LLDB_DAP_INVALID_VARRERF; /// The number of named variables in this scope. /// The client can use this information to present the variables in a paged UI @@ -355,7 +357,7 @@ struct Scope { /// If true, the number of variables in this scope is large or expensive to /// retrieve. - bool expensive; + bool expensive = false; /// The start line of the range covered by this scope. std::optional line; >From c3bffb542617bef10bb2cc814af9d8ec47ff12be Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Mon, 12 May 2025 20:36:21 +0100 Subject: [PATCH 3/5] [lldb][lldb-dap] review changes --- lldb/tools/lldb-dap/DAP.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index f66cb40451484..9065995f5d722 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -283,6 +283,8 @@ struct DAP { lldb::SBThread GetLLDBThread(const llvm::json::Object &arguments); lldb::SBFrame GetLLDBFrame(uint64_t frame_id); + /// TODO: remove this function when we finish migrating to the + /// new protocol types. lldb::SBFrame GetLLDBFrame(const llvm::json::Object &arguments); void PopulateExceptionBreakpoints(); >From 6fcf3c0089beccecd148676a0f3444d33f95d7c8 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Tue, 13 May 2025 12:03:02 +0100 Subject: [PATCH 4/5] [lldb][lldb-dap] add review changes --- .../lldb-dap/Handler/ScopesRequestHandler.cpp | 4 +- .../tools/lldb-dap/Protocol/ProtocolTypes.cpp | 56 +++++++++++++++---- lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 17 +++--- lldb/unittests/DAP/ProtocolTypesTest.cpp | 43 +++++++++++++- 4 files changed, 100 insertions(+), 20 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp index d9dd29f7269f2..e8ae25469d82f 100644 --- a/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp @@ -41,9 +41,9 @@ static Scope CreateScope(const llvm::StringRef name, int64_t variablesReference, // as the locals scope will not be expanded. It becomes more annoying when // the scope has arguments, return_value and locals. if (variablesReference == VARREF_LOCALS) - scope.presentationHint = Scope::ePresentationHintLocals; + scope.presentationHint = Scope::eScopePresentationHintLocals; else if (variablesReference == VARREF_REGS) - scope.presentationHint = Scope::ePresentationHintRegisters; + scope.presentationHint = Scope::eScopePresentationHintRegisters; scope.variablesReference = variablesReference; scope.namedVariables = namedVariables; diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index 74f8f749abe4c..09d383311a242 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -25,9 +25,9 @@ bool fromJSON(const json::Value &Params, Source::PresentationHint &PH, } std::optional hint = StringSwitch>(*rawHint) - .Case("normal", Source::ePresentationHintNormal) - .Case("emphasize", Source::ePresentationHintEmphasize) - .Case("deemphasize", Source::ePresentationHintDeemphasize) + .Case("normal", Source::eSourcePresentationHintNormal) + .Case("emphasize", Source::eSourcePresentationHintEmphasize) + .Case("deemphasize", Source::eSourcePresentationHintDeemphasize) .Default(std::nullopt); if (!hint) { P.report("unexpected value"); @@ -43,13 +43,14 @@ bool fromJSON(const json::Value &Params, Source &S, json::Path P) { O.map("presentationHint", S.presentationHint) && O.map("sourceReference", S.sourceReference); } + llvm::json::Value toJSON(Source::PresentationHint hint) { switch (hint) { - case Source::ePresentationHintNormal: + case Source::eSourcePresentationHintNormal: return "normal"; - case Source::ePresentationHintEmphasize: + case Source::eSourcePresentationHintEmphasize: return "emphasize"; - case Source::ePresentationHintDeemphasize: + case Source::eSourcePresentationHintDeemphasize: return "deemphasize"; } llvm_unreachable("unhandled presentation hint."); @@ -269,6 +270,41 @@ json::Value toJSON(const Capabilities &C) { return result; } +bool fromJSON(const json::Value &Params, Scope::PresentationHint &PH, + json::Path P) { + auto rawHint = Params.getAsString(); + if (!rawHint) { + P.report("expected a string"); + return false; + } + const std::optional hint = + StringSwitch>(*rawHint) + .Case("arguments", Scope::eScopePresentationHintArguments) + .Case("locals", Scope::eScopePresentationHintLocals) + .Case("registers", Scope::eScopePresentationHintRegisters) + .Case("returnValue", Scope::eScopePresentationHintReturnValue) + .Default(std::nullopt); + if (!hint) { + P.report("unexpected value"); + return false; + } + PH = *hint; + return true; +} + +bool fromJSON(const json::Value &Params, Scope &S, json::Path P) { + json::ObjectMapper O(Params, P); + return O && O.map("name", S.name) && + O.mapOptional("presentationHint", S.presentationHint) && + O.map("variablesReference", S.variablesReference) && + O.mapOptional("namedVariables", S.namedVariables) && + O.map("indexedVariables", S.indexedVariables) && + O.mapOptional("source", S.source) && O.map("expensive", S.expensive) && + O.mapOptional("line", S.line) && O.mapOptional("column", S.column) && + O.mapOptional("endLine", S.endLine) && + O.mapOptional("endColumn", S.endColumn); +} + llvm::json::Value toJSON(const Scope &SC) { llvm::json::Object result{{"name", SC.name}, {"variablesReference", SC.variablesReference}, @@ -277,16 +313,16 @@ llvm::json::Value toJSON(const Scope &SC) { if (SC.presentationHint.has_value()) { llvm::StringRef presentationHint; switch (*SC.presentationHint) { - case Scope::ePresentationHintArguments: + case Scope::eScopePresentationHintArguments: presentationHint = "arguments"; break; - case Scope::ePresentationHintLocals: + case Scope::eScopePresentationHintLocals: presentationHint = "locals"; break; - case Scope::ePresentationHintRegisters: + case Scope::eScopePresentationHintRegisters: presentationHint = "registers"; break; - case Scope::ePresentationHintReturnValue: + case Scope::eScopePresentationHintReturnValue: presentationHint = "returnValue"; break; } diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index 668c3d7682f3f..b42c2699b6248 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -278,9 +278,9 @@ llvm::json::Value toJSON(const Capabilities &); /// breakpoints. struct Source { enum PresentationHint : unsigned { - ePresentationHintNormal, - ePresentationHintEmphasize, - ePresentationHintDeemphasize, + eSourcePresentationHintNormal, + eSourcePresentationHintEmphasize, + eSourcePresentationHintDeemphasize, }; /// The short name of the source. Every source returned from the debug adapter @@ -314,10 +314,10 @@ llvm::json::Value toJSON(const Source &); /// a source or a range within a source. struct Scope { enum PresentationHint : unsigned { - ePresentationHintArguments, - ePresentationHintLocals, - ePresentationHintRegisters, - ePresentationHintReturnValue + eScopePresentationHintArguments, + eScopePresentationHintLocals, + eScopePresentationHintRegisters, + eScopePresentationHintReturnValue }; /// Name of the scope such as 'Arguments', 'Locals', or 'Registers'. This /// string is shown in the UI as is and can be translated. @@ -375,6 +375,9 @@ struct Scope { /// it is 0- or 1-based. std::optional endColumn; }; +bool fromJSON(const llvm::json::Value &Params, Scope::PresentationHint &PH, + llvm::json::Path); +bool fromJSON(const llvm::json::Value &, Scope &, llvm::json::Path); llvm::json::Value toJSON(const Scope &); /// The granularity of one `step` in the stepping requests `next`, `stepIn`, diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp index fa46816ca4a10..f330beef6e2a5 100644 --- a/lldb/unittests/DAP/ProtocolTypesTest.cpp +++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp @@ -50,7 +50,7 @@ TEST(ProtocolTypesTest, Source) { source.name = "testName"; source.path = "/path/to/source"; source.sourceReference = 12345; - source.presentationHint = ePresentationHintEmphasize; + source.presentationHint = Source::eSourcePresentationHintEmphasize; llvm::Expected deserialized_source = roundtrip(source); ASSERT_THAT_EXPECTED(deserialized_source, llvm::Succeeded()); @@ -60,3 +60,44 @@ TEST(ProtocolTypesTest, Source) { EXPECT_EQ(source.sourceReference, deserialized_source->sourceReference); EXPECT_EQ(source.presentationHint, deserialized_source->presentationHint); } + +TEST(ProtocolTypesTest, Scope) { + Scope scope; + scope.name = "Locals"; + scope.presentationHint = Scope::eScopePresentationHintLocals; + scope.variablesReference = 1; + scope.namedVariables = 2; + scope.indexedVariables = std::nullopt; + scope.expensive = false; + scope.line = 2; + scope.column = 3; + scope.endLine = 10; + scope.endColumn = 20; + + scope.source = + Source{.name = "testName", + .path = "/path/to/source", + .sourceReference = 12345, + .presentationHint = Source::eSourcePresentationHintNormal}; + + llvm::Expected deserialized_scope = roundtrip(scope); + ASSERT_THAT_EXPECTED(deserialized_scope, llvm::Succeeded()); + EXPECT_EQ(scope.name, deserialized_scope->name); + EXPECT_EQ(scope.presentationHint, deserialized_scope->presentationHint); + EXPECT_EQ(scope.variablesReference, deserialized_scope->variablesReference); + EXPECT_EQ(scope.namedVariables, deserialized_scope->namedVariables); + EXPECT_EQ(scope.indexedVariables, deserialized_scope->indexedVariables); + EXPECT_EQ(scope.expensive, deserialized_scope->expensive); + EXPECT_EQ(scope.line, deserialized_scope->line); + EXPECT_EQ(scope.column, deserialized_scope->column); + EXPECT_EQ(scope.endLine, deserialized_scope->endLine); + EXPECT_EQ(scope.endColumn, deserialized_scope->endColumn); + + EXPECT_THAT(deserialized_scope->source.has_value(), true); + const Source &source = scope.source.value(); + const Source &deserialized_source = deserialized_scope->source.value(); + + EXPECT_EQ(source.path, deserialized_source.path); + EXPECT_EQ(source.sourceReference, deserialized_source.sourceReference); + EXPECT_EQ(source.presentationHint, deserialized_source.presentationHint); +} >From 1ee076ccadf4c3c619eaf9479f70e53cc259c2f7 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Tue, 13 May 2025 12:12:22 +0100 Subject: [PATCH 5/5] [lldb][lldb-dap] clarify the todo. --- lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp index e8ae25469d82f..aaad0e20f9c21 100644 --- a/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp @@ -36,10 +36,11 @@ static Scope CreateScope(const llvm::StringRef name, int64_t variablesReference, // TODO: Support "arguments" and "return value" scope. // At the moment lldb-dap includes the arguments and return_value into the - // "locals" scope. add presentation hint; + // "locals" scope. // vscode only expands the first non-expensive scope, this causes friction - // as the locals scope will not be expanded. It becomes more annoying when - // the scope has arguments, return_value and locals. + // if we add the arguments above the local scope as the locals scope will not + // be expanded if we enter a function with arguments. It becomes more + // annoying when the scope has arguments, return_value and locals. if (variablesReference == VARREF_LOCALS) scope.presentationHint = Scope::eScopePresentationHintLocals; else if (variablesReference == VARREF_REGS) From lldb-commits at lists.llvm.org Tue May 13 04:16:11 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Tue, 13 May 2025 04:16:11 -0700 (PDT) Subject: [Lldb-commits] [lldb] Reapply "[lldb] Inherit DuplicateFileAction(HANDLE, HANDLE) handles on windows (#137978)" (PR #138896) In-Reply-To: Message-ID: <682329fb.a70a0220.1d42c7.0d97@mx.google.com> labath wrote: Thanks. I think I can fix that. Let me whip something up. https://github.com/llvm/llvm-project/pull/138896 From lldb-commits at lists.llvm.org Tue May 13 04:30:17 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Tue, 13 May 2025 04:30:17 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Fix compilation errors from #138896 (PR #139711) Message-ID: https://github.com/labath created https://github.com/llvm/llvm-project/pull/139711 - s/size_t/SIZE_T to match the windows API - case HANDLE to int64_t to avoid cast-to-int-of-different-size errors/warnings Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Tue May 13 04:30:45 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Tue, 13 May 2025 04:30:45 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Fix compilation errors from #138896 (PR #139711) In-Reply-To: Message-ID: <68232d65.620a0220.1ec2f3.241f@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Pavel Labath (labath)
Changes - s/size_t/SIZE_T to match the windows API - case HANDLE to int64_t to avoid cast-to-int-of-different-size errors/warnings --- Full diff: https://github.com/llvm/llvm-project/pull/139711.diff 3 Files Affected: - (modified) lldb/source/Host/windows/ProcessLauncherWindows.cpp (+1-1) - (modified) lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp (+1-1) - (modified) lldb/tools/lldb-server/lldb-platform.cpp (+2-2) ``````````diff diff --git a/lldb/source/Host/windows/ProcessLauncherWindows.cpp b/lldb/source/Host/windows/ProcessLauncherWindows.cpp index bc35667ea9a23..f5adadaf061bf 100644 --- a/lldb/source/Host/windows/ProcessLauncherWindows.cpp +++ b/lldb/source/Host/windows/ProcessLauncherWindows.cpp @@ -99,7 +99,7 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, if (startupinfo.hStdOutput) inherited_handles.push_back(startupinfo.hStdOutput); - size_t attributelist_size = 0; + SIZE_T attributelist_size = 0; InitializeProcThreadAttributeList(/*lpAttributeList=*/nullptr, /*dwAttributeCount=*/1, /*dwFlags=*/0, &attributelist_size); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 332b9255f226f..b37b35d3a50f8 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -924,7 +924,7 @@ Status GDBRemoteCommunication::StartDebugserverProcess( debugserver_args.AppendArgument(fd_arg.GetString()); // Send "pass_comm_fd" down to the inferior so it can use it to // communicate back with this process. Ignored on Windows. - launch_info.AppendDuplicateFileAction((int)pass_comm_fd, (int)pass_comm_fd); + launch_info.AppendDuplicateFileAction((int64_t)pass_comm_fd, (int64_t)pass_comm_fd); } // use native registers, not the GDB registers diff --git a/lldb/tools/lldb-server/lldb-platform.cpp b/lldb/tools/lldb-server/lldb-platform.cpp index 5b0a8ade01025..37ec8455c63a7 100644 --- a/lldb/tools/lldb-server/lldb-platform.cpp +++ b/lldb/tools/lldb-server/lldb-platform.cpp @@ -274,8 +274,8 @@ static Status spawn_process(const char *progname, const FileSpec &prog, self_args.AppendArgument(llvm::StringRef("platform")); self_args.AppendArgument(llvm::StringRef("--child-platform-fd")); self_args.AppendArgument(llvm::to_string(shared_socket.GetSendableFD())); - launch_info.AppendDuplicateFileAction((int)shared_socket.GetSendableFD(), - (int)shared_socket.GetSendableFD()); + launch_info.AppendDuplicateFileAction((int64_t)shared_socket.GetSendableFD(), + (int64_t)shared_socket.GetSendableFD()); if (gdb_port) { self_args.AppendArgument(llvm::StringRef("--gdbserver-port")); self_args.AppendArgument(llvm::to_string(gdb_port)); ``````````
https://github.com/llvm/llvm-project/pull/139711 From lldb-commits at lists.llvm.org Tue May 13 04:50:24 2025 From: lldb-commits at lists.llvm.org (=?UTF-8?Q?Martin_Storsj=C3=B6?= via lldb-commits) Date: Tue, 13 May 2025 04:50:24 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Fix compilation errors from #138896 (PR #139711) In-Reply-To: Message-ID: <68233200.050a0220.21da8b.2381@mx.google.com> https://github.com/mstorsjo approved this pull request. LGTM, thanks! I can confirm that this fixes compilation on mingw targets, on both 32 and 64 bit. https://github.com/llvm/llvm-project/pull/139711 From lldb-commits at lists.llvm.org Tue May 13 06:05:56 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Tue, 13 May 2025 06:05:56 -0700 (PDT) Subject: [Lldb-commits] [lldb] 89826f0 - [lldb] Fix compilation errors from #138896 (#139711) Message-ID: <682343b4.170a0220.271f4a.317f@mx.google.com> Author: Pavel Labath Date: 2025-05-13T15:05:53+02:00 New Revision: 89826f04589af9d309319b3651b609fdd8978631 URL: https://github.com/llvm/llvm-project/commit/89826f04589af9d309319b3651b609fdd8978631 DIFF: https://github.com/llvm/llvm-project/commit/89826f04589af9d309319b3651b609fdd8978631.diff LOG: [lldb] Fix compilation errors from #138896 (#139711) - s/size_t/SIZE_T to match the windows API - case HANDLE to int64_t to avoid cast-to-int-of-different-size errors/warnings Added: Modified: lldb/source/Host/windows/ProcessLauncherWindows.cpp lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp lldb/tools/lldb-server/lldb-platform.cpp Removed: ################################################################################ diff --git a/lldb/source/Host/windows/ProcessLauncherWindows.cpp b/lldb/source/Host/windows/ProcessLauncherWindows.cpp index bc35667ea9a23..f5adadaf061bf 100644 --- a/lldb/source/Host/windows/ProcessLauncherWindows.cpp +++ b/lldb/source/Host/windows/ProcessLauncherWindows.cpp @@ -99,7 +99,7 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, if (startupinfo.hStdOutput) inherited_handles.push_back(startupinfo.hStdOutput); - size_t attributelist_size = 0; + SIZE_T attributelist_size = 0; InitializeProcThreadAttributeList(/*lpAttributeList=*/nullptr, /*dwAttributeCount=*/1, /*dwFlags=*/0, &attributelist_size); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 332b9255f226f..2aea7c6b781d7 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -924,7 +924,8 @@ Status GDBRemoteCommunication::StartDebugserverProcess( debugserver_args.AppendArgument(fd_arg.GetString()); // Send "pass_comm_fd" down to the inferior so it can use it to // communicate back with this process. Ignored on Windows. - launch_info.AppendDuplicateFileAction((int)pass_comm_fd, (int)pass_comm_fd); + launch_info.AppendDuplicateFileAction((int64_t)pass_comm_fd, + (int64_t)pass_comm_fd); } // use native registers, not the GDB registers diff --git a/lldb/tools/lldb-server/lldb-platform.cpp b/lldb/tools/lldb-server/lldb-platform.cpp index 5b0a8ade01025..37ec8455c63a7 100644 --- a/lldb/tools/lldb-server/lldb-platform.cpp +++ b/lldb/tools/lldb-server/lldb-platform.cpp @@ -274,8 +274,8 @@ static Status spawn_process(const char *progname, const FileSpec &prog, self_args.AppendArgument(llvm::StringRef("platform")); self_args.AppendArgument(llvm::StringRef("--child-platform-fd")); self_args.AppendArgument(llvm::to_string(shared_socket.GetSendableFD())); - launch_info.AppendDuplicateFileAction((int)shared_socket.GetSendableFD(), - (int)shared_socket.GetSendableFD()); + launch_info.AppendDuplicateFileAction((int64_t)shared_socket.GetSendableFD(), + (int64_t)shared_socket.GetSendableFD()); if (gdb_port) { self_args.AppendArgument(llvm::StringRef("--gdbserver-port")); self_args.AppendArgument(llvm::to_string(gdb_port)); From lldb-commits at lists.llvm.org Tue May 13 06:05:59 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Tue, 13 May 2025 06:05:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Fix compilation errors from #138896 (PR #139711) In-Reply-To: Message-ID: <682343b7.630a0220.1f5179.85c8@mx.google.com> https://github.com/labath closed https://github.com/llvm/llvm-project/pull/139711 From lldb-commits at lists.llvm.org Tue May 13 08:47:20 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Tue, 13 May 2025 08:47:20 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Move lldb_enable_attach from test_common to a separate header (PR #139550) In-Reply-To: Message-ID: <68236988.170a0220.98c01.9600@mx.google.com> https://github.com/JDevlieghere approved this pull request. https://github.com/llvm/llvm-project/pull/139550 From lldb-commits at lists.llvm.org Tue May 13 08:52:27 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Tue, 13 May 2025 08:52:27 -0700 (PDT) Subject: [Lldb-commits] [lldb] 91ea494 - [lldb] Move lldb_enable_attach from test_common to a separate header (#139550) Message-ID: <68236abb.170a0220.2598dd.84e8@mx.google.com> Author: Pavel Labath Date: 2025-05-13T17:52:23+02:00 New Revision: 91ea49499325aeff8426135721b1bd432e5b7780 URL: https://github.com/llvm/llvm-project/commit/91ea49499325aeff8426135721b1bd432e5b7780 DIFF: https://github.com/llvm/llvm-project/commit/91ea49499325aeff8426135721b1bd432e5b7780.diff LOG: [lldb] Move lldb_enable_attach from test_common to a separate header (#139550) test_common is force-included into every compilation, which causes problems when we're compiling assembly code, as we were in #138805. This avoids that as we can include the header only when it's needed. Added: lldb/packages/Python/lldbsuite/test/make/attach.h Modified: lldb/packages/Python/lldbsuite/test/make/test_common.h lldb/test/API/commands/process/attach-resume/main.cpp lldb/test/API/commands/process/attach/main.cpp lldb/test/API/commands/process/detach-resumes/main.cpp lldb/test/API/commands/register/register/register_command/main.cpp lldb/test/API/driver/batch_mode/main.c lldb/test/API/functionalities/deleted-executable/main.cpp lldb/test/API/functionalities/load_after_attach/main.cpp lldb/test/API/functionalities/process_group/main.c lldb/test/API/functionalities/thread/create_after_attach/main.cpp lldb/test/API/iohandler/completion/main.c lldb/test/API/python_api/hello_world/main.c lldb/test/API/tools/lldb-dap/attach/main.c lldb/test/API/tools/lldb-dap/disconnect/main.cpp lldb/test/API/tools/lldb-server/attach-wait/shim.cpp lldb/test/API/tools/lldb-server/main.cpp Removed: ################################################################################ diff --git a/lldb/packages/Python/lldbsuite/test/make/attach.h b/lldb/packages/Python/lldbsuite/test/make/attach.h new file mode 100644 index 0000000000000..decd3ea986a4b --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/make/attach.h @@ -0,0 +1,34 @@ +#ifndef LLDB_TEST_ATTACH_H +#define LLDB_TEST_ATTACH_H + +// On some systems (e.g., some versions of linux) it is not possible to attach +// to a process without it giving us special permissions. This defines the +// lldb_enable_attach macro, which should perform any such actions, if needed by +// the platform. +#if defined(__linux__) +#include + +// Android API <= 16 does not have these defined. +#ifndef PR_SET_PTRACER +#define PR_SET_PTRACER 0x59616d61 +#endif +#ifndef PR_SET_PTRACER_ANY +#define PR_SET_PTRACER_ANY ((unsigned long)-1) +#endif + +// For now we execute on best effort basis. If this fails for some reason, so +// be it. +#define lldb_enable_attach() \ + do { \ + const int prctl_result = \ + prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0); \ + (void)prctl_result; \ + } while (0) + +#else // not linux + +#define lldb_enable_attach() + +#endif // defined(__linux__) + +#endif // LLDB_TEST_ATTACH_H diff --git a/lldb/packages/Python/lldbsuite/test/make/test_common.h b/lldb/packages/Python/lldbsuite/test/make/test_common.h index aa8960e1c0aea..5082e41987020 100644 --- a/lldb/packages/Python/lldbsuite/test/make/test_common.h +++ b/lldb/packages/Python/lldbsuite/test/make/test_common.h @@ -20,33 +20,3 @@ #else #define LLVM_PRETTY_FUNCTION LLVM_PRETTY_FUNCTION #endif - - -// On some systems (e.g., some versions of linux) it is not possible to attach to a process -// without it giving us special permissions. This defines the lldb_enable_attach macro, which -// should perform any such actions, if needed by the platform. This is a macro instead of a -// function to avoid the need for complex linking of the test programs. -#if defined(__linux__) -#include - -// Android API <= 16 does not have these defined. -#ifndef PR_SET_PTRACER -#define PR_SET_PTRACER 0x59616d61 -#endif -#ifndef PR_SET_PTRACER_ANY -#define PR_SET_PTRACER_ANY ((unsigned long)-1) -#endif - -// For now we execute on best effort basis. If this fails for some reason, so be it. -#define lldb_enable_attach() \ - do \ - { \ - const int prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0); \ - (void)prctl_result; \ - } while (0) - -#else // not linux - -#define lldb_enable_attach() - -#endif diff --git a/lldb/test/API/commands/process/attach-resume/main.cpp b/lldb/test/API/commands/process/attach-resume/main.cpp index 82aad70eed560..3fe54d1e45601 100644 --- a/lldb/test/API/commands/process/attach-resume/main.cpp +++ b/lldb/test/API/commands/process/attach-resume/main.cpp @@ -1,7 +1,7 @@ -#include -#include - +#include "attach.h" #include +#include +#include #include volatile bool debugger_flag = true; // The debugger will flip this to false diff --git a/lldb/test/API/commands/process/attach/main.cpp b/lldb/test/API/commands/process/attach/main.cpp index b4ed48fade306..034e80ed5f2b3 100644 --- a/lldb/test/API/commands/process/attach/main.cpp +++ b/lldb/test/API/commands/process/attach/main.cpp @@ -1,6 +1,6 @@ -#include - +#include "attach.h" #include +#include #include volatile int g_val = 12345; diff --git a/lldb/test/API/commands/process/detach-resumes/main.cpp b/lldb/test/API/commands/process/detach-resumes/main.cpp index e8050fef2c385..9005c0a95847b 100644 --- a/lldb/test/API/commands/process/detach-resumes/main.cpp +++ b/lldb/test/API/commands/process/detach-resumes/main.cpp @@ -1,8 +1,9 @@ +#include "attach.h" #include "pseudo_barrier.h" #include +#include #include #include -#include #include #include diff --git a/lldb/test/API/commands/register/register/register_command/main.cpp b/lldb/test/API/commands/register/register/register_command/main.cpp index 860dfef0b3b97..5950c19f82967 100644 --- a/lldb/test/API/commands/register/register/register_command/main.cpp +++ b/lldb/test/API/commands/register/register/register_command/main.cpp @@ -1,6 +1,6 @@ -#include - +#include "attach.h" #include +#include #include long double outermost_return_long_double (long double my_long_double); diff --git a/lldb/test/API/driver/batch_mode/main.c b/lldb/test/API/driver/batch_mode/main.c index c85a0f272d2c1..4527c144f96fc 100644 --- a/lldb/test/API/driver/batch_mode/main.c +++ b/lldb/test/API/driver/batch_mode/main.c @@ -1,3 +1,4 @@ +#include "attach.h" #include #include #include diff --git a/lldb/test/API/functionalities/deleted-executable/main.cpp b/lldb/test/API/functionalities/deleted-executable/main.cpp index af00ac263cc1b..1536c6cf9e4a7 100644 --- a/lldb/test/API/functionalities/deleted-executable/main.cpp +++ b/lldb/test/API/functionalities/deleted-executable/main.cpp @@ -1,3 +1,4 @@ +#include "attach.h" #include #include #include diff --git a/lldb/test/API/functionalities/load_after_attach/main.cpp b/lldb/test/API/functionalities/load_after_attach/main.cpp index 96012a126001a..60bfefb72bb11 100644 --- a/lldb/test/API/functionalities/load_after_attach/main.cpp +++ b/lldb/test/API/functionalities/load_after_attach/main.cpp @@ -1,9 +1,10 @@ +#include "attach.h" #include "dylib.h" #include -#include -#include #include +#include #include +#include int main(int argc, char* argv[]) { lldb_enable_attach(); diff --git a/lldb/test/API/functionalities/process_group/main.c b/lldb/test/API/functionalities/process_group/main.c index 7e986bbac65de..b4d5abc58169c 100644 --- a/lldb/test/API/functionalities/process_group/main.c +++ b/lldb/test/API/functionalities/process_group/main.c @@ -1,6 +1,7 @@ +#include "attach.h" #include -#include #include +#include volatile int release_child_flag = 0; diff --git a/lldb/test/API/functionalities/thread/create_after_attach/main.cpp b/lldb/test/API/functionalities/thread/create_after_attach/main.cpp index d8f06e55a2dd9..d99fb05f08315 100644 --- a/lldb/test/API/functionalities/thread/create_after_attach/main.cpp +++ b/lldb/test/API/functionalities/thread/create_after_attach/main.cpp @@ -1,5 +1,6 @@ -#include +#include "attach.h" #include +#include #include using std::chrono::microseconds; diff --git a/lldb/test/API/iohandler/completion/main.c b/lldb/test/API/iohandler/completion/main.c index 03350dd8299a6..6dd3616c1ae40 100644 --- a/lldb/test/API/iohandler/completion/main.c +++ b/lldb/test/API/iohandler/completion/main.c @@ -1,5 +1,4 @@ int main(int argc, char **argv) { - lldb_enable_attach(); int to_complete = 0; return to_complete; } diff --git a/lldb/test/API/python_api/hello_world/main.c b/lldb/test/API/python_api/hello_world/main.c index c516f923614f1..865baa4f4ed11 100644 --- a/lldb/test/API/python_api/hello_world/main.c +++ b/lldb/test/API/python_api/hello_world/main.c @@ -1,3 +1,4 @@ +#include "attach.h" #include #ifdef _MSC_VER #include diff --git a/lldb/test/API/tools/lldb-dap/attach/main.c b/lldb/test/API/tools/lldb-dap/attach/main.c index c0b128afe445a..f56d5d53afa05 100644 --- a/lldb/test/API/tools/lldb-dap/attach/main.c +++ b/lldb/test/API/tools/lldb-dap/attach/main.c @@ -1,3 +1,4 @@ +#include "attach.h" #include #ifdef _WIN32 #include diff --git a/lldb/test/API/tools/lldb-dap/disconnect/main.cpp b/lldb/test/API/tools/lldb-dap/disconnect/main.cpp index d3d7a4b7338a8..ca9610da4566a 100644 --- a/lldb/test/API/tools/lldb-dap/disconnect/main.cpp +++ b/lldb/test/API/tools/lldb-dap/disconnect/main.cpp @@ -1,3 +1,4 @@ +#include "attach.h" #include #include #include diff --git a/lldb/test/API/tools/lldb-server/attach-wait/shim.cpp b/lldb/test/API/tools/lldb-server/attach-wait/shim.cpp index 60d0ba3753026..5b8bcc97e3e8f 100644 --- a/lldb/test/API/tools/lldb-server/attach-wait/shim.cpp +++ b/lldb/test/API/tools/lldb-server/attach-wait/shim.cpp @@ -1,5 +1,6 @@ -#include +#include "attach.h" #include +#include int main(int argc, char *argv[]) { lldb_enable_attach(); diff --git a/lldb/test/API/tools/lldb-server/main.cpp b/lldb/test/API/tools/lldb-server/main.cpp index c661f5b4e82c4..0e9323cce88cf 100644 --- a/lldb/test/API/tools/lldb-server/main.cpp +++ b/lldb/test/API/tools/lldb-server/main.cpp @@ -1,3 +1,4 @@ +#include "attach.h" #include #include #include From lldb-commits at lists.llvm.org Tue May 13 08:52:30 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Tue, 13 May 2025 08:52:30 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Move lldb_enable_attach from test_common to a separate header (PR #139550) In-Reply-To: Message-ID: <68236abe.170a0220.cf2c4.c339@mx.google.com> https://github.com/labath closed https://github.com/llvm/llvm-project/pull/139550 From lldb-commits at lists.llvm.org Tue May 13 08:58:49 2025 From: lldb-commits at lists.llvm.org (Kazu Hirata via lldb-commits) Date: Tue, 13 May 2025 08:58:49 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use llvm::is_contained (NFC) (PR #139758) Message-ID: https://github.com/kazutakahirata created https://github.com/llvm/llvm-project/pull/139758 None >From dbe2a85661292455f0c6c141bb6d61d938212cc6 Mon Sep 17 00:00:00 2001 From: Kazu Hirata Date: Tue, 13 May 2025 08:56:44 -0700 Subject: [PATCH] [lldb] Use llvm::is_contained (NFC) --- lldb/tools/lldb-dap/DAP.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 4feca1253be20..51f9da854f4b6 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1194,8 +1194,7 @@ bool SendEventRequestHandler::DoExecute(lldb::SBDebugger debugger, "exited", "initialize", "loadedSource", "module", "process", "stopped", "terminated", "thread"}; - if (std::find(internal_events.begin(), internal_events.end(), name) != - std::end(internal_events)) { + if (llvm::is_contained(internal_events, name)) { std::string msg = llvm::formatv("Invalid use of lldb-dap send-event, event \"{0}\" " "should be handled by lldb-dap internally.", From lldb-commits at lists.llvm.org Tue May 13 08:59:29 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Tue, 13 May 2025 08:59:29 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use llvm::is_contained (NFC) (PR #139758) In-Reply-To: Message-ID: <68236c61.170a0220.b6a2b.abbe@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Kazu Hirata (kazutakahirata)
Changes --- Full diff: https://github.com/llvm/llvm-project/pull/139758.diff 1 Files Affected: - (modified) lldb/tools/lldb-dap/DAP.cpp (+1-2) ``````````diff diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 4feca1253be20..51f9da854f4b6 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1194,8 +1194,7 @@ bool SendEventRequestHandler::DoExecute(lldb::SBDebugger debugger, "exited", "initialize", "loadedSource", "module", "process", "stopped", "terminated", "thread"}; - if (std::find(internal_events.begin(), internal_events.end(), name) != - std::end(internal_events)) { + if (llvm::is_contained(internal_events, name)) { std::string msg = llvm::formatv("Invalid use of lldb-dap send-event, event \"{0}\" " "should be handled by lldb-dap internally.", ``````````
https://github.com/llvm/llvm-project/pull/139758 From lldb-commits at lists.llvm.org Tue May 13 09:14:16 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Tue, 13 May 2025 09:14:16 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Refactor lldb-dap event handling. (PR #139669) In-Reply-To: Message-ID: <68236fd8.170a0220.10e50c.cbac@mx.google.com> labath wrote: > I can split out some of the type fixes and some other changes I ended up lumping in here. That would be great. Thanks. > This isn't really a NFC because this is forcing some things to be serial that were previously not serial. We previously could trigger an event in the middle of a request handler and now we cannot. That forced some tests to change behavior slightly to figure out some synchronization points in tests. I believe you, but I don't understand. Since this restricts the set of possible message orderings (does it?), I would naively expect that a test which worked previously (with the wider set of orderings) would continue to work afterwards. The only way I can imagine this not being true is if the tests weren't 100% correct (i.e., they were flaky), but whereas previously the "bad" case would happen 0.1% of the time, this patch now makes it the 100% case. And it's easier to make the test always expect the (previously) bad case than it is to accept all of the technically legal orderings. Is that's what happening? Maybe an example would help... > Right now, I'm not actually using any read objects, just using the `MainLoop` to handle dispatching events. I think we can't use the MainLoop for reading from `stdin` on Windows yet. If it did work with `stdin` on Windows then we could use `RegisterReadObject` for handling events and remove a thread. Yeah, that unfortunately doesn't work right now. I would like to make that work one day, but my priority right now is for making it work with pipes (insomuch as you can call this a priority). https://github.com/llvm/llvm-project/pull/139669 From lldb-commits at lists.llvm.org Tue May 13 10:34:45 2025 From: lldb-commits at lists.llvm.org (Alex Langford via lldb-commits) Date: Tue, 13 May 2025 10:34:45 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use std:::string::find with std::string_view (NFC) (PR #139679) In-Reply-To: Message-ID: <682382b5.170a0220.37d80b.d844@mx.google.com> https://github.com/bulbazord approved this pull request. https://github.com/llvm/llvm-project/pull/139679 From lldb-commits at lists.llvm.org Tue May 13 11:09:31 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Tue, 13 May 2025 11:09:31 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Refactor lldb-dap event handling. (PR #139669) In-Reply-To: Message-ID: <68238adb.630a0220.9e92c.7faa@mx.google.com> ashgti wrote: > I believe you, but I don't understand. Since this restricts the set of possible message orderings (does it?), I would naively expect that a test which worked previously (with the wider set of orderings) would continue to work afterwards. > > The only way I can imagine this not being true is if the tests weren't 100% correct (i.e., they were flaky), but whereas previously the "bad" case would happen 0.1% of the time, this patch now makes it the 100% case. And it's easier to make the test always expect the (previously) bad case than it is to accept all of the technically legal orderings. Is that's what happening? Maybe an example would help... I think our tests are not fully specifying their expected state. For example, lldb/test/API/tools/lldb-dap/console/TestDAP_console.py `TestDAP_console.test_diagnositcs` was performing an evaluate and then using `get_important` to fetch output events with category 'important'. With the change, the `important` output was always coming after the request was handled. I updated the test to use a `self.collect_important` instead of `get_important`. Previously, this could have been emitted while the request was being handled, but now the output would only ever be emitted after the request handler is finished. https://github.com/llvm/llvm-project/pull/139669 From lldb-commits at lists.llvm.org Tue May 13 11:13:24 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Tue, 13 May 2025 11:13:24 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for ColumnDescriptor, BreakpointMode and Breakpoint (PR #139627) In-Reply-To: Message-ID: <68238bc4.170a0220.e301c.e152@mx.google.com> JDevlieghere wrote: low-priority ping (I'm doing this in the background and dealign with stacked PRs is a nuisance) https://github.com/llvm/llvm-project/pull/139627 From lldb-commits at lists.llvm.org Tue May 13 11:33:08 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Tue, 13 May 2025 11:33:08 -0700 (PDT) Subject: [Lldb-commits] [lldb] Support stepping through Darwin "branch islands" (PR #139301) In-Reply-To: Message-ID: <68239064.170a0220.8440c.cb8a@mx.google.com> https://github.com/jimingham updated https://github.com/llvm/llvm-project/pull/139301 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Tue May 13 11:33:21 2025 From: lldb-commits at lists.llvm.org (Chelsea Cassanova via lldb-commits) Date: Tue, 13 May 2025 11:33:21 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream lldb-rpc-gen tool (PR #138031) In-Reply-To: Message-ID: <68239071.170a0220.103b38.fe22@mx.google.com> ================ @@ -0,0 +1,535 @@ +//===-- RPCCommon.cpp -----------------------------------------------------===// +// +// 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 "RPCCommon.h" + +#include "clang/AST/AST.h" +#include "clang/AST/Mangle.h" +#include "clang/Lex/Lexer.h" + +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +// We intentionally do not generate some classes because they are currently +// inconvenient, they aren't really used by most consumers, or we're not sure +// why they exist. +static constexpr llvm::StringRef DisallowedClasses[] = { + "SBCommunication", // What is this used for? + "SBInputReader", // What is this used for? + "SBCommandPluginInterface", // This is hard to support, we can do it if + // really needed though. + "SBCommand", // There's nothing too difficult about this one, but many of + // its methods take a SBCommandPluginInterface pointer so + // there's no reason to support this. +}; + +// We intentionally avoid generating certain methods either because they are +// difficult to support correctly or they aren't really used much from C++. +// FIXME: We should be able to annotate these methods instead of maintaining a +// list in the generator itself. +static constexpr llvm::StringRef DisallowedMethods[] = { + // The threading functionality in SBHostOS is deprecated and thus we do not + // generate them. It would be ideal to add the annotations to the methods + // and then support not generating deprecated methods. However, without + // annotations the generator generates most things correctly. This one is + // problematic because it returns a pointer to an "opaque" structure + // (thread_t) that is not `void *`, so special casing it is more effort than + // it's worth. + "_ZN4lldb8SBHostOS10ThreadJoinEP17_opaque_pthread_tPPvPNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadCancelEP17_opaque_pthread_tPNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadCreateEPKcPFPvS3_ES3_PNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadDetachEP17_opaque_pthread_tPNS_7SBErrorE", + "_ZN4lldb8SBHostOS13ThreadCreatedEPKc", +}; + +static constexpr llvm::StringRef ClassesWithoutDefaultCtor[] = { + "SBHostOS", + "SBReproducer", +}; + +static constexpr llvm::StringRef ClassesWithoutCopyOperations[] = { + "SBHostOS", + "SBReproducer", + "SBStream", + "SBProgress", +}; + +static constexpr llvm::StringRef MethodsWithPointerPlusLen[] = { + "_ZN4lldb6SBData11ReadRawDataERNS_7SBErrorEyPvm", + "_ZN4lldb6SBData7SetDataERNS_7SBErrorEPKvmNS_9ByteOrderEh", + "_ZN4lldb6SBData20SetDataWithOwnershipERNS_7SBErrorEPKvmNS_9ByteOrderEh", + "_ZN4lldb6SBData25CreateDataFromUInt64ArrayENS_9ByteOrderEjPym", + "_ZN4lldb6SBData25CreateDataFromUInt32ArrayENS_9ByteOrderEjPjm", + "_ZN4lldb6SBData25CreateDataFromSInt64ArrayENS_9ByteOrderEjPxm", + "_ZN4lldb6SBData25CreateDataFromSInt32ArrayENS_9ByteOrderEjPim", + "_ZN4lldb6SBData25CreateDataFromDoubleArrayENS_9ByteOrderEjPdm", + "_ZN4lldb6SBData22SetDataFromUInt64ArrayEPym", + "_ZN4lldb6SBData22SetDataFromUInt32ArrayEPjm", + "_ZN4lldb6SBData22SetDataFromSInt64ArrayEPxm", + "_ZN4lldb6SBData22SetDataFromSInt32ArrayEPim", + "_ZN4lldb6SBData22SetDataFromDoubleArrayEPdm", + "_ZN4lldb10SBDebugger22GetDefaultArchitectureEPcm", + "_ZN4lldb10SBDebugger13DispatchInputEPvPKvm", + "_ZN4lldb10SBDebugger13DispatchInputEPKvm", + "_ZN4lldb6SBFile4ReadEPhmPm", + "_ZN4lldb6SBFile5WriteEPKhmPm", + "_ZNK4lldb10SBFileSpec7GetPathEPcm", + "_ZN4lldb10SBFileSpec11ResolvePathEPKcPcm", + "_ZN4lldb8SBModule10GetVersionEPjj", + "_ZN4lldb12SBModuleSpec12SetUUIDBytesEPKhm", + "_ZNK4lldb9SBProcess9GetSTDOUTEPcm", + "_ZNK4lldb9SBProcess9GetSTDERREPcm", + "_ZNK4lldb9SBProcess19GetAsyncProfileDataEPcm", + "_ZN4lldb9SBProcess10ReadMemoryEyPvmRNS_7SBErrorE", + "_ZN4lldb9SBProcess11WriteMemoryEyPKvmRNS_7SBErrorE", + "_ZN4lldb9SBProcess21ReadCStringFromMemoryEyPvmRNS_7SBErrorE", + "_ZNK4lldb16SBStructuredData14GetStringValueEPcm", + "_ZN4lldb8SBTarget23BreakpointCreateByNamesEPPKcjjRKNS_" + "14SBFileSpecListES6_", + "_ZN4lldb8SBTarget10ReadMemoryENS_9SBAddressEPvmRNS_7SBErrorE", + "_ZN4lldb8SBTarget15GetInstructionsENS_9SBAddressEPKvm", + "_ZN4lldb8SBTarget25GetInstructionsWithFlavorENS_9SBAddressEPKcPKvm", + "_ZN4lldb8SBTarget15GetInstructionsEyPKvm", + "_ZN4lldb8SBTarget25GetInstructionsWithFlavorEyPKcPKvm", + "_ZN4lldb8SBThread18GetStopDescriptionEPcm", + // The below mangled names are used for dummy methods in shell tests + // that test the emitters' output. If you're adding any new mangled names + // from the actual SB API to this list please add them above. + "_ZN4lldb33SBRPC_" + "CHECKCONSTCHARPTRPTRWITHLEN27CheckConstCharPtrPtrWithLenEPPKcm", + "_ZN4lldb19SBRPC_CHECKARRAYPTR13CheckArrayPtrEPPKcm", + "_ZN4lldb18SBRPC_CHECKVOIDPTR12CheckVoidPtrEPvm", +}; + +// These methods should take a connection parameter according to our logic in +// RequiresConnectionParameter() but in the handwritten version they +// don't take a connection. These methods need to have their implementation +// changed but for now, we just have an exception list of functions that will +// never be a given connection parameter. +// +// FIXME: Change the implementation of these methods so that they can be given a +// connection parameter. +static constexpr llvm::StringRef + MethodsThatUnconditionallyDoNotNeedConnection[] = { + "_ZN4lldb16SBBreakpointNameC1ERNS_8SBTargetEPKc", + "_ZN4lldb10SBDebugger7DestroyERS0_", + "_ZN4lldb18SBExecutionContextC1ENS_8SBThreadE", +}; + +// These classes inherit from rpc::ObjectRef directly (as opposed to +// rpc::LocalObjectRef). Changing them from ObjectRef to LocalObjectRef is ABI +// breaking, so we preserve that compatibility here. +// +// lldb-rpc-gen emits classes as LocalObjectRefs by default. +// +// FIXME: Does it matter which one it emits by default? +static constexpr llvm::StringRef ClassesThatInheritFromObjectRef[] = { + "SBAddress", + "SBBreakpointName", + "SBCommandInterpreter", + "SBCommandReturnObject", + "SBError", + "SBExecutionContext", + "SBExpressionOptions", + "SBFileSpec", + "SBFileSpecList", + "SBFormat", + "SBFunction", + "SBHistoricalFrame", + "SBHistoricalLineEntry", + "SBHistoricalLineEntryList", + "SBLineEntry", + "SBStream", + "SBStringList", + "SBStructuredData", + "SBSymbolContext", + "SBSymbolContextList", + "SBTypeMember", + "SBTypeSummaryOptions", + "SBValueList", +}; + +static llvm::StringMap> + ClassName_to_ParameterTypes = { + {"SBLaunchInfo", {"const char *"}}, + {"SBPlatformConnectOptions", {"const char *"}}, + {"SBPlatformShellCommand", {"const char *", "const char *"}}, + {"SBBreakpointList", {"SBTarget"}}, +}; + +QualType lldb_rpc_gen::GetUnderlyingType(QualType T) { + QualType UnderlyingType; + if (T->isPointerType()) + UnderlyingType = T->getPointeeType(); + else if (T->isReferenceType()) + UnderlyingType = T.getNonReferenceType(); + else + UnderlyingType = T; + + return UnderlyingType; +} + +QualType lldb_rpc_gen::GetUnqualifiedUnderlyingType(QualType T) { + QualType UnderlyingType = GetUnderlyingType(T); + return UnderlyingType.getUnqualifiedType(); +} + +std::string lldb_rpc_gen::GetMangledName(ASTContext &Context, + CXXMethodDecl *MDecl) { + std::string Mangled; + llvm::raw_string_ostream MangledStream(Mangled); + + GlobalDecl GDecl; + if (const auto *CtorDecl = dyn_cast(MDecl)) + GDecl = GlobalDecl(CtorDecl, Ctor_Complete); + else if (const auto *DtorDecl = dyn_cast(MDecl)) + GDecl = GlobalDecl(DtorDecl, Dtor_Deleting); + else + GDecl = GlobalDecl(MDecl); + + MangleContext *MC = Context.createMangleContext(); + MC->mangleName(GDecl, MangledStream); + return Mangled; +} + +bool lldb_rpc_gen::TypeIsFromLLDBPrivate(QualType T) { + + auto CheckTypeForLLDBPrivate = [](const Type *Ty) { + if (!Ty) + return false; + const auto *CXXRDecl = Ty->getAsCXXRecordDecl(); + if (!CXXRDecl) + return false; + const auto *NSDecl = + llvm::dyn_cast(CXXRDecl->getDeclContext()); + if (!NSDecl) + return false; + return NSDecl->getName() == "lldb_private"; + }; + + // First, get the underlying type (remove qualifications and strip off any + // pointers/references). Then we'll need to desugar this type. This will + // remove things like typedefs, so instead of seeing "lldb::DebuggerSP" we'll + // actually see something like "std::shared_ptr". + QualType UnqualifiedUnderlyingType = GetUnqualifiedUnderlyingType(T); + const Type *DesugaredType = + UnqualifiedUnderlyingType->getUnqualifiedDesugaredType(); + assert(DesugaredType && "DesugaredType from a valid Type is nullptr!"); + + // Check the type itself. + if (CheckTypeForLLDBPrivate(DesugaredType)) + return true; + + // If that didn't work, it's possible that the type has a template argument + // that is an lldb_private type. + if (const auto *TemplateSDecl = + llvm::dyn_cast_or_null( + DesugaredType->getAsCXXRecordDecl())) { + for (const TemplateArgument &TA : + TemplateSDecl->getTemplateArgs().asArray()) { + if (TA.getKind() != TemplateArgument::Type) + continue; + if (CheckTypeForLLDBPrivate(TA.getAsType().getTypePtr())) + return true; + } + } + return false; +} + +bool lldb_rpc_gen::TypeIsSBClass(QualType T) { + QualType UnqualifiedUnderlyingType = GetUnqualifiedUnderlyingType(T); + const auto *CXXRDecl = UnqualifiedUnderlyingType->getAsCXXRecordDecl(); + if (!CXXRDecl) + return false; // SB Classes are always C++ classes + + return CXXRDecl->getName().starts_with("SB"); +} + +bool lldb_rpc_gen::TypeIsConstCharPtr(QualType T) { + if (!T->isPointerType()) + return false; + + QualType UnderlyingType = T->getPointeeType(); + if (!UnderlyingType.isConstQualified()) + return false; + + // FIXME: We should be able to do `UnderlyingType->isCharType` but that will + // return true for `const uint8_t *` since that is effectively an unsigned + // char pointer. We currently do not support pointers other than `const char + // *` and `const char **`. + return UnderlyingType->isSpecificBuiltinType(BuiltinType::Char_S) || + UnderlyingType->isSpecificBuiltinType(BuiltinType::SChar); +} + +bool lldb_rpc_gen::TypeIsConstCharPtrPtr(QualType T) { + if (!T->isPointerType()) + return false; + + return TypeIsConstCharPtr(T->getPointeeType()); +} + +bool lldb_rpc_gen::TypeIsDisallowedClass(QualType T) { + QualType UUT = GetUnqualifiedUnderlyingType(T); + const auto *CXXRDecl = UUT->getAsCXXRecordDecl(); + if (!CXXRDecl) + return false; + + llvm::StringRef DeclName = CXXRDecl->getName(); + for (const llvm::StringRef DisallowedClass : DisallowedClasses) + if (DeclName == DisallowedClass) + return true; + return false; +} + +bool lldb_rpc_gen::TypeIsCallbackFunctionPointer(QualType T) { + return T->isFunctionPointerType(); +} + +bool lldb_rpc_gen::MethodIsDisallowed(const std::string &MangledName) { + llvm::StringRef MangledNameRef(MangledName); + return llvm::is_contained(DisallowedMethods, MangledNameRef); +} + +bool lldb_rpc_gen::HasCallbackParameter(CXXMethodDecl *MDecl) { + bool HasCallbackParameter = false; + bool HasBatonParameter = false; + auto End = MDecl->parameters().end(); + for (auto Iter = MDecl->parameters().begin(); Iter != End; Iter++) { + if ((*Iter)->getType()->isFunctionPointerType()) { + HasCallbackParameter = true; + continue; + } + + if ((*Iter)->getType()->isVoidPointerType()) + HasBatonParameter = true; + } + + return HasCallbackParameter && HasBatonParameter; +} + +// FIXME: Find a better way to do this. Here is why it is written this way: ---------------- chelcassanova wrote: So I have a couple thoughts on this FIXME. Just to clarify the main thought from your original comment, since we're picking up all our info from `liblldb`, qualified types for methods and their return types/params have the `lldb::` namespace and all references to this need to change to using `lldb_rpc::`. Currently, we change these namespaces as needed using this replace namespace function that we've implemented, but we'd rather replace those namespaces upon creating a `Method` object instead of when we reference information from `Method`. I like the idea of using Clang's `ChangeNamespace` tool instead of doing our own string replacement here, but looking at some example code for it it looks like it operates at the file level. (i.e. it takes a pattern of files to do the namespace changing). If we were to try using this, that gives me the initial idea of allowing `lldb-rpc-gen` to write everything with the original `lldb::` namespace and then using `ChangeNamespace` once everything has been said and done to replace the namespaces _after_ `lldb-rpc-gen` has emitted everything. I think we could also keep this `ReplaceLLDBNamespaceWithRPCNamespace` method, but possibly just use it to replace the strings that `Method` uses to hold on to the qualified name. This should reduce some of the places it's being used, but doesn't address return types or params since we hold on to those as `QualTypes` which is going to have the original namespaces. It would be nice if the namespaces were already changed when coming into `lldb-rpc-gen`, which I think that `ChangeNamespace` could do, but it would apply that change to the original SB API files? That would possibly mess up the info we need in other unsavoury ways. https://github.com/llvm/llvm-project/pull/138031 From lldb-commits at lists.llvm.org Tue May 13 11:35:16 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Tue, 13 May 2025 11:35:16 -0700 (PDT) Subject: [Lldb-commits] [lldb] Support stepping through Darwin "branch islands" (PR #139301) In-Reply-To: Message-ID: <682390e4.170a0220.227dac.3e00@mx.google.com> jimingham wrote: I used `skipTest` which you can call midway through a test, and will show the skip reason. https://github.com/llvm/llvm-project/pull/139301 From lldb-commits at lists.llvm.org Tue May 13 12:17:53 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Tue, 13 May 2025 12:17:53 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for ColumnDescriptor, BreakpointMode and Breakpoint (PR #139627) In-Reply-To: Message-ID: <68239ae1.050a0220.d1fe5.09ef@mx.google.com> https://github.com/ashgti approved this pull request. LGTM! https://github.com/llvm/llvm-project/pull/139627 From lldb-commits at lists.llvm.org Tue May 13 12:22:51 2025 From: lldb-commits at lists.llvm.org (Felipe de Azevedo Piovezan via lldb-commits) Date: Tue, 13 May 2025 12:22:51 -0700 (PDT) Subject: [Lldb-commits] [lldb] Support stepping through Darwin "branch islands" (PR #139301) In-Reply-To: Message-ID: <68239c0b.170a0220.1330.db81@mx.google.com> https://github.com/felipepiovezan approved this pull request. LGTM! https://github.com/llvm/llvm-project/pull/139301 From lldb-commits at lists.llvm.org Tue May 13 12:23:26 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Tue, 13 May 2025 12:23:26 -0700 (PDT) Subject: [Lldb-commits] [lldb] 8193294 - [lldb-dap] Add unit test for ColumnDescriptor, BreakpointMode and Breakpoint (#139627) Message-ID: <68239c2e.050a0220.11bc41.1f55@mx.google.com> Author: Jonas Devlieghere Date: 2025-05-13T12:23:22-07:00 New Revision: 81932945d76a49a4dd222da39afbc18435e66fb0 URL: https://github.com/llvm/llvm-project/commit/81932945d76a49a4dd222da39afbc18435e66fb0 DIFF: https://github.com/llvm/llvm-project/commit/81932945d76a49a4dd222da39afbc18435e66fb0.diff LOG: [lldb-dap] Add unit test for ColumnDescriptor, BreakpointMode and Breakpoint (#139627) Implement `fromJSON` for `ColumnDescriptor`, `BreakpointMode` and `Breakpoint` and use it to implement the corresponding unit tests. Added: Modified: lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp lldb/tools/lldb-dap/Protocol/ProtocolTypes.h lldb/unittests/DAP/ProtocolTypesTest.cpp Removed: ################################################################################ diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index c9cab350f9f12..7c2f4b20f4956 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -94,6 +94,28 @@ json::Value toJSON(const ExceptionBreakpointsFilter &EBF) { return result; } +bool fromJSON(const json::Value &Params, ColumnType &CT, json::Path P) { + auto rawColumnType = Params.getAsString(); + if (!rawColumnType) { + P.report("expected a string"); + return false; + } + std::optional columnType = + StringSwitch>(*rawColumnType) + .Case("string", eColumnTypeString) + .Case("number", eColumnTypeNumber) + .Case("boolean", eColumnTypeBoolean) + .Case("unixTimestampUTC ", eColumnTypeTimestamp) + .Default(std::nullopt); + if (!columnType) { + P.report("unexpected value, expected 'string', 'number', 'boolean', or " + "'unixTimestampUTC'"); + return false; + } + CT = *columnType; + return true; +} + json::Value toJSON(const ColumnType &T) { switch (T) { case eColumnTypeString: @@ -108,6 +130,14 @@ json::Value toJSON(const ColumnType &T) { llvm_unreachable("unhandled column type."); } +bool fromJSON(const llvm::json::Value &Params, ColumnDescriptor &CD, + llvm::json::Path P) { + llvm::json::ObjectMapper O(Params, P); + return O && O.map("attributeName", CD.attributeName) && + O.map("label", CD.label) && O.mapOptional("format", CD.format) && + O.mapOptional("type", CD.type) && O.mapOptional("width", CD.width); +} + json::Value toJSON(const ColumnDescriptor &CD) { json::Object result{{"attributeName", CD.attributeName}, {"label", CD.label}}; @@ -149,6 +179,30 @@ json::Value toJSON(const BreakpointModeApplicability &BMA) { llvm_unreachable("unhandled breakpoint mode applicability."); } +bool fromJSON(const llvm::json::Value &Params, BreakpointModeApplicability &BMA, + llvm::json::Path P) { + auto rawApplicability = Params.getAsString(); + if (!rawApplicability) { + P.report("expected a string"); + return false; + } + std::optional applicability = + llvm::StringSwitch>( + *rawApplicability) + .Case("source", eBreakpointModeApplicabilitySource) + .Case("exception", eBreakpointModeApplicabilityException) + .Case("data", eBreakpointModeApplicabilityData) + .Case("instruction", eBreakpointModeApplicabilityInstruction) + .Default(std::nullopt); + if (!applicability) { + P.report("unexpected value, expected 'source', 'exception', 'data', or " + "'instruction'"); + return false; + } + BMA = *applicability; + return true; +} + json::Value toJSON(const BreakpointMode &BM) { json::Object result{ {"mode", BM.mode}, @@ -162,6 +216,14 @@ json::Value toJSON(const BreakpointMode &BM) { return result; } +bool fromJSON(const llvm::json::Value &Params, BreakpointMode &BM, + llvm::json::Path P) { + llvm::json::ObjectMapper O(Params, P); + return O && O.map("mode", BM.mode) && O.map("label", BM.label) && + O.mapOptional("description", BM.description) && + O.map("appliesTo", BM.appliesTo); +} + static llvm::StringLiteral ToString(AdapterFeature feature) { switch (feature) { case eAdapterFeatureANSIStyling: @@ -320,6 +382,26 @@ llvm::json::Value toJSON(const BreakpointReason &BR) { llvm_unreachable("unhandled breakpoint reason."); } +bool fromJSON(const llvm::json::Value &Params, BreakpointReason &BR, + llvm::json::Path P) { + auto rawReason = Params.getAsString(); + if (!rawReason) { + P.report("expected a string"); + return false; + } + std::optional reason = + llvm::StringSwitch>(*rawReason) + .Case("pending", BreakpointReason::eBreakpointReasonPending) + .Case("failed", BreakpointReason::eBreakpointReasonFailed) + .Default(std::nullopt); + if (!reason) { + P.report("unexpected value, expected 'pending' or 'failed'"); + return false; + } + BR = *reason; + return true; +} + json::Value toJSON(const Breakpoint &BP) { json::Object result{{"verified", BP.verified}}; @@ -348,6 +430,20 @@ json::Value toJSON(const Breakpoint &BP) { return result; } +bool fromJSON(const llvm::json::Value &Params, Breakpoint &BP, + llvm::json::Path P) { + llvm::json::ObjectMapper O(Params, P); + return O && O.mapOptional("id", BP.id) && O.map("verified", BP.verified) && + O.mapOptional("message", BP.message) && + O.mapOptional("source", BP.source) && O.mapOptional("line", BP.line) && + O.mapOptional("column", BP.column) && + O.mapOptional("endLine", BP.endLine) && + O.mapOptional("endColumn", BP.endColumn) && + O.mapOptional("instructionReference", BP.instructionReference) && + O.mapOptional("offset", BP.offset) && + O.mapOptional("reason", BP.reason); +} + bool fromJSON(const llvm::json::Value &Params, SourceBreakpoint &SB, llvm::json::Path P) { json::ObjectMapper O(Params, P); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index d1e86b0897675..cab188637acd5 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -65,6 +65,8 @@ enum ColumnType : unsigned { eColumnTypeBoolean, eColumnTypeTimestamp }; +bool fromJSON(const llvm::json::Value &, ColumnType &, llvm::json::Path); +llvm::json::Value toJSON(const ColumnType &); /// A ColumnDescriptor specifies what module attribute to show in a column of /// the modules view, how to format it, and what the column’s label should be. @@ -89,6 +91,7 @@ struct ColumnDescriptor { /// Width of this column in characters (hint only). std::optional width; }; +bool fromJSON(const llvm::json::Value &, ColumnDescriptor &, llvm::json::Path); llvm::json::Value toJSON(const ColumnDescriptor &); /// Names of checksum algorithms that may be supported by a debug adapter. @@ -114,6 +117,8 @@ enum BreakpointModeApplicability : unsigned { /// In `InstructionBreakpoint`'s. eBreakpointModeApplicabilityInstruction }; +bool fromJSON(const llvm::json::Value &, BreakpointModeApplicability &, + llvm::json::Path); llvm::json::Value toJSON(const BreakpointModeApplicability &); /// A `BreakpointMode` is provided as a option when setting breakpoints on @@ -133,6 +138,7 @@ struct BreakpointMode { /// Describes one or more type of breakpoint this mode applies to. std::vector appliesTo; }; +bool fromJSON(const llvm::json::Value &, BreakpointMode &, llvm::json::Path); llvm::json::Value toJSON(const BreakpointMode &); /// Debug Adapter Features flags supported by lldb-dap. @@ -364,6 +370,7 @@ enum class BreakpointReason : unsigned { /// adapter does not believe it can be verified without intervention. eBreakpointReasonFailed, }; +bool fromJSON(const llvm::json::Value &, BreakpointReason &, llvm::json::Path); llvm::json::Value toJSON(const BreakpointReason &); /// Information about a breakpoint created in `setBreakpoints`, @@ -415,6 +422,7 @@ struct Breakpoint { /// should omit this property. std::optional reason; }; +bool fromJSON(const llvm::json::Value &, Breakpoint &, llvm::json::Path); llvm::json::Value toJSON(const Breakpoint &); /// Properties of a breakpoint or logpoint passed to the `setBreakpoints` diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp index fa46816ca4a10..56b21f18fa7cd 100644 --- a/lldb/unittests/DAP/ProtocolTypesTest.cpp +++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp @@ -60,3 +60,75 @@ TEST(ProtocolTypesTest, Source) { EXPECT_EQ(source.sourceReference, deserialized_source->sourceReference); EXPECT_EQ(source.presentationHint, deserialized_source->presentationHint); } + +TEST(ProtocolTypesTest, ColumnDescriptor) { + ColumnDescriptor column; + column.attributeName = "moduleName"; + column.label = "Module Name"; + column.format = "uppercase"; + column.type = eColumnTypeString; + column.width = 20; + + llvm::Expected deserialized_column = roundtrip(column); + ASSERT_THAT_EXPECTED(deserialized_column, llvm::Succeeded()); + + EXPECT_EQ(column.attributeName, deserialized_column->attributeName); + EXPECT_EQ(column.label, deserialized_column->label); + EXPECT_EQ(column.format, deserialized_column->format); + EXPECT_EQ(column.type, deserialized_column->type); + EXPECT_EQ(column.width, deserialized_column->width); +} + +TEST(ProtocolTypesTest, BreakpointMode) { + BreakpointMode mode; + mode.mode = "testMode"; + mode.label = "Test Mode"; + mode.description = "This is a test mode"; + mode.appliesTo = {eBreakpointModeApplicabilitySource, + eBreakpointModeApplicabilityException}; + + llvm::Expected deserialized_mode = roundtrip(mode); + ASSERT_THAT_EXPECTED(deserialized_mode, llvm::Succeeded()); + + EXPECT_EQ(mode.mode, deserialized_mode->mode); + EXPECT_EQ(mode.label, deserialized_mode->label); + EXPECT_EQ(mode.description, deserialized_mode->description); + EXPECT_EQ(mode.appliesTo, deserialized_mode->appliesTo); +} + +TEST(ProtocolTypesTest, Breakpoint) { + Breakpoint breakpoint; + breakpoint.id = 42; + breakpoint.verified = true; + breakpoint.message = "Breakpoint set successfully"; + breakpoint.source = + Source{"test.cpp", "/path/to/test.cpp", 123, ePresentationHintNormal}; + breakpoint.line = 10; + breakpoint.column = 5; + breakpoint.endLine = 15; + breakpoint.endColumn = 10; + breakpoint.instructionReference = "0x12345678"; + breakpoint.offset = 4; + breakpoint.reason = BreakpointReason::eBreakpointReasonPending; + + llvm::Expected deserialized_breakpoint = roundtrip(breakpoint); + ASSERT_THAT_EXPECTED(deserialized_breakpoint, llvm::Succeeded()); + + EXPECT_EQ(breakpoint.id, deserialized_breakpoint->id); + EXPECT_EQ(breakpoint.verified, deserialized_breakpoint->verified); + EXPECT_EQ(breakpoint.message, deserialized_breakpoint->message); + EXPECT_EQ(breakpoint.source->name, deserialized_breakpoint->source->name); + EXPECT_EQ(breakpoint.source->path, deserialized_breakpoint->source->path); + EXPECT_EQ(breakpoint.source->sourceReference, + deserialized_breakpoint->source->sourceReference); + EXPECT_EQ(breakpoint.source->presentationHint, + deserialized_breakpoint->source->presentationHint); + EXPECT_EQ(breakpoint.line, deserialized_breakpoint->line); + EXPECT_EQ(breakpoint.column, deserialized_breakpoint->column); + EXPECT_EQ(breakpoint.endLine, deserialized_breakpoint->endLine); + EXPECT_EQ(breakpoint.endColumn, deserialized_breakpoint->endColumn); + EXPECT_EQ(breakpoint.instructionReference, + deserialized_breakpoint->instructionReference); + EXPECT_EQ(breakpoint.offset, deserialized_breakpoint->offset); + EXPECT_EQ(breakpoint.reason, deserialized_breakpoint->reason); +} From lldb-commits at lists.llvm.org Tue May 13 12:23:28 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Tue, 13 May 2025 12:23:28 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for ColumnDescriptor, BreakpointMode and Breakpoint (PR #139627) In-Reply-To: Message-ID: <68239c30.050a0220.301c37.144d@mx.google.com> https://github.com/JDevlieghere closed https://github.com/llvm/llvm-project/pull/139627 From lldb-commits at lists.llvm.org Tue May 13 13:00:50 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Tue, 13 May 2025 13:00:50 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Improving tests logging to understand CI failures. (PR #139311) In-Reply-To: Message-ID: <6823a4f2.a70a0220.e4811.39da@mx.google.com> https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/139311 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Tue May 13 13:32:56 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Tue, 13 May 2025 13:32:56 -0700 (PDT) Subject: [Lldb-commits] [lldb] 952b680 - Support stepping through Darwin "branch islands" (#139301) Message-ID: <6823ac78.050a0220.2a492b.ebb9@mx.google.com> Author: jimingham Date: 2025-05-13T13:32:53-07:00 New Revision: 952b680fd1a283883ee2075146a7b10ea9510e8a URL: https://github.com/llvm/llvm-project/commit/952b680fd1a283883ee2075146a7b10ea9510e8a DIFF: https://github.com/llvm/llvm-project/commit/952b680fd1a283883ee2075146a7b10ea9510e8a.diff LOG: Support stepping through Darwin "branch islands" (#139301) When an intra-module jump doesn't fit in the immediate branch slot, the Darwin linker inserts "branch island" symbols, and emits code to jump from branch island to branch island till it makes it to the actual function. The previous submissions failed because in that environment the linker was putting the `foo.island` symbol at the same address as the `padding` symbol we we emitting to make our faked-up large binary. This submission jams a byte after the padding symbol so that the other symbols can't overlap it. Added: lldb/test/API/macosx/branch-islands/Makefile lldb/test/API/macosx/branch-islands/TestBranchIslands.py lldb/test/API/macosx/branch-islands/foo.c lldb/test/API/macosx/branch-islands/main.c lldb/test/API/macosx/branch-islands/padding1.s lldb/test/API/macosx/branch-islands/padding2.s lldb/test/API/macosx/branch-islands/padding3.s lldb/test/API/macosx/branch-islands/padding4.s Modified: lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp Removed: ################################################################################ diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp index e25c4ff55e408..578ab12268ea3 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp @@ -26,6 +26,7 @@ #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlanCallFunction.h" #include "lldb/Target/ThreadPlanRunToAddress.h" +#include "lldb/Target/ThreadPlanStepInstruction.h" #include "lldb/Utility/DataBuffer.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/LLDBLog.h" @@ -923,15 +924,15 @@ DynamicLoaderDarwin::GetStepThroughTrampolinePlan(Thread &thread, if (current_symbol != nullptr) { std::vector
addresses; + ConstString current_name = + current_symbol->GetMangled().GetName(Mangled::ePreferMangled); if (current_symbol->IsTrampoline()) { - ConstString trampoline_name = - current_symbol->GetMangled().GetName(Mangled::ePreferMangled); - if (trampoline_name) { + if (current_name) { const ModuleList &images = target_sp->GetImages(); SymbolContextList code_symbols; - images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeCode, + images.FindSymbolsWithNameAndType(current_name, eSymbolTypeCode, code_symbols); for (const SymbolContext &context : code_symbols) { Address addr = context.GetFunctionOrSymbolAddress(); @@ -945,8 +946,8 @@ DynamicLoaderDarwin::GetStepThroughTrampolinePlan(Thread &thread, } SymbolContextList reexported_symbols; - images.FindSymbolsWithNameAndType( - trampoline_name, eSymbolTypeReExported, reexported_symbols); + images.FindSymbolsWithNameAndType(current_name, eSymbolTypeReExported, + reexported_symbols); for (const SymbolContext &context : reexported_symbols) { if (context.symbol) { Symbol *actual_symbol = @@ -968,7 +969,7 @@ DynamicLoaderDarwin::GetStepThroughTrampolinePlan(Thread &thread, } SymbolContextList indirect_symbols; - images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeResolver, + images.FindSymbolsWithNameAndType(current_name, eSymbolTypeResolver, indirect_symbols); for (const SymbolContext &context : indirect_symbols) { @@ -1028,6 +1029,23 @@ DynamicLoaderDarwin::GetStepThroughTrampolinePlan(Thread &thread, thread_plan_sp = std::make_shared( thread, load_addrs, stop_others); } + // One more case we have to consider is "branch islands". These are regular + // TEXT symbols but their names end in .island plus maybe a .digit suffix. + // They are to allow arm64 code to branch further than the size of the + // address slot allows. We just need to single-instruction step in that + // case. + static const char *g_branch_island_pattern = "\\.island\\.?[0-9]*$"; + static RegularExpression g_branch_island_regex(g_branch_island_pattern); + + bool is_branch_island = g_branch_island_regex.Execute(current_name); + if (!thread_plan_sp && is_branch_island) { + thread_plan_sp = std::make_shared( + thread, + /* step_over= */ false, /* stop_others */ false, eVoteNoOpinion, + eVoteNoOpinion); + LLDB_LOG(log, "Stepping one instruction over branch island: '{0}'.", + current_name); + } } else { LLDB_LOGF(log, "Could not find symbol for step through."); } diff --git a/lldb/test/API/macosx/branch-islands/Makefile b/lldb/test/API/macosx/branch-islands/Makefile new file mode 100644 index 0000000000000..062e947f6d6ee --- /dev/null +++ b/lldb/test/API/macosx/branch-islands/Makefile @@ -0,0 +1,16 @@ +C_SOURCES := main.c foo.c +CFLAGS_EXTRAS := -std=c99 + +include Makefile.rules + +a.out: main.o padding1.o padding2.o padding3.o padding4.o foo.o + ${CC} ${LDFLAGS} foo.o padding1.o padding2.o padding3.o padding4.o main.o -o a.out + +%.o: $(SRCDIR)/%.s + ${CC} -c $< + +#padding1.o: padding1.s +# ${CC} -c $(SRCDIR)/padding1.s + +#padding2.o: padding2.s +# ${CC} -c $(SRCDIR)/padding2.s diff --git a/lldb/test/API/macosx/branch-islands/TestBranchIslands.py b/lldb/test/API/macosx/branch-islands/TestBranchIslands.py new file mode 100644 index 0000000000000..bc740e95ef4c1 --- /dev/null +++ b/lldb/test/API/macosx/branch-islands/TestBranchIslands.py @@ -0,0 +1,46 @@ +""" +Make sure that we can step in across an arm64 branch island +""" + + +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * + + +class TestBranchIslandStepping(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + @skipUnlessAppleSilicon + def test_step_in_branch_island(self): + """Make sure we can step in across a branch island""" + self.build() + self.main_source_file = lldb.SBFileSpec("main.c") + self.do_test() + + def do_test(self): + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( + self, "Set a breakpoint here", self.main_source_file + ) + + # Make sure that we did manage to generate a branch island for foo: + syms = target.FindSymbols("foo.island", lldb.eSymbolTypeCode) + self.assertEqual(len(syms), 1, "We did generate an island for foo") + # There's a bug in the Xcode 15.2 linker, where it did not emit + # "function starts" entries for the branch island symbols, which + # causes lldb to set the range of the previous non-island symbol to + # encompass the range of the branch island symbols. If we encounter + # that bug, then we won't successfully do the step in. Test for + # that here - if the symbol doesn't round-trip from + # name->address->name then the rest of the test can't pass. + island_sym_ctx = syms[0] + sym_addr = island_sym_ctx.symbol.addr + resolved_name = sym_addr.symbol.name + if resolved_name != "foo.island": + self.skipTest("Encountered overlapping symbol linker bug") + thread.StepInto() + stop_frame = thread.frames[0] + self.assertIn("foo", stop_frame.name, "Stepped into foo") + var = stop_frame.FindVariable("a_variable_in_foo") + self.assertTrue(var.IsValid(), "Found the variable in foo") diff --git a/lldb/test/API/macosx/branch-islands/foo.c b/lldb/test/API/macosx/branch-islands/foo.c new file mode 100644 index 0000000000000..a5dd2e59e1d82 --- /dev/null +++ b/lldb/test/API/macosx/branch-islands/foo.c @@ -0,0 +1,6 @@ +#include + +void foo() { + int a_variable_in_foo = 10; + printf("I am foo: %d.\n", a_variable_in_foo); +} diff --git a/lldb/test/API/macosx/branch-islands/main.c b/lldb/test/API/macosx/branch-islands/main.c new file mode 100644 index 0000000000000..b5578bdd715df --- /dev/null +++ b/lldb/test/API/macosx/branch-islands/main.c @@ -0,0 +1,6 @@ +extern void foo(); + +int main() { + foo(); // Set a breakpoint here + return 0; +} diff --git a/lldb/test/API/macosx/branch-islands/padding1.s b/lldb/test/API/macosx/branch-islands/padding1.s new file mode 100644 index 0000000000000..04abef5455c12 --- /dev/null +++ b/lldb/test/API/macosx/branch-islands/padding1.s @@ -0,0 +1,5 @@ +.text +_padding1: +.p2align 2 +.byte 0x10 +.space 120*1024*1024 diff --git a/lldb/test/API/macosx/branch-islands/padding2.s b/lldb/test/API/macosx/branch-islands/padding2.s new file mode 100644 index 0000000000000..dc66686cc779f --- /dev/null +++ b/lldb/test/API/macosx/branch-islands/padding2.s @@ -0,0 +1,5 @@ +.text +_padding2: +.p2align 2 +.byte 0x10 +.space 120*1024*1024 diff --git a/lldb/test/API/macosx/branch-islands/padding3.s b/lldb/test/API/macosx/branch-islands/padding3.s new file mode 100644 index 0000000000000..bf920e2e4f643 --- /dev/null +++ b/lldb/test/API/macosx/branch-islands/padding3.s @@ -0,0 +1,5 @@ +.text +_padding3: +.p2align 2 +.byte 0x10 +.space 120*1024*1024 diff --git a/lldb/test/API/macosx/branch-islands/padding4.s b/lldb/test/API/macosx/branch-islands/padding4.s new file mode 100644 index 0000000000000..1430fd2fd9729 --- /dev/null +++ b/lldb/test/API/macosx/branch-islands/padding4.s @@ -0,0 +1,5 @@ +.text +_padding4: +.p2align 2 +.byte 0x10 +.space 120*1024*1024 From lldb-commits at lists.llvm.org Tue May 13 13:33:00 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Tue, 13 May 2025 13:33:00 -0700 (PDT) Subject: [Lldb-commits] [lldb] Support stepping through Darwin "branch islands" (PR #139301) In-Reply-To: Message-ID: <6823ac7c.170a0220.22a736.00b9@mx.google.com> https://github.com/jimingham closed https://github.com/llvm/llvm-project/pull/139301 From lldb-commits at lists.llvm.org Tue May 13 13:34:35 2025 From: lldb-commits at lists.llvm.org (Alex Langford via lldb-commits) Date: Tue, 13 May 2025 13:34:35 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream lldb-rpc-gen tool (PR #138031) In-Reply-To: Message-ID: <6823acdb.a70a0220.1b734d.f051@mx.google.com> ================ @@ -0,0 +1,535 @@ +//===-- RPCCommon.cpp -----------------------------------------------------===// +// +// 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 "RPCCommon.h" + +#include "clang/AST/AST.h" +#include "clang/AST/Mangle.h" +#include "clang/Lex/Lexer.h" + +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +// We intentionally do not generate some classes because they are currently +// inconvenient, they aren't really used by most consumers, or we're not sure +// why they exist. +static constexpr llvm::StringRef DisallowedClasses[] = { + "SBCommunication", // What is this used for? + "SBInputReader", // What is this used for? + "SBCommandPluginInterface", // This is hard to support, we can do it if + // really needed though. + "SBCommand", // There's nothing too difficult about this one, but many of + // its methods take a SBCommandPluginInterface pointer so + // there's no reason to support this. +}; + +// We intentionally avoid generating certain methods either because they are +// difficult to support correctly or they aren't really used much from C++. +// FIXME: We should be able to annotate these methods instead of maintaining a +// list in the generator itself. +static constexpr llvm::StringRef DisallowedMethods[] = { + // The threading functionality in SBHostOS is deprecated and thus we do not + // generate them. It would be ideal to add the annotations to the methods + // and then support not generating deprecated methods. However, without + // annotations the generator generates most things correctly. This one is + // problematic because it returns a pointer to an "opaque" structure + // (thread_t) that is not `void *`, so special casing it is more effort than + // it's worth. + "_ZN4lldb8SBHostOS10ThreadJoinEP17_opaque_pthread_tPPvPNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadCancelEP17_opaque_pthread_tPNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadCreateEPKcPFPvS3_ES3_PNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadDetachEP17_opaque_pthread_tPNS_7SBErrorE", + "_ZN4lldb8SBHostOS13ThreadCreatedEPKc", +}; + +static constexpr llvm::StringRef ClassesWithoutDefaultCtor[] = { + "SBHostOS", + "SBReproducer", +}; + +static constexpr llvm::StringRef ClassesWithoutCopyOperations[] = { + "SBHostOS", + "SBReproducer", + "SBStream", + "SBProgress", +}; + +static constexpr llvm::StringRef MethodsWithPointerPlusLen[] = { ---------------- bulbazord wrote: I see. I think something like that could work, but it'd be a larger change that would require buy-in from the larger community and an audit of the SBAPI in general. https://github.com/llvm/llvm-project/pull/138031 From lldb-commits at lists.llvm.org Tue May 13 13:36:30 2025 From: lldb-commits at lists.llvm.org (Alex Langford via lldb-commits) Date: Tue, 13 May 2025 13:36:30 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream lldb-rpc-gen tool (PR #138031) In-Reply-To: Message-ID: <6823ad4e.050a0220.23be6a.1372@mx.google.com> ================ @@ -0,0 +1,535 @@ +//===-- RPCCommon.cpp -----------------------------------------------------===// +// +// 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 "RPCCommon.h" + +#include "clang/AST/AST.h" +#include "clang/AST/Mangle.h" +#include "clang/Lex/Lexer.h" + +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +// We intentionally do not generate some classes because they are currently +// inconvenient, they aren't really used by most consumers, or we're not sure +// why they exist. +static constexpr llvm::StringRef DisallowedClasses[] = { + "SBCommunication", // What is this used for? + "SBInputReader", // What is this used for? + "SBCommandPluginInterface", // This is hard to support, we can do it if + // really needed though. + "SBCommand", // There's nothing too difficult about this one, but many of + // its methods take a SBCommandPluginInterface pointer so + // there's no reason to support this. +}; + +// We intentionally avoid generating certain methods either because they are +// difficult to support correctly or they aren't really used much from C++. +// FIXME: We should be able to annotate these methods instead of maintaining a +// list in the generator itself. +static constexpr llvm::StringRef DisallowedMethods[] = { + // The threading functionality in SBHostOS is deprecated and thus we do not + // generate them. It would be ideal to add the annotations to the methods + // and then support not generating deprecated methods. However, without + // annotations the generator generates most things correctly. This one is + // problematic because it returns a pointer to an "opaque" structure + // (thread_t) that is not `void *`, so special casing it is more effort than + // it's worth. + "_ZN4lldb8SBHostOS10ThreadJoinEP17_opaque_pthread_tPPvPNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadCancelEP17_opaque_pthread_tPNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadCreateEPKcPFPvS3_ES3_PNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadDetachEP17_opaque_pthread_tPNS_7SBErrorE", + "_ZN4lldb8SBHostOS13ThreadCreatedEPKc", +}; + +static constexpr llvm::StringRef ClassesWithoutDefaultCtor[] = { + "SBHostOS", + "SBReproducer", +}; + +static constexpr llvm::StringRef ClassesWithoutCopyOperations[] = { + "SBHostOS", + "SBReproducer", + "SBStream", + "SBProgress", +}; + +static constexpr llvm::StringRef MethodsWithPointerPlusLen[] = { + "_ZN4lldb6SBData11ReadRawDataERNS_7SBErrorEyPvm", + "_ZN4lldb6SBData7SetDataERNS_7SBErrorEPKvmNS_9ByteOrderEh", + "_ZN4lldb6SBData20SetDataWithOwnershipERNS_7SBErrorEPKvmNS_9ByteOrderEh", + "_ZN4lldb6SBData25CreateDataFromUInt64ArrayENS_9ByteOrderEjPym", + "_ZN4lldb6SBData25CreateDataFromUInt32ArrayENS_9ByteOrderEjPjm", + "_ZN4lldb6SBData25CreateDataFromSInt64ArrayENS_9ByteOrderEjPxm", + "_ZN4lldb6SBData25CreateDataFromSInt32ArrayENS_9ByteOrderEjPim", + "_ZN4lldb6SBData25CreateDataFromDoubleArrayENS_9ByteOrderEjPdm", + "_ZN4lldb6SBData22SetDataFromUInt64ArrayEPym", + "_ZN4lldb6SBData22SetDataFromUInt32ArrayEPjm", + "_ZN4lldb6SBData22SetDataFromSInt64ArrayEPxm", + "_ZN4lldb6SBData22SetDataFromSInt32ArrayEPim", + "_ZN4lldb6SBData22SetDataFromDoubleArrayEPdm", + "_ZN4lldb10SBDebugger22GetDefaultArchitectureEPcm", + "_ZN4lldb10SBDebugger13DispatchInputEPvPKvm", + "_ZN4lldb10SBDebugger13DispatchInputEPKvm", + "_ZN4lldb6SBFile4ReadEPhmPm", + "_ZN4lldb6SBFile5WriteEPKhmPm", + "_ZNK4lldb10SBFileSpec7GetPathEPcm", + "_ZN4lldb10SBFileSpec11ResolvePathEPKcPcm", + "_ZN4lldb8SBModule10GetVersionEPjj", + "_ZN4lldb12SBModuleSpec12SetUUIDBytesEPKhm", + "_ZNK4lldb9SBProcess9GetSTDOUTEPcm", + "_ZNK4lldb9SBProcess9GetSTDERREPcm", + "_ZNK4lldb9SBProcess19GetAsyncProfileDataEPcm", + "_ZN4lldb9SBProcess10ReadMemoryEyPvmRNS_7SBErrorE", + "_ZN4lldb9SBProcess11WriteMemoryEyPKvmRNS_7SBErrorE", + "_ZN4lldb9SBProcess21ReadCStringFromMemoryEyPvmRNS_7SBErrorE", + "_ZNK4lldb16SBStructuredData14GetStringValueEPcm", + "_ZN4lldb8SBTarget23BreakpointCreateByNamesEPPKcjjRKNS_" + "14SBFileSpecListES6_", + "_ZN4lldb8SBTarget10ReadMemoryENS_9SBAddressEPvmRNS_7SBErrorE", + "_ZN4lldb8SBTarget15GetInstructionsENS_9SBAddressEPKvm", + "_ZN4lldb8SBTarget25GetInstructionsWithFlavorENS_9SBAddressEPKcPKvm", + "_ZN4lldb8SBTarget15GetInstructionsEyPKvm", + "_ZN4lldb8SBTarget25GetInstructionsWithFlavorEyPKcPKvm", + "_ZN4lldb8SBThread18GetStopDescriptionEPcm", + // The below mangled names are used for dummy methods in shell tests + // that test the emitters' output. If you're adding any new mangled names + // from the actual SB API to this list please add them above. + "_ZN4lldb33SBRPC_" + "CHECKCONSTCHARPTRPTRWITHLEN27CheckConstCharPtrPtrWithLenEPPKcm", + "_ZN4lldb19SBRPC_CHECKARRAYPTR13CheckArrayPtrEPPKcm", + "_ZN4lldb18SBRPC_CHECKVOIDPTR12CheckVoidPtrEPvm", +}; + +// These methods should take a connection parameter according to our logic in +// RequiresConnectionParameter() but in the handwritten version they +// don't take a connection. These methods need to have their implementation +// changed but for now, we just have an exception list of functions that will +// never be a given connection parameter. +// +// FIXME: Change the implementation of these methods so that they can be given a +// connection parameter. +static constexpr llvm::StringRef + MethodsThatUnconditionallyDoNotNeedConnection[] = { + "_ZN4lldb16SBBreakpointNameC1ERNS_8SBTargetEPKc", + "_ZN4lldb10SBDebugger7DestroyERS0_", + "_ZN4lldb18SBExecutionContextC1ENS_8SBThreadE", +}; + +// These classes inherit from rpc::ObjectRef directly (as opposed to +// rpc::LocalObjectRef). Changing them from ObjectRef to LocalObjectRef is ABI +// breaking, so we preserve that compatibility here. +// +// lldb-rpc-gen emits classes as LocalObjectRefs by default. +// +// FIXME: Does it matter which one it emits by default? +static constexpr llvm::StringRef ClassesThatInheritFromObjectRef[] = { + "SBAddress", + "SBBreakpointName", + "SBCommandInterpreter", + "SBCommandReturnObject", + "SBError", + "SBExecutionContext", + "SBExpressionOptions", + "SBFileSpec", + "SBFileSpecList", + "SBFormat", + "SBFunction", + "SBHistoricalFrame", + "SBHistoricalLineEntry", + "SBHistoricalLineEntryList", + "SBLineEntry", + "SBStream", + "SBStringList", + "SBStructuredData", + "SBSymbolContext", + "SBSymbolContextList", + "SBTypeMember", + "SBTypeSummaryOptions", + "SBValueList", +}; + +static llvm::StringMap> + ClassName_to_ParameterTypes = { + {"SBLaunchInfo", {"const char *"}}, + {"SBPlatformConnectOptions", {"const char *"}}, + {"SBPlatformShellCommand", {"const char *", "const char *"}}, + {"SBBreakpointList", {"SBTarget"}}, +}; + +QualType lldb_rpc_gen::GetUnderlyingType(QualType T) { + QualType UnderlyingType; + if (T->isPointerType()) + UnderlyingType = T->getPointeeType(); + else if (T->isReferenceType()) + UnderlyingType = T.getNonReferenceType(); + else + UnderlyingType = T; + + return UnderlyingType; +} + +QualType lldb_rpc_gen::GetUnqualifiedUnderlyingType(QualType T) { + QualType UnderlyingType = GetUnderlyingType(T); + return UnderlyingType.getUnqualifiedType(); +} + +std::string lldb_rpc_gen::GetMangledName(ASTContext &Context, + CXXMethodDecl *MDecl) { + std::string Mangled; + llvm::raw_string_ostream MangledStream(Mangled); + + GlobalDecl GDecl; + if (const auto *CtorDecl = dyn_cast(MDecl)) + GDecl = GlobalDecl(CtorDecl, Ctor_Complete); + else if (const auto *DtorDecl = dyn_cast(MDecl)) + GDecl = GlobalDecl(DtorDecl, Dtor_Deleting); + else + GDecl = GlobalDecl(MDecl); + + MangleContext *MC = Context.createMangleContext(); + MC->mangleName(GDecl, MangledStream); + return Mangled; +} + +bool lldb_rpc_gen::TypeIsFromLLDBPrivate(QualType T) { + + auto CheckTypeForLLDBPrivate = [](const Type *Ty) { + if (!Ty) + return false; + const auto *CXXRDecl = Ty->getAsCXXRecordDecl(); + if (!CXXRDecl) + return false; + const auto *NSDecl = + llvm::dyn_cast(CXXRDecl->getDeclContext()); + if (!NSDecl) + return false; + return NSDecl->getName() == "lldb_private"; + }; + + // First, get the underlying type (remove qualifications and strip off any + // pointers/references). Then we'll need to desugar this type. This will + // remove things like typedefs, so instead of seeing "lldb::DebuggerSP" we'll + // actually see something like "std::shared_ptr". + QualType UnqualifiedUnderlyingType = GetUnqualifiedUnderlyingType(T); + const Type *DesugaredType = + UnqualifiedUnderlyingType->getUnqualifiedDesugaredType(); + assert(DesugaredType && "DesugaredType from a valid Type is nullptr!"); + + // Check the type itself. + if (CheckTypeForLLDBPrivate(DesugaredType)) + return true; + + // If that didn't work, it's possible that the type has a template argument + // that is an lldb_private type. + if (const auto *TemplateSDecl = + llvm::dyn_cast_or_null( + DesugaredType->getAsCXXRecordDecl())) { + for (const TemplateArgument &TA : + TemplateSDecl->getTemplateArgs().asArray()) { + if (TA.getKind() != TemplateArgument::Type) + continue; + if (CheckTypeForLLDBPrivate(TA.getAsType().getTypePtr())) + return true; + } + } + return false; +} + +bool lldb_rpc_gen::TypeIsSBClass(QualType T) { + QualType UnqualifiedUnderlyingType = GetUnqualifiedUnderlyingType(T); + const auto *CXXRDecl = UnqualifiedUnderlyingType->getAsCXXRecordDecl(); + if (!CXXRDecl) + return false; // SB Classes are always C++ classes + + return CXXRDecl->getName().starts_with("SB"); +} + +bool lldb_rpc_gen::TypeIsConstCharPtr(QualType T) { + if (!T->isPointerType()) + return false; + + QualType UnderlyingType = T->getPointeeType(); + if (!UnderlyingType.isConstQualified()) + return false; + + // FIXME: We should be able to do `UnderlyingType->isCharType` but that will + // return true for `const uint8_t *` since that is effectively an unsigned + // char pointer. We currently do not support pointers other than `const char + // *` and `const char **`. + return UnderlyingType->isSpecificBuiltinType(BuiltinType::Char_S) || + UnderlyingType->isSpecificBuiltinType(BuiltinType::SChar); +} + +bool lldb_rpc_gen::TypeIsConstCharPtrPtr(QualType T) { + if (!T->isPointerType()) + return false; + + return TypeIsConstCharPtr(T->getPointeeType()); +} + +bool lldb_rpc_gen::TypeIsDisallowedClass(QualType T) { + QualType UUT = GetUnqualifiedUnderlyingType(T); + const auto *CXXRDecl = UUT->getAsCXXRecordDecl(); + if (!CXXRDecl) + return false; + + llvm::StringRef DeclName = CXXRDecl->getName(); + for (const llvm::StringRef DisallowedClass : DisallowedClasses) + if (DeclName == DisallowedClass) + return true; + return false; +} + +bool lldb_rpc_gen::TypeIsCallbackFunctionPointer(QualType T) { + return T->isFunctionPointerType(); +} + +bool lldb_rpc_gen::MethodIsDisallowed(const std::string &MangledName) { + llvm::StringRef MangledNameRef(MangledName); + return llvm::is_contained(DisallowedMethods, MangledNameRef); +} + +bool lldb_rpc_gen::HasCallbackParameter(CXXMethodDecl *MDecl) { + bool HasCallbackParameter = false; + bool HasBatonParameter = false; + auto End = MDecl->parameters().end(); + for (auto Iter = MDecl->parameters().begin(); Iter != End; Iter++) { + if ((*Iter)->getType()->isFunctionPointerType()) { + HasCallbackParameter = true; + continue; + } + + if ((*Iter)->getType()->isVoidPointerType()) + HasBatonParameter = true; + } + + return HasCallbackParameter && HasBatonParameter; +} + +// FIXME: Find a better way to do this. Here is why it is written this way: ---------------- bulbazord wrote: I think operating in 2 passes could be a good idea here. It was a bit of whack-a-mole getting the `ReplaceLLDBNamespaceWithRPCNamespace` stuff all working as intended, so it'd greatly simplify the code and probably be easier to reason about. The key would be to only apply it to the library. The server links against LLDB directly. https://github.com/llvm/llvm-project/pull/138031 From lldb-commits at lists.llvm.org Tue May 13 13:47:28 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Tue, 13 May 2025 13:47:28 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for breakpoint types (PR #139792) Message-ID: https://github.com/JDevlieghere created https://github.com/llvm/llvm-project/pull/139792 - Add unit test for breakpoint types for SourceBreakpoint, FunctionBreakpoint and DataBreakpoint. - Rename DataBreakpointInfo to DataBreakpoint. - Fix some mapOptions for optional fields. >From 653ea8956bb48c1b6e3ad1c6a861c57a84f72c02 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Tue, 13 May 2025 13:45:49 -0700 Subject: [PATCH] [lldb-dap] Add unit test for breakpoint types - Add unit test for breakpoint types for SourceBreakpoint, FunctionBreakpoint and DataBreakpoint. - Rename DataBreakpointInfo to DataBreakpoint. - Fix some mapOptions for optional fields. --- .../lldb-dap/Protocol/ProtocolRequests.h | 2 +- .../tools/lldb-dap/Protocol/ProtocolTypes.cpp | 77 +++++++++++++++---- lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 8 +- lldb/tools/lldb-dap/Watchpoint.cpp | 2 +- lldb/tools/lldb-dap/Watchpoint.h | 2 +- lldb/unittests/DAP/ProtocolTypesTest.cpp | 62 +++++++++++++++ 6 files changed, 131 insertions(+), 22 deletions(-) diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index c6456b4113320..710fa5d2c57ed 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -693,7 +693,7 @@ llvm::json::Value toJSON(const DataBreakpointInfoResponseBody &); struct SetDataBreakpointsArguments { /// The contents of this array replaces all existing data breakpoints. An /// empty array clears all data breakpoints. - std::vector breakpoints; + std::vector breakpoints; }; bool fromJSON(const llvm::json::Value &, SetDataBreakpointsArguments &, llvm::json::Path); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index 7c2f4b20f4956..8d95687e00e53 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -446,18 +446,48 @@ bool fromJSON(const llvm::json::Value &Params, Breakpoint &BP, bool fromJSON(const llvm::json::Value &Params, SourceBreakpoint &SB, llvm::json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("line", SB.line) && O.map("column", SB.column) && - O.map("condition", SB.condition) && - O.map("hitCondition", SB.hitCondition) && - O.map("logMessage", SB.logMessage) && O.map("mode", SB.mode); + llvm::json::ObjectMapper O(Params, P); + return O && O.map("line", SB.line) && O.mapOptional("column", SB.column) && + O.mapOptional("condition", SB.condition) && + O.mapOptional("hitCondition", SB.hitCondition) && + O.mapOptional("logMessage", SB.logMessage) && + O.mapOptional("mode", SB.mode); +} + +llvm::json::Value toJSON(const SourceBreakpoint &SB) { + llvm::json::Object result{{"line", SB.line}}; + + if (SB.column) + result.insert({"column", *SB.column}); + if (SB.condition) + result.insert({"condition", *SB.condition}); + if (SB.hitCondition) + result.insert({"hitCondition", *SB.hitCondition}); + if (SB.logMessage) + result.insert({"logMessage", *SB.logMessage}); + if (SB.mode) + result.insert({"mode", *SB.mode}); + + return result; } bool fromJSON(const llvm::json::Value &Params, FunctionBreakpoint &FB, llvm::json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("name", FB.name) && O.map("condition", FB.condition) && - O.map("hitCondition", FB.hitCondition); + llvm::json::ObjectMapper O(Params, P); + return O && O.map("name", FB.name) && + O.mapOptional("condition", FB.condition) && + O.mapOptional("hitCondition", FB.hitCondition); +} + +llvm::json::Value toJSON(const FunctionBreakpoint &FB) { + llvm::json::Object result{{"name", FB.name}}; + + if (FB.condition) + result.insert({"condition", *FB.condition}); + if (FB.hitCondition) + result.insert({"hitCondition", *FB.hitCondition}); + + return result; } bool fromJSON(const llvm::json::Value &Params, DataBreakpointAccessType &DBAT, @@ -493,21 +523,36 @@ llvm::json::Value toJSON(const DataBreakpointAccessType &DBAT) { llvm_unreachable("unhandled data breakpoint access type."); } -bool fromJSON(const llvm::json::Value &Params, DataBreakpointInfo &DBI, +bool fromJSON(const llvm::json::Value &Params, DataBreakpoint &DBI, llvm::json::Path P) { - json::ObjectMapper O(Params, P); + llvm::json::ObjectMapper O(Params, P); return O && O.map("dataId", DBI.dataId) && - O.map("accessType", DBI.accessType) && - O.map("condition", DBI.condition) && - O.map("hitCondition", DBI.hitCondition); + O.mapOptional("accessType", DBI.accessType) && + O.mapOptional("condition", DBI.condition) && + O.mapOptional("hitCondition", DBI.hitCondition); +} + +llvm::json::Value toJSON(const DataBreakpoint &DBI) { + llvm::json::Object result{{"dataId", DBI.dataId}}; + + if (DBI.accessType) + result.insert({"accessType", *DBI.accessType}); + if (DBI.condition) + result.insert({"condition", *DBI.condition}); + if (DBI.hitCondition) + result.insert({"hitCondition", *DBI.hitCondition}); + + return result; } bool fromJSON(const llvm::json::Value &Params, InstructionBreakpoint &IB, llvm::json::Path P) { - json::ObjectMapper O(Params, P); + llvm::json::ObjectMapper O(Params, P); return O && O.map("instructionReference", IB.instructionReference) && - O.map("offset", IB.offset) && O.map("condition", IB.condition) && - O.map("hitCondition", IB.hitCondition) && O.map("mode", IB.mode); + O.mapOptional("offset", IB.offset) && + O.mapOptional("condition", IB.condition) && + O.mapOptional("hitCondition", IB.hitCondition) && + O.mapOptional("mode", IB.mode); } } // namespace lldb_dap::protocol diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index cab188637acd5..c48988a48a373 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -464,6 +464,7 @@ struct SourceBreakpoint { std::optional mode; }; bool fromJSON(const llvm::json::Value &, SourceBreakpoint &, llvm::json::Path); +llvm::json::Value toJSON(const SourceBreakpoint &); /// Properties of a breakpoint passed to the `setFunctionBreakpoints` request. struct FunctionBreakpoint { @@ -483,6 +484,7 @@ struct FunctionBreakpoint { }; bool fromJSON(const llvm::json::Value &, FunctionBreakpoint &, llvm::json::Path); +llvm::json::Value toJSON(const FunctionBreakpoint &); /// This enumeration defines all possible access types for data breakpoints. /// Values: ‘read’, ‘write’, ‘readWrite’ @@ -496,7 +498,7 @@ bool fromJSON(const llvm::json::Value &, DataBreakpointAccessType &, llvm::json::Value toJSON(const DataBreakpointAccessType &); /// Properties of a data breakpoint passed to the `setDataBreakpoints` request. -struct DataBreakpointInfo { +struct DataBreakpoint { /// An id representing the data. This id is returned from the /// `dataBreakpointInfo` request. std::string dataId; @@ -511,8 +513,8 @@ struct DataBreakpointInfo { /// The debug adapter is expected to interpret the expression as needed. std::optional hitCondition; }; -bool fromJSON(const llvm::json::Value &, DataBreakpointInfo &, - llvm::json::Path); +bool fromJSON(const llvm::json::Value &, DataBreakpoint &, llvm::json::Path); +llvm::json::Value toJSON(const DataBreakpoint &); /// Properties of a breakpoint passed to the `setInstructionBreakpoints` request struct InstructionBreakpoint { diff --git a/lldb/tools/lldb-dap/Watchpoint.cpp b/lldb/tools/lldb-dap/Watchpoint.cpp index 73ed4fdbae1b8..0acc980890be8 100644 --- a/lldb/tools/lldb-dap/Watchpoint.cpp +++ b/lldb/tools/lldb-dap/Watchpoint.cpp @@ -17,7 +17,7 @@ #include namespace lldb_dap { -Watchpoint::Watchpoint(DAP &d, const protocol::DataBreakpointInfo &breakpoint) +Watchpoint::Watchpoint(DAP &d, const protocol::DataBreakpoint &breakpoint) : BreakpointBase(d, breakpoint.condition, breakpoint.hitCondition) { llvm::StringRef dataId = breakpoint.dataId; auto [addr_str, size_str] = dataId.split('/'); diff --git a/lldb/tools/lldb-dap/Watchpoint.h b/lldb/tools/lldb-dap/Watchpoint.h index b7fe58fe73501..d943e1218bdcd 100644 --- a/lldb/tools/lldb-dap/Watchpoint.h +++ b/lldb/tools/lldb-dap/Watchpoint.h @@ -22,7 +22,7 @@ namespace lldb_dap { class Watchpoint : public BreakpointBase { public: - Watchpoint(DAP &d, const protocol::DataBreakpointInfo &breakpoint); + Watchpoint(DAP &d, const protocol::DataBreakpoint &breakpoint); Watchpoint(DAP &d, lldb::SBWatchpoint wp) : BreakpointBase(d), m_wp(wp) {} void SetCondition() override; diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp index 56b21f18fa7cd..f5d72f06432d5 100644 --- a/lldb/unittests/DAP/ProtocolTypesTest.cpp +++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp @@ -132,3 +132,65 @@ TEST(ProtocolTypesTest, Breakpoint) { EXPECT_EQ(breakpoint.offset, deserialized_breakpoint->offset); EXPECT_EQ(breakpoint.reason, deserialized_breakpoint->reason); } + +TEST(ProtocolTypesTest, SourceBreakpoint) { + SourceBreakpoint source_breakpoint; + source_breakpoint.line = 42; + source_breakpoint.column = 5; + source_breakpoint.condition = "x > 10"; + source_breakpoint.hitCondition = "5"; + source_breakpoint.logMessage = "Breakpoint hit at line 42"; + source_breakpoint.mode = "hardware"; + + llvm::Expected deserialized_source_breakpoint = + roundtrip(source_breakpoint); + ASSERT_THAT_EXPECTED(deserialized_source_breakpoint, llvm::Succeeded()); + + EXPECT_EQ(source_breakpoint.line, deserialized_source_breakpoint->line); + EXPECT_EQ(source_breakpoint.column, deserialized_source_breakpoint->column); + EXPECT_EQ(source_breakpoint.condition, + deserialized_source_breakpoint->condition); + EXPECT_EQ(source_breakpoint.hitCondition, + deserialized_source_breakpoint->hitCondition); + EXPECT_EQ(source_breakpoint.logMessage, + deserialized_source_breakpoint->logMessage); + EXPECT_EQ(source_breakpoint.mode, deserialized_source_breakpoint->mode); +} + +TEST(ProtocolTypesTest, FunctionBreakpoint) { + FunctionBreakpoint function_breakpoint; + function_breakpoint.name = "myFunction"; + function_breakpoint.condition = "x == 0"; + function_breakpoint.hitCondition = "3"; + + llvm::Expected deserialized_function_breakpoint = + roundtrip(function_breakpoint); + ASSERT_THAT_EXPECTED(deserialized_function_breakpoint, llvm::Succeeded()); + + EXPECT_EQ(function_breakpoint.name, deserialized_function_breakpoint->name); + EXPECT_EQ(function_breakpoint.condition, + deserialized_function_breakpoint->condition); + EXPECT_EQ(function_breakpoint.hitCondition, + deserialized_function_breakpoint->hitCondition); +} + +TEST(ProtocolTypesTest, DataBreakpoint) { + DataBreakpoint data_breakpoint_info; + data_breakpoint_info.dataId = "variable1"; + data_breakpoint_info.accessType = eDataBreakpointAccessTypeReadWrite; + data_breakpoint_info.condition = "x > 100"; + data_breakpoint_info.hitCondition = "10"; + + llvm::Expected deserialized_data_breakpoint_info = + roundtrip(data_breakpoint_info); + ASSERT_THAT_EXPECTED(deserialized_data_breakpoint_info, llvm::Succeeded()); + + EXPECT_EQ(data_breakpoint_info.dataId, + deserialized_data_breakpoint_info->dataId); + EXPECT_EQ(data_breakpoint_info.accessType, + deserialized_data_breakpoint_info->accessType); + EXPECT_EQ(data_breakpoint_info.condition, + deserialized_data_breakpoint_info->condition); + EXPECT_EQ(data_breakpoint_info.hitCondition, + deserialized_data_breakpoint_info->hitCondition); +} From lldb-commits at lists.llvm.org Tue May 13 13:48:03 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Tue, 13 May 2025 13:48:03 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for breakpoint types (PR #139792) In-Reply-To: Message-ID: <6823b003.170a0220.27a9c0.e7e5@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Jonas Devlieghere (JDevlieghere)
Changes - Add unit test for breakpoint types for SourceBreakpoint, FunctionBreakpoint and DataBreakpoint. - Rename DataBreakpointInfo to DataBreakpoint. - Fix some mapOptions for optional fields. --- Full diff: https://github.com/llvm/llvm-project/pull/139792.diff 6 Files Affected: - (modified) lldb/tools/lldb-dap/Protocol/ProtocolRequests.h (+1-1) - (modified) lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp (+61-16) - (modified) lldb/tools/lldb-dap/Protocol/ProtocolTypes.h (+5-3) - (modified) lldb/tools/lldb-dap/Watchpoint.cpp (+1-1) - (modified) lldb/tools/lldb-dap/Watchpoint.h (+1-1) - (modified) lldb/unittests/DAP/ProtocolTypesTest.cpp (+62) ``````````diff diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index c6456b4113320..710fa5d2c57ed 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -693,7 +693,7 @@ llvm::json::Value toJSON(const DataBreakpointInfoResponseBody &); struct SetDataBreakpointsArguments { /// The contents of this array replaces all existing data breakpoints. An /// empty array clears all data breakpoints. - std::vector breakpoints; + std::vector breakpoints; }; bool fromJSON(const llvm::json::Value &, SetDataBreakpointsArguments &, llvm::json::Path); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index 7c2f4b20f4956..8d95687e00e53 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -446,18 +446,48 @@ bool fromJSON(const llvm::json::Value &Params, Breakpoint &BP, bool fromJSON(const llvm::json::Value &Params, SourceBreakpoint &SB, llvm::json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("line", SB.line) && O.map("column", SB.column) && - O.map("condition", SB.condition) && - O.map("hitCondition", SB.hitCondition) && - O.map("logMessage", SB.logMessage) && O.map("mode", SB.mode); + llvm::json::ObjectMapper O(Params, P); + return O && O.map("line", SB.line) && O.mapOptional("column", SB.column) && + O.mapOptional("condition", SB.condition) && + O.mapOptional("hitCondition", SB.hitCondition) && + O.mapOptional("logMessage", SB.logMessage) && + O.mapOptional("mode", SB.mode); +} + +llvm::json::Value toJSON(const SourceBreakpoint &SB) { + llvm::json::Object result{{"line", SB.line}}; + + if (SB.column) + result.insert({"column", *SB.column}); + if (SB.condition) + result.insert({"condition", *SB.condition}); + if (SB.hitCondition) + result.insert({"hitCondition", *SB.hitCondition}); + if (SB.logMessage) + result.insert({"logMessage", *SB.logMessage}); + if (SB.mode) + result.insert({"mode", *SB.mode}); + + return result; } bool fromJSON(const llvm::json::Value &Params, FunctionBreakpoint &FB, llvm::json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("name", FB.name) && O.map("condition", FB.condition) && - O.map("hitCondition", FB.hitCondition); + llvm::json::ObjectMapper O(Params, P); + return O && O.map("name", FB.name) && + O.mapOptional("condition", FB.condition) && + O.mapOptional("hitCondition", FB.hitCondition); +} + +llvm::json::Value toJSON(const FunctionBreakpoint &FB) { + llvm::json::Object result{{"name", FB.name}}; + + if (FB.condition) + result.insert({"condition", *FB.condition}); + if (FB.hitCondition) + result.insert({"hitCondition", *FB.hitCondition}); + + return result; } bool fromJSON(const llvm::json::Value &Params, DataBreakpointAccessType &DBAT, @@ -493,21 +523,36 @@ llvm::json::Value toJSON(const DataBreakpointAccessType &DBAT) { llvm_unreachable("unhandled data breakpoint access type."); } -bool fromJSON(const llvm::json::Value &Params, DataBreakpointInfo &DBI, +bool fromJSON(const llvm::json::Value &Params, DataBreakpoint &DBI, llvm::json::Path P) { - json::ObjectMapper O(Params, P); + llvm::json::ObjectMapper O(Params, P); return O && O.map("dataId", DBI.dataId) && - O.map("accessType", DBI.accessType) && - O.map("condition", DBI.condition) && - O.map("hitCondition", DBI.hitCondition); + O.mapOptional("accessType", DBI.accessType) && + O.mapOptional("condition", DBI.condition) && + O.mapOptional("hitCondition", DBI.hitCondition); +} + +llvm::json::Value toJSON(const DataBreakpoint &DBI) { + llvm::json::Object result{{"dataId", DBI.dataId}}; + + if (DBI.accessType) + result.insert({"accessType", *DBI.accessType}); + if (DBI.condition) + result.insert({"condition", *DBI.condition}); + if (DBI.hitCondition) + result.insert({"hitCondition", *DBI.hitCondition}); + + return result; } bool fromJSON(const llvm::json::Value &Params, InstructionBreakpoint &IB, llvm::json::Path P) { - json::ObjectMapper O(Params, P); + llvm::json::ObjectMapper O(Params, P); return O && O.map("instructionReference", IB.instructionReference) && - O.map("offset", IB.offset) && O.map("condition", IB.condition) && - O.map("hitCondition", IB.hitCondition) && O.map("mode", IB.mode); + O.mapOptional("offset", IB.offset) && + O.mapOptional("condition", IB.condition) && + O.mapOptional("hitCondition", IB.hitCondition) && + O.mapOptional("mode", IB.mode); } } // namespace lldb_dap::protocol diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index cab188637acd5..c48988a48a373 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -464,6 +464,7 @@ struct SourceBreakpoint { std::optional mode; }; bool fromJSON(const llvm::json::Value &, SourceBreakpoint &, llvm::json::Path); +llvm::json::Value toJSON(const SourceBreakpoint &); /// Properties of a breakpoint passed to the `setFunctionBreakpoints` request. struct FunctionBreakpoint { @@ -483,6 +484,7 @@ struct FunctionBreakpoint { }; bool fromJSON(const llvm::json::Value &, FunctionBreakpoint &, llvm::json::Path); +llvm::json::Value toJSON(const FunctionBreakpoint &); /// This enumeration defines all possible access types for data breakpoints. /// Values: ‘read’, ‘write’, ‘readWrite’ @@ -496,7 +498,7 @@ bool fromJSON(const llvm::json::Value &, DataBreakpointAccessType &, llvm::json::Value toJSON(const DataBreakpointAccessType &); /// Properties of a data breakpoint passed to the `setDataBreakpoints` request. -struct DataBreakpointInfo { +struct DataBreakpoint { /// An id representing the data. This id is returned from the /// `dataBreakpointInfo` request. std::string dataId; @@ -511,8 +513,8 @@ struct DataBreakpointInfo { /// The debug adapter is expected to interpret the expression as needed. std::optional hitCondition; }; -bool fromJSON(const llvm::json::Value &, DataBreakpointInfo &, - llvm::json::Path); +bool fromJSON(const llvm::json::Value &, DataBreakpoint &, llvm::json::Path); +llvm::json::Value toJSON(const DataBreakpoint &); /// Properties of a breakpoint passed to the `setInstructionBreakpoints` request struct InstructionBreakpoint { diff --git a/lldb/tools/lldb-dap/Watchpoint.cpp b/lldb/tools/lldb-dap/Watchpoint.cpp index 73ed4fdbae1b8..0acc980890be8 100644 --- a/lldb/tools/lldb-dap/Watchpoint.cpp +++ b/lldb/tools/lldb-dap/Watchpoint.cpp @@ -17,7 +17,7 @@ #include namespace lldb_dap { -Watchpoint::Watchpoint(DAP &d, const protocol::DataBreakpointInfo &breakpoint) +Watchpoint::Watchpoint(DAP &d, const protocol::DataBreakpoint &breakpoint) : BreakpointBase(d, breakpoint.condition, breakpoint.hitCondition) { llvm::StringRef dataId = breakpoint.dataId; auto [addr_str, size_str] = dataId.split('/'); diff --git a/lldb/tools/lldb-dap/Watchpoint.h b/lldb/tools/lldb-dap/Watchpoint.h index b7fe58fe73501..d943e1218bdcd 100644 --- a/lldb/tools/lldb-dap/Watchpoint.h +++ b/lldb/tools/lldb-dap/Watchpoint.h @@ -22,7 +22,7 @@ namespace lldb_dap { class Watchpoint : public BreakpointBase { public: - Watchpoint(DAP &d, const protocol::DataBreakpointInfo &breakpoint); + Watchpoint(DAP &d, const protocol::DataBreakpoint &breakpoint); Watchpoint(DAP &d, lldb::SBWatchpoint wp) : BreakpointBase(d), m_wp(wp) {} void SetCondition() override; diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp index 56b21f18fa7cd..f5d72f06432d5 100644 --- a/lldb/unittests/DAP/ProtocolTypesTest.cpp +++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp @@ -132,3 +132,65 @@ TEST(ProtocolTypesTest, Breakpoint) { EXPECT_EQ(breakpoint.offset, deserialized_breakpoint->offset); EXPECT_EQ(breakpoint.reason, deserialized_breakpoint->reason); } + +TEST(ProtocolTypesTest, SourceBreakpoint) { + SourceBreakpoint source_breakpoint; + source_breakpoint.line = 42; + source_breakpoint.column = 5; + source_breakpoint.condition = "x > 10"; + source_breakpoint.hitCondition = "5"; + source_breakpoint.logMessage = "Breakpoint hit at line 42"; + source_breakpoint.mode = "hardware"; + + llvm::Expected deserialized_source_breakpoint = + roundtrip(source_breakpoint); + ASSERT_THAT_EXPECTED(deserialized_source_breakpoint, llvm::Succeeded()); + + EXPECT_EQ(source_breakpoint.line, deserialized_source_breakpoint->line); + EXPECT_EQ(source_breakpoint.column, deserialized_source_breakpoint->column); + EXPECT_EQ(source_breakpoint.condition, + deserialized_source_breakpoint->condition); + EXPECT_EQ(source_breakpoint.hitCondition, + deserialized_source_breakpoint->hitCondition); + EXPECT_EQ(source_breakpoint.logMessage, + deserialized_source_breakpoint->logMessage); + EXPECT_EQ(source_breakpoint.mode, deserialized_source_breakpoint->mode); +} + +TEST(ProtocolTypesTest, FunctionBreakpoint) { + FunctionBreakpoint function_breakpoint; + function_breakpoint.name = "myFunction"; + function_breakpoint.condition = "x == 0"; + function_breakpoint.hitCondition = "3"; + + llvm::Expected deserialized_function_breakpoint = + roundtrip(function_breakpoint); + ASSERT_THAT_EXPECTED(deserialized_function_breakpoint, llvm::Succeeded()); + + EXPECT_EQ(function_breakpoint.name, deserialized_function_breakpoint->name); + EXPECT_EQ(function_breakpoint.condition, + deserialized_function_breakpoint->condition); + EXPECT_EQ(function_breakpoint.hitCondition, + deserialized_function_breakpoint->hitCondition); +} + +TEST(ProtocolTypesTest, DataBreakpoint) { + DataBreakpoint data_breakpoint_info; + data_breakpoint_info.dataId = "variable1"; + data_breakpoint_info.accessType = eDataBreakpointAccessTypeReadWrite; + data_breakpoint_info.condition = "x > 100"; + data_breakpoint_info.hitCondition = "10"; + + llvm::Expected deserialized_data_breakpoint_info = + roundtrip(data_breakpoint_info); + ASSERT_THAT_EXPECTED(deserialized_data_breakpoint_info, llvm::Succeeded()); + + EXPECT_EQ(data_breakpoint_info.dataId, + deserialized_data_breakpoint_info->dataId); + EXPECT_EQ(data_breakpoint_info.accessType, + deserialized_data_breakpoint_info->accessType); + EXPECT_EQ(data_breakpoint_info.condition, + deserialized_data_breakpoint_info->condition); + EXPECT_EQ(data_breakpoint_info.hitCondition, + deserialized_data_breakpoint_info->hitCondition); +} ``````````
https://github.com/llvm/llvm-project/pull/139792 From lldb-commits at lists.llvm.org Tue May 13 13:57:51 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Tue, 13 May 2025 13:57:51 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for breakpoint types (PR #139792) In-Reply-To: Message-ID: <6823b24f.a70a0220.165908.1a03@mx.google.com> https://github.com/ashgti approved this pull request. Looks good! https://github.com/llvm/llvm-project/pull/139792 From lldb-commits at lists.llvm.org Tue May 13 13:58:01 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Tue, 13 May 2025 13:58:01 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Migrate ScopesRequest to structured types (PR #138116) In-Reply-To: Message-ID: <6823b259.170a0220.2ad19b.ebe1@mx.google.com> https://github.com/da-viper updated https://github.com/llvm/llvm-project/pull/138116 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Tue May 13 14:00:49 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Tue, 13 May 2025 14:00:49 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for breakpoint types (PR #139792) In-Reply-To: Message-ID: <6823b301.a70a0220.16568f.2312@mx.google.com> https://github.com/da-viper approved this pull request. https://github.com/llvm/llvm-project/pull/139792 From lldb-commits at lists.llvm.org Tue May 13 14:04:17 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Tue, 13 May 2025 14:04:17 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Improving tests logging to understand CI failures. (PR #139311) In-Reply-To: Message-ID: <6823b3d1.170a0220.1f5fa1.0175@mx.google.com> https://github.com/da-viper approved this pull request. https://github.com/llvm/llvm-project/pull/139311 From lldb-commits at lists.llvm.org Tue May 13 14:27:02 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Tue, 13 May 2025 14:27:02 -0700 (PDT) Subject: [Lldb-commits] [lldb] [Support] [lldb] Fix thread jump #45326 (PR #135778) In-Reply-To: Message-ID: <6823b926.170a0220.18e312.087f@mx.google.com> https://github.com/da-viper edited https://github.com/llvm/llvm-project/pull/135778 From lldb-commits at lists.llvm.org Tue May 13 14:27:10 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Tue, 13 May 2025 14:27:10 -0700 (PDT) Subject: [Lldb-commits] [lldb] [Support] [lldb] Fix thread jump #45326 (PR #135778) In-Reply-To: Message-ID: <6823b92e.170a0220.38556f.eeb3@mx.google.com> https://github.com/da-viper updated https://github.com/llvm/llvm-project/pull/135778 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Tue May 13 14:31:56 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Tue, 13 May 2025 14:31:56 -0700 (PDT) Subject: [Lldb-commits] [lldb] [Support] [lldb] Fix thread jump #45326 (PR #135778) In-Reply-To: Message-ID: <6823ba4c.050a0220.266d37.1a6c@mx.google.com> https://github.com/da-viper updated https://github.com/llvm/llvm-project/pull/135778 >From 8070e1a391d876ccbab25dac6d2a6d2d77f16069 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Tue, 15 Apr 2025 12:25:41 +0100 Subject: [PATCH 1/4] [lldb] Add test for jumping by offset Signed-off-by: Ebuka Ezike --- .../thread/jump/TestThreadJump.py | 70 ++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/lldb/test/API/functionalities/thread/jump/TestThreadJump.py b/lldb/test/API/functionalities/thread/jump/TestThreadJump.py index 3c13a969bc3fd..d603580ac6f36 100644 --- a/lldb/test/API/functionalities/thread/jump/TestThreadJump.py +++ b/lldb/test/API/functionalities/thread/jump/TestThreadJump.py @@ -10,9 +10,12 @@ class ThreadJumpTestCase(TestBase): + def setUp(self): + TestBase.setUp(self) + self.build() + def test(self): """Test thread jump handling.""" - self.build() exe = self.getBuildArtifact("a.out") self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) @@ -62,6 +65,71 @@ def test(self): substrs=["error"], ) + def test_jump_offset(self): + """Test Thread Jump by negative or positive offset""" + exe = self.getBuildArtifact("a.out") + file_name = "main.cpp" + self.runCmd(f"target create {exe}", CURRENT_EXECUTABLE_SET) + + pos_jump = line_number(file_name, "// jump_offset 1") + neg_jump = line_number(file_name, "// jump_offset 2") + pos_breakpoint = line_number(file_name, "// breakpoint 1") + neg_breakpoint = line_number(file_name, "// breakpoint 2") + pos_jump_offset = pos_jump - pos_breakpoint + neg_jump_offset = neg_jump - neg_breakpoint + + var_1, var_1_value = ("var_1", "10") + var_2, var_2_value = ("var_2", "40") + var_3, var_3_value = ("var_3", "10") + + # create pos_breakpoint and neg_breakpoint + lldbutil.run_break_set_by_file_and_line( + self, file_name, pos_breakpoint, num_expected_locations=1 + ) + lldbutil.run_break_set_by_file_and_line( + self, file_name, neg_breakpoint, num_expected_locations=1 + ) + + self.runCmd("run", RUN_SUCCEEDED) + + # test positive jump + # The stop reason of the thread should be breakpoint 1. + self.expect( + "thread list", + STOPPED_DUE_TO_BREAKPOINT + " 1", + substrs=[ + "stopped", + f"{file_name}:{pos_breakpoint}", + "stop reason = breakpoint 1", + ], + ) + + self.runCmd(f"thread jump --by +{pos_jump_offset}") + self.expect("process status", substrs=[f"at {file_name}:{pos_jump}"]) + self.expect(f"print {var_1}", substrs=[var_1_value]) + + self.runCmd("thread step-over") + self.expect(f"print {var_2}", substrs=[var_2_value]) + + self.runCmd("continue") + + # test negative jump + # The stop reason of the thread should be breakpoint 1. + self.expect( + "thread list", + STOPPED_DUE_TO_BREAKPOINT + " 2", + substrs=[ + "stopped", + f"{file_name}:{neg_breakpoint}", + "stop reason = breakpoint 2", + ], + ) + + self.runCmd(f"thread jump --by {neg_jump_offset}") + self.expect("process status", substrs=[f"at {file_name}:{neg_jump}"]) + self.runCmd("thread step-over") + self.expect(f"print {var_3}", substrs=[var_3_value]) + def do_min_test(self, start, jump, var, value): # jump to the start marker self.runCmd("j %i" % start) >From e413cc9cc0967d0db256cc3c5e53fa0d221ba5b9 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Tue, 15 Apr 2025 12:33:52 +0100 Subject: [PATCH 2/4] [lldb] Add test main.cpp file Signed-off-by: Ebuka Ezike --- .../API/functionalities/thread/jump/main.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lldb/test/API/functionalities/thread/jump/main.cpp b/lldb/test/API/functionalities/thread/jump/main.cpp index d3c0de2af4bf4..9c7f0bcb3b732 100644 --- a/lldb/test/API/functionalities/thread/jump/main.cpp +++ b/lldb/test/API/functionalities/thread/jump/main.cpp @@ -13,6 +13,21 @@ T min(T a, T b) } } +int jump_positive_offset() { + int var_1 = 10; + var_1 = 20; // breakpoint 1 + + int var_2 = 40; // jump_offset 1 + return var_2; +} + +int jump_negative_offset() { + int var_3 = 10; // jump_offset 2 + var_3 = 99; + + return var_3; // breakpoint 2 +} + int main () { int i; @@ -22,5 +37,7 @@ int main () i = min(min_i_a, min_i_b); // 3rd marker j = min(min_j_a, min_j_b); // 4th marker + jump_positive_offset(); + jump_negative_offset(); return 0; } >From a84c26af67cd0b78dd83ceef89293dba02aeffbb Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Tue, 13 May 2025 22:26:18 +0100 Subject: [PATCH 3/4] [lldb][lldb-dap] remove `+` prefix --- lldb/source/Commands/CommandObjectThread.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index 224c523e69c5c..df56871feb1cf 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -1649,11 +1649,15 @@ class CommandObjectThreadJump : public CommandObjectParsed { return Status::FromErrorStringWithFormat("invalid line number: '%s'.", option_arg.str().c_str()); break; - case 'b': + case 'b': { + if (option_arg.starts_with('+')) + option_arg.consume_front("+"); + if (option_arg.getAsInteger(0, m_line_offset)) return Status::FromErrorStringWithFormat("invalid line offset: '%s'.", option_arg.str().c_str()); break; + } case 'a': m_load_addr = OptionArgParser::ToAddress(execution_context, option_arg, LLDB_INVALID_ADDRESS, &error); >From 155eac7b594af8dc3bd755af9e51663daba53416 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Tue, 13 May 2025 22:31:39 +0100 Subject: [PATCH 4/4] [lldb][lldb-dap] remove `+` prefix checking if it starts_with prefix is redundant since consume front also check it --- lldb/source/Commands/CommandObjectThread.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index df56871feb1cf..57c23d533fb96 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -1650,8 +1650,7 @@ class CommandObjectThreadJump : public CommandObjectParsed { option_arg.str().c_str()); break; case 'b': { - if (option_arg.starts_with('+')) - option_arg.consume_front("+"); + option_arg.consume_front("+"); if (option_arg.getAsInteger(0, m_line_offset)) return Status::FromErrorStringWithFormat("invalid line offset: '%s'.", From lldb-commits at lists.llvm.org Tue May 13 14:34:50 2025 From: lldb-commits at lists.llvm.org (Chelsea Cassanova via lldb-commits) Date: Tue, 13 May 2025 14:34:50 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream lldb-rpc-gen tool (PR #138031) In-Reply-To: Message-ID: <6823bafa.170a0220.1762c6.f22f@mx.google.com> ================ @@ -0,0 +1,535 @@ +//===-- RPCCommon.cpp -----------------------------------------------------===// +// +// 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 "RPCCommon.h" + +#include "clang/AST/AST.h" +#include "clang/AST/Mangle.h" +#include "clang/Lex/Lexer.h" + +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +// We intentionally do not generate some classes because they are currently +// inconvenient, they aren't really used by most consumers, or we're not sure +// why they exist. +static constexpr llvm::StringRef DisallowedClasses[] = { + "SBCommunication", // What is this used for? + "SBInputReader", // What is this used for? + "SBCommandPluginInterface", // This is hard to support, we can do it if + // really needed though. + "SBCommand", // There's nothing too difficult about this one, but many of + // its methods take a SBCommandPluginInterface pointer so + // there's no reason to support this. +}; + +// We intentionally avoid generating certain methods either because they are +// difficult to support correctly or they aren't really used much from C++. +// FIXME: We should be able to annotate these methods instead of maintaining a +// list in the generator itself. +static constexpr llvm::StringRef DisallowedMethods[] = { + // The threading functionality in SBHostOS is deprecated and thus we do not + // generate them. It would be ideal to add the annotations to the methods + // and then support not generating deprecated methods. However, without + // annotations the generator generates most things correctly. This one is + // problematic because it returns a pointer to an "opaque" structure + // (thread_t) that is not `void *`, so special casing it is more effort than + // it's worth. + "_ZN4lldb8SBHostOS10ThreadJoinEP17_opaque_pthread_tPPvPNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadCancelEP17_opaque_pthread_tPNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadCreateEPKcPFPvS3_ES3_PNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadDetachEP17_opaque_pthread_tPNS_7SBErrorE", + "_ZN4lldb8SBHostOS13ThreadCreatedEPKc", +}; + +static constexpr llvm::StringRef ClassesWithoutDefaultCtor[] = { + "SBHostOS", + "SBReproducer", +}; + +static constexpr llvm::StringRef ClassesWithoutCopyOperations[] = { + "SBHostOS", + "SBReproducer", + "SBStream", + "SBProgress", +}; + +static constexpr llvm::StringRef MethodsWithPointerPlusLen[] = { + "_ZN4lldb6SBData11ReadRawDataERNS_7SBErrorEyPvm", + "_ZN4lldb6SBData7SetDataERNS_7SBErrorEPKvmNS_9ByteOrderEh", + "_ZN4lldb6SBData20SetDataWithOwnershipERNS_7SBErrorEPKvmNS_9ByteOrderEh", + "_ZN4lldb6SBData25CreateDataFromUInt64ArrayENS_9ByteOrderEjPym", + "_ZN4lldb6SBData25CreateDataFromUInt32ArrayENS_9ByteOrderEjPjm", + "_ZN4lldb6SBData25CreateDataFromSInt64ArrayENS_9ByteOrderEjPxm", + "_ZN4lldb6SBData25CreateDataFromSInt32ArrayENS_9ByteOrderEjPim", + "_ZN4lldb6SBData25CreateDataFromDoubleArrayENS_9ByteOrderEjPdm", + "_ZN4lldb6SBData22SetDataFromUInt64ArrayEPym", + "_ZN4lldb6SBData22SetDataFromUInt32ArrayEPjm", + "_ZN4lldb6SBData22SetDataFromSInt64ArrayEPxm", + "_ZN4lldb6SBData22SetDataFromSInt32ArrayEPim", + "_ZN4lldb6SBData22SetDataFromDoubleArrayEPdm", + "_ZN4lldb10SBDebugger22GetDefaultArchitectureEPcm", + "_ZN4lldb10SBDebugger13DispatchInputEPvPKvm", + "_ZN4lldb10SBDebugger13DispatchInputEPKvm", + "_ZN4lldb6SBFile4ReadEPhmPm", + "_ZN4lldb6SBFile5WriteEPKhmPm", + "_ZNK4lldb10SBFileSpec7GetPathEPcm", + "_ZN4lldb10SBFileSpec11ResolvePathEPKcPcm", + "_ZN4lldb8SBModule10GetVersionEPjj", + "_ZN4lldb12SBModuleSpec12SetUUIDBytesEPKhm", + "_ZNK4lldb9SBProcess9GetSTDOUTEPcm", + "_ZNK4lldb9SBProcess9GetSTDERREPcm", + "_ZNK4lldb9SBProcess19GetAsyncProfileDataEPcm", + "_ZN4lldb9SBProcess10ReadMemoryEyPvmRNS_7SBErrorE", + "_ZN4lldb9SBProcess11WriteMemoryEyPKvmRNS_7SBErrorE", + "_ZN4lldb9SBProcess21ReadCStringFromMemoryEyPvmRNS_7SBErrorE", + "_ZNK4lldb16SBStructuredData14GetStringValueEPcm", + "_ZN4lldb8SBTarget23BreakpointCreateByNamesEPPKcjjRKNS_" + "14SBFileSpecListES6_", + "_ZN4lldb8SBTarget10ReadMemoryENS_9SBAddressEPvmRNS_7SBErrorE", + "_ZN4lldb8SBTarget15GetInstructionsENS_9SBAddressEPKvm", + "_ZN4lldb8SBTarget25GetInstructionsWithFlavorENS_9SBAddressEPKcPKvm", + "_ZN4lldb8SBTarget15GetInstructionsEyPKvm", + "_ZN4lldb8SBTarget25GetInstructionsWithFlavorEyPKcPKvm", + "_ZN4lldb8SBThread18GetStopDescriptionEPcm", + // The below mangled names are used for dummy methods in shell tests + // that test the emitters' output. If you're adding any new mangled names + // from the actual SB API to this list please add them above. + "_ZN4lldb33SBRPC_" + "CHECKCONSTCHARPTRPTRWITHLEN27CheckConstCharPtrPtrWithLenEPPKcm", + "_ZN4lldb19SBRPC_CHECKARRAYPTR13CheckArrayPtrEPPKcm", + "_ZN4lldb18SBRPC_CHECKVOIDPTR12CheckVoidPtrEPvm", +}; + +// These methods should take a connection parameter according to our logic in +// RequiresConnectionParameter() but in the handwritten version they +// don't take a connection. These methods need to have their implementation +// changed but for now, we just have an exception list of functions that will +// never be a given connection parameter. +// +// FIXME: Change the implementation of these methods so that they can be given a +// connection parameter. +static constexpr llvm::StringRef + MethodsThatUnconditionallyDoNotNeedConnection[] = { + "_ZN4lldb16SBBreakpointNameC1ERNS_8SBTargetEPKc", + "_ZN4lldb10SBDebugger7DestroyERS0_", + "_ZN4lldb18SBExecutionContextC1ENS_8SBThreadE", +}; + +// These classes inherit from rpc::ObjectRef directly (as opposed to +// rpc::LocalObjectRef). Changing them from ObjectRef to LocalObjectRef is ABI +// breaking, so we preserve that compatibility here. +// +// lldb-rpc-gen emits classes as LocalObjectRefs by default. +// +// FIXME: Does it matter which one it emits by default? +static constexpr llvm::StringRef ClassesThatInheritFromObjectRef[] = { + "SBAddress", + "SBBreakpointName", + "SBCommandInterpreter", + "SBCommandReturnObject", + "SBError", + "SBExecutionContext", + "SBExpressionOptions", + "SBFileSpec", + "SBFileSpecList", + "SBFormat", + "SBFunction", + "SBHistoricalFrame", + "SBHistoricalLineEntry", + "SBHistoricalLineEntryList", + "SBLineEntry", + "SBStream", + "SBStringList", + "SBStructuredData", + "SBSymbolContext", + "SBSymbolContextList", + "SBTypeMember", + "SBTypeSummaryOptions", + "SBValueList", +}; + +static llvm::StringMap> + ClassName_to_ParameterTypes = { + {"SBLaunchInfo", {"const char *"}}, + {"SBPlatformConnectOptions", {"const char *"}}, + {"SBPlatformShellCommand", {"const char *", "const char *"}}, + {"SBBreakpointList", {"SBTarget"}}, +}; + +QualType lldb_rpc_gen::GetUnderlyingType(QualType T) { + QualType UnderlyingType; + if (T->isPointerType()) + UnderlyingType = T->getPointeeType(); + else if (T->isReferenceType()) + UnderlyingType = T.getNonReferenceType(); + else + UnderlyingType = T; + + return UnderlyingType; +} + +QualType lldb_rpc_gen::GetUnqualifiedUnderlyingType(QualType T) { + QualType UnderlyingType = GetUnderlyingType(T); + return UnderlyingType.getUnqualifiedType(); +} + +std::string lldb_rpc_gen::GetMangledName(ASTContext &Context, + CXXMethodDecl *MDecl) { + std::string Mangled; + llvm::raw_string_ostream MangledStream(Mangled); + + GlobalDecl GDecl; + if (const auto *CtorDecl = dyn_cast(MDecl)) + GDecl = GlobalDecl(CtorDecl, Ctor_Complete); + else if (const auto *DtorDecl = dyn_cast(MDecl)) + GDecl = GlobalDecl(DtorDecl, Dtor_Deleting); + else + GDecl = GlobalDecl(MDecl); + + MangleContext *MC = Context.createMangleContext(); + MC->mangleName(GDecl, MangledStream); + return Mangled; +} + +bool lldb_rpc_gen::TypeIsFromLLDBPrivate(QualType T) { + + auto CheckTypeForLLDBPrivate = [](const Type *Ty) { + if (!Ty) + return false; + const auto *CXXRDecl = Ty->getAsCXXRecordDecl(); + if (!CXXRDecl) + return false; + const auto *NSDecl = + llvm::dyn_cast(CXXRDecl->getDeclContext()); + if (!NSDecl) + return false; + return NSDecl->getName() == "lldb_private"; + }; + + // First, get the underlying type (remove qualifications and strip off any + // pointers/references). Then we'll need to desugar this type. This will + // remove things like typedefs, so instead of seeing "lldb::DebuggerSP" we'll + // actually see something like "std::shared_ptr". + QualType UnqualifiedUnderlyingType = GetUnqualifiedUnderlyingType(T); + const Type *DesugaredType = + UnqualifiedUnderlyingType->getUnqualifiedDesugaredType(); + assert(DesugaredType && "DesugaredType from a valid Type is nullptr!"); + + // Check the type itself. + if (CheckTypeForLLDBPrivate(DesugaredType)) + return true; + + // If that didn't work, it's possible that the type has a template argument + // that is an lldb_private type. + if (const auto *TemplateSDecl = + llvm::dyn_cast_or_null( + DesugaredType->getAsCXXRecordDecl())) { + for (const TemplateArgument &TA : + TemplateSDecl->getTemplateArgs().asArray()) { + if (TA.getKind() != TemplateArgument::Type) + continue; + if (CheckTypeForLLDBPrivate(TA.getAsType().getTypePtr())) + return true; + } + } + return false; +} + +bool lldb_rpc_gen::TypeIsSBClass(QualType T) { + QualType UnqualifiedUnderlyingType = GetUnqualifiedUnderlyingType(T); + const auto *CXXRDecl = UnqualifiedUnderlyingType->getAsCXXRecordDecl(); + if (!CXXRDecl) + return false; // SB Classes are always C++ classes + + return CXXRDecl->getName().starts_with("SB"); +} + +bool lldb_rpc_gen::TypeIsConstCharPtr(QualType T) { + if (!T->isPointerType()) + return false; + + QualType UnderlyingType = T->getPointeeType(); + if (!UnderlyingType.isConstQualified()) + return false; + + // FIXME: We should be able to do `UnderlyingType->isCharType` but that will + // return true for `const uint8_t *` since that is effectively an unsigned + // char pointer. We currently do not support pointers other than `const char + // *` and `const char **`. + return UnderlyingType->isSpecificBuiltinType(BuiltinType::Char_S) || + UnderlyingType->isSpecificBuiltinType(BuiltinType::SChar); +} + +bool lldb_rpc_gen::TypeIsConstCharPtrPtr(QualType T) { + if (!T->isPointerType()) + return false; + + return TypeIsConstCharPtr(T->getPointeeType()); +} + +bool lldb_rpc_gen::TypeIsDisallowedClass(QualType T) { + QualType UUT = GetUnqualifiedUnderlyingType(T); + const auto *CXXRDecl = UUT->getAsCXXRecordDecl(); + if (!CXXRDecl) + return false; + + llvm::StringRef DeclName = CXXRDecl->getName(); + for (const llvm::StringRef DisallowedClass : DisallowedClasses) + if (DeclName == DisallowedClass) + return true; + return false; +} + +bool lldb_rpc_gen::TypeIsCallbackFunctionPointer(QualType T) { + return T->isFunctionPointerType(); +} + +bool lldb_rpc_gen::MethodIsDisallowed(const std::string &MangledName) { + llvm::StringRef MangledNameRef(MangledName); + return llvm::is_contained(DisallowedMethods, MangledNameRef); +} + +bool lldb_rpc_gen::HasCallbackParameter(CXXMethodDecl *MDecl) { + bool HasCallbackParameter = false; + bool HasBatonParameter = false; + auto End = MDecl->parameters().end(); + for (auto Iter = MDecl->parameters().begin(); Iter != End; Iter++) { + if ((*Iter)->getType()->isFunctionPointerType()) { + HasCallbackParameter = true; + continue; + } + + if ((*Iter)->getType()->isVoidPointerType()) + HasBatonParameter = true; + } + + return HasCallbackParameter && HasBatonParameter; +} + +// FIXME: Find a better way to do this. Here is why it is written this way: ---------------- chelcassanova wrote: > I think operating in 2 passes could be a good idea here. If we're ok with having a dependency on `clang-tools-extra`, then we could use the `clang-change-namespace` tool itself after the files have been generated. Otherwise, if we want to reimplement the code from `ChangeNamespace` in `lldb-rpc-gen`, that _looks_ like it should be feasible? Again, I'm just looking at the code from the change namespace stuff but I think it's backed by `Refactoring` in Clang tooling. We already have that dependency, I think the change namespace code is a specific application of `RefactoringTool`. This could be worth pursuing. It's not just that this cuts down on our string replacement function, but this might also be useful for cutting out the [Python scripts](https://github.com/llvm/llvm-project/pull/138028) that we're using to modify the namespaces for the lldb headers. > The key would be to only apply it to the library. Correct. As it is right now, `lldb-rpc-gen` generates all server, client and byproduct code within the same file, I wonder if this lends credence to subtooling this? :) https://github.com/llvm/llvm-project/pull/138031 From lldb-commits at lists.llvm.org Tue May 13 14:58:43 2025 From: lldb-commits at lists.llvm.org (Chelsea Cassanova via lldb-commits) Date: Tue, 13 May 2025 14:58:43 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream Python scripts (PR #138028) In-Reply-To: Message-ID: <6823c093.a70a0220.2633aa.f00c@mx.google.com> ================ @@ -0,0 +1,13 @@ +// Generate a dummy SB API file using lldb-rpc-gen. +# RUN: mkdir -p %t/server +# RUN: mkdir -p %t/lib ---------------- chelcassanova wrote: > I don't see anything that would need job control, I'm wondering if a stray character is causing the shell to think that. It could be the "%" in `RUN: mkdir -p %t/lib`? That itself would be strange since the previous line creates a directory in the same way and the other shell tests here pass in that run 🤔 https://github.com/llvm/llvm-project/pull/138028 From lldb-commits at lists.llvm.org Tue May 13 15:08:30 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Tue, 13 May 2025 15:08:30 -0700 (PDT) Subject: [Lldb-commits] [lldb] [Support] [lldb] Fix thread jump #45326 (PR #135778) In-Reply-To: Message-ID: <6823c2de.630a0220.259617.7e13@mx.google.com> https://github.com/ashgti edited https://github.com/llvm/llvm-project/pull/135778 From lldb-commits at lists.llvm.org Tue May 13 15:08:30 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Tue, 13 May 2025 15:08:30 -0700 (PDT) Subject: [Lldb-commits] [lldb] [Support] [lldb] Fix thread jump #45326 (PR #135778) In-Reply-To: Message-ID: <6823c2de.170a0220.33e4bd.e0d5@mx.google.com> https://github.com/ashgti commented: I'm less familiar with this part of lldb, so I'd defer to others here. https://github.com/llvm/llvm-project/pull/135778 From lldb-commits at lists.llvm.org Tue May 13 15:08:31 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Tue, 13 May 2025 15:08:31 -0700 (PDT) Subject: [Lldb-commits] [lldb] [Support] [lldb] Fix thread jump #45326 (PR #135778) In-Reply-To: Message-ID: <6823c2df.170a0220.17331f.03f1@mx.google.com> ================ @@ -62,6 +65,71 @@ def test(self): substrs=["error"], ) + def test_jump_offset(self): + """Test Thread Jump by negative or positive offset""" + exe = self.getBuildArtifact("a.out") + file_name = "main.cpp" + self.runCmd(f"target create {exe}", CURRENT_EXECUTABLE_SET) + + pos_jump = line_number(file_name, "// jump_offset 1") + neg_jump = line_number(file_name, "// jump_offset 2") + pos_breakpoint = line_number(file_name, "// breakpoint 1") + neg_breakpoint = line_number(file_name, "// breakpoint 2") + pos_jump_offset = pos_jump - pos_breakpoint + neg_jump_offset = neg_jump - neg_breakpoint + + var_1, var_1_value = ("var_1", "10") + var_2, var_2_value = ("var_2", "40") + var_3, var_3_value = ("var_3", "10") + + # create pos_breakpoint and neg_breakpoint + lldbutil.run_break_set_by_file_and_line( + self, file_name, pos_breakpoint, num_expected_locations=1 + ) + lldbutil.run_break_set_by_file_and_line( + self, file_name, neg_breakpoint, num_expected_locations=1 + ) + + self.runCmd("run", RUN_SUCCEEDED) + + # test positive jump + # The stop reason of the thread should be breakpoint 1. + self.expect( + "thread list", + STOPPED_DUE_TO_BREAKPOINT + " 1", + substrs=[ + "stopped", + f"{file_name}:{pos_breakpoint}", + "stop reason = breakpoint 1", + ], + ) + + self.runCmd(f"thread jump --by +{pos_jump_offset}") ---------------- ashgti wrote: If the `+` prefix is optional, should we also test that this works without the prefix? https://github.com/llvm/llvm-project/pull/135778 From lldb-commits at lists.llvm.org Tue May 13 15:08:32 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Tue, 13 May 2025 15:08:32 -0700 (PDT) Subject: [Lldb-commits] [lldb] [Support] [lldb] Fix thread jump #45326 (PR #135778) In-Reply-To: Message-ID: <6823c2e0.050a0220.1a878f.01fb@mx.google.com> ================ @@ -1649,11 +1649,14 @@ class CommandObjectThreadJump : public CommandObjectParsed { return Status::FromErrorStringWithFormat("invalid line number: '%s'.", option_arg.str().c_str()); break; - case 'b': + case 'b': { + option_arg.consume_front("+"); ---------------- ashgti wrote: Should this be documented that an optional `+` can be specified? https://github.com/llvm/llvm-project/pull/135778 From lldb-commits at lists.llvm.org Tue May 13 15:27:23 2025 From: lldb-commits at lists.llvm.org (Chelsea Cassanova via lldb-commits) Date: Tue, 13 May 2025 15:27:23 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream Python scripts (PR #138028) In-Reply-To: Message-ID: <6823c74b.170a0220.8749f.efa4@mx.google.com> ================ @@ -0,0 +1,18 @@ +// Copy lldb-rpc-defines.h from source. +# RUN: mkdir -p %t/input +# RUN: mkdir -p %t/output +# RUN: cp %p/../../../../../include/lldb/lldb-defines.h %t/input + +// Run the convert script on it, then run the framework include fix on it. The framework version fix script +// expects that all lldb references have been renamed to lldb-rpc in order for it to modify the includes +// to go into the framework. +# RUN: %python %p/../../../../../scripts/convert-lldb-header-to-rpc-header.py %t/input/lldb-defines.h %t/output/lldb-rpc-defines.h +# RUN: %python %p/../../../../../scripts/framework-header-version-fix.py %t/output/lldb-rpc-defines.h %t/output/lldb-rpc-defines.h 17 0 0 + +// Check the output +# RUN: cat %t/output/lldb-rpc-defines.h | FileCheck %s + +// The LLDB version defines must be uncommented and filled in with the values passed into the script. +# CHECK: #define LLDB_RPC_VERSION 17 +# CHECK: #define LLDB_RPC_REVISION 0 +# CHECK: #define LLDB_RPC_VERSION_STRING "17.0.0" ---------------- chelcassanova wrote: This did in fact pass when checking lines that have been commented, I'll fix this. https://github.com/llvm/llvm-project/pull/138028 From lldb-commits at lists.llvm.org Tue May 13 15:30:31 2025 From: lldb-commits at lists.llvm.org (Chelsea Cassanova via lldb-commits) Date: Tue, 13 May 2025 15:30:31 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream Python scripts (PR #138028) In-Reply-To: Message-ID: <6823c807.a70a0220.218476.2780@mx.google.com> ================ @@ -0,0 +1,13 @@ +// Generate a dummy SB API file using lldb-rpc-gen. +# RUN: mkdir -p %t/server +# RUN: mkdir -p %t/lib ---------------- chelcassanova wrote: I just checked on macOS and got the same error. The error is a bit misleading, it's actually happening because I'm using `%lldb-rpc-gen` which expects that this binary exists in the build which it doesn't (since the tool hasn't landed yet). If you're ok it, I can XFAIL this test until the `lldb-rpc-gen` itself lands: https://github.com/llvm/llvm-project/pull/138031 https://github.com/llvm/llvm-project/pull/138028 From lldb-commits at lists.llvm.org Tue May 13 15:39:40 2025 From: lldb-commits at lists.llvm.org (Chelsea Cassanova via lldb-commits) Date: Tue, 13 May 2025 15:39:40 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream Python scripts (PR #138028) In-Reply-To: Message-ID: <6823ca2c.170a0220.2d63e7.0493@mx.google.com> https://github.com/chelcassanova updated https://github.com/llvm/llvm-project/pull/138028 >From a00c76df4467c85a7436fc340c79d0a15ab6231a Mon Sep 17 00:00:00 2001 From: Chelsea Cassanova Date: Wed, 30 Apr 2025 13:37:15 -0700 Subject: [PATCH] [lldb][RPC] Upstream Python scripts As part of upstreaming LLDB RPC, this commit adds python scripts that are used by LLDB RPC to modify the public lldb header files for use with RPC. https://discourse.llvm.org/t/rfc-upstreaming-lldb-rpc/85804 --- .../convert-lldb-header-to-rpc-header.py | 65 +++++++++++++++++++ lldb/scripts/framework-header-include-fix.py | 43 ++++++++++++ lldb/scripts/framework-header-version-fix.py | 65 +++++++++++++++++++ .../TestConvertScript/CheckLLDBDefines.test | 20 ++++++ .../CheckLLDBEnumerations.test | 23 +++++++ .../TestConvertScript/CheckLLDBTypes.test | 26 ++++++++ .../TestConvertScript/CheckSBDefines.test | 22 +++++++ .../CheckLLDBDefines.test | 16 +++++ .../CheckLLDBTypes.test | 16 +++++ .../CheckSBClass.test | 15 +++++ .../CheckSBDefines.test | 18 +++++ .../Inputs/SBRPC-FrameworkFix.h | 13 ++++ .../CheckLLDBDefines.test | 18 +++++ 13 files changed, 360 insertions(+) create mode 100755 lldb/scripts/convert-lldb-header-to-rpc-header.py create mode 100755 lldb/scripts/framework-header-include-fix.py create mode 100755 lldb/scripts/framework-header-version-fix.py create mode 100644 lldb/test/Shell/RPC/Scripts/TestConvertScript/CheckLLDBDefines.test create mode 100644 lldb/test/Shell/RPC/Scripts/TestConvertScript/CheckLLDBEnumerations.test create mode 100644 lldb/test/Shell/RPC/Scripts/TestConvertScript/CheckLLDBTypes.test create mode 100644 lldb/test/Shell/RPC/Scripts/TestConvertScript/CheckSBDefines.test create mode 100644 lldb/test/Shell/RPC/Scripts/TestFrameworkIncludeFixScript/CheckLLDBDefines.test create mode 100644 lldb/test/Shell/RPC/Scripts/TestFrameworkIncludeFixScript/CheckLLDBTypes.test create mode 100644 lldb/test/Shell/RPC/Scripts/TestFrameworkIncludeFixScript/CheckSBClass.test create mode 100644 lldb/test/Shell/RPC/Scripts/TestFrameworkIncludeFixScript/CheckSBDefines.test create mode 100644 lldb/test/Shell/RPC/Scripts/TestFrameworkIncludeFixScript/Inputs/SBRPC-FrameworkFix.h create mode 100644 lldb/test/Shell/RPC/Scripts/TestVersionFixScript/CheckLLDBDefines.test diff --git a/lldb/scripts/convert-lldb-header-to-rpc-header.py b/lldb/scripts/convert-lldb-header-to-rpc-header.py new file mode 100755 index 0000000000000..fe23ef029dcf1 --- /dev/null +++ b/lldb/scripts/convert-lldb-header-to-rpc-header.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +# Usage: convert-lldb-header-to-rpc-header.py +# This scripts takes common LLDB headers (such as lldb-defines.h) and replaces references to LLDB +# with those for RPC. This happens for: +# - namespace definitions +# - namespace usage +# - version string macros +# - ifdef/ifndef lines + +import argparse +import os +import re + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("input") + parser.add_argument("output") + args = parser.parse_args() + input_path = str(args.input) + output_path = str(args.output) + with open(input_path, "r") as input_file: + lines = input_file.readlines() + + with open(output_path, "w") as output_file: + for line in lines: + # NOTE: We do not use lldb-forward.h or lldb-versioning.h in RPC, so remove + # all includes that are found for these files. + if re.match( + r'#include "lldb/lldb-forward|#include "lldb/lldb-versioning', line + ): + continue + # For lldb-rpc-defines.h, replace the ifndef LLDB_LLDB_ portion with LLDB_RPC_ as we're not + # using LLDB private definitions in RPC. + elif re.match(r".+LLDB_LLDB_", line): + output_file.write(re.sub(r"LLDB_LLDB_", r"LLDB_RPC_", line)) + # Similarly to lldb-rpc-defines.h, replace the ifndef for LLDB_API in SBDefines.h to LLDB_RPC_API_ for the same reason. + elif re.match(r".+LLDB_API_", line): + output_file.write(re.sub(r"LLDB_API_", r"LLDB_RPC_API_", line)) + # Replace the references for the macros that define the versioning strings in + # lldb-rpc-defines.h. + elif re.match(r".+LLDB_VERSION", line): + output_file.write(re.sub(r"LLDB_VERSION", r"LLDB_RPC_VERSION", line)) + elif re.match(r".+LLDB_REVISION", line): + output_file.write(re.sub(r"LLDB_REVISION", r"LLDB_RPC_REVISION", line)) + elif re.match(r".+LLDB_VERSION_STRING", line): + output_file.write( + re.sub(r"LLDB_VERSION_STRING", r"LLDB_RPC_VERSION_STRING", line) + ) + # For local #includes + elif re.match(r'#include "lldb/lldb-', line): + output_file.write(re.sub(r"lldb/lldb-", r"lldb-rpc-", line)) + # Rename the lldb namespace definition to lldb-rpc. + elif re.match(r".*namespace lldb", line): + output_file.write(re.sub(r"lldb", r"lldb_rpc", line)) + # Rename namespace references + elif re.match(r".+lldb::", line): + output_file.write(re.sub(r"lldb::", r"lldb_rpc::", line)) + else: + # Write any line that doesn't need to be converted + output_file.write(line) + + +if __name__ == "__main__": + main() diff --git a/lldb/scripts/framework-header-include-fix.py b/lldb/scripts/framework-header-include-fix.py new file mode 100755 index 0000000000000..4c3a6d2e14366 --- /dev/null +++ b/lldb/scripts/framework-header-include-fix.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# Usage: framework-header-include-fix.py +# This script modifies all #include lines in all lldb-rpc headers +# from either filesystem or local includes to liblldbrpc includes. + +import argparse +import os +import re + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("input") + parser.add_argument("output") + args = parser.parse_args() + input_path = str(args.input) + output_path = str(args.output) + with open(input_path, "r") as input_file: + lines = input_file.readlines() + + with open(output_path, "w") as output_file: + for line in lines: + # Replace includes from RPCCommon to liblldbrpc includes. + # e.g. #include -> #include + if re.match(r".+ #include + elif include_filename := re.match(r'#include "(.*)"', line): + output_file.write( + re.sub( + r'#include "(.*)"', + r"#include ", + line, + ) + ) + else: + # Write any line that doesn't need to be converted + output_file.write(line) + + +if __name__ == "__main__": + main() diff --git a/lldb/scripts/framework-header-version-fix.py b/lldb/scripts/framework-header-version-fix.py new file mode 100755 index 0000000000000..72185f8e820ce --- /dev/null +++ b/lldb/scripts/framework-header-version-fix.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +# Usage: framework-header-version-fix.py MAJOR MINOR PATCH +# This script modifies lldb-rpc-defines.h to uncomment the macro defines used for the LLDB +# major, minor and patch values as well as populating their definitions. + +import argparse +import os +import re + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("input") + parser.add_argument("output") + parser.add_argument("lldb_version_major") + parser.add_argument("lldb_version_minor") + parser.add_argument("lldb_version_patch") + args = parser.parse_args() + input_path = str(args.input) + output_path = str(args.output) + lldb_version_major = args.lldb_version_major + lldb_version_minor = args.lldb_version_minor + lldb_version_patch = args.lldb_version_patch + + with open(input_path, "r") as input_file: + lines = input_file.readlines() + + with open(output_path, "w") as output_file: + for line in lines: + # Uncomment the line that defines the LLDB major version and populate its value. + if re.match(r"//#define LLDB_RPC_VERSION$", line): + output_file.write( + re.sub( + r"//#define LLDB_RPC_VERSION", + r"#define LLDB_RPC_VERSION " + lldb_version_major, + line, + ) + ) + # Uncomment the line that defines the LLDB minor version and populate its value. + elif re.match(r"//#define LLDB_RPC_REVISION$", line): + output_file.write( + re.sub( + r"//#define LLDB_RPC_REVISION", + r"#define LLDB_RPC_REVISION " + lldb_version_minor, + line, + ) + ) + # Uncomment the line that defines the complete LLDB version string and populate its value. + elif re.match(r"//#define LLDB_RPC_VERSION_STRING$", line): + output_file.write( + re.sub( + r"//#define LLDB_RPC_VERSION_STRING", + r'#define LLDB_RPC_VERSION_STRING "{0}.{1}.{2}"'.format( + lldb_version_major, lldb_version_minor, lldb_version_patch + ), + line, + ) + ) + else: + # Write any line that doesn't need to be converted + output_file.write(line) + + +if __name__ == "__main__": + main() diff --git a/lldb/test/Shell/RPC/Scripts/TestConvertScript/CheckLLDBDefines.test b/lldb/test/Shell/RPC/Scripts/TestConvertScript/CheckLLDBDefines.test new file mode 100644 index 0000000000000..bd85eaa823230 --- /dev/null +++ b/lldb/test/Shell/RPC/Scripts/TestConvertScript/CheckLLDBDefines.test @@ -0,0 +1,20 @@ +// Copy lldb-defines.h from source. +# RUN: mkdir -p %t/input +# RUN: mkdir -p %t/output +# RUN: cp %p/../../../../../include/lldb/lldb-defines.h %t/input + +// Run the convert script on it. +# RUN: %python %p/../../../../../scripts/convert-lldb-header-to-rpc-header.py %t/input/lldb-defines.h %t/output/lldb-rpc-defines.h + +// Check the output +# RUN: cat %t/output/lldb-rpc-defines.h | FileCheck %s + +// The include guards must change from LLDB_LLDB_DEFINES_H to LLDB_RPC_DEFINES_H. +# CHECK: #ifndef LLDB_RPC_DEFINES_H +# CHECK: #define LLDB_RPC_DEFINES_H + +// Includes of other lldb headers must begin with "lldb-rpc-". +# CHECK: #include "lldb-rpc-types.h" + +// The comment that closes the include guard should match the guard. +# CHECK: #endif // LLDB_RPC_DEFINES_H diff --git a/lldb/test/Shell/RPC/Scripts/TestConvertScript/CheckLLDBEnumerations.test b/lldb/test/Shell/RPC/Scripts/TestConvertScript/CheckLLDBEnumerations.test new file mode 100644 index 0000000000000..285072a7673f9 --- /dev/null +++ b/lldb/test/Shell/RPC/Scripts/TestConvertScript/CheckLLDBEnumerations.test @@ -0,0 +1,23 @@ +// Copy lldb-enumerations.h from source. +# RUN: mkdir -p %t/input +# RUN: mkdir -p %t/output +# RUN: cp %p/../../../../../include/lldb/lldb-enumerations.h %t/input + +// Run the convert script on it. +# RUN: %python %p/../../../../../scripts/convert-lldb-header-to-rpc-header.py %t/input/lldb-enumerations.h %t/output/lldb-rpc-enumerations.h + +// Check the output +# RUN: cat %t/output/lldb-rpc-enumerations.h | FileCheck %s + +// The include guards must change from LLDB_LLDB_ENUMERATIONS_H to LLDB_RPC_ENUMERATIONS_H. +# CHECK: #ifndef LLDB_RPC_ENUMERATIONS_H +# CHECK: #define LLDB_RPC_ENUMERATIONS_H + +// Change the namespace to lldb_rpc. +# CHECK: namespace lldb_rpc + +// The comment that closes the namespace should match the namespace. +# CHECK: // namespace lldb_rpc + +// The comment that closes the include guard should match the guard. +# CHECK: #endif // LLDB_RPC_ENUMERATIONS_H diff --git a/lldb/test/Shell/RPC/Scripts/TestConvertScript/CheckLLDBTypes.test b/lldb/test/Shell/RPC/Scripts/TestConvertScript/CheckLLDBTypes.test new file mode 100644 index 0000000000000..3641195babeab --- /dev/null +++ b/lldb/test/Shell/RPC/Scripts/TestConvertScript/CheckLLDBTypes.test @@ -0,0 +1,26 @@ +// Copy lldb-types.h from source. +# RUN: mkdir -p %t/input +# RUN: mkdir -p %t/output +# RUN: cp %p/../../../../../include/lldb/lldb-types.h %t/input + +// Run the convert script on it. +# RUN: %python %p/../../../../../scripts/convert-lldb-header-to-rpc-header.py %t/input/lldb-types.h %t/output/lldb-rpc-types.h + +// Check the output +# RUN: cat %t/output/lldb-rpc-types.h | FileCheck %s + +// The include guards must change from LLDB_LLDB_ENUMERATIONS_H to LLDB_RPC_ENUMERATIONS_H. +# CHECK: #ifndef LLDB_RPC_TYPES_H +# CHECK: #define LLDB_RPC_TYPES_H + +// Includes of other lldb headers must begin with "lldb-rpc-". +# CHECK: #include "lldb-rpc-enumerations.h" + +// Change the namespace to lldb_rpc. +# CHECK: namespace lldb_rpc + +// The comment that closes the namespace should match the namespace. +# CHECK: // namespace lldb_rpc + +// The comment that closes the include guard should match the guard. +# CHECK: #endif // LLDB_RPC_TYPES_H diff --git a/lldb/test/Shell/RPC/Scripts/TestConvertScript/CheckSBDefines.test b/lldb/test/Shell/RPC/Scripts/TestConvertScript/CheckSBDefines.test new file mode 100644 index 0000000000000..39cd7a954c554 --- /dev/null +++ b/lldb/test/Shell/RPC/Scripts/TestConvertScript/CheckSBDefines.test @@ -0,0 +1,22 @@ +// Copy SBDefines.h from source. +# RUN: mkdir -p %t/input +# RUN: mkdir -p %t/output +# RUN: cp %p/../../../../../include/lldb/API/SBDefines.h %t/input + +// Run the convert script on it. +# RUN: %python %p/../../../../../scripts/convert-lldb-header-to-rpc-header.py %t/input/SBDefines.h %t/output/SBDefines.h + +// Check the output +# RUN: cat %t/output/SBDefines.h | FileCheck %s + +// The include guards must change from LLDB_LLDB_API_SBDEFINES_H to LLDB_RPC_API_SBDEFINES_H. +# CHECK: #ifndef LLDB_RPC_API_SBDEFINES_H +# CHECK: #define LLDB_RPC_API_SBDEFINES_H + +// Includes of other lldb headers must begin with "lldb-rpc-". +# CHECK: #include "lldb-rpc-defines.h" +# CHECK: #include "lldb-rpc-enumerations.h" +# CHECK: #include "lldb-rpc-types.h" + +// The comment that closes the include guard should match the guard. +# CHECK: #endif // LLDB_RPC_API_SBDEFINES_H diff --git a/lldb/test/Shell/RPC/Scripts/TestFrameworkIncludeFixScript/CheckLLDBDefines.test b/lldb/test/Shell/RPC/Scripts/TestFrameworkIncludeFixScript/CheckLLDBDefines.test new file mode 100644 index 0000000000000..b2e25f7a70eae --- /dev/null +++ b/lldb/test/Shell/RPC/Scripts/TestFrameworkIncludeFixScript/CheckLLDBDefines.test @@ -0,0 +1,16 @@ +// Copy lldb-rpc-defines.h from source. +# RUN: mkdir -p %t/input +# RUN: mkdir -p %t/output +# RUN: cp %p/../../../../../include/lldb/lldb-defines.h %t/input + +// Run the convert script on it, then run the framework include fix on it. The framework include fix script +// expects that all lldb references have been renamed to lldb-rpc in order for it to modify the includes +// to go into the framework. +# RUN: %python %p/../../../../../scripts/convert-lldb-header-to-rpc-header.py %t/input/lldb-defines.h %t/output/lldb-rpc-defines.h +# RUN: %python %p/../../../../../scripts/framework-header-include-fix.py %t/output/lldb-rpc-defines.h %t/output/lldb-rpc-defines.h + +// Check the output +# RUN: cat %t/output/lldb-rpc-defines.h | FileCheck %s + +// Local includes for LLDB RPC headers must be changed for the framework. +# CHECK: #include diff --git a/lldb/test/Shell/RPC/Scripts/TestFrameworkIncludeFixScript/CheckLLDBTypes.test b/lldb/test/Shell/RPC/Scripts/TestFrameworkIncludeFixScript/CheckLLDBTypes.test new file mode 100644 index 0000000000000..7da7c6ad80ac5 --- /dev/null +++ b/lldb/test/Shell/RPC/Scripts/TestFrameworkIncludeFixScript/CheckLLDBTypes.test @@ -0,0 +1,16 @@ +// Copy lldb-rpc-types.h from source. +# RUN: mkdir -p %t/input +# RUN: mkdir -p %t/output +# RUN: cp %p/../../../../../include/lldb/lldb-types.h %t/input + +// Run the convert script on it, then run the framework include fix on it. The framework include fix script +// expects that all lldb references have been renamed to lldb-rpc in order for it to modify the includes +// to go into the framework. +# RUN: %python %p/../../../../../scripts/convert-lldb-header-to-rpc-header.py %t/input/lldb-types.h %t/output/lldb-rpc-types.h +# RUN: %python %p/../../../../../scripts/framework-header-include-fix.py %t/output/lldb-rpc-types.h %t/output/lldb-rpc-types.h + +// Check the output +# RUN: cat %t/output/lldb-rpc-types.h | FileCheck %s + +// Local includes for LLDB RPC headers must be changed for the framework. +# CHECK: #include diff --git a/lldb/test/Shell/RPC/Scripts/TestFrameworkIncludeFixScript/CheckSBClass.test b/lldb/test/Shell/RPC/Scripts/TestFrameworkIncludeFixScript/CheckSBClass.test new file mode 100644 index 0000000000000..3326ee899a078 --- /dev/null +++ b/lldb/test/Shell/RPC/Scripts/TestFrameworkIncludeFixScript/CheckSBClass.test @@ -0,0 +1,15 @@ +// Disabling until the lldb-rpc-gen tool itself lands. +# XFAIL: * +// Generate a dummy SB API file using lldb-rpc-gen. +# RUN: mkdir -p %t/server +# RUN: mkdir -p %t/lib +# RUN: %lldb-rpc-gen --output-dir=%t %S/Inputs/SBRPC-FrameworkFix.h + +# RUN: %python %p/../../../../../scripts/framework-header-include-fix.py %t/lib/SBRPC-FrameworkFix.h %t/lib/SBRPC-FrameworkFix.h + +// Check the output +# RUN: cat %t/lib/SBRPC-FrameworkFix.h | FileCheck %s + +# CHECK: #include +# CHECK: #include +# CHECK: #include diff --git a/lldb/test/Shell/RPC/Scripts/TestFrameworkIncludeFixScript/CheckSBDefines.test b/lldb/test/Shell/RPC/Scripts/TestFrameworkIncludeFixScript/CheckSBDefines.test new file mode 100644 index 0000000000000..6dee17232aee7 --- /dev/null +++ b/lldb/test/Shell/RPC/Scripts/TestFrameworkIncludeFixScript/CheckSBDefines.test @@ -0,0 +1,18 @@ +// Copy SBDefines.h from source. +# RUN: mkdir -p %t/input +# RUN: mkdir -p %t/output +# RUN: cp %p/../../../../../include/lldb/API/SBDefines.h %t/input + +// Run the convert script on it, then run the framework include fix on it. The framework include fix script +// expects that all lldb references have been renamed to lldb-rpc in order for it to modify the includes +// to go into the framework. +# RUN: %python %p/../../../../../scripts/convert-lldb-header-to-rpc-header.py %t/input/SBDefines.h %t/output/SBDefines.h +# RUN: %python %p/../../../../../scripts/framework-header-include-fix.py %t/output/SBDefines.h %t/output/SBDefines.h + +// Check the output +# RUN: cat %t/output/SBDefines.h | FileCheck %s + +// Local includes for LLDB RPC headers must be changed for the framework. +# CHECK: #include +# CHECK: #include +# CHECK: #include diff --git a/lldb/test/Shell/RPC/Scripts/TestFrameworkIncludeFixScript/Inputs/SBRPC-FrameworkFix.h b/lldb/test/Shell/RPC/Scripts/TestFrameworkIncludeFixScript/Inputs/SBRPC-FrameworkFix.h new file mode 100644 index 0000000000000..39cf490737293 --- /dev/null +++ b/lldb/test/Shell/RPC/Scripts/TestFrameworkIncludeFixScript/Inputs/SBRPC-FrameworkFix.h @@ -0,0 +1,13 @@ +#ifndef LLDB_API_SBRPC_FRAMEWORKINCLUDEFIX_H +#define LLDB_API_SBRPC_FRAMEWORKINCLUDEFIX_H + +// The includes for local SB API files and RPC common files +// must be changed to become framework includes. +// They're commented out so that the tool doesn't actually +// try and locate these files. + +// #include +// #include "SBDefines.h" +// #include "LLDBRPC.h" + +#endif // LLDB_API_SBRPC_FRAMEWORKINCLUDEFIX_H diff --git a/lldb/test/Shell/RPC/Scripts/TestVersionFixScript/CheckLLDBDefines.test b/lldb/test/Shell/RPC/Scripts/TestVersionFixScript/CheckLLDBDefines.test new file mode 100644 index 0000000000000..e88a9ef305de1 --- /dev/null +++ b/lldb/test/Shell/RPC/Scripts/TestVersionFixScript/CheckLLDBDefines.test @@ -0,0 +1,18 @@ +// Copy lldb-rpc-defines.h from source. +# RUN: mkdir -p %t/input +# RUN: mkdir -p %t/output +# RUN: cp %p/../../../../../include/lldb/lldb-defines.h %t/input + +// Run the convert script on it, then run the framework include fix on it. The framework version fix script +// expects that all lldb references have been renamed to lldb-rpc in order for it to modify the includes +// to go into the framework. +# RUN: %python %p/../../../../../scripts/convert-lldb-header-to-rpc-header.py %t/input/lldb-defines.h %t/output/lldb-rpc-defines.h +# RUN: %python %p/../../../../../scripts/framework-header-version-fix.py %t/output/lldb-rpc-defines.h %t/output/lldb-rpc-defines.h 17 0 0 + +// Check the output +# RUN: cat %t/output/lldb-rpc-defines.h | FileCheck %s + +// The LLDB version defines must be uncommented and filled in with the values passed into the script. +# CHECK: {{^}}#define LLDB_RPC_VERSION 17 +# CHECK: {{^}}#define LLDB_RPC_REVISION 0 +# CHECK: {{^}}#define LLDB_RPC_VERSION_STRING "17.0.0" From lldb-commits at lists.llvm.org Tue May 13 15:48:18 2025 From: lldb-commits at lists.llvm.org (Chelsea Cassanova via lldb-commits) Date: Tue, 13 May 2025 15:48:18 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream Python scripts (PR #138028) In-Reply-To: Message-ID: <6823cc32.630a0220.2e524d.9deb@mx.google.com> chelcassanova wrote: @DavidSpickett I pushed here to address most of the outstanding changes I needed to make from your comments, and this change should also fix the CI issue on BuildKite. Could you give this patch another pass over? https://github.com/llvm/llvm-project/pull/138028 From lldb-commits at lists.llvm.org Tue May 13 15:48:27 2025 From: lldb-commits at lists.llvm.org (Chelsea Cassanova via lldb-commits) Date: Tue, 13 May 2025 15:48:27 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream Python scripts (PR #138028) In-Reply-To: Message-ID: <6823cc3b.170a0220.3dc054.0386@mx.google.com> https://github.com/chelcassanova closed https://github.com/llvm/llvm-project/pull/138028 From lldb-commits at lists.llvm.org Tue May 13 15:48:41 2025 From: lldb-commits at lists.llvm.org (Chelsea Cassanova via lldb-commits) Date: Tue, 13 May 2025 15:48:41 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream Python scripts (PR #138028) In-Reply-To: Message-ID: <6823cc49.a70a0220.d74e1.0433@mx.google.com> https://github.com/chelcassanova reopened https://github.com/llvm/llvm-project/pull/138028 From lldb-commits at lists.llvm.org Tue May 13 15:48:54 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Tue, 13 May 2025 15:48:54 -0700 (PDT) Subject: [Lldb-commits] [lldb] cc2bedd - [lldb] Use std:::string::find with std::string_view (NFC) (#139679) Message-ID: <6823cc56.170a0220.215e7c.f5bb@mx.google.com> Author: Kazu Hirata Date: 2025-05-13T15:48:50-07:00 New Revision: cc2beddaa44fb1f0e0ca9eb51c5feaca368c00b0 URL: https://github.com/llvm/llvm-project/commit/cc2beddaa44fb1f0e0ca9eb51c5feaca368c00b0 DIFF: https://github.com/llvm/llvm-project/commit/cc2beddaa44fb1f0e0ca9eb51c5feaca368c00b0.diff LOG: [lldb] Use std:::string::find with std::string_view (NFC) (#139679) std::string::find accepts anything that can be converted to std::string_view starting in C++17. Since StringRef can be converted to std::string_view, we do not need to create a temporary instance of std::string here. Added: Modified: lldb/source/Interpreter/Options.cpp Removed: ################################################################################ diff --git a/lldb/source/Interpreter/Options.cpp b/lldb/source/Interpreter/Options.cpp index fdadba62987d3..4cf68db466158 100644 --- a/lldb/source/Interpreter/Options.cpp +++ b/lldb/source/Interpreter/Options.cpp @@ -1076,7 +1076,7 @@ llvm::Expected Options::ParseAlias(const Args &args, if (!input_line.empty()) { llvm::StringRef tmp_arg = args_copy[idx].ref(); - size_t pos = input_line.find(std::string(tmp_arg)); + size_t pos = input_line.find(tmp_arg); if (pos != std::string::npos) input_line.erase(pos, tmp_arg.size()); } From lldb-commits at lists.llvm.org Tue May 13 15:48:57 2025 From: lldb-commits at lists.llvm.org (Kazu Hirata via lldb-commits) Date: Tue, 13 May 2025 15:48:57 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use std:::string::find with std::string_view (NFC) (PR #139679) In-Reply-To: Message-ID: <6823cc59.170a0220.fe896.0537@mx.google.com> https://github.com/kazutakahirata closed https://github.com/llvm/llvm-project/pull/139679 From lldb-commits at lists.llvm.org Tue May 13 15:51:24 2025 From: lldb-commits at lists.llvm.org (Dave Lee via lldb-commits) Date: Tue, 13 May 2025 15:51:24 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Fix ForwardListFrontEnd::CalculateNumChildren (PR #139805) Message-ID: https://github.com/kastiglione created https://github.com/llvm/llvm-project/pull/139805 Fixes the calculation of the number of children for `std::forward_list` to no longer be capped. The calculation was capped by the value of `target.max-children-count`. This resulted in at least the following problems: 1. The summary formatter would display the incorrect size when the size was greater than `max-child-count`. 2. The elision marker (`...`) would not be shown when the number of elements was greater than `max-child-count`. >From beeb0d9d29e098e4a7063541f657e4ec65db285d Mon Sep 17 00:00:00 2001 From: Dave Lee Date: Tue, 13 May 2025 15:45:44 -0700 Subject: [PATCH] [lldb] Fix ForwardListFrontEnd::CalculateNumChildren Fixes the calculation of the number of children for `std::forward_list` to no longer be capped. The calculation was capped by the value of `target.max-children-count`. This resulted in at least the following problems: 1. The summary formatter would display the incorrect size when the size was greater than `max-child-count`. 2. The elision marker (`...`) would not be shown when the number of elements was greater than `max-child-count`. --- lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp | 2 +- .../TestDataFormatterGenericForwardList.py | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp index 30db5f15c388f..e3c200da6a0f5 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp @@ -251,7 +251,7 @@ llvm::Expected ForwardListFrontEnd::CalculateNumChildren() { ListEntry current(m_head); m_count = 0; - while (current && m_count < m_list_capping_size) { + while (current) { ++m_count; current = current.next(); } diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/TestDataFormatterGenericForwardList.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/TestDataFormatterGenericForwardList.py index 185a24cf6dce3..1639d7275b407 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/TestDataFormatterGenericForwardList.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/TestDataFormatterGenericForwardList.py @@ -53,13 +53,14 @@ def do_test(self, stdlib_type): substrs=["target.max-children-count (unsigned) = 256"], ) + self.runCmd("settings set target.max-children-count 256", check=False) self.expect( "frame variable thousand_elts", matching=False, - substrs=["[256]", "[333]", "[444]", "[555]", "[666]", "..."], + substrs=["[256]", "[333]", "[444]", "[555]", "[666]"], ) - self.runCmd("settings set target.max-children-count 3", check=False) + self.runCmd("settings set target.max-children-count 3", check=False) self.expect( "frame variable thousand_elts", matching=False, @@ -73,7 +74,7 @@ def do_test(self, stdlib_type): self.expect( "frame variable thousand_elts", matching=True, - substrs=["size=256", "[0]", "[1]", "[2]", "..."], + substrs=["size=1000", "[0]", "[1]", "[2]", "..."], ) def do_test_ptr_and_ref(self, stdlib_type): @@ -138,7 +139,7 @@ def do_test_ptr_and_ref(self, stdlib_type): "frame variable ref", matching=True, substrs=[ - "size=256", + "size=1000", "[0] = 999", "[1] = 998", "[2] = 997", @@ -149,7 +150,7 @@ def do_test_ptr_and_ref(self, stdlib_type): "frame variable *ptr", matching=True, substrs=[ - "size=256", + "size=1000", "[0] = 999", "[1] = 998", "[2] = 997", From lldb-commits at lists.llvm.org Tue May 13 15:51:58 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Tue, 13 May 2025 15:51:58 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Fix ForwardListFrontEnd::CalculateNumChildren (PR #139805) In-Reply-To: Message-ID: <6823cd0e.170a0220.1e7264.05f1@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Dave Lee (kastiglione)
Changes Fixes the calculation of the number of children for `std::forward_list` to no longer be capped. The calculation was capped by the value of `target.max-children-count`. This resulted in at least the following problems: 1. The summary formatter would display the incorrect size when the size was greater than `max-child-count`. 2. The elision marker (`...`) would not be shown when the number of elements was greater than `max-child-count`. --- Full diff: https://github.com/llvm/llvm-project/pull/139805.diff 2 Files Affected: - (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp (+1-1) - (modified) lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/TestDataFormatterGenericForwardList.py (+6-5) ``````````diff diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp index 30db5f15c388f..e3c200da6a0f5 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp @@ -251,7 +251,7 @@ llvm::Expected ForwardListFrontEnd::CalculateNumChildren() { ListEntry current(m_head); m_count = 0; - while (current && m_count < m_list_capping_size) { + while (current) { ++m_count; current = current.next(); } diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/TestDataFormatterGenericForwardList.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/TestDataFormatterGenericForwardList.py index 185a24cf6dce3..1639d7275b407 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/TestDataFormatterGenericForwardList.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/TestDataFormatterGenericForwardList.py @@ -53,13 +53,14 @@ def do_test(self, stdlib_type): substrs=["target.max-children-count (unsigned) = 256"], ) + self.runCmd("settings set target.max-children-count 256", check=False) self.expect( "frame variable thousand_elts", matching=False, - substrs=["[256]", "[333]", "[444]", "[555]", "[666]", "..."], + substrs=["[256]", "[333]", "[444]", "[555]", "[666]"], ) - self.runCmd("settings set target.max-children-count 3", check=False) + self.runCmd("settings set target.max-children-count 3", check=False) self.expect( "frame variable thousand_elts", matching=False, @@ -73,7 +74,7 @@ def do_test(self, stdlib_type): self.expect( "frame variable thousand_elts", matching=True, - substrs=["size=256", "[0]", "[1]", "[2]", "..."], + substrs=["size=1000", "[0]", "[1]", "[2]", "..."], ) def do_test_ptr_and_ref(self, stdlib_type): @@ -138,7 +139,7 @@ def do_test_ptr_and_ref(self, stdlib_type): "frame variable ref", matching=True, substrs=[ - "size=256", + "size=1000", "[0] = 999", "[1] = 998", "[2] = 997", @@ -149,7 +150,7 @@ def do_test_ptr_and_ref(self, stdlib_type): "frame variable *ptr", matching=True, substrs=[ - "size=256", + "size=1000", "[0] = 999", "[1] = 998", "[2] = 997", ``````````
https://github.com/llvm/llvm-project/pull/139805 From lldb-commits at lists.llvm.org Tue May 13 15:53:24 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Tue, 13 May 2025 15:53:24 -0700 (PDT) Subject: [Lldb-commits] [lldb] 85bbf8c - [lldb] Use llvm::is_contained (NFC) (#139758) Message-ID: <6823cd64.630a0220.39e75f.7994@mx.google.com> Author: Kazu Hirata Date: 2025-05-13T15:53:20-07:00 New Revision: 85bbf8c887615b6b2c70353761fad8139d6ecbe8 URL: https://github.com/llvm/llvm-project/commit/85bbf8c887615b6b2c70353761fad8139d6ecbe8 DIFF: https://github.com/llvm/llvm-project/commit/85bbf8c887615b6b2c70353761fad8139d6ecbe8.diff LOG: [lldb] Use llvm::is_contained (NFC) (#139758) Added: Modified: lldb/tools/lldb-dap/DAP.cpp Removed: ################################################################################ diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 4feca1253be20..51f9da854f4b6 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1194,8 +1194,7 @@ bool SendEventRequestHandler::DoExecute(lldb::SBDebugger debugger, "exited", "initialize", "loadedSource", "module", "process", "stopped", "terminated", "thread"}; - if (std::find(internal_events.begin(), internal_events.end(), name) != - std::end(internal_events)) { + if (llvm::is_contained(internal_events, name)) { std::string msg = llvm::formatv("Invalid use of lldb-dap send-event, event \"{0}\" " "should be handled by lldb-dap internally.", From lldb-commits at lists.llvm.org Tue May 13 15:53:27 2025 From: lldb-commits at lists.llvm.org (Kazu Hirata via lldb-commits) Date: Tue, 13 May 2025 15:53:27 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use llvm::is_contained (NFC) (PR #139758) In-Reply-To: Message-ID: <6823cd67.170a0220.2d2ba4.04a6@mx.google.com> https://github.com/kazutakahirata closed https://github.com/llvm/llvm-project/pull/139758 From lldb-commits at lists.llvm.org Tue May 13 17:02:16 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Tue, 13 May 2025 17:02:16 -0700 (PDT) Subject: [Lldb-commits] [lldb] 2d57b61 - [lldb-dap] Add unit test for breakpoint types (#139792) Message-ID: <6823dd88.170a0220.59850.0865@mx.google.com> Author: Jonas Devlieghere Date: 2025-05-13T17:02:13-07:00 New Revision: 2d57b6132588cd1676d817d120c2f49916227414 URL: https://github.com/llvm/llvm-project/commit/2d57b6132588cd1676d817d120c2f49916227414 DIFF: https://github.com/llvm/llvm-project/commit/2d57b6132588cd1676d817d120c2f49916227414.diff LOG: [lldb-dap] Add unit test for breakpoint types (#139792) - Add unit test for breakpoint types for SourceBreakpoint, FunctionBreakpoint and DataBreakpoint. - Rename DataBreakpointInfo to DataBreakpoint. - Fix some mapOptions for optional fields. Added: Modified: lldb/tools/lldb-dap/Protocol/ProtocolRequests.h lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp lldb/tools/lldb-dap/Protocol/ProtocolTypes.h lldb/tools/lldb-dap/Watchpoint.cpp lldb/tools/lldb-dap/Watchpoint.h lldb/unittests/DAP/ProtocolTypesTest.cpp Removed: ################################################################################ diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index c6456b4113320..710fa5d2c57ed 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -693,7 +693,7 @@ llvm::json::Value toJSON(const DataBreakpointInfoResponseBody &); struct SetDataBreakpointsArguments { /// The contents of this array replaces all existing data breakpoints. An /// empty array clears all data breakpoints. - std::vector breakpoints; + std::vector breakpoints; }; bool fromJSON(const llvm::json::Value &, SetDataBreakpointsArguments &, llvm::json::Path); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index 7c2f4b20f4956..8d95687e00e53 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -446,18 +446,48 @@ bool fromJSON(const llvm::json::Value &Params, Breakpoint &BP, bool fromJSON(const llvm::json::Value &Params, SourceBreakpoint &SB, llvm::json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("line", SB.line) && O.map("column", SB.column) && - O.map("condition", SB.condition) && - O.map("hitCondition", SB.hitCondition) && - O.map("logMessage", SB.logMessage) && O.map("mode", SB.mode); + llvm::json::ObjectMapper O(Params, P); + return O && O.map("line", SB.line) && O.mapOptional("column", SB.column) && + O.mapOptional("condition", SB.condition) && + O.mapOptional("hitCondition", SB.hitCondition) && + O.mapOptional("logMessage", SB.logMessage) && + O.mapOptional("mode", SB.mode); +} + +llvm::json::Value toJSON(const SourceBreakpoint &SB) { + llvm::json::Object result{{"line", SB.line}}; + + if (SB.column) + result.insert({"column", *SB.column}); + if (SB.condition) + result.insert({"condition", *SB.condition}); + if (SB.hitCondition) + result.insert({"hitCondition", *SB.hitCondition}); + if (SB.logMessage) + result.insert({"logMessage", *SB.logMessage}); + if (SB.mode) + result.insert({"mode", *SB.mode}); + + return result; } bool fromJSON(const llvm::json::Value &Params, FunctionBreakpoint &FB, llvm::json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("name", FB.name) && O.map("condition", FB.condition) && - O.map("hitCondition", FB.hitCondition); + llvm::json::ObjectMapper O(Params, P); + return O && O.map("name", FB.name) && + O.mapOptional("condition", FB.condition) && + O.mapOptional("hitCondition", FB.hitCondition); +} + +llvm::json::Value toJSON(const FunctionBreakpoint &FB) { + llvm::json::Object result{{"name", FB.name}}; + + if (FB.condition) + result.insert({"condition", *FB.condition}); + if (FB.hitCondition) + result.insert({"hitCondition", *FB.hitCondition}); + + return result; } bool fromJSON(const llvm::json::Value &Params, DataBreakpointAccessType &DBAT, @@ -493,21 +523,36 @@ llvm::json::Value toJSON(const DataBreakpointAccessType &DBAT) { llvm_unreachable("unhandled data breakpoint access type."); } -bool fromJSON(const llvm::json::Value &Params, DataBreakpointInfo &DBI, +bool fromJSON(const llvm::json::Value &Params, DataBreakpoint &DBI, llvm::json::Path P) { - json::ObjectMapper O(Params, P); + llvm::json::ObjectMapper O(Params, P); return O && O.map("dataId", DBI.dataId) && - O.map("accessType", DBI.accessType) && - O.map("condition", DBI.condition) && - O.map("hitCondition", DBI.hitCondition); + O.mapOptional("accessType", DBI.accessType) && + O.mapOptional("condition", DBI.condition) && + O.mapOptional("hitCondition", DBI.hitCondition); +} + +llvm::json::Value toJSON(const DataBreakpoint &DBI) { + llvm::json::Object result{{"dataId", DBI.dataId}}; + + if (DBI.accessType) + result.insert({"accessType", *DBI.accessType}); + if (DBI.condition) + result.insert({"condition", *DBI.condition}); + if (DBI.hitCondition) + result.insert({"hitCondition", *DBI.hitCondition}); + + return result; } bool fromJSON(const llvm::json::Value &Params, InstructionBreakpoint &IB, llvm::json::Path P) { - json::ObjectMapper O(Params, P); + llvm::json::ObjectMapper O(Params, P); return O && O.map("instructionReference", IB.instructionReference) && - O.map("offset", IB.offset) && O.map("condition", IB.condition) && - O.map("hitCondition", IB.hitCondition) && O.map("mode", IB.mode); + O.mapOptional("offset", IB.offset) && + O.mapOptional("condition", IB.condition) && + O.mapOptional("hitCondition", IB.hitCondition) && + O.mapOptional("mode", IB.mode); } } // namespace lldb_dap::protocol diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index cab188637acd5..c48988a48a373 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -464,6 +464,7 @@ struct SourceBreakpoint { std::optional mode; }; bool fromJSON(const llvm::json::Value &, SourceBreakpoint &, llvm::json::Path); +llvm::json::Value toJSON(const SourceBreakpoint &); /// Properties of a breakpoint passed to the `setFunctionBreakpoints` request. struct FunctionBreakpoint { @@ -483,6 +484,7 @@ struct FunctionBreakpoint { }; bool fromJSON(const llvm::json::Value &, FunctionBreakpoint &, llvm::json::Path); +llvm::json::Value toJSON(const FunctionBreakpoint &); /// This enumeration defines all possible access types for data breakpoints. /// Values: ‘read’, ‘write’, ‘readWrite’ @@ -496,7 +498,7 @@ bool fromJSON(const llvm::json::Value &, DataBreakpointAccessType &, llvm::json::Value toJSON(const DataBreakpointAccessType &); /// Properties of a data breakpoint passed to the `setDataBreakpoints` request. -struct DataBreakpointInfo { +struct DataBreakpoint { /// An id representing the data. This id is returned from the /// `dataBreakpointInfo` request. std::string dataId; @@ -511,8 +513,8 @@ struct DataBreakpointInfo { /// The debug adapter is expected to interpret the expression as needed. std::optional hitCondition; }; -bool fromJSON(const llvm::json::Value &, DataBreakpointInfo &, - llvm::json::Path); +bool fromJSON(const llvm::json::Value &, DataBreakpoint &, llvm::json::Path); +llvm::json::Value toJSON(const DataBreakpoint &); /// Properties of a breakpoint passed to the `setInstructionBreakpoints` request struct InstructionBreakpoint { diff --git a/lldb/tools/lldb-dap/Watchpoint.cpp b/lldb/tools/lldb-dap/Watchpoint.cpp index 73ed4fdbae1b8..0acc980890be8 100644 --- a/lldb/tools/lldb-dap/Watchpoint.cpp +++ b/lldb/tools/lldb-dap/Watchpoint.cpp @@ -17,7 +17,7 @@ #include namespace lldb_dap { -Watchpoint::Watchpoint(DAP &d, const protocol::DataBreakpointInfo &breakpoint) +Watchpoint::Watchpoint(DAP &d, const protocol::DataBreakpoint &breakpoint) : BreakpointBase(d, breakpoint.condition, breakpoint.hitCondition) { llvm::StringRef dataId = breakpoint.dataId; auto [addr_str, size_str] = dataId.split('/'); diff --git a/lldb/tools/lldb-dap/Watchpoint.h b/lldb/tools/lldb-dap/Watchpoint.h index b7fe58fe73501..d943e1218bdcd 100644 --- a/lldb/tools/lldb-dap/Watchpoint.h +++ b/lldb/tools/lldb-dap/Watchpoint.h @@ -22,7 +22,7 @@ namespace lldb_dap { class Watchpoint : public BreakpointBase { public: - Watchpoint(DAP &d, const protocol::DataBreakpointInfo &breakpoint); + Watchpoint(DAP &d, const protocol::DataBreakpoint &breakpoint); Watchpoint(DAP &d, lldb::SBWatchpoint wp) : BreakpointBase(d), m_wp(wp) {} void SetCondition() override; diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp index 56b21f18fa7cd..f5d72f06432d5 100644 --- a/lldb/unittests/DAP/ProtocolTypesTest.cpp +++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp @@ -132,3 +132,65 @@ TEST(ProtocolTypesTest, Breakpoint) { EXPECT_EQ(breakpoint.offset, deserialized_breakpoint->offset); EXPECT_EQ(breakpoint.reason, deserialized_breakpoint->reason); } + +TEST(ProtocolTypesTest, SourceBreakpoint) { + SourceBreakpoint source_breakpoint; + source_breakpoint.line = 42; + source_breakpoint.column = 5; + source_breakpoint.condition = "x > 10"; + source_breakpoint.hitCondition = "5"; + source_breakpoint.logMessage = "Breakpoint hit at line 42"; + source_breakpoint.mode = "hardware"; + + llvm::Expected deserialized_source_breakpoint = + roundtrip(source_breakpoint); + ASSERT_THAT_EXPECTED(deserialized_source_breakpoint, llvm::Succeeded()); + + EXPECT_EQ(source_breakpoint.line, deserialized_source_breakpoint->line); + EXPECT_EQ(source_breakpoint.column, deserialized_source_breakpoint->column); + EXPECT_EQ(source_breakpoint.condition, + deserialized_source_breakpoint->condition); + EXPECT_EQ(source_breakpoint.hitCondition, + deserialized_source_breakpoint->hitCondition); + EXPECT_EQ(source_breakpoint.logMessage, + deserialized_source_breakpoint->logMessage); + EXPECT_EQ(source_breakpoint.mode, deserialized_source_breakpoint->mode); +} + +TEST(ProtocolTypesTest, FunctionBreakpoint) { + FunctionBreakpoint function_breakpoint; + function_breakpoint.name = "myFunction"; + function_breakpoint.condition = "x == 0"; + function_breakpoint.hitCondition = "3"; + + llvm::Expected deserialized_function_breakpoint = + roundtrip(function_breakpoint); + ASSERT_THAT_EXPECTED(deserialized_function_breakpoint, llvm::Succeeded()); + + EXPECT_EQ(function_breakpoint.name, deserialized_function_breakpoint->name); + EXPECT_EQ(function_breakpoint.condition, + deserialized_function_breakpoint->condition); + EXPECT_EQ(function_breakpoint.hitCondition, + deserialized_function_breakpoint->hitCondition); +} + +TEST(ProtocolTypesTest, DataBreakpoint) { + DataBreakpoint data_breakpoint_info; + data_breakpoint_info.dataId = "variable1"; + data_breakpoint_info.accessType = eDataBreakpointAccessTypeReadWrite; + data_breakpoint_info.condition = "x > 100"; + data_breakpoint_info.hitCondition = "10"; + + llvm::Expected deserialized_data_breakpoint_info = + roundtrip(data_breakpoint_info); + ASSERT_THAT_EXPECTED(deserialized_data_breakpoint_info, llvm::Succeeded()); + + EXPECT_EQ(data_breakpoint_info.dataId, + deserialized_data_breakpoint_info->dataId); + EXPECT_EQ(data_breakpoint_info.accessType, + deserialized_data_breakpoint_info->accessType); + EXPECT_EQ(data_breakpoint_info.condition, + deserialized_data_breakpoint_info->condition); + EXPECT_EQ(data_breakpoint_info.hitCondition, + deserialized_data_breakpoint_info->hitCondition); +} From lldb-commits at lists.llvm.org Tue May 13 17:02:19 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Tue, 13 May 2025 17:02:19 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for breakpoint types (PR #139792) In-Reply-To: Message-ID: <6823dd8b.170a0220.31c209.093c@mx.google.com> https://github.com/JDevlieghere closed https://github.com/llvm/llvm-project/pull/139792 From lldb-commits at lists.llvm.org Tue May 13 17:57:12 2025 From: lldb-commits at lists.llvm.org (Jason Molenda via lldb-commits) Date: Tue, 13 May 2025 17:57:12 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][NFC] Split RegisterContextUnwind::SavedLocationForRegister (PR #139817) In-Reply-To: Message-ID: <6823ea68.170a0220.31ae39.f614@mx.google.com> jasonmolenda wrote: to be clear: The diff for the first half of the old SavedLocationForRegister is entirely pointless to look at. Reading RegisterContextUnwind::GetAbstractRegisterLocation in the "new" version of the file is the way to go, and I'm pretty comfortable with everything that I've kept in here, I think the behaviors are easy to reason as correct when I read it. The diff for the second half -- taking an AbstractRegisterLocation and converting it into a ConcreteRegisterLocation -- involved very few changes and is readable. I've run it through our testsuite on macOS and it shows no issues, but I look forward to all the CI bots getting their hands on it & seeing that result confirmed. https://github.com/llvm/llvm-project/pull/139817 From lldb-commits at lists.llvm.org Tue May 13 18:03:58 2025 From: lldb-commits at lists.llvm.org (Jason Molenda via lldb-commits) Date: Tue, 13 May 2025 18:03:58 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][NFC] Split RegisterContextUnwind::SavedLocationForRegister (PR #139817) In-Reply-To: Message-ID: <6823ebfe.170a0220.272ffa.0571@mx.google.com> https://github.com/jasonmolenda updated https://github.com/llvm/llvm-project/pull/139817 >From e63e53adc0909f481a165eca958a3ac2ca4374ee Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 13 May 2025 17:11:08 -0700 Subject: [PATCH 1/4] [lldb][NFC] Split RegisterContextUnwind::SavedLocationForRegister RegisterContextUnwind::SavedLocationForRegister is around 450 lines that first find an abstract register location (e.g. "CFA-8") for a register by looking in the UnwindPlans. Then it evaluates the abstract register location to create a concrete register location (e.g. "stored at address 0x...", "live in register at frame 0"). There are some complicated cases in the first half of the method to handle return address register architectures correctly, in particular. Looking at the two halves, they're both exactly 226 lines long and there's little involvement between them except for passing an abstract register location along. (there were some parts in the "abstract register location" code that would set the concrete register location, unnecessarily) It's also a complex enough method that there are some bits of code that aren't actually doing anything at this point. This patch adds a RegisterContextUnwind::GetAbstractRegisterLocation method, which does the first half, and has a clearly defined return values. The code to convert an AbstractRegisterLocation into a ConcreteRegisterLocation remains in SavedLocationForRegister. It's a bit of a tricky patch to visually inspect, despite it not changing functionality, the reorganizations and rewrites make the diff unreadable. Nearly all the real changes are in the "find the abstract register location" first half of the method. I think reading the new code in its new form is the easiest way to inspect this PR. With a defined interface between the two of what is expected, it's pretty easy to look at the code and reason about whether it is written correctly. (whereas before, that was very difficult, for me at least.) --- .../lldb/Target/RegisterContextUnwind.h | 3 + lldb/source/Target/RegisterContextUnwind.cpp | 530 +++++++++--------- lldb/source/Target/RegisterNumber.cpp | 1 + 3 files changed, 259 insertions(+), 275 deletions(-) diff --git a/lldb/include/lldb/Target/RegisterContextUnwind.h b/lldb/include/lldb/Target/RegisterContextUnwind.h index 044a387fe5aa2..b10a364823b83 100644 --- a/lldb/include/lldb/Target/RegisterContextUnwind.h +++ b/lldb/include/lldb/Target/RegisterContextUnwind.h @@ -151,6 +151,9 @@ class RegisterContextUnwind : public lldb_private::RegisterContext { uint32_t lldb_regnum, lldb_private::UnwindLLDB::ConcreteRegisterLocation ®loc); + std::optional + GetAbstractRegisterLocation(uint32_t lldb_regnum, lldb::RegisterKind &kind); + bool ReadRegisterValueFromRegisterLocation( lldb_private::UnwindLLDB::ConcreteRegisterLocation regloc, const lldb_private::RegisterInfo *reg_info, diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index cf4b96c6eda9f..a3931abefb054 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1243,247 +1243,194 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( return false; } -// Answer the question: Where did THIS frame save the CALLER frame ("previous" -// frame)'s register value? - -enum UnwindLLDB::RegisterSearchResult -RegisterContextUnwind::SavedLocationForRegister( - uint32_t lldb_regnum, - lldb_private::UnwindLLDB::ConcreteRegisterLocation ®loc) { +// Search this stack frame's UnwindPlans for the AbstractRegisterLocation +// for this register. +// +// When an AbstractRegisterLocation is found in an UnwindPlan, that is +// returned, regardless of the ABI rules for volatile/non-volatile registers +// in effect. +// +// If there is no unwind rule for a volatile (caller-preserved) register +// the returned AbstractRegisterLocation will be IsUndefined, +// indicating that we should stop searching. +// +// If there is no unwind rule for a non-volatile (callee-preserved) +// register, the returned AbstractRegisterLocation will be IsSame. +// In frame 0, IsSame means get the value from the live register context. +// Else it means to continue descending down the stack to more-live frames +// looking for a location/value. +// +// An empty optional indicates that there was an error in processing. +std::optional +RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, + lldb::RegisterKind &kind) { RegisterNumber regnum(m_thread, eRegisterKindLLDB, lldb_regnum); Log *log = GetLog(LLDBLog::Unwind); - // Have we already found this register location? - if (!m_registers.empty()) { - std::map::const_iterator - iterator; - iterator = m_registers.find(regnum.GetAsKind(eRegisterKindLLDB)); - if (iterator != m_registers.end()) { - regloc = iterator->second; - UnwindLogMsg("supplying caller's saved %s (%d)'s location, cached", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } - } - - // Look through the available UnwindPlans for the register location. - UnwindPlan::Row::AbstractRegisterLocation unwindplan_regloc; - bool have_unwindplan_regloc = false; - RegisterKind unwindplan_registerkind = kNumRegisterKinds; + // First, try to find a register location via the FastUnwindPlan if (m_fast_unwind_plan_sp) { const UnwindPlan::Row *active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); - unwindplan_registerkind = m_fast_unwind_plan_sp->GetRegisterKind(); - if (regnum.GetAsKind(unwindplan_registerkind) == LLDB_INVALID_REGNUM) { + kind = m_fast_unwind_plan_sp->GetRegisterKind(); + if (regnum.GetAsKind(kind) == LLDB_INVALID_REGNUM) { UnwindLogMsg("could not convert lldb regnum %s (%d) into %d RegisterKind " "reg numbering scheme", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - (int)unwindplan_registerkind); - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; + (int)kind); + return {}; } // The architecture default unwind plan marks unknown registers as // Undefined so that we don't forward them up the stack when a // jitted stack frame may have overwritten them. But when the // arch default unwind plan is used as the Fast Unwind Plan, we // need to recognize this & switch over to the Full Unwind Plan - // to see what unwind rule that (more knoweldgeable, probably) - // UnwindPlan has. If the full UnwindPlan says the register - // location is Undefined, then it really is. - if (active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind), + // to see what unwind rule that (more knowledgeable, probably) + // UnwindPlan has. + if (active_row->GetRegisterInfo(regnum.GetAsKind(kind), unwindplan_regloc) && !unwindplan_regloc.IsUndefined()) { UnwindLogMsg( "supplying caller's saved %s (%d)'s location using FastUnwindPlan", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - have_unwindplan_regloc = true; + return unwindplan_regloc; } } - if (!have_unwindplan_regloc) { - // m_full_unwind_plan_sp being NULL means that we haven't tried to find a - // full UnwindPlan yet - bool got_new_full_unwindplan = false; - if (!m_full_unwind_plan_sp) { - m_full_unwind_plan_sp = GetFullUnwindPlanForFrame(); - got_new_full_unwindplan = true; - } + // Second, try to find a register location via the FullUnwindPlan. + bool got_new_full_unwindplan = false; + if (!m_full_unwind_plan_sp) { + m_full_unwind_plan_sp = GetFullUnwindPlanForFrame(); + got_new_full_unwindplan = true; + } + if (m_full_unwind_plan_sp) { + RegisterNumber pc_regnum(m_thread, eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_PC); - if (m_full_unwind_plan_sp) { - RegisterNumber pc_regnum(m_thread, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_PC); + const UnwindPlan::Row *active_row = + m_full_unwind_plan_sp->GetRowForFunctionOffset( + m_current_offset_backed_up_one); + kind = m_full_unwind_plan_sp->GetRegisterKind(); - const UnwindPlan::Row *active_row = - m_full_unwind_plan_sp->GetRowForFunctionOffset( - m_current_offset_backed_up_one); - unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind(); + if (got_new_full_unwindplan && active_row && log) { + StreamString active_row_strm; + ExecutionContext exe_ctx(m_thread.shared_from_this()); + active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, + m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); + UnwindLogMsg("Using full unwind plan '%s'", + m_full_unwind_plan_sp->GetSourceName().AsCString()); + UnwindLogMsg("active row: %s", active_row_strm.GetData()); + } - if (got_new_full_unwindplan && active_row && log) { - StreamString active_row_strm; - ExecutionContext exe_ctx(m_thread.shared_from_this()); - active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), - &m_thread, - m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); - UnwindLogMsg("Using full unwind plan '%s'", - m_full_unwind_plan_sp->GetSourceName().AsCString()); - UnwindLogMsg("active row: %s", active_row_strm.GetData()); + if (regnum.GetAsKind(kind) == LLDB_INVALID_REGNUM) { + if (kind == eRegisterKindGeneric) { + UnwindLogMsg("could not convert lldb regnum %s (%d) into " + "eRegisterKindGeneric reg numbering scheme", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + } else { + UnwindLogMsg("could not convert lldb regnum %s (%d) into %d " + "RegisterKind reg numbering scheme", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), + (int)kind); } + return {}; + } + + if (regnum.IsValid() && active_row && + active_row->GetRegisterInfo(regnum.GetAsKind(kind), + unwindplan_regloc)) { + UnwindLogMsg( + "supplying caller's saved %s (%d)'s location using %s UnwindPlan", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), + m_full_unwind_plan_sp->GetSourceName().GetCString()); + return unwindplan_regloc; + } + + // When asking for the caller's pc, check if we have a + // Return Address register on this target. + // + // On a Return Address Register architecture like arm/mips/riscv, + // the caller's pc is in the RA register, and will be spilled to + // stack before any other function can be called. We may have a + // register location saying + // pc=RAReg {caller's retrun addr is in RA register} + // ra=IsSame {caller's return addr is live in RA register} + // ra=StackAddr {caller's return addr spilled to stack} + // or none of the above, which means the caller's pc is live in the + // return address reg if this is frame 0, or the frame below is + // a trap/sigtramp/interrupt handler function. Any other mid-stack + // function must have an unwind rule for PC/RA giving a location/value. + // + // In the case of an interrupted function -- the function above sigtramp, + // or a function interrupted asynchronously, or that has faulted to + // a trap handler -- it is valid to ask both the "pc" value -- the + // instruction that was executing when the interrupt/fault happend -- + // and the RA Register value. If a frameless function (which doesn't + // create a stack frame, doesn't save the RA reg to stack) is interrupted, + // the trap handler will have a rule to provide the pc (the instruction + // that was executing) AND a rule to provide the RA Register, which we + // need to use to find the caller function: + // pc=StackAddr1 + // ra=StackAddr2 + // and we don't want to rewrite a request of "pc" to "ra" here, because + // they mean different things. + + if (pc_regnum.IsValid() && pc_regnum == regnum) { RegisterNumber return_address_reg; + uint32_t return_address_regnum = + LLDB_INVALID_REGNUM; // in full UnwindPlan's numbering + + // Get the return address register number from the UnwindPlan + // or the arch register set. + if (m_full_unwind_plan_sp->GetReturnAddressRegister() != + LLDB_INVALID_REGNUM) { + return_address_regnum = + m_full_unwind_plan_sp->GetReturnAddressRegister(); + } else { + RegisterNumber arch_default_ra_regnum(m_thread, eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_RA); + return_address_regnum = arch_default_ra_regnum.GetAsKind(kind); + } - // If we're fetching the saved pc and this UnwindPlan defines a - // ReturnAddress register (e.g. lr on arm), look for the return address - // register number in the UnwindPlan's row. - if (pc_regnum.IsValid() && pc_regnum == regnum && - m_full_unwind_plan_sp->GetReturnAddressRegister() != - LLDB_INVALID_REGNUM) { - // If this is a trap handler frame, we should have access to - // the complete register context when the interrupt/async - // signal was received, we should fetch the actual saved $pc - // value instead of the Return Address register. - // If $pc is not available, fall back to the RA reg. + if (return_address_regnum != LLDB_INVALID_REGNUM) { UnwindPlan::Row::AbstractRegisterLocation scratch; + // This is a sigtramp/interrupt handler - treat a + // request for "pc" and "ra" as distinct. if (m_frame_type == eTrapHandlerFrame && active_row && - active_row->GetRegisterInfo( - pc_regnum.GetAsKind(unwindplan_registerkind), scratch)) { + active_row->GetRegisterInfo(pc_regnum.GetAsKind(kind), scratch)) { UnwindLogMsg("Providing pc register instead of rewriting to " "RA reg because this is a trap handler and there is " "a location for the saved pc register value."); } else { - return_address_reg.init( - m_thread, m_full_unwind_plan_sp->GetRegisterKind(), - m_full_unwind_plan_sp->GetReturnAddressRegister()); + // This is a normal function, there's no rule for + // finding the caller's pc value, look for the caller's + // return address register value. + return_address_reg.init(m_thread, + m_full_unwind_plan_sp->GetRegisterKind(), + return_address_regnum); regnum = return_address_reg; UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a " "RA reg; getting %s (%d) instead", return_address_reg.GetName(), return_address_reg.GetAsKind(eRegisterKindLLDB)); - } - } else { - if (regnum.GetAsKind(unwindplan_registerkind) == LLDB_INVALID_REGNUM) { - if (unwindplan_registerkind == eRegisterKindGeneric) { - UnwindLogMsg("could not convert lldb regnum %s (%d) into " - "eRegisterKindGeneric reg numbering scheme", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - } else { - UnwindLogMsg("could not convert lldb regnum %s (%d) into %d " - "RegisterKind reg numbering scheme", + if (active_row && active_row->GetRegisterInfo(regnum.GetAsKind(kind), + unwindplan_regloc)) { + UnwindLogMsg("supplying caller's saved %s (%d)'s location using " + "%s UnwindPlan", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - (int)unwindplan_registerkind); - } - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - } - } - - // Check if the active_row has a register location listed. - if (regnum.IsValid() && active_row && - active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind), - unwindplan_regloc)) { - have_unwindplan_regloc = true; - UnwindLogMsg( - "supplying caller's saved %s (%d)'s location using %s UnwindPlan", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - m_full_unwind_plan_sp->GetSourceName().GetCString()); - } - - // This is frame 0 and we're retrieving the PC and it's saved in a Return - // Address register and it hasn't been saved anywhere yet -- that is, - // it's still live in the actual register. Handle this specially. - if (!have_unwindplan_regloc && return_address_reg.IsValid() && - return_address_reg.GetAsKind(eRegisterKindLLDB) != - LLDB_INVALID_REGNUM) { - if (IsFrameZero()) { - lldb_private::UnwindLLDB::ConcreteRegisterLocation new_regloc; - new_regloc.type = UnwindLLDB::ConcreteRegisterLocation:: - eRegisterInLiveRegisterContext; - new_regloc.location.register_number = - return_address_reg.GetAsKind(eRegisterKindLLDB); - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; - regloc = new_regloc; - UnwindLogMsg("supplying caller's register %s (%d) from the live " - "RegisterContext at frame 0, saved in %d", - return_address_reg.GetName(), - return_address_reg.GetAsKind(eRegisterKindLLDB), - return_address_reg.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } else if (BehavesLikeZerothFrame()) { - // This function was interrupted asynchronously -- it faulted, - // an async interrupt, a timer fired, a debugger expression etc. - // The caller's pc is in the Return Address register, but the - // UnwindPlan for this function may have no location rule for - // the RA reg. - // This means that the caller's return address is in the RA reg - // when the function was interrupted--descend down one stack frame - // to retrieve it from the trap handler's saved context. - unwindplan_regloc.SetSame(); - have_unwindplan_regloc = true; - } - } - - // If this architecture stores the return address in a register (it - // defines a Return Address register) and we're on a non-zero stack frame - // and the Full UnwindPlan says that the pc is stored in the - // RA registers (e.g. lr on arm), then we know that the full unwindplan is - // not trustworthy -- this - // is an impossible situation and the instruction emulation code has - // likely been misled. If this stack frame meets those criteria, we need - // to throw away the Full UnwindPlan that the instruction emulation came - // up with and fall back to the architecture's Default UnwindPlan so the - // stack walk can get past this point. - - // Special note: If the Full UnwindPlan was generated from the compiler, - // don't second-guess it when we're at a call site location. - - // arch_default_ra_regnum is the return address register # in the Full - // UnwindPlan register numbering - RegisterNumber arch_default_ra_regnum(m_thread, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_RA); - - if (arch_default_ra_regnum.GetAsKind(unwindplan_registerkind) != - LLDB_INVALID_REGNUM && - pc_regnum == regnum && unwindplan_regloc.IsInOtherRegister() && - unwindplan_regloc.GetRegisterNumber() == - arch_default_ra_regnum.GetAsKind(unwindplan_registerkind) && - m_full_unwind_plan_sp->GetSourcedFromCompiler() != eLazyBoolYes && - !m_all_registers_available) { - UnwindLogMsg("%s UnwindPlan tried to restore the pc from the link " - "register but this is a non-zero frame", - m_full_unwind_plan_sp->GetSourceName().GetCString()); - - // Throw away the full unwindplan; install the arch default unwindplan - if (ForceSwitchToFallbackUnwindPlan()) { - // Update for the possibly new unwind plan - unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind(); - const UnwindPlan::Row *active_row = - m_full_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); - - // Sanity check: Verify that we can fetch a pc value and CFA value - // with this unwind plan - - RegisterNumber arch_default_pc_reg(m_thread, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_PC); - bool can_fetch_pc_value = false; - bool can_fetch_cfa = false; - addr_t cfa_value; - if (active_row) { - if (arch_default_pc_reg.GetAsKind(unwindplan_registerkind) != - LLDB_INVALID_REGNUM && - active_row->GetRegisterInfo( - arch_default_pc_reg.GetAsKind(unwindplan_registerkind), - unwindplan_regloc)) { - can_fetch_pc_value = true; - } - if (ReadFrameAddress(unwindplan_registerkind, - active_row->GetCFAValue(), cfa_value)) { - can_fetch_cfa = true; + m_full_unwind_plan_sp->GetSourceName().GetCString()); + if (unwindplan_regloc.IsSame()) + unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + return unwindplan_regloc; + } else { + // No unwind rule for the return address reg on frame + // 0 means that the caller's address is still in RA reg. + if (BehavesLikeZerothFrame()) { + unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + return unwindplan_regloc; } } - - have_unwindplan_regloc = can_fetch_pc_value && can_fetch_cfa; - } else { - // We were unable to fall back to another unwind plan - have_unwindplan_regloc = false; } } } @@ -1491,55 +1438,84 @@ RegisterContextUnwind::SavedLocationForRegister( ExecutionContext exe_ctx(m_thread.shared_from_this()); Process *process = exe_ctx.GetProcessPtr(); - if (!have_unwindplan_regloc) { - // If the UnwindPlan failed to give us an unwind location for this - // register, we may be able to fall back to some ABI-defined default. For - // example, some ABIs allow to determine the caller's SP via the CFA. Also, - // the ABI may set volatile registers to the undefined state. - ABI *abi = process ? process->GetABI().get() : nullptr; - if (abi) { - const RegisterInfo *reg_info = - GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB)); - if (reg_info && - abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) { - UnwindLogMsg( - "supplying caller's saved %s (%d)'s location using ABI default", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - have_unwindplan_regloc = true; - } + + // Third, try finding a register location via the ABI + // FallbackRegisterLocation. + // + // If the UnwindPlan failed to give us an unwind location for this + // register, we may be able to fall back to some ABI-defined default. For + // example, some ABIs allow to determine the caller's SP via the CFA. Also, + // the ABI willset volatile registers to the undefined state. + ABI *abi = process ? process->GetABI().get() : nullptr; + if (abi) { + const RegisterInfo *reg_info = + GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB)); + if (reg_info && + abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) { + UnwindLogMsg( + "supplying caller's saved %s (%d)'s location using ABI default", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + return unwindplan_regloc; } } - if (!have_unwindplan_regloc) { - if (IsFrameZero()) { - // This is frame 0 - we should return the actual live register context - // value - lldb_private::UnwindLLDB::ConcreteRegisterLocation new_regloc; - new_regloc.type = - UnwindLLDB::ConcreteRegisterLocation::eRegisterInLiveRegisterContext; - new_regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; - regloc = new_regloc; - UnwindLogMsg("supplying caller's register %s (%d) from the live " - "RegisterContext at frame 0", + // We have no AbstractRegisterRule, and the ABI says this is a + // non-volatile / callee-preserved register. + std::string unwindplan_name; + if (m_full_unwind_plan_sp) { + unwindplan_name += "via '"; + unwindplan_name += m_full_unwind_plan_sp->GetSourceName().AsCString(); + unwindplan_name += "'"; + } + UnwindLogMsg("no save location for %s (%d) %s", regnum.GetName(), + regnum.GetAsKind(eRegisterKindLLDB), unwindplan_name.c_str()); + + unwindplan_regloc.SetSame(); + return unwindplan_regloc; +} + +// Answer the question: Where did THIS frame save the CALLER frame ("previous" +// frame)'s register value? + +enum UnwindLLDB::RegisterSearchResult +RegisterContextUnwind::SavedLocationForRegister( + uint32_t lldb_regnum, + lldb_private::UnwindLLDB::ConcreteRegisterLocation ®loc) { + RegisterNumber regnum(m_thread, eRegisterKindLLDB, lldb_regnum); + Log *log = GetLog(LLDBLog::Unwind); + + // Have we already found this register location? + if (!m_registers.empty()) { + std::map::const_iterator + iterator; + iterator = m_registers.find(regnum.GetAsKind(eRegisterKindLLDB)); + if (iterator != m_registers.end()) { + regloc = iterator->second; + UnwindLogMsg("supplying caller's saved %s (%d)'s location, cached", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } else { - std::string unwindplan_name; - if (m_full_unwind_plan_sp) { - unwindplan_name += "via '"; - unwindplan_name += m_full_unwind_plan_sp->GetSourceName().AsCString(); - unwindplan_name += "'"; - } - UnwindLogMsg("no save location for %s (%d) %s", regnum.GetName(), - regnum.GetAsKind(eRegisterKindLLDB), - unwindplan_name.c_str()); } + } + + RegisterKind abs_regkind; + std::optional abs_regloc = + GetAbstractRegisterLocation(lldb_regnum, abs_regkind); + + if (!abs_regloc) return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; + + if (abs_regloc->IsUndefined()) { + UnwindLogMsg( + "did not supply reg location for %s (%d) because it is volatile", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile; } - // unwindplan_regloc has valid contents about where to retrieve the register - if (unwindplan_regloc.IsUnspecified()) { + ExecutionContext exe_ctx(m_thread.shared_from_this()); + Process *process = exe_ctx.GetProcessPtr(); + // abs_regloc has valid contents about where to retrieve the register + if (abs_regloc->IsUnspecified()) { lldb_private::UnwindLLDB::ConcreteRegisterLocation new_regloc = {}; new_regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterNotSaved; m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; @@ -1548,15 +1524,23 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; } - if (unwindplan_regloc.IsUndefined()) { - UnwindLogMsg( - "did not supply reg location for %s (%d) because it is volatile", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile; - } - - if (unwindplan_regloc.IsSame()) { - if (!m_all_registers_available && + if (abs_regloc->IsSame()) { + if (IsFrameZero()) { + regloc.type = + UnwindLLDB::ConcreteRegisterLocation::eRegisterInLiveRegisterContext; + regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); + m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; + UnwindLogMsg("supplying caller's register %s (%d) from the live " + "RegisterContext at frame 0", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + return UnwindLLDB::RegisterSearchResult::eRegisterFound; + } + // PC/RA reg don't follow the usual "callee-saved aka non-volatile" versus + // "caller saved aka volatile" system. A stack frame can provide its caller + // return address, but if we don't find a rule for pc/RA mid-stack, we + // never want to iterate further down the stack looking for it. + // Defensively prevent iterating down the stack for these two. + if (!BehavesLikeZerothFrame() && (regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_PC || regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_RA)) { UnwindLogMsg("register %s (%d) is marked as 'IsSame' - it is a pc or " @@ -1564,20 +1548,19 @@ RegisterContextUnwind::SavedLocationForRegister( "registers available -- treat as if we have no information", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - } else { - regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterInRegister; - regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; - UnwindLogMsg( - "supplying caller's register %s (%d), saved in register %s (%d)", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; } + + regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterInRegister; + regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); + m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; + UnwindLogMsg( + "supplying caller's register %s (%d) value is unmodified in this frame", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsCFAPlusOffset()) { - int offset = unwindplan_regloc.GetOffset(); + if (abs_regloc->IsCFAPlusOffset()) { + int offset = abs_regloc->GetOffset(); regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred; regloc.location.inferred_value = m_cfa + offset; m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; @@ -1588,8 +1571,8 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsAtCFAPlusOffset()) { - int offset = unwindplan_regloc.GetOffset(); + if (abs_regloc->IsAtCFAPlusOffset()) { + int offset = abs_regloc->GetOffset(); regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterSavedAtMemoryLocation; regloc.location.target_memory_location = m_cfa + offset; @@ -1601,11 +1584,11 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsAFAPlusOffset()) { + if (abs_regloc->IsAFAPlusOffset()) { if (m_afa == LLDB_INVALID_ADDRESS) return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - int offset = unwindplan_regloc.GetOffset(); + int offset = abs_regloc->GetOffset(); regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred; regloc.location.inferred_value = m_afa + offset; m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; @@ -1616,11 +1599,11 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsAtAFAPlusOffset()) { + if (abs_regloc->IsAtAFAPlusOffset()) { if (m_afa == LLDB_INVALID_ADDRESS) return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - int offset = unwindplan_regloc.GetOffset(); + int offset = abs_regloc->GetOffset(); regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterSavedAtMemoryLocation; regloc.location.target_memory_location = m_afa + offset; @@ -1632,10 +1615,9 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsInOtherRegister()) { - uint32_t unwindplan_regnum = unwindplan_regloc.GetRegisterNumber(); - RegisterNumber row_regnum(m_thread, unwindplan_registerkind, - unwindplan_regnum); + if (abs_regloc->IsInOtherRegister()) { + RegisterNumber row_regnum(m_thread, abs_regkind, + abs_regloc->GetRegisterNumber()); if (row_regnum.GetAsKind(eRegisterKindLLDB) == LLDB_INVALID_REGNUM) { UnwindLogMsg("could not supply caller's %s (%d) location - was saved in " "another reg but couldn't convert that regnum", @@ -1652,16 +1634,14 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsDWARFExpression() || - unwindplan_regloc.IsAtDWARFExpression()) { - DataExtractor dwarfdata(unwindplan_regloc.GetDWARFExpressionBytes(), - unwindplan_regloc.GetDWARFExpressionLength(), + if (abs_regloc->IsDWARFExpression() || abs_regloc->IsAtDWARFExpression()) { + DataExtractor dwarfdata(abs_regloc->GetDWARFExpressionBytes(), + abs_regloc->GetDWARFExpressionLength(), process->GetByteOrder(), process->GetAddressByteSize()); ModuleSP opcode_ctx; DWARFExpressionList dwarfexpr(opcode_ctx, dwarfdata, nullptr); - dwarfexpr.GetMutableExpressionAtAddress()->SetRegisterKind( - unwindplan_registerkind); + dwarfexpr.GetMutableExpressionAtAddress()->SetRegisterKind(abs_regkind); Value cfa_val = Scalar(m_cfa); cfa_val.SetValueType(Value::ValueType::LoadAddress); llvm::Expected result = @@ -1672,7 +1652,7 @@ RegisterContextUnwind::SavedLocationForRegister( } else { addr_t val; val = result->GetScalar().ULongLong(); - if (unwindplan_regloc.IsDWARFExpression()) { + if (abs_regloc->IsDWARFExpression()) { regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred; regloc.location.inferred_value = val; @@ -1698,9 +1678,9 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; } - if (unwindplan_regloc.IsConstant()) { + if (abs_regloc->IsConstant()) { regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred; - regloc.location.inferred_value = unwindplan_regloc.GetConstant(); + regloc.location.inferred_value = abs_regloc->GetConstant(); m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; UnwindLogMsg("supplying caller's register %s (%d) via constant value", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); diff --git a/lldb/source/Target/RegisterNumber.cpp b/lldb/source/Target/RegisterNumber.cpp index e5610bf588543..56dda8d8be8b8 100644 --- a/lldb/source/Target/RegisterNumber.cpp +++ b/lldb/source/Target/RegisterNumber.cpp @@ -47,6 +47,7 @@ const RegisterNumber &RegisterNumber::operator=(const RegisterNumber &rhs) { m_reg_ctx_sp = rhs.m_reg_ctx_sp; m_regnum = rhs.m_regnum; m_kind = rhs.m_kind; + m_kind_regnum_map.clear(); for (auto it : rhs.m_kind_regnum_map) m_kind_regnum_map[it.first] = it.second; m_name = rhs.m_name; >From c1aad81d5c5c7d2e9fce64f83197c05b827c6f22 Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 13 May 2025 17:37:42 -0700 Subject: [PATCH 2/4] Remove another bit of code in GetAbstractRegisterLocation that wasn't doing anything. --- lldb/source/Target/RegisterContextUnwind.cpp | 60 ++++++++------------ 1 file changed, 25 insertions(+), 35 deletions(-) diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index a3931abefb054..aae5de97de242 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1256,7 +1256,7 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( // // If there is no unwind rule for a non-volatile (callee-preserved) // register, the returned AbstractRegisterLocation will be IsSame. -// In frame 0, IsSame means get the value from the live register context. +// In frame 0, IsSame means get the value from the live register context. // Else it means to continue descending down the stack to more-live frames // looking for a location/value. // @@ -1394,42 +1394,32 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, } if (return_address_regnum != LLDB_INVALID_REGNUM) { - UnwindPlan::Row::AbstractRegisterLocation scratch; - // This is a sigtramp/interrupt handler - treat a - // request for "pc" and "ra" as distinct. - if (m_frame_type == eTrapHandlerFrame && active_row && - active_row->GetRegisterInfo(pc_regnum.GetAsKind(kind), scratch)) { - UnwindLogMsg("Providing pc register instead of rewriting to " - "RA reg because this is a trap handler and there is " - "a location for the saved pc register value."); + // This is a normal function, there's no rule for + // finding the caller's pc value, look for the caller's + // return address register value. + return_address_reg.init(m_thread, + m_full_unwind_plan_sp->GetRegisterKind(), + return_address_regnum); + regnum = return_address_reg; + UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a " + "RA reg; getting %s (%d) instead", + return_address_reg.GetName(), + return_address_reg.GetAsKind(eRegisterKindLLDB)); + if (active_row && active_row->GetRegisterInfo(regnum.GetAsKind(kind), + unwindplan_regloc)) { + UnwindLogMsg("supplying caller's saved %s (%d)'s location using " + "%s UnwindPlan", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), + m_full_unwind_plan_sp->GetSourceName().GetCString()); + if (unwindplan_regloc.IsSame()) + unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + return unwindplan_regloc; } else { - // This is a normal function, there's no rule for - // finding the caller's pc value, look for the caller's - // return address register value. - return_address_reg.init(m_thread, - m_full_unwind_plan_sp->GetRegisterKind(), - return_address_regnum); - regnum = return_address_reg; - UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a " - "RA reg; getting %s (%d) instead", - return_address_reg.GetName(), - return_address_reg.GetAsKind(eRegisterKindLLDB)); - if (active_row && active_row->GetRegisterInfo(regnum.GetAsKind(kind), - unwindplan_regloc)) { - UnwindLogMsg("supplying caller's saved %s (%d)'s location using " - "%s UnwindPlan", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - m_full_unwind_plan_sp->GetSourceName().GetCString()); - if (unwindplan_regloc.IsSame()) - unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + // No unwind rule for the return address reg on frame + // 0 means that the caller's address is still in RA reg. + if (BehavesLikeZerothFrame()) { + unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); return unwindplan_regloc; - } else { - // No unwind rule for the return address reg on frame - // 0 means that the caller's address is still in RA reg. - if (BehavesLikeZerothFrame()) { - unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); - return unwindplan_regloc; - } } } } >From fde91220492202f7a8b56312cac5b7316975d69a Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 13 May 2025 17:41:45 -0700 Subject: [PATCH 3/4] Don't log a message when the ABI says this is a volatile register -- has an Undefined abstract register location. --- lldb/source/Target/RegisterContextUnwind.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index aae5de97de242..cf23df21f5044 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1441,7 +1441,8 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, const RegisterInfo *reg_info = GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB)); if (reg_info && - abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) { + abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc) && + !unwindplan_regloc.IsUndefined()) { UnwindLogMsg( "supplying caller's saved %s (%d)'s location using ABI default", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); >From 853da6655104080cb7022ca4e7f18ffae2e5df1b Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 13 May 2025 18:03:41 -0700 Subject: [PATCH 4/4] clarify comment. --- lldb/source/Target/RegisterContextUnwind.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index cf23df21f5044..64cb906f4d6c3 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1450,8 +1450,9 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, } } - // We have no AbstractRegisterRule, and the ABI says this is a - // non-volatile / callee-preserved register. + // We have no AbstractRegisterLocation, and the ABI says this is a + // non-volatile / callee-preserved register. Continue down the stack + // or to frame 0 & the live RegisterContext. std::string unwindplan_name; if (m_full_unwind_plan_sp) { unwindplan_name += "via '"; From lldb-commits at lists.llvm.org Tue May 13 18:16:20 2025 From: lldb-commits at lists.llvm.org (Jason Molenda via lldb-commits) Date: Tue, 13 May 2025 18:16:20 -0700 (PDT) Subject: [Lldb-commits] [lldb] b8ba963 - [lldb] don't run TestUnwindFramelessFaulted.py on Linux Message-ID: <6823eee4.170a0220.3c9a8f.09d2@mx.google.com> Author: Jason Molenda Date: 2025-05-13T18:14:57-07:00 New Revision: b8ba9636f0f46a02ebe3ab369fe6b47703f45ba6 URL: https://github.com/llvm/llvm-project/commit/b8ba9636f0f46a02ebe3ab369fe6b47703f45ba6 DIFF: https://github.com/llvm/llvm-project/commit/b8ba9636f0f46a02ebe3ab369fe6b47703f45ba6.diff LOG: [lldb] don't run TestUnwindFramelessFaulted.py on Linux I thought I could call $(CPP) to preprocess the assembly file, but the aarch64-ubuntu bot runs this as clang -E and it issues a warning and no output file, apparently, build/bin/clang -E -o interrupt-and-trap-funcs.s /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/functionalities/unwind/frameless-faulted/interrupt-and-trap-funcs.s clang: warning: /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/functionalities/unwind/frameless-faulted/interrupt-and-trap-funcs.s: 'assembler' input unused [-Wunused-command-line-argument] /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang -g -O0 -c -o interrupt-and-trap-funcs.o interrupt-and-trap-funcs.s clang: error: no such file or directory: 'interrupt-and-trap-funcs.s' clang: error: no input files Added: Modified: lldb/test/API/functionalities/unwind/frameless-faulted/TestUnwindFramelessFaulted.py Removed: ################################################################################ diff --git a/lldb/test/API/functionalities/unwind/frameless-faulted/TestUnwindFramelessFaulted.py b/lldb/test/API/functionalities/unwind/frameless-faulted/TestUnwindFramelessFaulted.py index 03af87fcf32f6..483a487d76899 100644 --- a/lldb/test/API/functionalities/unwind/frameless-faulted/TestUnwindFramelessFaulted.py +++ b/lldb/test/API/functionalities/unwind/frameless-faulted/TestUnwindFramelessFaulted.py @@ -10,7 +10,7 @@ class TestUnwindFramelessFaulted(TestBase): NO_DEBUG_INFO_TESTCASE = True - @skipIf(oslist=no_match([lldbplatformutil.getDarwinOSTriples(), "linux"])) + @skipIf(oslist=no_match([lldbplatformutil.getDarwinOSTriples()])) @skipIf(archs=no_match(["aarch64", "arm64", "arm64e"])) # The static linker in Xcode 15.0-15.2 on macOS 14 will mislink From lldb-commits at lists.llvm.org Tue May 13 21:03:37 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Tue, 13 May 2025 21:03:37 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for capabilities (PR #139835) Message-ID: https://github.com/JDevlieghere created https://github.com/llvm/llvm-project/pull/139835 Add unit a test for the capabilities types. Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Tue May 13 21:04:13 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Tue, 13 May 2025 21:04:13 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for capabilities (PR #139835) In-Reply-To: Message-ID: <6824163d.a70a0220.205d9e.fd45@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Jonas Devlieghere (JDevlieghere)
Changes Add unit a test for the capabilities types. --- Full diff: https://github.com/llvm/llvm-project/pull/139835.diff 3 Files Affected: - (modified) lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp (+130) - (modified) lldb/tools/lldb-dap/Protocol/ProtocolTypes.h (+8-1) - (modified) lldb/unittests/DAP/ProtocolTypesTest.cpp (+97) ``````````diff diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index 8d95687e00e53..fafd061334bc9 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -165,6 +165,32 @@ json::Value toJSON(const ChecksumAlgorithm &CA) { llvm_unreachable("unhandled checksum algorithm."); } +bool fromJSON(const llvm::json::Value &Params, ChecksumAlgorithm &CA, + llvm::json::Path P) { + auto rawAlgorithm = Params.getAsString(); + if (!rawAlgorithm) { + P.report("expected a string"); + return false; + } + + std::optional algorithm = + llvm::StringSwitch>(*rawAlgorithm) + .Case("MD5", eChecksumAlgorithmMD5) + .Case("SHA1", eChecksumAlgorithmSHA1) + .Case("SHA256", eChecksumAlgorithmSHA256) + .Case("timestamp", eChecksumAlgorithmTimestamp) + .Default(std::nullopt); + + if (!algorithm) { + P.report( + "unexpected value, expected 'MD5', 'SHA1', 'SHA256', or 'timestamp'"); + return false; + } + + CA = *algorithm; + return true; +} + json::Value toJSON(const BreakpointModeApplicability &BMA) { switch (BMA) { case eBreakpointModeApplicabilitySource: @@ -304,6 +330,84 @@ static llvm::StringLiteral ToString(AdapterFeature feature) { llvm_unreachable("unhandled adapter feature."); } +llvm::json::Value toJSON(const AdapterFeature &feature) { + return ToString(feature); +} + +bool fromJSON(const llvm::json::Value &Params, AdapterFeature &feature, + llvm::json::Path P) { + auto rawFeature = Params.getAsString(); + if (!rawFeature) { + P.report("expected a string"); + return false; + } + + std::optional parsedFeature = + llvm::StringSwitch>(*rawFeature) + .Case("supportsANSIStyling", eAdapterFeatureANSIStyling) + .Case("supportsBreakpointLocationsRequest", + eAdapterFeatureBreakpointLocationsRequest) + .Case("supportsCancelRequest", eAdapterFeatureCancelRequest) + .Case("supportsClipboardContext", eAdapterFeatureClipboardContext) + .Case("supportsCompletionsRequest", eAdapterFeatureCompletionsRequest) + .Case("supportsConditionalBreakpoints", + eAdapterFeatureConditionalBreakpoints) + .Case("supportsConfigurationDoneRequest", + eAdapterFeatureConfigurationDoneRequest) + .Case("supportsDataBreakpointBytes", + eAdapterFeatureDataBreakpointBytes) + .Case("supportsDataBreakpoints", eAdapterFeatureDataBreakpoints) + .Case("supportsDelayedStackTraceLoading", + eAdapterFeatureDelayedStackTraceLoading) + .Case("supportsDisassembleRequest", eAdapterFeatureDisassembleRequest) + .Case("supportsEvaluateForHovers", eAdapterFeatureEvaluateForHovers) + .Case("supportsExceptionFilterOptions", + eAdapterFeatureExceptionFilterOptions) + .Case("supportsExceptionInfoRequest", + eAdapterFeatureExceptionInfoRequest) + .Case("supportsExceptionOptions", eAdapterFeatureExceptionOptions) + .Case("supportsFunctionBreakpoints", + eAdapterFeatureFunctionBreakpoints) + .Case("supportsGotoTargetsRequest", eAdapterFeatureGotoTargetsRequest) + .Case("supportsHitConditionalBreakpoints", + eAdapterFeatureHitConditionalBreakpoints) + .Case("supportsInstructionBreakpoints", + eAdapterFeatureInstructionBreakpoints) + .Case("supportsLoadedSourcesRequest", + eAdapterFeatureLoadedSourcesRequest) + .Case("supportsLogPoints", eAdapterFeatureLogPoints) + .Case("supportsModulesRequest", eAdapterFeatureModulesRequest) + .Case("supportsReadMemoryRequest", eAdapterFeatureReadMemoryRequest) + .Case("supportsRestartFrame", eAdapterFeatureRestartFrame) + .Case("supportsRestartRequest", eAdapterFeatureRestartRequest) + .Case("supportsSetExpression", eAdapterFeatureSetExpression) + .Case("supportsSetVariable", eAdapterFeatureSetVariable) + .Case("supportsSingleThreadExecutionRequests", + eAdapterFeatureSingleThreadExecutionRequests) + .Case("supportsStepBack", eAdapterFeatureStepBack) + .Case("supportsStepInTargetsRequest", + eAdapterFeatureStepInTargetsRequest) + .Case("supportsSteppingGranularity", + eAdapterFeatureSteppingGranularity) + .Case("supportsTerminateRequest", eAdapterFeatureTerminateRequest) + .Case("supportsTerminateThreadsRequest", + eAdapterFeatureTerminateThreadsRequest) + .Case("supportSuspendDebuggee", eAdapterFeatureSuspendDebuggee) + .Case("supportsValueFormattingOptions", + eAdapterFeatureValueFormattingOptions) + .Case("supportsWriteMemoryRequest", eAdapterFeatureWriteMemoryRequest) + .Case("supportTerminateDebuggee", eAdapterFeatureTerminateDebuggee) + .Default(std::nullopt); + + if (!parsedFeature) { + P.report("unexpected value for AdapterFeature"); + return false; + } + + feature = *parsedFeature; + return true; +} + json::Value toJSON(const Capabilities &C) { json::Object result; @@ -331,6 +435,32 @@ json::Value toJSON(const Capabilities &C) { return result; } +bool fromJSON(const llvm::json::Value &Params, Capabilities &C, + llvm::json::Path P) { + auto *Object = Params.getAsObject(); + if (!Object) { + P.report("expected an object"); + return false; + } + // Check for the presence of supported features. + for (unsigned i = eAdapterFeatureFirst; i <= eAdapterFeatureLast; ++i) { + AdapterFeature feature = static_cast(i); + if (Object->getBoolean(ToString(feature))) + C.supportedFeatures.insert(feature); + } + llvm::json::ObjectMapper O(Params, P); + return O && + O.mapOptional("exceptionBreakpointFilters", + C.exceptionBreakpointFilters) && + O.mapOptional("completionTriggerCharacters", + C.completionTriggerCharacters) && + O.mapOptional("additionalModuleColumns", C.additionalModuleColumns) && + O.mapOptional("supportedChecksumAlgorithms", + C.supportedChecksumAlgorithms) && + O.mapOptional("breakpointModes", C.breakpointModes) && + O.mapOptional("$__lldb_version", C.lldbExtVersion); +} + bool fromJSON(const llvm::json::Value &Params, SteppingGranularity &SG, llvm::json::Path P) { auto raw_granularity = Params.getAsString(); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index c48988a48a373..f8d2b35ce3e14 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -102,6 +102,7 @@ enum ChecksumAlgorithm : unsigned { eChecksumAlgorithmSHA256, eChecksumAlgorithmTimestamp }; +bool fromJSON(const llvm::json::Value &, ChecksumAlgorithm &, llvm::json::Path); llvm::json::Value toJSON(const ChecksumAlgorithm &); /// Describes one or more type of breakpoint a BreakpointMode applies to. This @@ -237,7 +238,11 @@ enum AdapterFeature : unsigned { /// The debug adapter supports the `terminateDebuggee` attribute on the /// `disconnect` request. eAdapterFeatureTerminateDebuggee, + eAdapterFeatureFirst = eAdapterFeatureANSIStyling, + eAdapterFeatureLast = eAdapterFeatureTerminateDebuggee, }; +bool fromJSON(const llvm::json::Value &, AdapterFeature &, llvm::json::Path); +llvm::json::Value toJSON(const AdapterFeature &); /// Information about the capabilities of a debug adapter. struct Capabilities { @@ -275,13 +280,15 @@ struct Capabilities { /// @} }; +bool fromJSON(const llvm::json::Value &, Capabilities &, llvm::json::Path); llvm::json::Value toJSON(const Capabilities &); enum PresentationHint : unsigned { ePresentationHintNormal, ePresentationHintEmphasize, - ePresentationHintDeemphasize, + ePresentationHintDeemphasize }; +bool fromJSON(const llvm::json::Value &, PresentationHint &, llvm::json::Path); llvm::json::Value toJSON(PresentationHint hint); /// A `Source` is a descriptor for source code. It is returned from the debug diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp index f5d72f06432d5..fd3e3be073183 100644 --- a/lldb/unittests/DAP/ProtocolTypesTest.cpp +++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp @@ -194,3 +194,100 @@ TEST(ProtocolTypesTest, DataBreakpoint) { EXPECT_EQ(data_breakpoint_info.hitCondition, deserialized_data_breakpoint_info->hitCondition); } + +TEST(ProtocolTypesTest, Capabilities) { + Capabilities capabilities; + + // Populate supported features. + capabilities.supportedFeatures.insert(eAdapterFeatureANSIStyling); + capabilities.supportedFeatures.insert( + eAdapterFeatureBreakpointLocationsRequest); + + // Populate optional fields. + capabilities.exceptionBreakpointFilters = { + {{"filter1", "Filter 1", "Description 1", true, true, "Condition 1"}, + {"filter2", "Filter 2", "Description 2", false, false, "Condition 2"}}}; + + capabilities.completionTriggerCharacters = {".", "->"}; + capabilities.additionalModuleColumns = { + {"moduleName", "Module Name", "uppercase", eColumnTypeString, 20}}; + capabilities.supportedChecksumAlgorithms = {eChecksumAlgorithmMD5, + eChecksumAlgorithmSHA256}; + capabilities.breakpointModes = {{"hardware", + "Hardware Breakpoint", + "Description", + {eBreakpointModeApplicabilitySource}}}; + capabilities.lldbExtVersion = "1.0.0"; + + // Perform roundtrip serialization and deserialization. + llvm::Expected deserialized_capabilities = + roundtrip(capabilities); + ASSERT_THAT_EXPECTED(deserialized_capabilities, llvm::Succeeded()); + + // Verify supported features. + EXPECT_EQ(capabilities.supportedFeatures, + deserialized_capabilities->supportedFeatures); + + // Verify exception breakpoint filters. + ASSERT_TRUE( + deserialized_capabilities->exceptionBreakpointFilters.has_value()); + EXPECT_EQ(capabilities.exceptionBreakpointFilters->size(), + deserialized_capabilities->exceptionBreakpointFilters->size()); + for (size_t i = 0; i < capabilities.exceptionBreakpointFilters->size(); ++i) { + const auto &original = capabilities.exceptionBreakpointFilters->at(i); + const auto &deserialized = + deserialized_capabilities->exceptionBreakpointFilters->at(i); + EXPECT_EQ(original.filter, deserialized.filter); + EXPECT_EQ(original.label, deserialized.label); + EXPECT_EQ(original.description, deserialized.description); + EXPECT_EQ(original.defaultState, deserialized.defaultState); + EXPECT_EQ(original.supportsCondition, deserialized.supportsCondition); + EXPECT_EQ(original.conditionDescription, deserialized.conditionDescription); + } + + // Verify completion trigger characters. + ASSERT_TRUE( + deserialized_capabilities->completionTriggerCharacters.has_value()); + EXPECT_EQ(capabilities.completionTriggerCharacters, + deserialized_capabilities->completionTriggerCharacters); + + // Verify additional module columns. + ASSERT_TRUE(deserialized_capabilities->additionalModuleColumns.has_value()); + EXPECT_EQ(capabilities.additionalModuleColumns->size(), + deserialized_capabilities->additionalModuleColumns->size()); + for (size_t i = 0; i < capabilities.additionalModuleColumns->size(); ++i) { + const auto &original = capabilities.additionalModuleColumns->at(i); + const auto &deserialized = + deserialized_capabilities->additionalModuleColumns->at(i); + EXPECT_EQ(original.attributeName, deserialized.attributeName); + EXPECT_EQ(original.label, deserialized.label); + EXPECT_EQ(original.format, deserialized.format); + EXPECT_EQ(original.type, deserialized.type); + EXPECT_EQ(original.width, deserialized.width); + } + + // Verify supported checksum algorithms. + ASSERT_TRUE( + deserialized_capabilities->supportedChecksumAlgorithms.has_value()); + EXPECT_EQ(capabilities.supportedChecksumAlgorithms, + deserialized_capabilities->supportedChecksumAlgorithms); + + // Verify breakpoint modes. + ASSERT_TRUE(deserialized_capabilities->breakpointModes.has_value()); + EXPECT_EQ(capabilities.breakpointModes->size(), + deserialized_capabilities->breakpointModes->size()); + for (size_t i = 0; i < capabilities.breakpointModes->size(); ++i) { + const auto &original = capabilities.breakpointModes->at(i); + const auto &deserialized = + deserialized_capabilities->breakpointModes->at(i); + EXPECT_EQ(original.mode, deserialized.mode); + EXPECT_EQ(original.label, deserialized.label); + EXPECT_EQ(original.description, deserialized.description); + EXPECT_EQ(original.appliesTo, deserialized.appliesTo); + } + + // Verify lldb extension version. + ASSERT_TRUE(deserialized_capabilities->lldbExtVersion.has_value()); + EXPECT_EQ(capabilities.lldbExtVersion, + deserialized_capabilities->lldbExtVersion); +} ``````````
https://github.com/llvm/llvm-project/pull/139835 From lldb-commits at lists.llvm.org Tue May 13 21:46:24 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Tue, 13 May 2025 21:46:24 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Adding NativeThreadAIX (PR #139537) In-Reply-To: Message-ID: <68242020.050a0220.13ccdb.1b62@mx.google.com> https://github.com/DhruvSrivastavaX edited https://github.com/llvm/llvm-project/pull/139537 From lldb-commits at lists.llvm.org Tue May 13 21:48:38 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Tue, 13 May 2025 21:48:38 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Adding NativeThreadAIX (PR #139537) In-Reply-To: Message-ID: <682420a6.170a0220.2c12b8.15f7@mx.google.com> https://github.com/DhruvSrivastavaX edited https://github.com/llvm/llvm-project/pull/139537 From lldb-commits at lists.llvm.org Tue May 13 21:49:40 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Tue, 13 May 2025 21:49:40 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Adding NativeThreadAIX (PR #139537) In-Reply-To: Message-ID: <682420e4.630a0220.6cc13.7b63@mx.google.com> https://github.com/DhruvSrivastavaX updated https://github.com/llvm/llvm-project/pull/139537 >From 05aef7d40097d9a554c648fa2be75530f23ca05c Mon Sep 17 00:00:00 2001 From: DhruvSrivastavaX Date: Mon, 12 May 2025 03:23:49 -0500 Subject: [PATCH 1/2] Added NativeThreadAIX --- .../source/Plugins/Process/AIX/CMakeLists.txt | 1 + .../Plugins/Process/AIX/NativeThreadAIX.cpp | 71 +++++++++++++++++++ .../Plugins/Process/AIX/NativeThreadAIX.h | 53 ++++++++++++++ 3 files changed, 125 insertions(+) create mode 100644 lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeThreadAIX.h diff --git a/lldb/source/Plugins/Process/AIX/CMakeLists.txt b/lldb/source/Plugins/Process/AIX/CMakeLists.txt index 9a3c77bd2ffeb..911f30349ef52 100644 --- a/lldb/source/Plugins/Process/AIX/CMakeLists.txt +++ b/lldb/source/Plugins/Process/AIX/CMakeLists.txt @@ -1,5 +1,6 @@ add_lldb_library(lldbPluginProcessAIX NativeProcessAIX.cpp + NativeThreadAIX.cpp LINK_LIBS lldbCore diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp new file mode 100644 index 0000000000000..c9593fbf08441 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp @@ -0,0 +1,71 @@ +//===-- NativeThreadAIX.cpp ---------------------------------------------===// +// +// 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 "NativeThreadAIX.h" +#include "NativeProcessAIX.h" +#include "lldb/Utility/State.h" +#include +#include + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; + +NativeThreadAIX::NativeThreadAIX(NativeProcessAIX &process, lldb::tid_t tid) + : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid) {} + +std::string NativeThreadAIX::GetName() { + NativeProcessAIX &process = GetProcess(); + auto BufferOrError = getProcFile(process.GetID(), "psinfo"); + if (!BufferOrError) + return ""; + auto &Buffer = *BufferOrError; + if (Buffer->getBufferSize() < sizeof(psinfo_t)) + return ""; + const psinfo_t *psinfo = + reinterpret_cast(Buffer->getBufferStart()); + return std::string(psinfo->pr_fname); +} + +lldb::StateType NativeThreadAIX::GetState() { return m_state; } + +bool NativeThreadAIX::GetStopReason(ThreadStopInfo &stop_info, + std::string &description) { + return false; +} + +Status NativeThreadAIX::SetWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags, bool hardware) { + return Status(); +} + +Status NativeThreadAIX::RemoveWatchpoint(lldb::addr_t addr) { + return Status("Clearing hardware watchpoint failed."); +} + +Status NativeThreadAIX::SetHardwareBreakpoint(lldb::addr_t addr, size_t size) { + return Status(); +} + +Status NativeThreadAIX::RemoveHardwareBreakpoint(lldb::addr_t addr) { + return Status("Clearing hardware breakpoint failed."); +} + +NativeProcessAIX &NativeThreadAIX::GetProcess() { + return static_cast(m_process); +} + +const NativeProcessAIX &NativeThreadAIX::GetProcess() const { + return static_cast(m_process); +} + +llvm::Expected> +NativeThreadAIX::GetSiginfo() const { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Not implemented"); +} diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h new file mode 100644 index 0000000000000..e32d3db2c5fa2 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h @@ -0,0 +1,53 @@ +//===-- NativeThreadAIX.h ----------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_NATIVETHREADAIX_H_ +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_NATIVETHREADAIX_H_ + +#include "lldb/Host/common/NativeThreadProtocol.h" + +namespace lldb_private::process_aix { + +class NativeProcessAIX; + +class NativeThreadAIX : public NativeThreadProtocol { + friend class NativeProcessAIX; + +public: + NativeThreadAIX(NativeProcessAIX &process, lldb::tid_t tid); + + // NativeThreadProtocol Interface + std::string GetName() override; + + lldb::StateType GetState() override; + + bool GetStopReason(ThreadStopInfo &stop_info, + std::string &description) override; + + Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, + bool hardware) override; + + Status RemoveWatchpoint(lldb::addr_t addr) override; + + Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override; + + Status RemoveHardwareBreakpoint(lldb::addr_t addr) override; + + NativeProcessAIX &GetProcess(); + + const NativeProcessAIX &GetProcess() const; + + llvm::Expected> + GetSiginfo() const override; + +private: + lldb::StateType m_state; +}; +} // namespace lldb_private::process_aix + +#endif // #ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_NATIVETHREADAIX_H_ >From c78c83f861e5ce438bdbc103dca1bd495425956a Mon Sep 17 00:00:00 2001 From: DhruvSrivastavaX Date: Tue, 13 May 2025 23:49:27 -0500 Subject: [PATCH 2/2] Modified returns --- lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp index c9593fbf08441..75a5c2b6ad2a8 100644 --- a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp @@ -41,7 +41,7 @@ bool NativeThreadAIX::GetStopReason(ThreadStopInfo &stop_info, Status NativeThreadAIX::SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) { - return Status(); + return Status("Unable to Set hardware watchpoint."); } Status NativeThreadAIX::RemoveWatchpoint(lldb::addr_t addr) { @@ -49,7 +49,7 @@ Status NativeThreadAIX::RemoveWatchpoint(lldb::addr_t addr) { } Status NativeThreadAIX::SetHardwareBreakpoint(lldb::addr_t addr, size_t size) { - return Status(); + return Status("Unable to set hardware breakpoint."); } Status NativeThreadAIX::RemoveHardwareBreakpoint(lldb::addr_t addr) { From lldb-commits at lists.llvm.org Tue May 13 21:49:55 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Tue, 13 May 2025 21:49:55 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Adding NativeThreadAIX (PR #139537) In-Reply-To: Message-ID: <682420f3.170a0220.53196.15dd@mx.google.com> ================ @@ -0,0 +1,71 @@ +//===-- NativeThreadAIX.cpp ---------------------------------------------===// +// +// 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 "NativeThreadAIX.h" +#include "NativeProcessAIX.h" +#include "lldb/Utility/State.h" +#include +#include + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; + +NativeThreadAIX::NativeThreadAIX(NativeProcessAIX &process, lldb::tid_t tid) + : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid) {} + +std::string NativeThreadAIX::GetName() { + NativeProcessAIX &process = GetProcess(); + auto BufferOrError = getProcFile(process.GetID(), "psinfo"); + if (!BufferOrError) + return ""; + auto &Buffer = *BufferOrError; + if (Buffer->getBufferSize() < sizeof(psinfo_t)) + return ""; + const psinfo_t *psinfo = + reinterpret_cast(Buffer->getBufferStart()); + return std::string(psinfo->pr_fname); +} + +lldb::StateType NativeThreadAIX::GetState() { return m_state; } + +bool NativeThreadAIX::GetStopReason(ThreadStopInfo &stop_info, + std::string &description) { + return false; +} + +Status NativeThreadAIX::SetWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags, bool hardware) { + return Status(); ---------------- DhruvSrivastavaX wrote: Done. https://github.com/llvm/llvm-project/pull/139537 From lldb-commits at lists.llvm.org Tue May 13 21:54:44 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Tue, 13 May 2025 21:54:44 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Adding NativeThreadAIX (PR #139537) In-Reply-To: Message-ID: <68242214.170a0220.7f76.fe5b@mx.google.com> https://github.com/DhruvSrivastavaX edited https://github.com/llvm/llvm-project/pull/139537 From lldb-commits at lists.llvm.org Tue May 13 21:56:37 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Tue, 13 May 2025 21:56:37 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Adding NativeThreadAIX (PR #139537) In-Reply-To: Message-ID: <68242285.170a0220.fc349.fbb4@mx.google.com> https://github.com/DhruvSrivastavaX edited https://github.com/llvm/llvm-project/pull/139537 From lldb-commits at lists.llvm.org Tue May 13 22:03:17 2025 From: lldb-commits at lists.llvm.org (Jason Molenda via lldb-commits) Date: Tue, 13 May 2025 22:03:17 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][NFC] Split RegisterContextUnwind::SavedLocationForRegister (PR #139817) In-Reply-To: Message-ID: <68242415.050a0220.18e5dd.37fb@mx.google.com> https://github.com/jasonmolenda updated https://github.com/llvm/llvm-project/pull/139817 >From e63e53adc0909f481a165eca958a3ac2ca4374ee Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 13 May 2025 17:11:08 -0700 Subject: [PATCH 1/5] [lldb][NFC] Split RegisterContextUnwind::SavedLocationForRegister RegisterContextUnwind::SavedLocationForRegister is around 450 lines that first find an abstract register location (e.g. "CFA-8") for a register by looking in the UnwindPlans. Then it evaluates the abstract register location to create a concrete register location (e.g. "stored at address 0x...", "live in register at frame 0"). There are some complicated cases in the first half of the method to handle return address register architectures correctly, in particular. Looking at the two halves, they're both exactly 226 lines long and there's little involvement between them except for passing an abstract register location along. (there were some parts in the "abstract register location" code that would set the concrete register location, unnecessarily) It's also a complex enough method that there are some bits of code that aren't actually doing anything at this point. This patch adds a RegisterContextUnwind::GetAbstractRegisterLocation method, which does the first half, and has a clearly defined return values. The code to convert an AbstractRegisterLocation into a ConcreteRegisterLocation remains in SavedLocationForRegister. It's a bit of a tricky patch to visually inspect, despite it not changing functionality, the reorganizations and rewrites make the diff unreadable. Nearly all the real changes are in the "find the abstract register location" first half of the method. I think reading the new code in its new form is the easiest way to inspect this PR. With a defined interface between the two of what is expected, it's pretty easy to look at the code and reason about whether it is written correctly. (whereas before, that was very difficult, for me at least.) --- .../lldb/Target/RegisterContextUnwind.h | 3 + lldb/source/Target/RegisterContextUnwind.cpp | 530 +++++++++--------- lldb/source/Target/RegisterNumber.cpp | 1 + 3 files changed, 259 insertions(+), 275 deletions(-) diff --git a/lldb/include/lldb/Target/RegisterContextUnwind.h b/lldb/include/lldb/Target/RegisterContextUnwind.h index 044a387fe5aa2..b10a364823b83 100644 --- a/lldb/include/lldb/Target/RegisterContextUnwind.h +++ b/lldb/include/lldb/Target/RegisterContextUnwind.h @@ -151,6 +151,9 @@ class RegisterContextUnwind : public lldb_private::RegisterContext { uint32_t lldb_regnum, lldb_private::UnwindLLDB::ConcreteRegisterLocation ®loc); + std::optional + GetAbstractRegisterLocation(uint32_t lldb_regnum, lldb::RegisterKind &kind); + bool ReadRegisterValueFromRegisterLocation( lldb_private::UnwindLLDB::ConcreteRegisterLocation regloc, const lldb_private::RegisterInfo *reg_info, diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index cf4b96c6eda9f..a3931abefb054 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1243,247 +1243,194 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( return false; } -// Answer the question: Where did THIS frame save the CALLER frame ("previous" -// frame)'s register value? - -enum UnwindLLDB::RegisterSearchResult -RegisterContextUnwind::SavedLocationForRegister( - uint32_t lldb_regnum, - lldb_private::UnwindLLDB::ConcreteRegisterLocation ®loc) { +// Search this stack frame's UnwindPlans for the AbstractRegisterLocation +// for this register. +// +// When an AbstractRegisterLocation is found in an UnwindPlan, that is +// returned, regardless of the ABI rules for volatile/non-volatile registers +// in effect. +// +// If there is no unwind rule for a volatile (caller-preserved) register +// the returned AbstractRegisterLocation will be IsUndefined, +// indicating that we should stop searching. +// +// If there is no unwind rule for a non-volatile (callee-preserved) +// register, the returned AbstractRegisterLocation will be IsSame. +// In frame 0, IsSame means get the value from the live register context. +// Else it means to continue descending down the stack to more-live frames +// looking for a location/value. +// +// An empty optional indicates that there was an error in processing. +std::optional +RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, + lldb::RegisterKind &kind) { RegisterNumber regnum(m_thread, eRegisterKindLLDB, lldb_regnum); Log *log = GetLog(LLDBLog::Unwind); - // Have we already found this register location? - if (!m_registers.empty()) { - std::map::const_iterator - iterator; - iterator = m_registers.find(regnum.GetAsKind(eRegisterKindLLDB)); - if (iterator != m_registers.end()) { - regloc = iterator->second; - UnwindLogMsg("supplying caller's saved %s (%d)'s location, cached", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } - } - - // Look through the available UnwindPlans for the register location. - UnwindPlan::Row::AbstractRegisterLocation unwindplan_regloc; - bool have_unwindplan_regloc = false; - RegisterKind unwindplan_registerkind = kNumRegisterKinds; + // First, try to find a register location via the FastUnwindPlan if (m_fast_unwind_plan_sp) { const UnwindPlan::Row *active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); - unwindplan_registerkind = m_fast_unwind_plan_sp->GetRegisterKind(); - if (regnum.GetAsKind(unwindplan_registerkind) == LLDB_INVALID_REGNUM) { + kind = m_fast_unwind_plan_sp->GetRegisterKind(); + if (regnum.GetAsKind(kind) == LLDB_INVALID_REGNUM) { UnwindLogMsg("could not convert lldb regnum %s (%d) into %d RegisterKind " "reg numbering scheme", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - (int)unwindplan_registerkind); - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; + (int)kind); + return {}; } // The architecture default unwind plan marks unknown registers as // Undefined so that we don't forward them up the stack when a // jitted stack frame may have overwritten them. But when the // arch default unwind plan is used as the Fast Unwind Plan, we // need to recognize this & switch over to the Full Unwind Plan - // to see what unwind rule that (more knoweldgeable, probably) - // UnwindPlan has. If the full UnwindPlan says the register - // location is Undefined, then it really is. - if (active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind), + // to see what unwind rule that (more knowledgeable, probably) + // UnwindPlan has. + if (active_row->GetRegisterInfo(regnum.GetAsKind(kind), unwindplan_regloc) && !unwindplan_regloc.IsUndefined()) { UnwindLogMsg( "supplying caller's saved %s (%d)'s location using FastUnwindPlan", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - have_unwindplan_regloc = true; + return unwindplan_regloc; } } - if (!have_unwindplan_regloc) { - // m_full_unwind_plan_sp being NULL means that we haven't tried to find a - // full UnwindPlan yet - bool got_new_full_unwindplan = false; - if (!m_full_unwind_plan_sp) { - m_full_unwind_plan_sp = GetFullUnwindPlanForFrame(); - got_new_full_unwindplan = true; - } + // Second, try to find a register location via the FullUnwindPlan. + bool got_new_full_unwindplan = false; + if (!m_full_unwind_plan_sp) { + m_full_unwind_plan_sp = GetFullUnwindPlanForFrame(); + got_new_full_unwindplan = true; + } + if (m_full_unwind_plan_sp) { + RegisterNumber pc_regnum(m_thread, eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_PC); - if (m_full_unwind_plan_sp) { - RegisterNumber pc_regnum(m_thread, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_PC); + const UnwindPlan::Row *active_row = + m_full_unwind_plan_sp->GetRowForFunctionOffset( + m_current_offset_backed_up_one); + kind = m_full_unwind_plan_sp->GetRegisterKind(); - const UnwindPlan::Row *active_row = - m_full_unwind_plan_sp->GetRowForFunctionOffset( - m_current_offset_backed_up_one); - unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind(); + if (got_new_full_unwindplan && active_row && log) { + StreamString active_row_strm; + ExecutionContext exe_ctx(m_thread.shared_from_this()); + active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, + m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); + UnwindLogMsg("Using full unwind plan '%s'", + m_full_unwind_plan_sp->GetSourceName().AsCString()); + UnwindLogMsg("active row: %s", active_row_strm.GetData()); + } - if (got_new_full_unwindplan && active_row && log) { - StreamString active_row_strm; - ExecutionContext exe_ctx(m_thread.shared_from_this()); - active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), - &m_thread, - m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); - UnwindLogMsg("Using full unwind plan '%s'", - m_full_unwind_plan_sp->GetSourceName().AsCString()); - UnwindLogMsg("active row: %s", active_row_strm.GetData()); + if (regnum.GetAsKind(kind) == LLDB_INVALID_REGNUM) { + if (kind == eRegisterKindGeneric) { + UnwindLogMsg("could not convert lldb regnum %s (%d) into " + "eRegisterKindGeneric reg numbering scheme", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + } else { + UnwindLogMsg("could not convert lldb regnum %s (%d) into %d " + "RegisterKind reg numbering scheme", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), + (int)kind); } + return {}; + } + + if (regnum.IsValid() && active_row && + active_row->GetRegisterInfo(regnum.GetAsKind(kind), + unwindplan_regloc)) { + UnwindLogMsg( + "supplying caller's saved %s (%d)'s location using %s UnwindPlan", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), + m_full_unwind_plan_sp->GetSourceName().GetCString()); + return unwindplan_regloc; + } + + // When asking for the caller's pc, check if we have a + // Return Address register on this target. + // + // On a Return Address Register architecture like arm/mips/riscv, + // the caller's pc is in the RA register, and will be spilled to + // stack before any other function can be called. We may have a + // register location saying + // pc=RAReg {caller's retrun addr is in RA register} + // ra=IsSame {caller's return addr is live in RA register} + // ra=StackAddr {caller's return addr spilled to stack} + // or none of the above, which means the caller's pc is live in the + // return address reg if this is frame 0, or the frame below is + // a trap/sigtramp/interrupt handler function. Any other mid-stack + // function must have an unwind rule for PC/RA giving a location/value. + // + // In the case of an interrupted function -- the function above sigtramp, + // or a function interrupted asynchronously, or that has faulted to + // a trap handler -- it is valid to ask both the "pc" value -- the + // instruction that was executing when the interrupt/fault happend -- + // and the RA Register value. If a frameless function (which doesn't + // create a stack frame, doesn't save the RA reg to stack) is interrupted, + // the trap handler will have a rule to provide the pc (the instruction + // that was executing) AND a rule to provide the RA Register, which we + // need to use to find the caller function: + // pc=StackAddr1 + // ra=StackAddr2 + // and we don't want to rewrite a request of "pc" to "ra" here, because + // they mean different things. + + if (pc_regnum.IsValid() && pc_regnum == regnum) { RegisterNumber return_address_reg; + uint32_t return_address_regnum = + LLDB_INVALID_REGNUM; // in full UnwindPlan's numbering + + // Get the return address register number from the UnwindPlan + // or the arch register set. + if (m_full_unwind_plan_sp->GetReturnAddressRegister() != + LLDB_INVALID_REGNUM) { + return_address_regnum = + m_full_unwind_plan_sp->GetReturnAddressRegister(); + } else { + RegisterNumber arch_default_ra_regnum(m_thread, eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_RA); + return_address_regnum = arch_default_ra_regnum.GetAsKind(kind); + } - // If we're fetching the saved pc and this UnwindPlan defines a - // ReturnAddress register (e.g. lr on arm), look for the return address - // register number in the UnwindPlan's row. - if (pc_regnum.IsValid() && pc_regnum == regnum && - m_full_unwind_plan_sp->GetReturnAddressRegister() != - LLDB_INVALID_REGNUM) { - // If this is a trap handler frame, we should have access to - // the complete register context when the interrupt/async - // signal was received, we should fetch the actual saved $pc - // value instead of the Return Address register. - // If $pc is not available, fall back to the RA reg. + if (return_address_regnum != LLDB_INVALID_REGNUM) { UnwindPlan::Row::AbstractRegisterLocation scratch; + // This is a sigtramp/interrupt handler - treat a + // request for "pc" and "ra" as distinct. if (m_frame_type == eTrapHandlerFrame && active_row && - active_row->GetRegisterInfo( - pc_regnum.GetAsKind(unwindplan_registerkind), scratch)) { + active_row->GetRegisterInfo(pc_regnum.GetAsKind(kind), scratch)) { UnwindLogMsg("Providing pc register instead of rewriting to " "RA reg because this is a trap handler and there is " "a location for the saved pc register value."); } else { - return_address_reg.init( - m_thread, m_full_unwind_plan_sp->GetRegisterKind(), - m_full_unwind_plan_sp->GetReturnAddressRegister()); + // This is a normal function, there's no rule for + // finding the caller's pc value, look for the caller's + // return address register value. + return_address_reg.init(m_thread, + m_full_unwind_plan_sp->GetRegisterKind(), + return_address_regnum); regnum = return_address_reg; UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a " "RA reg; getting %s (%d) instead", return_address_reg.GetName(), return_address_reg.GetAsKind(eRegisterKindLLDB)); - } - } else { - if (regnum.GetAsKind(unwindplan_registerkind) == LLDB_INVALID_REGNUM) { - if (unwindplan_registerkind == eRegisterKindGeneric) { - UnwindLogMsg("could not convert lldb regnum %s (%d) into " - "eRegisterKindGeneric reg numbering scheme", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - } else { - UnwindLogMsg("could not convert lldb regnum %s (%d) into %d " - "RegisterKind reg numbering scheme", + if (active_row && active_row->GetRegisterInfo(regnum.GetAsKind(kind), + unwindplan_regloc)) { + UnwindLogMsg("supplying caller's saved %s (%d)'s location using " + "%s UnwindPlan", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - (int)unwindplan_registerkind); - } - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - } - } - - // Check if the active_row has a register location listed. - if (regnum.IsValid() && active_row && - active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind), - unwindplan_regloc)) { - have_unwindplan_regloc = true; - UnwindLogMsg( - "supplying caller's saved %s (%d)'s location using %s UnwindPlan", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - m_full_unwind_plan_sp->GetSourceName().GetCString()); - } - - // This is frame 0 and we're retrieving the PC and it's saved in a Return - // Address register and it hasn't been saved anywhere yet -- that is, - // it's still live in the actual register. Handle this specially. - if (!have_unwindplan_regloc && return_address_reg.IsValid() && - return_address_reg.GetAsKind(eRegisterKindLLDB) != - LLDB_INVALID_REGNUM) { - if (IsFrameZero()) { - lldb_private::UnwindLLDB::ConcreteRegisterLocation new_regloc; - new_regloc.type = UnwindLLDB::ConcreteRegisterLocation:: - eRegisterInLiveRegisterContext; - new_regloc.location.register_number = - return_address_reg.GetAsKind(eRegisterKindLLDB); - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; - regloc = new_regloc; - UnwindLogMsg("supplying caller's register %s (%d) from the live " - "RegisterContext at frame 0, saved in %d", - return_address_reg.GetName(), - return_address_reg.GetAsKind(eRegisterKindLLDB), - return_address_reg.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } else if (BehavesLikeZerothFrame()) { - // This function was interrupted asynchronously -- it faulted, - // an async interrupt, a timer fired, a debugger expression etc. - // The caller's pc is in the Return Address register, but the - // UnwindPlan for this function may have no location rule for - // the RA reg. - // This means that the caller's return address is in the RA reg - // when the function was interrupted--descend down one stack frame - // to retrieve it from the trap handler's saved context. - unwindplan_regloc.SetSame(); - have_unwindplan_regloc = true; - } - } - - // If this architecture stores the return address in a register (it - // defines a Return Address register) and we're on a non-zero stack frame - // and the Full UnwindPlan says that the pc is stored in the - // RA registers (e.g. lr on arm), then we know that the full unwindplan is - // not trustworthy -- this - // is an impossible situation and the instruction emulation code has - // likely been misled. If this stack frame meets those criteria, we need - // to throw away the Full UnwindPlan that the instruction emulation came - // up with and fall back to the architecture's Default UnwindPlan so the - // stack walk can get past this point. - - // Special note: If the Full UnwindPlan was generated from the compiler, - // don't second-guess it when we're at a call site location. - - // arch_default_ra_regnum is the return address register # in the Full - // UnwindPlan register numbering - RegisterNumber arch_default_ra_regnum(m_thread, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_RA); - - if (arch_default_ra_regnum.GetAsKind(unwindplan_registerkind) != - LLDB_INVALID_REGNUM && - pc_regnum == regnum && unwindplan_regloc.IsInOtherRegister() && - unwindplan_regloc.GetRegisterNumber() == - arch_default_ra_regnum.GetAsKind(unwindplan_registerkind) && - m_full_unwind_plan_sp->GetSourcedFromCompiler() != eLazyBoolYes && - !m_all_registers_available) { - UnwindLogMsg("%s UnwindPlan tried to restore the pc from the link " - "register but this is a non-zero frame", - m_full_unwind_plan_sp->GetSourceName().GetCString()); - - // Throw away the full unwindplan; install the arch default unwindplan - if (ForceSwitchToFallbackUnwindPlan()) { - // Update for the possibly new unwind plan - unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind(); - const UnwindPlan::Row *active_row = - m_full_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); - - // Sanity check: Verify that we can fetch a pc value and CFA value - // with this unwind plan - - RegisterNumber arch_default_pc_reg(m_thread, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_PC); - bool can_fetch_pc_value = false; - bool can_fetch_cfa = false; - addr_t cfa_value; - if (active_row) { - if (arch_default_pc_reg.GetAsKind(unwindplan_registerkind) != - LLDB_INVALID_REGNUM && - active_row->GetRegisterInfo( - arch_default_pc_reg.GetAsKind(unwindplan_registerkind), - unwindplan_regloc)) { - can_fetch_pc_value = true; - } - if (ReadFrameAddress(unwindplan_registerkind, - active_row->GetCFAValue(), cfa_value)) { - can_fetch_cfa = true; + m_full_unwind_plan_sp->GetSourceName().GetCString()); + if (unwindplan_regloc.IsSame()) + unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + return unwindplan_regloc; + } else { + // No unwind rule for the return address reg on frame + // 0 means that the caller's address is still in RA reg. + if (BehavesLikeZerothFrame()) { + unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + return unwindplan_regloc; } } - - have_unwindplan_regloc = can_fetch_pc_value && can_fetch_cfa; - } else { - // We were unable to fall back to another unwind plan - have_unwindplan_regloc = false; } } } @@ -1491,55 +1438,84 @@ RegisterContextUnwind::SavedLocationForRegister( ExecutionContext exe_ctx(m_thread.shared_from_this()); Process *process = exe_ctx.GetProcessPtr(); - if (!have_unwindplan_regloc) { - // If the UnwindPlan failed to give us an unwind location for this - // register, we may be able to fall back to some ABI-defined default. For - // example, some ABIs allow to determine the caller's SP via the CFA. Also, - // the ABI may set volatile registers to the undefined state. - ABI *abi = process ? process->GetABI().get() : nullptr; - if (abi) { - const RegisterInfo *reg_info = - GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB)); - if (reg_info && - abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) { - UnwindLogMsg( - "supplying caller's saved %s (%d)'s location using ABI default", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - have_unwindplan_regloc = true; - } + + // Third, try finding a register location via the ABI + // FallbackRegisterLocation. + // + // If the UnwindPlan failed to give us an unwind location for this + // register, we may be able to fall back to some ABI-defined default. For + // example, some ABIs allow to determine the caller's SP via the CFA. Also, + // the ABI willset volatile registers to the undefined state. + ABI *abi = process ? process->GetABI().get() : nullptr; + if (abi) { + const RegisterInfo *reg_info = + GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB)); + if (reg_info && + abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) { + UnwindLogMsg( + "supplying caller's saved %s (%d)'s location using ABI default", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + return unwindplan_regloc; } } - if (!have_unwindplan_regloc) { - if (IsFrameZero()) { - // This is frame 0 - we should return the actual live register context - // value - lldb_private::UnwindLLDB::ConcreteRegisterLocation new_regloc; - new_regloc.type = - UnwindLLDB::ConcreteRegisterLocation::eRegisterInLiveRegisterContext; - new_regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; - regloc = new_regloc; - UnwindLogMsg("supplying caller's register %s (%d) from the live " - "RegisterContext at frame 0", + // We have no AbstractRegisterRule, and the ABI says this is a + // non-volatile / callee-preserved register. + std::string unwindplan_name; + if (m_full_unwind_plan_sp) { + unwindplan_name += "via '"; + unwindplan_name += m_full_unwind_plan_sp->GetSourceName().AsCString(); + unwindplan_name += "'"; + } + UnwindLogMsg("no save location for %s (%d) %s", regnum.GetName(), + regnum.GetAsKind(eRegisterKindLLDB), unwindplan_name.c_str()); + + unwindplan_regloc.SetSame(); + return unwindplan_regloc; +} + +// Answer the question: Where did THIS frame save the CALLER frame ("previous" +// frame)'s register value? + +enum UnwindLLDB::RegisterSearchResult +RegisterContextUnwind::SavedLocationForRegister( + uint32_t lldb_regnum, + lldb_private::UnwindLLDB::ConcreteRegisterLocation ®loc) { + RegisterNumber regnum(m_thread, eRegisterKindLLDB, lldb_regnum); + Log *log = GetLog(LLDBLog::Unwind); + + // Have we already found this register location? + if (!m_registers.empty()) { + std::map::const_iterator + iterator; + iterator = m_registers.find(regnum.GetAsKind(eRegisterKindLLDB)); + if (iterator != m_registers.end()) { + regloc = iterator->second; + UnwindLogMsg("supplying caller's saved %s (%d)'s location, cached", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } else { - std::string unwindplan_name; - if (m_full_unwind_plan_sp) { - unwindplan_name += "via '"; - unwindplan_name += m_full_unwind_plan_sp->GetSourceName().AsCString(); - unwindplan_name += "'"; - } - UnwindLogMsg("no save location for %s (%d) %s", regnum.GetName(), - regnum.GetAsKind(eRegisterKindLLDB), - unwindplan_name.c_str()); } + } + + RegisterKind abs_regkind; + std::optional abs_regloc = + GetAbstractRegisterLocation(lldb_regnum, abs_regkind); + + if (!abs_regloc) return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; + + if (abs_regloc->IsUndefined()) { + UnwindLogMsg( + "did not supply reg location for %s (%d) because it is volatile", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile; } - // unwindplan_regloc has valid contents about where to retrieve the register - if (unwindplan_regloc.IsUnspecified()) { + ExecutionContext exe_ctx(m_thread.shared_from_this()); + Process *process = exe_ctx.GetProcessPtr(); + // abs_regloc has valid contents about where to retrieve the register + if (abs_regloc->IsUnspecified()) { lldb_private::UnwindLLDB::ConcreteRegisterLocation new_regloc = {}; new_regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterNotSaved; m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; @@ -1548,15 +1524,23 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; } - if (unwindplan_regloc.IsUndefined()) { - UnwindLogMsg( - "did not supply reg location for %s (%d) because it is volatile", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile; - } - - if (unwindplan_regloc.IsSame()) { - if (!m_all_registers_available && + if (abs_regloc->IsSame()) { + if (IsFrameZero()) { + regloc.type = + UnwindLLDB::ConcreteRegisterLocation::eRegisterInLiveRegisterContext; + regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); + m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; + UnwindLogMsg("supplying caller's register %s (%d) from the live " + "RegisterContext at frame 0", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + return UnwindLLDB::RegisterSearchResult::eRegisterFound; + } + // PC/RA reg don't follow the usual "callee-saved aka non-volatile" versus + // "caller saved aka volatile" system. A stack frame can provide its caller + // return address, but if we don't find a rule for pc/RA mid-stack, we + // never want to iterate further down the stack looking for it. + // Defensively prevent iterating down the stack for these two. + if (!BehavesLikeZerothFrame() && (regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_PC || regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_RA)) { UnwindLogMsg("register %s (%d) is marked as 'IsSame' - it is a pc or " @@ -1564,20 +1548,19 @@ RegisterContextUnwind::SavedLocationForRegister( "registers available -- treat as if we have no information", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - } else { - regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterInRegister; - regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; - UnwindLogMsg( - "supplying caller's register %s (%d), saved in register %s (%d)", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; } + + regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterInRegister; + regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); + m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; + UnwindLogMsg( + "supplying caller's register %s (%d) value is unmodified in this frame", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsCFAPlusOffset()) { - int offset = unwindplan_regloc.GetOffset(); + if (abs_regloc->IsCFAPlusOffset()) { + int offset = abs_regloc->GetOffset(); regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred; regloc.location.inferred_value = m_cfa + offset; m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; @@ -1588,8 +1571,8 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsAtCFAPlusOffset()) { - int offset = unwindplan_regloc.GetOffset(); + if (abs_regloc->IsAtCFAPlusOffset()) { + int offset = abs_regloc->GetOffset(); regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterSavedAtMemoryLocation; regloc.location.target_memory_location = m_cfa + offset; @@ -1601,11 +1584,11 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsAFAPlusOffset()) { + if (abs_regloc->IsAFAPlusOffset()) { if (m_afa == LLDB_INVALID_ADDRESS) return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - int offset = unwindplan_regloc.GetOffset(); + int offset = abs_regloc->GetOffset(); regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred; regloc.location.inferred_value = m_afa + offset; m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; @@ -1616,11 +1599,11 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsAtAFAPlusOffset()) { + if (abs_regloc->IsAtAFAPlusOffset()) { if (m_afa == LLDB_INVALID_ADDRESS) return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - int offset = unwindplan_regloc.GetOffset(); + int offset = abs_regloc->GetOffset(); regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterSavedAtMemoryLocation; regloc.location.target_memory_location = m_afa + offset; @@ -1632,10 +1615,9 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsInOtherRegister()) { - uint32_t unwindplan_regnum = unwindplan_regloc.GetRegisterNumber(); - RegisterNumber row_regnum(m_thread, unwindplan_registerkind, - unwindplan_regnum); + if (abs_regloc->IsInOtherRegister()) { + RegisterNumber row_regnum(m_thread, abs_regkind, + abs_regloc->GetRegisterNumber()); if (row_regnum.GetAsKind(eRegisterKindLLDB) == LLDB_INVALID_REGNUM) { UnwindLogMsg("could not supply caller's %s (%d) location - was saved in " "another reg but couldn't convert that regnum", @@ -1652,16 +1634,14 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsDWARFExpression() || - unwindplan_regloc.IsAtDWARFExpression()) { - DataExtractor dwarfdata(unwindplan_regloc.GetDWARFExpressionBytes(), - unwindplan_regloc.GetDWARFExpressionLength(), + if (abs_regloc->IsDWARFExpression() || abs_regloc->IsAtDWARFExpression()) { + DataExtractor dwarfdata(abs_regloc->GetDWARFExpressionBytes(), + abs_regloc->GetDWARFExpressionLength(), process->GetByteOrder(), process->GetAddressByteSize()); ModuleSP opcode_ctx; DWARFExpressionList dwarfexpr(opcode_ctx, dwarfdata, nullptr); - dwarfexpr.GetMutableExpressionAtAddress()->SetRegisterKind( - unwindplan_registerkind); + dwarfexpr.GetMutableExpressionAtAddress()->SetRegisterKind(abs_regkind); Value cfa_val = Scalar(m_cfa); cfa_val.SetValueType(Value::ValueType::LoadAddress); llvm::Expected result = @@ -1672,7 +1652,7 @@ RegisterContextUnwind::SavedLocationForRegister( } else { addr_t val; val = result->GetScalar().ULongLong(); - if (unwindplan_regloc.IsDWARFExpression()) { + if (abs_regloc->IsDWARFExpression()) { regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred; regloc.location.inferred_value = val; @@ -1698,9 +1678,9 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; } - if (unwindplan_regloc.IsConstant()) { + if (abs_regloc->IsConstant()) { regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred; - regloc.location.inferred_value = unwindplan_regloc.GetConstant(); + regloc.location.inferred_value = abs_regloc->GetConstant(); m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; UnwindLogMsg("supplying caller's register %s (%d) via constant value", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); diff --git a/lldb/source/Target/RegisterNumber.cpp b/lldb/source/Target/RegisterNumber.cpp index e5610bf588543..56dda8d8be8b8 100644 --- a/lldb/source/Target/RegisterNumber.cpp +++ b/lldb/source/Target/RegisterNumber.cpp @@ -47,6 +47,7 @@ const RegisterNumber &RegisterNumber::operator=(const RegisterNumber &rhs) { m_reg_ctx_sp = rhs.m_reg_ctx_sp; m_regnum = rhs.m_regnum; m_kind = rhs.m_kind; + m_kind_regnum_map.clear(); for (auto it : rhs.m_kind_regnum_map) m_kind_regnum_map[it.first] = it.second; m_name = rhs.m_name; >From c1aad81d5c5c7d2e9fce64f83197c05b827c6f22 Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 13 May 2025 17:37:42 -0700 Subject: [PATCH 2/5] Remove another bit of code in GetAbstractRegisterLocation that wasn't doing anything. --- lldb/source/Target/RegisterContextUnwind.cpp | 60 ++++++++------------ 1 file changed, 25 insertions(+), 35 deletions(-) diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index a3931abefb054..aae5de97de242 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1256,7 +1256,7 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( // // If there is no unwind rule for a non-volatile (callee-preserved) // register, the returned AbstractRegisterLocation will be IsSame. -// In frame 0, IsSame means get the value from the live register context. +// In frame 0, IsSame means get the value from the live register context. // Else it means to continue descending down the stack to more-live frames // looking for a location/value. // @@ -1394,42 +1394,32 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, } if (return_address_regnum != LLDB_INVALID_REGNUM) { - UnwindPlan::Row::AbstractRegisterLocation scratch; - // This is a sigtramp/interrupt handler - treat a - // request for "pc" and "ra" as distinct. - if (m_frame_type == eTrapHandlerFrame && active_row && - active_row->GetRegisterInfo(pc_regnum.GetAsKind(kind), scratch)) { - UnwindLogMsg("Providing pc register instead of rewriting to " - "RA reg because this is a trap handler and there is " - "a location for the saved pc register value."); + // This is a normal function, there's no rule for + // finding the caller's pc value, look for the caller's + // return address register value. + return_address_reg.init(m_thread, + m_full_unwind_plan_sp->GetRegisterKind(), + return_address_regnum); + regnum = return_address_reg; + UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a " + "RA reg; getting %s (%d) instead", + return_address_reg.GetName(), + return_address_reg.GetAsKind(eRegisterKindLLDB)); + if (active_row && active_row->GetRegisterInfo(regnum.GetAsKind(kind), + unwindplan_regloc)) { + UnwindLogMsg("supplying caller's saved %s (%d)'s location using " + "%s UnwindPlan", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), + m_full_unwind_plan_sp->GetSourceName().GetCString()); + if (unwindplan_regloc.IsSame()) + unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + return unwindplan_regloc; } else { - // This is a normal function, there's no rule for - // finding the caller's pc value, look for the caller's - // return address register value. - return_address_reg.init(m_thread, - m_full_unwind_plan_sp->GetRegisterKind(), - return_address_regnum); - regnum = return_address_reg; - UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a " - "RA reg; getting %s (%d) instead", - return_address_reg.GetName(), - return_address_reg.GetAsKind(eRegisterKindLLDB)); - if (active_row && active_row->GetRegisterInfo(regnum.GetAsKind(kind), - unwindplan_regloc)) { - UnwindLogMsg("supplying caller's saved %s (%d)'s location using " - "%s UnwindPlan", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - m_full_unwind_plan_sp->GetSourceName().GetCString()); - if (unwindplan_regloc.IsSame()) - unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + // No unwind rule for the return address reg on frame + // 0 means that the caller's address is still in RA reg. + if (BehavesLikeZerothFrame()) { + unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); return unwindplan_regloc; - } else { - // No unwind rule for the return address reg on frame - // 0 means that the caller's address is still in RA reg. - if (BehavesLikeZerothFrame()) { - unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); - return unwindplan_regloc; - } } } } >From fde91220492202f7a8b56312cac5b7316975d69a Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 13 May 2025 17:41:45 -0700 Subject: [PATCH 3/5] Don't log a message when the ABI says this is a volatile register -- has an Undefined abstract register location. --- lldb/source/Target/RegisterContextUnwind.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index aae5de97de242..cf23df21f5044 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1441,7 +1441,8 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, const RegisterInfo *reg_info = GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB)); if (reg_info && - abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) { + abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc) && + !unwindplan_regloc.IsUndefined()) { UnwindLogMsg( "supplying caller's saved %s (%d)'s location using ABI default", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); >From 853da6655104080cb7022ca4e7f18ffae2e5df1b Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 13 May 2025 18:03:41 -0700 Subject: [PATCH 4/5] clarify comment. --- lldb/source/Target/RegisterContextUnwind.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index cf23df21f5044..64cb906f4d6c3 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1450,8 +1450,9 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, } } - // We have no AbstractRegisterRule, and the ABI says this is a - // non-volatile / callee-preserved register. + // We have no AbstractRegisterLocation, and the ABI says this is a + // non-volatile / callee-preserved register. Continue down the stack + // or to frame 0 & the live RegisterContext. std::string unwindplan_name; if (m_full_unwind_plan_sp) { unwindplan_name += "via '"; >From 1f40042126fb4941f365c6b0bb3f83961248695e Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 13 May 2025 22:02:17 -0700 Subject: [PATCH 5/5] make another pass over all the comments and rewrite/clarify a bunch of them. Tiny tweaks to the code to make it more readable. --- lldb/source/Target/RegisterContextUnwind.cpp | 143 ++++++++++--------- 1 file changed, 78 insertions(+), 65 deletions(-) diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index 64cb906f4d6c3..791671dc8e166 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1243,24 +1243,34 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( return false; } -// Search this stack frame's UnwindPlans for the AbstractRegisterLocation -// for this register. -// -// When an AbstractRegisterLocation is found in an UnwindPlan, that is -// returned, regardless of the ABI rules for volatile/non-volatile registers -// in effect. -// -// If there is no unwind rule for a volatile (caller-preserved) register -// the returned AbstractRegisterLocation will be IsUndefined, -// indicating that we should stop searching. -// -// If there is no unwind rule for a non-volatile (callee-preserved) -// register, the returned AbstractRegisterLocation will be IsSame. -// In frame 0, IsSame means get the value from the live register context. -// Else it means to continue descending down the stack to more-live frames -// looking for a location/value. -// -// An empty optional indicates that there was an error in processing. +/// Search this stack frame's UnwindPlans for the AbstractRegisterLocation +/// for this register. +/// +/// \param[out] kind +/// Set to the RegisterKind of the UnwindPlan which is the basis for +/// the returned AbstractRegisterLocation; if the location is in terms +/// of another register number, this Kind is needed to interpret it +/// correctly. +/// +/// \return +/// An empty optional indicaTes that there was an error in processing +/// the request. +/// +/// If there is no unwind rule for a volatile (caller-preserved) register, +/// the returned AbstractRegisterLocation will be IsUndefined, +/// indicating that we should stop searching. +/// +/// If there is no unwind rule for a non-volatile (callee-preserved) +/// register, the returned AbstractRegisterLocation will be IsSame. +/// In frame 0, IsSame means get the value from the live register context. +/// Else it means to continue descending down the stack to more-live frames +/// looking for a location/value. +/// +/// If an AbstractRegisterLocation is found in an UnwindPlan, that will +/// be returned, with no consideration of the current ABI rules for +/// registers. Functions using an alternate ABI calling convention +/// will work as long as the UnwindPlans are exhaustive about what +/// registers are volatile/non-volatile. std::optional RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, lldb::RegisterKind &kind) { @@ -1324,16 +1334,15 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, } if (regnum.GetAsKind(kind) == LLDB_INVALID_REGNUM) { - if (kind == eRegisterKindGeneric) { + if (kind == eRegisterKindGeneric) UnwindLogMsg("could not convert lldb regnum %s (%d) into " "eRegisterKindGeneric reg numbering scheme", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - } else { + else UnwindLogMsg("could not convert lldb regnum %s (%d) into %d " "RegisterKind reg numbering scheme", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), (int)kind); - } return {}; } @@ -1347,42 +1356,37 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, return unwindplan_regloc; } - // When asking for the caller's pc, check if we have a + // When asking for the caller's pc, and did not find a register + // location for PC above in the UnwindPlan. Check if we have a // Return Address register on this target. // // On a Return Address Register architecture like arm/mips/riscv, // the caller's pc is in the RA register, and will be spilled to - // stack before any other function can be called. We may have a - // register location saying - // pc=RAReg {caller's retrun addr is in RA register} - // ra=IsSame {caller's return addr is live in RA register} - // ra=StackAddr {caller's return addr spilled to stack} - // or none of the above, which means the caller's pc is live in the - // return address reg if this is frame 0, or the frame below is - // a trap/sigtramp/interrupt handler function. Any other mid-stack - // function must have an unwind rule for PC/RA giving a location/value. + // stack before any other function is called. If no function + // has been called yet, the return address may still be in the + // live RA reg. // - // In the case of an interrupted function -- the function above sigtramp, - // or a function interrupted asynchronously, or that has faulted to - // a trap handler -- it is valid to ask both the "pc" value -- the - // instruction that was executing when the interrupt/fault happend -- - // and the RA Register value. If a frameless function (which doesn't - // create a stack frame, doesn't save the RA reg to stack) is interrupted, - // the trap handler will have a rule to provide the pc (the instruction - // that was executing) AND a rule to provide the RA Register, which we - // need to use to find the caller function: - // pc=StackAddr1 - // ra=StackAddr2 - // and we don't want to rewrite a request of "pc" to "ra" here, because - // they mean different things. - + // There's a lot of variety of what we might see in an UnwindPlan. + // We may have + // ra=IsSame {unncessary} + // ra=StackAddr {caller's return addr spilled to stack} + // or no unwindrule for pc or ra at all, in a frameless function - + // the caller's return address is in live ra reg. + // + // If a function has been interrupted in a non-call way -- + // async signal/sigtramp, or a hardware exception / interrupt / fault -- + // then the "pc" and "ra" are two distinct values, and must be + // handled separately. The "pc" is the pc value at the point + // the function was interrupted. The "ra" is the return address + // register value at that point. + // The UnwindPlan for the sigtramp/trap handler will normally have + // register loations for both pc and lr, and so we'll have already + // fetched them above. if (pc_regnum.IsValid() && pc_regnum == regnum) { - RegisterNumber return_address_reg; - uint32_t return_address_regnum = - LLDB_INVALID_REGNUM; // in full UnwindPlan's numbering + uint32_t return_address_regnum = LLDB_INVALID_REGNUM; // Get the return address register number from the UnwindPlan - // or the arch register set. + // or the register set definition. if (m_full_unwind_plan_sp->GetReturnAddressRegister() != LLDB_INVALID_REGNUM) { return_address_regnum = @@ -1393,32 +1397,38 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, return_address_regnum = arch_default_ra_regnum.GetAsKind(kind); } + // This system is using a return address register. if (return_address_regnum != LLDB_INVALID_REGNUM) { - // This is a normal function, there's no rule for - // finding the caller's pc value, look for the caller's - // return address register value. + RegisterNumber return_address_reg; return_address_reg.init(m_thread, m_full_unwind_plan_sp->GetRegisterKind(), return_address_regnum); - regnum = return_address_reg; UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a " "RA reg; getting %s (%d) instead", return_address_reg.GetName(), return_address_reg.GetAsKind(eRegisterKindLLDB)); - if (active_row && active_row->GetRegisterInfo(regnum.GetAsKind(kind), - unwindplan_regloc)) { + + // Do we have a location for the ra register? + if (active_row && + active_row->GetRegisterInfo(return_address_reg.GetAsKind(kind), + unwindplan_regloc)) { UnwindLogMsg("supplying caller's saved %s (%d)'s location using " "%s UnwindPlan", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), + return_address_reg.GetName(), + return_address_reg.GetAsKind(eRegisterKindLLDB), m_full_unwind_plan_sp->GetSourceName().GetCString()); + // If we have "ra=IsSame", rewrite to "ra=InRegister(ra)" because the + // calling function thinks it is fetching "pc" and if we return an + // IsSame register location, it will try to read pc. if (unwindplan_regloc.IsSame()) - unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + unwindplan_regloc.SetInRegister(return_address_reg.GetAsKind(kind)); return unwindplan_regloc; } else { - // No unwind rule for the return address reg on frame - // 0 means that the caller's address is still in RA reg. + // No unwind rule for the return address reg on frame 0, or an + // interrupted function, means that the caller's address is still in + // RA reg. if (BehavesLikeZerothFrame()) { - unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + unwindplan_regloc.SetInRegister(return_address_reg.GetAsKind(kind)); return unwindplan_regloc; } } @@ -1441,11 +1451,14 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, const RegisterInfo *reg_info = GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB)); if (reg_info && - abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc) && - !unwindplan_regloc.IsUndefined()) { - UnwindLogMsg( - "supplying caller's saved %s (%d)'s location using ABI default", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) { + if (!unwindplan_regloc.IsUndefined()) + UnwindLogMsg( + "supplying caller's saved %s (%d)'s location using ABI default", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + // ABI defined volatile registers with no register location + // will be returned as IsUndefined, stopping the search down + // the stack. return unwindplan_regloc; } } From lldb-commits at lists.llvm.org Tue May 13 22:18:26 2025 From: lldb-commits at lists.llvm.org (Jason Molenda via lldb-commits) Date: Tue, 13 May 2025 22:18:26 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][NFC] Split RegisterContextUnwind::SavedLocationForRegister (PR #139817) In-Reply-To: Message-ID: <682427a2.170a0220.2bc9cb.ed7c@mx.google.com> https://github.com/jasonmolenda updated https://github.com/llvm/llvm-project/pull/139817 >From e63e53adc0909f481a165eca958a3ac2ca4374ee Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 13 May 2025 17:11:08 -0700 Subject: [PATCH 1/6] [lldb][NFC] Split RegisterContextUnwind::SavedLocationForRegister RegisterContextUnwind::SavedLocationForRegister is around 450 lines that first find an abstract register location (e.g. "CFA-8") for a register by looking in the UnwindPlans. Then it evaluates the abstract register location to create a concrete register location (e.g. "stored at address 0x...", "live in register at frame 0"). There are some complicated cases in the first half of the method to handle return address register architectures correctly, in particular. Looking at the two halves, they're both exactly 226 lines long and there's little involvement between them except for passing an abstract register location along. (there were some parts in the "abstract register location" code that would set the concrete register location, unnecessarily) It's also a complex enough method that there are some bits of code that aren't actually doing anything at this point. This patch adds a RegisterContextUnwind::GetAbstractRegisterLocation method, which does the first half, and has a clearly defined return values. The code to convert an AbstractRegisterLocation into a ConcreteRegisterLocation remains in SavedLocationForRegister. It's a bit of a tricky patch to visually inspect, despite it not changing functionality, the reorganizations and rewrites make the diff unreadable. Nearly all the real changes are in the "find the abstract register location" first half of the method. I think reading the new code in its new form is the easiest way to inspect this PR. With a defined interface between the two of what is expected, it's pretty easy to look at the code and reason about whether it is written correctly. (whereas before, that was very difficult, for me at least.) --- .../lldb/Target/RegisterContextUnwind.h | 3 + lldb/source/Target/RegisterContextUnwind.cpp | 530 +++++++++--------- lldb/source/Target/RegisterNumber.cpp | 1 + 3 files changed, 259 insertions(+), 275 deletions(-) diff --git a/lldb/include/lldb/Target/RegisterContextUnwind.h b/lldb/include/lldb/Target/RegisterContextUnwind.h index 044a387fe5aa2..b10a364823b83 100644 --- a/lldb/include/lldb/Target/RegisterContextUnwind.h +++ b/lldb/include/lldb/Target/RegisterContextUnwind.h @@ -151,6 +151,9 @@ class RegisterContextUnwind : public lldb_private::RegisterContext { uint32_t lldb_regnum, lldb_private::UnwindLLDB::ConcreteRegisterLocation ®loc); + std::optional + GetAbstractRegisterLocation(uint32_t lldb_regnum, lldb::RegisterKind &kind); + bool ReadRegisterValueFromRegisterLocation( lldb_private::UnwindLLDB::ConcreteRegisterLocation regloc, const lldb_private::RegisterInfo *reg_info, diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index cf4b96c6eda9f..a3931abefb054 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1243,247 +1243,194 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( return false; } -// Answer the question: Where did THIS frame save the CALLER frame ("previous" -// frame)'s register value? - -enum UnwindLLDB::RegisterSearchResult -RegisterContextUnwind::SavedLocationForRegister( - uint32_t lldb_regnum, - lldb_private::UnwindLLDB::ConcreteRegisterLocation ®loc) { +// Search this stack frame's UnwindPlans for the AbstractRegisterLocation +// for this register. +// +// When an AbstractRegisterLocation is found in an UnwindPlan, that is +// returned, regardless of the ABI rules for volatile/non-volatile registers +// in effect. +// +// If there is no unwind rule for a volatile (caller-preserved) register +// the returned AbstractRegisterLocation will be IsUndefined, +// indicating that we should stop searching. +// +// If there is no unwind rule for a non-volatile (callee-preserved) +// register, the returned AbstractRegisterLocation will be IsSame. +// In frame 0, IsSame means get the value from the live register context. +// Else it means to continue descending down the stack to more-live frames +// looking for a location/value. +// +// An empty optional indicates that there was an error in processing. +std::optional +RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, + lldb::RegisterKind &kind) { RegisterNumber regnum(m_thread, eRegisterKindLLDB, lldb_regnum); Log *log = GetLog(LLDBLog::Unwind); - // Have we already found this register location? - if (!m_registers.empty()) { - std::map::const_iterator - iterator; - iterator = m_registers.find(regnum.GetAsKind(eRegisterKindLLDB)); - if (iterator != m_registers.end()) { - regloc = iterator->second; - UnwindLogMsg("supplying caller's saved %s (%d)'s location, cached", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } - } - - // Look through the available UnwindPlans for the register location. - UnwindPlan::Row::AbstractRegisterLocation unwindplan_regloc; - bool have_unwindplan_regloc = false; - RegisterKind unwindplan_registerkind = kNumRegisterKinds; + // First, try to find a register location via the FastUnwindPlan if (m_fast_unwind_plan_sp) { const UnwindPlan::Row *active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); - unwindplan_registerkind = m_fast_unwind_plan_sp->GetRegisterKind(); - if (regnum.GetAsKind(unwindplan_registerkind) == LLDB_INVALID_REGNUM) { + kind = m_fast_unwind_plan_sp->GetRegisterKind(); + if (regnum.GetAsKind(kind) == LLDB_INVALID_REGNUM) { UnwindLogMsg("could not convert lldb regnum %s (%d) into %d RegisterKind " "reg numbering scheme", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - (int)unwindplan_registerkind); - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; + (int)kind); + return {}; } // The architecture default unwind plan marks unknown registers as // Undefined so that we don't forward them up the stack when a // jitted stack frame may have overwritten them. But when the // arch default unwind plan is used as the Fast Unwind Plan, we // need to recognize this & switch over to the Full Unwind Plan - // to see what unwind rule that (more knoweldgeable, probably) - // UnwindPlan has. If the full UnwindPlan says the register - // location is Undefined, then it really is. - if (active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind), + // to see what unwind rule that (more knowledgeable, probably) + // UnwindPlan has. + if (active_row->GetRegisterInfo(regnum.GetAsKind(kind), unwindplan_regloc) && !unwindplan_regloc.IsUndefined()) { UnwindLogMsg( "supplying caller's saved %s (%d)'s location using FastUnwindPlan", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - have_unwindplan_regloc = true; + return unwindplan_regloc; } } - if (!have_unwindplan_regloc) { - // m_full_unwind_plan_sp being NULL means that we haven't tried to find a - // full UnwindPlan yet - bool got_new_full_unwindplan = false; - if (!m_full_unwind_plan_sp) { - m_full_unwind_plan_sp = GetFullUnwindPlanForFrame(); - got_new_full_unwindplan = true; - } + // Second, try to find a register location via the FullUnwindPlan. + bool got_new_full_unwindplan = false; + if (!m_full_unwind_plan_sp) { + m_full_unwind_plan_sp = GetFullUnwindPlanForFrame(); + got_new_full_unwindplan = true; + } + if (m_full_unwind_plan_sp) { + RegisterNumber pc_regnum(m_thread, eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_PC); - if (m_full_unwind_plan_sp) { - RegisterNumber pc_regnum(m_thread, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_PC); + const UnwindPlan::Row *active_row = + m_full_unwind_plan_sp->GetRowForFunctionOffset( + m_current_offset_backed_up_one); + kind = m_full_unwind_plan_sp->GetRegisterKind(); - const UnwindPlan::Row *active_row = - m_full_unwind_plan_sp->GetRowForFunctionOffset( - m_current_offset_backed_up_one); - unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind(); + if (got_new_full_unwindplan && active_row && log) { + StreamString active_row_strm; + ExecutionContext exe_ctx(m_thread.shared_from_this()); + active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, + m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); + UnwindLogMsg("Using full unwind plan '%s'", + m_full_unwind_plan_sp->GetSourceName().AsCString()); + UnwindLogMsg("active row: %s", active_row_strm.GetData()); + } - if (got_new_full_unwindplan && active_row && log) { - StreamString active_row_strm; - ExecutionContext exe_ctx(m_thread.shared_from_this()); - active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), - &m_thread, - m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); - UnwindLogMsg("Using full unwind plan '%s'", - m_full_unwind_plan_sp->GetSourceName().AsCString()); - UnwindLogMsg("active row: %s", active_row_strm.GetData()); + if (regnum.GetAsKind(kind) == LLDB_INVALID_REGNUM) { + if (kind == eRegisterKindGeneric) { + UnwindLogMsg("could not convert lldb regnum %s (%d) into " + "eRegisterKindGeneric reg numbering scheme", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + } else { + UnwindLogMsg("could not convert lldb regnum %s (%d) into %d " + "RegisterKind reg numbering scheme", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), + (int)kind); } + return {}; + } + + if (regnum.IsValid() && active_row && + active_row->GetRegisterInfo(regnum.GetAsKind(kind), + unwindplan_regloc)) { + UnwindLogMsg( + "supplying caller's saved %s (%d)'s location using %s UnwindPlan", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), + m_full_unwind_plan_sp->GetSourceName().GetCString()); + return unwindplan_regloc; + } + + // When asking for the caller's pc, check if we have a + // Return Address register on this target. + // + // On a Return Address Register architecture like arm/mips/riscv, + // the caller's pc is in the RA register, and will be spilled to + // stack before any other function can be called. We may have a + // register location saying + // pc=RAReg {caller's retrun addr is in RA register} + // ra=IsSame {caller's return addr is live in RA register} + // ra=StackAddr {caller's return addr spilled to stack} + // or none of the above, which means the caller's pc is live in the + // return address reg if this is frame 0, or the frame below is + // a trap/sigtramp/interrupt handler function. Any other mid-stack + // function must have an unwind rule for PC/RA giving a location/value. + // + // In the case of an interrupted function -- the function above sigtramp, + // or a function interrupted asynchronously, or that has faulted to + // a trap handler -- it is valid to ask both the "pc" value -- the + // instruction that was executing when the interrupt/fault happend -- + // and the RA Register value. If a frameless function (which doesn't + // create a stack frame, doesn't save the RA reg to stack) is interrupted, + // the trap handler will have a rule to provide the pc (the instruction + // that was executing) AND a rule to provide the RA Register, which we + // need to use to find the caller function: + // pc=StackAddr1 + // ra=StackAddr2 + // and we don't want to rewrite a request of "pc" to "ra" here, because + // they mean different things. + + if (pc_regnum.IsValid() && pc_regnum == regnum) { RegisterNumber return_address_reg; + uint32_t return_address_regnum = + LLDB_INVALID_REGNUM; // in full UnwindPlan's numbering + + // Get the return address register number from the UnwindPlan + // or the arch register set. + if (m_full_unwind_plan_sp->GetReturnAddressRegister() != + LLDB_INVALID_REGNUM) { + return_address_regnum = + m_full_unwind_plan_sp->GetReturnAddressRegister(); + } else { + RegisterNumber arch_default_ra_regnum(m_thread, eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_RA); + return_address_regnum = arch_default_ra_regnum.GetAsKind(kind); + } - // If we're fetching the saved pc and this UnwindPlan defines a - // ReturnAddress register (e.g. lr on arm), look for the return address - // register number in the UnwindPlan's row. - if (pc_regnum.IsValid() && pc_regnum == regnum && - m_full_unwind_plan_sp->GetReturnAddressRegister() != - LLDB_INVALID_REGNUM) { - // If this is a trap handler frame, we should have access to - // the complete register context when the interrupt/async - // signal was received, we should fetch the actual saved $pc - // value instead of the Return Address register. - // If $pc is not available, fall back to the RA reg. + if (return_address_regnum != LLDB_INVALID_REGNUM) { UnwindPlan::Row::AbstractRegisterLocation scratch; + // This is a sigtramp/interrupt handler - treat a + // request for "pc" and "ra" as distinct. if (m_frame_type == eTrapHandlerFrame && active_row && - active_row->GetRegisterInfo( - pc_regnum.GetAsKind(unwindplan_registerkind), scratch)) { + active_row->GetRegisterInfo(pc_regnum.GetAsKind(kind), scratch)) { UnwindLogMsg("Providing pc register instead of rewriting to " "RA reg because this is a trap handler and there is " "a location for the saved pc register value."); } else { - return_address_reg.init( - m_thread, m_full_unwind_plan_sp->GetRegisterKind(), - m_full_unwind_plan_sp->GetReturnAddressRegister()); + // This is a normal function, there's no rule for + // finding the caller's pc value, look for the caller's + // return address register value. + return_address_reg.init(m_thread, + m_full_unwind_plan_sp->GetRegisterKind(), + return_address_regnum); regnum = return_address_reg; UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a " "RA reg; getting %s (%d) instead", return_address_reg.GetName(), return_address_reg.GetAsKind(eRegisterKindLLDB)); - } - } else { - if (regnum.GetAsKind(unwindplan_registerkind) == LLDB_INVALID_REGNUM) { - if (unwindplan_registerkind == eRegisterKindGeneric) { - UnwindLogMsg("could not convert lldb regnum %s (%d) into " - "eRegisterKindGeneric reg numbering scheme", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - } else { - UnwindLogMsg("could not convert lldb regnum %s (%d) into %d " - "RegisterKind reg numbering scheme", + if (active_row && active_row->GetRegisterInfo(regnum.GetAsKind(kind), + unwindplan_regloc)) { + UnwindLogMsg("supplying caller's saved %s (%d)'s location using " + "%s UnwindPlan", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - (int)unwindplan_registerkind); - } - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - } - } - - // Check if the active_row has a register location listed. - if (regnum.IsValid() && active_row && - active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind), - unwindplan_regloc)) { - have_unwindplan_regloc = true; - UnwindLogMsg( - "supplying caller's saved %s (%d)'s location using %s UnwindPlan", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - m_full_unwind_plan_sp->GetSourceName().GetCString()); - } - - // This is frame 0 and we're retrieving the PC and it's saved in a Return - // Address register and it hasn't been saved anywhere yet -- that is, - // it's still live in the actual register. Handle this specially. - if (!have_unwindplan_regloc && return_address_reg.IsValid() && - return_address_reg.GetAsKind(eRegisterKindLLDB) != - LLDB_INVALID_REGNUM) { - if (IsFrameZero()) { - lldb_private::UnwindLLDB::ConcreteRegisterLocation new_regloc; - new_regloc.type = UnwindLLDB::ConcreteRegisterLocation:: - eRegisterInLiveRegisterContext; - new_regloc.location.register_number = - return_address_reg.GetAsKind(eRegisterKindLLDB); - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; - regloc = new_regloc; - UnwindLogMsg("supplying caller's register %s (%d) from the live " - "RegisterContext at frame 0, saved in %d", - return_address_reg.GetName(), - return_address_reg.GetAsKind(eRegisterKindLLDB), - return_address_reg.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } else if (BehavesLikeZerothFrame()) { - // This function was interrupted asynchronously -- it faulted, - // an async interrupt, a timer fired, a debugger expression etc. - // The caller's pc is in the Return Address register, but the - // UnwindPlan for this function may have no location rule for - // the RA reg. - // This means that the caller's return address is in the RA reg - // when the function was interrupted--descend down one stack frame - // to retrieve it from the trap handler's saved context. - unwindplan_regloc.SetSame(); - have_unwindplan_regloc = true; - } - } - - // If this architecture stores the return address in a register (it - // defines a Return Address register) and we're on a non-zero stack frame - // and the Full UnwindPlan says that the pc is stored in the - // RA registers (e.g. lr on arm), then we know that the full unwindplan is - // not trustworthy -- this - // is an impossible situation and the instruction emulation code has - // likely been misled. If this stack frame meets those criteria, we need - // to throw away the Full UnwindPlan that the instruction emulation came - // up with and fall back to the architecture's Default UnwindPlan so the - // stack walk can get past this point. - - // Special note: If the Full UnwindPlan was generated from the compiler, - // don't second-guess it when we're at a call site location. - - // arch_default_ra_regnum is the return address register # in the Full - // UnwindPlan register numbering - RegisterNumber arch_default_ra_regnum(m_thread, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_RA); - - if (arch_default_ra_regnum.GetAsKind(unwindplan_registerkind) != - LLDB_INVALID_REGNUM && - pc_regnum == regnum && unwindplan_regloc.IsInOtherRegister() && - unwindplan_regloc.GetRegisterNumber() == - arch_default_ra_regnum.GetAsKind(unwindplan_registerkind) && - m_full_unwind_plan_sp->GetSourcedFromCompiler() != eLazyBoolYes && - !m_all_registers_available) { - UnwindLogMsg("%s UnwindPlan tried to restore the pc from the link " - "register but this is a non-zero frame", - m_full_unwind_plan_sp->GetSourceName().GetCString()); - - // Throw away the full unwindplan; install the arch default unwindplan - if (ForceSwitchToFallbackUnwindPlan()) { - // Update for the possibly new unwind plan - unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind(); - const UnwindPlan::Row *active_row = - m_full_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); - - // Sanity check: Verify that we can fetch a pc value and CFA value - // with this unwind plan - - RegisterNumber arch_default_pc_reg(m_thread, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_PC); - bool can_fetch_pc_value = false; - bool can_fetch_cfa = false; - addr_t cfa_value; - if (active_row) { - if (arch_default_pc_reg.GetAsKind(unwindplan_registerkind) != - LLDB_INVALID_REGNUM && - active_row->GetRegisterInfo( - arch_default_pc_reg.GetAsKind(unwindplan_registerkind), - unwindplan_regloc)) { - can_fetch_pc_value = true; - } - if (ReadFrameAddress(unwindplan_registerkind, - active_row->GetCFAValue(), cfa_value)) { - can_fetch_cfa = true; + m_full_unwind_plan_sp->GetSourceName().GetCString()); + if (unwindplan_regloc.IsSame()) + unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + return unwindplan_regloc; + } else { + // No unwind rule for the return address reg on frame + // 0 means that the caller's address is still in RA reg. + if (BehavesLikeZerothFrame()) { + unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + return unwindplan_regloc; } } - - have_unwindplan_regloc = can_fetch_pc_value && can_fetch_cfa; - } else { - // We were unable to fall back to another unwind plan - have_unwindplan_regloc = false; } } } @@ -1491,55 +1438,84 @@ RegisterContextUnwind::SavedLocationForRegister( ExecutionContext exe_ctx(m_thread.shared_from_this()); Process *process = exe_ctx.GetProcessPtr(); - if (!have_unwindplan_regloc) { - // If the UnwindPlan failed to give us an unwind location for this - // register, we may be able to fall back to some ABI-defined default. For - // example, some ABIs allow to determine the caller's SP via the CFA. Also, - // the ABI may set volatile registers to the undefined state. - ABI *abi = process ? process->GetABI().get() : nullptr; - if (abi) { - const RegisterInfo *reg_info = - GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB)); - if (reg_info && - abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) { - UnwindLogMsg( - "supplying caller's saved %s (%d)'s location using ABI default", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - have_unwindplan_regloc = true; - } + + // Third, try finding a register location via the ABI + // FallbackRegisterLocation. + // + // If the UnwindPlan failed to give us an unwind location for this + // register, we may be able to fall back to some ABI-defined default. For + // example, some ABIs allow to determine the caller's SP via the CFA. Also, + // the ABI willset volatile registers to the undefined state. + ABI *abi = process ? process->GetABI().get() : nullptr; + if (abi) { + const RegisterInfo *reg_info = + GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB)); + if (reg_info && + abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) { + UnwindLogMsg( + "supplying caller's saved %s (%d)'s location using ABI default", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + return unwindplan_regloc; } } - if (!have_unwindplan_regloc) { - if (IsFrameZero()) { - // This is frame 0 - we should return the actual live register context - // value - lldb_private::UnwindLLDB::ConcreteRegisterLocation new_regloc; - new_regloc.type = - UnwindLLDB::ConcreteRegisterLocation::eRegisterInLiveRegisterContext; - new_regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; - regloc = new_regloc; - UnwindLogMsg("supplying caller's register %s (%d) from the live " - "RegisterContext at frame 0", + // We have no AbstractRegisterRule, and the ABI says this is a + // non-volatile / callee-preserved register. + std::string unwindplan_name; + if (m_full_unwind_plan_sp) { + unwindplan_name += "via '"; + unwindplan_name += m_full_unwind_plan_sp->GetSourceName().AsCString(); + unwindplan_name += "'"; + } + UnwindLogMsg("no save location for %s (%d) %s", regnum.GetName(), + regnum.GetAsKind(eRegisterKindLLDB), unwindplan_name.c_str()); + + unwindplan_regloc.SetSame(); + return unwindplan_regloc; +} + +// Answer the question: Where did THIS frame save the CALLER frame ("previous" +// frame)'s register value? + +enum UnwindLLDB::RegisterSearchResult +RegisterContextUnwind::SavedLocationForRegister( + uint32_t lldb_regnum, + lldb_private::UnwindLLDB::ConcreteRegisterLocation ®loc) { + RegisterNumber regnum(m_thread, eRegisterKindLLDB, lldb_regnum); + Log *log = GetLog(LLDBLog::Unwind); + + // Have we already found this register location? + if (!m_registers.empty()) { + std::map::const_iterator + iterator; + iterator = m_registers.find(regnum.GetAsKind(eRegisterKindLLDB)); + if (iterator != m_registers.end()) { + regloc = iterator->second; + UnwindLogMsg("supplying caller's saved %s (%d)'s location, cached", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } else { - std::string unwindplan_name; - if (m_full_unwind_plan_sp) { - unwindplan_name += "via '"; - unwindplan_name += m_full_unwind_plan_sp->GetSourceName().AsCString(); - unwindplan_name += "'"; - } - UnwindLogMsg("no save location for %s (%d) %s", regnum.GetName(), - regnum.GetAsKind(eRegisterKindLLDB), - unwindplan_name.c_str()); } + } + + RegisterKind abs_regkind; + std::optional abs_regloc = + GetAbstractRegisterLocation(lldb_regnum, abs_regkind); + + if (!abs_regloc) return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; + + if (abs_regloc->IsUndefined()) { + UnwindLogMsg( + "did not supply reg location for %s (%d) because it is volatile", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile; } - // unwindplan_regloc has valid contents about where to retrieve the register - if (unwindplan_regloc.IsUnspecified()) { + ExecutionContext exe_ctx(m_thread.shared_from_this()); + Process *process = exe_ctx.GetProcessPtr(); + // abs_regloc has valid contents about where to retrieve the register + if (abs_regloc->IsUnspecified()) { lldb_private::UnwindLLDB::ConcreteRegisterLocation new_regloc = {}; new_regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterNotSaved; m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; @@ -1548,15 +1524,23 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; } - if (unwindplan_regloc.IsUndefined()) { - UnwindLogMsg( - "did not supply reg location for %s (%d) because it is volatile", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile; - } - - if (unwindplan_regloc.IsSame()) { - if (!m_all_registers_available && + if (abs_regloc->IsSame()) { + if (IsFrameZero()) { + regloc.type = + UnwindLLDB::ConcreteRegisterLocation::eRegisterInLiveRegisterContext; + regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); + m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; + UnwindLogMsg("supplying caller's register %s (%d) from the live " + "RegisterContext at frame 0", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + return UnwindLLDB::RegisterSearchResult::eRegisterFound; + } + // PC/RA reg don't follow the usual "callee-saved aka non-volatile" versus + // "caller saved aka volatile" system. A stack frame can provide its caller + // return address, but if we don't find a rule for pc/RA mid-stack, we + // never want to iterate further down the stack looking for it. + // Defensively prevent iterating down the stack for these two. + if (!BehavesLikeZerothFrame() && (regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_PC || regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_RA)) { UnwindLogMsg("register %s (%d) is marked as 'IsSame' - it is a pc or " @@ -1564,20 +1548,19 @@ RegisterContextUnwind::SavedLocationForRegister( "registers available -- treat as if we have no information", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - } else { - regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterInRegister; - regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; - UnwindLogMsg( - "supplying caller's register %s (%d), saved in register %s (%d)", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; } + + regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterInRegister; + regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); + m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; + UnwindLogMsg( + "supplying caller's register %s (%d) value is unmodified in this frame", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsCFAPlusOffset()) { - int offset = unwindplan_regloc.GetOffset(); + if (abs_regloc->IsCFAPlusOffset()) { + int offset = abs_regloc->GetOffset(); regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred; regloc.location.inferred_value = m_cfa + offset; m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; @@ -1588,8 +1571,8 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsAtCFAPlusOffset()) { - int offset = unwindplan_regloc.GetOffset(); + if (abs_regloc->IsAtCFAPlusOffset()) { + int offset = abs_regloc->GetOffset(); regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterSavedAtMemoryLocation; regloc.location.target_memory_location = m_cfa + offset; @@ -1601,11 +1584,11 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsAFAPlusOffset()) { + if (abs_regloc->IsAFAPlusOffset()) { if (m_afa == LLDB_INVALID_ADDRESS) return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - int offset = unwindplan_regloc.GetOffset(); + int offset = abs_regloc->GetOffset(); regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred; regloc.location.inferred_value = m_afa + offset; m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; @@ -1616,11 +1599,11 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsAtAFAPlusOffset()) { + if (abs_regloc->IsAtAFAPlusOffset()) { if (m_afa == LLDB_INVALID_ADDRESS) return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - int offset = unwindplan_regloc.GetOffset(); + int offset = abs_regloc->GetOffset(); regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterSavedAtMemoryLocation; regloc.location.target_memory_location = m_afa + offset; @@ -1632,10 +1615,9 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsInOtherRegister()) { - uint32_t unwindplan_regnum = unwindplan_regloc.GetRegisterNumber(); - RegisterNumber row_regnum(m_thread, unwindplan_registerkind, - unwindplan_regnum); + if (abs_regloc->IsInOtherRegister()) { + RegisterNumber row_regnum(m_thread, abs_regkind, + abs_regloc->GetRegisterNumber()); if (row_regnum.GetAsKind(eRegisterKindLLDB) == LLDB_INVALID_REGNUM) { UnwindLogMsg("could not supply caller's %s (%d) location - was saved in " "another reg but couldn't convert that regnum", @@ -1652,16 +1634,14 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsDWARFExpression() || - unwindplan_regloc.IsAtDWARFExpression()) { - DataExtractor dwarfdata(unwindplan_regloc.GetDWARFExpressionBytes(), - unwindplan_regloc.GetDWARFExpressionLength(), + if (abs_regloc->IsDWARFExpression() || abs_regloc->IsAtDWARFExpression()) { + DataExtractor dwarfdata(abs_regloc->GetDWARFExpressionBytes(), + abs_regloc->GetDWARFExpressionLength(), process->GetByteOrder(), process->GetAddressByteSize()); ModuleSP opcode_ctx; DWARFExpressionList dwarfexpr(opcode_ctx, dwarfdata, nullptr); - dwarfexpr.GetMutableExpressionAtAddress()->SetRegisterKind( - unwindplan_registerkind); + dwarfexpr.GetMutableExpressionAtAddress()->SetRegisterKind(abs_regkind); Value cfa_val = Scalar(m_cfa); cfa_val.SetValueType(Value::ValueType::LoadAddress); llvm::Expected result = @@ -1672,7 +1652,7 @@ RegisterContextUnwind::SavedLocationForRegister( } else { addr_t val; val = result->GetScalar().ULongLong(); - if (unwindplan_regloc.IsDWARFExpression()) { + if (abs_regloc->IsDWARFExpression()) { regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred; regloc.location.inferred_value = val; @@ -1698,9 +1678,9 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; } - if (unwindplan_regloc.IsConstant()) { + if (abs_regloc->IsConstant()) { regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred; - regloc.location.inferred_value = unwindplan_regloc.GetConstant(); + regloc.location.inferred_value = abs_regloc->GetConstant(); m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; UnwindLogMsg("supplying caller's register %s (%d) via constant value", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); diff --git a/lldb/source/Target/RegisterNumber.cpp b/lldb/source/Target/RegisterNumber.cpp index e5610bf588543..56dda8d8be8b8 100644 --- a/lldb/source/Target/RegisterNumber.cpp +++ b/lldb/source/Target/RegisterNumber.cpp @@ -47,6 +47,7 @@ const RegisterNumber &RegisterNumber::operator=(const RegisterNumber &rhs) { m_reg_ctx_sp = rhs.m_reg_ctx_sp; m_regnum = rhs.m_regnum; m_kind = rhs.m_kind; + m_kind_regnum_map.clear(); for (auto it : rhs.m_kind_regnum_map) m_kind_regnum_map[it.first] = it.second; m_name = rhs.m_name; >From c1aad81d5c5c7d2e9fce64f83197c05b827c6f22 Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 13 May 2025 17:37:42 -0700 Subject: [PATCH 2/6] Remove another bit of code in GetAbstractRegisterLocation that wasn't doing anything. --- lldb/source/Target/RegisterContextUnwind.cpp | 60 ++++++++------------ 1 file changed, 25 insertions(+), 35 deletions(-) diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index a3931abefb054..aae5de97de242 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1256,7 +1256,7 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( // // If there is no unwind rule for a non-volatile (callee-preserved) // register, the returned AbstractRegisterLocation will be IsSame. -// In frame 0, IsSame means get the value from the live register context. +// In frame 0, IsSame means get the value from the live register context. // Else it means to continue descending down the stack to more-live frames // looking for a location/value. // @@ -1394,42 +1394,32 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, } if (return_address_regnum != LLDB_INVALID_REGNUM) { - UnwindPlan::Row::AbstractRegisterLocation scratch; - // This is a sigtramp/interrupt handler - treat a - // request for "pc" and "ra" as distinct. - if (m_frame_type == eTrapHandlerFrame && active_row && - active_row->GetRegisterInfo(pc_regnum.GetAsKind(kind), scratch)) { - UnwindLogMsg("Providing pc register instead of rewriting to " - "RA reg because this is a trap handler and there is " - "a location for the saved pc register value."); + // This is a normal function, there's no rule for + // finding the caller's pc value, look for the caller's + // return address register value. + return_address_reg.init(m_thread, + m_full_unwind_plan_sp->GetRegisterKind(), + return_address_regnum); + regnum = return_address_reg; + UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a " + "RA reg; getting %s (%d) instead", + return_address_reg.GetName(), + return_address_reg.GetAsKind(eRegisterKindLLDB)); + if (active_row && active_row->GetRegisterInfo(regnum.GetAsKind(kind), + unwindplan_regloc)) { + UnwindLogMsg("supplying caller's saved %s (%d)'s location using " + "%s UnwindPlan", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), + m_full_unwind_plan_sp->GetSourceName().GetCString()); + if (unwindplan_regloc.IsSame()) + unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + return unwindplan_regloc; } else { - // This is a normal function, there's no rule for - // finding the caller's pc value, look for the caller's - // return address register value. - return_address_reg.init(m_thread, - m_full_unwind_plan_sp->GetRegisterKind(), - return_address_regnum); - regnum = return_address_reg; - UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a " - "RA reg; getting %s (%d) instead", - return_address_reg.GetName(), - return_address_reg.GetAsKind(eRegisterKindLLDB)); - if (active_row && active_row->GetRegisterInfo(regnum.GetAsKind(kind), - unwindplan_regloc)) { - UnwindLogMsg("supplying caller's saved %s (%d)'s location using " - "%s UnwindPlan", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - m_full_unwind_plan_sp->GetSourceName().GetCString()); - if (unwindplan_regloc.IsSame()) - unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + // No unwind rule for the return address reg on frame + // 0 means that the caller's address is still in RA reg. + if (BehavesLikeZerothFrame()) { + unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); return unwindplan_regloc; - } else { - // No unwind rule for the return address reg on frame - // 0 means that the caller's address is still in RA reg. - if (BehavesLikeZerothFrame()) { - unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); - return unwindplan_regloc; - } } } } >From fde91220492202f7a8b56312cac5b7316975d69a Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 13 May 2025 17:41:45 -0700 Subject: [PATCH 3/6] Don't log a message when the ABI says this is a volatile register -- has an Undefined abstract register location. --- lldb/source/Target/RegisterContextUnwind.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index aae5de97de242..cf23df21f5044 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1441,7 +1441,8 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, const RegisterInfo *reg_info = GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB)); if (reg_info && - abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) { + abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc) && + !unwindplan_regloc.IsUndefined()) { UnwindLogMsg( "supplying caller's saved %s (%d)'s location using ABI default", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); >From 853da6655104080cb7022ca4e7f18ffae2e5df1b Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 13 May 2025 18:03:41 -0700 Subject: [PATCH 4/6] clarify comment. --- lldb/source/Target/RegisterContextUnwind.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index cf23df21f5044..64cb906f4d6c3 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1450,8 +1450,9 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, } } - // We have no AbstractRegisterRule, and the ABI says this is a - // non-volatile / callee-preserved register. + // We have no AbstractRegisterLocation, and the ABI says this is a + // non-volatile / callee-preserved register. Continue down the stack + // or to frame 0 & the live RegisterContext. std::string unwindplan_name; if (m_full_unwind_plan_sp) { unwindplan_name += "via '"; >From 1f40042126fb4941f365c6b0bb3f83961248695e Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 13 May 2025 22:02:17 -0700 Subject: [PATCH 5/6] make another pass over all the comments and rewrite/clarify a bunch of them. Tiny tweaks to the code to make it more readable. --- lldb/source/Target/RegisterContextUnwind.cpp | 143 ++++++++++--------- 1 file changed, 78 insertions(+), 65 deletions(-) diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index 64cb906f4d6c3..791671dc8e166 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1243,24 +1243,34 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( return false; } -// Search this stack frame's UnwindPlans for the AbstractRegisterLocation -// for this register. -// -// When an AbstractRegisterLocation is found in an UnwindPlan, that is -// returned, regardless of the ABI rules for volatile/non-volatile registers -// in effect. -// -// If there is no unwind rule for a volatile (caller-preserved) register -// the returned AbstractRegisterLocation will be IsUndefined, -// indicating that we should stop searching. -// -// If there is no unwind rule for a non-volatile (callee-preserved) -// register, the returned AbstractRegisterLocation will be IsSame. -// In frame 0, IsSame means get the value from the live register context. -// Else it means to continue descending down the stack to more-live frames -// looking for a location/value. -// -// An empty optional indicates that there was an error in processing. +/// Search this stack frame's UnwindPlans for the AbstractRegisterLocation +/// for this register. +/// +/// \param[out] kind +/// Set to the RegisterKind of the UnwindPlan which is the basis for +/// the returned AbstractRegisterLocation; if the location is in terms +/// of another register number, this Kind is needed to interpret it +/// correctly. +/// +/// \return +/// An empty optional indicaTes that there was an error in processing +/// the request. +/// +/// If there is no unwind rule for a volatile (caller-preserved) register, +/// the returned AbstractRegisterLocation will be IsUndefined, +/// indicating that we should stop searching. +/// +/// If there is no unwind rule for a non-volatile (callee-preserved) +/// register, the returned AbstractRegisterLocation will be IsSame. +/// In frame 0, IsSame means get the value from the live register context. +/// Else it means to continue descending down the stack to more-live frames +/// looking for a location/value. +/// +/// If an AbstractRegisterLocation is found in an UnwindPlan, that will +/// be returned, with no consideration of the current ABI rules for +/// registers. Functions using an alternate ABI calling convention +/// will work as long as the UnwindPlans are exhaustive about what +/// registers are volatile/non-volatile. std::optional RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, lldb::RegisterKind &kind) { @@ -1324,16 +1334,15 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, } if (regnum.GetAsKind(kind) == LLDB_INVALID_REGNUM) { - if (kind == eRegisterKindGeneric) { + if (kind == eRegisterKindGeneric) UnwindLogMsg("could not convert lldb regnum %s (%d) into " "eRegisterKindGeneric reg numbering scheme", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - } else { + else UnwindLogMsg("could not convert lldb regnum %s (%d) into %d " "RegisterKind reg numbering scheme", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), (int)kind); - } return {}; } @@ -1347,42 +1356,37 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, return unwindplan_regloc; } - // When asking for the caller's pc, check if we have a + // When asking for the caller's pc, and did not find a register + // location for PC above in the UnwindPlan. Check if we have a // Return Address register on this target. // // On a Return Address Register architecture like arm/mips/riscv, // the caller's pc is in the RA register, and will be spilled to - // stack before any other function can be called. We may have a - // register location saying - // pc=RAReg {caller's retrun addr is in RA register} - // ra=IsSame {caller's return addr is live in RA register} - // ra=StackAddr {caller's return addr spilled to stack} - // or none of the above, which means the caller's pc is live in the - // return address reg if this is frame 0, or the frame below is - // a trap/sigtramp/interrupt handler function. Any other mid-stack - // function must have an unwind rule for PC/RA giving a location/value. + // stack before any other function is called. If no function + // has been called yet, the return address may still be in the + // live RA reg. // - // In the case of an interrupted function -- the function above sigtramp, - // or a function interrupted asynchronously, or that has faulted to - // a trap handler -- it is valid to ask both the "pc" value -- the - // instruction that was executing when the interrupt/fault happend -- - // and the RA Register value. If a frameless function (which doesn't - // create a stack frame, doesn't save the RA reg to stack) is interrupted, - // the trap handler will have a rule to provide the pc (the instruction - // that was executing) AND a rule to provide the RA Register, which we - // need to use to find the caller function: - // pc=StackAddr1 - // ra=StackAddr2 - // and we don't want to rewrite a request of "pc" to "ra" here, because - // they mean different things. - + // There's a lot of variety of what we might see in an UnwindPlan. + // We may have + // ra=IsSame {unncessary} + // ra=StackAddr {caller's return addr spilled to stack} + // or no unwindrule for pc or ra at all, in a frameless function - + // the caller's return address is in live ra reg. + // + // If a function has been interrupted in a non-call way -- + // async signal/sigtramp, or a hardware exception / interrupt / fault -- + // then the "pc" and "ra" are two distinct values, and must be + // handled separately. The "pc" is the pc value at the point + // the function was interrupted. The "ra" is the return address + // register value at that point. + // The UnwindPlan for the sigtramp/trap handler will normally have + // register loations for both pc and lr, and so we'll have already + // fetched them above. if (pc_regnum.IsValid() && pc_regnum == regnum) { - RegisterNumber return_address_reg; - uint32_t return_address_regnum = - LLDB_INVALID_REGNUM; // in full UnwindPlan's numbering + uint32_t return_address_regnum = LLDB_INVALID_REGNUM; // Get the return address register number from the UnwindPlan - // or the arch register set. + // or the register set definition. if (m_full_unwind_plan_sp->GetReturnAddressRegister() != LLDB_INVALID_REGNUM) { return_address_regnum = @@ -1393,32 +1397,38 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, return_address_regnum = arch_default_ra_regnum.GetAsKind(kind); } + // This system is using a return address register. if (return_address_regnum != LLDB_INVALID_REGNUM) { - // This is a normal function, there's no rule for - // finding the caller's pc value, look for the caller's - // return address register value. + RegisterNumber return_address_reg; return_address_reg.init(m_thread, m_full_unwind_plan_sp->GetRegisterKind(), return_address_regnum); - regnum = return_address_reg; UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a " "RA reg; getting %s (%d) instead", return_address_reg.GetName(), return_address_reg.GetAsKind(eRegisterKindLLDB)); - if (active_row && active_row->GetRegisterInfo(regnum.GetAsKind(kind), - unwindplan_regloc)) { + + // Do we have a location for the ra register? + if (active_row && + active_row->GetRegisterInfo(return_address_reg.GetAsKind(kind), + unwindplan_regloc)) { UnwindLogMsg("supplying caller's saved %s (%d)'s location using " "%s UnwindPlan", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), + return_address_reg.GetName(), + return_address_reg.GetAsKind(eRegisterKindLLDB), m_full_unwind_plan_sp->GetSourceName().GetCString()); + // If we have "ra=IsSame", rewrite to "ra=InRegister(ra)" because the + // calling function thinks it is fetching "pc" and if we return an + // IsSame register location, it will try to read pc. if (unwindplan_regloc.IsSame()) - unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + unwindplan_regloc.SetInRegister(return_address_reg.GetAsKind(kind)); return unwindplan_regloc; } else { - // No unwind rule for the return address reg on frame - // 0 means that the caller's address is still in RA reg. + // No unwind rule for the return address reg on frame 0, or an + // interrupted function, means that the caller's address is still in + // RA reg. if (BehavesLikeZerothFrame()) { - unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + unwindplan_regloc.SetInRegister(return_address_reg.GetAsKind(kind)); return unwindplan_regloc; } } @@ -1441,11 +1451,14 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, const RegisterInfo *reg_info = GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB)); if (reg_info && - abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc) && - !unwindplan_regloc.IsUndefined()) { - UnwindLogMsg( - "supplying caller's saved %s (%d)'s location using ABI default", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) { + if (!unwindplan_regloc.IsUndefined()) + UnwindLogMsg( + "supplying caller's saved %s (%d)'s location using ABI default", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + // ABI defined volatile registers with no register location + // will be returned as IsUndefined, stopping the search down + // the stack. return unwindplan_regloc; } } >From 967f99d89f874be9e89fd3de37c8ca2fc88e3fa3 Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 13 May 2025 22:18:09 -0700 Subject: [PATCH 6/6] tiny edit --- lldb/source/Target/RegisterContextUnwind.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index 791671dc8e166..97fefd8d09d69 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1370,7 +1370,7 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, // We may have // ra=IsSame {unncessary} // ra=StackAddr {caller's return addr spilled to stack} - // or no unwindrule for pc or ra at all, in a frameless function - + // or no reg location for pc or ra at all, in a frameless function - // the caller's return address is in live ra reg. // // If a function has been interrupted in a non-call way -- @@ -1426,7 +1426,8 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, } else { // No unwind rule for the return address reg on frame 0, or an // interrupted function, means that the caller's address is still in - // RA reg. + // RA reg (0th frame) or the trap handler below this one (sigtramp + // etc) has a save location for the RA reg. if (BehavesLikeZerothFrame()) { unwindplan_regloc.SetInRegister(return_address_reg.GetAsKind(kind)); return unwindplan_regloc; From lldb-commits at lists.llvm.org Tue May 13 22:20:04 2025 From: lldb-commits at lists.llvm.org (Alex Langford via lldb-commits) Date: Tue, 13 May 2025 22:20:04 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Fix typos in documentation (PR #139839) In-Reply-To: Message-ID: <68242804.170a0220.10096a.04a2@mx.google.com> https://github.com/bulbazord approved this pull request. https://github.com/llvm/llvm-project/pull/139839 From lldb-commits at lists.llvm.org Tue May 13 22:25:31 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Tue, 13 May 2025 22:25:31 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Fix typos in documentation (PR #139839) In-Reply-To: Message-ID: <6824294b.050a0220.9368e.3b76@mx.google.com> https://github.com/JDevlieghere approved this pull request. https://github.com/llvm/llvm-project/pull/139839 From lldb-commits at lists.llvm.org Tue May 13 22:34:03 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Tue, 13 May 2025 22:34:03 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for capabilities (PR #139835) In-Reply-To: Message-ID: <68242b4b.170a0220.11c97c.0d90@mx.google.com> JDevlieghere wrote: > Should we also have some tests for invalid enum cases? Sounds good, let me cover the enum cases in a separate PR. https://github.com/llvm/llvm-project/pull/139835 From lldb-commits at lists.llvm.org Tue May 13 22:51:06 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Tue, 13 May 2025 22:51:06 -0700 (PDT) Subject: [Lldb-commits] [lldb] ad2f703 - [lldb-dap] Add unit test for capabilities (#139835) Message-ID: <68242f4a.170a0220.1dc49a.1859@mx.google.com> Author: Jonas Devlieghere Date: 2025-05-13T22:51:03-07:00 New Revision: ad2f7034a2823f2366e55a5758c1c623b9348746 URL: https://github.com/llvm/llvm-project/commit/ad2f7034a2823f2366e55a5758c1c623b9348746 DIFF: https://github.com/llvm/llvm-project/commit/ad2f7034a2823f2366e55a5758c1c623b9348746.diff LOG: [lldb-dap] Add unit test for capabilities (#139835) Add unit a test for the capabilities type. Added: Modified: lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp lldb/tools/lldb-dap/Protocol/ProtocolTypes.h lldb/unittests/DAP/ProtocolTypesTest.cpp Removed: ################################################################################ diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index 8d95687e00e53..fafd061334bc9 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -165,6 +165,32 @@ json::Value toJSON(const ChecksumAlgorithm &CA) { llvm_unreachable("unhandled checksum algorithm."); } +bool fromJSON(const llvm::json::Value &Params, ChecksumAlgorithm &CA, + llvm::json::Path P) { + auto rawAlgorithm = Params.getAsString(); + if (!rawAlgorithm) { + P.report("expected a string"); + return false; + } + + std::optional algorithm = + llvm::StringSwitch>(*rawAlgorithm) + .Case("MD5", eChecksumAlgorithmMD5) + .Case("SHA1", eChecksumAlgorithmSHA1) + .Case("SHA256", eChecksumAlgorithmSHA256) + .Case("timestamp", eChecksumAlgorithmTimestamp) + .Default(std::nullopt); + + if (!algorithm) { + P.report( + "unexpected value, expected 'MD5', 'SHA1', 'SHA256', or 'timestamp'"); + return false; + } + + CA = *algorithm; + return true; +} + json::Value toJSON(const BreakpointModeApplicability &BMA) { switch (BMA) { case eBreakpointModeApplicabilitySource: @@ -304,6 +330,84 @@ static llvm::StringLiteral ToString(AdapterFeature feature) { llvm_unreachable("unhandled adapter feature."); } +llvm::json::Value toJSON(const AdapterFeature &feature) { + return ToString(feature); +} + +bool fromJSON(const llvm::json::Value &Params, AdapterFeature &feature, + llvm::json::Path P) { + auto rawFeature = Params.getAsString(); + if (!rawFeature) { + P.report("expected a string"); + return false; + } + + std::optional parsedFeature = + llvm::StringSwitch>(*rawFeature) + .Case("supportsANSIStyling", eAdapterFeatureANSIStyling) + .Case("supportsBreakpointLocationsRequest", + eAdapterFeatureBreakpointLocationsRequest) + .Case("supportsCancelRequest", eAdapterFeatureCancelRequest) + .Case("supportsClipboardContext", eAdapterFeatureClipboardContext) + .Case("supportsCompletionsRequest", eAdapterFeatureCompletionsRequest) + .Case("supportsConditionalBreakpoints", + eAdapterFeatureConditionalBreakpoints) + .Case("supportsConfigurationDoneRequest", + eAdapterFeatureConfigurationDoneRequest) + .Case("supportsDataBreakpointBytes", + eAdapterFeatureDataBreakpointBytes) + .Case("supportsDataBreakpoints", eAdapterFeatureDataBreakpoints) + .Case("supportsDelayedStackTraceLoading", + eAdapterFeatureDelayedStackTraceLoading) + .Case("supportsDisassembleRequest", eAdapterFeatureDisassembleRequest) + .Case("supportsEvaluateForHovers", eAdapterFeatureEvaluateForHovers) + .Case("supportsExceptionFilterOptions", + eAdapterFeatureExceptionFilterOptions) + .Case("supportsExceptionInfoRequest", + eAdapterFeatureExceptionInfoRequest) + .Case("supportsExceptionOptions", eAdapterFeatureExceptionOptions) + .Case("supportsFunctionBreakpoints", + eAdapterFeatureFunctionBreakpoints) + .Case("supportsGotoTargetsRequest", eAdapterFeatureGotoTargetsRequest) + .Case("supportsHitConditionalBreakpoints", + eAdapterFeatureHitConditionalBreakpoints) + .Case("supportsInstructionBreakpoints", + eAdapterFeatureInstructionBreakpoints) + .Case("supportsLoadedSourcesRequest", + eAdapterFeatureLoadedSourcesRequest) + .Case("supportsLogPoints", eAdapterFeatureLogPoints) + .Case("supportsModulesRequest", eAdapterFeatureModulesRequest) + .Case("supportsReadMemoryRequest", eAdapterFeatureReadMemoryRequest) + .Case("supportsRestartFrame", eAdapterFeatureRestartFrame) + .Case("supportsRestartRequest", eAdapterFeatureRestartRequest) + .Case("supportsSetExpression", eAdapterFeatureSetExpression) + .Case("supportsSetVariable", eAdapterFeatureSetVariable) + .Case("supportsSingleThreadExecutionRequests", + eAdapterFeatureSingleThreadExecutionRequests) + .Case("supportsStepBack", eAdapterFeatureStepBack) + .Case("supportsStepInTargetsRequest", + eAdapterFeatureStepInTargetsRequest) + .Case("supportsSteppingGranularity", + eAdapterFeatureSteppingGranularity) + .Case("supportsTerminateRequest", eAdapterFeatureTerminateRequest) + .Case("supportsTerminateThreadsRequest", + eAdapterFeatureTerminateThreadsRequest) + .Case("supportSuspendDebuggee", eAdapterFeatureSuspendDebuggee) + .Case("supportsValueFormattingOptions", + eAdapterFeatureValueFormattingOptions) + .Case("supportsWriteMemoryRequest", eAdapterFeatureWriteMemoryRequest) + .Case("supportTerminateDebuggee", eAdapterFeatureTerminateDebuggee) + .Default(std::nullopt); + + if (!parsedFeature) { + P.report("unexpected value for AdapterFeature"); + return false; + } + + feature = *parsedFeature; + return true; +} + json::Value toJSON(const Capabilities &C) { json::Object result; @@ -331,6 +435,32 @@ json::Value toJSON(const Capabilities &C) { return result; } +bool fromJSON(const llvm::json::Value &Params, Capabilities &C, + llvm::json::Path P) { + auto *Object = Params.getAsObject(); + if (!Object) { + P.report("expected an object"); + return false; + } + // Check for the presence of supported features. + for (unsigned i = eAdapterFeatureFirst; i <= eAdapterFeatureLast; ++i) { + AdapterFeature feature = static_cast(i); + if (Object->getBoolean(ToString(feature))) + C.supportedFeatures.insert(feature); + } + llvm::json::ObjectMapper O(Params, P); + return O && + O.mapOptional("exceptionBreakpointFilters", + C.exceptionBreakpointFilters) && + O.mapOptional("completionTriggerCharacters", + C.completionTriggerCharacters) && + O.mapOptional("additionalModuleColumns", C.additionalModuleColumns) && + O.mapOptional("supportedChecksumAlgorithms", + C.supportedChecksumAlgorithms) && + O.mapOptional("breakpointModes", C.breakpointModes) && + O.mapOptional("$__lldb_version", C.lldbExtVersion); +} + bool fromJSON(const llvm::json::Value &Params, SteppingGranularity &SG, llvm::json::Path P) { auto raw_granularity = Params.getAsString(); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index c48988a48a373..f8d2b35ce3e14 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -102,6 +102,7 @@ enum ChecksumAlgorithm : unsigned { eChecksumAlgorithmSHA256, eChecksumAlgorithmTimestamp }; +bool fromJSON(const llvm::json::Value &, ChecksumAlgorithm &, llvm::json::Path); llvm::json::Value toJSON(const ChecksumAlgorithm &); /// Describes one or more type of breakpoint a BreakpointMode applies to. This @@ -237,7 +238,11 @@ enum AdapterFeature : unsigned { /// The debug adapter supports the `terminateDebuggee` attribute on the /// `disconnect` request. eAdapterFeatureTerminateDebuggee, + eAdapterFeatureFirst = eAdapterFeatureANSIStyling, + eAdapterFeatureLast = eAdapterFeatureTerminateDebuggee, }; +bool fromJSON(const llvm::json::Value &, AdapterFeature &, llvm::json::Path); +llvm::json::Value toJSON(const AdapterFeature &); /// Information about the capabilities of a debug adapter. struct Capabilities { @@ -275,13 +280,15 @@ struct Capabilities { /// @} }; +bool fromJSON(const llvm::json::Value &, Capabilities &, llvm::json::Path); llvm::json::Value toJSON(const Capabilities &); enum PresentationHint : unsigned { ePresentationHintNormal, ePresentationHintEmphasize, - ePresentationHintDeemphasize, + ePresentationHintDeemphasize }; +bool fromJSON(const llvm::json::Value &, PresentationHint &, llvm::json::Path); llvm::json::Value toJSON(PresentationHint hint); /// A `Source` is a descriptor for source code. It is returned from the debug diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp index f5d72f06432d5..fd3e3be073183 100644 --- a/lldb/unittests/DAP/ProtocolTypesTest.cpp +++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp @@ -194,3 +194,100 @@ TEST(ProtocolTypesTest, DataBreakpoint) { EXPECT_EQ(data_breakpoint_info.hitCondition, deserialized_data_breakpoint_info->hitCondition); } + +TEST(ProtocolTypesTest, Capabilities) { + Capabilities capabilities; + + // Populate supported features. + capabilities.supportedFeatures.insert(eAdapterFeatureANSIStyling); + capabilities.supportedFeatures.insert( + eAdapterFeatureBreakpointLocationsRequest); + + // Populate optional fields. + capabilities.exceptionBreakpointFilters = { + {{"filter1", "Filter 1", "Description 1", true, true, "Condition 1"}, + {"filter2", "Filter 2", "Description 2", false, false, "Condition 2"}}}; + + capabilities.completionTriggerCharacters = {".", "->"}; + capabilities.additionalModuleColumns = { + {"moduleName", "Module Name", "uppercase", eColumnTypeString, 20}}; + capabilities.supportedChecksumAlgorithms = {eChecksumAlgorithmMD5, + eChecksumAlgorithmSHA256}; + capabilities.breakpointModes = {{"hardware", + "Hardware Breakpoint", + "Description", + {eBreakpointModeApplicabilitySource}}}; + capabilities.lldbExtVersion = "1.0.0"; + + // Perform roundtrip serialization and deserialization. + llvm::Expected deserialized_capabilities = + roundtrip(capabilities); + ASSERT_THAT_EXPECTED(deserialized_capabilities, llvm::Succeeded()); + + // Verify supported features. + EXPECT_EQ(capabilities.supportedFeatures, + deserialized_capabilities->supportedFeatures); + + // Verify exception breakpoint filters. + ASSERT_TRUE( + deserialized_capabilities->exceptionBreakpointFilters.has_value()); + EXPECT_EQ(capabilities.exceptionBreakpointFilters->size(), + deserialized_capabilities->exceptionBreakpointFilters->size()); + for (size_t i = 0; i < capabilities.exceptionBreakpointFilters->size(); ++i) { + const auto &original = capabilities.exceptionBreakpointFilters->at(i); + const auto &deserialized = + deserialized_capabilities->exceptionBreakpointFilters->at(i); + EXPECT_EQ(original.filter, deserialized.filter); + EXPECT_EQ(original.label, deserialized.label); + EXPECT_EQ(original.description, deserialized.description); + EXPECT_EQ(original.defaultState, deserialized.defaultState); + EXPECT_EQ(original.supportsCondition, deserialized.supportsCondition); + EXPECT_EQ(original.conditionDescription, deserialized.conditionDescription); + } + + // Verify completion trigger characters. + ASSERT_TRUE( + deserialized_capabilities->completionTriggerCharacters.has_value()); + EXPECT_EQ(capabilities.completionTriggerCharacters, + deserialized_capabilities->completionTriggerCharacters); + + // Verify additional module columns. + ASSERT_TRUE(deserialized_capabilities->additionalModuleColumns.has_value()); + EXPECT_EQ(capabilities.additionalModuleColumns->size(), + deserialized_capabilities->additionalModuleColumns->size()); + for (size_t i = 0; i < capabilities.additionalModuleColumns->size(); ++i) { + const auto &original = capabilities.additionalModuleColumns->at(i); + const auto &deserialized = + deserialized_capabilities->additionalModuleColumns->at(i); + EXPECT_EQ(original.attributeName, deserialized.attributeName); + EXPECT_EQ(original.label, deserialized.label); + EXPECT_EQ(original.format, deserialized.format); + EXPECT_EQ(original.type, deserialized.type); + EXPECT_EQ(original.width, deserialized.width); + } + + // Verify supported checksum algorithms. + ASSERT_TRUE( + deserialized_capabilities->supportedChecksumAlgorithms.has_value()); + EXPECT_EQ(capabilities.supportedChecksumAlgorithms, + deserialized_capabilities->supportedChecksumAlgorithms); + + // Verify breakpoint modes. + ASSERT_TRUE(deserialized_capabilities->breakpointModes.has_value()); + EXPECT_EQ(capabilities.breakpointModes->size(), + deserialized_capabilities->breakpointModes->size()); + for (size_t i = 0; i < capabilities.breakpointModes->size(); ++i) { + const auto &original = capabilities.breakpointModes->at(i); + const auto &deserialized = + deserialized_capabilities->breakpointModes->at(i); + EXPECT_EQ(original.mode, deserialized.mode); + EXPECT_EQ(original.label, deserialized.label); + EXPECT_EQ(original.description, deserialized.description); + EXPECT_EQ(original.appliesTo, deserialized.appliesTo); + } + + // Verify lldb extension version. + ASSERT_TRUE(deserialized_capabilities->lldbExtVersion.has_value()); + EXPECT_EQ(capabilities.lldbExtVersion, + deserialized_capabilities->lldbExtVersion); +} From lldb-commits at lists.llvm.org Tue May 13 22:51:09 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Tue, 13 May 2025 22:51:09 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for capabilities (PR #139835) In-Reply-To: Message-ID: <68242f4d.170a0220.1e52b1.178b@mx.google.com> https://github.com/JDevlieghere closed https://github.com/llvm/llvm-project/pull/139835 From lldb-commits at lists.llvm.org Tue May 13 22:52:08 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Tue, 13 May 2025 22:52:08 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for protocol enum types (PR #139848) Message-ID: https://github.com/JDevlieghere created https://github.com/llvm/llvm-project/pull/139848 Add dedicated unit tests for the protocol enum types. Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Tue May 13 22:52:41 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Tue, 13 May 2025 22:52:41 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for protocol enum types (PR #139848) In-Reply-To: Message-ID: <68242fa9.630a0220.234a60.99e6@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Jonas Devlieghere (JDevlieghere)
Changes Add dedicated unit tests for the protocol enum types. --- Full diff: https://github.com/llvm/llvm-project/pull/139848.diff 3 Files Affected: - (modified) lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp (+13-1) - (modified) lldb/tools/lldb-dap/Protocol/ProtocolTypes.h (+1) - (modified) lldb/unittests/DAP/ProtocolTypesTest.cpp (+198) ``````````diff diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index fafd061334bc9..857503b3a0084 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -105,7 +105,7 @@ bool fromJSON(const json::Value &Params, ColumnType &CT, json::Path P) { .Case("string", eColumnTypeString) .Case("number", eColumnTypeNumber) .Case("boolean", eColumnTypeBoolean) - .Case("unixTimestampUTC ", eColumnTypeTimestamp) + .Case("unixTimestampUTC", eColumnTypeTimestamp) .Default(std::nullopt); if (!columnType) { P.report("unexpected value, expected 'string', 'number', 'boolean', or " @@ -482,6 +482,18 @@ bool fromJSON(const llvm::json::Value &Params, SteppingGranularity &SG, return true; } +llvm::json::Value toJSON(const SteppingGranularity &SG) { + switch (SG) { + case eSteppingGranularityStatement: + return "statement"; + case eSteppingGranularityLine: + return "line"; + case eSteppingGranularityInstruction: + return "instruction"; + } + llvm_unreachable("unhandled stepping granularity."); +} + bool fromJSON(const llvm::json::Value &Params, ValueFormat &VF, llvm::json::Path P) { json::ObjectMapper O(Params, P); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index f8d2b35ce3e14..757037a7b6ed2 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -339,6 +339,7 @@ enum SteppingGranularity : unsigned { }; bool fromJSON(const llvm::json::Value &, SteppingGranularity &, llvm::json::Path); +llvm::json::Value toJSON(const SteppingGranularity &); /// Provides formatting information for a value. struct ValueFormat { diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp index fd3e3be073183..d97bbaffa2bc0 100644 --- a/lldb/unittests/DAP/ProtocolTypesTest.cpp +++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp @@ -291,3 +291,201 @@ TEST(ProtocolTypesTest, Capabilities) { EXPECT_EQ(capabilities.lldbExtVersion, deserialized_capabilities->lldbExtVersion); } + +TEST(ProtocolTypesTest, PresentationHint) { + // Test all PresentationHint values. + std::vector> test_cases = { + {ePresentationHintNormal, "normal"}, + {ePresentationHintEmphasize, "emphasize"}, + {ePresentationHintDeemphasize, "deemphasize"}}; + + for (const auto &test_case : test_cases) { + // Serialize the PresentationHint to JSON. + llvm::json::Value serialized = toJSON(test_case.first); + ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String); + EXPECT_EQ(serialized.getAsString(), test_case.second); + + // Deserialize the JSON back to PresentationHint. + PresentationHint deserialized; + llvm::json::Path::Root root; + ASSERT_TRUE(fromJSON(serialized, deserialized, root)) + << llvm::toString(root.getError()); + EXPECT_EQ(deserialized, test_case.first); + } + + // Test invalid value. + llvm::json::Value invalid_value = "invalid_hint"; + PresentationHint deserialized_invalid; + llvm::json::Path::Root root; + EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root)); +} + +TEST(ProtocolTypesTest, SteppingGranularity) { + // Test all SteppingGranularity values. + std::vector> test_cases = { + {eSteppingGranularityStatement, "statement"}, + {eSteppingGranularityLine, "line"}, + {eSteppingGranularityInstruction, "instruction"}}; + + for (const auto &test_case : test_cases) { + // Serialize the SteppingGranularity to JSON. + llvm::json::Value serialized = toJSON(test_case.first); + ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String); + EXPECT_EQ(serialized.getAsString(), test_case.second); + + // Deserialize the JSON back to SteppingGranularity. + SteppingGranularity deserialized; + llvm::json::Path::Root root; + ASSERT_TRUE(fromJSON(serialized, deserialized, root)) + << llvm::toString(root.getError()); + EXPECT_EQ(deserialized, test_case.first); + } + + // Test invalid value. + llvm::json::Value invalid_value = "invalid_granularity"; + SteppingGranularity deserialized_invalid; + llvm::json::Path::Root root; + EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root)); +} + +TEST(ProtocolTypesTest, BreakpointReason) { + // Test all BreakpointReason values. + std::vector> test_cases = { + {BreakpointReason::eBreakpointReasonPending, "pending"}, + {BreakpointReason::eBreakpointReasonFailed, "failed"}}; + + for (const auto &test_case : test_cases) { + // Serialize the BreakpointReason to JSON. + llvm::json::Value serialized = toJSON(test_case.first); + ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String); + EXPECT_EQ(serialized.getAsString(), test_case.second); + + // Deserialize the JSON back to BreakpointReason. + BreakpointReason deserialized; + llvm::json::Path::Root root; + ASSERT_TRUE(fromJSON(serialized, deserialized, root)) + << llvm::toString(root.getError()); + EXPECT_EQ(deserialized, test_case.first); + } + + // Test invalid value. + llvm::json::Value invalid_value = "invalid_reason"; + BreakpointReason deserialized_invalid; + llvm::json::Path::Root root; + EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root)); +} + +TEST(ProtocolTypesTest, DataBreakpointAccessType) { + // Test all DataBreakpointAccessType values. + std::vector> test_cases = + {{eDataBreakpointAccessTypeRead, "read"}, + {eDataBreakpointAccessTypeWrite, "write"}, + {eDataBreakpointAccessTypeReadWrite, "readWrite"}}; + + for (const auto &test_case : test_cases) { + // Serialize the DataBreakpointAccessType to JSON. + llvm::json::Value serialized = toJSON(test_case.first); + ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String); + EXPECT_EQ(serialized.getAsString(), test_case.second); + + // Deserialize the JSON back to DataBreakpointAccessType. + DataBreakpointAccessType deserialized; + llvm::json::Path::Root root; + ASSERT_TRUE(fromJSON(serialized, deserialized, root)) + << llvm::toString(root.getError()); + EXPECT_EQ(deserialized, test_case.first); + } + + // Test invalid value + llvm::json::Value invalid_value = "invalid_access_type"; + DataBreakpointAccessType deserialized_invalid; + llvm::json::Path::Root root; + EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root)); +} + +TEST(ProtocolTypesTest, ColumnType) { + // Test all ColumnType values. + std::vector> test_cases = { + {eColumnTypeString, "string"}, + {eColumnTypeNumber, "number"}, + {eColumnTypeBoolean, "boolean"}, + {eColumnTypeTimestamp, "unixTimestampUTC"}}; + + for (const auto &test_case : test_cases) { + // Serialize the ColumnType to JSON. + llvm::json::Value serialized = toJSON(test_case.first); + ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String); + EXPECT_EQ(serialized.getAsString(), test_case.second); + + // Deserialize the JSON back to ColumnType. + ColumnType deserialized; + llvm::json::Path::Root root; + ASSERT_TRUE(fromJSON(serialized, deserialized, root)) + << llvm::toString(root.getError()); + EXPECT_EQ(deserialized, test_case.first); + } + + // Test invalid value. + llvm::json::Value invalid_value = "invalid_column_type"; + ColumnType deserialized_invalid; + llvm::json::Path::Root root; + EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root)); +} + +TEST(ProtocolTypesTest, BreakpointModeApplicability) { + // Test all BreakpointModeApplicability values. + std::vector> + test_cases = {{eBreakpointModeApplicabilitySource, "source"}, + {eBreakpointModeApplicabilityException, "exception"}, + {eBreakpointModeApplicabilityData, "data"}, + {eBreakpointModeApplicabilityInstruction, "instruction"}}; + + for (const auto &test_case : test_cases) { + // Serialize the BreakpointModeApplicability to JSON. + llvm::json::Value serialized = toJSON(test_case.first); + ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String); + EXPECT_EQ(serialized.getAsString(), test_case.second); + + // Deserialize the JSON back to BreakpointModeApplicability. + BreakpointModeApplicability deserialized; + llvm::json::Path::Root root; + ASSERT_TRUE(fromJSON(serialized, deserialized, root)) + << llvm::toString(root.getError()); + EXPECT_EQ(deserialized, test_case.first); + } + + // Test invalid value. + llvm::json::Value invalid_value = "invalid_applicability"; + BreakpointModeApplicability deserialized_invalid; + llvm::json::Path::Root root; + EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root)); +} + +TEST(ProtocolTypesTest, ChecksumAlgorithm) { + // Test all ChecksumAlgorithm values. + std::vector> test_cases = { + {eChecksumAlgorithmMD5, "MD5"}, + {eChecksumAlgorithmSHA1, "SHA1"}, + {eChecksumAlgorithmSHA256, "SHA256"}, + {eChecksumAlgorithmTimestamp, "timestamp"}}; + + for (const auto &test_case : test_cases) { + // Serialize the ChecksumAlgorithm to JSON. + llvm::json::Value serialized = toJSON(test_case.first); + ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String); + EXPECT_EQ(serialized.getAsString(), test_case.second); + + // Deserialize the JSON back to ChecksumAlgorithm. + ChecksumAlgorithm deserialized; + llvm::json::Path::Root root; + ASSERT_TRUE(fromJSON(serialized, deserialized, root)) + << llvm::toString(root.getError()); + EXPECT_EQ(deserialized, test_case.first); + } + + // Test invalid value. + llvm::json::Value invalid_value = "invalid_algorithm"; + ChecksumAlgorithm deserialized_invalid; + llvm::json::Path::Root root; + EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root)); +} ``````````
https://github.com/llvm/llvm-project/pull/139848 From lldb-commits at lists.llvm.org Tue May 13 22:52:56 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Tue, 13 May 2025 22:52:56 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for protocol enum types (PR #139848) In-Reply-To: Message-ID: <68242fb8.a70a0220.361314.214c@mx.google.com> ================ @@ -105,7 +105,7 @@ bool fromJSON(const json::Value &Params, ColumnType &CT, json::Path P) { .Case("string", eColumnTypeString) .Case("number", eColumnTypeNumber) .Case("boolean", eColumnTypeBoolean) - .Case("unixTimestampUTC ", eColumnTypeTimestamp) + .Case("unixTimestampUTC", eColumnTypeTimestamp) ---------------- JDevlieghere wrote: My unit test found an actual bug/typo :-) https://github.com/llvm/llvm-project/pull/139848 From lldb-commits at lists.llvm.org Tue May 13 23:22:24 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Tue, 13 May 2025 23:22:24 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for protocol enum types (PR #139848) In-Reply-To: Message-ID: <682436a0.050a0220.21e321.24ce@mx.google.com> https://github.com/ashgti approved this pull request. LGTM! https://github.com/llvm/llvm-project/pull/139848 From lldb-commits at lists.llvm.org Tue May 13 23:34:32 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Tue, 13 May 2025 23:34:32 -0700 (PDT) Subject: [Lldb-commits] [lldb] bdf8c99 - [lldb] Fix typos in documentation (#139839) Message-ID: <68243978.a70a0220.14f131.0fb8@mx.google.com> Author: Kazu Hirata Date: 2025-05-13T23:34:28-07:00 New Revision: bdf8c9984ae325b9934ec6051a853a29830af9e2 URL: https://github.com/llvm/llvm-project/commit/bdf8c9984ae325b9934ec6051a853a29830af9e2 DIFF: https://github.com/llvm/llvm-project/commit/bdf8c9984ae325b9934ec6051a853a29830af9e2.diff LOG: [lldb] Fix typos in documentation (#139839) Added: Modified: lldb/docs/resources/build.rst lldb/docs/resources/contributing.rst lldb/docs/resources/debugging.rst lldb/docs/resources/qemu-testing.rst lldb/docs/use/variable.rst Removed: ################################################################################ diff --git a/lldb/docs/resources/build.rst b/lldb/docs/resources/build.rst index e59dcc1972418..480430fede928 100644 --- a/lldb/docs/resources/build.rst +++ b/lldb/docs/resources/build.rst @@ -100,7 +100,7 @@ Windows * The Active Template Library (ATL). * `GnuWin32 `_ for CoreUtils and Make. * `Python 3 `_. Make sure to (1) get - the x64 variant if that's what you're targetting and (2) install the debug + the x64 variant if that's what you're targeting and (2) install the debug library if you want to build a debug lldb. The standalone installer is the easiest way to get the debug library. * `Python Tools for Visual Studio diff --git a/lldb/docs/resources/contributing.rst b/lldb/docs/resources/contributing.rst index d3d467533c9ea..48fd000765f66 100644 --- a/lldb/docs/resources/contributing.rst +++ b/lldb/docs/resources/contributing.rst @@ -39,7 +39,7 @@ in a few ways. The 2 main ones are: * `Use of asserts `_: See the :ref:`section below`. -For any other contradications, consider the +For any other contradictions, consider the `golden rule `_ before choosing to update the style of existing code. diff --git a/lldb/docs/resources/debugging.rst b/lldb/docs/resources/debugging.rst index ba23759b44cf5..ee3e45a49cbde 100644 --- a/lldb/docs/resources/debugging.rst +++ b/lldb/docs/resources/debugging.rst @@ -130,7 +130,7 @@ The inferior will stop, you place the breakpoint and then ``continue``. Go back to the inferior and input the command that should trigger the breakpoint. If you are running debugger and inferior in the same window, input ``ctrl+c`` -instead of ``process interrupt`` and then folllow the rest of the steps. +instead of ``process interrupt`` and then follow the rest of the steps. If you are doing this with ``lldb-server`` and find your breakpoint is never hit, check that you are breaking in code that is actually run by @@ -187,7 +187,7 @@ predictable way, or change the prompt of one or both copies of ``lldb``. If you are debugging a scenario where the ``lldb-server`` starts in ``platform`` mode, but you want to debug the ``gdbserver`` mode you'll have to work out what subprocess it's starting for the ``gdbserver`` part. One way is to look at the -list of runninng processes and take the command line from there. +list of running processes and take the command line from there. In theory it should be possible to use LLDB's ``target.process.follow-fork-mode`` or GDB's ``follow-fork-mode`` to @@ -387,8 +387,8 @@ an issue or asking for help. This is simply inspiration. Reduction ********* -The first step is to reduce uneeded compexity where it is cheap to do so. If -something is easily removed or frozen to a cerain value, do so. The goal is to +The first step is to reduce unneeded complexity where it is cheap to do so. If +something is easily removed or frozen to a certain value, do so. The goal is to keep the failure mode the same, with fewer dependencies. This includes, but is not limited to: @@ -396,11 +396,11 @@ This includes, but is not limited to: * Removing test cases that don't crash. * Replacing dynamic lookups with constant values. * Replace supporting functions with stubs that do nothing. -* Moving the test case to less unqiue system. If your machine has an exotic +* Moving the test case to less unique system. If your machine has an exotic extension, try it on a readily available commodity machine. * Removing irrelevant parts of the test program. * Reproducing the issue without using the LLDB test runner. -* Converting a remote debuging scenario into a local one. +* Converting a remote debugging scenario into a local one. Now we hopefully have a smaller reproducer than we started with. Next we need to find out what components of the software stack might be failing. @@ -578,14 +578,14 @@ Doing it this way instead of exactly copying what LLDB does will save a few ptrace calls. The AArch64 example program shows how to do this. * The inferior contains ``BRK #0`` then ``NOP``. -* 2 4 byte instructins means 8 bytes of data to replace, which matches the +* 2 4-byte instructions means 8 bytes of data to replace, which matches the minimum size you can write with ``PTRACE_POKETEXT``. * The inferior runs to the ``BRK``, which brings us into the debugger. * The debugger reads ``PC`` and writes ``NOP`` then ``NOP`` to the location pointed to by ``PC``. * The debugger then single steps the inferior to the next instruction (this is not required in this specific scenario, you could just continue but - it is included because this more cloesly matches what ``lldb`` does). + it is included because this more closely matches what ``lldb`` does). * The debugger then continues the inferior. * The inferior exits, and the whole program exits. diff --git a/lldb/docs/resources/qemu-testing.rst b/lldb/docs/resources/qemu-testing.rst index e102f84a1d31f..8571287a04262 100644 --- a/lldb/docs/resources/qemu-testing.rst +++ b/lldb/docs/resources/qemu-testing.rst @@ -156,7 +156,7 @@ certainly not forwarded. An example of this is shown below. :: - $ lldb-server plaform --server --listen 0.0.0.0:54321 --gdbserver-port 49140 + $ lldb-server platform --server --listen 0.0.0.0:54321 --gdbserver-port 49140 The result of this is that: diff --git a/lldb/docs/use/variable.rst b/lldb/docs/use/variable.rst index 3ad71cb93c51d..22c1fd64c4a96 100644 --- a/lldb/docs/use/variable.rst +++ b/lldb/docs/use/variable.rst @@ -961,7 +961,7 @@ printed one by one. [1] The `max_children` argument is optional (since lldb 3.8.0) and indicates the maximum number of children that lldb is interested in (at this moment). If the computation of the number of children is expensive (for example, requires -travesing a linked list to determine its size) your implementation may return +traversing a linked list to determine its size) your implementation may return `max_children` rather than the actual number. If the computation is cheap (e.g., the number is stored as a field of the object), then you can always return the true number of children (that is, ignore the `max_children` argument). From lldb-commits at lists.llvm.org Tue May 13 23:34:34 2025 From: lldb-commits at lists.llvm.org (Kazu Hirata via lldb-commits) Date: Tue, 13 May 2025 23:34:34 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Fix typos in documentation (PR #139839) In-Reply-To: Message-ID: <6824397a.170a0220.8cac6.2c60@mx.google.com> https://github.com/kazutakahirata closed https://github.com/llvm/llvm-project/pull/139839 From lldb-commits at lists.llvm.org Tue May 13 23:39:25 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Tue, 13 May 2025 23:39:25 -0700 (PDT) Subject: [Lldb-commits] [lldb] Extending LLDB to work on AIX (PR #102601) In-Reply-To: Message-ID: <68243a9d.170a0220.2fe897.fe0c@mx.google.com> https://github.com/ravindra-shinde2 updated https://github.com/llvm/llvm-project/pull/102601 >From 39d395f75c306a0d932a783eef039fd93d66e246 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 7 Aug 2024 12:10:43 -0500 Subject: [PATCH 01/47] LLDB Support for AIX --- clang/lib/CodeGen/CGObjCMac.cpp | 6 +- lldb/CMakeLists.txt | 4 + lldb/cmake/modules/LLDBConfig.cmake | 2 +- lldb/include/lldb/Core/Module.h | 3 + lldb/include/lldb/Core/ModuleSpec.h | 23 +- lldb/include/lldb/Host/HostGetOpt.h | 2 +- lldb/include/lldb/Host/HostInfo.h | 3 + lldb/include/lldb/Host/HostInfoBase.h | 2 +- lldb/include/lldb/Host/XML.h | 5 + lldb/include/lldb/Host/aix/AbstractSocket.h | 25 + lldb/include/lldb/Host/aix/Host.h | 22 + lldb/include/lldb/Host/aix/HostInfoAIX.h | 42 + lldb/include/lldb/Host/aix/Ptrace.h | 62 + lldb/include/lldb/Host/aix/Support.h | 29 + lldb/include/lldb/Host/aix/Uio.h | 23 + lldb/include/lldb/Host/common/GetOptInc.h | 6 +- lldb/include/lldb/Symbol/ObjectFile.h | 5 + lldb/include/lldb/Target/ABI.h | 6 + lldb/include/lldb/Target/DynamicLoader.h | 6 + lldb/include/lldb/Target/Process.h | 14 + .../lldb/Target/RegisterContextUnwind.h | 4 + .../lldb/Target/ThreadPlanCallFunction.h | 6 + .../lldb/Utility/StringExtractorGDBRemote.h | 1 + lldb/include/lldb/lldb-private-enumerations.h | 1 + lldb/source/API/CMakeLists.txt | 108 + lldb/source/API/SBBreakpoint.cpp | 6 +- lldb/source/API/SBBreakpointLocation.cpp | 6 +- lldb/source/API/SBBreakpointName.cpp | 4 +- lldb/source/Core/DynamicLoader.cpp | 10 + lldb/source/Core/Mangled.cpp | 2 + lldb/source/Core/Module.cpp | 12 + lldb/source/Core/Section.cpp | 4 + lldb/source/Expression/DWARFExpression.cpp | 10 +- lldb/source/Host/CMakeLists.txt | 13 + lldb/source/Host/aix/AbstractSocket.cpp | 21 + lldb/source/Host/aix/Host.cpp | 304 +++ lldb/source/Host/aix/HostInfoAIX.cpp | 215 ++ lldb/source/Host/aix/Support.cpp | 44 + lldb/source/Host/common/GetOptInc.cpp | 2 +- lldb/source/Host/common/Host.cpp | 180 +- .../source/Host/common/LICENSE.aix-netbsd.txt | 125 + lldb/source/Host/common/XML.cpp | 3 + .../posix/ConnectionFileDescriptorPosix.cpp | 2 + lldb/source/Host/posix/FileSystemPosix.cpp | 2 + lldb/source/Host/posix/MainLoopPosix.cpp | 17 + .../Host/posix/ProcessLauncherPosixFork.cpp | 5 + lldb/source/Initialization/CMakeLists.txt | 2 +- .../SystemInitializerCommon.cpp | 4 +- .../Plugins/ABI/PowerPC/ABISysV_ppc64.cpp | 131 +- .../Plugins/ABI/PowerPC/ABISysV_ppc64.h | 6 + .../DynamicLoader/AIX-DYLD/CMakeLists.txt | 11 + .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 272 +++ .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 55 + .../Plugins/DynamicLoader/CMakeLists.txt | 1 + .../DynamicLoaderDarwinKernel.cpp | 4 +- .../MacOSX-DYLD/DynamicLoaderDarwin.cpp | 2 +- .../PPC64/EmulateInstructionPPC64.cpp | 196 +- .../PPC64/EmulateInstructionPPC64.h | 14 + ...nstrumentationRuntimeMainThreadChecker.cpp | 2 +- .../TSan/InstrumentationRuntimeTSan.cpp | 14 +- .../UBSan/InstrumentationRuntimeUBSan.cpp | 2 +- .../Plugins/JITLoader/GDB/JITLoaderGDB.cpp | 4 + lldb/source/Plugins/Language/ObjC/Cocoa.cpp | 2 + .../MemoryHistory/asan/MemoryHistoryASan.cpp | 2 +- .../BSD-Archive/ObjectContainerBSDArchive.cpp | 2 +- .../Big-Archive/CMakeLists.txt | 10 + .../Big-Archive/ObjectContainerBigArchive.cpp | 522 +++++ .../Big-Archive/ObjectContainerBigArchive.h | 177 ++ .../Plugins/ObjectContainer/CMakeLists.txt | 1 + lldb/source/Plugins/ObjectFile/CMakeLists.txt | 1 + .../ObjectFile/Mach-O/ObjectFileMachO.cpp | 6 +- .../Minidump/ObjectFileMinidump.cpp | 2 + .../Plugins/ObjectFile/PDB/ObjectFilePDB.cpp | 15 +- .../ObjectFile/PECOFF/ObjectFilePECOFF.cpp | 18 +- .../Plugins/ObjectFile/XCOFF/CMakeLists.txt | 13 + .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 780 +++++++ .../ObjectFile/XCOFF/ObjectFileXCOFF.h | 243 ++ .../Python/OperatingSystemPython.cpp | 2 +- .../Plugins/Platform/AIX/CMakeLists.txt | 13 + .../Plugins/Platform/AIX/PlatformAIX.cpp | 471 ++++ .../source/Plugins/Platform/AIX/PlatformAIX.h | 74 + lldb/source/Plugins/Platform/CMakeLists.txt | 1 + .../source/Plugins/Process/AIX/CMakeLists.txt | 19 + .../Plugins/Process/AIX/NativeProcessAIX.cpp | 2048 +++++++++++++++++ .../Plugins/Process/AIX/NativeProcessAIX.h | 283 +++ .../Process/AIX/NativeRegisterContextAIX.cpp | 157 ++ .../Process/AIX/NativeRegisterContextAIX.h | 133 ++ .../AIX/NativeRegisterContextAIX_ppc64.cpp | 744 ++++++ .../AIX/NativeRegisterContextAIX_ppc64.h | 138 ++ .../Plugins/Process/AIX/NativeThreadAIX.cpp | 526 +++++ .../Plugins/Process/AIX/NativeThreadAIX.h | 126 + lldb/source/Plugins/Process/CMakeLists.txt | 3 + .../Process/Utility/InferiorCallPOSIX.cpp | 33 + .../Utility/RegisterInfoPOSIX_ppc64le.cpp | 4 + .../Plugins/Process/Utility/ThreadMemory.cpp | 2 +- .../Plugins/Process/gdb-remote/CMakeLists.txt | 5 + .../GDBRemoteCommunicationClient.cpp | 30 + .../gdb-remote/GDBRemoteCommunicationClient.h | 7 + .../GDBRemoteCommunicationServerLLGS.cpp | 28 + .../GDBRemoteCommunicationServerLLGS.h | 2 + .../Process/gdb-remote/ProcessGDBRemote.cpp | 13 +- .../Process/gdb-remote/ProcessGDBRemote.h | 8 + .../Process/mach-core/ProcessMachCore.cpp | 8 +- .../ScriptInterpreter/Python/CMakeLists.txt | 5 + .../SymbolFile/DWARF/DWARFFormValue.cpp | 4 + .../Plugins/SymbolFile/DWARF/DWARFUnit.cpp | 12 +- .../MacOSX/AppleGetThreadItemInfoHandler.cpp | 2 +- lldb/source/Symbol/DWARFCallFrameInfo.cpp | 4 +- lldb/source/Target/ABI.cpp | 9 + lldb/source/Target/CMakeLists.txt | 5 + lldb/source/Target/Process.cpp | 10 + lldb/source/Target/RegisterContextUnwind.cpp | 46 + lldb/source/Target/ThreadPlanCallFunction.cpp | 34 + lldb/source/Target/UnwindLLDB.cpp | 15 + lldb/source/Utility/ArchSpec.cpp | 18 +- .../Utility/StringExtractorGDBRemote.cpp | 2 + lldb/test/CMakeLists.txt | 2 +- lldb/test/Shell/Expr/TestIRMemoryMap.test | 2 +- lldb/test/Shell/Process/TestEnvironment.test | 2 +- lldb/tools/driver/CMakeLists.txt | 5 + lldb/tools/driver/Driver.cpp | 5 +- lldb/tools/lldb-dap/CMakeLists.txt | 4 + lldb/tools/lldb-server/CMakeLists.txt | 7 + .../lldb-server/SystemInitializerLLGS.cpp | 15 + lldb/tools/lldb-server/lldb-gdbserver.cpp | 4 + lldb/unittests/Host/FileSystemTest.cpp | 2 +- lldb/unittests/Host/posix/TerminalTest.cpp | 4 + llvm/include/llvm/Object/XCOFFObjectFile.h | 4 +- llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 15 +- 129 files changed, 8950 insertions(+), 76 deletions(-) create mode 100644 lldb/include/lldb/Host/aix/AbstractSocket.h create mode 100644 lldb/include/lldb/Host/aix/Host.h create mode 100644 lldb/include/lldb/Host/aix/HostInfoAIX.h create mode 100644 lldb/include/lldb/Host/aix/Ptrace.h create mode 100644 lldb/include/lldb/Host/aix/Support.h create mode 100644 lldb/include/lldb/Host/aix/Uio.h create mode 100644 lldb/source/Host/aix/AbstractSocket.cpp create mode 100644 lldb/source/Host/aix/Host.cpp create mode 100644 lldb/source/Host/aix/HostInfoAIX.cpp create mode 100644 lldb/source/Host/aix/Support.cpp create mode 100644 lldb/source/Host/common/LICENSE.aix-netbsd.txt create mode 100644 lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt create mode 100644 lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp create mode 100644 lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h create mode 100644 lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt create mode 100644 lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp create mode 100644 lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h create mode 100644 lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt create mode 100644 lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp create mode 100644 lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h create mode 100644 lldb/source/Plugins/Platform/AIX/CMakeLists.txt create mode 100644 lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp create mode 100644 lldb/source/Plugins/Platform/AIX/PlatformAIX.h create mode 100644 lldb/source/Plugins/Process/AIX/CMakeLists.txt create mode 100644 lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeProcessAIX.h create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h create mode 100644 lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeThreadAIX.h diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index 30f3911a8b03c..fc91981db68c1 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -5052,10 +5052,14 @@ std::string CGObjCCommonMac::GetSectionName(StringRef Section, case llvm::Triple::COFF: assert(Section.starts_with("__") && "expected the name to begin with __"); return ("." + Section.substr(2) + "$B").str(); + case llvm::Triple::XCOFF: + // Hack to allow "p 10+1" on AIX for lldb + assert(Section.substr(0, 2) == "__" && + "expected the name to begin with __"); + return Section.substr(2).str(); case llvm::Triple::Wasm: case llvm::Triple::GOFF: case llvm::Triple::SPIRV: - case llvm::Triple::XCOFF: case llvm::Triple::DXContainer: llvm::report_fatal_error( "Objective-C support is unimplemented for object file format"); diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt index 59cdc4593463c..2e9ae0d0b3221 100644 --- a/lldb/CMakeLists.txt +++ b/lldb/CMakeLists.txt @@ -38,6 +38,10 @@ endif() include(LLDBConfig) include(AddLLDB) +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + add_definitions("-D__AIX__") +endif() + # Define the LLDB_CONFIGURATION_xxx matching the build type. if(uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" ) add_definitions(-DLLDB_CONFIGURATION_DEBUG) diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake index a60921990cf77..a0f118a11984c 100644 --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -299,7 +299,7 @@ endif() # Figure out if lldb could use lldb-server. If so, then we'll # ensure we build lldb-server when an lldb target is being built. -if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD|Windows") +if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD|Windows|AIX") set(LLDB_CAN_USE_LLDB_SERVER ON) else() set(LLDB_CAN_USE_LLDB_SERVER OFF) diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 5589c1c9a350d..3829386562795 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -196,6 +196,9 @@ class Module : public std::enable_shared_from_this, bool SetLoadAddress(Target &target, lldb::addr_t value, bool value_is_offset, bool &changed); + bool SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, bool &changed, int type_id); + /// \copydoc SymbolContextScope::CalculateSymbolContext(SymbolContext*) /// /// \see SymbolContextScope diff --git a/lldb/include/lldb/Core/ModuleSpec.h b/lldb/include/lldb/Core/ModuleSpec.h index 4cbbbfa8a26e1..4fe06412b6b0b 100644 --- a/lldb/include/lldb/Core/ModuleSpec.h +++ b/lldb/include/lldb/Core/ModuleSpec.h @@ -21,6 +21,7 @@ #include #include +#include namespace lldb_private { @@ -41,8 +42,26 @@ class ModuleSpec { } ModuleSpec(const FileSpec &file_spec, const ArchSpec &arch) - : m_file(file_spec), m_arch(arch), m_object_offset(0), - m_object_size(FileSystem::Instance().GetByteSize(file_spec)) {} + : m_arch(arch), m_object_offset(0) { + // parse object inside module format for example: /usr/ccs/lib/libc.a(shr_64.o) + llvm::SmallString<256> path_with_object; + file_spec.GetPath(path_with_object); + if (strstr(path_with_object.c_str(), "(") != nullptr) { + char *part; + char *str = (char *)path_with_object.c_str(); + part = strtok(str, "()"); + assert(part); + llvm::StringRef file_name(part); + part = strtok(nullptr, "()"); + assert(part); + m_object_name = ConstString(part); + m_file = FileSpec(file_name); + m_object_size = FileSystem::Instance().GetByteSize(m_file); + } else { + m_file = file_spec; + m_object_size = FileSystem::Instance().GetByteSize(file_spec); + } + } FileSpec *GetFileSpecPtr() { return (m_file ? &m_file : nullptr); } diff --git a/lldb/include/lldb/Host/HostGetOpt.h b/lldb/include/lldb/Host/HostGetOpt.h index 52cfdf4dbb89c..f450e561d6afb 100644 --- a/lldb/include/lldb/Host/HostGetOpt.h +++ b/lldb/include/lldb/Host/HostGetOpt.h @@ -9,7 +9,7 @@ #ifndef LLDB_HOST_HOSTGETOPT_H #define LLDB_HOST_HOSTGETOPT_H -#if !defined(_MSC_VER) && !defined(__NetBSD__) +#if !defined(_MSC_VER) && !defined(__NetBSD__) && !defined(__AIX__) #include #include diff --git a/lldb/include/lldb/Host/HostInfo.h b/lldb/include/lldb/Host/HostInfo.h index b7010d69d88e7..156df8cf6901d 100644 --- a/lldb/include/lldb/Host/HostInfo.h +++ b/lldb/include/lldb/Host/HostInfo.h @@ -55,6 +55,9 @@ #elif defined(__APPLE__) #include "lldb/Host/macosx/HostInfoMacOSX.h" #define HOST_INFO_TYPE HostInfoMacOSX +#elif defined(__AIX__) +#include "lldb/Host/aix/HostInfoAIX.h" +#define HOST_INFO_TYPE HostInfoAIX #else #include "lldb/Host/posix/HostInfoPosix.h" #define HOST_INFO_TYPE HostInfoPosix diff --git a/lldb/include/lldb/Host/HostInfoBase.h b/lldb/include/lldb/Host/HostInfoBase.h index 705aad559f3b7..29e6acf39bfb2 100644 --- a/lldb/include/lldb/Host/HostInfoBase.h +++ b/lldb/include/lldb/Host/HostInfoBase.h @@ -149,6 +149,7 @@ class HostInfoBase { return {}; } + static bool ComputeSharedLibraryDirectory(FileSpec &file_spec); /// Returns the distribution id of the host /// /// This will be something like "ubuntu", "fedora", etc. on Linux. @@ -158,7 +159,6 @@ class HostInfoBase { static llvm::StringRef GetDistributionId() { return llvm::StringRef(); } protected: - static bool ComputeSharedLibraryDirectory(FileSpec &file_spec); static bool ComputeSupportExeDirectory(FileSpec &file_spec); static bool ComputeProcessTempFileDirectory(FileSpec &file_spec); static bool ComputeGlobalTempFileDirectory(FileSpec &file_spec); diff --git a/lldb/include/lldb/Host/XML.h b/lldb/include/lldb/Host/XML.h index da0f9cd7aa8c0..cf359f7726d5d 100644 --- a/lldb/include/lldb/Host/XML.h +++ b/lldb/include/lldb/Host/XML.h @@ -11,6 +11,11 @@ #include "lldb/Host/Config.h" +#if defined(__AIX__) +//FIXME for AIX +#undef LLDB_ENABLE_LIBXML2 +#endif + #if LLDB_ENABLE_LIBXML2 #include #endif diff --git a/lldb/include/lldb/Host/aix/AbstractSocket.h b/lldb/include/lldb/Host/aix/AbstractSocket.h new file mode 100644 index 0000000000000..78a567a6b9095 --- /dev/null +++ b/lldb/include/lldb/Host/aix/AbstractSocket.h @@ -0,0 +1,25 @@ +//===-- AbstractSocket.h ----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_AbstractSocket_h_ +#define liblldb_AbstractSocket_h_ + +#include "lldb/Host/posix/DomainSocket.h" + +namespace lldb_private { +class AbstractSocket : public DomainSocket { +public: + AbstractSocket(bool child_processes_inherit); + +protected: + size_t GetNameOffset() const override; + void DeleteSocketFile(llvm::StringRef name) override; +}; +} + +#endif // ifndef liblldb_AbstractSocket_h_ diff --git a/lldb/include/lldb/Host/aix/Host.h b/lldb/include/lldb/Host/aix/Host.h new file mode 100644 index 0000000000000..1e3487752995f --- /dev/null +++ b/lldb/include/lldb/Host/aix/Host.h @@ -0,0 +1,22 @@ +//===-- Host.h --------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_HOST_AIX_HOST_H +#define LLDB_HOST_AIX_HOST_H + +#include "lldb/lldb-types.h" +#include + +namespace lldb_private { + +// Get PID (i.e. the primary thread ID) corresponding to the specified TID. +std::optional getPIDForTID(lldb::pid_t tid); + +} // namespace lldb_private + +#endif // #ifndef LLDB_HOST_AIX_HOST_H diff --git a/lldb/include/lldb/Host/aix/HostInfoAIX.h b/lldb/include/lldb/Host/aix/HostInfoAIX.h new file mode 100644 index 0000000000000..ced4cf34d38a8 --- /dev/null +++ b/lldb/include/lldb/Host/aix/HostInfoAIX.h @@ -0,0 +1,42 @@ +//===-- HostInfoAIX.h -----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_Host_aix_HostInfoAIX_h_ +#define lldb_Host_aix_HostInfoAIX_h_ + +#include "lldb/Host/posix/HostInfoPosix.h" +#include "lldb/Utility/FileSpec.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VersionTuple.h" + +#include + +namespace lldb_private { + +class HostInfoAIX : public HostInfoPosix { + friend class HostInfoBase; + +public: + static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr); + static void Terminate(); + + static llvm::VersionTuple GetOSVersion(); + static std::optional GetOSBuildString(); + static llvm::StringRef GetDistributionId(); + static FileSpec GetProgramFileSpec(); + +protected: + static bool ComputeSupportExeDirectory(FileSpec &file_spec); + static bool ComputeSystemPluginsDirectory(FileSpec &file_spec); + static bool ComputeUserPluginsDirectory(FileSpec &file_spec); + static void ComputeHostArchitectureSupport(ArchSpec &arch_32, + ArchSpec &arch_64); +}; +} + +#endif diff --git a/lldb/include/lldb/Host/aix/Ptrace.h b/lldb/include/lldb/Host/aix/Ptrace.h new file mode 100644 index 0000000000000..88928f18102d7 --- /dev/null +++ b/lldb/include/lldb/Host/aix/Ptrace.h @@ -0,0 +1,62 @@ +//===-- Ptrace.h ------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +// This file defines ptrace functions & structures + +#ifndef liblldb_Host_aix_Ptrace_h_ +#define liblldb_Host_aix_Ptrace_h_ + +#include + +#define DEBUG_PTRACE_MAXBYTES 20 + +// Support ptrace extensions even when compiled without required kernel support +#ifndef PTRACE_GETREGS +#define PTRACE_GETREGS (PT_COMMAND_MAX+1) +#endif +#ifndef PTRACE_SETREGS +#define PTRACE_SETREGS (PT_COMMAND_MAX+2) +#endif +#ifndef PTRACE_GETFPREGS +#define PTRACE_GETFPREGS (PT_COMMAND_MAX+3) +#endif +#ifndef PTRACE_SETFPREGS +#define PTRACE_SETFPREGS (PT_COMMAND_MAX+4) +#endif +#ifndef PTRACE_GETREGSET +#define PTRACE_GETREGSET 0x4204 +#endif +#ifndef PTRACE_SETREGSET +#define PTRACE_SETREGSET 0x4205 +#endif +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA (PT_COMMAND_MAX+5) +#endif +#ifndef PTRACE_ARCH_PRCTL +#define PTRACE_ARCH_PRCTL (PT_COMMAND_MAX+6) +#endif +#ifndef ARCH_GET_FS +#define ARCH_SET_GS 0x1001 +#define ARCH_SET_FS 0x1002 +#define ARCH_GET_FS 0x1003 +#define ARCH_GET_GS 0x1004 +#endif +#ifndef PTRACE_PEEKMTETAGS +#define PTRACE_PEEKMTETAGS (PT_COMMAND_MAX+7) +#endif +#ifndef PTRACE_POKEMTETAGS +#define PTRACE_POKEMTETAGS (PT_COMMAND_MAX+8) +#endif +#ifndef PTRACE_GETVRREGS +#define PTRACE_GETVRREGS (PT_COMMAND_MAX+9) +#endif +#ifndef PTRACE_GETVSRREGS +#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+10) +#endif + +#endif // liblldb_Host_aix_Ptrace_h_ diff --git a/lldb/include/lldb/Host/aix/Support.h b/lldb/include/lldb/Host/aix/Support.h new file mode 100644 index 0000000000000..27d6c2b50a35b --- /dev/null +++ b/lldb/include/lldb/Host/aix/Support.h @@ -0,0 +1,29 @@ +//===-- Support.h -----------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_HOST_AIX_SUPPORT_H +#define LLDB_HOST_AIX_SUPPORT_H + +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MemoryBuffer.h" +#include + +namespace lldb_private { + +llvm::ErrorOr> +getProcFile(::pid_t pid, ::pid_t tid, const llvm::Twine &file); + +llvm::ErrorOr> +getProcFile(::pid_t pid, const llvm::Twine &file); + +llvm::ErrorOr> +getProcFile(const llvm::Twine &file); + +} // namespace lldb_private + +#endif // #ifndef LLDB_HOST_AIX_SUPPORT_H diff --git a/lldb/include/lldb/Host/aix/Uio.h b/lldb/include/lldb/Host/aix/Uio.h new file mode 100644 index 0000000000000..acf79ecc6a1d0 --- /dev/null +++ b/lldb/include/lldb/Host/aix/Uio.h @@ -0,0 +1,23 @@ +//===-- Uio.h ---------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Host_aix_Uio_h_ +#define liblldb_Host_aix_Uio_h_ + +#include "lldb/Host/Config.h" +#include + +// We shall provide our own implementation of process_vm_readv if it is not +// present +#if !HAVE_PROCESS_VM_READV +ssize_t process_vm_readv(::pid_t pid, const struct iovec *local_iov, + unsigned long liovcnt, const struct iovec *remote_iov, + unsigned long riovcnt, unsigned long flags); +#endif + +#endif // liblldb_Host_aix_Uio_h_ diff --git a/lldb/include/lldb/Host/common/GetOptInc.h b/lldb/include/lldb/Host/common/GetOptInc.h index 3fb9add479541..ebb475bfaf6b8 100644 --- a/lldb/include/lldb/Host/common/GetOptInc.h +++ b/lldb/include/lldb/Host/common/GetOptInc.h @@ -11,11 +11,11 @@ #include "lldb/lldb-defines.h" -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__AIX__) #define REPLACE_GETOPT #define REPLACE_GETOPT_LONG #endif -#if defined(_MSC_VER) || defined(__NetBSD__) +#if defined(_MSC_VER) || defined(__NetBSD__) || defined(__AIX__) #define REPLACE_GETOPT_LONG_ONLY #endif @@ -35,7 +35,7 @@ struct option { int val; }; -int getopt(int argc, char *const argv[], const char *optstring); +int getopt(int argc, char *const argv[], const char *optstring) throw(); // from getopt.h extern char *optarg; diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h index 8592323322e38..bf66ccec263d2 100644 --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/lldb/include/lldb/Symbol/ObjectFile.h @@ -401,6 +401,11 @@ class ObjectFile : public std::enable_shared_from_this, return false; } + virtual bool SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) { + return false; + } + /// Gets whether endian swapping should occur when extracting data from this /// object file. /// diff --git a/lldb/include/lldb/Target/ABI.h b/lldb/include/lldb/Target/ABI.h index 7b646d743346b..281a89951ef88 100644 --- a/lldb/include/lldb/Target/ABI.h +++ b/lldb/include/lldb/Target/ABI.h @@ -47,6 +47,12 @@ class ABI : public PluginInterface { lldb::addr_t returnAddress, llvm::ArrayRef args) const = 0; + virtual bool PrepareTrivialCall(lldb_private::Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t tocAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef args) const; + // Prepare trivial call used from ThreadPlanFunctionCallUsingABI // AD: // . Because i don't want to change other ABI's this is not declared pure diff --git a/lldb/include/lldb/Target/DynamicLoader.h b/lldb/include/lldb/Target/DynamicLoader.h index 0629e2faae7e9..7dccd317c2dca 100644 --- a/lldb/include/lldb/Target/DynamicLoader.h +++ b/lldb/include/lldb/Target/DynamicLoader.h @@ -359,6 +359,12 @@ class DynamicLoader : public PluginInterface { lldb::addr_t base_addr, bool base_addr_is_offset); + virtual void UpdateLoadedSectionsByType(lldb::ModuleSP module, + lldb::addr_t link_map_addr, + lldb::addr_t base_addr, + bool base_addr_is_offset, + int type_id); + // Utility method so base classes can share implementation of // UpdateLoadedSections void UpdateLoadedSectionsCommon(lldb::ModuleSP module, lldb::addr_t base_addr, diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index cf16fbc812aa4..886ca766112c8 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -63,6 +63,10 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/VersionTuple.h" +#if defined(__AIX__) +struct ld_xinfo; +#endif + namespace lldb_private { template struct Range; @@ -1915,6 +1919,10 @@ class Process : public std::enable_shared_from_this, Status GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &range_info); +#if defined(__AIX__) + Status GetLDXINFO(struct ld_xinfo *info_ptr); +#endif + /// Obtain all the mapped memory regions within this process. /// /// \param[out] region_list @@ -2855,6 +2863,12 @@ void PruneThreadPlans(); return Status("Process::DoGetMemoryRegionInfo() not supported"); } +#if defined(__AIX__) + virtual Status DoGetLDXINFO(struct ld_xinfo *info_ptr) { + return Status("Process::DoGetLDXINFO() not supported"); + } +#endif + /// Provide an override value in the subclass for lldb's /// CPU-based logic for whether watchpoint exceptions are /// received before or after an instruction executes. diff --git a/lldb/include/lldb/Target/RegisterContextUnwind.h b/lldb/include/lldb/Target/RegisterContextUnwind.h index ef8ae88403866..00a95853800ed 100644 --- a/lldb/include/lldb/Target/RegisterContextUnwind.h +++ b/lldb/include/lldb/Target/RegisterContextUnwind.h @@ -67,6 +67,10 @@ class RegisterContextUnwind : public lldb_private::RegisterContext { bool ReadPC(lldb::addr_t &start_pc); +#ifdef __AIX__ + bool ReadLR(lldb::addr_t &lr); +#endif + // Indicates whether this frame *behaves* like frame zero -- the currently // executing frame -- or not. This can be true in the middle of the stack // above asynchronous trap handlers (sigtramp) for instance. diff --git a/lldb/include/lldb/Target/ThreadPlanCallFunction.h b/lldb/include/lldb/Target/ThreadPlanCallFunction.h index cb6e7caebb4ad..7880db1592e04 100644 --- a/lldb/include/lldb/Target/ThreadPlanCallFunction.h +++ b/lldb/include/lldb/Target/ThreadPlanCallFunction.h @@ -27,6 +27,12 @@ class ThreadPlanCallFunction : public ThreadPlan { llvm::ArrayRef args, const EvaluateExpressionOptions &options); + ThreadPlanCallFunction(Thread &thread, const Address &function, + const Address &toc, + const CompilerType &return_type, + llvm::ArrayRef args, + const EvaluateExpressionOptions &options); + ThreadPlanCallFunction(Thread &thread, const Address &function, const EvaluateExpressionOptions &options); diff --git a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h index dd468ef5bddef..9953bd6c24588 100644 --- a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h +++ b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h @@ -61,6 +61,7 @@ class StringExtractorGDBRemote : public StringExtractor { eServerPacketType_qQueryGDBServer, eServerPacketType_qKillSpawnedProcess, eServerPacketType_qLaunchSuccess, + eServerPacketType_qLDXINFO, eServerPacketType_qModuleInfo, eServerPacketType_qProcessInfoPID, eServerPacketType_qSpeedTest, diff --git a/lldb/include/lldb/lldb-private-enumerations.h b/lldb/include/lldb/lldb-private-enumerations.h index c24a3538f58da..98c1e956bf8f7 100644 --- a/lldb/include/lldb/lldb-private-enumerations.h +++ b/lldb/include/lldb/lldb-private-enumerations.h @@ -65,6 +65,7 @@ enum ArchitectureType { eArchTypeMachO, eArchTypeELF, eArchTypeCOFF, + eArchTypeXCOFF, kNumArchTypes }; diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index a32bc58507d8e..3ecdb11daef7d 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -40,6 +40,113 @@ add_custom_target(lldb-sbapi-dwarf-enums DEPENDS ${sb_languages_file}) set_target_properties(lldb-sbapi-dwarf-enums PROPERTIES FOLDER "LLDB/Tablegenning") +if(CMAKE_SYSTEM_NAME MATCHES "AIX") +add_lldb_library(liblldb STATIC ${option_framework} + SBAddress.cpp + SBAddressRange.cpp + SBAddressRangeList.cpp + SBAttachInfo.cpp + SBBlock.cpp + SBBreakpoint.cpp + SBBreakpointLocation.cpp + SBBreakpointName.cpp + SBBreakpointOptionCommon.cpp + SBBroadcaster.cpp + SBCommandInterpreter.cpp + SBCommandInterpreterRunOptions.cpp + SBCommandReturnObject.cpp + SBCommunication.cpp + SBCompileUnit.cpp + SBSaveCoreOptions.cpp + SBData.cpp + SBDebugger.cpp + SBDeclaration.cpp + SBEnvironment.cpp + SBError.cpp + SBEvent.cpp + SBExecutionContext.cpp + SBExpressionOptions.cpp + SBFileSpec.cpp + SBFile.cpp + SBFileSpecList.cpp + SBFormat.cpp + SBFrame.cpp + SBFunction.cpp + SBHostOS.cpp + SBInstruction.cpp + SBInstructionList.cpp + SBLanguageRuntime.cpp + SBLaunchInfo.cpp + SBLineEntry.cpp + SBListener.cpp + SBMemoryRegionInfo.cpp + SBMemoryRegionInfoList.cpp + SBModule.cpp + SBModuleSpec.cpp + SBPlatform.cpp + SBProcess.cpp + SBProcessInfo.cpp + SBProcessInfoList.cpp + SBQueue.cpp + SBQueueItem.cpp + SBReproducer.cpp + SBScriptObject.cpp + SBSection.cpp + SBSourceManager.cpp + SBStatisticsOptions.cpp + SBStream.cpp + SBStringList.cpp + SBStructuredData.cpp + SBSymbol.cpp + SBSymbolContext.cpp + SBSymbolContextList.cpp + SBTarget.cpp + SBThread.cpp + SBThreadCollection.cpp + SBThreadPlan.cpp + SBTrace.cpp + SBTraceCursor.cpp + SBType.cpp + SBTypeCategory.cpp + SBTypeEnumMember.cpp + SBTypeFilter.cpp + SBTypeFormat.cpp + SBTypeNameSpecifier.cpp + SBTypeSummary.cpp + SBTypeSynthetic.cpp + SBValue.cpp + SBValueList.cpp + SBVariablesOptions.cpp + SBWatchpoint.cpp + SBWatchpointOptions.cpp + SBUnixSignals.cpp + SystemInitializerFull.cpp + ${lldb_python_wrapper} + ${lldb_lua_wrapper} + + DEPENDS + lldb-sbapi-dwarf-enums + + LINK_LIBS + lldbBreakpoint + lldbCore + lldbDataFormatters + lldbExpression + lldbHost + lldbInitialization + lldbInterpreter + lldbSymbol + lldbTarget + lldbUtility + lldbVersion + ${LLDB_ALL_PLUGINS} + LINK_COMPONENTS + Support + + ${option_install_prefix} +) + +else() add_lldb_library(liblldb SHARED ${option_framework} SBAddress.cpp SBAddressRange.cpp @@ -144,6 +251,7 @@ add_lldb_library(liblldb SHARED ${option_framework} ${option_install_prefix} ) +endif() # lib/pythonX.Y/dist-packages/lldb/_lldb.so is a symlink to lib/liblldb.so, # which depends on lib/libLLVM*.so (BUILD_SHARED_LIBS) or lib/libLLVM-10git.so diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp index 3d908047f9455..728fe04d14d92 100644 --- a/lldb/source/API/SBBreakpoint.cpp +++ b/lldb/source/API/SBBreakpoint.cpp @@ -342,7 +342,7 @@ uint32_t SBBreakpoint::GetIgnoreCount() const { return count; } -void SBBreakpoint::SetThreadID(tid_t tid) { +void SBBreakpoint::SetThreadID(lldb::tid_t tid) { LLDB_INSTRUMENT_VA(this, tid); BreakpointSP bkpt_sp = GetSP(); @@ -353,10 +353,10 @@ void SBBreakpoint::SetThreadID(tid_t tid) { } } -tid_t SBBreakpoint::GetThreadID() { +lldb::tid_t SBBreakpoint::GetThreadID() { LLDB_INSTRUMENT_VA(this); - tid_t tid = LLDB_INVALID_THREAD_ID; + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; BreakpointSP bkpt_sp = GetSP(); if (bkpt_sp) { std::lock_guard guard( diff --git a/lldb/source/API/SBBreakpointLocation.cpp b/lldb/source/API/SBBreakpointLocation.cpp index 75b66364d4f1a..fad9a4076a54f 100644 --- a/lldb/source/API/SBBreakpointLocation.cpp +++ b/lldb/source/API/SBBreakpointLocation.cpp @@ -302,7 +302,7 @@ bool SBBreakpointLocation::GetCommandLineCommands(SBStringList &commands) { return has_commands; } -void SBBreakpointLocation::SetThreadID(tid_t thread_id) { +void SBBreakpointLocation::SetThreadID(lldb::tid_t thread_id) { LLDB_INSTRUMENT_VA(this, thread_id); BreakpointLocationSP loc_sp = GetSP(); @@ -313,10 +313,10 @@ void SBBreakpointLocation::SetThreadID(tid_t thread_id) { } } -tid_t SBBreakpointLocation::GetThreadID() { +lldb::tid_t SBBreakpointLocation::GetThreadID() { LLDB_INSTRUMENT_VA(this); - tid_t tid = LLDB_INVALID_THREAD_ID; + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; BreakpointLocationSP loc_sp = GetSP(); if (loc_sp) { std::lock_guard guard( diff --git a/lldb/source/API/SBBreakpointName.cpp b/lldb/source/API/SBBreakpointName.cpp index 7f63aaf6fa7d5..5c7c0a8f6504b 100644 --- a/lldb/source/API/SBBreakpointName.cpp +++ b/lldb/source/API/SBBreakpointName.cpp @@ -347,7 +347,7 @@ bool SBBreakpointName::GetAutoContinue() { return bp_name->GetOptions().IsAutoContinue(); } -void SBBreakpointName::SetThreadID(tid_t tid) { +void SBBreakpointName::SetThreadID(lldb::tid_t tid) { LLDB_INSTRUMENT_VA(this, tid); BreakpointName *bp_name = GetBreakpointName(); @@ -361,7 +361,7 @@ void SBBreakpointName::SetThreadID(tid_t tid) { UpdateName(*bp_name); } -tid_t SBBreakpointName::GetThreadID() { +lldb::tid_t SBBreakpointName::GetThreadID() { LLDB_INSTRUMENT_VA(this); BreakpointName *bp_name = GetBreakpointName(); diff --git a/lldb/source/Core/DynamicLoader.cpp b/lldb/source/Core/DynamicLoader.cpp index 7758a87403b5a..ea43a7f98b69f 100644 --- a/lldb/source/Core/DynamicLoader.cpp +++ b/lldb/source/Core/DynamicLoader.cpp @@ -113,6 +113,16 @@ void DynamicLoader::UpdateLoadedSections(ModuleSP module, addr_t link_map_addr, UpdateLoadedSectionsCommon(module, base_addr, base_addr_is_offset); } +void DynamicLoader::UpdateLoadedSectionsByType(lldb::ModuleSP module, + lldb::addr_t link_map_addr, + lldb::addr_t base_addr, + bool base_addr_is_offset, + int type_id) { + bool changed; + module->SetLoadAddressByType(m_process->GetTarget(), base_addr, base_addr_is_offset, + changed, type_id); +} + void DynamicLoader::UpdateLoadedSectionsCommon(ModuleSP module, addr_t base_addr, bool base_addr_is_offset) { diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp index 387c4fac6b0f8..43c5b043ef7a2 100644 --- a/lldb/source/Core/Mangled.cpp +++ b/lldb/source/Core/Mangled.cpp @@ -167,12 +167,14 @@ static char *GetItaniumDemangledStr(const char *M) { "Expected demangled_size to return length including trailing null"); } +#if !defined(__AIX__) if (Log *log = GetLog(LLDBLog::Demangle)) { if (demangled_cstr) LLDB_LOGF(log, "demangled itanium: %s -> \"%s\"", M, demangled_cstr); else LLDB_LOGF(log, "demangled itanium: %s -> error: failed to demangle", M); } +#endif return demangled_cstr; } diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index f9d7832254f46..044a5d29978e8 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -1510,6 +1510,18 @@ bool Module::SetLoadAddress(Target &target, lldb::addr_t value, return false; } +bool Module::SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, bool &changed, int type_id) { + ObjectFile *object_file = GetObjectFile(); + if (object_file != nullptr) { + changed = object_file->SetLoadAddressByType(target, value, value_is_offset, type_id); + return true; + } else { + changed = false; + } + return false; +} + bool Module::MatchesModuleSpec(const ModuleSpec &module_ref) { const UUID &uuid = module_ref.GetUUID(); diff --git a/lldb/source/Core/Section.cpp b/lldb/source/Core/Section.cpp index 0763e88d4608f..9ed55853930a6 100644 --- a/lldb/source/Core/Section.cpp +++ b/lldb/source/Core/Section.cpp @@ -263,6 +263,10 @@ bool Section::ResolveContainedAddress(addr_t offset, Address &so_addr, bool Section::ContainsFileAddress(addr_t vm_addr) const { const addr_t file_addr = GetFileAddress(); +#ifdef __AIX__ + if (file_addr == 0) + return false; +#endif if (file_addr != LLDB_INVALID_ADDRESS && !IsThreadSpecific()) { if (file_addr <= vm_addr) { const addr_t offset = (vm_addr - file_addr) * m_target_byte_size; diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index 444e44b392891..c1feec990f989 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -130,7 +130,7 @@ static llvm::Error ReadRegisterValueAsScalar(RegisterContext *reg_ctx, /// Return the length in bytes of the set of operands for \p op. No guarantees /// are made on the state of \p data after this call. -static offset_t GetOpcodeDataSize(const DataExtractor &data, +static lldb::offset_t GetOpcodeDataSize(const DataExtractor &data, const lldb::offset_t data_offset, const uint8_t op, const DWARFUnit *dwarf_cu) { lldb::offset_t offset = data_offset; @@ -358,7 +358,7 @@ lldb::addr_t DWARFExpression::GetLocation_DW_OP_addr(const DWARFUnit *dwarf_cu, error = true; break; } - const offset_t op_arg_size = + const lldb::offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op, dwarf_cu); if (op_arg_size == LLDB_INVALID_OFFSET) { error = true; @@ -418,7 +418,7 @@ bool DWARFExpression::Update_DW_OP_addr(const DWARFUnit *dwarf_cu, m_data.SetData(encoder.GetDataBuffer()); return true; } - const offset_t op_arg_size = + const lldb::offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op, dwarf_cu); if (op_arg_size == LLDB_INVALID_OFFSET) break; @@ -435,7 +435,7 @@ bool DWARFExpression::ContainsThreadLocalStorage( if (op == DW_OP_form_tls_address || op == DW_OP_GNU_push_tls_address) return true; - const offset_t op_arg_size = + const lldb::offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op, dwarf_cu); if (op_arg_size == LLDB_INVALID_OFFSET) return false; @@ -515,7 +515,7 @@ bool DWARFExpression::LinkThreadLocalStorage( } if (!decoded_data) { - const offset_t op_arg_size = + const lldb::offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op, dwarf_cu); if (op_arg_size == LLDB_INVALID_OFFSET) return false; diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index c2e091ee8555b..5374b16881950 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -7,6 +7,11 @@ if (APPLE AND LLVM_ENABLE_LOCAL_SUBMODULE_VISIBILITY) endif() endif() +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + macro(add_host_subdirectory group) list(APPEND HOST_SOURCES ${ARGN}) source_group(${group} FILES ${ARGN}) @@ -133,6 +138,14 @@ else() openbsd/Host.cpp openbsd/HostInfoOpenBSD.cpp ) + + elseif (CMAKE_SYSTEM_NAME MATCHES "AIX") + add_host_subdirectory(aix + aix/AbstractSocket.cpp + aix/Host.cpp + aix/HostInfoAIX.cpp + aix/Support.cpp + ) endif() endif() diff --git a/lldb/source/Host/aix/AbstractSocket.cpp b/lldb/source/Host/aix/AbstractSocket.cpp new file mode 100644 index 0000000000000..bfb67d452f7ec --- /dev/null +++ b/lldb/source/Host/aix/AbstractSocket.cpp @@ -0,0 +1,21 @@ +//===-- AbstractSocket.cpp ------------------------------------------------===// +// +// 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 "lldb/Host/aix/AbstractSocket.h" + +#include "llvm/ADT/StringRef.h" + +using namespace lldb; +using namespace lldb_private; + +AbstractSocket::AbstractSocket(bool child_processes_inherit) + : DomainSocket(ProtocolUnixAbstract, child_processes_inherit) {} + +size_t AbstractSocket::GetNameOffset() const { return 1; } + +void AbstractSocket::DeleteSocketFile(llvm::StringRef name) {} diff --git a/lldb/source/Host/aix/Host.cpp b/lldb/source/Host/aix/Host.cpp new file mode 100644 index 0000000000000..d82cb9049d389 --- /dev/null +++ b/lldb/source/Host/aix/Host.cpp @@ -0,0 +1,304 @@ +//===-- source/Host/aix/Host.cpp ----------------------------------------===// +// +// 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/ScopedPrinter.h" + +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/ProcessInfo.h" +#include "lldb/Utility/Status.h" + +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Host/aix/Host.h" +#include "lldb/Host/aix/Support.h" +#include "lldb/Utility/DataExtractor.h" +#include "llvm/BinaryFormat/XCOFF.h" + +#include +#include + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; + +namespace { +enum class ProcessState { + Unknown, + Dead, + DiskSleep, + Idle, + Paging, + Parked, + Running, + Sleeping, + TracedOrStopped, + Zombie, +}; +} + +namespace lldb_private { +class ProcessLaunchInfo; +} + +static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo, + ProcessState &State, ::pid_t &TracerPid, + ::pid_t &Tgid) { + Log *log = GetLog(LLDBLog::Host); + + auto BufferOrError = getProcFile(Pid, "status"); + if (!BufferOrError) + return false; + + llvm::StringRef Rest = BufferOrError.get()->getBuffer(); + while (!Rest.empty()) { + llvm::StringRef Line; + std::tie(Line, Rest) = Rest.split('\n'); + + if (Line.consume_front("Gid:")) { + // Real, effective, saved set, and file system GIDs. Read the first two. + Line = Line.ltrim(); + uint32_t RGid, EGid; + Line.consumeInteger(10, RGid); + Line = Line.ltrim(); + Line.consumeInteger(10, EGid); + + ProcessInfo.SetGroupID(RGid); + ProcessInfo.SetEffectiveGroupID(EGid); + } else if (Line.consume_front("Uid:")) { + // Real, effective, saved set, and file system UIDs. Read the first two. + Line = Line.ltrim(); + uint32_t RUid, EUid; + Line.consumeInteger(10, RUid); + Line = Line.ltrim(); + Line.consumeInteger(10, EUid); + + ProcessInfo.SetUserID(RUid); + ProcessInfo.SetEffectiveUserID(EUid); + } else if (Line.consume_front("PPid:")) { + ::pid_t PPid; + Line.ltrim().consumeInteger(10, PPid); + ProcessInfo.SetParentProcessID(PPid); + } else if (Line.consume_front("State:")) { + State = llvm::StringSwitch(Line.ltrim().take_front(1)) + .Case("D", ProcessState::DiskSleep) + .Case("I", ProcessState::Idle) + .Case("R", ProcessState::Running) + .Case("S", ProcessState::Sleeping) + .CaseLower("T", ProcessState::TracedOrStopped) + .Case("W", ProcessState::Paging) + .Case("P", ProcessState::Parked) + .Case("X", ProcessState::Dead) + .Case("Z", ProcessState::Zombie) + .Default(ProcessState::Unknown); + if (State == ProcessState::Unknown) { + LLDB_LOG(log, "Unknown process state {0}", Line); + } + } else if (Line.consume_front("TracerPid:")) { + Line = Line.ltrim(); + Line.consumeInteger(10, TracerPid); + } else if (Line.consume_front("Tgid:")) { + Line = Line.ltrim(); + Line.consumeInteger(10, Tgid); + } + } + return true; +} + +static bool IsDirNumeric(const char *dname) { + for (; *dname; dname++) { + if (!isdigit(*dname)) + return false; + } + return true; +} + +static void GetProcessArgs(::pid_t pid, ProcessInstanceInfo &process_info) { + auto BufferOrError = getProcFile(pid, "cmdline"); + if (!BufferOrError) + return; + std::unique_ptr Cmdline = std::move(*BufferOrError); + + llvm::StringRef Arg0, Rest; + std::tie(Arg0, Rest) = Cmdline->getBuffer().split('\0'); + process_info.SetArg0(Arg0); + while (!Rest.empty()) { + llvm::StringRef Arg; + std::tie(Arg, Rest) = Rest.split('\0'); + process_info.GetArguments().AppendArgument(Arg); + } +} + +static void GetExePathAndArch(::pid_t pid, ProcessInstanceInfo &process_info) { + Log *log = GetLog(LLDBLog::Process); + std::string ExePath(PATH_MAX, '\0'); + std::string Basename(PATH_MAX, '\0'); + struct psinfo psinfoData; + + // We can't use getProcFile here because proc/[pid]/exe is a symbolic link. + llvm::SmallString<64> ProcExe; + (llvm::Twine("/proc/") + llvm::Twine(pid) + "/cwd").toVector(ProcExe); + + ssize_t len = readlink(ProcExe.c_str(), &ExePath[0], PATH_MAX); + if (len > 0) { + ExePath.resize(len); + + //FIXME: hack to get basename + struct stat statData; + + std::ostringstream oss; + + oss << "/proc/" << std::dec << pid << "/psinfo"; + assert(stat(oss.str().c_str(), &statData) == 0); + + const int fd = open(oss.str().c_str(), O_RDONLY); + assert (fd >= 0); + + ssize_t readNum = read(fd, &psinfoData, sizeof(psinfoData)); + assert (readNum >= 0); + + close (fd); + } else { + LLDB_LOG(log, "failed to read link exe link for {0}: {1}", pid, + Status(errno, eErrorTypePOSIX)); + ExePath.resize(0); + } + + llvm::StringRef PathRef = std::string(&(psinfoData.pr_psargs[0])); + + if (!PathRef.empty()) { + process_info.GetExecutableFile().SetFile(PathRef, FileSpec::Style::native); + ArchSpec arch_spec = ArchSpec(); + arch_spec.SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX); + process_info.SetArchitecture(arch_spec); + } +} + +static void GetProcessEnviron(::pid_t pid, ProcessInstanceInfo &process_info) { + // Get the process environment. + auto BufferOrError = getProcFile(pid, "environ"); + if (!BufferOrError) + return; + + std::unique_ptr Environ = std::move(*BufferOrError); + llvm::StringRef Rest = Environ->getBuffer(); + while (!Rest.empty()) { + llvm::StringRef Var; + std::tie(Var, Rest) = Rest.split('\0'); + process_info.GetEnvironment().insert(Var); + } +} + +static bool GetProcessAndStatInfo(::pid_t pid, + ProcessInstanceInfo &process_info, + ProcessState &State, ::pid_t &tracerpid) { + ::pid_t tgid; + tracerpid = 0; + process_info.Clear(); + + process_info.SetProcessID(pid); + + GetExePathAndArch(pid, process_info); + GetProcessArgs(pid, process_info); + GetProcessEnviron(pid, process_info); + + // Get User and Group IDs and get tracer pid. + if (!GetStatusInfo(pid, process_info, State, tracerpid, tgid)) + return false; + + return true; +} + +uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { + static const char procdir[] = "/proc/"; + + DIR *dirproc = opendir(procdir); + if (dirproc) { + struct dirent *direntry = nullptr; + const uid_t our_uid = getuid(); + const lldb::pid_t our_pid = getpid(); + bool all_users = match_info.GetMatchAllUsers(); + + while ((direntry = readdir(dirproc)) != nullptr) { + /* + if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name)) + continue; + */ + + lldb::pid_t pid = atoi(direntry->d_name); + + // Skip this process. + if (pid == our_pid) + continue; + + ::pid_t tracerpid; + ProcessState State; + ProcessInstanceInfo process_info; + + if (!GetProcessAndStatInfo(pid, process_info, State, tracerpid)) + continue; + + // Skip if process is being debugged. + if (tracerpid != 0) + continue; + + if (State == ProcessState::Zombie) + continue; + + // Check for user match if we're not matching all users and not running + // as root. + if (!all_users && (our_uid != 0) && (process_info.GetUserID() != our_uid)) + continue; + + if (match_info.Matches(process_info)) { + process_infos.push_back(process_info); + } + } + + closedir(dirproc); + } + + return process_infos.size(); +} + +bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { + ::pid_t tracerpid; + ProcessState State; + return GetProcessAndStatInfo(pid, process_info, State, tracerpid); +} + +Environment Host::GetEnvironment() { return Environment(environ); } + +Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) { + return Status("unimplemented"); +} + +std::optional lldb_private::getPIDForTID(lldb::pid_t tid) { + ::pid_t tracerpid, tgid = LLDB_INVALID_PROCESS_ID; + ProcessInstanceInfo process_info; + ProcessState state; + + if (!GetStatusInfo(tid, process_info, state, tracerpid, tgid) || + tgid == LLDB_INVALID_PROCESS_ID) + return std::nullopt; + return tgid; +} diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp new file mode 100644 index 0000000000000..8bda09e01741b --- /dev/null +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -0,0 +1,215 @@ +//===-- HostInfoAIX.cpp -------------------------------------------------===// +// +// 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 "lldb/Host/aix/HostInfoAIX.h" +#include "lldb/Host/Config.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" + +#include "llvm/Support/Threading.h" + +#include +#include +#include +#include +#include + +#include +#include + +using namespace lldb_private; + +namespace { +struct HostInfoAIXFields { + llvm::once_flag m_distribution_once_flag; + std::string m_distribution_id; + llvm::once_flag m_os_version_once_flag; + llvm::VersionTuple m_os_version; +}; +} // namespace + +static HostInfoAIXFields *g_fields = nullptr; + +void HostInfoAIX::Initialize(SharedLibraryDirectoryHelper *helper) { + HostInfoPosix::Initialize(helper); + + g_fields = new HostInfoAIXFields(); +} + +void HostInfoAIX::Terminate() { + assert(g_fields && "Missing call to Initialize?"); + delete g_fields; + g_fields = nullptr; + HostInfoBase::Terminate(); +} + +llvm::VersionTuple HostInfoAIX::GetOSVersion() { + assert(g_fields && "Missing call to Initialize?"); + llvm::call_once(g_fields->m_os_version_once_flag, []() { + struct utsname un; + if (uname(&un) != 0) + return; + + llvm::StringRef release = un.release; + // The kernel release string can include a lot of stuff (e.g. + // 4.9.0-6-amd64). We're only interested in the numbered prefix. + release = release.substr(0, release.find_first_not_of("0123456789.")); + g_fields->m_os_version.tryParse(release); + }); + + return g_fields->m_os_version; +} + +std::optional HostInfoAIX::GetOSBuildString() { + struct utsname un; + ::memset(&un, 0, sizeof(utsname)); + + if (uname(&un) < 0) + return std::nullopt; + + return std::string(un.release); +} + +llvm::StringRef HostInfoAIX::GetDistributionId() { + assert(g_fields && "Missing call to Initialize?"); + // Try to run 'lbs_release -i', and use that response for the distribution + // id. + llvm::call_once(g_fields->m_distribution_once_flag, []() { + Log *log = GetLog(LLDBLog::Host); + LLDB_LOGF(log, "attempting to determine AIX distribution..."); + + // check if the lsb_release command exists at one of the following paths + const char *const exe_paths[] = {"/bin/lsb_release", + "/usr/bin/lsb_release"}; + + for (size_t exe_index = 0; + exe_index < sizeof(exe_paths) / sizeof(exe_paths[0]); ++exe_index) { + const char *const get_distribution_info_exe = exe_paths[exe_index]; + if (access(get_distribution_info_exe, F_OK)) { + // this exe doesn't exist, move on to next exe + LLDB_LOGF(log, "executable doesn't exist: %s", + get_distribution_info_exe); + continue; + } + + // execute the distribution-retrieval command, read output + std::string get_distribution_id_command(get_distribution_info_exe); + get_distribution_id_command += " -i"; + + FILE *file = popen(get_distribution_id_command.c_str(), "r"); + if (!file) { + LLDB_LOGF(log, + "failed to run command: \"%s\", cannot retrieve " + "platform information", + get_distribution_id_command.c_str()); + break; + } + + // retrieve the distribution id string. + char distribution_id[256] = {'\0'}; + if (fgets(distribution_id, sizeof(distribution_id) - 1, file) != + nullptr) { + LLDB_LOGF(log, "distribution id command returned \"%s\"", + distribution_id); + + const char *const distributor_id_key = "Distributor ID:\t"; + if (strstr(distribution_id, distributor_id_key)) { + // strip newlines + std::string id_string(distribution_id + strlen(distributor_id_key)); + id_string.erase(std::remove(id_string.begin(), id_string.end(), '\n'), + id_string.end()); + + // lower case it and convert whitespace to underscores + std::transform( + id_string.begin(), id_string.end(), id_string.begin(), + [](char ch) { return tolower(isspace(ch) ? '_' : ch); }); + + g_fields->m_distribution_id = id_string; + LLDB_LOGF(log, "distribution id set to \"%s\"", + g_fields->m_distribution_id.c_str()); + } else { + LLDB_LOGF(log, "failed to find \"%s\" field in \"%s\"", + distributor_id_key, distribution_id); + } + } else { + LLDB_LOGF(log, + "failed to retrieve distribution id, \"%s\" returned no" + " lines", + get_distribution_id_command.c_str()); + } + + // clean up the file + pclose(file); + } + }); + + return g_fields->m_distribution_id; +} + +FileSpec HostInfoAIX::GetProgramFileSpec() { + static FileSpec g_program_filespec; + + if (!g_program_filespec) { + char exe_path[PATH_MAX]; + ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); + if (len > 0) { + exe_path[len] = 0; + g_program_filespec.SetFile(exe_path, FileSpec::Style::native); + } + } + + return g_program_filespec; +} + +bool HostInfoAIX::ComputeSupportExeDirectory(FileSpec &file_spec) { + if (HostInfoPosix::ComputeSupportExeDirectory(file_spec) && + file_spec.IsAbsolute() && FileSystem::Instance().Exists(file_spec)) + return true; + file_spec.SetDirectory(GetProgramFileSpec().GetDirectory()); + return !file_spec.GetDirectory().IsEmpty(); +} + +bool HostInfoAIX::ComputeSystemPluginsDirectory(FileSpec &file_spec) { + FileSpec temp_file("/usr/" LLDB_INSTALL_LIBDIR_BASENAME "/lldb/plugins"); + FileSystem::Instance().Resolve(temp_file); + file_spec.SetDirectory(temp_file.GetPath()); + return true; +} + +bool HostInfoAIX::ComputeUserPluginsDirectory(FileSpec &file_spec) { + // XDG Base Directory Specification + // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html If + // XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb. + const char *xdg_data_home = getenv("XDG_DATA_HOME"); + if (xdg_data_home && xdg_data_home[0]) { + std::string user_plugin_dir(xdg_data_home); + user_plugin_dir += "/lldb"; + file_spec.SetDirectory(user_plugin_dir.c_str()); + } else + file_spec.SetDirectory("~/.local/share/lldb"); + return true; +} + +void HostInfoAIX::ComputeHostArchitectureSupport(ArchSpec &arch_32, + ArchSpec &arch_64) { + HostInfoPosix::ComputeHostArchitectureSupport(arch_32, arch_64); + + const char *distribution_id = GetDistributionId().data(); + + // On Linux, "unknown" in the vendor slot isn't what we want for the default + // triple. It's probably an artifact of config.guess. + if (arch_32.IsValid()) { + if (arch_32.GetTriple().getVendor() == llvm::Triple::UnknownVendor) + arch_32.GetTriple().setVendorName(llvm::StringRef()); + } + if (arch_64.IsValid()) { + if (arch_64.GetTriple().getVendor() == llvm::Triple::UnknownVendor) + arch_64.GetTriple().setVendorName(llvm::StringRef()); + } +} diff --git a/lldb/source/Host/aix/Support.cpp b/lldb/source/Host/aix/Support.cpp new file mode 100644 index 0000000000000..1bf2662190127 --- /dev/null +++ b/lldb/source/Host/aix/Support.cpp @@ -0,0 +1,44 @@ +//===-- Support.cpp -------------------------------------------------------===// +// +// 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 "lldb/Host/aix/Support.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "llvm/Support/MemoryBuffer.h" + +llvm::ErrorOr> +lldb_private::getProcFile(::pid_t pid, ::pid_t tid, const llvm::Twine &file) { + Log *log = GetLog(LLDBLog::Host); + std::string File = + ("/proc/" + llvm::Twine(pid) + "/task/" + llvm::Twine(tid) + "/" + file) + .str(); + auto Ret = llvm::MemoryBuffer::getFileAsStream(File); + if (!Ret) + LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message()); + return Ret; +} + +llvm::ErrorOr> +lldb_private::getProcFile(::pid_t pid, const llvm::Twine &file) { + Log *log = GetLog(LLDBLog::Host); + std::string File = ("/proc/" + llvm::Twine(pid) + "/" + file).str(); + auto Ret = llvm::MemoryBuffer::getFileAsStream(File); + if (!Ret) + LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message()); + return Ret; +} + +llvm::ErrorOr> +lldb_private::getProcFile(const llvm::Twine &file) { + Log *log = GetLog(LLDBLog::Host); + std::string File = ("/proc/" + file).str(); + auto Ret = llvm::MemoryBuffer::getFileAsStream(File); + if (!Ret) + LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message()); + return Ret; +} diff --git a/lldb/source/Host/common/GetOptInc.cpp b/lldb/source/Host/common/GetOptInc.cpp index c2044b6873221..e0ae2aa1774b3 100644 --- a/lldb/source/Host/common/GetOptInc.cpp +++ b/lldb/source/Host/common/GetOptInc.cpp @@ -409,7 +409,7 @@ static int getopt_internal(int nargc, char *const *nargv, const char *options, * [eventually this will replace the BSD getopt] */ #if defined(REPLACE_GETOPT) -int getopt(int nargc, char *const *nargv, const char *options) { +int getopt(int nargc, char *const *nargv, const char *options) throw() { /* * We don't pass FLAG_PERMUTE to getopt_internal() since diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index e03d36e9cad4a..2fd7111a94fb2 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -357,9 +357,183 @@ bool Host::ResolveExecutableInBundle(FileSpec &file) { return false; } #ifndef _WIN32 +#if defined(__AIX__) + +#include +extern char **p_xargv; + +/* Fix missing Dl_info & dladdr in AIX + * The code is taken from netbsd.org (src/crypto/external/bsd/openssl/dist/crypto/dso/dso_dlfcn.c) + * except strlcpy & strlcat (those are taken from openbsd.org (src/lib/libc/string)) + */ +/*- + * See IBM's AIX Version 7.2, Technical Reference: + * Base Operating System and Extensions, Volume 1 and 2 + * https://www.ibm.com/support/knowledgecenter/ssw_aix_72/com.ibm.aix.base/technicalreferences.htm + */ +#include +#include + +/* strlcpy: + * Copy string src to buffer dst of size dsize. At most dsize-1 + * chars will be copied. Always NUL terminates (unless dsize == 0). + * Returns strlen(src); if retval >= dsize, truncation occurred. + */ +size_t strlcpy(char *dst, const char *src, size_t dsize) +{ + const char *osrc = src; + size_t nleft = dsize; + + /* Copy as many bytes as will fit. */ + if (nleft != 0) { + while (--nleft != 0) { + if ((*dst++ = *src++) == '\0') { + break; + } + } + } + + /* Not enough room in dst, add NUL and traverse rest of src. */ + if (nleft == 0) { + if (dsize != 0) { + *dst = '\0'; /* NUL-terminate dst */ + } + while (*src++) { + ; + } + } + + return src - osrc - 1; /* count does not include NUL */ +} + +/* strlcat: + * Appends src to string dst of size dsize (unlike strncat, dsize is the + * full size of dst, not space left). At most dsize-1 characters + * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). + * Returns strlen(src) + MIN(dsize, strlen(initial dst)). + * If retval >= dsize, truncation occurred. + */ +size_t strlcat(char *dst, const char *src, size_t dsize) +{ + const char *odst = dst; + const char *osrc = src; + size_t n = dsize; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end. */ + while (n-- != 0 && *dst != '\0') { + dst++; + } + dlen = dst - odst; + n = dsize - dlen; + + if (n-- == 0) { + return dlen + strlen(src); + } + while (*src != '\0') { + if (n != 0) { + *dst++ = *src; + n--; + } + src++; + } + *dst = '\0'; + + return dlen + src - osrc; /* count does not include NUL */ +} + +/* ~ 64 * (sizeof(struct ld_info) + _XOPEN_PATH_MAX + _XOPEN_NAME_MAX) */ +# define DLFCN_LDINFO_SIZE 86976 +typedef struct Dl_info { + const char *dli_fname; +} Dl_info; +/* + * This dladdr()-implementation will also find the ptrgl (Pointer Glue) virtual + * address of a function, which is just located in the DATA segment instead of + * the TEXT segment. + */ +static int dladdr(const void *ptr, Dl_info *dl) +{ + uintptr_t addr = (uintptr_t)ptr; + struct ld_info *ldinfos; + struct ld_info *next_ldi; + struct ld_info *this_ldi; + + if ((ldinfos = (struct ld_info *)malloc(DLFCN_LDINFO_SIZE)) == NULL) { + dl->dli_fname = NULL; + return 0; + } + + if ((loadquery(L_GETINFO, (void *)ldinfos, DLFCN_LDINFO_SIZE)) < 0) { + /*- + * Error handling is done through errno and dlerror() reading errno: + * ENOMEM (ldinfos buffer is too small), + * EINVAL (invalid flags), + * EFAULT (invalid ldinfos ptr) + */ + free((void *)ldinfos); + dl->dli_fname = NULL; + return 0; + } + next_ldi = ldinfos; + + do { + this_ldi = next_ldi; + if (((addr >= (uintptr_t)this_ldi->ldinfo_textorg) + && (addr < ((uintptr_t)this_ldi->ldinfo_textorg + + this_ldi->ldinfo_textsize))) + || ((addr >= (uintptr_t)this_ldi->ldinfo_dataorg) + && (addr < ((uintptr_t)this_ldi->ldinfo_dataorg + + this_ldi->ldinfo_datasize)))) { + char *buffer = NULL; + char *member = NULL; + size_t buffer_sz; + size_t member_len; + + buffer_sz = strlen(this_ldi->ldinfo_filename) + 1; + member = this_ldi->ldinfo_filename + buffer_sz; + if ((member_len = strlen(member)) > 0) { + buffer_sz += 1 + member_len + 1; + } + if ((buffer = (char *)malloc(buffer_sz)) != NULL) { + strlcpy(buffer, this_ldi->ldinfo_filename, buffer_sz); + if (member_len > 0) { + /* + * Need to respect a possible member name and not just + * returning the path name in this case. See docs: + * sys/ldr.h, loadquery() and dlopen()/RTLD_MEMBER. + */ + strlcat(buffer, "(", buffer_sz); + strlcat(buffer, member, buffer_sz); + strlcat(buffer, ")", buffer_sz); + } + dl->dli_fname = buffer; + } + break; + } else { + next_ldi = (struct ld_info *)((uintptr_t)this_ldi + + this_ldi->ldinfo_next); + } + } while (this_ldi->ldinfo_next); + free((void *)ldinfos); + return dl->dli_fname != NULL; +} + +#endif + FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSpec module_filespec; #if !defined(__ANDROID__) +#ifdef __AIX__ + if (host_addr == reinterpret_cast(HostInfoBase::ComputeSharedLibraryDirectory)) { + // FIXME: AIX dladdr return "lldb" for this case + if (p_xargv[0]) { + module_filespec.SetFile(p_xargv[0], FileSpec::Style::native); + FileSystem::Instance().Resolve(module_filespec); + return module_filespec; + } + } +#endif Dl_info info; if (::dladdr(host_addr, &info)) { if (info.dli_fname) { @@ -373,12 +547,6 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { #endif -#if !defined(__linux__) -bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) { - return false; -} -#endif - struct ShellInfo { ShellInfo() : process_reaped(false) {} diff --git a/lldb/source/Host/common/LICENSE.aix-netbsd.txt b/lldb/source/Host/common/LICENSE.aix-netbsd.txt new file mode 100644 index 0000000000000..9601ab43575f9 --- /dev/null +++ b/lldb/source/Host/common/LICENSE.aix-netbsd.txt @@ -0,0 +1,125 @@ + + LICENSE ISSUES + ============== + + The OpenSSL toolkit stays under a double license, i.e. both the conditions of + the OpenSSL License and the original SSLeay license apply to the toolkit. + See below for the actual license texts. + + OpenSSL License + --------------- + +/* ==================================================================== + * Copyright (c) 1998-2019 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core at openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay at cryptsoft.com). This product includes software written by Tim + * Hudson (tjh at cryptsoft.com). + * + */ + + Original SSLeay License + ----------------------- + +/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay at cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh at cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay at cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh at cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + diff --git a/lldb/source/Host/common/XML.cpp b/lldb/source/Host/common/XML.cpp index f480ef3166a44..62cac78aaac23 100644 --- a/lldb/source/Host/common/XML.cpp +++ b/lldb/source/Host/common/XML.cpp @@ -10,6 +10,9 @@ #include "lldb/Host/XML.h" #include "llvm/ADT/StringExtras.h" +#if defined(__AIX__) +#undef LLDB_ENABLE_LIBXML2 +#endif using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index fceeff08ed9d3..143254bb12901 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -721,6 +721,7 @@ ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, ConnectionStatus ConnectionFileDescriptor::ConnectFile( llvm::StringRef s, socket_id_callback_type socket_id_callback, Status *error_ptr) { +#if !defined(__AIX__) #if LLDB_ENABLE_POSIX std::string addr_str = s.str(); // file:///PATH @@ -753,6 +754,7 @@ ConnectionStatus ConnectionFileDescriptor::ConnectFile( m_io_sp = std::make_shared(fd, File::eOpenOptionReadWrite, true); return eConnectionStatusSuccess; #endif // LLDB_ENABLE_POSIX +#endif llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX"); } diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index cdb76da626bc9..a7c50f6a3c835 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,7 +11,9 @@ // C includes #include #include +#if !defined(__AIX__) #include +#endif #include #include #include diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp index 5fe4d015251c8..e5be0db4cf19b 100644 --- a/lldb/source/Host/posix/MainLoopPosix.cpp +++ b/lldb/source/Host/posix/MainLoopPosix.cpp @@ -179,9 +179,21 @@ Status MainLoopPosix::RunImpl::Poll() { read_fds.push_back(pfd); } +#if defined(__AIX__) + sigset_t origmask; + int timeout; + + timeout = -1; + pthread_sigmask(SIG_SETMASK, &sigmask, &origmask); + int ready = poll(read_fds.data(), read_fds.size(), timeout); + pthread_sigmask(SIG_SETMASK, &origmask, nullptr); + if (ready == -1 && errno != EINTR) + return Status(errno, eErrorTypePOSIX); +#else if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 && errno != EINTR) return Status(errno, eErrorTypePOSIX); +#endif return Status(); } @@ -312,8 +324,13 @@ MainLoopPosix::RegisterSignal(int signo, const Callback &callback, // If we're using kqueue, the signal needs to be unblocked in order to // receive it. If using pselect/ppoll, we need to block it, and later unblock // it as a part of the system call. +#if defined(__AIX__) + //FIXME: where is signal unblocked? + ret = pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, &old_set); +#else ret = pthread_sigmask(HAVE_SYS_EVENT_H ? SIG_UNBLOCK : SIG_BLOCK, &new_action.sa_mask, &old_set); +#endif assert(ret == 0 && "pthread_sigmask failed"); info.was_blocked = sigismember(&old_set, signo); auto insert_ret = m_signals.insert({signo, info}); diff --git a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp index 0a832ebad13a7..cd106f605b1f4 100644 --- a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp +++ b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp @@ -193,8 +193,13 @@ struct ForkLaunchInfo { } // Start tracing this child that is about to exec. +#if !defined(__AIX__) if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1) ExitWithError(error_fd, "ptrace"); +#else + if (ptrace64(PT_TRACE_ME, 0, 0, 0, nullptr) == -1) + ExitWithError(error_fd, "ptrace"); +#endif } // Execute. We should never return... diff --git a/lldb/source/Initialization/CMakeLists.txt b/lldb/source/Initialization/CMakeLists.txt index c1a167826f76f..9f94830c8509f 100644 --- a/lldb/source/Initialization/CMakeLists.txt +++ b/lldb/source/Initialization/CMakeLists.txt @@ -1,4 +1,4 @@ -if ( CMAKE_SYSTEM_NAME MATCHES "Linux|Android|FreeBSD|NetBSD" ) +if ( CMAKE_SYSTEM_NAME MATCHES "Linux|Android|FreeBSD|NetBSD|AIX" ) list(APPEND EXTRA_PLUGINS lldbPluginProcessPOSIX) endif() diff --git a/lldb/source/Initialization/SystemInitializerCommon.cpp b/lldb/source/Initialization/SystemInitializerCommon.cpp index 1a172a95aa147..4b01442a94bac 100644 --- a/lldb/source/Initialization/SystemInitializerCommon.cpp +++ b/lldb/source/Initialization/SystemInitializerCommon.cpp @@ -19,7 +19,7 @@ #include "lldb/Version/Version.h" #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__OpenBSD__) + defined(__OpenBSD__) || defined(__AIX__) #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" #endif @@ -79,7 +79,7 @@ llvm::Error SystemInitializerCommon::Initialize() { process_gdb_remote::ProcessGDBRemoteLog::Initialize(); #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__OpenBSD__) + defined(__OpenBSD__) || defined(__AIX__) ProcessPOSIXLog::Initialize(); #endif #if defined(_WIN32) diff --git a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp index eac058701313b..feb0d7c0e09be 100644 --- a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp +++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp @@ -156,6 +156,9 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) return false; +#if defined(__AIX__) + assert(0); +#else // Read TOC pointer value. reg_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0); @@ -171,6 +174,132 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, (uint64_t)reg_value); if (!process_sp->WritePointerToMemory(sp + stack_offset, reg_value, error)) return false; +#endif + + // Read the current SP value. + reg_value = reg_ctx->ReadRegisterAsUnsigned(sp_reg_info, 0); + + // Save current SP onto the stack. + LLDB_LOGF(log, "Writing SP at SP(0x%" PRIx64 ")+0: 0x%" PRIx64, (uint64_t)sp, + (uint64_t)reg_value); + if (!process_sp->WritePointerToMemory(sp, reg_value, error)) + return false; + + // %r1 is set to the actual stack value. + LLDB_LOGF(log, "Writing SP: 0x%" PRIx64, (uint64_t)sp); + + if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_info, sp)) + return false; + + // %pc is set to the address of the called function. + + LLDB_LOGF(log, "Writing IP: 0x%" PRIx64, (uint64_t)func_addr); + + if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_info, func_addr)) + return false; + + return true; +} + +bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, + addr_t func_addr, addr_t toc_addr, + addr_t return_addr, + llvm::ArrayRef args) const { + Log *log = GetLog(LLDBLog::Expressions); + + if (log) { + StreamString s; + s.Printf("ABISysV_ppc64::PrepareTrivialCall (tid = 0x%" PRIx64 + ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 + ", return_addr = 0x%" PRIx64, + thread.GetID(), (uint64_t)sp, (uint64_t)func_addr, + (uint64_t)return_addr); + + for (size_t i = 0; i < args.size(); ++i) + s.Printf(", arg%" PRIu64 " = 0x%" PRIx64, static_cast(i + 1), + args[i]); + s.PutCString(")"); + log->PutString(s.GetString()); + } + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return false; + + const RegisterInfo *reg_info = nullptr; + + if (args.size() > 8) // TODO handle more than 8 arguments + return false; + + for (size_t i = 0; i < args.size(); ++i) { + reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_ARG1 + i); + LLDB_LOGF(log, "About to write arg%" PRIu64 " (0x%" PRIx64 ") into %s", + static_cast(i + 1), args[i], reg_info->name); + if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) + return false; + } + + // First, align the SP + + LLDB_LOGF(log, "16-byte aligning SP: 0x%" PRIx64 " to 0x%" PRIx64, + (uint64_t)sp, (uint64_t)(sp & ~0xfull)); + + sp &= ~(0xfull); // 16-byte alignment + + sp -= 544; // allocate frame to save TOC, RA and SP. + + Status error; + uint64_t reg_value; + const RegisterInfo *pc_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + const RegisterInfo *sp_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); + ProcessSP process_sp(thread.GetProcess()); + const RegisterInfo *lr_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); + const RegisterInfo *r2_reg_info = reg_ctx->GetRegisterInfoAtIndex(2); + const RegisterInfo *r12_reg_info = reg_ctx->GetRegisterInfoAtIndex(12); + + // Save return address onto the stack. + LLDB_LOGF(log, + "Pushing the return address onto the stack: 0x%" PRIx64 + "(+16): 0x%" PRIx64, + (uint64_t)sp, (uint64_t)return_addr); + if (!process_sp->WritePointerToMemory(sp + 16, return_addr, error)) + return false; + + // Write the return address to link register. + LLDB_LOGF(log, "Writing LR: 0x%" PRIx64, (uint64_t)return_addr); + if (!reg_ctx->WriteRegisterFromUnsigned(lr_reg_info, return_addr)) + return false; + + // Write target address to %r12 register. + LLDB_LOGF(log, "Writing R12: 0x%" PRIx64, (uint64_t)func_addr); + if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) + return false; + +#if defined(__AIX__) + LLDB_LOGF(log, "Writing R2: 0x%" PRIx64, (uint64_t)toc_addr); + if (!reg_ctx->WriteRegisterFromUnsigned(r2_reg_info, toc_addr)) + return false; +#else + // Read TOC pointer value. + reg_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0); + + // Write TOC pointer onto the stack. + uint64_t stack_offset; + if (GetByteOrder() == lldb::eByteOrderLittle) + stack_offset = 24; + else + stack_offset = 40; + + LLDB_LOGF(log, "Writing R2 (TOC) at SP(0x%" PRIx64 ")+%d: 0x%" PRIx64, + (uint64_t)(sp + stack_offset), (int)stack_offset, + (uint64_t)reg_value); + if (!process_sp->WritePointerToMemory(sp + stack_offset, reg_value, error)) + return false; +#endif // Read the current SP value. reg_value = reg_ctx->ReadRegisterAsUnsigned(sp_reg_info, 0); @@ -641,7 +770,7 @@ class ReturnValueExtractor { DataExtractor de(&raw_data, sizeof(raw_data), m_byte_order, m_addr_size); - offset_t offset = 0; + lldb::offset_t offset = 0; std::optional byte_size = type.GetByteSize(m_process_sp.get()); if (!byte_size) return {}; diff --git a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h index bfa96cc0df703..d752a8ded9748 100644 --- a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h +++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h @@ -23,6 +23,12 @@ class ABISysV_ppc64 : public lldb_private::RegInfoBasedABI { lldb::addr_t returnAddress, llvm::ArrayRef args) const override; + bool PrepareTrivialCall(lldb_private::Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t tocAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef args) const override; + bool GetArgumentValues(lldb_private::Thread &thread, lldb_private::ValueList &values) const override; diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt new file mode 100644 index 0000000000000..02fe0d617955a --- /dev/null +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt @@ -0,0 +1,11 @@ +add_definitions("-D_ALL_SOURCE") + +add_lldb_library(lldbPluginDynamicLoaderAIXDYLD PLUGIN + DynamicLoaderAIXDYLD.cpp + + LINK_LIBS + lldbCore + lldbTarget + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp new file mode 100644 index 0000000000000..62663974134b0 --- /dev/null +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -0,0 +1,272 @@ +//===-- DynamicLoaderAIXDYLD.cpp --------------------------------------===// +// +// 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 "DynamicLoaderAIXDYLD.h" + +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Platform.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/ThreadPlanStepInstruction.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#if defined(__AIX__) +#include +#endif + +/*#include "llvm/ADT/Triple.h" +*/ + +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(DynamicLoaderAIXDYLD) + +DynamicLoaderAIXDYLD::DynamicLoaderAIXDYLD(Process *process) + : DynamicLoader(process) {} + +DynamicLoaderAIXDYLD::~DynamicLoaderAIXDYLD() = default; + +void DynamicLoaderAIXDYLD::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); +} + +void DynamicLoaderAIXDYLD::Terminate() {} + +llvm::StringRef DynamicLoaderAIXDYLD::GetPluginDescriptionStatic() { + return "Dynamic loader plug-in that watches for shared library " + "loads/unloads in AIX processes."; +} + +DynamicLoader *DynamicLoaderAIXDYLD::CreateInstance(Process *process, + bool force) { + bool should_create = force; + if (!should_create) { + const llvm::Triple &triple_ref = + process->GetTarget().GetArchitecture().GetTriple(); + if (triple_ref.getOS() == llvm::Triple::AIX) + should_create = true; + } + + if (should_create) + return new DynamicLoaderAIXDYLD(process); + + return nullptr; +} + +void DynamicLoaderAIXDYLD::OnLoadModule(lldb::ModuleSP module_sp, + const ModuleSpec module_spec, + lldb::addr_t module_addr) { + + // Resolve the module unless we already have one. + if (!module_sp) { + Status error; + module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, + true /* notify */, &error); + if (error.Fail()) + return; + } + + m_loaded_modules[module_sp] = module_addr; + UpdateLoadedSectionsCommon(module_sp, module_addr, false); + ModuleList module_list; + module_list.Append(module_sp); + m_process->GetTarget().ModulesDidLoad(module_list); +} + +void DynamicLoaderAIXDYLD::OnUnloadModule(lldb::addr_t module_addr) { + Address resolved_addr; + if (!m_process->GetTarget().ResolveLoadAddress(module_addr, resolved_addr)) + return; + + ModuleSP module_sp = resolved_addr.GetModule(); + if (module_sp) { + m_loaded_modules.erase(module_sp); + UnloadSectionsCommon(module_sp); + ModuleList module_list; + module_list.Append(module_sp); + m_process->GetTarget().ModulesDidUnload(module_list, false); + } +} + +lldb::addr_t DynamicLoaderAIXDYLD::GetLoadAddress(ModuleSP executable) { + // First, see if the load address is already cached. + auto it = m_loaded_modules.find(executable); + if (it != m_loaded_modules.end() && it->second != LLDB_INVALID_ADDRESS) + return it->second; + + lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; + + // Second, try to get it through the process plugins. For a remote process, + // the remote platform will be responsible for providing it. + FileSpec file_spec(executable->GetPlatformFileSpec()); + bool is_loaded = false; + Status status = + m_process->GetFileLoadAddress(file_spec, is_loaded, load_addr); + // Servers other than lldb server could respond with a bogus address. + if (status.Success() && is_loaded && load_addr != LLDB_INVALID_ADDRESS) { + m_loaded_modules[executable] = load_addr; + return load_addr; + } + + //// Hack to try set breakpoint + //Breakpoint *dyld_break = m_process->GetTarget().CreateBreakpoint(0x100000638, true, false).get(); + //dyld_break->SetCallback(DynamicLoaderAIXDYLD::NotifyBreakpointHit, this, true); + //dyld_break->SetBreakpointKind("hack-debug"); + + return LLDB_INVALID_ADDRESS; +} + +bool DynamicLoaderAIXDYLD::NotifyBreakpointHit( + void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, + lldb::user_id_t break_loc_id) { +} + +void DynamicLoaderAIXDYLD::DidAttach() { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); + + ModuleSP executable = GetTargetExecutable(); + + if (!executable.get()) + return; + + // Try to fetch the load address of the file from the process, since there + // could be randomization of the load address. + lldb::addr_t load_addr = GetLoadAddress(executable); + if (load_addr == LLDB_INVALID_ADDRESS) + return; + + // Request the process base address. + lldb::addr_t image_base = m_process->GetImageInfoAddress(); + if (image_base == load_addr) + return; + + // Rebase the process's modules if there is a mismatch. + UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_addr, false); + + ModuleList module_list; + module_list.Append(executable); + m_process->GetTarget().ModulesDidLoad(module_list); + auto error = m_process->LoadModules(); + LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}"); + +#if defined(__AIX__) + // Get struct ld_xinfo (FIXME) + struct ld_xinfo ldinfo[64]; + Status status = m_process->GetLDXINFO(&(ldinfo[0])); + if (status.Fail()) { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOG(log, "LDXINFO failed: {0}", status); + return; + } + struct ld_xinfo *ptr = &(ldinfo[0]); + bool skip_current = true; + while (ptr != nullptr) { + char *pathName = (char *)ptr + ptr->ldinfo_filename; + char *memberName = pathName + (strlen(pathName) + 1); + if (!skip_current) { + // FIXME: buffer size + char pathWithMember[128] = {0}; + if (strlen(memberName) > 0) { + sprintf(pathWithMember, "%s(%s)", pathName, memberName); + } else { + sprintf(pathWithMember, "%s", pathName); + } + FileSpec file(pathWithMember); + ModuleSpec module_spec(file, m_process->GetTarget().GetArchitecture()); + if (ModuleSP module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, true /* notify */)) { + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_textorg, false, 1); + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_dataorg, false, 2); + // FIXME: .tdata, .bss + } + } else { + skip_current = false; + } + if (ptr->ldinfo_next == 0) { + ptr = nullptr; + } else { + ptr = (struct ld_xinfo *)((char *)ptr + ptr->ldinfo_next); + } + } +#endif +} + +void DynamicLoaderAIXDYLD::DidLaunch() { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); + + ModuleSP executable = GetTargetExecutable(); + if (!executable.get()) + return; + + lldb::addr_t load_addr = GetLoadAddress(executable); + if (load_addr != LLDB_INVALID_ADDRESS) { + // Update the loaded sections so that the breakpoints can be resolved. + UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_addr, false); + + ModuleList module_list; + module_list.Append(executable); + m_process->GetTarget().ModulesDidLoad(module_list); + auto error = m_process->LoadModules(); + LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}"); + } + +#if defined(__AIX__) + // Get struct ld_xinfo (FIXME) + struct ld_xinfo ldinfo[64]; + Status status = m_process->GetLDXINFO(&(ldinfo[0])); + if (status.Fail()) { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOG(log, "LDXINFO failed: {0}", status); + return; + } + struct ld_xinfo *ptr = &(ldinfo[0]); + bool skip_current = true; + while (ptr != nullptr) { + char *pathName = (char *)ptr + ptr->ldinfo_filename; + char *memberName = pathName + (strlen(pathName) + 1); + if (!skip_current) { + // FIXME: buffer size + char pathWithMember[128] = {0}; + if (strlen(memberName) > 0) { + sprintf(pathWithMember, "%s(%s)", pathName, memberName); + } else { + sprintf(pathWithMember, "%s", pathName); + } + FileSpec file(pathWithMember); + ModuleSpec module_spec(file, m_process->GetTarget().GetArchitecture()); + if (ModuleSP module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, true /* notify */)) { + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_textorg, false, 1); + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_dataorg, false, 2); + // FIXME: .tdata, .bss + } + } else { + skip_current = false; + } + if (ptr->ldinfo_next == 0) { + ptr = nullptr; + } else { + ptr = (struct ld_xinfo *)((char *)ptr + ptr->ldinfo_next); + } + } +#endif +} + +Status DynamicLoaderAIXDYLD::CanLoadImage() { return Status(); } + +ThreadPlanSP +DynamicLoaderAIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, + bool stop) { + //FIXME + return ThreadPlanSP(); +} diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h new file mode 100644 index 0000000000000..ae4b7aca66dcc --- /dev/null +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -0,0 +1,55 @@ +//===-- DynamicLoaderAIXDYLD.h ------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_DYNAMICLOADER_AIX_DYLD_DYNAMICLOADERAIXDYLD_H +#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_AIX_DYLD_DYNAMICLOADERAIXDYLD_H + +#include "lldb/Target/DynamicLoader.h" +#include "lldb/lldb-forward.h" + +#include + +namespace lldb_private { + +class DynamicLoaderAIXDYLD : public DynamicLoader { +public: + DynamicLoaderAIXDYLD(Process *process); + + ~DynamicLoaderAIXDYLD() override; + + static void Initialize(); + static void Terminate(); + static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; } + static llvm::StringRef GetPluginDescriptionStatic(); + + static DynamicLoader *CreateInstance(Process *process, bool force); + + void OnLoadModule(lldb::ModuleSP module_sp, const ModuleSpec module_spec, + lldb::addr_t module_addr); + void OnUnloadModule(lldb::addr_t module_addr); + + void DidAttach() override; + void DidLaunch() override; + Status CanLoadImage() override; + lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread, + bool stop) override; + + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + static bool NotifyBreakpointHit(void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id); + +protected: + lldb::addr_t GetLoadAddress(lldb::ModuleSP executable); + +private: + std::map m_loaded_modules; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_AIX_DYLD_DYNAMICLOADERWAIXDYLD_H diff --git a/lldb/source/Plugins/DynamicLoader/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/CMakeLists.txt index 30607159acdc0..4f3fb693faae1 100644 --- a/lldb/source/Plugins/DynamicLoader/CMakeLists.txt +++ b/lldb/source/Plugins/DynamicLoader/CMakeLists.txt @@ -5,4 +5,5 @@ add_subdirectory(POSIX-DYLD) add_subdirectory(Static) add_subdirectory(Hexagon-DYLD) add_subdirectory(Windows-DYLD) +add_subdirectory(AIX-DYLD) add_subdirectory(wasm-DYLD) diff --git a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp index 20e5652c65bf8..26abea0fdd24d 100644 --- a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp +++ b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp @@ -256,7 +256,7 @@ DynamicLoaderDarwinKernel::SearchForKernelWithDebugHints(Process *process) { if (process->ReadMemoryFromInferior (kernel_addresses_64[i], uval, 8, read_err) == 8) { DataExtractor data (&uval, 8, process->GetByteOrder(), process->GetAddressByteSize()); - offset_t offset = 0; + lldb::offset_t offset = 0; uint64_t addr = data.GetU64 (&offset); if (CheckForKernelImageAtAddress(addr, process).IsValid()) { return addr; @@ -270,7 +270,7 @@ DynamicLoaderDarwinKernel::SearchForKernelWithDebugHints(Process *process) { if (process->ReadMemoryFromInferior (kernel_addresses_32[i], uval, 4, read_err) == 4) { DataExtractor data (&uval, 4, process->GetByteOrder(), process->GetAddressByteSize()); - offset_t offset = 0; + lldb::offset_t offset = 0; uint32_t addr = data.GetU32 (&offset); if (CheckForKernelImageAtAddress(addr, process).IsValid()) { return addr; diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp index 3863b6b3520db..624848dee6ec3 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp @@ -1151,7 +1151,7 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp, // TLS data for the pthread_key on a specific thread yet. If we have we // can re-use it since its location will not change unless the process // execs. - const tid_t tid = thread_sp->GetID(); + const lldb::tid_t tid = thread_sp->GetID(); auto tid_pos = m_tid_to_tls_map.find(tid); if (tid_pos != m_tid_to_tls_map.end()) { auto tls_pos = tid_pos->second.find(key); diff --git a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp index 3035c51341778..d14ae2daeb47d 100644 --- a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp +++ b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp @@ -146,7 +146,25 @@ EmulateInstructionPPC64::GetOpcodeForInstruction(uint32_t opcode) { {0xfc000000, 0x38000000, &EmulateInstructionPPC64::EmulateADDI, "addi RT, RA, SI"}, {0xfc000003, 0xe8000000, &EmulateInstructionPPC64::EmulateLD, - "ld RT, DS(RA)"}}; + "ld RT, DS(RA)"}, +// {0xffff0003, 0x40820000, &EmulateInstructionPPC64::EmulateBNE, +// "bne TARGET"}, + {0xfc000002, 0x48000000, &EmulateInstructionPPC64::EmulateB, + "b TARGET"}, + {0xfc000003, 0x48000002, &EmulateInstructionPPC64::EmulateBA, + "ba TARGET"}, + {0xfc000003, 0x48000003, &EmulateInstructionPPC64::EmulateBLA, + "bla TARGET"}, + {0xfc000002, 0x40000000, &EmulateInstructionPPC64::EmulateBC, + "bc BO,BI,TARGET"}, + {0xfc000002, 0x40000002, &EmulateInstructionPPC64::EmulateBCA, + "bca BO,BI,TARGET"}, + {0xfc0007fe, 0x4c000020, &EmulateInstructionPPC64::EmulateBCLR, + "bclr BO,BI,BH"}, + {0xfc0007fe, 0x4c000420, &EmulateInstructionPPC64::EmulateBCCTR, + "bcctr BO,BI,BH"}, + {0xfc0007fe, 0x4c000460, &EmulateInstructionPPC64::EmulateBCTAR, + "bctar BO,BI,BH"}}; static const size_t k_num_ppc_opcodes = std::size(g_opcodes); for (size_t i = 0; i < k_num_ppc_opcodes; ++i) { @@ -169,12 +187,13 @@ bool EmulateInstructionPPC64::EvaluateInstruction(uint32_t evaluate_options) { bool success = false; - uint32_t orig_pc_value = 0; + uint64_t orig_pc_value = 0; if (auto_advance_pc) { orig_pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); if (!success) return false; + LLDB_LOG(GetLog(LLDBLog::Unwind), "orig_pc_value:{0}", orig_pc_value); } // Call the Emulate... function. @@ -183,11 +202,13 @@ bool EmulateInstructionPPC64::EvaluateInstruction(uint32_t evaluate_options) { return false; if (auto_advance_pc) { - uint32_t new_pc_value = + uint64_t new_pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); if (!success) return false; + LLDB_LOG(GetLog(LLDBLog::Unwind), "new_pc_value:{0}", new_pc_value); + if (new_pc_value == orig_pc_value) { EmulateInstruction::Context context; context.type = eContextAdvancePC; @@ -389,5 +410,174 @@ bool EmulateInstructionPPC64::EmulateADDI(uint32_t opcode) { return false; WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_r1_ppc64le, r1 + si_val); LLDB_LOG(log, "EmulateADDI: success!"); + + // FIX the next-pc + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + + return true; +} + +bool EmulateInstructionPPC64::EmulateBC(uint32_t opcode) { + // FIXME:32bit M + uint32_t M = 0; + uint32_t target32 = Bits32(opcode, 15, 2) << 2; + uint64_t target = (uint64_t)target32 + ((target32 & 0x8000) ? 0xffffffffffff0000UL : 0); + uint32_t BO = Bits32(opcode, 25, 21); + bool success; + uint64_t ctr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success); + if ((~BO) & (1U << 2)) + ctr_value = ctr_value - 1; + bool ctr_ok = (bool)(BO & (1U << 2)) | ((bool)(ctr_value != 0) ^ (bool)(BO & (1U << 1))); + uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success); + uint32_t BI = Bits32(opcode, 20, 16); + bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U)); + + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + if (ctr_ok & cond_ok) + next_pc = pc_value + target; + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + Log *log = GetLog(LLDBLog::Unwind); + LLDB_LOG(log, "EmulateBC: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBCA(uint32_t opcode) { + // FIXME:32bit M + uint32_t M = 0; + uint32_t target32 = Bits32(opcode, 15, 2) << 2; + uint64_t target = (uint64_t)target32 + ((target32 & 0x8000) ? 0xffffffffffff0000UL : 0); + uint32_t BO = Bits32(opcode, 25, 21); + bool success; + uint64_t ctr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success); + if ((~BO) & (1U << 2)) + ctr_value = ctr_value - 1; + bool ctr_ok = (bool)(BO & (1U << 2)) | ((bool)(ctr_value != 0) ^ (bool)(BO & (1U << 1))); + uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success); + uint32_t BI = Bits32(opcode, 20, 16); + bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U)); + + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + if (ctr_ok & cond_ok) + next_pc = target; + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + Log *log = GetLog(LLDBLog::Unwind); + LLDB_LOG(log, "EmulateBCA: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBCLR(uint32_t opcode) { + // FIXME:32bit M + uint32_t M = 0; + uint32_t BO = Bits32(opcode, 25, 21); + bool success; + uint64_t ctr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success); + if ((~BO) & (1U << 2)) + ctr_value = ctr_value - 1; + bool ctr_ok = (bool)(BO & (1U << 2)) | ((bool)(ctr_value != 0) ^ (bool)(BO & (1U << 1))); + uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success); + uint32_t BI = Bits32(opcode, 20, 16); + bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U)); + + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + if (ctr_ok & cond_ok) { + next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success); + next_pc &= ~((1UL << 2) - 1); + } + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + Log *log = GetLog(LLDBLog::Unwind); + LLDB_LOG(log, "EmulateBCLR: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBCCTR(uint32_t opcode) { + // FIXME:32bit M + uint32_t M = 0; + uint32_t BO = Bits32(opcode, 25, 21); + bool success; + uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success); + uint32_t BI = Bits32(opcode, 20, 16); + bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U)); + + Log *log = GetLog(LLDBLog::Unwind); + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + if (cond_ok) { + next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success); + next_pc &= ~((1UL << 2) - 1); + if (next_pc < 0x4000000) { + LLDB_LOGF(log, "EmulateBCCTR: next address %lx out of range, emulate by goto LR!"); + next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success); + } + } + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + LLDB_LOG(log, "EmulateBCCTR: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBCTAR(uint32_t opcode) { + // Not supported yet. + LLDB_LOG(GetLog(LLDBLog::Unwind), "EmulateBCTAR: not supported!"); + assert(0); + return false; +} + +bool EmulateInstructionPPC64::EmulateB(uint32_t opcode) { + uint32_t target32 = Bits32(opcode, 25, 2) << 2; + uint64_t target = (uint64_t)target32 + ((target32 & 0x2000000) ? 0xfffffffffc000000UL : 0); + + bool success; + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + target; + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + Log *log = GetLog(LLDBLog::Unwind); + LLDB_LOG(log, "EmulateB: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBA(uint32_t opcode) { + Log *log = GetLog(LLDBLog::Unwind); + + bool success; + uint64_t next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success); + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + LLDB_LOG(log, "EmulateBA: emulate by branch to lr!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBLA(uint32_t opcode) { + Log *log = GetLog(LLDBLog::Unwind); + + bool success; + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + LLDB_LOG(log, "EmulateBLA: emulate by branch to lr!"); return true; } diff --git a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h index a9424f16b0ad0..1576c9700e557 100644 --- a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h +++ b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h @@ -39,6 +39,12 @@ class EmulateInstructionPPC64 : public EmulateInstruction { return true; case eInstructionTypePCModifying: +#if defined(__AIX__) + return true; +#else + return false; +#endif + case eInstructionTypeAll: return false; } @@ -84,6 +90,14 @@ class EmulateInstructionPPC64 : public EmulateInstruction { bool EmulateSTD(uint32_t opcode); bool EmulateOR(uint32_t opcode); bool EmulateADDI(uint32_t opcode); + bool EmulateB(uint32_t opcode); + bool EmulateBA(uint32_t opcode); + bool EmulateBLA(uint32_t opcode); + bool EmulateBC(uint32_t opcode); + bool EmulateBCA(uint32_t opcode); + bool EmulateBCLR(uint32_t opcode); + bool EmulateBCCTR(uint32_t opcode); + bool EmulateBCTAR(uint32_t opcode); }; } // namespace lldb_private diff --git a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp index b7cd2b1ac6bf6..876e74056face 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp @@ -261,7 +261,7 @@ InstrumentationRuntimeMainThreadChecker::GetBacktracesFromExtendedStopInfo( StructuredData::ObjectSP thread_id_obj = info->GetObjectForDotSeparatedPath("tid"); - tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; + lldb::tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; // We gather symbolication addresses above, so no need for HistoryThread to // try to infer the call addresses. diff --git a/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp b/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp index b2781aa5e7db1..7a827a3ea76f9 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp @@ -770,13 +770,13 @@ std::string InstrumentationRuntimeTSan::GetLocationDescription( Sprintf("Location is a %ld-byte heap object at 0x%llx", size, addr); } } else if (type == "stack") { - tid_t tid = loc->GetAsDictionary() + lldb::tid_t tid = loc->GetAsDictionary() ->GetValueForKey("thread_id") ->GetUnsignedIntegerValue(); result = Sprintf("Location is stack of thread %d", tid); } else if (type == "tls") { - tid_t tid = loc->GetAsDictionary() + lldb::tid_t tid = loc->GetAsDictionary() ->GetValueForKey("thread_id") ->GetUnsignedIntegerValue(); @@ -948,7 +948,7 @@ static std::string GenerateThreadName(const std::string &path, if (path == "mops") { size_t size = o->GetObjectForDotSeparatedPath("size")->GetUnsignedIntegerValue(); - tid_t thread_id = + lldb::tid_t thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); bool is_write = o->GetObjectForDotSeparatedPath("is_write")->GetBooleanValue(); @@ -979,7 +979,7 @@ static std::string GenerateThreadName(const std::string &path, } if (path == "threads") { - tid_t thread_id = + lldb::tid_t thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); result = Sprintf("Thread %zu created", thread_id); } @@ -987,7 +987,7 @@ static std::string GenerateThreadName(const std::string &path, if (path == "locs") { std::string type = std::string( o->GetAsDictionary()->GetValueForKey("type")->GetStringValue()); - tid_t thread_id = + lldb::tid_t thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); int fd = o->GetObjectForDotSeparatedPath("file_descriptor") ->GetSignedIntegerValue(); @@ -1007,7 +1007,7 @@ static std::string GenerateThreadName(const std::string &path, } if (path == "stacks") { - tid_t thread_id = + lldb::tid_t thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); result = Sprintf("Thread %" PRIu64, thread_id); } @@ -1034,7 +1034,7 @@ static void AddThreadsForPath(const std::string &path, StructuredData::ObjectSP thread_id_obj = o->GetObjectForDotSeparatedPath("thread_os_id"); - tid_t tid = + lldb::tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; ThreadSP new_thread_sp = diff --git a/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp index 1c58922e8d36c..de9719ad4a89e 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp @@ -321,7 +321,7 @@ InstrumentationRuntimeUBSan::GetBacktracesFromExtendedStopInfo( StructuredData::ObjectSP thread_id_obj = info->GetObjectForDotSeparatedPath("tid"); - tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; + lldb::tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; // We gather symbolication addresses above, so no need for HistoryThread to // try to infer the call addresses. diff --git a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp index 1688fb27430a7..690fb0d60a09a 100644 --- a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp +++ b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp @@ -194,6 +194,10 @@ void JITLoaderGDB::SetJITBreakpoint(lldb_private::ModuleList &module_list) { if (jit_addr == LLDB_INVALID_ADDRESS) return; +#if defined(__AIX__) + return; +#endif + m_jit_descriptor_addr = GetSymbolAddress( module_list, ConstString("__jit_debug_descriptor"), eSymbolTypeData); if (m_jit_descriptor_addr == LLDB_INVALID_ADDRESS) { diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index 341923108e321..fb5bc2c58e6fb 100644 --- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -1227,6 +1227,7 @@ bool lldb_private::formatters::ObjCSELSummaryProvider( time_t lldb_private::formatters::GetOSXEpoch() { static time_t epoch = 0; if (!epoch) { +#if !defined(__AIX__) #ifndef _WIN32 tzset(); tm tm_epoch; @@ -1240,6 +1241,7 @@ time_t lldb_private::formatters::GetOSXEpoch() { tm_epoch.tm_gmtoff = 0; tm_epoch.tm_zone = nullptr; epoch = timegm(&tm_epoch); +#endif #endif } return epoch; diff --git a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp index 6efd2516578ff..fe6c5a0544be3 100644 --- a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp +++ b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp @@ -107,7 +107,7 @@ static void CreateHistoryThreadFromValueObject(ProcessSP process_sp, return; int count = count_sp->GetValueAsUnsigned(0); - tid_t tid = tid_sp->GetValueAsUnsigned(0) + 1; + lldb::tid_t tid = tid_sp->GetValueAsUnsigned(0) + 1; if (count <= 0) return; diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 7aa5b8d81890a..5ea55772c3aba 100644 --- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -8,7 +8,7 @@ #include "ObjectContainerBSDArchive.h" -#if defined(_WIN32) || defined(__ANDROID__) +#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__) // Defines from ar, missing on Windows #define SARMAG 8 #define ARFMAG "`\n" diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt b/lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt new file mode 100644 index 0000000000000..612a36265b536 --- /dev/null +++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt @@ -0,0 +1,10 @@ +add_lldb_library(lldbPluginObjectContainerBigArchive PLUGIN + ObjectContainerBigArchive.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp new file mode 100644 index 0000000000000..050ad73f1d19a --- /dev/null +++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp @@ -0,0 +1,522 @@ +//===-- ObjectContainerBigArchive.cpp -------------------------------------===// +// +// 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 "ObjectContainerBigArchive.h" + +#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__) +// Defines from ar, missing on Windows +#define ARMAG "!\n" +#define SARMAG 8 +#define ARFMAG "`\n" + +typedef struct ar_hdr { + char ar_name[16]; + char ar_date[12]; + char ar_uid[6], ar_gid[6]; + char ar_mode[8]; + char ar_size[10]; + char ar_fmag[2]; +} ar_hdr; +#else +#include +#endif + +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/Timer.h" + +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Object/Archive.h" +#include "llvm/Support/Chrono.h" + +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ObjectContainerBigArchive) + +ObjectContainerBigArchive::Object::Object() : ar_name() {} + +void ObjectContainerBigArchive::Object::Clear() { + ar_name.Clear(); + modification_time = 0; + uid = 0; + gid = 0; + mode = 0; + size = 0; + file_offset = 0; + file_size = 0; +} + +lldb::offset_t +ObjectContainerBigArchive::Object::Extract(const DataExtractor &data, + lldb::offset_t offset) { + size_t ar_name_len = 0; + std::string str; + char *err; + + // File header + // + // The common format is as follows. + // + // Offset Length Name Format + // 0 16 File name ASCII right padded with spaces (no spaces + // allowed in file name) + // 16 12 File mod Decimal as cstring right padded with + // spaces + // 28 6 Owner ID Decimal as cstring right padded with + // spaces + // 34 6 Group ID Decimal as cstring right padded with + // spaces + // 40 8 File mode Octal as cstring right padded with + // spaces + // 48 10 File byte size Decimal as cstring right padded with + // spaces + // 58 2 File magic 0x60 0x0A + + // Make sure there is enough data for the file header and bail if not + if (!data.ValidOffsetForDataOfSize(offset, 60)) + return LLDB_INVALID_OFFSET; + + str.assign((const char *)data.GetData(&offset, 16), 16); + if (llvm::StringRef(str).starts_with("#1/")) { + // If the name is longer than 16 bytes, or contains an embedded space then + // it will use this format where the length of the name is here and the + // name characters are after this header. + ar_name_len = strtoul(str.c_str() + 3, &err, 10); + } else { + // Strip off any trailing spaces. + const size_t last_pos = str.find_last_not_of(' '); + if (last_pos != std::string::npos) { + if (last_pos + 1 < 16) + str.erase(last_pos + 1); + } + ar_name.SetCString(str.c_str()); + } + + str.assign((const char *)data.GetData(&offset, 12), 12); + modification_time = strtoul(str.c_str(), &err, 10); + + str.assign((const char *)data.GetData(&offset, 6), 6); + uid = strtoul(str.c_str(), &err, 10); + + str.assign((const char *)data.GetData(&offset, 6), 6); + gid = strtoul(str.c_str(), &err, 10); + + str.assign((const char *)data.GetData(&offset, 8), 8); + mode = strtoul(str.c_str(), &err, 8); + + str.assign((const char *)data.GetData(&offset, 10), 10); + size = strtoul(str.c_str(), &err, 10); + + str.assign((const char *)data.GetData(&offset, 2), 2); + if (str == ARFMAG) { + if (ar_name_len > 0) { + const void *ar_name_ptr = data.GetData(&offset, ar_name_len); + // Make sure there was enough data for the string value and bail if not + if (ar_name_ptr == nullptr) + return LLDB_INVALID_OFFSET; + str.assign((const char *)ar_name_ptr, ar_name_len); + ar_name.SetCString(str.c_str()); + } + file_offset = offset; + file_size = size - ar_name_len; + return offset; + } + return LLDB_INVALID_OFFSET; +} + +ObjectContainerBigArchive::Archive::Archive(const lldb_private::ArchSpec &arch, + const llvm::sys::TimePoint<> &time, + lldb::offset_t file_offset, + lldb_private::DataExtractor &data) + : m_arch(arch), m_modification_time(time), m_file_offset(file_offset), + m_objects(), m_data(data) {} + +ObjectContainerBigArchive::Archive::~Archive() = default; + +size_t ObjectContainerBigArchive::Archive::ParseObjects() { + DataExtractor &data = m_data; + std::string str; + lldb::offset_t offset = 0; + str.assign((const char *)data.GetData(&offset, (sizeof(llvm::object::BigArchiveMagic) - 1)), + (sizeof(llvm::object::BigArchiveMagic) - 1)); + if (str == llvm::object::BigArchiveMagic) { + llvm::Error err = llvm::Error::success(); + llvm::object::BigArchive bigAr(llvm::MemoryBufferRef(toStringRef(m_data.GetData()), llvm::StringRef("")), err); + if (err) + return 0; + + for (const llvm::object::Archive::Child &child : bigAr.children(err)) { + if (err) + continue; + if (!child.getParent()) + continue; + Object obj; + obj.Clear(); + // FIXME: check errors + llvm::Expected childNameOrErr = child.getName(); + if (!childNameOrErr) + continue; + obj.ar_name.SetCString(childNameOrErr->str().c_str()); + llvm::Expected> lastModifiedOrErr = child.getLastModified(); + if (!lastModifiedOrErr) + continue; + obj.modification_time = (uint32_t)llvm::sys::toTimeT(*(lastModifiedOrErr)); + llvm::Expected getUIDOrErr = child.getUID(); + if (!getUIDOrErr) + continue; + obj.uid = (uint16_t)*getUIDOrErr; + llvm::Expected getGIDOrErr = child.getGID(); + if (!getGIDOrErr) + continue; + obj.gid = (uint16_t)*getGIDOrErr; + llvm::Expected getAccessModeOrErr = child.getAccessMode(); + if (!getAccessModeOrErr) + continue; + obj.mode = (uint16_t)*getAccessModeOrErr; + llvm::Expected getRawSizeOrErr = child.getRawSize(); + if (!getRawSizeOrErr) + continue; + obj.size = (uint32_t)*getRawSizeOrErr; + + obj.file_offset = (lldb::offset_t)child.getDataOffset(); + + llvm::Expected getSizeOrErr = child.getSize(); + if (!getSizeOrErr) + continue; + obj.file_size = (lldb::offset_t)*getSizeOrErr; + + size_t obj_idx = m_objects.size(); + m_objects.push_back(obj); + // Insert all of the C strings out of order for now... + m_object_name_to_index_map.Append(obj.ar_name, obj_idx); + } + if (err) + return 0; + + // Now sort all of the object name pointers + m_object_name_to_index_map.Sort(); + } + return m_objects.size(); +} + +ObjectContainerBigArchive::Object * +ObjectContainerBigArchive::Archive::FindObject( + ConstString object_name, const llvm::sys::TimePoint<> &object_mod_time) { + const ObjectNameToIndexMap::Entry *match = + m_object_name_to_index_map.FindFirstValueForName(object_name); + if (!match) + return nullptr; + if (object_mod_time == llvm::sys::TimePoint<>()) + return &m_objects[match->value]; + + const uint64_t object_modification_date = llvm::sys::toTimeT(object_mod_time); + if (m_objects[match->value].modification_time == object_modification_date) + return &m_objects[match->value]; + + const ObjectNameToIndexMap::Entry *next_match = + m_object_name_to_index_map.FindNextValueForName(match); + while (next_match) { + if (m_objects[next_match->value].modification_time == + object_modification_date) + return &m_objects[next_match->value]; + next_match = m_object_name_to_index_map.FindNextValueForName(next_match); + } + + return nullptr; +} + +ObjectContainerBigArchive::Archive::shared_ptr +ObjectContainerBigArchive::Archive::FindCachedArchive( + const FileSpec &file, const ArchSpec &arch, + const llvm::sys::TimePoint<> &time, lldb::offset_t file_offset) { + std::lock_guard guard(Archive::GetArchiveCacheMutex()); + shared_ptr archive_sp; + Archive::Map &archive_map = Archive::GetArchiveCache(); + Archive::Map::iterator pos = archive_map.find(file); + // Don't cache a value for "archive_map.end()" below since we might delete an + // archive entry... + while (pos != archive_map.end() && pos->first == file) { + bool match = true; + if (arch.IsValid() && + !pos->second->GetArchitecture().IsCompatibleMatch(arch)) + match = false; + else if (file_offset != LLDB_INVALID_OFFSET && + pos->second->GetFileOffset() != file_offset) + match = false; + if (match) { + if (pos->second->GetModificationTime() == time) { + return pos->second; + } else { + // We have a file at the same path with the same architecture whose + // modification time doesn't match. It doesn't make sense for us to + // continue to use this Big archive since we cache only the object info + // which consists of file time info and also the file offset and file + // size of any contained objects. Since this information is now out of + // date, we won't get the correct information if we go and extract the + // file data, so we should remove the old and outdated entry. + archive_map.erase(pos); + pos = archive_map.find(file); + continue; // Continue to next iteration so we don't increment pos + // below... + } + } + ++pos; + } + return archive_sp; +} + +ObjectContainerBigArchive::Archive::shared_ptr +ObjectContainerBigArchive::Archive::ParseAndCacheArchiveForFile( + const FileSpec &file, const ArchSpec &arch, + const llvm::sys::TimePoint<> &time, lldb::offset_t file_offset, + DataExtractor &data) { + shared_ptr archive_sp(new Archive(arch, time, file_offset, data)); + if (archive_sp) { + const size_t num_objects = archive_sp->ParseObjects(); + if (num_objects > 0) { + std::lock_guard guard( + Archive::GetArchiveCacheMutex()); + Archive::GetArchiveCache().insert(std::make_pair(file, archive_sp)); + } else { + archive_sp.reset(); + } + } + return archive_sp; +} + +ObjectContainerBigArchive::Archive::Map & +ObjectContainerBigArchive::Archive::GetArchiveCache() { + static Archive::Map g_archive_map; + return g_archive_map; +} + +std::recursive_mutex & +ObjectContainerBigArchive::Archive::GetArchiveCacheMutex() { + static std::recursive_mutex g_archive_map_mutex; + return g_archive_map_mutex; +} + +void ObjectContainerBigArchive::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + GetModuleSpecifications); +} + +void ObjectContainerBigArchive::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ObjectContainer *ObjectContainerBigArchive::CreateInstance( + const lldb::ModuleSP &module_sp, DataBufferSP &data_sp, + lldb::offset_t data_offset, const FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length) { + ConstString object_name(module_sp->GetObjectName()); + if (!object_name) + return nullptr; + + if (data_sp) { + // We have data, which means this is the first 512 bytes of the file Check + // to see if the magic bytes match and if they do, read the entire table of + // contents for the archive and cache it + DataExtractor data; + data.SetData(data_sp, data_offset, length); + if (file && data_sp && ObjectContainerBigArchive::MagicBytesMatch(data)) { + LLDB_SCOPED_TIMERF( + "ObjectContainerBigArchive::CreateInstance (module = %s, file = " + "%p, file_offset = 0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")", + module_sp->GetFileSpec().GetPath().c_str(), + static_cast(file), static_cast(file_offset), + static_cast(length)); + + // Map the entire .a file to be sure that we don't lose any data if the + // file gets updated by a new build while this .a file is being used for + // debugging + DataBufferSP archive_data_sp = + FileSystem::Instance().CreateDataBuffer(*file, length, file_offset); + if (!archive_data_sp) + return nullptr; + + lldb::offset_t archive_data_offset = 0; + + Archive::shared_ptr archive_sp(Archive::FindCachedArchive( + *file, module_sp->GetArchitecture(), module_sp->GetModificationTime(), + file_offset)); + std::unique_ptr container_up( + new ObjectContainerBigArchive(module_sp, archive_data_sp, + archive_data_offset, file, file_offset, + length)); + + if (container_up) { + if (archive_sp) { + // We already have this archive in our cache, use it + container_up->SetArchive(archive_sp); + return container_up.release(); + } else if (container_up->ParseHeader()) + return container_up.release(); + } + } + } else { + // No data, just check for a cached archive + Archive::shared_ptr archive_sp(Archive::FindCachedArchive( + *file, module_sp->GetArchitecture(), module_sp->GetModificationTime(), + file_offset)); + if (archive_sp) { + std::unique_ptr container_up( + new ObjectContainerBigArchive(module_sp, data_sp, data_offset, file, + file_offset, length)); + + if (container_up) { + // We already have this archive in our cache, use it + container_up->SetArchive(archive_sp); + return container_up.release(); + } + } + } + return nullptr; +} + +bool ObjectContainerBigArchive::MagicBytesMatch(const DataExtractor &data) { + uint32_t offset = 0; + const char *armag = (const char *)data.PeekData(offset, (sizeof(llvm::object::BigArchiveMagic) - 1)); + if (armag && ::strncmp(armag, llvm::object::BigArchiveMagic, (sizeof(llvm::object::BigArchiveMagic) - 1)) == 0) + return true; + return false; +} + +ObjectContainerBigArchive::ObjectContainerBigArchive( + const lldb::ModuleSP &module_sp, DataBufferSP &data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t size) + : ObjectContainer(module_sp, file, file_offset, size, data_sp, data_offset), + m_archive_sp() {} +void ObjectContainerBigArchive::SetArchive(Archive::shared_ptr &archive_sp) { + m_archive_sp = archive_sp; +} + +ObjectContainerBigArchive::~ObjectContainerBigArchive() = default; + +bool ObjectContainerBigArchive::ParseHeader() { + if (m_archive_sp.get() == nullptr) { + if (m_data.GetByteSize() > 0) { + ModuleSP module_sp(GetModule()); + if (module_sp) { + m_archive_sp = Archive::ParseAndCacheArchiveForFile( + m_file, module_sp->GetArchitecture(), + module_sp->GetModificationTime(), m_offset, m_data); + } + // Clear the m_data that contains the entire archive data and let our + // m_archive_sp hold onto the data. + m_data.Clear(); + } + } + return m_archive_sp.get() != nullptr; +} + +void ObjectContainerBigArchive::Object::Dump(Stream *s) const { + printf("name = \"%s\"\n", ar_name.GetCString()); + printf("mtime = 0x%8.8" PRIx32 "\n", modification_time); + printf("size = 0x%8.8" PRIx32 " (%" PRIu32 ")\n", size, size); + printf("file_offset = 0x%16.16" PRIx64 " (%" PRIu64 ")\n", file_offset, + file_offset); + printf("file_size = 0x%16.16" PRIx64 " (%" PRIu64 ")\n\n", file_size, + file_size); +} + +ObjectFileSP ObjectContainerBigArchive::GetObjectFile(const FileSpec *file) { + ModuleSP module_sp(GetModule()); + if (module_sp) { + if (module_sp->GetObjectName() && m_archive_sp) { + Object *object = m_archive_sp->FindObject( + module_sp->GetObjectName(), module_sp->GetObjectModificationTime()); + if (object) { + lldb::offset_t data_offset = object->file_offset; + return ObjectFile::FindPlugin( + module_sp, file, m_offset + object->file_offset, object->file_size, + m_archive_sp->GetData().GetSharedDataBuffer(), data_offset); + } + } + } + return ObjectFileSP(); +} + +size_t ObjectContainerBigArchive::GetModuleSpecifications( + const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, lldb::offset_t file_offset, + lldb::offset_t file_size, lldb_private::ModuleSpecList &specs) { + + // We have data, which means this is the first 512 bytes of the file Check to + // see if the magic bytes match and if they do, read the entire table of + // contents for the archive and cache it + DataExtractor data; + data.SetData(data_sp, data_offset, data_sp->GetByteSize()); + if (!file || !data_sp || !ObjectContainerBigArchive::MagicBytesMatch(data)) + return 0; + + const size_t initial_count = specs.GetSize(); + llvm::sys::TimePoint<> file_mod_time = FileSystem::Instance().GetModificationTime(file); + Archive::shared_ptr archive_sp( + Archive::FindCachedArchive(file, ArchSpec(), file_mod_time, file_offset)); + bool set_archive_arch = false; + if (!archive_sp) { + set_archive_arch = true; + data_sp = + FileSystem::Instance().CreateDataBuffer(file, file_size, file_offset); + if (data_sp) { + data.SetData(data_sp, 0, data_sp->GetByteSize()); + archive_sp = Archive::ParseAndCacheArchiveForFile( + file, ArchSpec(), file_mod_time, file_offset, data); + } + } + + if (archive_sp) { + const size_t num_objects = archive_sp->GetNumObjects(); + for (size_t idx = 0; idx < num_objects; ++idx) { + const Object *object = archive_sp->GetObjectAtIndex(idx); + if (object) { + 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( + file, object_file_offset, file_size - object_file_offset, + specs)) { + ModuleSpec &spec = + specs.GetModuleSpecRefAtIndex(specs.GetSize() - 1); + llvm::sys::TimePoint<> object_mod_time( + std::chrono::seconds(object->modification_time)); + spec.GetObjectName() = object->ar_name; + spec.SetObjectOffset(object_file_offset); + spec.SetObjectSize(file_size - object_file_offset); + spec.GetObjectModificationTime() = object_mod_time; + } + } + } + } + } + const size_t end_count = specs.GetSize(); + size_t num_specs_added = end_count - initial_count; + if (set_archive_arch && num_specs_added > 0) { + // The archive was created but we didn't have an architecture so we need to + // set it + for (size_t i = initial_count; i < end_count; ++i) { + ModuleSpec module_spec; + if (specs.GetModuleSpecAtIndex(i, module_spec)) { + if (module_spec.GetArchitecture().IsValid()) { + archive_sp->SetArchitecture(module_spec.GetArchitecture()); + break; + } + } + } + } + return num_specs_added; +} diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h new file mode 100644 index 0000000000000..ad9b814048a87 --- /dev/null +++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h @@ -0,0 +1,177 @@ +//===-- ObjectContainerBigArchive.h -----------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BIG_ARCHIVE_OBJECTCONTAINERBIGARCHIVE_H +#define LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BIG_ARCHIVE_OBJECTCONTAINERBIGARCHIVE_H + +#include "lldb/Core/UniqueCStringMap.h" +#include "lldb/Symbol/ObjectContainer.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/FileSpec.h" + +#include "llvm/Support/Chrono.h" + +#include +#include +#include + +class ObjectContainerBigArchive : public lldb_private::ObjectContainer { +public: + ObjectContainerBigArchive(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + ~ObjectContainerBigArchive() override; + + // Static Functions + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "big-archive"; } + + static llvm::StringRef GetPluginDescriptionStatic() { + return "Big Archive object container reader."; + } + + static lldb_private::ObjectContainer * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + static size_t GetModuleSpecifications(const lldb_private::FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + lldb_private::ModuleSpecList &specs); + + static bool MagicBytesMatch(const lldb_private::DataExtractor &data); + + // Member Functions + bool ParseHeader() override; + + size_t GetNumObjects() const override { + if (m_archive_sp) + return m_archive_sp->GetNumObjects(); + return 0; + } + + lldb::ObjectFileSP GetObjectFile(const lldb_private::FileSpec *file) override; + + // PluginInterface protocol + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + +protected: + struct Object { + Object(); + + void Clear(); + + lldb::offset_t Extract(const lldb_private::DataExtractor &data, + lldb::offset_t offset); + /// Object name in the archive. + lldb_private::ConstString ar_name; + + /// Object modification time in the archive. + uint32_t modification_time = 0; + + /// Object user id in the archive. + uint16_t uid = 0; + + /// Object group id in the archive. + uint16_t gid = 0; + + /// Object octal file permissions in the archive. + uint16_t mode = 0; + + /// Object size in bytes in the archive. + uint32_t size = 0; + + /// File offset in bytes from the beginning of the file of the object data. + lldb::offset_t file_offset = 0; + + /// Length of the object data. + lldb::offset_t file_size = 0; + + void Dump(lldb_private::Stream *s) const; + }; + + class Archive { + public: + typedef std::shared_ptr shared_ptr; + typedef std::multimap Map; + + Archive(const lldb_private::ArchSpec &arch, + const llvm::sys::TimePoint<> &mod_time, lldb::offset_t file_offset, + lldb_private::DataExtractor &data); + + ~Archive(); + + static Map &GetArchiveCache(); + + static std::recursive_mutex &GetArchiveCacheMutex(); + + static Archive::shared_ptr FindCachedArchive( + const lldb_private::FileSpec &file, const lldb_private::ArchSpec &arch, + const llvm::sys::TimePoint<> &mod_time, lldb::offset_t file_offset); + + static Archive::shared_ptr ParseAndCacheArchiveForFile( + const lldb_private::FileSpec &file, const lldb_private::ArchSpec &arch, + const llvm::sys::TimePoint<> &mod_time, lldb::offset_t file_offset, + lldb_private::DataExtractor &data); + + size_t GetNumObjects() const { return m_objects.size(); } + + const Object *GetObjectAtIndex(size_t idx) { + if (idx < m_objects.size()) + return &m_objects[idx]; + return nullptr; + } + + size_t ParseObjects(); + + Object *FindObject(lldb_private::ConstString object_name, + const llvm::sys::TimePoint<> &object_mod_time); + + lldb::offset_t GetFileOffset() const { return m_file_offset; } + + const llvm::sys::TimePoint<> &GetModificationTime() { + return m_modification_time; + } + + const lldb_private::ArchSpec &GetArchitecture() const { return m_arch; } + + void SetArchitecture(const lldb_private::ArchSpec &arch) { m_arch = arch; } + + bool HasNoExternalReferences() const; + + lldb_private::DataExtractor &GetData() { return m_data; } + + protected: + typedef lldb_private::UniqueCStringMap ObjectNameToIndexMap; + // Member Variables + lldb_private::ArchSpec m_arch; + llvm::sys::TimePoint<> m_modification_time; + lldb::offset_t m_file_offset; + std::vector m_objects; + ObjectNameToIndexMap m_object_name_to_index_map; + lldb_private::DataExtractor m_data; ///< The data for this object container + ///so we don't lose data if the .a files + ///gets modified + }; + + void SetArchive(Archive::shared_ptr &archive_sp); + + Archive::shared_ptr m_archive_sp; +}; + +#endif // LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BIG_ARCHIVE_OBJECTCONTAINERBIGARCHIVE_H diff --git a/lldb/source/Plugins/ObjectContainer/CMakeLists.txt b/lldb/source/Plugins/ObjectContainer/CMakeLists.txt index cda0c8151dd8a..2492798bb13ef 100644 --- a/lldb/source/Plugins/ObjectContainer/CMakeLists.txt +++ b/lldb/source/Plugins/ObjectContainer/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(BSD-Archive) +add_subdirectory(Big-Archive) add_subdirectory(Universal-Mach-O) add_subdirectory(Mach-O-Fileset) diff --git a/lldb/source/Plugins/ObjectFile/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/CMakeLists.txt index 773241c8944c8..7abd0c96f4fd7 100644 --- a/lldb/source/Plugins/ObjectFile/CMakeLists.txt +++ b/lldb/source/Plugins/ObjectFile/CMakeLists.txt @@ -6,5 +6,6 @@ add_subdirectory(Mach-O) add_subdirectory(Minidump) add_subdirectory(PDB) add_subdirectory(PECOFF) +add_subdirectory(XCOFF) add_subdirectory(Placeholder) add_subdirectory(wasm) diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index ce095bcc48374..bcb6330cbb1f9 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -5673,7 +5673,7 @@ bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &value, return false; } -bool ObjectFileMachO::GetCorefileThreadExtraInfos(std::vector &tids) { +bool ObjectFileMachO::GetCorefileThreadExtraInfos(std::vector &tids) { tids.clear(); ModuleSP module_sp(GetModule()); if (module_sp) { @@ -5724,8 +5724,8 @@ bool ObjectFileMachO::GetCorefileThreadExtraInfos(std::vector &tids) { return false; } StructuredData::Dictionary *thread = *maybe_thread; - tid_t tid = LLDB_INVALID_THREAD_ID; - if (thread->GetValueForKeyAsInteger("thread_id", tid)) + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; + if (thread->GetValueForKeyAsInteger("thread_id", tid)) if (tid == 0) tid = LLDB_INVALID_THREAD_ID; tids.push_back(tid); diff --git a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp index faa144bfb5f6a..d27cdfc60de85 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp +++ b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp @@ -51,7 +51,9 @@ size_t ObjectFileMinidump::GetModuleSpecifications( const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, lldb_private::ModuleSpecList &specs) { +#if !defined(__AIX__) specs.Clear(); +#endif return 0; } diff --git a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp index f0832dbf07347..75cc54e4f0d48 100644 --- a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp +++ b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp @@ -116,18 +116,31 @@ size_t ObjectFilePDB::GetModuleSpecifications( ModuleSpec module_spec(file); llvm::BumpPtrAllocator allocator; std::unique_ptr pdb_file = loadPDBFile(file.GetPath(), allocator); - if (!pdb_file) + if (!pdb_file){ +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif + } auto info_stream = pdb_file->getPDBInfoStream(); if (!info_stream) { llvm::consumeError(info_stream.takeError()); +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif } auto dbi_stream = pdb_file->getPDBDbiStream(); if (!dbi_stream) { llvm::consumeError(dbi_stream.takeError()); +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif } lldb_private::UUID &uuid = module_spec.GetUUID(); diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index bda691ade8af0..db8fa78043fdc 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -252,8 +252,13 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, lldb_private::ModuleSpecList &specs) { const size_t initial_count = specs.GetSize(); - if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp)) + if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp)){ +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif + } Log *log = GetLog(LLDBLog::Object); @@ -266,12 +271,21 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( if (!binary) { LLDB_LOG_ERROR(log, binary.takeError(), "Failed to create binary for file ({1}): {0}", file); +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif } auto *COFFObj = llvm::dyn_cast(binary->get()); - if (!COFFObj) + if (!COFFObj){ +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif + } ModuleSpec module_spec(file); ArchSpec &spec = module_spec.GetArchitecture(); diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt new file mode 100644 index 0000000000000..8840248574c88 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt @@ -0,0 +1,13 @@ +add_lldb_library(lldbPluginObjectFileXCOFF PLUGIN + ObjectFileXCOFF.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + lldbTarget + LINK_COMPONENTS + BinaryFormat + Object + Support + ) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp new file mode 100644 index 0000000000000..a4d9ea295b4c3 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -0,0 +1,780 @@ +//===-- ObjectFileXCOFF.cpp -------------------------------------------------===// +// +// 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 "ObjectFileXCOFF.h" + +#include +#include +#include +#include + +#include "lldb/Utility/FileSpecList.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Progress.h" +#include "lldb/Core/Section.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/LZMA.h" +#include "lldb/Symbol/DWARFCallFrameInfo.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RangeMap.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/Timer.h" +#include "llvm/ADT/IntervalMap.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/Object/Decompressor.h" +#include "llvm/Support/CRC.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Object/XCOFFObjectFile.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ObjectFileXCOFF) + +char ObjectFileXCOFF::ID; + +// FIXME: target 64bit at this moment. + +// Static methods. +void ObjectFileXCOFF::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + CreateMemoryInstance, GetModuleSpecifications); +} + +void ObjectFileXCOFF::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; + +ObjectFile *ObjectFileXCOFF::CreateInstance(const lldb::ModuleSP &module_sp, + DataBufferSP data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t file_offset, + lldb::offset_t length) { + if (!data_sp) { + data_sp = MapFileData(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + } + + if (!ObjectFileXCOFF::MagicBytesMatch(data_sp, data_offset, length)) + return nullptr; + + // Update the data to contain the entire file if it doesn't already + if (data_sp->GetByteSize() < length) { + data_sp = MapFileData(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + } + auto objfile_up = std::make_unique( + module_sp, data_sp, data_offset, file, file_offset, length); + if (!objfile_up) + return nullptr; + + // Cache xcoff binary. + if (!objfile_up->CreateBinary()) + return nullptr; + + if (!objfile_up->ParseHeader()) + //FIXME objfile leak + return nullptr; + + UGLY_FLAG_FOR_AIX = true; + return objfile_up.release(); +} + +bool ObjectFileXCOFF::CreateBinary() { + if (m_binary) + return true; + + Log *log = GetLog(LLDBLog::Object); + + auto binary = llvm::object::XCOFFObjectFile::createObjectFile(llvm::MemoryBufferRef( + toStringRef(m_data.GetData()), m_file.GetFilename().GetStringRef()), + file_magic::xcoff_object_64); + if (!binary) { + LLDB_LOG_ERROR(log, binary.takeError(), + "Failed to create binary for file ({1}): {0}", m_file); + return false; + } + + // Make sure we only handle COFF format. + m_binary = + llvm::unique_dyn_cast(std::move(*binary)); + if (!m_binary) + return false; + + LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}", + this, GetModule().get(), GetModule()->GetSpecificationDescription(), + m_file.GetPath(), m_binary.get()); + return true; +} + +ObjectFile *ObjectFileXCOFF::CreateMemoryInstance( + const lldb::ModuleSP &module_sp, WritableDataBufferSP data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) { + return nullptr; +} + +size_t ObjectFileXCOFF::GetModuleSpecifications( + const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, lldb::offset_t file_offset, + lldb::offset_t length, lldb_private::ModuleSpecList &specs) { + const size_t initial_count = specs.GetSize(); + + if (ObjectFileXCOFF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) { + ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + ModuleSpec spec(file, arch_spec); + spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX); + specs.Append(spec); + } + return specs.GetSize() - initial_count; +} + +static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) { + switch (magic) { + /* TODO: 32bit not supported yet + case XCOFF::XCOFF32: + return sizeof(struct llvm::object::XCOFFFileHeader32); + */ + + case XCOFF::XCOFF64: + return sizeof(struct llvm::object::XCOFFFileHeader64); + break; + + default: + break; + } + return 0; +} + +bool ObjectFileXCOFF::MagicBytesMatch(DataBufferSP &data_sp, + lldb::addr_t data_offset, + lldb::addr_t data_length) { + lldb_private::DataExtractor data; + data.SetData(data_sp, data_offset, data_length); + lldb::offset_t offset = 0; + uint16_t magic = data.GetU16(&offset); + return XCOFFHeaderSizeFromMagic(magic) != 0; +} + +bool ObjectFileXCOFF::ParseHeader() { + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard guard(module_sp->GetMutex()); + m_sect_headers.clear(); + lldb::offset_t offset = 0; + + if (ParseXCOFFHeader(m_data, &offset, m_xcoff_header)) { + m_data.SetAddressByteSize(GetAddressByteSize()); + if (m_xcoff_header.auxhdrsize > 0) + ParseXCOFFOptionalHeader(m_data, &offset); + ParseSectionHeaders(offset); + } + return true; + } + + return false; +} + +bool ObjectFileXCOFF::ParseXCOFFHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + xcoff_header_t &xcoff_header) { + //FIXME: data.ValidOffsetForDataOfSize + xcoff_header.magic = data.GetU16(offset_ptr); + xcoff_header.nsects = data.GetU16(offset_ptr); + xcoff_header.modtime = data.GetU32(offset_ptr); + xcoff_header.symoff = data.GetU64(offset_ptr); + xcoff_header.auxhdrsize = data.GetU16(offset_ptr); + xcoff_header.flags = data.GetU16(offset_ptr); + xcoff_header.nsyms = data.GetU32(offset_ptr); + return true; +} + +bool ObjectFileXCOFF::ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr) { + lldb::offset_t init_offset = *offset_ptr; + //FIXME: data.ValidOffsetForDataOfSize + m_xcoff_aux_header.AuxMagic = data.GetU16(offset_ptr); + m_xcoff_aux_header.Version = data.GetU16(offset_ptr); + m_xcoff_aux_header.ReservedForDebugger = data.GetU32(offset_ptr); + m_xcoff_aux_header.TextStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.DataStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.TOCAnchorAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfEntryPoint = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTOC = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfLoader = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.ModuleType = data.GetU16(offset_ptr); + m_xcoff_aux_header.CpuFlag = data.GetU8(offset_ptr); + m_xcoff_aux_header.CpuType = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.DataPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.StackPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.FlagAndTDataAlignment = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.InitDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.BssDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.EntryPointAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxStackSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfTData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.XCOFF64Flag = data.GetU16(offset_ptr); + lldb::offset_t last_offset = *offset_ptr; + if ((last_offset - init_offset) < m_xcoff_header.auxhdrsize) + *offset_ptr += (m_xcoff_header.auxhdrsize - (last_offset - init_offset)); + return true; +} + +bool ObjectFileXCOFF::ParseSectionHeaders( + uint32_t section_header_data_offset) { + const uint32_t nsects = m_xcoff_header.nsects; + m_sect_headers.clear(); + + if (nsects > 0) { + const size_t section_header_byte_size = nsects * m_binary->getSectionHeaderSize(); + lldb_private::DataExtractor section_header_data = + ReadImageData(section_header_data_offset, section_header_byte_size); + + lldb::offset_t offset = 0; + //FIXME: section_header_data.ValidOffsetForDataOfSize + m_sect_headers.resize(nsects); + + for (uint32_t idx = 0; idx < nsects; ++idx) { + const void *name_data = section_header_data.GetData(&offset, 8); + if (name_data) { + memcpy(m_sect_headers[idx].name, name_data, 8); + m_sect_headers[idx].phyaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].vmaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].size = section_header_data.GetU64(&offset); + m_sect_headers[idx].offset = section_header_data.GetU64(&offset); + m_sect_headers[idx].reloff = section_header_data.GetU64(&offset); + m_sect_headers[idx].lineoff = section_header_data.GetU64(&offset); + m_sect_headers[idx].nreloc = section_header_data.GetU32(&offset); + m_sect_headers[idx].nline = section_header_data.GetU32(&offset); + m_sect_headers[idx].flags = section_header_data.GetU32(&offset); + offset += 4; + } else { + offset += (m_binary->getSectionHeaderSize() - 8); + } + } + } + + return !m_sect_headers.empty(); +} + +lldb_private::DataExtractor ObjectFileXCOFF::ReadImageData(uint32_t offset, size_t size) { + if (!size) + return {}; + + if (m_data.ValidOffsetForDataOfSize(offset, size)) + return lldb_private::DataExtractor(m_data, offset, size); + + assert(0); + ProcessSP process_sp(m_process_wp.lock()); + lldb_private::DataExtractor data; + if (process_sp) { + auto data_up = std::make_unique(size, 0); + Status readmem_error; + size_t bytes_read = + process_sp->ReadMemory(offset, data_up->GetBytes(), + data_up->GetByteSize(), readmem_error); + if (bytes_read == size) { + DataBufferSP buffer_sp(data_up.release()); + data.SetData(buffer_sp, 0, buffer_sp->GetByteSize()); + } + } + return data; +} + +bool ObjectFileXCOFF::SetLoadAddress(Target &target, lldb::addr_t value, + bool value_is_offset) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (section_sp && !section_sp->IsThreadSpecific()) { + bool use_offset = false; + if (strcmp(section_sp->GetName().AsCString(), ".text") == 0 || + strcmp(section_sp->GetName().AsCString(), ".data") == 0 || + strcmp(section_sp->GetName().AsCString(), ".bss") == 0) + use_offset = true; + + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, (use_offset ? + (section_sp->GetFileOffset() + value) : (section_sp->GetFileAddress() + value)))) + ++num_loaded_sections; + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (type_id == 1 && section_sp && strcmp(section_sp->GetName().AsCString(), ".text") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileOffset() + value)) + ++num_loaded_sections; + } + } else if (type_id == 2 && section_sp && strcmp(section_sp->GetName().AsCString(), ".data") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileAddress() + value)) + ++num_loaded_sections; + } + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +ByteOrder ObjectFileXCOFF::GetByteOrder() const { + return eByteOrderBig; +} + +bool ObjectFileXCOFF::IsExecutable() const { + return true; +} + +uint32_t ObjectFileXCOFF::GetAddressByteSize() const { + if (m_xcoff_header.magic == XCOFF::XCOFF64) + return 8; + else if (m_xcoff_header.magic == XCOFF::XCOFF32) + return 4; + return 4; +} + +AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) { + return AddressClass::eUnknown; +} + +lldb::SymbolType ObjectFileXCOFF::MapSymbolType(llvm::object::SymbolRef::Type sym_type) { + if (sym_type == llvm::object::SymbolRef::ST_Function) + return lldb::eSymbolTypeCode; + else if (sym_type == llvm::object::SymbolRef::ST_Data) + return lldb::eSymbolTypeData; + return lldb::eSymbolTypeInvalid; +} + +void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) { + SectionList *sect_list = GetSectionList(); + const uint32_t num_syms = m_xcoff_header.nsyms; + uint32_t sidx = 0; + if (num_syms > 0 && m_xcoff_header.symoff > 0) { + const uint32_t symbol_size = XCOFF::SymbolTableEntrySize; + const size_t symbol_data_size = num_syms * symbol_size; + lldb_private::DataExtractor symtab_data = + ReadImageData(m_xcoff_header.symoff, symbol_data_size); + + lldb::offset_t offset = 0; + std::string symbol_name; + Symbol *symbols = lldb_symtab.Resize(num_syms); + llvm::object::symbol_iterator SI = m_binary->symbol_begin(); + for (uint32_t i = 0; i < num_syms; ++i, ++SI) { + xcoff_symbol_t symbol; + const uint32_t symbol_offset = offset; + symbol.value = symtab_data.GetU64(&offset); + symbol.offset = symtab_data.GetU32(&offset); + Expected symbol_name_or_err = m_binary->getStringTableEntry(symbol.offset); + if (!symbol_name_or_err) { + consumeError(symbol_name_or_err.takeError()); + return; + } + StringRef symbol_name_str = symbol_name_or_err.get(); + symbol_name.assign(symbol_name_str.data()); + symbol.sect = symtab_data.GetU16(&offset); + symbol.type = symtab_data.GetU16(&offset); + symbol.storage = symtab_data.GetU8(&offset); + symbol.naux = symtab_data.GetU8(&offset); + // Allow C_HIDEXT TOC symbol, and check others. + if (symbol.storage == XCOFF::C_HIDEXT && strcmp(symbol_name.c_str(), "TOC") != 0) { + if (symbol.naux == 0) + continue; + if (symbol.naux > 1) { + i += symbol.naux; + offset += symbol.naux * symbol_size; + continue; + } + /* Allow XCOFF::C_HIDEXT with following SMC and AT: + StorageMappingClass: XMC_PR (0x0) + Auxiliary Type: AUX_CSECT (0xFB) + */ + xcoff_sym_csect_aux_entry_t symbol_aux; + symbol_aux.section_or_len_low_byte = symtab_data.GetU32(&offset); + symbol_aux.parameter_hash_index = symtab_data.GetU32(&offset); + symbol_aux.type_check_sect_num = symtab_data.GetU16(&offset); + symbol_aux.symbol_alignment_and_type = symtab_data.GetU8(&offset); + symbol_aux.storage_mapping_class = symtab_data.GetU8(&offset); + symbol_aux.section_or_len_high_byte = symtab_data.GetU32(&offset); + symbol_aux.pad = symtab_data.GetU8(&offset); + symbol_aux.aux_type = symtab_data.GetU8(&offset); + offset -= symbol.naux * symbol_size; + if (symbol_aux.storage_mapping_class != XCOFF::XMC_PR || symbol_aux.aux_type != XCOFF::AUX_CSECT) { + i += symbol.naux; + offset += symbol.naux * symbol_size; + continue; + } + } + // Remove the dot prefix for demangle + if (symbol_name_str.size() > 1 && symbol_name_str.data()[0] == '.') { + symbols[sidx].GetMangled().SetValue(ConstString(symbol_name.c_str() + 1)); + } else { + symbols[sidx].GetMangled().SetValue(ConstString(symbol_name.c_str())); + } + if ((int16_t)symbol.sect >= 1) { + Address symbol_addr(sect_list->GetSectionAtIndex((size_t)(symbol.sect - 1)), + (symbol.value - sect_list->GetSectionAtIndex((size_t)(symbol.sect - 1))->GetFileAddress())); + symbols[sidx].GetAddressRef() = symbol_addr; + + Expected sym_type_or_err = SI->getType(); + if (!sym_type_or_err) { + consumeError(sym_type_or_err.takeError()); + return; + } + symbols[sidx].SetType(MapSymbolType(sym_type_or_err.get())); + } + ++sidx; + + if (symbol.naux > 0) { + i += symbol.naux; + offset += symbol.naux * symbol_size; + } + } + lldb_symtab.Resize(sidx); + } +} + +bool ObjectFileXCOFF::IsStripped() { + return false; +} + +void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) { + if (m_sections_up) + return; + m_sections_up = std::make_unique(); + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard guard(module_sp->GetMutex()); + + const uint32_t nsects = m_sect_headers.size(); + ModuleSP module_sp(GetModule()); + for (uint32_t idx = 0; idx < nsects; ++idx) { + llvm::StringRef sect_name = GetSectionName(m_sect_headers[idx]); + ConstString const_sect_name(sect_name); + SectionType section_type = GetSectionType(sect_name, m_sect_headers[idx]); + + SectionSP section_sp(new Section( + module_sp, // Module to which this section belongs + this, // Object file to which this section belongs + idx + 1, // Section ID is the 1 based section index. + const_sect_name, // Name of this section + section_type, + m_sect_headers[idx].vmaddr, // File VM address == addresses as + // they are found in the object file + m_sect_headers[idx].size, // VM size in bytes of this section + m_sect_headers[idx].offset, // Offset to the data for this section in the file + m_sect_headers[idx].size, // Size in bytes of this section as found in the file + 0, // FIXME: alignment + m_sect_headers[idx].flags)); // Flags for this section + + // FIXME + uint32_t permissions = 0; + permissions |= ePermissionsReadable; + if (m_sect_headers[idx].flags & (XCOFF::STYP_DATA | XCOFF::STYP_BSS)) + permissions |= ePermissionsWritable; + if (m_sect_headers[idx].flags & XCOFF::STYP_TEXT) + permissions |= ePermissionsExecutable; + section_sp->SetPermissions(permissions); + + m_sections_up->AddSection(section_sp); + unified_section_list.AddSection(section_sp); + } + } +} + +llvm::StringRef ObjectFileXCOFF::GetSectionName(const section_header_t §) { + llvm::StringRef hdr_name(sect.name, std::size(sect.name)); + hdr_name = hdr_name.split('\0').first; + if (hdr_name.consume_front("/")) { + lldb::offset_t stroff; + if (!to_integer(hdr_name, stroff, 10)) + return ""; + lldb::offset_t string_file_offset = + m_xcoff_header.symoff + (m_xcoff_header.nsyms * static_cast(XCOFF::SymbolTableEntrySize)) + stroff; + if (const char *name = m_data.GetCStr(&string_file_offset)) + return name; + return ""; + } + return hdr_name; +} + +SectionType ObjectFileXCOFF::GetSectionType(llvm::StringRef sect_name, + const section_header_t §) { + if (sect.flags & XCOFF::STYP_TEXT) + return eSectionTypeCode; + if (sect.flags & XCOFF::STYP_DATA) + return eSectionTypeData; + if (sect.flags & XCOFF::STYP_BSS) + return eSectionTypeZeroFill; + if (sect.flags & XCOFF::STYP_DWARF) { + SectionType section_type = + llvm::StringSwitch(sect_name) + .Case(".dwinfo", eSectionTypeDWARFDebugInfo) + .Case(".dwline", eSectionTypeDWARFDebugLine) + .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev) + .Default(eSectionTypeInvalid); + + if (section_type != eSectionTypeInvalid) + return section_type; + } + return eSectionTypeOther; +} + +void ObjectFileXCOFF::Dump(Stream *s) { +} + +ArchSpec ObjectFileXCOFF::GetArchitecture() { + ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + return arch_spec; +} + +UUID ObjectFileXCOFF::GetUUID() { + return UUID(); +} + +std::optional ObjectFileXCOFF::GetDebugLink() { + return std::nullopt; +} + +uint32_t ObjectFileXCOFF::ParseDependentModules() { + ModuleSP module_sp(GetModule()); + if (!module_sp) + return 0; + + std::lock_guard guard(module_sp->GetMutex()); + if (m_deps_filespec) + return m_deps_filespec->GetSize(); + + // Cache coff binary if it is not done yet. + if (!CreateBinary()) + return 0; + + Log *log = GetLog(LLDBLog::Object); + LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}", + this, GetModule().get(), GetModule()->GetSpecificationDescription(), + m_file.GetPath(), m_binary.get()); + + m_deps_filespec = FileSpecList(); + + auto ImportFilesOrError = m_binary->getImportFileTable(); + if (!ImportFilesOrError) { + consumeError(ImportFilesOrError.takeError()); + return 0; + } + +#if 0 + StringRef ImportFileTable = ImportFilesOrError.get(); + const char *CurrentStr = ImportFileTable.data(); + const char *TableEnd = ImportFileTable.end(); + const char *Basename = nullptr; + + for (size_t StrIndex = 0; CurrentStr < TableEnd; + ++StrIndex, CurrentStr += strlen(CurrentStr) + 1) { + if (StrIndex >= 3 && StrIndex % 3 == 1) { + // base_name + llvm::StringRef dll_name(CurrentStr); + Basename = CurrentStr; + + // At this moment we only have the base name of the DLL. The full path can + // only be seen after the dynamic loading. Our best guess is Try to get it + // with the help of the object file's directory. + llvm::SmallString<128> dll_fullpath; + FileSpec dll_specs(dll_name); + // FIXME: hack to get libc.a loaded + if (strcmp(CurrentStr, "libc.a") == 0) { + dll_specs.GetDirectory().SetString("/usr/lib"); + } else { + dll_specs.GetDirectory().SetString(m_file.GetDirectory().GetCString()); + } + + if (!llvm::sys::fs::real_path(dll_specs.GetPath(), dll_fullpath)) + //m_deps_filespec->EmplaceBack(dll_fullpath); + m_deps_filespec->EmplaceBack("/usr/lib/libc.a(shr_64.o)"); + else { + // Known DLLs or DLL not found in the object file directory. + m_deps_filespec->EmplaceBack(dll_name); + } + } else if (StrIndex >= 3 && StrIndex % 3 == 2) { + // archive_member_name + if (strcmp(CurrentStr, "") == 0) { + continue; + } + assert(strcmp(Basename, "") != 0); + std::map>::iterator iter = m_deps_base_members.find(std::string(Basename)); + if (iter == m_deps_base_members.end()) { + m_deps_base_members[std::string(Basename)] = std::vector(); + iter = m_deps_base_members.find(std::string(Basename)); + } + iter->second.push_back(std::string(CurrentStr)); + } + } +#endif + return m_deps_filespec->GetSize(); +} + +uint32_t ObjectFileXCOFF::GetDependentModules(FileSpecList &files) { + auto num_modules = ParseDependentModules(); + auto original_size = files.GetSize(); + + for (unsigned i = 0; i < num_modules; ++i) + files.AppendIfUnique(m_deps_filespec->GetFileSpecAtIndex(i)); + + return files.GetSize() - original_size; +} + +Address ObjectFileXCOFF::GetImageInfoAddress(Target *target) { + return Address(); +} + +lldb_private::Address ObjectFileXCOFF::GetEntryPointAddress() { + if (m_entry_point_address.IsValid()) + return m_entry_point_address; + + if (!ParseHeader() || !IsExecutable()) + return m_entry_point_address; + + SectionList *section_list = GetSectionList(); + addr_t vm_addr = m_xcoff_aux_header.EntryPointAddr; + SectionSP section_sp( + section_list->FindSectionContainingFileAddress(vm_addr)); + if (section_sp) { + lldb::offset_t offset_ptr = section_sp->GetFileOffset() + (vm_addr - section_sp->GetFileAddress()); + vm_addr = m_data.GetU64(&offset_ptr); + } + + if (!section_list) + m_entry_point_address.SetOffset(vm_addr); + else + m_entry_point_address.ResolveAddressUsingFileSections(vm_addr, + section_list); + + return m_entry_point_address; +} + +lldb_private::Address ObjectFileXCOFF::GetBaseAddress() { + return lldb_private::Address(); +} + +ObjectFile::Type ObjectFileXCOFF::CalculateType() { + if (m_xcoff_header.flags & XCOFF::F_EXEC) + return eTypeExecutable; + else if (m_xcoff_header.flags & XCOFF::F_SHROBJ) + return eTypeSharedLibrary; + return eTypeUnknown; +} + +ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { + return eStrataUnknown; +} + +llvm::StringRef +ObjectFileXCOFF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const { + return llvm::StringRef(); +} + +void ObjectFileXCOFF::RelocateSection(lldb_private::Section *section) +{ +} + +std::vector +ObjectFileXCOFF::GetLoadableData(Target &target) { + std::vector loadables; + return loadables; +} + +lldb::WritableDataBufferSP +ObjectFileXCOFF::MapFileDataWritable(const FileSpec &file, uint64_t Size, + uint64_t Offset) { + return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size, + Offset); +} + +ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp, + DataBufferSP data_sp, lldb::offset_t data_offset, + const FileSpec *file, lldb::offset_t file_offset, + lldb::offset_t length) + : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset), + m_xcoff_header(), m_sect_headers(), m_deps_filespec(), m_deps_base_members(), + m_entry_point_address() { + ::memset(&m_xcoff_header, 0, sizeof(m_xcoff_header)); + if (file) + m_file = *file; +} + +ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp, + DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, + addr_t header_addr) + : ObjectFile(module_sp, process_sp, header_addr, header_data_sp), + m_xcoff_header(), m_sect_headers(), m_deps_filespec(), m_deps_base_members(), + m_entry_point_address() { + ::memset(&m_xcoff_header, 0, sizeof(m_xcoff_header)); +} diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h new file mode 100644 index 0000000000000..5a12d16886489 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h @@ -0,0 +1,243 @@ +//===-- ObjectFileXCOFF.h --------------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H + +#include + +#include + +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/UUID.h" +#include "lldb/lldb-private.h" +#include "llvm/Object/XCOFFObjectFile.h" + +/// \class ObjectFileXCOFF +/// Generic XCOFF object file reader. +/// +/// This class provides a generic XCOFF (32/64 bit) reader plugin implementing +/// the ObjectFile protocol. +class ObjectFileXCOFF : public lldb_private::ObjectFile { +public: + // Static Functions + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "xcoff"; } + + static llvm::StringRef GetPluginDescriptionStatic() { + return "XCOFF object file reader."; + } + + static lldb_private::ObjectFile * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length); + + static lldb_private::ObjectFile *CreateMemoryInstance( + const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + + static size_t GetModuleSpecifications(const lldb_private::FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + lldb_private::ModuleSpecList &specs); + + static bool MagicBytesMatch(lldb::DataBufferSP &data_sp, lldb::addr_t offset, + lldb::addr_t length); + + static lldb::SymbolType MapSymbolType(llvm::object::SymbolRef::Type sym_type); + + // PluginInterface protocol + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + // LLVM RTTI support + static char ID; + bool isA(const void *ClassID) const override { + return ClassID == &ID || ObjectFile::isA(ClassID); + } + static bool classof(const ObjectFile *obj) { return obj->isA(&ID); } + + // ObjectFile Protocol. + bool ParseHeader() override; + + bool SetLoadAddress(lldb_private::Target &target, lldb::addr_t value, + bool value_is_offset) override; + + bool SetLoadAddressByType(lldb_private::Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) override; + + lldb::ByteOrder GetByteOrder() const override; + + bool IsExecutable() const override; + + uint32_t GetAddressByteSize() const override; + + lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override; + + void ParseSymtab(lldb_private::Symtab &symtab) override; + + bool IsStripped() override; + + void CreateSections(lldb_private::SectionList &unified_section_list) override; + + void Dump(lldb_private::Stream *s) override; + + lldb_private::ArchSpec GetArchitecture() override; + + lldb_private::UUID GetUUID() override; + + /// Return the contents of the .gnu_debuglink section, if the object file + /// contains it. + std::optional GetDebugLink(); + + uint32_t GetDependentModules(lldb_private::FileSpecList &files) override; + + lldb_private::Address + GetImageInfoAddress(lldb_private::Target *target) override; + + lldb_private::Address GetEntryPointAddress() override; + + lldb_private::Address GetBaseAddress() override; + + ObjectFile::Type CalculateType() override; + + ObjectFile::Strata CalculateStrata() override; + + llvm::StringRef + StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const override; + + void RelocateSection(lldb_private::Section *section) override; + + lldb_private::DataExtractor ReadImageData(uint32_t offset, size_t size); + + ObjectFileXCOFF(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + ObjectFileXCOFF(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + +protected: + + typedef struct xcoff_header { + uint16_t magic; + uint16_t nsects; + uint32_t modtime; + uint64_t symoff; + uint32_t nsyms; + uint16_t auxhdrsize; + uint16_t flags; + } xcoff_header_t; + + typedef struct xcoff_aux_header { + uint16_t AuxMagic; + uint16_t Version; + uint32_t ReservedForDebugger; + uint64_t TextStartAddr; + uint64_t DataStartAddr; + uint64_t TOCAnchorAddr; + uint16_t SecNumOfEntryPoint; + uint16_t SecNumOfText; + uint16_t SecNumOfData; + uint16_t SecNumOfTOC; + uint16_t SecNumOfLoader; + uint16_t SecNumOfBSS; + uint16_t MaxAlignOfText; + uint16_t MaxAlignOfData; + uint16_t ModuleType; + uint8_t CpuFlag; + uint8_t CpuType; + uint8_t TextPageSize; + uint8_t DataPageSize; + uint8_t StackPageSize; + uint8_t FlagAndTDataAlignment; + uint64_t TextSize; + uint64_t InitDataSize; + uint64_t BssDataSize; + uint64_t EntryPointAddr; + uint64_t MaxStackSize; + uint64_t MaxDataSize; + uint16_t SecNumOfTData; + uint16_t SecNumOfTBSS; + uint16_t XCOFF64Flag; + } xcoff_aux_header_t; + + typedef struct section_header { + char name[8]; + uint64_t phyaddr; // Physical Addr + uint64_t vmaddr; // Virtual Addr + uint64_t size; // Section size + uint64_t offset; // File offset to raw data + uint64_t reloff; // Offset to relocations + uint64_t lineoff; // Offset to line table entries + uint32_t nreloc; // Number of relocation entries + uint32_t nline; // Number of line table entries + uint32_t flags; + } section_header_t; + + typedef struct xcoff_symbol { + uint64_t value; + uint32_t offset; + uint16_t sect; + uint16_t type; + uint8_t storage; + uint8_t naux; + } xcoff_symbol_t; + + typedef struct xcoff_sym_csect_aux_entry { + uint32_t section_or_len_low_byte; + uint32_t parameter_hash_index; + uint16_t type_check_sect_num; + uint8_t symbol_alignment_and_type; + uint8_t storage_mapping_class; + uint32_t section_or_len_high_byte; + uint8_t pad; + uint8_t aux_type; + } xcoff_sym_csect_aux_entry_t; + + static bool ParseXCOFFHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + xcoff_header_t &xcoff_header); + bool ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr); + bool ParseSectionHeaders(uint32_t offset); + + std::vector + GetLoadableData(lldb_private::Target &target) override; + + static lldb::WritableDataBufferSP + MapFileDataWritable(const lldb_private::FileSpec &file, uint64_t Size, + uint64_t Offset); + llvm::StringRef GetSectionName(const section_header_t §); + static lldb::SectionType GetSectionType(llvm::StringRef sect_name, + const section_header_t §); + + uint32_t ParseDependentModules(); + typedef std::vector SectionHeaderColl; + +private: + bool CreateBinary(); + + xcoff_header_t m_xcoff_header; + xcoff_aux_header_t m_xcoff_aux_header; + SectionHeaderColl m_sect_headers; + std::unique_ptr m_binary; + lldb_private::Address m_entry_point_address; + std::optional m_deps_filespec; + std::map> m_deps_base_members; +}; + +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H diff --git a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp index e026ffefd645e..106e38b6e25ae 100644 --- a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp +++ b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp @@ -227,7 +227,7 @@ ThreadSP OperatingSystemPython::CreateThreadFromThreadInfo( ThreadList &old_thread_list, std::vector &core_used_map, bool *did_create_ptr) { ThreadSP thread_sp; - tid_t tid = LLDB_INVALID_THREAD_ID; + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; if (!thread_dict.GetValueForKeyAsInteger("tid", tid)) return ThreadSP(); diff --git a/lldb/source/Plugins/Platform/AIX/CMakeLists.txt b/lldb/source/Plugins/Platform/AIX/CMakeLists.txt new file mode 100644 index 0000000000000..85ff0a315eabd --- /dev/null +++ b/lldb/source/Plugins/Platform/AIX/CMakeLists.txt @@ -0,0 +1,13 @@ +add_definitions("-D_ALL_SOURCE") + +add_lldb_library(lldbPluginPlatformAIX PLUGIN + PlatformAIX.cpp + + LINK_LIBS + lldbBreakpoint + lldbCore + lldbHost + lldbInterpreter + lldbTarget + lldbPluginPlatformPOSIX + ) diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp new file mode 100644 index 0000000000000..b6b08b73bec41 --- /dev/null +++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp @@ -0,0 +1,471 @@ +//===-- PlatformAIX.cpp -------------------------------------------------===// +// +// 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 "PlatformAIX.h" +#include "lldb/Host/Config.h" + +#include +#if LLDB_ENABLE_POSIX +#include +#endif + +#include "Utility/ARM64_DWARF_Registers.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/StreamString.h" + +// Define these constants from AIX mman.h for use when targeting remote aix +// systems even when host has different values. + +#if defined(__AIX__) +#include +#endif + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::platform_aix; + +LLDB_PLUGIN_DEFINE(PlatformAIX) + +static uint32_t g_initialize_count = 0; + + +PlatformSP PlatformAIX::CreateInstance(bool force, const ArchSpec *arch) { + Log *log = GetLog(LLDBLog::Platform); + LLDB_LOG(log, "force = {0}, arch=({1}, {2})", force, + arch ? arch->GetArchitectureName() : "", + arch ? arch->GetTriple().getTriple() : ""); + + bool create = force; + if (!create && arch && arch->IsValid()) { + const llvm::Triple &triple = arch->GetTriple(); + switch (triple.getOS()) { + case llvm::Triple::AIX: + create = true; + break; + + default: + break; + } + } + + LLDB_LOG(log, "create = {0}", create); + if (create) { + return PlatformSP(new PlatformAIX(false)); + } + return PlatformSP(); +} + +llvm::StringRef PlatformAIX::GetPluginDescriptionStatic(bool is_host) { + if (is_host) + return "Local AIX user platform plug-in."; + return "Remote AIX user platform plug-in."; +} + +void PlatformAIX::Initialize() { + PlatformPOSIX::Initialize(); + + if (g_initialize_count++ == 0) { +#if defined(__AIX__) + PlatformSP default_platform_sp(new PlatformAIX(true)); + default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); + Platform::SetHostPlatform(default_platform_sp); +#endif + PluginManager::RegisterPlugin( + PlatformAIX::GetPluginNameStatic(false), + PlatformAIX::GetPluginDescriptionStatic(false), + PlatformAIX::CreateInstance, nullptr); + } +} + +void PlatformAIX::Terminate() { + if (g_initialize_count > 0) { + if (--g_initialize_count == 0) { + PluginManager::UnregisterPlugin(PlatformAIX::CreateInstance); + } + } + + PlatformPOSIX::Terminate(); +} + +/// Default Constructor +PlatformAIX::PlatformAIX(bool is_host) + : PlatformPOSIX(is_host) // This is the local host platform +{ + if (is_host) { + ArchSpec hostArch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault); + m_supported_architectures.push_back(hostArch); + if (hostArch.GetTriple().isArch64Bit()) { + m_supported_architectures.push_back( + HostInfo::GetArchitecture(HostInfo::eArchKind32)); + } + } else { + m_supported_architectures = CreateArchList( + {llvm::Triple::x86_64, llvm::Triple::x86, llvm::Triple::arm, + llvm::Triple::aarch64, llvm::Triple::mips64, llvm::Triple::mips64, + llvm::Triple::hexagon, llvm::Triple::mips, llvm::Triple::mips64el, + llvm::Triple::mipsel, llvm::Triple::systemz}, + llvm::Triple::AIX); + } +} + +std::vector +PlatformAIX::GetSupportedArchitectures(const ArchSpec &process_host_arch) { + if (m_remote_platform_sp) + return m_remote_platform_sp->GetSupportedArchitectures(process_host_arch); + return m_supported_architectures; +} + +void PlatformAIX::GetStatus(Stream &strm) { + Platform::GetStatus(strm); + +#if LLDB_ENABLE_POSIX + // Display local kernel information only when we are running in host mode. + // Otherwise, we would end up printing non-AIX information (when running on + // Mac OS for example). + if (IsHost()) { + struct utsname un; + + if (uname(&un)) + return; + + strm.Printf(" Kernel: %s\n", un.sysname); + strm.Printf(" Release: %s\n", un.release); + strm.Printf(" Version: %s\n", un.version); + } +#endif +} + +uint32_t +PlatformAIX::GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) { + uint32_t resume_count = 0; + + // Always resume past the initial stop when we use eLaunchFlagDebug + if (launch_info.GetFlags().Test(eLaunchFlagDebug)) { + // Resume past the stop for the final exec into the true inferior. + ++resume_count; + } + + // If we're not launching a shell, we're done. + const FileSpec &shell = launch_info.GetShell(); + if (!shell) + return resume_count; + + std::string shell_string = shell.GetPath(); + // We're in a shell, so for sure we have to resume past the shell exec. + ++resume_count; + + // Figure out what shell we're planning on using. + const char *shell_name = strrchr(shell_string.c_str(), '/'); + if (shell_name == nullptr) + shell_name = shell_string.c_str(); + else + shell_name++; + + if (strcmp(shell_name, "csh") == 0 || strcmp(shell_name, "tcsh") == 0 || + strcmp(shell_name, "zsh") == 0 || strcmp(shell_name, "sh") == 0) { + // These shells seem to re-exec themselves. Add another resume. + ++resume_count; + } + + return resume_count; +} + +bool PlatformAIX::CanDebugProcess() { + if (IsHost()) { + return true; + } else { + // If we're connected, we can debug. + return IsConnected(); + } +} + +void PlatformAIX::CalculateTrapHandlerSymbolNames() { + m_trap_handlers.push_back(ConstString("_sigtramp")); + m_trap_handlers.push_back(ConstString("__kernel_rt_sigreturn")); + m_trap_handlers.push_back(ConstString("__restore_rt")); +} + +static lldb::UnwindPlanSP GetAArch64TrapHanlderUnwindPlan(ConstString name) { + UnwindPlanSP unwind_plan_sp; + if (name != "__kernel_rt_sigreturn") + return unwind_plan_sp; + + UnwindPlan::RowSP row = std::make_shared(); + row->SetOffset(0); + + // In the signal trampoline frame, sp points to an rt_sigframe[1], which is: + // - 128-byte siginfo struct + // - ucontext struct: + // - 8-byte long (uc_flags) + // - 8-byte pointer (uc_link) + // - 24-byte stack_t + // - 128-byte signal set + // - 8 bytes of padding because sigcontext has 16-byte alignment + // - sigcontext/mcontext_t + // [1] + // https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/signal.c + int32_t offset = 128 + 8 + 8 + 24 + 128 + 8; + // Then sigcontext[2] is: + // - 8 byte fault address + // - 31 8 byte registers + // - 8 byte sp + // - 8 byte pc + // [2] + // https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/sigcontext.h + + // Skip fault address + offset += 8; + row->GetCFAValue().SetIsRegisterPlusOffset(arm64_dwarf::sp, offset); + + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x0, 0 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x1, 1 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x2, 2 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x3, 3 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x4, 4 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x5, 5 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x6, 6 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x7, 7 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x8, 8 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x9, 9 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x10, 10 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x11, 11 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x12, 12 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x13, 13 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x14, 14 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x15, 15 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x16, 16 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x17, 17 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x18, 18 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x19, 19 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x20, 20 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x21, 21 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x22, 22 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x23, 23 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x24, 24 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x25, 25 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x26, 26 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x27, 27 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x28, 28 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::fp, 29 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x30, 30 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::sp, 31 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::pc, 32 * 8, false); + + // The sigcontext may also contain floating point and SVE registers. + // However this would require a dynamic unwind plan so they are not included + // here. + + unwind_plan_sp = std::make_shared(eRegisterKindDWARF); + unwind_plan_sp->AppendRow(row); + unwind_plan_sp->SetSourceName("AArch64 AIX sigcontext"); + unwind_plan_sp->SetSourcedFromCompiler(eLazyBoolYes); + // Because sp is the same throughout the function + unwind_plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolYes); + unwind_plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolYes); + + return unwind_plan_sp; +} + +lldb::UnwindPlanSP +PlatformAIX::GetTrapHandlerUnwindPlan(const llvm::Triple &triple, + ConstString name) { + if (triple.isAArch64()) + return GetAArch64TrapHanlderUnwindPlan(name); + + return {}; +} + +MmapArgList PlatformAIX::GetMmapArgumentList(const ArchSpec &arch, + addr_t addr, addr_t length, + unsigned prot, unsigned flags, + addr_t fd, addr_t offset) { +#if defined(__AIX__) + unsigned flags_platform = MAP_VARIABLE | MAP_PRIVATE | MAP_ANONYMOUS; +#else + unsigned flags_platform = 0; +#endif + MmapArgList args({addr, length, prot, flags_platform, fd, offset}); + return args; +} + +CompilerType PlatformAIX::GetSiginfoType(const llvm::Triple &triple) { + if (!m_type_system_up) + m_type_system_up.reset(new TypeSystemClang("siginfo", triple)); + TypeSystemClang *ast = m_type_system_up.get(); + + bool si_errno_then_code = true; + + switch (triple.getArch()) { + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + // mips has si_code and si_errno swapped + si_errno_then_code = false; + break; + default: + break; + } + + // generic types + CompilerType int_type = ast->GetBasicType(eBasicTypeInt); + CompilerType uint_type = ast->GetBasicType(eBasicTypeUnsignedInt); + CompilerType short_type = ast->GetBasicType(eBasicTypeShort); + CompilerType long_type = ast->GetBasicType(eBasicTypeLong); + CompilerType voidp_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); + + // platform-specific types + CompilerType &pid_type = int_type; + CompilerType &uid_type = uint_type; + CompilerType &clock_type = long_type; + CompilerType &band_type = long_type; + + CompilerType sigval_type = ast->CreateRecordType( + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_sigval_t", + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); + ast->StartTagDeclarationDefinition(sigval_type); + ast->AddFieldToRecordType(sigval_type, "sival_int", int_type, + lldb::eAccessPublic, 0); + ast->AddFieldToRecordType(sigval_type, "sival_ptr", voidp_type, + lldb::eAccessPublic, 0); + ast->CompleteTagDeclarationDefinition(sigval_type); + + CompilerType sigfault_bounds_type = ast->CreateRecordType( + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); + ast->StartTagDeclarationDefinition(sigfault_bounds_type); + ast->AddFieldToRecordType(sigfault_bounds_type, "_addr_bnd", + ast->CreateStructForIdentifier(ConstString(), + { + {"_lower", voidp_type}, + {"_upper", voidp_type}, + }), + lldb::eAccessPublic, 0); + ast->AddFieldToRecordType(sigfault_bounds_type, "_pkey", uint_type, + lldb::eAccessPublic, 0); + ast->CompleteTagDeclarationDefinition(sigfault_bounds_type); + + // siginfo_t + CompilerType siginfo_type = ast->CreateRecordType( + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_siginfo_t", + llvm::to_underlying(clang::TagTypeKind::Struct), lldb::eLanguageTypeC); + ast->StartTagDeclarationDefinition(siginfo_type); + ast->AddFieldToRecordType(siginfo_type, "si_signo", int_type, + lldb::eAccessPublic, 0); + + if (si_errno_then_code) { + ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type, + lldb::eAccessPublic, 0); + ast->AddFieldToRecordType(siginfo_type, "si_code", int_type, + lldb::eAccessPublic, 0); + } else { + ast->AddFieldToRecordType(siginfo_type, "si_code", int_type, + lldb::eAccessPublic, 0); + ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type, + lldb::eAccessPublic, 0); + } + + // the structure is padded on 64-bit arches to fix alignment + if (triple.isArch64Bit()) + ast->AddFieldToRecordType(siginfo_type, "__pad0", int_type, + lldb::eAccessPublic, 0); + + // union used to hold the signal data + CompilerType union_type = ast->CreateRecordType( + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); + ast->StartTagDeclarationDefinition(union_type); + + ast->AddFieldToRecordType( + union_type, "_kill", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_pid", pid_type}, + {"si_uid", uid_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_timer", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_tid", int_type}, + {"si_overrun", int_type}, + {"si_sigval", sigval_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_rt", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_pid", pid_type}, + {"si_uid", uid_type}, + {"si_sigval", sigval_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_sigchld", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_pid", pid_type}, + {"si_uid", uid_type}, + {"si_status", int_type}, + {"si_utime", clock_type}, + {"si_stime", clock_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_sigfault", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_addr", voidp_type}, + {"si_addr_lsb", short_type}, + {"_bounds", sigfault_bounds_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_sigpoll", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_band", band_type}, + {"si_fd", int_type}, + }), + lldb::eAccessPublic, 0); + + // NB: SIGSYS is not present on ia64 but we don't seem to support that + ast->AddFieldToRecordType( + union_type, "_sigsys", + ast->CreateStructForIdentifier(ConstString(), + { + {"_call_addr", voidp_type}, + {"_syscall", int_type}, + {"_arch", uint_type}, + }), + lldb::eAccessPublic, 0); + + ast->CompleteTagDeclarationDefinition(union_type); + ast->AddFieldToRecordType(siginfo_type, "_sifields", union_type, + lldb::eAccessPublic, 0); + + ast->CompleteTagDeclarationDefinition(siginfo_type); + return siginfo_type; +} diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.h b/lldb/source/Plugins/Platform/AIX/PlatformAIX.h new file mode 100644 index 0000000000000..3ae8089a48d71 --- /dev/null +++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.h @@ -0,0 +1,74 @@ +//===-- PlatformAIX.h -----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PLATFORM_AIX_PLATFORMAIX_H +#define LLDB_SOURCE_PLUGINS_PLATFORM_AIX_PLATFORMAIX_H + +#include "Plugins/Platform/POSIX/PlatformPOSIX.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" + +namespace lldb_private { +namespace platform_aix { + +class PlatformAIX : public PlatformPOSIX { +public: + PlatformAIX(bool is_host); + + static void Initialize(); + + static void Terminate(); + + // lldb_private::PluginInterface functions + static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch); + + static llvm::StringRef GetPluginNameStatic(bool is_host) { + return is_host ? Platform::GetHostPlatformName() : "remote-AIX"; + } + + static llvm::StringRef GetPluginDescriptionStatic(bool is_host); + + llvm::StringRef GetPluginName() override { + return GetPluginNameStatic(IsHost()); + } + + // lldb_private::Platform functions + llvm::StringRef GetDescription() override { + return GetPluginDescriptionStatic(IsHost()); + } + + void GetStatus(Stream &strm) override; + + std::vector + GetSupportedArchitectures(const ArchSpec &process_host_arch) override; + + uint32_t GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) override; + + bool CanDebugProcess() override; + + void CalculateTrapHandlerSymbolNames() override; + + lldb::UnwindPlanSP GetTrapHandlerUnwindPlan(const llvm::Triple &triple, + ConstString name) override; + + MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr, + lldb::addr_t length, unsigned prot, + unsigned flags, lldb::addr_t fd, + lldb::addr_t offset) override; + + CompilerType GetSiginfoType(const llvm::Triple &triple) override; + + std::vector m_supported_architectures; + +private: + std::unique_ptr m_type_system_up; +}; + +} // namespace platform_AIX +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_PLATFORM_AIX_PLATFORMAIX_H diff --git a/lldb/source/Plugins/Platform/CMakeLists.txt b/lldb/source/Plugins/Platform/CMakeLists.txt index 6869587f917eb..9d0afd97cff85 100644 --- a/lldb/source/Plugins/Platform/CMakeLists.txt +++ b/lldb/source/Plugins/Platform/CMakeLists.txt @@ -8,3 +8,4 @@ add_subdirectory(OpenBSD) add_subdirectory(POSIX) add_subdirectory(QemuUser) add_subdirectory(Windows) +add_subdirectory(AIX) diff --git a/lldb/source/Plugins/Process/AIX/CMakeLists.txt b/lldb/source/Plugins/Process/AIX/CMakeLists.txt new file mode 100644 index 0000000000000..e9d83266f5857 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/CMakeLists.txt @@ -0,0 +1,19 @@ +add_definitions("-D_ALL_SOURCE") + +add_lldb_library(lldbPluginProcessAIX + NativeProcessAIX.cpp + NativeRegisterContextAIX.cpp + NativeRegisterContextAIX_ppc64.cpp + NativeThreadAIX.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + lldbTarget + lldbUtility + lldbPluginProcessPOSIX + lldbPluginProcessUtility + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp new file mode 100644 index 0000000000000..882f20d30a3bf --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -0,0 +1,2048 @@ +//===-- NativeProcessAIX.cpp --------------------------------------------===// +// +// 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 "NativeProcessAIX.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "NativeThreadAIX.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +//#include "Plugins/Process/Utility/LinuxProcMaps.h" +//#include "Procfs.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/HostProcess.h" +#include "lldb/Host/ProcessLaunchInfo.h" +#include "lldb/Host/PseudoTerminal.h" +#include "lldb/Host/ThreadLauncher.h" +#include "lldb/Host/common/NativeRegisterContext.h" +#include "lldb/Host/aix/Ptrace.h" +//#include "lldb/Host/linux/Host.h" +//#include "lldb/Host/linux/Uio.h" +#include "lldb/Host/posix/ProcessLauncherPosixFork.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/State.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/StringExtractor.h" +#include "llvm/ADT/ScopeExit.h" +#include "llvm/Support/Errno.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Threading.h" + +#include +#include +#include +#include +//#include +#include +#include +#include +#include + +#ifdef __aarch64__ +#include +#include +#endif + +// Support hardware breakpoints in case it has not been defined +#ifndef TRAP_HWBKPT +#define TRAP_HWBKPT 4 +#endif + +#ifndef HWCAP2_MTE +#define HWCAP2_MTE (1 << 18) +#endif + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; +using namespace llvm; + +// Private bits we only need internally. + +static bool ProcessVmReadvSupported() { + static bool is_supported; + static llvm::once_flag flag; + + llvm::call_once(flag, [] { + Log *log = GetLog(POSIXLog::Process); + + uint32_t source = 0x47424742; + uint32_t dest = 0; + + struct iovec local, remote; + remote.iov_base = &source; + local.iov_base = &dest; + remote.iov_len = local.iov_len = sizeof source; + +#if 0 + // We shall try if cross-process-memory reads work by attempting to read a + // value from our own process. + ssize_t res = process_vm_readv(getpid(), &local, 1, &remote, 1, 0); + is_supported = (res == sizeof(source) && source == dest); + if (is_supported) + LLDB_LOG(log, + "Detected kernel support for process_vm_readv syscall. " + "Fast memory reads enabled."); + else + LLDB_LOG(log, + "syscall process_vm_readv failed (error: {0}). Fast memory " + "reads disabled.", + llvm::sys::StrError()); +#endif + }); + + return is_supported; +} + +static void MaybeLogLaunchInfo(const ProcessLaunchInfo &info) { + Log *log = GetLog(POSIXLog::Process); + if (!log) + return; + + if (const FileAction *action = info.GetFileActionForFD(STDIN_FILENO)) + LLDB_LOG(log, "setting STDIN to '{0}'", action->GetFileSpec()); + else + LLDB_LOG(log, "leaving STDIN as is"); + + if (const FileAction *action = info.GetFileActionForFD(STDOUT_FILENO)) + LLDB_LOG(log, "setting STDOUT to '{0}'", action->GetFileSpec()); + else + LLDB_LOG(log, "leaving STDOUT as is"); + + if (const FileAction *action = info.GetFileActionForFD(STDERR_FILENO)) + LLDB_LOG(log, "setting STDERR to '{0}'", action->GetFileSpec()); + else + LLDB_LOG(log, "leaving STDERR as is"); + + int i = 0; + for (const char **args = info.GetArguments().GetConstArgumentVector(); *args; + ++args, ++i) + LLDB_LOG(log, "arg {0}: '{1}'", i, *args); +} + +static void DisplayBytes(StreamString &s, void *bytes, uint32_t count) { + uint8_t *ptr = (uint8_t *)bytes; + const uint32_t loop_count = std::min(DEBUG_PTRACE_MAXBYTES, count); + for (uint32_t i = 0; i < loop_count; i++) { + s.Printf("[%x]", *ptr); + ptr++; + } +} + +static void PtraceDisplayBytes(int &req, void *data, size_t data_size) { + Log *log = GetLog(POSIXLog::Ptrace); + if (!log) + return; + StreamString buf; + + switch (req) { + case PTRACE_POKETEXT: { + DisplayBytes(buf, &data, 8); + LLDB_LOGV(log, "PTRACE_POKETEXT {0}", buf.GetData()); + break; + } + case PTRACE_POKEDATA: { + DisplayBytes(buf, &data, 8); + LLDB_LOGV(log, "PTRACE_POKEDATA {0}", buf.GetData()); + break; + } + case PTRACE_POKEUSER: { + DisplayBytes(buf, &data, 8); + LLDB_LOGV(log, "PTRACE_POKEUSER {0}", buf.GetData()); + break; + } + case PTRACE_SETREGS: { + DisplayBytes(buf, data, data_size); + LLDB_LOGV(log, "PTRACE_SETREGS {0}", buf.GetData()); + break; + } + case PTRACE_SETFPREGS: { + DisplayBytes(buf, data, data_size); + LLDB_LOGV(log, "PTRACE_SETFPREGS {0}", buf.GetData()); + break; + } +#if 0 + case PTRACE_SETSIGINFO: { + DisplayBytes(buf, data, sizeof(siginfo_t)); + LLDB_LOGV(log, "PTRACE_SETSIGINFO {0}", buf.GetData()); + break; + } +#endif + case PTRACE_SETREGSET: { + // Extract iov_base from data, which is a pointer to the struct iovec + DisplayBytes(buf, *(void **)data, data_size); + LLDB_LOGV(log, "PTRACE_SETREGSET {0}", buf.GetData()); + break; + } + default: {} + } +} + +static constexpr unsigned k_ptrace_word_size = sizeof(void *); +static_assert(sizeof(long) >= k_ptrace_word_size, + "Size of long must be larger than ptrace word size"); + +// Simple helper function to ensure flags are enabled on the given file +// descriptor. +static Status EnsureFDFlags(int fd, int flags) { + Status error; + + int status = fcntl(fd, F_GETFL); + if (status == -1) { + error.SetErrorToErrno(); + return error; + } + + if (fcntl(fd, F_SETFL, status | flags) == -1) { + error.SetErrorToErrno(); + return error; + } + + return error; +} + +#if 0 +static llvm::Error AddPtraceScopeNote(llvm::Error original_error) { + Expected ptrace_scope = GetPtraceScope(); + if (auto E = ptrace_scope.takeError()) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "error reading value of ptrace_scope: {0}", E); + + // The original error is probably more interesting than not being able to + // read or interpret ptrace_scope. + return original_error; + } + + // We only have suggestions to provide for 1-3. + switch (*ptrace_scope) { + case 1: + case 2: + return llvm::createStringError( + std::error_code(errno, std::generic_category()), + "The current value of ptrace_scope is %d, which can cause ptrace to " + "fail to attach to a running process. To fix this, run:\n" + "\tsudo sysctl -w kernel.yama.ptrace_scope=0\n" + "For more information, see: " + "https://www.kernel.org/doc/Documentation/security/Yama.txt.", + *ptrace_scope); + case 3: + return llvm::createStringError( + std::error_code(errno, std::generic_category()), + "The current value of ptrace_scope is 3, which will cause ptrace to " + "fail to attach to a running process. This value cannot be changed " + "without rebooting.\n" + "For more information, see: " + "https://www.kernel.org/doc/Documentation/security/Yama.txt."); + case 0: + default: + return original_error; + } +} +#endif + +NativeProcessAIX::Manager::Manager(MainLoop &mainloop) + : NativeProcessProtocol::Manager(mainloop) { + Status status; + m_sigchld_handle = mainloop.RegisterSignal( + SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status); + assert(m_sigchld_handle && status.Success()); +} + +// Public Static Methods + +llvm::Expected> +NativeProcessAIX::Manager::Launch(ProcessLaunchInfo &launch_info, + NativeDelegate &native_delegate) { + Log *log = GetLog(POSIXLog::Process); + + MaybeLogLaunchInfo(launch_info); + + Status status; + ::pid_t pid = ProcessLauncherPosixFork() + .LaunchProcess(launch_info, status) + .GetProcessId(); + LLDB_LOG(log, "pid = {0:x}", pid); + if (status.Fail()) { + LLDB_LOG(log, "failed to launch process: {0}", status); + return status.ToError(); + } + + // Wait for the child process to trap on its call to execve. + int wstatus = 0; + ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0); + assert(wpid == pid); + UNUSED_IF_ASSERT_DISABLED(wpid); + if (!WIFSTOPPED(wstatus)) { + LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}", + WaitStatus::Decode(wstatus)); + return llvm::make_error("Could not sync with inferior process", + llvm::inconvertibleErrorCode()); + } + LLDB_LOG(log, "inferior started, now in stopped state"); + + ProcessInstanceInfo Info; + if (!Host::GetProcessInfo(pid, Info)) { + return llvm::make_error("Cannot get process architectrue", + llvm::inconvertibleErrorCode()); + } + /*llvm::Expected arch_or = + NativeRegisterContextAIX::DetermineArchitecture(pid); + if (!arch_or) + return arch_or.takeError();*/ + + // Set the architecture to the exe architecture. + LLDB_LOG(log, "pid = {0}, detected architecture {1}", pid, + Info.GetArchitecture().GetArchitectureName()); + + return std::unique_ptr(new NativeProcessAIX( + pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate, + Info.GetArchitecture(), *this, {pid})); +} + +llvm::Expected> +NativeProcessAIX::Manager::Attach( + lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "pid = {0:x}", pid); + + ProcessInstanceInfo Info; + if (!Host::GetProcessInfo(pid, Info)) { + return llvm::make_error("Cannot get process architectrue", + llvm::inconvertibleErrorCode()); + } + auto tids_or = NativeProcessAIX::Attach(pid); + if (!tids_or) + return tids_or.takeError(); +#if 0 + ArrayRef<::pid_t> tids = *tids_or; + llvm::Expected arch_or = + NativeRegisterContextAIX::DetermineArchitecture(tids[0]); + if (!arch_or) + return arch_or.takeError(); +#endif + + return std::unique_ptr( + new NativeProcessAIX(pid, -1, native_delegate, Info.GetArchitecture(), *this, *tids_or)); +} + +lldb::addr_t NativeProcessAIX::GetSharedLibraryInfoAddress() { + // punt on this for now + return LLDB_INVALID_ADDRESS; +} + +NativeProcessAIX::Extension +NativeProcessAIX::Manager::GetSupportedExtensions() const { + NativeProcessAIX::Extension supported = + Extension::multiprocess | Extension::fork | Extension::vfork | + Extension::pass_signals | Extension::auxv | Extension::libraries_svr4 | + Extension::siginfo_read; + +#ifdef __aarch64__ + // At this point we do not have a process so read auxv directly. + if ((getauxval(AT_HWCAP2) & HWCAP2_MTE)) + supported |= Extension::memory_tagging; +#endif + + return supported; +} + +static std::optional> WaitPid() { + Log *log = GetLog(POSIXLog::Process); + + int status; + ::pid_t wait_pid = llvm::sys::RetryAfterSignal( + -1, ::waitpid, -1, &status, /*__WALL | __WNOTHREAD |*/ WNOHANG); + + if (wait_pid == 0) + return std::nullopt; + + if (wait_pid == -1) { + Status error(errno, eErrorTypePOSIX); + LLDB_LOG(log, "waitpid(-1, &status, _) failed: {1}", error); + return std::nullopt; + } + + WaitStatus wait_status = WaitStatus::Decode(status); + + LLDB_LOG(log, "waitpid(-1, &status, _) = {0}, status = {1}", wait_pid, + wait_status); + return std::make_pair(wait_pid, wait_status); +} + +void NativeProcessAIX::Manager::SigchldHandler() { + Log *log = GetLog(POSIXLog::Process); + while (true) { + auto wait_result = WaitPid(); + if (!wait_result) + return; + lldb::pid_t pid = wait_result->first; + WaitStatus status = wait_result->second; + + // Ask each process whether it wants to handle the event. Each event should + // be handled by exactly one process, but thread creation events require + // special handling. + // Thread creation consists of two events (one on the parent and one on the + // child thread) and they can arrive in any order nondeterministically. The + // parent event carries the information about the child thread, but not + // vice-versa. This means that if the child event arrives first, it may not + // be handled by any process (because it doesn't know the thread belongs to + // it). + bool handled = llvm::any_of(m_processes, [&](NativeProcessAIX *process) { + return process->TryHandleWaitStatus(pid, status); + }); + if (!handled) { + if (status.type == WaitStatus::Stop && status.status == SIGSTOP) { + // Store the thread creation event for later collection. + m_unowned_threads.insert(pid); + } else { + LLDB_LOG(log, "Ignoring waitpid event {0} for pid {1}", status, pid); + } + } + } +} + +void NativeProcessAIX::Manager::CollectThread(::pid_t tid) { + Log *log = GetLog(POSIXLog::Process); + + if (m_unowned_threads.erase(tid)) + return; // We've encountered this thread already. + + // The TID is not tracked yet, let's wait for it to appear. + int status = -1; + LLDB_LOG(log, + "received clone event for tid {0}. tid not tracked yet, " + "waiting for it to appear...", + tid); + ::pid_t wait_pid = + llvm::sys::RetryAfterSignal(-1, ::waitpid, tid, &status, P_ALL/*__WALL*/); + + // It's theoretically possible to get other events if the entire process was + // SIGKILLed before we got a chance to check this. In that case, we'll just + // clean everything up when we get the process exit event. + + LLDB_LOG(log, + "waitpid({0}, &status, __WALL) => {1} (errno: {2}, status = {3})", + tid, wait_pid, errno, WaitStatus::Decode(status)); +} + +// Public Instance Methods + +NativeProcessAIX::NativeProcessAIX(::pid_t pid, int terminal_fd, + NativeDelegate &delegate, + const ArchSpec &arch, Manager &manager, + llvm::ArrayRef<::pid_t> tids) + : NativeProcessProtocol(pid, terminal_fd, delegate), m_manager(manager), + m_arch(arch) { + manager.AddProcess(*this); + if (m_terminal_fd != -1) { + Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK); + assert(status.Success()); + } + + for (const auto &tid : tids) { + NativeThreadAIX &thread = AddThread(tid, /*resume*/ false); + ThreadWasCreated(thread); + } + + // Let our process instance know the thread has stopped. + SetCurrentThreadID(tids[0]); + SetState(StateType::eStateStopped, false); +} + +llvm::Expected> NativeProcessAIX::Attach(::pid_t pid) { + Log *log = GetLog(POSIXLog::Process); + + Status status; + if ((status = PtraceWrapper(PT_ATTACH, pid)).Fail()) { + return status.ToError(); + } + + int wpid = + llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, nullptr, WNOHANG); + if (wpid <= 0) { + return llvm::errorCodeToError( + std::error_code(errno, std::generic_category())); + } + + LLDB_LOG(log, "adding pid = {0}", pid); + + std::vector<::pid_t> tids; + tids.push_back(pid); + return std::move(tids); +} + +bool NativeProcessAIX::TryHandleWaitStatus(lldb::pid_t pid, + WaitStatus status) { + if (pid == GetID() && + (status.type == WaitStatus::Exit || status.type == WaitStatus::Signal)) { + // The process exited. We're done monitoring. Report to delegate. + SetExitStatus(status, true); + return true; + } + if (NativeThreadAIX *thread = GetThreadByID(pid)) { + MonitorCallback(*thread, status); + return true; + } + return false; +} + +// Handles all waitpid events from the inferior process. +void NativeProcessAIX::MonitorCallback(NativeThreadAIX &thread, + WaitStatus status) { + Log *log = GetLog(LLDBLog::Process); + + // Certain activities differ based on whether the pid is the tid of the main + // thread. + const bool is_main_thread = (thread.GetID() == GetID()); + + // Handle when the thread exits. + if (status.type == WaitStatus::Exit || status.type == WaitStatus::Signal) { + LLDB_LOG(log, + "got exit status({0}) , tid = {1} ({2} main thread), process " + "state = {3}", + status, thread.GetID(), is_main_thread ? "is" : "is not", + GetState()); + + // This is a thread that exited. Ensure we're not tracking it anymore. + StopTrackingThread(thread); + + assert(!is_main_thread && "Main thread exits handled elsewhere"); + return; + } + + int8_t signo = GetSignalInfo(status); + + // Get details on the signal raised. + if (signo) { + // We have retrieved the signal info. Dispatch appropriately. + if (signo == SIGTRAP) + MonitorSIGTRAP(status, thread); + else + MonitorSignal(status, thread); + } else { + assert(0); + } +} + + +void NativeProcessAIX::MonitorSIGTRAP(const WaitStatus status, + NativeThreadAIX &thread) { + Log *log = GetLog(POSIXLog::Process); + const bool is_main_thread = (thread.GetID() == GetID()); + + NativeRegisterContextAIX ®_ctx = thread.GetRegisterContext(); + const RegisterInfo *pc_info = reg_ctx.GetRegisterInfoByName("pc", 0); + RegisterValue pc_value; + + switch (status.status) { + case SIGTRAP: + // Determine the source of SIGTRAP by checking current instruction: + // if that is trap instruction, then this is breakpoint, otherwise + // this is watchpoint. + reg_ctx.ReadRegister(pc_info, pc_value); + + MonitorBreakpoint(thread); + break; + default: + LLDB_LOG(log, "received unknown SIGTRAP stop event ({0}, pid {1} tid {2}", + status.status, GetID(), thread.GetID()); + MonitorSignal(status, thread); + break; + } +} + +void NativeProcessAIX::MonitorTrace(NativeThreadAIX &thread) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "received trace event, pid = {0}", thread.GetID()); + + // This thread is currently stopped. + thread.SetStoppedByTrace(); + + StopRunningThreads(thread.GetID()); +} + +void NativeProcessAIX::MonitorBreakpoint(NativeThreadAIX &thread) { + Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints); + LLDB_LOG(log, "received breakpoint event, pid = {0}", thread.GetID()); + + // Mark the thread as stopped at breakpoint. + thread.SetStoppedByBreakpoint(); + FixupBreakpointPCAsNeeded(thread); + + if (m_threads_stepping_with_breakpoint.find(thread.GetID()) != + m_threads_stepping_with_breakpoint.end()) + thread.SetStoppedByTrace(); + + StopRunningThreads(thread.GetID()); +} + +void NativeProcessAIX::MonitorWatchpoint(NativeThreadAIX &thread, + uint32_t wp_index) { + Log *log = GetLog(LLDBLog::Process | LLDBLog::Watchpoints); + LLDB_LOG(log, "received watchpoint event, pid = {0}, wp_index = {1}", + thread.GetID(), wp_index); + + // Mark the thread as stopped at watchpoint. The address is at + // (lldb::addr_t)info->si_addr if we need it. + thread.SetStoppedByWatchpoint(wp_index); + + // We need to tell all other running threads before we notify the delegate + // about this stop. + StopRunningThreads(thread.GetID()); +} + +void NativeProcessAIX::MonitorSignal(const WaitStatus status, + NativeThreadAIX &thread) { + int8_t signo = GetSignalInfo(status); +#if 0 + const bool is_from_llgs = info.si_pid == getpid(); +#endif + + Log *log = GetLog(POSIXLog::Process); + + // POSIX says that process behaviour is undefined after it ignores a SIGFPE, + // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a kill(2) + // or raise(3). Similarly for tgkill(2) on AIX. + // + // IOW, user generated signals never generate what we consider to be a + // "crash". + // + // Similarly, ACK signals generated by this monitor. + + // Handle the signal. + LLDB_LOG(log, + "received signal {0} ({1}) with code NA, (siginfo pid = {2}, " + "waitpid pid = {3})", + Host::GetSignalAsCString(signo), signo, thread.GetID(), GetID()); + +#if 0 + // Check for thread stop notification. + // FIXME + if (is_from_llgs /*&& (info.si_code == SI_TKILL)*/ && (signo == SIGSTOP)) { + // This is a tgkill()-based stop. + LLDB_LOG(log, "pid {0} tid {1}, thread stopped", GetID(), thread.GetID()); + + // Check that we're not already marked with a stop reason. Note this thread + // really shouldn't already be marked as stopped - if we were, that would + // imply that the kernel signaled us with the thread stopping which we + // handled and marked as stopped, and that, without an intervening resume, + // we received another stop. It is more likely that we are missing the + // marking of a run state somewhere if we find that the thread was marked + // as stopped. + const StateType thread_state = thread.GetState(); + if (!StateIsStoppedState(thread_state, false)) { + // An inferior thread has stopped because of a SIGSTOP we have sent it. + // Generally, these are not important stops and we don't want to report + // them as they are just used to stop other threads when one thread (the + // one with the *real* stop reason) hits a breakpoint (watchpoint, + // etc...). However, in the case of an asynchronous Interrupt(), this + // *is* the real stop reason, so we leave the signal intact if this is + // the thread that was chosen as the triggering thread. + if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID) { + if (m_pending_notification_tid == thread.GetID()) + thread.SetStoppedBySignal(SIGSTOP, &info); + else + thread.SetStoppedWithNoReason(); + + SetCurrentThreadID(thread.GetID()); + SignalIfAllThreadsStopped(); + } else { + // We can end up here if stop was initiated by LLGS but by this time a + // thread stop has occurred - maybe initiated by another event. + Status error = ResumeThread(thread, thread.GetState(), 0); + if (error.Fail()) + LLDB_LOG(log, "failed to resume thread {0}: {1}", thread.GetID(), + error); + } + } else { + LLDB_LOG(log, + "pid {0} tid {1}, thread was already marked as a stopped " + "state (state={2}), leaving stop signal as is", + GetID(), thread.GetID(), thread_state); + SignalIfAllThreadsStopped(); + } + + // Done handling. + return; + } +#endif + + // Check if debugger should stop at this signal or just ignore it and resume + // the inferior. + if (m_signals_to_ignore.contains(signo) || signo == SIGCHLD) { + ResumeThread(thread, thread.GetState(), signo); + return; + } + + // This thread is stopped. + LLDB_LOG(log, "received signal {0}", Host::GetSignalAsCString(signo)); + thread.SetStoppedBySignal(signo); + + // Send a stop to the debugger after we get all other threads to stop. + StopRunningThreads(thread.GetID()); +} + +bool NativeProcessAIX::MonitorClone(NativeThreadAIX &parent, + lldb::pid_t child_pid, int event) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "parent_tid={0}, child_pid={1}, event={2}", parent.GetID(), + child_pid, event); + + // WaitForCloneNotification(child_pid); + + switch (event) { +#if 0 + case PTRACE_EVENT_CLONE: { + // PTRACE_EVENT_CLONE can either mean a new thread or a new process. + // Try to grab the new process' PGID to figure out which one it is. + // If PGID is the same as the PID, then it's a new process. Otherwise, + // it's a thread. + auto tgid_ret = getPIDForTID(child_pid); + if (tgid_ret != child_pid) { + // A new thread should have PGID matching our process' PID. + assert(!tgid_ret || tgid_ret.getValue() == GetID()); + + NativeThreadAIX &child_thread = AddThread(child_pid, /*resume*/ true); + ThreadWasCreated(child_thread); + + // Resume the parent. + ResumeThread(parent, parent.GetState(), LLDB_INVALID_SIGNAL_NUMBER); + break; + } + } + LLVM_FALLTHROUGH; + case PTRACE_EVENT_FORK: + case PTRACE_EVENT_VFORK: { + bool is_vfork = event == PTRACE_EVENT_VFORK; + std::unique_ptr child_process{new NativeProcessAIX( + static_cast<::pid_t>(child_pid), m_terminal_fd, m_delegate, m_arch, + m_main_loop, {static_cast<::pid_t>(child_pid)})}; + if (!is_vfork) + child_process->m_software_breakpoints = m_software_breakpoints; + + Extension expected_ext = is_vfork ? Extension::vfork : Extension::fork; + if (bool(m_enabled_extensions & expected_ext)) { + m_delegate.NewSubprocess(this, std::move(child_process)); + // NB: non-vfork clone() is reported as fork + parent.SetStoppedByFork(is_vfork, child_pid); + StopRunningThreads(parent.GetID()); + } else { + child_process->Detach(); + ResumeThread(parent, parent.GetState(), LLDB_INVALID_SIGNAL_NUMBER); + } + break; + } +#endif + default: + llvm_unreachable("unknown clone_info.event"); + } + + return true; +} + +bool NativeProcessAIX::SupportHardwareSingleStepping() const { + return false; +} + +Status NativeProcessAIX::Resume(const ResumeActionList &resume_actions) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "pid {0}", GetID()); + + bool software_single_step = !SupportHardwareSingleStepping(); + + if (software_single_step) { + for (const auto &thread : m_threads) { + assert(thread && "thread list should not contain NULL threads"); + + const ResumeAction *const action = + resume_actions.GetActionForThread(thread->GetID(), true); + if (action == nullptr) + continue; + + if (action->state == eStateStepping) { + Status error = SetupSoftwareSingleStepping( + static_cast(*thread)); + if (error.Fail()) + return error; + } + } + } + + for (const auto &thread : m_threads) { + assert(thread && "thread list should not contain NULL threads"); + + const ResumeAction *const action = + resume_actions.GetActionForThread(thread->GetID(), true); + + if (action == nullptr) { + LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(), + thread->GetID()); + continue; + } + + LLDB_LOG(log, "processing resume action state {0} for pid {1} tid {2}", + action->state, GetID(), thread->GetID()); + + switch (action->state) { + case eStateRunning: + case eStateStepping: { + // Run the thread, possibly feeding it the signal. + const int signo = action->signal; + Status error = ResumeThread(static_cast(*thread), + action->state, signo); + if (error.Fail()) + return Status("NativeProcessAIX::%s: failed to resume thread " + "for pid %" PRIu64 ", tid %" PRIu64 ", error = %s", + __FUNCTION__, GetID(), thread->GetID(), + error.AsCString()); + + break; + } + + case eStateSuspended: + case eStateStopped: + break; + + default: + return Status("NativeProcessAIX::%s (): unexpected state %s specified " + "for pid %" PRIu64 ", tid %" PRIu64, + __FUNCTION__, StateAsCString(action->state), GetID(), + thread->GetID()); + } + } + + return Status(); +} + +Status NativeProcessAIX::Halt() { + Status error; + + if (kill(GetID(), SIGSTOP) != 0) + error.SetErrorToErrno(); + + return error; +} + +Status NativeProcessAIX::Detach() { + Status error; + + // Tell ptrace to detach from the process. + if (GetID() == LLDB_INVALID_PROCESS_ID) + return error; + + // Cancel out any SIGSTOPs we may have sent while stopping the process. + // Otherwise, the process may stop as soon as we detach from it. + kill(GetID(), SIGCONT); + + for (const auto &thread : m_threads) { + Status e = Detach(thread->GetID()); + if (e.Fail()) + error = + e; // Save the error, but still attempt to detach from other threads. + } + + return error; +} + +Status NativeProcessAIX::Signal(int signo) { + Status error; + + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "sending signal {0} ({1}) to pid {1}", signo, + Host::GetSignalAsCString(signo), GetID()); + + if (kill(GetID(), signo)) + error.SetErrorToErrno(); + + return error; +} + +Status NativeProcessAIX::Interrupt() { + // Pick a running thread (or if none, a not-dead stopped thread) as the + // chosen thread that will be the stop-reason thread. + Log *log = GetLog(POSIXLog::Process); + + NativeThreadProtocol *running_thread = nullptr; + NativeThreadProtocol *stopped_thread = nullptr; + + LLDB_LOG(log, "selecting running thread for interrupt target"); + for (const auto &thread : m_threads) { + // If we have a running or stepping thread, we'll call that the target of + // the interrupt. + const auto thread_state = thread->GetState(); + if (thread_state == eStateRunning || thread_state == eStateStepping) { + running_thread = thread.get(); + break; + } else if (!stopped_thread && StateIsStoppedState(thread_state, true)) { + // Remember the first non-dead stopped thread. We'll use that as a + // backup if there are no running threads. + stopped_thread = thread.get(); + } + } + + if (!running_thread && !stopped_thread) { + Status error("found no running/stepping or live stopped threads as target " + "for interrupt"); + LLDB_LOG(log, "skipping due to error: {0}", error); + + return error; + } + + NativeThreadProtocol *deferred_signal_thread = + running_thread ? running_thread : stopped_thread; + + LLDB_LOG(log, "pid {0} {1} tid {2} chosen for interrupt target", GetID(), + running_thread ? "running" : "stopped", + deferred_signal_thread->GetID()); + + StopRunningThreads(deferred_signal_thread->GetID()); + + return Status(); +} + +Status NativeProcessAIX::Kill() { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "pid {0}", GetID()); + + Status error; + + switch (m_state) { + case StateType::eStateInvalid: + case StateType::eStateExited: + case StateType::eStateCrashed: + case StateType::eStateDetached: + case StateType::eStateUnloaded: + // Nothing to do - the process is already dead. + LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(), + m_state); + return error; + + case StateType::eStateConnected: + case StateType::eStateAttaching: + case StateType::eStateLaunching: + case StateType::eStateStopped: + case StateType::eStateRunning: + case StateType::eStateStepping: + case StateType::eStateSuspended: + // We can try to kill a process in these states. + break; + } + + if (kill(GetID(), SIGKILL) != 0) { + error.SetErrorToErrno(); + return error; + } + + return error; +} + +Status NativeProcessAIX::GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info) { + // FIXME review that the final memory region returned extends to the end of + // the virtual address space, + // with no perms if it is not mapped. + + // Use an approach that reads memory regions from /proc/{pid}/maps. Assume + // proc maps entries are in ascending order. + // FIXME assert if we find differently. + + if (m_supports_mem_region == LazyBool::eLazyBoolNo) { + // We're done. + return Status("unsupported"); + } + + Status error = PopulateMemoryRegionCache(); + if (error.Fail()) { + return error; + } + + lldb::addr_t prev_base_address = 0; + + // FIXME start by finding the last region that is <= target address using + // binary search. Data is sorted. + // There can be a ton of regions on pthreads apps with lots of threads. + for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end(); + ++it) { + MemoryRegionInfo &proc_entry_info = it->first; + + // Sanity check assumption that /proc/{pid}/maps entries are ascending. + assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) && + "descending /proc/pid/maps entries detected, unexpected"); + prev_base_address = proc_entry_info.GetRange().GetRangeBase(); + UNUSED_IF_ASSERT_DISABLED(prev_base_address); + + // If the target address comes before this entry, indicate distance to next + // region. + if (load_addr < proc_entry_info.GetRange().GetRangeBase()) { + range_info.GetRange().SetRangeBase(load_addr); + range_info.GetRange().SetByteSize( + proc_entry_info.GetRange().GetRangeBase() - load_addr); + range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); + + return error; + } else if (proc_entry_info.GetRange().Contains(load_addr)) { + // The target address is within the memory region we're processing here. + range_info = proc_entry_info; + return error; + } + + // The target memory address comes somewhere after the region we just + // parsed. + } + + // If we made it here, we didn't find an entry that contained the given + // address. Return the load_addr as start and the amount of bytes betwwen + // load address and the end of the memory as size. + range_info.GetRange().SetRangeBase(load_addr); + range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS); + range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); + return error; +} + +Status NativeProcessAIX::PopulateMemoryRegionCache() { + Log *log = GetLog(POSIXLog::Process); + + // If our cache is empty, pull the latest. There should always be at least + // one memory region if memory region handling is supported. + if (!m_mem_region_cache.empty()) { + LLDB_LOG(log, "reusing {0} cached memory region entries", + m_mem_region_cache.size()); + return Status(); + } + + Status Result; +#if 0 + AIXMapCallback callback = [&](llvm::Expected Info) { + if (Info) { + FileSpec file_spec(Info->GetName().GetCString()); + FileSystem::Instance().Resolve(file_spec); + m_mem_region_cache.emplace_back(*Info, file_spec); + return true; + } + + Result = Info.takeError(); + m_supports_mem_region = LazyBool::eLazyBoolNo; + LLDB_LOG(log, "failed to parse proc maps: {0}", Result); + return false; + }; + + // AIX kernel since 2.6.14 has /proc/{pid}/smaps + // if CONFIG_PROC_PAGE_MONITOR is enabled + auto BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "smaps"); + if (BufferOrError) + ParseAIXSMapRegions(BufferOrError.get()->getBuffer(), callback); + else { + BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "maps"); + if (!BufferOrError) { + m_supports_mem_region = LazyBool::eLazyBoolNo; + return BufferOrError.getError(); + } + + ParseAIXMapRegions(BufferOrError.get()->getBuffer(), callback); + } + + if (Result.Fail()) + return Result; + + if (m_mem_region_cache.empty()) { + // No entries after attempting to read them. This shouldn't happen if + // /proc/{pid}/maps is supported. Assume we don't support map entries via + // procfs. + m_supports_mem_region = LazyBool::eLazyBoolNo; + LLDB_LOG(log, + "failed to find any procfs maps entries, assuming no support " + "for memory region metadata retrieval"); + return Status("not supported"); + } + + LLDB_LOG(log, "read {0} memory region entries from /proc/{1}/maps", + m_mem_region_cache.size(), GetID()); + + // We support memory retrieval, remember that. + m_supports_mem_region = LazyBool::eLazyBoolYes; +#endif + return Status(); +} + +void NativeProcessAIX::DoStopIDBumped(uint32_t newBumpId) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "newBumpId={0}", newBumpId); + LLDB_LOG(log, "clearing {0} entries from memory region cache", + m_mem_region_cache.size()); + m_mem_region_cache.clear(); +} + +llvm::Expected +NativeProcessAIX::Syscall(llvm::ArrayRef args) { + PopulateMemoryRegionCache(); + auto region_it = llvm::find_if(m_mem_region_cache, [](const auto &pair) { + return pair.first.GetExecutable() == MemoryRegionInfo::eYes && + pair.first.GetShared() != MemoryRegionInfo::eYes; + }); + if (region_it == m_mem_region_cache.end()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "No executable memory region found!"); + + addr_t exe_addr = region_it->first.GetRange().GetRangeBase(); + + NativeThreadAIX &thread = *GetCurrentThread(); + assert(thread.GetState() == eStateStopped); + NativeRegisterContextAIX ®_ctx = thread.GetRegisterContext(); + + NativeRegisterContextAIX::SyscallData syscall_data = + *reg_ctx.GetSyscallData(); + + WritableDataBufferSP registers_sp; + if (llvm::Error Err = reg_ctx.ReadAllRegisterValues(registers_sp).ToError()) + return std::move(Err); + auto restore_regs = llvm::make_scope_exit( + [&] { reg_ctx.WriteAllRegisterValues(registers_sp); }); + + llvm::SmallVector memory(syscall_data.Insn.size()); + size_t bytes_read; + if (llvm::Error Err = + ReadMemory(exe_addr, memory.data(), memory.size(), bytes_read) + .ToError()) { + return std::move(Err); + } + + auto restore_mem = llvm::make_scope_exit( + [&] { WriteMemory(exe_addr, memory.data(), memory.size(), bytes_read); }); + + if (llvm::Error Err = reg_ctx.SetPC(exe_addr).ToError()) + return std::move(Err); + + for (const auto &zip : llvm::zip_first(args, syscall_data.Args)) { + if (llvm::Error Err = + reg_ctx + .WriteRegisterFromUnsigned(std::get<1>(zip), std::get<0>(zip)) + .ToError()) { + return std::move(Err); + } + } + if (llvm::Error Err = WriteMemory(exe_addr, syscall_data.Insn.data(), + syscall_data.Insn.size(), bytes_read) + .ToError()) + return std::move(Err); + + m_mem_region_cache.clear(); + + // With software single stepping the syscall insn buffer must also include a + // trap instruction to stop the process. + int req = SupportHardwareSingleStepping() ? PTRACE_SINGLESTEP : PTRACE_CONT; + if (llvm::Error Err = + PtraceWrapper(req, thread.GetID(), nullptr, nullptr).ToError()) + return std::move(Err); + + //FIXME + int status; + ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, ::waitpid, thread.GetID(), + &status, P_ALL/*__WALL*/); + if (wait_pid == -1) { + return llvm::errorCodeToError( + std::error_code(errno, std::generic_category())); + } + assert((unsigned)wait_pid == thread.GetID()); + + uint64_t result = reg_ctx.ReadRegisterAsUnsigned(syscall_data.Result, -ESRCH); + + // Values larger than this are actually negative errno numbers. + uint64_t errno_threshold = + (uint64_t(-1) >> (64 - 8 * m_arch.GetAddressByteSize())) - 0x1000; + if (result > errno_threshold) { + return llvm::errorCodeToError( + std::error_code(-result & 0xfff, std::generic_category())); + } + + return result; +} + +llvm::Expected +NativeProcessAIX::AllocateMemory(size_t size, uint32_t permissions) { + + std::optional mmap_data = + GetCurrentThread()->GetRegisterContext().GetMmapData(); + if (!mmap_data) + return llvm::make_error(); + + unsigned prot = PROT_NONE; + assert((permissions & (ePermissionsReadable | ePermissionsWritable | + ePermissionsExecutable)) == permissions && + "Unknown permission!"); + if (permissions & ePermissionsReadable) + prot |= PROT_READ; + if (permissions & ePermissionsWritable) + prot |= PROT_WRITE; + if (permissions & ePermissionsExecutable) + prot |= PROT_EXEC; + + llvm::Expected Result = + Syscall({mmap_data->SysMmap, 0, size, prot, MAP_ANONYMOUS | MAP_PRIVATE, + uint64_t(-1), 0}); + if (Result) + m_allocated_memory.try_emplace(*Result, size); + return Result; +} + +llvm::Error NativeProcessAIX::DeallocateMemory(lldb::addr_t addr) { + std::optional mmap_data = + GetCurrentThread()->GetRegisterContext().GetMmapData(); + if (!mmap_data) + return llvm::make_error(); + + auto it = m_allocated_memory.find(addr); + if (it == m_allocated_memory.end()) + return llvm::createStringError(llvm::errc::invalid_argument, + "Memory not allocated by the debugger."); + + llvm::Expected Result = + Syscall({mmap_data->SysMunmap, addr, it->second}); + if (!Result) + return Result.takeError(); + + m_allocated_memory.erase(it); + return llvm::Error::success(); +} + +Status NativeProcessAIX::ReadMemoryTags(int32_t type, lldb::addr_t addr, + size_t len, + std::vector &tags) { + llvm::Expected details = + GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); + if (!details) + return Status(details.takeError()); + + // Ignore 0 length read + if (!len) + return Status(); + + // lldb will align the range it requests but it is not required to by + // the protocol so we'll do it again just in case. + // Remove tag bits too. Ptrace calls may work regardless but that + // is not a guarantee. + MemoryTagManager::TagRange range(details->manager->RemoveTagBits(addr), len); + range = details->manager->ExpandToGranule(range); + + // Allocate enough space for all tags to be read + size_t num_tags = range.GetByteSize() / details->manager->GetGranuleSize(); + tags.resize(num_tags * details->manager->GetTagSizeInBytes()); + + struct iovec tags_iovec; + uint8_t *dest = tags.data(); + lldb::addr_t read_addr = range.GetRangeBase(); + + // This call can return partial data so loop until we error or + // get all tags back. + while (num_tags) { + tags_iovec.iov_base = dest; + tags_iovec.iov_len = num_tags; + + Status error = NativeProcessAIX::PtraceWrapper( + details->ptrace_read_req, GetCurrentThreadID(), + reinterpret_cast(read_addr), static_cast(&tags_iovec), + 0, nullptr); + + if (error.Fail()) { + // Discard partial reads + tags.resize(0); + return error; + } + + size_t tags_read = tags_iovec.iov_len; + assert(tags_read && (tags_read <= num_tags)); + + dest += tags_read * details->manager->GetTagSizeInBytes(); + read_addr += details->manager->GetGranuleSize() * tags_read; + num_tags -= tags_read; + } + + return Status(); +} + +Status NativeProcessAIX::WriteMemoryTags(int32_t type, lldb::addr_t addr, + size_t len, + const std::vector &tags) { + llvm::Expected details = + GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); + if (!details) + return Status(details.takeError()); + + // Ignore 0 length write + if (!len) + return Status(); + + // lldb will align the range it requests but it is not required to by + // the protocol so we'll do it again just in case. + // Remove tag bits too. Ptrace calls may work regardless but that + // is not a guarantee. + MemoryTagManager::TagRange range(details->manager->RemoveTagBits(addr), len); + range = details->manager->ExpandToGranule(range); + + // Not checking number of tags here, we may repeat them below + llvm::Expected> unpacked_tags_or_err = + details->manager->UnpackTagsData(tags); + if (!unpacked_tags_or_err) + return Status(unpacked_tags_or_err.takeError()); + + llvm::Expected> repeated_tags_or_err = + details->manager->RepeatTagsForRange(*unpacked_tags_or_err, range); + if (!repeated_tags_or_err) + return Status(repeated_tags_or_err.takeError()); + + // Repack them for ptrace to use + llvm::Expected> final_tag_data = + details->manager->PackTags(*repeated_tags_or_err); + if (!final_tag_data) + return Status(final_tag_data.takeError()); + + struct iovec tags_vec; + uint8_t *src = final_tag_data->data(); + lldb::addr_t write_addr = range.GetRangeBase(); + // unpacked tags size because the number of bytes per tag might not be 1 + size_t num_tags = repeated_tags_or_err->size(); + + // This call can partially write tags, so we loop until we + // error or all tags have been written. + while (num_tags > 0) { + tags_vec.iov_base = src; + tags_vec.iov_len = num_tags; + + Status error = NativeProcessAIX::PtraceWrapper( + details->ptrace_write_req, GetCurrentThreadID(), + reinterpret_cast(write_addr), static_cast(&tags_vec), 0, + nullptr); + + if (error.Fail()) { + // Don't attempt to restore the original values in the case of a partial + // write + return error; + } + + size_t tags_written = tags_vec.iov_len; + assert(tags_written && (tags_written <= num_tags)); + + src += tags_written * details->manager->GetTagSizeInBytes(); + write_addr += details->manager->GetGranuleSize() * tags_written; + num_tags -= tags_written; + } + + return Status(); +} + +size_t NativeProcessAIX::UpdateThreads() { + // The NativeProcessAIX monitoring threads are always up to date with + // respect to thread state and they keep the thread list populated properly. + // All this method needs to do is return the thread count. + return m_threads.size(); +} + +Status NativeProcessAIX::SetBreakpoint(lldb::addr_t addr, uint32_t size, + bool hardware) { + if (hardware) + return SetHardwareBreakpoint(addr, size); + else + return SetSoftwareBreakpoint(addr, size); +} + +Status NativeProcessAIX::RemoveBreakpoint(lldb::addr_t addr, bool hardware) { + if (hardware) + return RemoveHardwareBreakpoint(addr); + else + return NativeProcessProtocol::RemoveBreakpoint(addr); +} + +llvm::Expected> +NativeProcessAIX::GetSoftwareBreakpointTrapOpcode(size_t size_hint) { + // The ARM reference recommends the use of 0xe7fddefe and 0xdefe but the + // linux kernel does otherwise. + static const uint8_t g_arm_opcode[] = {0xf0, 0x01, 0xf0, 0xe7}; + static const uint8_t g_thumb_opcode[] = {0x01, 0xde}; + + switch (GetArchitecture().GetMachine()) { + case llvm::Triple::arm: + switch (size_hint) { + case 2: + return llvm::ArrayRef(g_thumb_opcode); + case 4: + return llvm::ArrayRef(g_arm_opcode); + default: + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Unrecognised trap opcode size hint!"); + } + default: + return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint); + } +} + +Status NativeProcessAIX::ReadMemory(lldb::addr_t addr, void *buf, size_t size, + size_t &bytes_read) { + unsigned char *dst = static_cast(buf); + size_t remainder; + long data; + + Log *log = GetLog(POSIXLog::Memory); + LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); + + for (bytes_read = 0; bytes_read < size; bytes_read += remainder) { + Status error = NativeProcessAIX::PtraceWrapper( + PT_READ_BLOCK, GetCurrentThreadID(), (void *)addr, nullptr, sizeof(data), &data); + if (error.Fail()) + return error; + + remainder = size - bytes_read; + remainder = remainder > k_ptrace_word_size ? k_ptrace_word_size : remainder; + + // Copy the data into our buffer + memcpy(dst, &data, remainder); + + LLDB_LOG(log, "[{0:x}]:{1:x}", addr, data); + addr += k_ptrace_word_size; + dst += k_ptrace_word_size; + } + return Status(); +} + +Status NativeProcessAIX::WriteMemory(lldb::addr_t addr, const void *buf, + size_t size, size_t &bytes_written) { + const unsigned char *src = static_cast(buf); + size_t remainder; + Status error; + + Log *log = GetLog(POSIXLog::Memory); + LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); + + error = NativeProcessAIX::PtraceWrapper( + PT_WRITE_BLOCK, GetCurrentThreadID(), (void *)addr, nullptr, (int)size, (long *)buf); + if (error.Fail()) + return error; + + bytes_written = size; + return error; +} + +int8_t NativeProcessAIX::GetSignalInfo(WaitStatus wstatus) const { + return wstatus.status; +} + +Status NativeProcessAIX::GetEventMessage(lldb::tid_t tid, + unsigned long *message) { + //FIXME + return PtraceWrapper(PT_CLEAR/*PTRACE_GETEVENTMSG*/, tid, nullptr, message); +} + +Status NativeProcessAIX::Detach(lldb::tid_t tid) { + if (tid == LLDB_INVALID_THREAD_ID) + return Status(); + + return PtraceWrapper(PT_DETACH, tid); +} + +bool NativeProcessAIX::HasThreadNoLock(lldb::tid_t thread_id) { + for (const auto &thread : m_threads) { + assert(thread && "thread list should not contain NULL threads"); + if (thread->GetID() == thread_id) { + // We have this thread. + return true; + } + } + + // We don't have this thread. + return false; +} + +void NativeProcessAIX::StopTrackingThread(NativeThreadAIX &thread) { + Log *const log = GetLog(POSIXLog::Thread); + lldb::tid_t thread_id = thread.GetID(); + LLDB_LOG(log, "tid: {0}", thread_id); + + auto it = llvm::find_if(m_threads, [&](const auto &thread_up) { + return thread_up.get() == &thread; + }); + assert(it != m_threads.end()); + m_threads.erase(it); + + NotifyTracersOfThreadDestroyed(thread_id); + SignalIfAllThreadsStopped(); +} + +void NativeProcessAIX::NotifyTracersProcessDidStop() { +} + +void NativeProcessAIX::NotifyTracersProcessWillResume() { +} + +Status NativeProcessAIX::NotifyTracersOfNewThread(lldb::tid_t tid) { + Log *log = GetLog(POSIXLog::Thread); + Status error; + return error; +} + +Status NativeProcessAIX::NotifyTracersOfThreadDestroyed(lldb::tid_t tid) { + Log *log = GetLog(POSIXLog::Thread); + Status error; + return error; +} + +NativeThreadAIX &NativeProcessAIX::AddThread(lldb::tid_t thread_id, + bool resume) { + Log *log = GetLog(POSIXLog::Thread); + LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id); + + assert(!HasThreadNoLock(thread_id) && + "attempted to add a thread by id that already exists"); + + // If this is the first thread, save it as the current thread + if (m_threads.empty()) + SetCurrentThreadID(thread_id); + + m_threads.push_back(std::make_unique(*this, thread_id)); + NativeThreadAIX &thread = + static_cast(*m_threads.back()); + + Status tracing_error = NotifyTracersOfNewThread(thread.GetID()); + if (tracing_error.Fail()) { + thread.SetStoppedByProcessorTrace(tracing_error.AsCString()); + StopRunningThreads(thread.GetID()); + } else if (resume) + ResumeThread(thread, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); + else + thread.SetStoppedBySignal(SIGSTOP); + + return thread; +} + +Status NativeProcessAIX::GetLoadedModuleFileSpec(const char *module_path, + FileSpec &file_spec) { + Status error = PopulateMemoryRegionCache(); + if (error.Fail()) + return error; + + FileSpec module_file_spec(module_path); + FileSystem::Instance().Resolve(module_file_spec); + + file_spec.Clear(); + for (const auto &it : m_mem_region_cache) { + if (it.second.GetFilename() == module_file_spec.GetFilename()) { + file_spec = it.second; + return Status(); + } + } + return Status("Module file (%s) not found in /proc/%" PRIu64 "/maps file!", + module_file_spec.GetFilename().AsCString(), GetID()); +} + +Status NativeProcessAIX::GetFileLoadAddress(const llvm::StringRef &file_name, + lldb::addr_t &load_addr) { + load_addr = LLDB_INVALID_ADDRESS; + + NativeThreadAIX &thread = *GetCurrentThread(); + NativeRegisterContextAIX ®_ctx = thread.GetRegisterContext(); + + // FIXME: buffer size + struct ld_xinfo info[64]; + if (ptrace64(PT_LDXINFO, reg_ctx.GetThread().GetID(), (long long)&(info[0]), sizeof(info), nullptr) == 0) { + load_addr = (unsigned long)info[0].ldinfo_textorg; + return Status(); + } + return Status("No load address found for specified file."); +} + +NativeThreadAIX *NativeProcessAIX::GetThreadByID(lldb::tid_t tid) { + return static_cast( + NativeProcessProtocol::GetThreadByID(tid)); +} + +NativeThreadAIX *NativeProcessAIX::GetCurrentThread() { + return static_cast( + NativeProcessProtocol::GetCurrentThread()); +} + +Status NativeProcessAIX::ResumeThread(NativeThreadAIX &thread, + lldb::StateType state, int signo) { + Log *const log = GetLog(POSIXLog::Thread); + LLDB_LOG(log, "tid: {0}", thread.GetID()); + + // Before we do the resume below, first check if we have a pending stop + // notification that is currently waiting for all threads to stop. This is + // potentially a buggy situation since we're ostensibly waiting for threads + // to stop before we send out the pending notification, and here we are + // resuming one before we send out the pending stop notification. + if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID) { + LLDB_LOG(log, + "about to resume tid {0} per explicit request but we have a " + "pending stop notification (tid {1}) that is actively " + "waiting for this thread to stop. Valid sequence of events?", + thread.GetID(), m_pending_notification_tid); + } + + // Request a resume. We expect this to be synchronous and the system to + // reflect it is running after this completes. + switch (state) { + case eStateRunning: { + const auto resume_result = thread.Resume(signo); + if (resume_result.Success()) + SetState(eStateRunning, true); + return resume_result; + } + case eStateStepping: { + const auto step_result = thread.SingleStep(signo); + if (step_result.Success()) + SetState(eStateRunning, true); + return step_result; + } + default: + LLDB_LOG(log, "Unhandled state {0}.", state); + llvm_unreachable("Unhandled state for resume"); + } +} + +//===----------------------------------------------------------------------===// + +void NativeProcessAIX::StopRunningThreads(const lldb::tid_t triggering_tid) { + Log *const log = GetLog(POSIXLog::Thread); + LLDB_LOG(log, "about to process event: (triggering_tid: {0})", + triggering_tid); + + m_pending_notification_tid = triggering_tid; + + // Request a stop for all the thread stops that need to be stopped and are + // not already known to be stopped. + for (const auto &thread : m_threads) { + if (StateIsRunningState(thread->GetState())) + static_cast(thread.get())->RequestStop(); + } + + SignalIfAllThreadsStopped(); + LLDB_LOG(log, "event processing done"); +} + +void NativeProcessAIX::SignalIfAllThreadsStopped() { + if (m_pending_notification_tid == LLDB_INVALID_THREAD_ID) + return; // No pending notification. Nothing to do. + + for (const auto &thread_sp : m_threads) { + if (StateIsRunningState(thread_sp->GetState())) + return; // Some threads are still running. Don't signal yet. + } + + // We have a pending notification and all threads have stopped. + Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints); + + // Clear any temporary breakpoints we used to implement software single + // stepping. + for (const auto &thread_info : m_threads_stepping_with_breakpoint) { + Status error = RemoveBreakpoint(thread_info.second); + if (error.Fail()) + LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}", + thread_info.first, error); + } + m_threads_stepping_with_breakpoint.clear(); + + // Notify the delegate about the stop + SetCurrentThreadID(m_pending_notification_tid); + SetState(StateType::eStateStopped, true); + m_pending_notification_tid = LLDB_INVALID_THREAD_ID; +} + +void NativeProcessAIX::ThreadWasCreated(NativeThreadAIX &thread) { + Log *const log = GetLog(POSIXLog::Thread); + LLDB_LOG(log, "tid: {0}", thread.GetID()); + + if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID && + StateIsRunningState(thread.GetState())) { + // We will need to wait for this new thread to stop as well before firing + // the notification. + thread.RequestStop(); + } +} + +#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT +#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h" +#undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT + +static void GetRegister(lldb::pid_t pid, long long addr, void *buf) { + uint64_t val = 0; + ptrace64(PT_READ_GPR, pid, addr, 0, (int *)&val); + *(uint64_t *)buf = llvm::byteswap(val); +} + +static void SetRegister(lldb::pid_t pid, long long addr, void *buf) { + uint64_t val = llvm::byteswap(*(uint64_t *)buf); + ptrace64(PT_WRITE_GPR, pid, addr, 0, (int *)&val); +} + +static void GetFPRegister(lldb::pid_t pid, long long addr, void *buf) { + uint64_t val = 0; + ptrace64(PT_READ_FPR, pid, addr, 0, (int *)&val); + *(uint64_t *)buf = llvm::byteswap(val); +} + +static void GetVMRegister(lldb::tid_t tid, long long addr, void *buf) { + uint64_t val = 0; + ptrace64(PTT_READ_VEC, tid, addr, 0, (int *)&val); + //*(uint64_t *)buf = llvm::byteswap(val); +} + +static void GetVSRegister(lldb::tid_t tid, long long addr, void *buf) { + uint64_t val = 0; + ptrace64(PTT_READ_VSX, tid, addr, 0, (int *)&val); + //*(uint64_t *)buf = llvm::byteswap(val); +} + +// Wrapper for ptrace to catch errors and log calls. Note that ptrace sets +// errno on error because -1 can be a valid result (i.e. for PTRACE_PEEK*) +Status NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid, void *addr, + void *data, size_t data_size, + long *result) { + Status error; + long int ret; + + Log *log = GetLog(POSIXLog::Ptrace); + + PtraceDisplayBytes(req, data, data_size); + + errno = 0; + + // for PTT_* + const char procdir[] = "/proc/"; + const char lwpdir[] = "/lwp/"; + std::string process_task_dir = procdir + std::to_string(pid) + lwpdir; + DIR *dirproc = opendir(process_task_dir.c_str()); + + lldb::tid_t tid = 0; + if (dirproc) { + struct dirent *direntry = nullptr; + while ((direntry = readdir(dirproc)) != nullptr) { + if (strcmp(direntry->d_name, ".") == 0 || strcmp(direntry->d_name, "..") == 0) { + continue; + } + tid = atoi(direntry->d_name); + break; + } + closedir(dirproc); + } + + if (req == PTRACE_GETREGS) { + GetRegister(pid, GPR0, &(((GPR *)data)->r0)); + GetRegister(pid, GPR1, &(((GPR *)data)->r1)); + GetRegister(pid, GPR2, &(((GPR *)data)->r2)); + GetRegister(pid, GPR3, &(((GPR *)data)->r3)); + GetRegister(pid, GPR4, &(((GPR *)data)->r4)); + GetRegister(pid, GPR5, &(((GPR *)data)->r5)); + GetRegister(pid, GPR6, &(((GPR *)data)->r6)); + GetRegister(pid, GPR7, &(((GPR *)data)->r7)); + GetRegister(pid, GPR8, &(((GPR *)data)->r8)); + GetRegister(pid, GPR9, &(((GPR *)data)->r9)); + GetRegister(pid, GPR10, &(((GPR *)data)->r10)); + GetRegister(pid, GPR11, &(((GPR *)data)->r11)); + GetRegister(pid, GPR12, &(((GPR *)data)->r12)); + GetRegister(pid, GPR13, &(((GPR *)data)->r13)); + GetRegister(pid, GPR14, &(((GPR *)data)->r14)); + GetRegister(pid, GPR15, &(((GPR *)data)->r15)); + GetRegister(pid, GPR16, &(((GPR *)data)->r16)); + GetRegister(pid, GPR17, &(((GPR *)data)->r17)); + GetRegister(pid, GPR18, &(((GPR *)data)->r18)); + GetRegister(pid, GPR19, &(((GPR *)data)->r19)); + GetRegister(pid, GPR20, &(((GPR *)data)->r20)); + GetRegister(pid, GPR21, &(((GPR *)data)->r21)); + GetRegister(pid, GPR22, &(((GPR *)data)->r22)); + GetRegister(pid, GPR23, &(((GPR *)data)->r23)); + GetRegister(pid, GPR24, &(((GPR *)data)->r24)); + GetRegister(pid, GPR25, &(((GPR *)data)->r25)); + GetRegister(pid, GPR26, &(((GPR *)data)->r26)); + GetRegister(pid, GPR27, &(((GPR *)data)->r27)); + GetRegister(pid, GPR28, &(((GPR *)data)->r28)); + GetRegister(pid, GPR29, &(((GPR *)data)->r29)); + GetRegister(pid, GPR30, &(((GPR *)data)->r30)); + GetRegister(pid, GPR31, &(((GPR *)data)->r31)); + GetRegister(pid, IAR, &(((GPR *)data)->pc)); + GetRegister(pid, MSR, &(((GPR *)data)->msr)); + //FIXME: origr3/softe/trap on AIX? + GetRegister(pid, CTR, &(((GPR *)data)->ctr)); + GetRegister(pid, LR, &(((GPR *)data)->lr)); + GetRegister(pid, XER, &(((GPR *)data)->xer)); + GetRegister(pid, CR, &(((GPR *)data)->cr)); + } else if (req == PTRACE_SETREGS) { + SetRegister(pid, GPR0, &(((GPR *)data)->r0)); + SetRegister(pid, GPR1, &(((GPR *)data)->r1)); + SetRegister(pid, GPR2, &(((GPR *)data)->r2)); + SetRegister(pid, GPR3, &(((GPR *)data)->r3)); + SetRegister(pid, GPR4, &(((GPR *)data)->r4)); + SetRegister(pid, GPR5, &(((GPR *)data)->r5)); + SetRegister(pid, GPR6, &(((GPR *)data)->r6)); + SetRegister(pid, GPR7, &(((GPR *)data)->r7)); + SetRegister(pid, GPR8, &(((GPR *)data)->r8)); + SetRegister(pid, GPR9, &(((GPR *)data)->r9)); + SetRegister(pid, GPR10, &(((GPR *)data)->r10)); + SetRegister(pid, GPR11, &(((GPR *)data)->r11)); + SetRegister(pid, GPR12, &(((GPR *)data)->r12)); + SetRegister(pid, GPR13, &(((GPR *)data)->r13)); + SetRegister(pid, GPR14, &(((GPR *)data)->r14)); + SetRegister(pid, GPR15, &(((GPR *)data)->r15)); + SetRegister(pid, GPR16, &(((GPR *)data)->r16)); + SetRegister(pid, GPR17, &(((GPR *)data)->r17)); + SetRegister(pid, GPR18, &(((GPR *)data)->r18)); + SetRegister(pid, GPR19, &(((GPR *)data)->r19)); + SetRegister(pid, GPR20, &(((GPR *)data)->r20)); + SetRegister(pid, GPR21, &(((GPR *)data)->r21)); + SetRegister(pid, GPR22, &(((GPR *)data)->r22)); + SetRegister(pid, GPR23, &(((GPR *)data)->r23)); + SetRegister(pid, GPR24, &(((GPR *)data)->r24)); + SetRegister(pid, GPR25, &(((GPR *)data)->r25)); + SetRegister(pid, GPR26, &(((GPR *)data)->r26)); + SetRegister(pid, GPR27, &(((GPR *)data)->r27)); + SetRegister(pid, GPR28, &(((GPR *)data)->r28)); + SetRegister(pid, GPR29, &(((GPR *)data)->r29)); + SetRegister(pid, GPR30, &(((GPR *)data)->r30)); + SetRegister(pid, GPR31, &(((GPR *)data)->r31)); + SetRegister(pid, IAR, &(((GPR *)data)->pc)); + SetRegister(pid, MSR, &(((GPR *)data)->msr)); + //FIXME: origr3/softe/trap on AIX? + SetRegister(pid, CTR, &(((GPR *)data)->ctr)); + SetRegister(pid, LR, &(((GPR *)data)->lr)); + SetRegister(pid, XER, &(((GPR *)data)->xer)); + SetRegister(pid, CR, &(((GPR *)data)->cr)); + } else if (req == PTRACE_GETFPREGS) { + GetFPRegister(pid, FPR0, &(((FPR *)data)->f0)); + GetFPRegister(pid, FPR1, &(((FPR *)data)->f1)); + GetFPRegister(pid, FPR2, &(((FPR *)data)->f2)); + GetFPRegister(pid, FPR3, &(((FPR *)data)->f3)); + GetFPRegister(pid, FPR4, &(((FPR *)data)->f4)); + GetFPRegister(pid, FPR5, &(((FPR *)data)->f5)); + GetFPRegister(pid, FPR6, &(((FPR *)data)->f6)); + GetFPRegister(pid, FPR7, &(((FPR *)data)->f7)); + GetFPRegister(pid, FPR8, &(((FPR *)data)->f8)); + GetFPRegister(pid, FPR9, &(((FPR *)data)->f9)); + GetFPRegister(pid, FPR10, &(((FPR *)data)->f10)); + GetFPRegister(pid, FPR11, &(((FPR *)data)->f11)); + GetFPRegister(pid, FPR12, &(((FPR *)data)->f12)); + GetFPRegister(pid, FPR13, &(((FPR *)data)->f13)); + GetFPRegister(pid, FPR14, &(((FPR *)data)->f14)); + GetFPRegister(pid, FPR15, &(((FPR *)data)->f15)); + GetFPRegister(pid, FPR16, &(((FPR *)data)->f16)); + GetFPRegister(pid, FPR17, &(((FPR *)data)->f17)); + GetFPRegister(pid, FPR18, &(((FPR *)data)->f18)); + GetFPRegister(pid, FPR19, &(((FPR *)data)->f19)); + GetFPRegister(pid, FPR20, &(((FPR *)data)->f20)); + GetFPRegister(pid, FPR21, &(((FPR *)data)->f21)); + GetFPRegister(pid, FPR22, &(((FPR *)data)->f22)); + GetFPRegister(pid, FPR23, &(((FPR *)data)->f23)); + GetFPRegister(pid, FPR24, &(((FPR *)data)->f24)); + GetFPRegister(pid, FPR25, &(((FPR *)data)->f25)); + GetFPRegister(pid, FPR26, &(((FPR *)data)->f26)); + GetFPRegister(pid, FPR27, &(((FPR *)data)->f27)); + GetFPRegister(pid, FPR28, &(((FPR *)data)->f28)); + GetFPRegister(pid, FPR29, &(((FPR *)data)->f29)); + GetFPRegister(pid, FPR30, &(((FPR *)data)->f30)); + GetFPRegister(pid, FPR31, &(((FPR *)data)->f31)); + GetFPRegister(pid, FPSCR, &(((FPR *)data)->fpscr)); + } else if (req == PTRACE_GETVRREGS && tid) { + GetVMRegister(tid, VR0, &(((VMX *)data)->vr0[0])); + GetVMRegister(tid, VR1, &(((VMX *)data)->vr1[0])); + GetVMRegister(tid, VR2, &(((VMX *)data)->vr2[0])); + GetVMRegister(tid, VR3, &(((VMX *)data)->vr3[0])); + GetVMRegister(tid, VR4, &(((VMX *)data)->vr4[0])); + GetVMRegister(tid, VR5, &(((VMX *)data)->vr5[0])); + GetVMRegister(tid, VR6, &(((VMX *)data)->vr6[0])); + GetVMRegister(tid, VR7, &(((VMX *)data)->vr7[0])); + GetVMRegister(tid, VR8, &(((VMX *)data)->vr8[0])); + GetVMRegister(tid, VR9, &(((VMX *)data)->vr9[0])); + GetVMRegister(tid, VR10, &(((VMX *)data)->vr10[0])); + GetVMRegister(tid, VR11, &(((VMX *)data)->vr11[0])); + GetVMRegister(tid, VR12, &(((VMX *)data)->vr12[0])); + GetVMRegister(tid, VR13, &(((VMX *)data)->vr13[0])); + GetVMRegister(tid, VR14, &(((VMX *)data)->vr14[0])); + GetVMRegister(tid, VR15, &(((VMX *)data)->vr15[0])); + GetVMRegister(tid, VR16, &(((VMX *)data)->vr16[0])); + GetVMRegister(tid, VR17, &(((VMX *)data)->vr17[0])); + GetVMRegister(tid, VR18, &(((VMX *)data)->vr18[0])); + GetVMRegister(tid, VR19, &(((VMX *)data)->vr19[0])); + GetVMRegister(tid, VR20, &(((VMX *)data)->vr20[0])); + GetVMRegister(tid, VR21, &(((VMX *)data)->vr21[0])); + GetVMRegister(tid, VR22, &(((VMX *)data)->vr22[0])); + GetVMRegister(tid, VR23, &(((VMX *)data)->vr23[0])); + GetVMRegister(tid, VR24, &(((VMX *)data)->vr24[0])); + GetVMRegister(tid, VR25, &(((VMX *)data)->vr25[0])); + GetVMRegister(tid, VR26, &(((VMX *)data)->vr26[0])); + GetVMRegister(tid, VR27, &(((VMX *)data)->vr27[0])); + GetVMRegister(tid, VR28, &(((VMX *)data)->vr28[0])); + GetVMRegister(tid, VR29, &(((VMX *)data)->vr29[0])); + GetVMRegister(tid, VR30, &(((VMX *)data)->vr30[0])); + GetVMRegister(tid, VR31, &(((VMX *)data)->vr31[0])); + GetVMRegister(tid, VSCR, &(((VMX *)data)->vscr[0])); + GetVMRegister(tid, VRSAVE, &(((VMX *)data)->vrsave)); + } else if (req == PTRACE_GETVSRREGS && tid) { + GetVSRegister(tid, VSR0, &(((VSX *)data)->vs0[0])); + GetVSRegister(tid, VSR1, &(((VSX *)data)->vs1[0])); + GetVSRegister(tid, VSR2, &(((VSX *)data)->vs2[0])); + GetVSRegister(tid, VSR3, &(((VSX *)data)->vs3[0])); + GetVSRegister(tid, VSR4, &(((VSX *)data)->vs4[0])); + GetVSRegister(tid, VSR5, &(((VSX *)data)->vs5[0])); + GetVSRegister(tid, VSR6, &(((VSX *)data)->vs6[0])); + GetVSRegister(tid, VSR7, &(((VSX *)data)->vs7[0])); + GetVSRegister(tid, VSR8, &(((VSX *)data)->vs8[0])); + GetVSRegister(tid, VSR9, &(((VSX *)data)->vs9[0])); + GetVSRegister(tid, VSR10, &(((VSX *)data)->vs10[0])); + GetVSRegister(tid, VSR11, &(((VSX *)data)->vs11[0])); + GetVSRegister(tid, VSR12, &(((VSX *)data)->vs12[0])); + GetVSRegister(tid, VSR13, &(((VSX *)data)->vs13[0])); + GetVSRegister(tid, VSR14, &(((VSX *)data)->vs14[0])); + GetVSRegister(tid, VSR15, &(((VSX *)data)->vs15[0])); + GetVSRegister(tid, VSR16, &(((VSX *)data)->vs16[0])); + GetVSRegister(tid, VSR17, &(((VSX *)data)->vs17[0])); + GetVSRegister(tid, VSR18, &(((VSX *)data)->vs18[0])); + GetVSRegister(tid, VSR19, &(((VSX *)data)->vs19[0])); + GetVSRegister(tid, VSR20, &(((VSX *)data)->vs20[0])); + GetVSRegister(tid, VSR21, &(((VSX *)data)->vs21[0])); + GetVSRegister(tid, VSR22, &(((VSX *)data)->vs22[0])); + GetVSRegister(tid, VSR23, &(((VSX *)data)->vs23[0])); + GetVSRegister(tid, VSR24, &(((VSX *)data)->vs24[0])); + GetVSRegister(tid, VSR25, &(((VSX *)data)->vs25[0])); + GetVSRegister(tid, VSR26, &(((VSX *)data)->vs26[0])); + GetVSRegister(tid, VSR27, &(((VSX *)data)->vs27[0])); + GetVSRegister(tid, VSR28, &(((VSX *)data)->vs28[0])); + GetVSRegister(tid, VSR29, &(((VSX *)data)->vs29[0])); + GetVSRegister(tid, VSR30, &(((VSX *)data)->vs30[0])); + GetVSRegister(tid, VSR31, &(((VSX *)data)->vs31[0])); + GetVSRegister(tid, VSR32, &(((VSX *)data)->vs32[0])); + GetVSRegister(tid, VSR33, &(((VSX *)data)->vs33[0])); + GetVSRegister(tid, VSR34, &(((VSX *)data)->vs34[0])); + GetVSRegister(tid, VSR35, &(((VSX *)data)->vs35[0])); + GetVSRegister(tid, VSR36, &(((VSX *)data)->vs36[0])); + GetVSRegister(tid, VSR37, &(((VSX *)data)->vs37[0])); + GetVSRegister(tid, VSR38, &(((VSX *)data)->vs38[0])); + GetVSRegister(tid, VSR39, &(((VSX *)data)->vs39[0])); + GetVSRegister(tid, VSR40, &(((VSX *)data)->vs40[0])); + GetVSRegister(tid, VSR41, &(((VSX *)data)->vs41[0])); + GetVSRegister(tid, VSR42, &(((VSX *)data)->vs42[0])); + GetVSRegister(tid, VSR43, &(((VSX *)data)->vs43[0])); + GetVSRegister(tid, VSR44, &(((VSX *)data)->vs44[0])); + GetVSRegister(tid, VSR45, &(((VSX *)data)->vs45[0])); + GetVSRegister(tid, VSR46, &(((VSX *)data)->vs46[0])); + GetVSRegister(tid, VSR47, &(((VSX *)data)->vs47[0])); + GetVSRegister(tid, VSR48, &(((VSX *)data)->vs48[0])); + GetVSRegister(tid, VSR49, &(((VSX *)data)->vs49[0])); + GetVSRegister(tid, VSR50, &(((VSX *)data)->vs50[0])); + GetVSRegister(tid, VSR51, &(((VSX *)data)->vs51[0])); + GetVSRegister(tid, VSR52, &(((VSX *)data)->vs52[0])); + GetVSRegister(tid, VSR53, &(((VSX *)data)->vs53[0])); + GetVSRegister(tid, VSR54, &(((VSX *)data)->vs54[0])); + GetVSRegister(tid, VSR55, &(((VSX *)data)->vs55[0])); + GetVSRegister(tid, VSR56, &(((VSX *)data)->vs56[0])); + GetVSRegister(tid, VSR57, &(((VSX *)data)->vs57[0])); + GetVSRegister(tid, VSR58, &(((VSX *)data)->vs58[0])); + GetVSRegister(tid, VSR59, &(((VSX *)data)->vs59[0])); + GetVSRegister(tid, VSR60, &(((VSX *)data)->vs60[0])); + GetVSRegister(tid, VSR61, &(((VSX *)data)->vs61[0])); + GetVSRegister(tid, VSR62, &(((VSX *)data)->vs62[0])); + GetVSRegister(tid, VSR63, &(((VSX *)data)->vs63[0])); + } else if (req < PT_COMMAND_MAX) { + if (req == PT_CONTINUE) { +#if 0 + // Use PTT_CONTINUE + const char procdir[] = "/proc/"; + const char lwpdir[] = "/lwp/"; + std::string process_task_dir = procdir + std::to_string(pid) + lwpdir; + DIR *dirproc = opendir(process_task_dir.c_str()); + + struct ptthreads64 pts; + int idx = 0; + lldb::tid_t tid = 0; + if (dirproc) { + struct dirent *direntry = nullptr; + while ((direntry = readdir(dirproc)) != nullptr) { + if (strcmp(direntry->d_name, ".") == 0 || strcmp(direntry->d_name, "..") == 0) { + continue; + } + tid = atoi(direntry->d_name); + pts.th[idx++] = tid; + } + closedir(dirproc); + } + pts.th[idx] = 0; + ret = ptrace64(PTT_CONTINUE, tid, (long long)1, (int)(size_t)data, (int *)&pts); +#else + int buf; + ptrace64(req, pid, 1, (int)(size_t)data, &buf); +#endif + } else if (req == PT_READ_BLOCK) { + ptrace64(req, pid, (long long)addr, (int)data_size, (int *)result); + } else if (req == PT_WRITE_BLOCK) { + ptrace64(req, pid, (long long)addr, (int)data_size, (int *)result); + } else if (req == PT_ATTACH) { + ptrace64(req, pid, 0, 0, nullptr); + } else if (req == PT_WATCH) { + ptrace64(req, pid, (long long)addr, (int)data_size, nullptr); + } else if (req == PT_DETACH) { + ptrace64(req, pid, 0, 0, nullptr); + } else { + assert(0 && "Not supported yet."); + } + } else { + assert(0 && "Not supported yet."); + } + + if (errno) { + error.SetErrorToErrno(); + ret = -1; + } + + LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3}, {4})={5:x}", req, pid, addr, data, + data_size, ret); + + PtraceDisplayBytes(req, data, data_size); + + if (error.Fail()) + LLDB_LOG(log, "ptrace() failed: {0}", error); + + return error; +} + +llvm::Expected NativeProcessAIX::TraceSupported() { + return NativeProcessProtocol::TraceSupported(); +} + +Error NativeProcessAIX::TraceStart(StringRef json_request, StringRef type) { + return NativeProcessProtocol::TraceStart(json_request, type); +} + +Error NativeProcessAIX::TraceStop(const TraceStopRequest &request) { + return NativeProcessProtocol::TraceStop(request); +} + +Expected NativeProcessAIX::TraceGetState(StringRef type) { + return NativeProcessProtocol::TraceGetState(type); +} + +Expected> NativeProcessAIX::TraceGetBinaryData( + const TraceGetBinaryDataRequest &request) { + return NativeProcessProtocol::TraceGetBinaryData(request); +} diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h new file mode 100644 index 0000000000000..bdb6f7c500885 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h @@ -0,0 +1,283 @@ +//===-- NativeProcessAIX.h ---------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeProcessAIX_H_ +#define liblldb_NativeProcessAIX_H_ + +#include +#include + +#include "lldb/Host/Debug.h" +#include "lldb/Host/HostThread.h" +#include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/lldb-types.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "lldb/Host/aix/Support.h" + +#include "NativeThreadAIX.h" +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h" + +namespace lldb_private { +class Status; +class Scalar; + +namespace process_aix { +/// \class NativeProcessAIX +/// Manages communication with the inferior (debugee) process. +/// +/// Upon construction, this class prepares and launches an inferior process +/// for debugging. +/// +/// Changes in the inferior process state are broadcasted. +class NativeProcessAIX : public NativeProcessProtocol, + private NativeProcessSoftwareSingleStep { +public: + class Manager : public NativeProcessProtocol::Manager { + public: + Manager(MainLoop &mainloop); + + llvm::Expected> + Launch(ProcessLaunchInfo &launch_info, + NativeDelegate &native_delegate) override; + + llvm::Expected> + Attach(lldb::pid_t pid, NativeDelegate &native_delegate) override; + + Extension GetSupportedExtensions() const override; + + void AddProcess(NativeProcessAIX &process) { + m_processes.insert(&process); + } + + void RemoveProcess(NativeProcessAIX &process) { + m_processes.erase(&process); + } + + // Collect an event for the given tid, waiting for it if necessary. + void CollectThread(::pid_t tid); + + private: + MainLoop::SignalHandleUP m_sigchld_handle; + + llvm::SmallPtrSet m_processes; + + // Threads (events) which haven't been claimed by any process. + llvm::DenseSet<::pid_t> m_unowned_threads; + + void SigchldHandler(); + }; + + // NativeProcessProtocol Interface + + ~NativeProcessAIX() override { m_manager.RemoveProcess(*this); } + + Status Resume(const ResumeActionList &resume_actions) override; + + Status Halt() override; + + Status Detach() override; + + Status Signal(int signo) override; + + Status Interrupt() override; + + Status Kill() override; + + lldb::addr_t GetSharedLibraryInfoAddress() override; + + Status GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info) override; + + Status ReadMemory(lldb::addr_t addr, void *buf, size_t size, + size_t &bytes_read) override; + + Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, + size_t &bytes_written) override; + + llvm::Expected AllocateMemory(size_t size, + uint32_t permissions) override; + + llvm::Error DeallocateMemory(lldb::addr_t addr) override; + + Status ReadMemoryTags(int32_t type, lldb::addr_t addr, size_t len, + std::vector &tags) override; + + Status WriteMemoryTags(int32_t type, lldb::addr_t addr, size_t len, + const std::vector &tags) override; + + size_t UpdateThreads() override; + + const ArchSpec &GetArchitecture() const override { return m_arch; } + + Status SetBreakpoint(lldb::addr_t addr, uint32_t size, + bool hardware) override; + + Status RemoveBreakpoint(lldb::addr_t addr, bool hardware = false) override; + + void DoStopIDBumped(uint32_t newBumpId) override; + + Status GetLoadedModuleFileSpec(const char *module_path, + FileSpec &file_spec) override; + + Status GetFileLoadAddress(const llvm::StringRef &file_name, + lldb::addr_t &load_addr) override; + + NativeThreadAIX *GetThreadByID(lldb::tid_t id); + NativeThreadAIX *GetCurrentThread(); + + llvm::ErrorOr> + GetAuxvData() const override { + // Not available on this target. + return llvm::errc::not_supported; + } + + /// Tracing + /// These methods implement the jLLDBTrace packets + /// \{ + llvm::Error TraceStart(llvm::StringRef json_request, + llvm::StringRef type) override; + + llvm::Error TraceStop(const TraceStopRequest &request) override; + + llvm::Expected + TraceGetState(llvm::StringRef type) override; + + llvm::Expected> + TraceGetBinaryData(const TraceGetBinaryDataRequest &request) override; + + llvm::Expected TraceSupported() override; + /// } + + // Interface used by NativeRegisterContext-derived classes. + static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr, + void *data = nullptr, size_t data_size = 0, + long *result = nullptr); + + bool SupportHardwareSingleStepping() const; + + /// Writes a siginfo_t structure corresponding to the given thread ID to the + /// memory region pointed to by \p siginfo. + int8_t GetSignalInfo(WaitStatus wstatus) const; + +protected: + llvm::Expected> + GetSoftwareBreakpointTrapOpcode(size_t size_hint) override; + + llvm::Expected Syscall(llvm::ArrayRef args); + +private: + Manager &m_manager; + /*MainLoop::SignalHandleUP m_sigchld_handle;*/ + ArchSpec m_arch; + /*MainLoop& m_main_loop;*/ + + LazyBool m_supports_mem_region = eLazyBoolCalculate; + std::vector> m_mem_region_cache; + + lldb::tid_t m_pending_notification_tid = LLDB_INVALID_THREAD_ID; + + /// Inferior memory (allocated by us) and its size. + llvm::DenseMap m_allocated_memory; + + // Private Instance Methods + NativeProcessAIX(::pid_t pid, int terminal_fd, NativeDelegate &delegate, + const ArchSpec &arch, Manager &manager, + llvm::ArrayRef<::pid_t> tids); + + // Returns a list of process threads that we have attached to. + static llvm::Expected> Attach(::pid_t pid); + + static Status SetDefaultPtraceOpts(const lldb::pid_t); + + bool TryHandleWaitStatus(lldb::pid_t pid, WaitStatus status); + + void MonitorCallback(NativeThreadAIX &thread, WaitStatus status); + + void MonitorSIGTRAP(const WaitStatus status, NativeThreadAIX &thread); + + void MonitorTrace(NativeThreadAIX &thread); + + void MonitorBreakpoint(NativeThreadAIX &thread); + + void MonitorWatchpoint(NativeThreadAIX &thread, uint32_t wp_index); + + void MonitorSignal(const WaitStatus status, NativeThreadAIX &thread); + + bool HasThreadNoLock(lldb::tid_t thread_id); + + void StopTrackingThread(NativeThreadAIX &thread); + + /// Create a new thread. + /// + /// If process tracing is enabled and the thread can't be traced, then the + /// thread is left stopped with a \a eStopReasonProcessorTrace status, and + /// then the process is stopped. + /// + /// \param[in] resume + /// If a tracing error didn't happen, then resume the thread after + /// creation if \b true, or leave it stopped with SIGSTOP if \b false. + NativeThreadAIX &AddThread(lldb::tid_t thread_id, bool resume); + + /// Start tracing a new thread if process tracing is enabled. + /// + /// Trace mechanisms should modify this method to provide automatic tracing + /// for new threads. + Status NotifyTracersOfNewThread(lldb::tid_t tid); + + /// Stop tracing threads upon a destroy event. + /// + /// Trace mechanisms should modify this method to provide automatic trace + /// stopping for threads being destroyed. + Status NotifyTracersOfThreadDestroyed(lldb::tid_t tid); + + void NotifyTracersProcessWillResume() override; + + void NotifyTracersProcessDidStop() override; + /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG) + /// corresponding to the given thread ID to the memory pointed to by @p + /// message. + Status GetEventMessage(lldb::tid_t tid, unsigned long *message); + + void NotifyThreadDeath(lldb::tid_t tid); + + Status Detach(lldb::tid_t tid); + + // This method is requests a stop on all threads which are still running. It + // sets up a + // deferred delegate notification, which will fire once threads report as + // stopped. The + // triggerring_tid will be set as the current thread (main stop reason). + void StopRunningThreads(lldb::tid_t triggering_tid); + + // Notify the delegate if all threads have stopped. + void SignalIfAllThreadsStopped(); + + // Resume the given thread, optionally passing it the given signal. The type + // of resume + // operation (continue, single-step) depends on the state parameter. + Status ResumeThread(NativeThreadAIX &thread, lldb::StateType state, + int signo); + + void ThreadWasCreated(NativeThreadAIX &thread); + + void SigchldHandler(); + + Status PopulateMemoryRegionCache(); + + // Handle a clone()-like event. + bool MonitorClone(NativeThreadAIX &parent, lldb::pid_t child_pid, + int event); +}; + +} // namespace process_aix +} // namespace lldb_private + +#endif // #ifndef liblldb_NativeProcessAIX_H_ diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp new file mode 100644 index 0000000000000..0859f9501c1b6 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp @@ -0,0 +1,157 @@ +//===-- NativeRegisterContextAIX.cpp ------------------------------------===// +// +// 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 "NativeRegisterContextAIX.h" + +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/Utility/RegisterValue.h" + +#include "Plugins/Process/AIX/NativeProcessAIX.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "lldb/Host/aix/Ptrace.h" + +using namespace lldb_private; +using namespace lldb_private::process_aix; + +lldb::ByteOrder NativeRegisterContextAIX::GetByteOrder() const { + return m_thread.GetProcess().GetByteOrder(); +} + +Status NativeRegisterContextAIX::ReadRegisterRaw(uint32_t reg_index, + RegisterValue ®_value) { + const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); + if (!reg_info) + return Status("register %" PRIu32 " not found", reg_index); + + return DoReadRegisterValue(GetPtraceOffset(reg_index), reg_info->name, + reg_info->byte_size, reg_value); +} + +Status +NativeRegisterContextAIX::WriteRegisterRaw(uint32_t reg_index, + const RegisterValue ®_value) { + uint32_t reg_to_write = reg_index; + RegisterValue value_to_write = reg_value; + + // Check if this is a subregister of a full register. + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index); + if (reg_info->invalidate_regs && + (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) { + Status error; + + RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + error = ReadRegister(full_reg_info, full_value); + if (error.Fail()) + return error; + + lldb::ByteOrder byte_order = GetByteOrder(); + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData( + *full_reg_info, dst, sizeof(dst), byte_order, error); + if (error.Success() && dest_size) { + uint8_t src[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = reg_value.GetAsMemoryData( + *reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) { + // Copy the src bytes to the destination. + memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(*full_reg_info); + reg_to_write = full_reg; + } + } + } + + const RegisterInfo *const register_to_write_info_p = + GetRegisterInfoAtIndex(reg_to_write); + assert(register_to_write_info_p && + "register to write does not have valid RegisterInfo"); + if (!register_to_write_info_p) + return Status("NativeRegisterContextAIX::%s failed to get RegisterInfo " + "for write register index %" PRIu32, + __FUNCTION__, reg_to_write); + + return DoWriteRegisterValue(GetPtraceOffset(reg_index), reg_info->name, + reg_value); +} + +Status NativeRegisterContextAIX::ReadGPR() { + return NativeProcessAIX::PtraceWrapper( + PTRACE_GETREGS, m_thread.GetID(), nullptr, GetGPRBuffer(), GetGPRSize()); +} + +Status NativeRegisterContextAIX::WriteGPR() { + return NativeProcessAIX::PtraceWrapper( + PTRACE_SETREGS, m_thread.GetID(), nullptr, GetGPRBuffer(), GetGPRSize()); +} + +Status NativeRegisterContextAIX::ReadFPR() { + return NativeProcessAIX::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(), + nullptr, GetFPRBuffer(), + GetFPRSize()); +} + +Status NativeRegisterContextAIX::WriteFPR() { + return NativeProcessAIX::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(), + nullptr, GetFPRBuffer(), + GetFPRSize()); +} + +Status NativeRegisterContextAIX::ReadRegisterSet(void *buf, size_t buf_size, + unsigned int regset) { + return NativeProcessAIX::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), + static_cast(®set), buf, + buf_size); +} + +Status NativeRegisterContextAIX::WriteRegisterSet(void *buf, size_t buf_size, + unsigned int regset) { + return NativeProcessAIX::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), + static_cast(®set), buf, + buf_size); +} + +Status NativeRegisterContextAIX::DoReadRegisterValue(uint32_t offset, + const char *reg_name, + uint32_t size, + RegisterValue &value) { + Log *log = GetLog(POSIXLog::Registers); + + long data; + Status error = NativeProcessAIX::PtraceWrapper( + PTRACE_PEEKUSER, m_thread.GetID(), reinterpret_cast(offset), + nullptr, 0, &data); + + if (error.Success()) + // First cast to an unsigned of the same size to avoid sign extension. + value.SetUInt(static_cast(data), size); + + LLDB_LOG(log, "{0}: {1:x}", reg_name, data); + return error; +} + +Status NativeRegisterContextAIX::DoWriteRegisterValue( + uint32_t offset, const char *reg_name, const RegisterValue &value) { + Log *log = GetLog(POSIXLog::Registers); + + void *buf = reinterpret_cast(value.GetAsUInt64()); + LLDB_LOG(log, "{0}: {1}", reg_name, buf); + + return NativeProcessAIX::PtraceWrapper( + PTRACE_POKEUSER, m_thread.GetID(), reinterpret_cast(offset), buf); +} diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h new file mode 100644 index 0000000000000..9c2a326856c0b --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h @@ -0,0 +1,133 @@ +//===-- NativeRegisterContextAIX.h ----------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_NativeRegisterContextAIX_h +#define lldb_NativeRegisterContextAIX_h + +#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h" +#include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/Target/MemoryTagManager.h" +#include "llvm/Support/Error.h" + +namespace lldb_private { +namespace process_aix { + +class NativeThreadAIX; + +class NativeRegisterContextAIX + : public virtual NativeRegisterContextRegisterInfo { +public: + // This function is implemented in the NativeRegisterContextAIX_* subclasses + // to create a new instance of the host specific NativeRegisterContextAIX. + // The implementations can't collide as only one NativeRegisterContextAIX_* + // variant should be compiled into the final executable. + static std::unique_ptr + CreateHostNativeRegisterContextAIX(const ArchSpec &target_arch, + NativeThreadAIX &native_thread); + + // Invalidates cached values in register context data structures + virtual void InvalidateAllRegisters(){} + + struct SyscallData { + /// The syscall instruction. If the architecture uses software + /// single-stepping, the instruction should also be followed by a trap to + /// ensure the process is stopped after the syscall. + llvm::ArrayRef Insn; + + /// Registers used for syscall arguments. The first register is used to + /// store the syscall number. + llvm::ArrayRef Args; + + uint32_t Result; ///< Register containing the syscall result. + }; + /// Return architecture-specific data needed to make inferior syscalls, if + /// they are supported. + virtual std::optional GetSyscallData() { return std::nullopt; } + + struct MmapData { + // Syscall numbers can be found (e.g.) in /usr/include/asm/unistd.h for the + // relevant architecture. + unsigned SysMmap; ///< mmap syscall number. + unsigned SysMunmap; ///< munmap syscall number + }; + /// Return the architecture-specific data needed to make mmap syscalls, if + /// they are supported. + virtual std::optional GetMmapData() { return std::nullopt; } + + struct MemoryTaggingDetails { + /// Object with tag handling utilities. If the function below returns + /// a valid structure, you can assume that this pointer is valid. + std::unique_ptr manager; + int ptrace_read_req; /// ptrace operation number for memory tag read + int ptrace_write_req; /// ptrace operation number for memory tag write + }; + /// Return architecture specific data needed to use memory tags, + /// if they are supported. + virtual llvm::Expected + GetMemoryTaggingDetails(int32_t type) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Architecture does not support memory tagging"); + } + +protected: + // NB: This constructor is here only because gcc<=6.5 requires a virtual base + // class initializer on abstract class (even though it is never used). It can + // be deleted once we move to gcc>=7.0. + NativeRegisterContextAIX(NativeThreadProtocol &thread) + : NativeRegisterContextRegisterInfo(thread, nullptr) {} + + lldb::ByteOrder GetByteOrder() const; + + virtual Status ReadRegisterRaw(uint32_t reg_index, RegisterValue ®_value); + + virtual Status WriteRegisterRaw(uint32_t reg_index, + const RegisterValue ®_value); + + virtual Status ReadRegisterSet(void *buf, size_t buf_size, + unsigned int regset); + + virtual Status WriteRegisterSet(void *buf, size_t buf_size, + unsigned int regset); + + virtual Status ReadGPR(); + + virtual Status WriteGPR(); + + virtual Status ReadFPR(); + + virtual Status WriteFPR(); + + virtual void *GetGPRBuffer() = 0; + + virtual size_t GetGPRSize() const { + return GetRegisterInfoInterface().GetGPRSize(); + } + + virtual void *GetFPRBuffer() = 0; + + virtual size_t GetFPRSize() = 0; + + virtual uint32_t GetPtraceOffset(uint32_t reg_index) { + return GetRegisterInfoAtIndex(reg_index)->byte_offset; + } + + // The Do*** functions are executed on the privileged thread and can perform + // ptrace + // operations directly. + virtual Status DoReadRegisterValue(uint32_t offset, const char *reg_name, + uint32_t size, RegisterValue &value); + + virtual Status DoWriteRegisterValue(uint32_t offset, const char *reg_name, + const RegisterValue &value); +}; + +} // namespace process_aix +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextAIX_h diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp new file mode 100644 index 0000000000000..1996373791748 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp @@ -0,0 +1,744 @@ +//===-- NativeRegisterContextAIX_ppc64.cpp ----------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// This implementation is related to the OpenPOWER ABI for Power Architecture +// 64-bit ELF V2 ABI + +#if defined(__powerpc64__) + +#include "NativeRegisterContextAIX_ppc64.h" + +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Status.h" +#include "lldb/Host/aix/Ptrace.h" + +#include "Plugins/Process/AIX/NativeProcessAIX.h" +#include "Plugins/Process/Linux/Procfs.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h" + +// System includes - They have to be included after framework includes because +// they define some macros which collide with variable names in other modules +#include +#include +#include +#include + +#define REG_CONTEXT_SIZE \ + (GetGPRSize() + GetFPRSize() + sizeof(m_vmx_ppc64le) + sizeof(m_vsx_ppc64le)) +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; + +static const uint32_t g_gpr_regnums_ppc64le[] = { + gpr_r0_ppc64le, gpr_r1_ppc64le, gpr_r2_ppc64le, gpr_r3_ppc64le, + gpr_r4_ppc64le, gpr_r5_ppc64le, gpr_r6_ppc64le, gpr_r7_ppc64le, + gpr_r8_ppc64le, gpr_r9_ppc64le, gpr_r10_ppc64le, gpr_r11_ppc64le, + gpr_r12_ppc64le, gpr_r13_ppc64le, gpr_r14_ppc64le, gpr_r15_ppc64le, + gpr_r16_ppc64le, gpr_r17_ppc64le, gpr_r18_ppc64le, gpr_r19_ppc64le, + gpr_r20_ppc64le, gpr_r21_ppc64le, gpr_r22_ppc64le, gpr_r23_ppc64le, + gpr_r24_ppc64le, gpr_r25_ppc64le, gpr_r26_ppc64le, gpr_r27_ppc64le, + gpr_r28_ppc64le, gpr_r29_ppc64le, gpr_r30_ppc64le, gpr_r31_ppc64le, + gpr_pc_ppc64le, gpr_msr_ppc64le, gpr_origr3_ppc64le, gpr_ctr_ppc64le, + gpr_lr_ppc64le, gpr_xer_ppc64le, gpr_cr_ppc64le, gpr_softe_ppc64le, + gpr_trap_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +static const uint32_t g_fpr_regnums_ppc64le[] = { + fpr_f0_ppc64le, fpr_f1_ppc64le, fpr_f2_ppc64le, fpr_f3_ppc64le, + fpr_f4_ppc64le, fpr_f5_ppc64le, fpr_f6_ppc64le, fpr_f7_ppc64le, + fpr_f8_ppc64le, fpr_f9_ppc64le, fpr_f10_ppc64le, fpr_f11_ppc64le, + fpr_f12_ppc64le, fpr_f13_ppc64le, fpr_f14_ppc64le, fpr_f15_ppc64le, + fpr_f16_ppc64le, fpr_f17_ppc64le, fpr_f18_ppc64le, fpr_f19_ppc64le, + fpr_f20_ppc64le, fpr_f21_ppc64le, fpr_f22_ppc64le, fpr_f23_ppc64le, + fpr_f24_ppc64le, fpr_f25_ppc64le, fpr_f26_ppc64le, fpr_f27_ppc64le, + fpr_f28_ppc64le, fpr_f29_ppc64le, fpr_f30_ppc64le, fpr_f31_ppc64le, + fpr_fpscr_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +static const uint32_t g_vmx_regnums_ppc64le[] = { + vmx_vr0_ppc64le, vmx_vr1_ppc64le, vmx_vr2_ppc64le, vmx_vr3_ppc64le, + vmx_vr4_ppc64le, vmx_vr5_ppc64le, vmx_vr6_ppc64le, vmx_vr7_ppc64le, + vmx_vr8_ppc64le, vmx_vr9_ppc64le, vmx_vr10_ppc64le, vmx_vr11_ppc64le, + vmx_vr12_ppc64le, vmx_vr13_ppc64le, vmx_vr14_ppc64le, vmx_vr15_ppc64le, + vmx_vr16_ppc64le, vmx_vr17_ppc64le, vmx_vr18_ppc64le, vmx_vr19_ppc64le, + vmx_vr20_ppc64le, vmx_vr21_ppc64le, vmx_vr22_ppc64le, vmx_vr23_ppc64le, + vmx_vr24_ppc64le, vmx_vr25_ppc64le, vmx_vr26_ppc64le, vmx_vr27_ppc64le, + vmx_vr28_ppc64le, vmx_vr29_ppc64le, vmx_vr30_ppc64le, vmx_vr31_ppc64le, + vmx_vscr_ppc64le, vmx_vrsave_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +static const uint32_t g_vsx_regnums_ppc64le[] = { + vsx_vs0_ppc64le, vsx_vs1_ppc64le, vsx_vs2_ppc64le, vsx_vs3_ppc64le, + vsx_vs4_ppc64le, vsx_vs5_ppc64le, vsx_vs6_ppc64le, vsx_vs7_ppc64le, + vsx_vs8_ppc64le, vsx_vs9_ppc64le, vsx_vs10_ppc64le, vsx_vs11_ppc64le, + vsx_vs12_ppc64le, vsx_vs13_ppc64le, vsx_vs14_ppc64le, vsx_vs15_ppc64le, + vsx_vs16_ppc64le, vsx_vs17_ppc64le, vsx_vs18_ppc64le, vsx_vs19_ppc64le, + vsx_vs20_ppc64le, vsx_vs21_ppc64le, vsx_vs22_ppc64le, vsx_vs23_ppc64le, + vsx_vs24_ppc64le, vsx_vs25_ppc64le, vsx_vs26_ppc64le, vsx_vs27_ppc64le, + vsx_vs28_ppc64le, vsx_vs29_ppc64le, vsx_vs30_ppc64le, vsx_vs31_ppc64le, + vsx_vs32_ppc64le, vsx_vs33_ppc64le, vsx_vs34_ppc64le, vsx_vs35_ppc64le, + vsx_vs36_ppc64le, vsx_vs37_ppc64le, vsx_vs38_ppc64le, vsx_vs39_ppc64le, + vsx_vs40_ppc64le, vsx_vs41_ppc64le, vsx_vs42_ppc64le, vsx_vs43_ppc64le, + vsx_vs44_ppc64le, vsx_vs45_ppc64le, vsx_vs46_ppc64le, vsx_vs47_ppc64le, + vsx_vs48_ppc64le, vsx_vs49_ppc64le, vsx_vs50_ppc64le, vsx_vs51_ppc64le, + vsx_vs52_ppc64le, vsx_vs53_ppc64le, vsx_vs54_ppc64le, vsx_vs55_ppc64le, + vsx_vs56_ppc64le, vsx_vs57_ppc64le, vsx_vs58_ppc64le, vsx_vs59_ppc64le, + vsx_vs60_ppc64le, vsx_vs61_ppc64le, vsx_vs62_ppc64le, vsx_vs63_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +// Number of register sets provided by this context. +static constexpr int k_num_register_sets = 4; + +static const RegisterSet g_reg_sets_ppc64le[k_num_register_sets] = { + {"General Purpose Registers", "gpr", k_num_gpr_registers_ppc64le, + g_gpr_regnums_ppc64le}, + {"Floating Point Registers", "fpr", k_num_fpr_registers_ppc64le, + g_fpr_regnums_ppc64le}, + {"AltiVec/VMX Registers", "vmx", k_num_vmx_registers_ppc64le, + g_vmx_regnums_ppc64le}, + {"VSX Registers", "vsx", k_num_vsx_registers_ppc64le, + g_vsx_regnums_ppc64le}, +}; + +std::unique_ptr +NativeRegisterContextAIX::CreateHostNativeRegisterContextAIX( + const ArchSpec &target_arch, NativeThreadAIX &native_thread) { + switch (target_arch.GetMachine()) { + case llvm::Triple::ppc64: + return std::make_unique(target_arch, + native_thread); + default: + llvm_unreachable("have no register context for architecture"); + } +} + +NativeRegisterContextAIX_ppc64::NativeRegisterContextAIX_ppc64( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + : NativeRegisterContextRegisterInfo( + native_thread, new RegisterInfoPOSIX_ppc64le(target_arch)), + NativeRegisterContextAIX(native_thread) { + if (target_arch.GetMachine() != llvm::Triple::ppc64) { + llvm_unreachable("Unhandled target architecture."); + } + + ::memset(&m_gpr_ppc64le, 0, sizeof(m_gpr_ppc64le)); + ::memset(&m_fpr_ppc64le, 0, sizeof(m_fpr_ppc64le)); + ::memset(&m_vmx_ppc64le, 0, sizeof(m_vmx_ppc64le)); + ::memset(&m_vsx_ppc64le, 0, sizeof(m_vsx_ppc64le)); + ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); +} + +uint32_t NativeRegisterContextAIX_ppc64::GetRegisterSetCount() const { + return k_num_register_sets; +} + +const RegisterSet * +NativeRegisterContextAIX_ppc64::GetRegisterSet(uint32_t set_index) const { + if (set_index < k_num_register_sets) + return &g_reg_sets_ppc64le[set_index]; + + return nullptr; +} + +uint32_t NativeRegisterContextAIX_ppc64::GetUserRegisterCount() const { + uint32_t count = 0; + for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) + count += g_reg_sets_ppc64le[set_index].num_registers; + return count; +} + +Status NativeRegisterContextAIX_ppc64::ReadRegister( + const RegisterInfo *reg_info, RegisterValue ®_value) { + Status error; + + if (!reg_info) { + error.SetErrorString("reg_info NULL"); + return error; + } + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (IsFPR(reg)) { + error = ReadFPR(); + if (error.Fail()) + return error; + + // Get pointer to m_fpr_ppc64le variable and set the data from it. + uint32_t fpr_offset = CalculateFprOffset(reg_info); + assert(fpr_offset < sizeof m_fpr_ppc64le); + uint8_t *src = (uint8_t *)&m_fpr_ppc64le + fpr_offset; + reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } else if (IsVSX(reg)) { + uint32_t vsx_offset = CalculateVsxOffset(reg_info); + assert(vsx_offset < sizeof(m_vsx_ppc64le)); + + if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) { + error = ReadVSX(); + if (error.Fail()) + return error; + + error = ReadFPR(); + if (error.Fail()) + return error; + + uint64_t value[2]; + uint8_t *dst, *src; + dst = (uint8_t *)&value; + src = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + dst += 8; + src = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + reg_value.SetFromMemoryData(*reg_info, &value, reg_info->byte_size, + eByteOrderLittle, error); + } else { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data from it. + uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2; + uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } + } else if (IsVMX(reg)) { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data from it. + uint32_t vmx_offset = CalculateVmxOffset(reg_info); + assert(vmx_offset < sizeof m_vmx_ppc64le); + uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } else if (IsGPR(reg)) { + error = ReadGPR(); + if (error.Fail()) + return error; + + uint8_t *src = (uint8_t *) &m_gpr_ppc64le + reg_info->byte_offset; + reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } else { + return Status("failed - register wasn't recognized to be a GPR, FPR, VSX " + "or VMX, read strategy unknown"); + } + + return error; +} + +Status NativeRegisterContextAIX_ppc64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue ®_value) { + Status error; + if (!reg_info) + return Status("reg_info NULL"); + + const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; + if (reg_index == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : ""); + + if (IsGPR(reg_index)) { + error = ReadGPR(); + if (error.Fail()) + return error; + + uint8_t *dst = (uint8_t *)&m_gpr_ppc64le + reg_info->byte_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + *(uint64_t *)dst = llvm::byteswap(*(uint64_t *)dst); + + error = WriteGPR(); + if (error.Fail()) + return error; + + return Status(); + } + + if (IsFPR(reg_index)) { + error = ReadFPR(); + if (error.Fail()) + return error; + + // Get pointer to m_fpr_ppc64le variable and set the data to it. + uint32_t fpr_offset = CalculateFprOffset(reg_info); + assert(fpr_offset < GetFPRSize()); + uint8_t *dst = (uint8_t *)&m_fpr_ppc64le + fpr_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + + error = WriteFPR(); + if (error.Fail()) + return error; + + return Status(); + } + + if (IsVMX(reg_index)) { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data to it. + uint32_t vmx_offset = CalculateVmxOffset(reg_info); + assert(vmx_offset < sizeof(m_vmx_ppc64le)); + uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + + error = WriteVMX(); + if (error.Fail()) + return error; + + return Status(); + } + + if (IsVSX(reg_index)) { + uint32_t vsx_offset = CalculateVsxOffset(reg_info); + assert(vsx_offset < sizeof(m_vsx_ppc64le)); + + if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) { + error = ReadVSX(); + if (error.Fail()) + return error; + + error = ReadFPR(); + if (error.Fail()) + return error; + + uint64_t value[2]; + ::memcpy(value, reg_value.GetBytes(), 16); + uint8_t *dst, *src; + src = (uint8_t *)value; + dst = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + src += 8; + dst = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + + WriteVSX(); + WriteFPR(); + } else { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data from it. + uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2; + uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + WriteVMX(); + } + + return Status(); + } + + return Status("failed - register wasn't recognized to be a GPR, FPR, VSX " + "or VMX, write strategy unknown"); +} + +Status NativeRegisterContextAIX_ppc64::ReadAllRegisterValues( + lldb::WritableDataBufferSP &data_sp) { + Status error; + + data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); + error = ReadGPR(); + if (error.Fail()) + return error; + + error = ReadFPR(); + if (error.Fail()) + return error; + + error = ReadVMX(); + if (error.Fail()) + return error; + + error = ReadVSX(); + if (error.Fail()) + return error; + + uint8_t *dst = data_sp->GetBytes(); + ::memcpy(dst, &m_gpr_ppc64le, GetGPRSize()); + dst += GetGPRSize(); + ::memcpy(dst, &m_fpr_ppc64le, GetFPRSize()); + dst += GetFPRSize(); + ::memcpy(dst, &m_vmx_ppc64le, sizeof(m_vmx_ppc64le)); + dst += sizeof(m_vmx_ppc64le); + ::memcpy(dst, &m_vsx_ppc64le, sizeof(m_vsx_ppc64le)); + + return error; +} + +Status NativeRegisterContextAIX_ppc64::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + Status error; + + if (!data_sp) { + error.SetErrorStringWithFormat( + "NativeRegisterContextAIX_ppc64::%s invalid data_sp provided", + __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { + error.SetErrorStringWithFormat( + "NativeRegisterContextAIX_ppc64::%s data_sp contained mismatched " + "data size, expected %" PRIu64 ", actual %" PRIu64, + __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); + return error; + } + + const uint8_t *src = data_sp->GetBytes(); + if (src == nullptr) { + error.SetErrorStringWithFormat("NativeRegisterContextAIX_ppc64::%s " + "DataBuffer::GetBytes() returned a null " + "pointer", + __FUNCTION__); + return error; + } + + ::memcpy(&m_gpr_ppc64le, src, GetGPRSize()); + error = WriteGPR(); + + if (error.Fail()) + return error; + + src += GetGPRSize(); + ::memcpy(&m_fpr_ppc64le, src, GetFPRSize()); + + error = WriteFPR(); + if (error.Fail()) + return error; + + src += GetFPRSize(); + ::memcpy(&m_vmx_ppc64le, src, sizeof(m_vmx_ppc64le)); + + error = WriteVMX(); + if (error.Fail()) + return error; + + src += sizeof(m_vmx_ppc64le); + ::memcpy(&m_vsx_ppc64le, src, sizeof(m_vsx_ppc64le)); + error = WriteVSX(); + + return error; +} + +bool NativeRegisterContextAIX_ppc64::IsGPR(unsigned reg) const { + return reg <= k_last_gpr_ppc64le; // GPR's come first. +} + +bool NativeRegisterContextAIX_ppc64::IsFPR(unsigned reg) const { + return (k_first_fpr_ppc64le <= reg && reg <= k_last_fpr_ppc64le); +} + +uint32_t NativeRegisterContextAIX_ppc64::CalculateFprOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - + GetRegisterInfoAtIndex(k_first_fpr_ppc64le)->byte_offset; +} + +uint32_t NativeRegisterContextAIX_ppc64::CalculateVmxOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - + GetRegisterInfoAtIndex(k_first_vmx_ppc64le)->byte_offset; +} + +uint32_t NativeRegisterContextAIX_ppc64::CalculateVsxOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - + GetRegisterInfoAtIndex(k_first_vsx_ppc64le)->byte_offset; +} + +Status NativeRegisterContextAIX_ppc64::ReadVMX() { + return NativeProcessAIX::PtraceWrapper(PTRACE_GETVRREGS, m_thread.GetID(), + nullptr, &m_vmx_ppc64le, + sizeof(m_vmx_ppc64le)); +} + +Status NativeRegisterContextAIX_ppc64::WriteVMX() { + //FIXME + int regset = 0/*NT_PPC_VMX*/; + return NativeProcessAIX::PtraceWrapper(PT_CLEAR/*PTRACE_SETVRREGS*/, m_thread.GetID(), + ®set, &m_vmx_ppc64le, + sizeof(m_vmx_ppc64le)); +} + +Status NativeRegisterContextAIX_ppc64::ReadVSX() { + return NativeProcessAIX::PtraceWrapper(PTRACE_GETVSRREGS, m_thread.GetID(), + nullptr, &m_vsx_ppc64le, + sizeof(m_vsx_ppc64le)); +} + +Status NativeRegisterContextAIX_ppc64::WriteVSX() { + //FIXME + int regset = 0/*NT_PPC_VSX*/; + return NativeProcessAIX::PtraceWrapper(PT_CLEAR/*PTRACE_SETVSRREGS*/, m_thread.GetID(), + ®set, &m_vsx_ppc64le, + sizeof(m_vsx_ppc64le)); +} + +bool NativeRegisterContextAIX_ppc64::IsVMX(unsigned reg) { + return (reg >= k_first_vmx_ppc64le) && (reg <= k_last_vmx_ppc64le); +} + +bool NativeRegisterContextAIX_ppc64::IsVSX(unsigned reg) { + return (reg >= k_first_vsx_ppc64le) && (reg <= k_last_vsx_ppc64le); +} + +uint32_t NativeRegisterContextAIX_ppc64::NumSupportedHardwareWatchpoints() { + Log *log = GetLog(POSIXLog::Watchpoints); + + // Read hardware breakpoint and watchpoint information. + Status error = ReadHardwareDebugInfo(); + + if (error.Fail()) + return 0; + + LLDB_LOG(log, "{0}", m_max_hwp_supported); + return m_max_hwp_supported; +} + +uint32_t NativeRegisterContextAIX_ppc64::SetHardwareWatchpoint( + lldb::addr_t addr, size_t size, uint32_t watch_flags) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size, + watch_flags); + + // Read hardware breakpoint and watchpoint information. + Status error = ReadHardwareDebugInfo(); + + if (error.Fail()) + return LLDB_INVALID_INDEX32; + + uint32_t control_value = 0, wp_index = 0; + lldb::addr_t real_addr = addr; + uint32_t rw_mode = 0; + + // Check if we are setting watchpoint other than read/write/access Update + // watchpoint flag to match ppc64le write-read bit configuration. + switch (watch_flags) { + case eWatchpointKindWrite: + //FIXME + //rw_mode = 0/*PPC_BREAKPOINT_TRIGGER_WRITE*/; + watch_flags = 2; + break; + // Watchpoint read not supported + case eWatchpointKindRead: + case (eWatchpointKindRead | eWatchpointKindWrite): + default: + return LLDB_INVALID_INDEX32; + } + + // Check if size has a valid hardware watchpoint length. + if (size != 8) + return LLDB_INVALID_INDEX32; + + // Check 8-byte alignment for hardware watchpoint target address. Below is a + // hack to recalculate address and size in order to make sure we can watch + // non 8-byte aligned addresses as well. + if (addr & 0x07) { + + addr_t begin = llvm::alignDown(addr, 8); + addr_t end = llvm::alignTo(addr + size, 8); + size = llvm::PowerOf2Ceil(end - begin); + + addr = addr & (~0x07); + } + + // Setup control value + control_value = watch_flags << 3; + control_value |= ((1 << size) - 1) << 5; + control_value |= (2 << 1) | 1; + + // Iterate over stored watchpoints and find a free wp_index + wp_index = LLDB_INVALID_INDEX32; + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + if ((m_hwp_regs[i].control & 1) == 0) { + wp_index = i; // Mark last free slot + } else if (m_hwp_regs[i].address == addr) { + return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints. + } + } + + if (wp_index == LLDB_INVALID_INDEX32) + return LLDB_INVALID_INDEX32; + + // Update watchpoint in local cache + m_hwp_regs[wp_index].real_addr = real_addr; + m_hwp_regs[wp_index].address = addr; + m_hwp_regs[wp_index].control = control_value; + //m_hwp_regs[wp_index].mode = rw_mode; + + // PTRACE call to set corresponding watchpoint register. + error = WriteHardwareDebugRegs(); + + if (error.Fail()) { + m_hwp_regs[wp_index].address = 0; + m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros(1); + + return LLDB_INVALID_INDEX32; + } + + return wp_index; +} + +bool NativeRegisterContextAIX_ppc64::ClearHardwareWatchpoint( + uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + // Read hardware breakpoint and watchpoint information. + Status error = ReadHardwareDebugInfo(); + + if (error.Fail()) + return false; + + if (wp_index >= m_max_hwp_supported) + return false; + + // Create a backup we can revert to in case of failure. + lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; + uint32_t tempControl = m_hwp_regs[wp_index].control; + long *tempSlot = reinterpret_cast(m_hwp_regs[wp_index].slot); + + // Update watchpoint in local cache + m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros(1); + m_hwp_regs[wp_index].address = 0; + m_hwp_regs[wp_index].slot = 0; + m_hwp_regs[wp_index].mode = 0; + + // Ptrace call to update hardware debug registers + //FIXME + error = NativeProcessAIX::PtraceWrapper(PT_CLEAR/*PPC_PTRACE_DELHWDEBUG*/, + m_thread.GetID(), 0, tempSlot); + + if (error.Fail()) { + m_hwp_regs[wp_index].control = tempControl; + m_hwp_regs[wp_index].address = tempAddr; + m_hwp_regs[wp_index].slot = reinterpret_cast(tempSlot); + + return false; + } + + return true; +} + +uint32_t +NativeRegisterContextAIX_ppc64::GetWatchpointSize(uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + unsigned control = (m_hwp_regs[wp_index].control >> 5) & 0xff; + if (llvm::isPowerOf2_32(control + 1)) { + return llvm::popcount(control); + } + + return 0; +} + +bool NativeRegisterContextAIX_ppc64::WatchpointIsEnabled( + uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + return !!((m_hwp_regs[wp_index].control & 0x1) == 0x1); +} + +Status NativeRegisterContextAIX_ppc64::GetWatchpointHitIndex( + uint32_t &wp_index, lldb::addr_t trap_addr) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr); + + uint32_t watch_size; + lldb::addr_t watch_addr; + + for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) { + watch_size = GetWatchpointSize(wp_index); + watch_addr = m_hwp_regs[wp_index].address; + + if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr && + trap_addr <= watch_addr + watch_size) { + m_hwp_regs[wp_index].hit_addr = trap_addr; + return Status(); + } + } + + wp_index = LLDB_INVALID_INDEX32; + return Status(); +} + +lldb::addr_t +NativeRegisterContextAIX_ppc64::GetWatchpointAddress(uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + if (wp_index >= m_max_hwp_supported) + return LLDB_INVALID_ADDRESS; + + if (WatchpointIsEnabled(wp_index)) + return m_hwp_regs[wp_index].real_addr; + else + return LLDB_INVALID_ADDRESS; +} + +lldb::addr_t +NativeRegisterContextAIX_ppc64::GetWatchpointHitAddress(uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + if (wp_index >= m_max_hwp_supported) + return LLDB_INVALID_ADDRESS; + + if (WatchpointIsEnabled(wp_index)) + return m_hwp_regs[wp_index].hit_addr; + + return LLDB_INVALID_ADDRESS; +} + +Status NativeRegisterContextAIX_ppc64::ReadHardwareDebugInfo() { + if (!m_refresh_hwdebug_info) { + return Status(); + } + + m_max_hwp_supported = 1; + m_max_hbp_supported = 0; + m_refresh_hwdebug_info = false; + + return Status(); +} + +Status NativeRegisterContextAIX_ppc64::WriteHardwareDebugRegs() { + Status error; + long ret; + + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + if ((m_hwp_regs[i].control & 1) == 0) + continue; + + error = NativeProcessAIX::PtraceWrapper(PT_WATCH, m_thread.GetID(), (void *)m_hwp_regs[i].address, nullptr, 8, &ret); + + if (error.Fail()) + return error; + + m_hwp_regs[i].slot = ret; + } + return error; +} + +#endif // defined(__powerpc64__) diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h new file mode 100644 index 0000000000000..a29f786f2313a --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h @@ -0,0 +1,138 @@ +//===-- NativeRegisterContextAIX_ppc64.h --------------------*- 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 +// +//===----------------------------------------------------------------------===// + +// This implementation is related to the OpenPOWER ABI for Power Architecture +// 64-bit ELF V2 ABI + +#if defined(__powerpc64__) + +#ifndef lldb_NativeRegisterContextAIX_ppc64_h +#define lldb_NativeRegisterContextAIX_ppc64_h + +#include "Plugins/Process/AIX/NativeRegisterContextAIX.h" +#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" + +#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT +#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h" +#undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT + +namespace lldb_private { +namespace process_aix { + +class NativeProcessAIX; + +class NativeRegisterContextAIX_ppc64 : public NativeRegisterContextAIX { +public: + NativeRegisterContextAIX_ppc64(const ArchSpec &target_arch, + NativeThreadProtocol &native_thread); + + uint32_t GetRegisterSetCount() const override; + + uint32_t GetUserRegisterCount() const override; + + const RegisterSet *GetRegisterSet(uint32_t set_index) const override; + + Status ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + + Status WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + + Status ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override; + + Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + // Hardware watchpoint management functions + + uint32_t NumSupportedHardwareWatchpoints() override; + + uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags) override; + + bool ClearHardwareWatchpoint(uint32_t hw_index) override; + + Status GetWatchpointHitIndex(uint32_t &wp_index, + lldb::addr_t trap_addr) override; + + lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override; + + lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; + + uint32_t GetWatchpointSize(uint32_t wp_index); + + bool WatchpointIsEnabled(uint32_t wp_index); + +protected: + bool IsVMX(unsigned reg); + + bool IsVSX(unsigned reg); + + Status ReadVMX(); + + Status WriteVMX(); + + Status ReadVSX(); + + Status WriteVSX(); + + void *GetGPRBuffer() override { return &m_gpr_ppc64le; } + + void *GetFPRBuffer() override { return &m_fpr_ppc64le; } + + size_t GetFPRSize() override { return sizeof(m_fpr_ppc64le); } + +private: + GPR m_gpr_ppc64le; // 64-bit general purpose registers. + FPR m_fpr_ppc64le; // floating-point registers including extended register. + VMX m_vmx_ppc64le; // VMX registers. + VSX m_vsx_ppc64le; // Last lower bytes from first VSX registers. + + bool IsGPR(unsigned reg) const; + + bool IsFPR(unsigned reg) const; + + bool IsVMX(unsigned reg) const; + + bool IsVSX(unsigned reg) const; + + uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const; + + uint32_t CalculateVmxOffset(const RegisterInfo *reg_info) const; + + uint32_t CalculateVsxOffset(const RegisterInfo *reg_info) const; + + Status ReadHardwareDebugInfo(); + + Status WriteHardwareDebugRegs(); + + // Debug register info for hardware watchpoints management. + struct DREG { + lldb::addr_t address; // Breakpoint/watchpoint address value. + lldb::addr_t hit_addr; // Address at which last watchpoint trigger + // exception occurred. + lldb::addr_t real_addr; // Address value that should cause target to stop. + uint32_t control; // Breakpoint/watchpoint control value. + uint32_t refcount; // Serves as enable/disable and reference counter. + long slot; // Saves the value returned from PTRACE_SETHWDEBUG. + int mode; // Defines if watchpoint is read/write/access. + }; + + std::array m_hwp_regs; + + // 16 is just a maximum value, query hardware for actual watchpoint count + uint32_t m_max_hwp_supported = 16; + uint32_t m_max_hbp_supported = 16; + bool m_refresh_hwdebug_info = true; +}; + +} // namespace process_aix +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextAIX_ppc64_h + +#endif // defined(__powerpc64__) diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp new file mode 100644 index 0000000000000..e07daccdff550 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp @@ -0,0 +1,526 @@ +//===-- NativeThreadAIX.cpp ---------------------------------------------===// +// +// 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 "NativeThreadAIX.h" + +#include +#include + +#include "NativeProcessAIX.h" +#include "NativeRegisterContextAIX.h" + +#include "lldb/Host/HostNativeThread.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" +#include "lldb/lldb-enumerations.h" + +#include "llvm/ADT/SmallString.h" + +#include "Plugins/Process/POSIX/CrashReason.h" + +#include +#include +#include + +#if 0 +#include +// Try to define a macro to encapsulate the tgkill syscall +#define tgkill(pid, tid, sig) \ + syscall(__NR_tgkill, static_cast<::pid_t>(pid), static_cast<::pid_t>(tid), \ + sig) +#endif + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; + +namespace { +void LogThreadStopInfo(Log &log, const ThreadStopInfo &stop_info, + const char *const header) { + switch (stop_info.reason) { + case eStopReasonNone: + log.Printf("%s: %s no stop reason", __FUNCTION__, header); + return; + case eStopReasonTrace: + log.Printf("%s: %s trace, stopping signal 0x%" PRIx32, __FUNCTION__, header, + stop_info.signo); + return; + case eStopReasonBreakpoint: + log.Printf("%s: %s breakpoint, stopping signal 0x%" PRIx32, __FUNCTION__, + header, stop_info.signo); + return; + case eStopReasonWatchpoint: + log.Printf("%s: %s watchpoint, stopping signal 0x%" PRIx32, __FUNCTION__, + header, stop_info.signo); + return; + case eStopReasonSignal: + log.Printf("%s: %s signal 0x%02" PRIx32, __FUNCTION__, header, + stop_info.signo); + return; + case eStopReasonException: + log.Printf("%s: %s exception type 0x%02" PRIx64, __FUNCTION__, header, + stop_info.details.exception.type); + return; + case eStopReasonExec: + log.Printf("%s: %s exec, stopping signal 0x%" PRIx32, __FUNCTION__, header, + stop_info.signo); + return; + case eStopReasonPlanComplete: + log.Printf("%s: %s plan complete", __FUNCTION__, header); + return; + case eStopReasonThreadExiting: + log.Printf("%s: %s thread exiting", __FUNCTION__, header); + return; + case eStopReasonInstrumentation: + log.Printf("%s: %s instrumentation", __FUNCTION__, header); + return; + case eStopReasonProcessorTrace: + log.Printf("%s: %s processor trace", __FUNCTION__, header); + return; + default: + log.Printf("%s: %s invalid stop reason %" PRIu32, __FUNCTION__, header, + static_cast(stop_info.reason)); + } +} +} + +NativeThreadAIX::NativeThreadAIX(NativeProcessAIX &process, + lldb::tid_t tid) + : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid), + m_stop_info(), + m_reg_context_up( + NativeRegisterContextAIX::CreateHostNativeRegisterContextAIX( + process.GetArchitecture(), *this)), + m_stop_description() {} + +std::string NativeThreadAIX::GetName() { + NativeProcessAIX &process = GetProcess(); + + auto BufferOrError = getProcFile(process.GetID(), GetID(), "comm"); + if (!BufferOrError) + return ""; + return std::string(BufferOrError.get()->getBuffer().rtrim('\n')); +} + +lldb::StateType NativeThreadAIX::GetState() { return m_state; } + +bool NativeThreadAIX::GetStopReason(ThreadStopInfo &stop_info, + std::string &description) { + Log *log = GetLog(LLDBLog::Thread); + + description.clear(); + + switch (m_state) { + case eStateStopped: + case eStateCrashed: + case eStateExited: + case eStateSuspended: + case eStateUnloaded: + if (log) + LogThreadStopInfo(*log, m_stop_info, "m_stop_info in thread:"); + stop_info = m_stop_info; + description = m_stop_description; + if (log) + LogThreadStopInfo(*log, stop_info, "returned stop_info:"); + + return true; + + case eStateInvalid: + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + case eStateRunning: + case eStateStepping: + case eStateDetached: + if (log) { + LLDB_LOGF(log, + "NativeThreadAIX::%s tid %" PRIu64 + " in state %s cannot answer stop reason", + __FUNCTION__, GetID(), StateAsCString(m_state)); + } + return false; + } + llvm_unreachable("unhandled StateType!"); +} + +Status NativeThreadAIX::SetWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags, bool hardware) { + if (!hardware) + return Status("not implemented"); + if (m_state == eStateLaunching) + return Status(); + Status error = RemoveWatchpoint(addr); + if (error.Fail()) + return error; + uint32_t wp_index = + m_reg_context_up->SetHardwareWatchpoint(addr, size, watch_flags); + if (wp_index == LLDB_INVALID_INDEX32) + return Status("Setting hardware watchpoint failed."); + m_watchpoint_index_map.insert({addr, wp_index}); + return Status(); +} + +Status NativeThreadAIX::RemoveWatchpoint(lldb::addr_t addr) { + auto wp = m_watchpoint_index_map.find(addr); + if (wp == m_watchpoint_index_map.end()) + return Status(); + uint32_t wp_index = wp->second; + m_watchpoint_index_map.erase(wp); + if (m_reg_context_up->ClearHardwareWatchpoint(wp_index)) + return Status(); + return Status("Clearing hardware watchpoint failed."); +} + +Status NativeThreadAIX::SetHardwareBreakpoint(lldb::addr_t addr, + size_t size) { + if (m_state == eStateLaunching) + return Status(); + + Status error = RemoveHardwareBreakpoint(addr); + if (error.Fail()) + return error; + + uint32_t bp_index = m_reg_context_up->SetHardwareBreakpoint(addr, size); + + if (bp_index == LLDB_INVALID_INDEX32) + return Status("Setting hardware breakpoint failed."); + + m_hw_break_index_map.insert({addr, bp_index}); + return Status(); +} + +Status NativeThreadAIX::RemoveHardwareBreakpoint(lldb::addr_t addr) { + auto bp = m_hw_break_index_map.find(addr); + if (bp == m_hw_break_index_map.end()) + return Status(); + + uint32_t bp_index = bp->second; + if (m_reg_context_up->ClearHardwareBreakpoint(bp_index)) { + m_hw_break_index_map.erase(bp); + return Status(); + } + + return Status("Clearing hardware breakpoint failed."); +} + +Status NativeThreadAIX::Resume(uint32_t signo) { + const StateType new_state = StateType::eStateRunning; + MaybeLogStateChange(new_state); + m_state = new_state; + + m_stop_info.reason = StopReason::eStopReasonNone; + m_stop_description.clear(); + + // If watchpoints have been set, but none on this thread, then this is a new + // thread. So set all existing watchpoints. + if (m_watchpoint_index_map.empty()) { + NativeProcessAIX &process = GetProcess(); + + const auto &watchpoint_map = process.GetWatchpointMap(); + m_reg_context_up->ClearAllHardwareWatchpoints(); + for (const auto &pair : watchpoint_map) { + const auto &wp = pair.second; + SetWatchpoint(wp.m_addr, wp.m_size, wp.m_watch_flags, wp.m_hardware); + } + } + + // Set all active hardware breakpoint on all threads. + if (m_hw_break_index_map.empty()) { + NativeProcessAIX &process = GetProcess(); + + const auto &hw_breakpoint_map = process.GetHardwareBreakpointMap(); + m_reg_context_up->ClearAllHardwareBreakpoints(); + for (const auto &pair : hw_breakpoint_map) { + const auto &bp = pair.second; + SetHardwareBreakpoint(bp.m_addr, bp.m_size); + } + } + + intptr_t data = 0; + + if (signo != LLDB_INVALID_SIGNAL_NUMBER) + data = signo; + + return NativeProcessAIX::PtraceWrapper(PT_CONTINUE, GetID(), nullptr, + reinterpret_cast(data)); +} + +Status NativeThreadAIX::SingleStep(uint32_t signo) { + const StateType new_state = StateType::eStateStepping; + MaybeLogStateChange(new_state); + m_state = new_state; + m_stop_info.reason = StopReason::eStopReasonNone; + + intptr_t data = 0; + if (signo != LLDB_INVALID_SIGNAL_NUMBER) + data = signo; + + // If hardware single-stepping is not supported, we just do a continue. The + // breakpoint on the next instruction has been setup in + // NativeProcessAIX::Resume. + return NativeProcessAIX::PtraceWrapper( + GetProcess().SupportHardwareSingleStepping() ? PT_STEP : PT_CONTINUE, + m_tid, nullptr, reinterpret_cast(data)); +} + +void NativeThreadAIX::SetStoppedBySignal(uint32_t signo, + const siginfo_t *info) { + Log *log = GetLog(LLDBLog::Thread); + LLDB_LOGF(log, "NativeThreadAIX::%s called with signal 0x%02" PRIx32, + __FUNCTION__, signo); + + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonSignal; + m_stop_info.signo = signo; + + m_stop_description.clear(); + switch (signo) { + case SIGSEGV: + case SIGBUS: + case SIGFPE: + case SIGILL: + break; + } +} + +void NativeThreadAIX::AnnotateSyncTagCheckFault(const siginfo_t *info) { + int32_t allocation_tag_type = 0; + switch (GetProcess().GetArchitecture().GetMachine()) { + default: + return; + } + + auto details = + GetRegisterContext().GetMemoryTaggingDetails(allocation_tag_type); + if (!details) { + llvm::consumeError(details.takeError()); + return; + } + + // We assume that the stop description is currently: + // signal SIGSEGV: sync tag check fault (fault address: ) + // Remove the closing ) + m_stop_description.pop_back(); + + std::stringstream ss; + lldb::addr_t fault_addr = reinterpret_cast(info->si_addr); + std::unique_ptr manager(std::move(details->manager)); + + ss << " logical tag: 0x" << std::hex << manager->GetLogicalTag(fault_addr); + + std::vector allocation_tag_data; + // The fault address may not be granule aligned. ReadMemoryTags will granule + // align any range you give it, potentially making it larger. + // To prevent this set len to 1. This always results in a range that is at + // most 1 granule in size and includes fault_addr. + Status status = GetProcess().ReadMemoryTags(allocation_tag_type, fault_addr, + 1, allocation_tag_data); + + if (status.Success()) { + llvm::Expected> allocation_tag = + manager->UnpackTagsData(allocation_tag_data, 1); + if (allocation_tag) { + ss << " allocation tag: 0x" << std::hex << allocation_tag->front() << ")"; + } else { + llvm::consumeError(allocation_tag.takeError()); + ss << ")"; + } + } else + ss << ")"; + + m_stop_description += ss.str(); +} + +bool NativeThreadAIX::IsStopped(int *signo) { + if (!StateIsStoppedState(m_state, false)) + return false; + + // If we are stopped by a signal, return the signo. + if (signo && m_state == StateType::eStateStopped && + m_stop_info.reason == StopReason::eStopReasonSignal) { + *signo = m_stop_info.signo; + } + + // Regardless, we are stopped. + return true; +} + +void NativeThreadAIX::SetStopped() { + // On every stop, clear any cached register data structures + GetRegisterContext().InvalidateAllRegisters(); + + const StateType new_state = StateType::eStateStopped; + MaybeLogStateChange(new_state); + m_state = new_state; + m_stop_description.clear(); +} + +void NativeThreadAIX::SetStoppedByExec() { + Log *log = GetLog(LLDBLog::Thread); + LLDB_LOGF(log, "NativeThreadAIX::%s()", __FUNCTION__); + + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonExec; + m_stop_info.signo = SIGSTOP; +} + +void NativeThreadAIX::SetStoppedByBreakpoint() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonBreakpoint; + m_stop_info.signo = SIGTRAP; + m_stop_description.clear(); +} + +void NativeThreadAIX::SetStoppedByWatchpoint(uint32_t wp_index) { + SetStopped(); + + lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); + + std::ostringstream ostr; + ostr << m_reg_context_up->GetWatchpointAddress(wp_index) << " "; + ostr << wp_index; + + /* + * MIPS: Last 3bits of the watchpoint address are masked by the kernel. For + * example: + * 'n' is at 0x120010d00 and 'm' is 0x120010d04. When a watchpoint is set at + * 'm', then + * watch exception is generated even when 'n' is read/written. To handle this + * case, + * find the base address of the load/store instruction and append it in the + * stop-info + * packet. + */ + ostr << " " << m_reg_context_up->GetWatchpointHitAddress(wp_index); + + m_stop_description = ostr.str(); + + m_stop_info.reason = StopReason::eStopReasonWatchpoint; + m_stop_info.signo = SIGTRAP; +} + +bool NativeThreadAIX::IsStoppedAtBreakpoint() { + return GetState() == StateType::eStateStopped && + m_stop_info.reason == StopReason::eStopReasonBreakpoint; +} + +bool NativeThreadAIX::IsStoppedAtWatchpoint() { + return GetState() == StateType::eStateStopped && + m_stop_info.reason == StopReason::eStopReasonWatchpoint; +} + +void NativeThreadAIX::SetStoppedByTrace() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonTrace; + m_stop_info.signo = SIGTRAP; +} + +void NativeThreadAIX::SetStoppedByFork(bool is_vfork, lldb::pid_t child_pid) { + SetStopped(); + + m_stop_info.reason = + is_vfork ? StopReason::eStopReasonVFork : StopReason::eStopReasonFork; + m_stop_info.details.fork.child_pid = child_pid; + m_stop_info.details.fork.child_tid = child_pid; +} + +void NativeThreadAIX::SetStoppedByVForkDone() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonVForkDone; +} + +void NativeThreadAIX::SetStoppedWithNoReason() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonNone; + m_stop_info.signo = 0; +} + +void NativeThreadAIX::SetStoppedByProcessorTrace( + llvm::StringRef description) { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonProcessorTrace; + m_stop_info.signo = 0; + m_stop_description = description.str(); +} + +void NativeThreadAIX::SetExited() { + const StateType new_state = StateType::eStateExited; + MaybeLogStateChange(new_state); + m_state = new_state; + + m_stop_info.reason = StopReason::eStopReasonThreadExiting; +} + +Status NativeThreadAIX::RequestStop() { + Log *log = GetLog(LLDBLog::Thread); + + NativeProcessAIX &process = GetProcess(); + + lldb::pid_t pid = process.GetID(); + lldb::tid_t tid = GetID(); + + LLDB_LOGF(log, + "NativeThreadAIX::%s requesting thread stop(pid: %" PRIu64 + ", tid: %" PRIu64 ")", + __FUNCTION__, pid, tid); + + Status err; + errno = 0; + if (::kill(pid, SIGSTOP) != 0) { + err.SetErrorToErrno(); + LLDB_LOGF(log, + "NativeThreadAIX::%s kill(%" PRIu64 ", SIGSTOP) failed: %s", + __FUNCTION__, pid, err.AsCString()); + } + return err; +} + +void NativeThreadAIX::MaybeLogStateChange(lldb::StateType new_state) { + Log *log = GetLog(LLDBLog::Thread); + // If we're not logging, we're done. + if (!log) + return; + + // If this is a state change to the same state, we're done. + lldb::StateType old_state = m_state; + if (new_state == old_state) + return; + + LLDB_LOG(log, "pid={0}, tid={1}: changing from state {2} to {3}", + m_process.GetID(), GetID(), old_state, new_state); +} + +NativeProcessAIX &NativeThreadAIX::GetProcess() { + return static_cast(m_process); +} + +const NativeProcessAIX &NativeThreadAIX::GetProcess() const { + return static_cast(m_process); +} + +llvm::Expected> +NativeThreadAIX::GetSiginfo() const { + auto siginfo_buf = + llvm::WritableMemoryBuffer::getNewUninitMemBuffer(sizeof(siginfo_t)); +#if 0 + Status error = + GetProcess().GetSignalInfo(GetID(), siginfo_buf->getBufferStart()); + if (!error.Success()) + return error.ToError(); +#endif + return std::move(siginfo_buf); +} diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h new file mode 100644 index 0000000000000..706a7ce69da8e --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h @@ -0,0 +1,126 @@ +//===-- NativeThreadAIX.h ----------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeThreadAIX_H_ +#define liblldb_NativeThreadAIX_H_ + +#include "Plugins/Process/AIX/NativeRegisterContextAIX.h" +#include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/lldb-private-forward.h" + +#include "llvm/ADT/StringRef.h" + +#include +#include +#include +#include + +namespace lldb_private { +namespace process_aix { + +class NativeProcessAIX; + +class NativeThreadAIX : public NativeThreadProtocol { + friend class NativeProcessAIX; + +public: + NativeThreadAIX(NativeProcessAIX &process, lldb::tid_t tid); + + // NativeThreadProtocol Interface + std::string GetName() override; + + lldb::StateType GetState() override; + + bool GetStopReason(ThreadStopInfo &stop_info, + std::string &description) override; + + NativeRegisterContextAIX &GetRegisterContext() override { + return *m_reg_context_up; + } + + Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, + bool hardware) override; + + Status RemoveWatchpoint(lldb::addr_t addr) override; + + Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override; + + Status RemoveHardwareBreakpoint(lldb::addr_t addr) override; + + NativeProcessAIX &GetProcess(); + + const NativeProcessAIX &GetProcess() const; + + llvm::Expected> + GetSiginfo() const override; + +private: + // Interface for friend classes + + /// Resumes the thread. If \p signo is anything but + /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. + Status Resume(uint32_t signo); + + /// Single steps the thread. If \p signo is anything but + /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. + Status SingleStep(uint32_t signo); + + void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr); + + /// Return true if the thread is stopped. + /// If stopped by a signal, indicate the signo in the signo argument. + /// Otherwise, return LLDB_INVALID_SIGNAL_NUMBER. + bool IsStopped(int *signo); + + void SetStoppedByExec(); + + void SetStoppedByBreakpoint(); + + void SetStoppedByWatchpoint(uint32_t wp_index); + + bool IsStoppedAtBreakpoint(); + + bool IsStoppedAtWatchpoint(); + + void SetStoppedByTrace(); + + void SetStoppedByFork(bool is_vfork, lldb::pid_t child_pid); + + void SetStoppedByVForkDone(); + + void SetStoppedWithNoReason(); + + void SetStoppedByProcessorTrace(llvm::StringRef description); + + void SetExited(); + + Status RequestStop(); + + // Private interface + void MaybeLogStateChange(lldb::StateType new_state); + + void SetStopped(); + + /// Extend m_stop_description with logical and allocation tag values. + /// If there is an error along the way just add the information we were able + /// to get. + void AnnotateSyncTagCheckFault(const siginfo_t *info); + + // Member Variables + lldb::StateType m_state; + ThreadStopInfo m_stop_info; + std::unique_ptr m_reg_context_up; + std::string m_stop_description; + using WatchpointIndexMap = std::map; + WatchpointIndexMap m_watchpoint_index_map; + WatchpointIndexMap m_hw_break_index_map; +}; +} // namespace process_aix +} // namespace lldb_private + +#endif // #ifndef liblldb_NativeThreadAIX_H_ diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt index a51d0f7afd175..01bb5f462eba4 100644 --- a/lldb/source/Plugins/Process/CMakeLists.txt +++ b/lldb/source/Plugins/Process/CMakeLists.txt @@ -7,6 +7,9 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD") add_subdirectory(NetBSD) add_subdirectory(POSIX) +elseif (CMAKE_SYSTEM_NAME MATCHES "AIX") + add_subdirectory(AIX) + add_subdirectory(POSIX) elseif (CMAKE_SYSTEM_NAME MATCHES "Windows") add_subdirectory(Windows/Common) elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin") diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 32c71d87c7f58..db271357d792a 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -46,8 +46,34 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, function_options.include_inlines = false; SymbolContextList sc_list; +#if !defined(__AIX__) process->GetTarget().GetImages().FindFunctions( ConstString("mmap"), eFunctionNameTypeFull, function_options, sc_list); +#else + process->GetTarget().GetImages().FindFunctions( + ConstString("mmap64"), eFunctionNameTypeFull, function_options, sc_list); + SymbolContextList toc_list; + process->GetTarget().GetImages().FindSymbolsWithNameAndType( + ConstString("TOC"), lldb::eSymbolTypeAny, toc_list); + + AddressRange toc_range; + if (sc_list.GetSize() > 0) { + SymbolContext sc; + if (sc_list.GetContextAtIndex(0, sc)) { + for (int i = 0; i < toc_list.GetSize(); ++i) { + SymbolContext tocSC; + if (toc_list.GetContextAtIndex(i, tocSC)) { + if (tocSC.module_sp == sc.module_sp) { + if (tocSC.GetAddressRange(eSymbolContextSymbol, 0, false, + toc_range)) { + break; + } + } + } + } + } + } +#endif const uint32_t count = sc_list.GetSize(); if (count > 0) { SymbolContext sc; @@ -96,9 +122,16 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, MmapArgList args = process->GetTarget().GetPlatform()->GetMmapArgumentList( arch, addr, length, prot_arg, flags, fd, offset); +#if defined(__AIX__) + lldb::ThreadPlanSP call_plan_sp( + new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(), + toc_range.GetBaseAddress(), + void_ptr_type, args, options)); +#else lldb::ThreadPlanSP call_plan_sp( new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(), void_ptr_type, args, options)); +#endif if (call_plan_sp) { DiagnosticManager diagnostics; diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp index 159fd2856443c..d9b41d595147f 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp @@ -23,6 +23,8 @@ static const lldb_private::RegisterInfo * GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { + //HH + case llvm::Triple::ppc64: case llvm::Triple::ppc64le: return g_register_infos_ppc64le; default: @@ -34,6 +36,8 @@ GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) { static uint32_t GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { + //HitchHike + case llvm::Triple::ppc64: case llvm::Triple::ppc64le: return static_cast(sizeof(g_register_infos_ppc64le) / sizeof(g_register_infos_ppc64le[0])); diff --git a/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp b/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp index 89ecc757a68f5..550b53688fd39 100644 --- a/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp +++ b/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp @@ -20,7 +20,7 @@ using namespace lldb; using namespace lldb_private; -ThreadMemory::ThreadMemory(Process &process, tid_t tid, +ThreadMemory::ThreadMemory(Process &process, lldb::tid_t tid, const ValueObjectSP &thread_info_valobj_sp) : Thread(process, tid), m_backing_thread_sp(), m_thread_info_valobj_sp(thread_info_valobj_sp), m_name(), m_queue(), diff --git a/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt b/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt index 6755999b18185..4eddbb5ec4cfd 100644 --- a/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt +++ b/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt @@ -6,6 +6,11 @@ lldb_tablegen(ProcessGDBRemotePropertiesEnum.inc -gen-lldb-property-enum-defs SOURCE ProcessGDBRemoteProperties.td TARGET LLDBPluginProcessGDBRemotePropertiesEnumGen) +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + set(LLDB_PLUGINS lldbPluginProcessUtility ) diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 74e392249a94e..b7ecf7a5dc328 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -40,6 +40,10 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/JSON.h" +#if defined(__AIX__) +#include +#endif + #if defined(HAVE_LIBCOMPRESSION) #include #endif @@ -1710,6 +1714,32 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( return error; } +#if defined(__AIX__) +Status GDBRemoteCommunicationClient::GetLDXINFO(struct ld_xinfo *info_ptr) +{ + Status error; + + char packet[64]; + const int packet_len = ::snprintf(packet, sizeof(packet), "qLDXINFO"); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response) == + PacketResult::Success && + response.GetResponseType() == StringExtractorGDBRemote::eResponse) { + llvm::MutableArrayRef infoData((uint8_t *)info_ptr, sizeof(struct ld_xinfo)*64); + size_t got_bytes = response.GetHexBytesAvail(infoData); + if (got_bytes != sizeof(struct ld_xinfo)*64) { + error.SetErrorString("qLDXINFO ret bad size"); + return error; + } + } else { + error.SetErrorString("qLDXINFO is not supported"); + } + return error; +} +#endif + Status GDBRemoteCommunicationClient::GetQXferMemoryMapRegionInfo( lldb::addr_t addr, MemoryRegionInfo ®ion) { Status error = LoadQXferMemoryMap(); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 898d176abc346..520f37ac56716 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -32,6 +32,10 @@ #include "llvm/Support/VersionTuple.h" +#if defined(__AIX__) +struct ld_xinfo; +#endif + namespace lldb_private { namespace process_gdb_remote { @@ -196,6 +200,9 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase { Status GetMemoryRegionInfo(lldb::addr_t addr, MemoryRegionInfo &range_info); std::optional GetWatchpointSlotCount(); +#if defined(__AIX__) + Status GetLDXINFO(struct ld_xinfo *info_ptr); +#endif std::optional GetWatchpointReportedAfter(); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index a0b08a219ae14..f019062986925 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -48,6 +48,9 @@ #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "lldb/Utility/StringExtractorGDBRemote.h" +#if defined(__AIX__) +#include +#endif using namespace lldb; using namespace lldb_private; @@ -193,6 +196,8 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { &GDBRemoteCommunicationServerLLGS::Handle_Z); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_z, &GDBRemoteCommunicationServerLLGS::Handle_z); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLDXINFO, + &GDBRemoteCommunicationServerLLGS::Handle_qLDXINFO); RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_QPassSignals, &GDBRemoteCommunicationServerLLGS::Handle_QPassSignals); @@ -3006,6 +3011,29 @@ GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) { } } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_qLDXINFO(StringExtractorGDBRemote &packet) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { + Log *log = GetLog(LLDBLog::Process); + LLDB_LOG(log, "qLDXINFO failed, no process available"); + return SendErrorResponse(0xff); + } + +#if defined(__AIX__) + // FIXME: buffer size + struct ld_xinfo info[64]; + if (ptrace64(PT_LDXINFO, m_current_process->GetID(), (long long)&(info[0]), sizeof(info), nullptr) != 0) { + return SendErrorResponse(0xff); + } + StreamGDBRemote response; + response.PutBytesAsRawHex8(&(info[0]), sizeof(info)); + return SendPacketNoLock(response.GetString()); +#else + return SendErrorResponse(0xff); +#endif +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index 646b6a102abf6..a464479e178de 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -211,6 +211,8 @@ class GDBRemoteCommunicationServerLLGS PacketResult Handle_z(StringExtractorGDBRemote &packet); + PacketResult Handle_qLDXINFO(StringExtractorGDBRemote &packet); + PacketResult Handle_s(StringExtractorGDBRemote &packet); PacketResult Handle_qXfer(StringExtractorGDBRemote &packet); diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 6f9c2cc1e4b4e..10fbaa2b3c837 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -92,6 +92,10 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/raw_ostream.h" +#if defined(__AIX__) +#include +#endif + #define DEBUGSERVER_BASENAME "debugserver" using namespace lldb; using namespace lldb_private; @@ -1513,7 +1517,7 @@ bool ProcessGDBRemote::DoUpdateThreadList(ThreadList &old_thread_list, ThreadList old_thread_list_copy(old_thread_list); if (num_thread_ids > 0) { for (size_t i = 0; i < num_thread_ids; ++i) { - tid_t tid = m_thread_ids[i]; + lldb::tid_t tid = m_thread_ids[i]; ThreadSP thread_sp( old_thread_list_copy.RemoveThreadByProtocolID(tid, false)); if (!thread_sp) { @@ -2945,6 +2949,13 @@ Status ProcessGDBRemote::DoGetMemoryRegionInfo(addr_t load_addr, return error; } +#if defined(__AIX__) +Status ProcessGDBRemote::DoGetLDXINFO(struct ld_xinfo *info_ptr) { + Status error(m_gdb_comm.GetLDXINFO(info_ptr)); + return error; +} +#endif + std::optional ProcessGDBRemote::GetWatchpointSlotCount() { return m_gdb_comm.GetWatchpointSlotCount(); } diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 2492795851388..82200fbea21cd 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -37,6 +37,10 @@ #include "GDBRemoteCommunicationClient.h" #include "GDBRemoteRegisterContext.h" +#if defined(__AIX__) +struct ld_xinfo; +#endif + #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" @@ -423,6 +427,10 @@ class ProcessGDBRemote : public Process, Status DoGetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo ®ion_info) override; +#if defined(__AIX__) + Status DoGetLDXINFO(struct ld_xinfo *info_ptr) override; +#endif + private: // For ProcessGDBRemote only std::string m_partial_profile_data; diff --git a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp index 1da7696c9a352..930c707604bb3 100644 --- a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp +++ b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp @@ -593,19 +593,19 @@ bool ProcessMachCore::DoUpdateThreadList(ThreadList &old_thread_list, ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); if (core_objfile) { - std::set used_tids; + std::set used_tids; const uint32_t num_threads = core_objfile->GetNumThreadContexts(); - std::vector tids; + std::vector tids; if (core_objfile->GetCorefileThreadExtraInfos(tids)) { assert(tids.size() == num_threads); // Find highest tid value. - tid_t highest_tid = 0; + lldb::tid_t highest_tid = 0; for (uint32_t i = 0; i < num_threads; i++) { if (tids[i] != LLDB_INVALID_THREAD_ID && tids[i] > highest_tid) highest_tid = tids[i]; } - tid_t current_unused_tid = highest_tid + 1; + lldb::tid_t current_unused_tid = highest_tid + 1; for (uint32_t i = 0; i < num_threads; i++) { if (tids[i] == LLDB_INVALID_THREAD_ID) { tids[i] = current_unused_tid++; diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt index 7523d65abf0f8..1ce60a0b66154 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt +++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt @@ -20,6 +20,11 @@ if (LLDB_ENABLE_LIBEDIT) endif() add_subdirectory(Interfaces) +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + add_lldb_library(lldbPluginScriptInterpreterPython PLUGIN PythonDataObjects.cpp diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp index e1f73f1997e36..92882cfc3da31 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -500,6 +500,8 @@ dw_addr_t DWARFFormValue::Address() const { &offset, index_size); } +bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; + std::pair DWARFFormValue::ReferencedUnitAndOffset() const { uint64_t value = m_value.value.uval; @@ -512,6 +514,8 @@ DWARFFormValue::ReferencedUnitAndOffset() const { assert(m_unit); // Unit must be valid for DW_FORM_ref forms that are compile // unit relative or we will get this wrong value += m_unit->GetOffset(); + if (UGLY_FLAG_FOR_AIX) + value -= 8; if (!m_unit->ContainsDIEOffset(value)) { m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( "DW_FORM_ref* DIE reference {0:x16} is outside of its CU", value); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index 66a762bf9b685..6721c1895a576 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -924,6 +924,12 @@ const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() { return *m_func_aranges_up; } +/* AIX-NOTE - TODO: Removed conflicting code due to merge conflicts + * Refer Patches: 27,28,29,30,35 and 76 + * and modify the code accordingly. */ + +bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; + llvm::Expected DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid, const DWARFDataExtractor &debug_info, @@ -1002,6 +1008,10 @@ const lldb_private::DWARFDataExtractor &DWARFUnit::GetData() const { uint32_t DWARFUnit::GetHeaderByteSize() const { switch (m_header.getUnitType()) { case llvm::dwarf::DW_UT_compile: + if (UGLY_FLAG_FOR_AIX) + return 11 + 4/*GetDWARFSizeOfOffset*/; + else + return GetVersion() < 5 ? 11 : 12; case llvm::dwarf::DW_UT_partial: return GetVersion() < 5 ? 11 : 12; case llvm::dwarf::DW_UT_skeleton: @@ -1016,7 +1026,7 @@ uint32_t DWARFUnit::GetHeaderByteSize() const { std::optional DWARFUnit::GetStringOffsetSectionItem(uint32_t index) const { - offset_t offset = GetStrOffsetsBase() + index * 4; + lldb::offset_t offset = GetStrOffsetsBase() + index * 4; return m_dwarf.GetDWARFContext().getOrLoadStrOffsetsData().GetU32(&offset); } diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp index 2064b73dc3ea5..824528fc3acfa 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp @@ -216,7 +216,7 @@ lldb::addr_t AppleGetThreadItemInfoHandler::SetupGetThreadItemInfoFunction( AppleGetThreadItemInfoHandler::GetThreadItemInfoReturnInfo AppleGetThreadItemInfoHandler::GetThreadItemInfo(Thread &thread, - tid_t thread_id, + lldb::tid_t thread_id, addr_t page_to_free, uint64_t page_to_free_size, Status &error) { diff --git a/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/lldb/source/Symbol/DWARFCallFrameInfo.cpp index f3df8a2c27f5a..de244e372579d 100644 --- a/lldb/source/Symbol/DWARFCallFrameInfo.cpp +++ b/lldb/source/Symbol/DWARFCallFrameInfo.cpp @@ -33,7 +33,7 @@ using namespace lldb_private::dwarf; // Used for calls when the value type is specified by a DWARF EH Frame pointer // encoding. static uint64_t -GetGNUEHPointer(const DataExtractor &DE, offset_t *offset_ptr, +GetGNUEHPointer(const DataExtractor &DE, lldb::offset_t *offset_ptr, uint32_t eh_ptr_enc, addr_t pc_rel_addr, addr_t text_addr, addr_t data_addr) //, BSDRelocs *data_relocs) const { @@ -588,7 +588,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset, if (cie->augmentation[0] == 'z') { uint32_t aug_data_len = (uint32_t)m_cfi_data.GetULEB128(&offset); if (aug_data_len != 0 && cie->lsda_addr_encoding != DW_EH_PE_omit) { - offset_t saved_offset = offset; + lldb::offset_t saved_offset = offset; lsda_data_file_address = GetGNUEHPointer(m_cfi_data, &offset, cie->lsda_addr_encoding, pc_rel_addr, text_addr, data_addr); diff --git a/lldb/source/Target/ABI.cpp b/lldb/source/Target/ABI.cpp index 110b5c86fc425..6df03533cda29 100644 --- a/lldb/source/Target/ABI.cpp +++ b/lldb/source/Target/ABI.cpp @@ -208,6 +208,15 @@ bool ABI::PrepareTrivialCall(Thread &thread, lldb::addr_t sp, llvm_unreachable("Should never get here!"); } +bool ABI::PrepareTrivialCall(Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t tocAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef args) const { + // dummy prepare trivial call + llvm_unreachable("Should never get here!"); +} + bool ABI::GetFallbackRegisterLocation( const RegisterInfo *reg_info, UnwindPlan::Row::RegisterLocation &unwind_regloc) { diff --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt index a42c44b761dc5..833489b16dfd7 100644 --- a/lldb/source/Target/CMakeLists.txt +++ b/lldb/source/Target/CMakeLists.txt @@ -1,3 +1,8 @@ +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + lldb_tablegen(TargetProperties.inc -gen-lldb-property-defs SOURCE TargetProperties.td TARGET LLDBTargetPropertiesGen) diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index e3c4f2ee398cc..e31245178b2f2 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -75,6 +75,10 @@ #include "lldb/Utility/State.h" #include "lldb/Utility/Timer.h" +#if defined(__AIX__) +#include +#endif + using namespace lldb; using namespace lldb_private; using namespace std::chrono; @@ -6206,6 +6210,12 @@ Status Process::GetMemoryRegionInfo(lldb::addr_t load_addr, return DoGetMemoryRegionInfo(load_addr, range_info); } +#if defined(__AIX__) +Status Process::GetLDXINFO(struct ld_xinfo *info_ptr) { + return DoGetLDXINFO(info_ptr); +} +#endif + Status Process::GetMemoryRegions(lldb_private::MemoryRegionInfos ®ion_list) { Status error; diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index a61228d092d89..57f42ea56cb18 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -40,6 +40,9 @@ #include #include +#ifdef __AIX__ +#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" +#endif using namespace lldb; using namespace lldb_private; @@ -1257,6 +1260,10 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( // Answer the question: Where did THIS frame save the CALLER frame ("previous" // frame)'s register value? +#ifdef __AIX__ +extern bool UGLY_HACK_NULL_TOPFRAME; +#endif + enum UnwindLLDB::RegisterSearchResult RegisterContextUnwind::SavedLocationForRegister( uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc) { @@ -1517,6 +1524,11 @@ RegisterContextUnwind::SavedLocationForRegister( new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext; new_regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); +#ifdef __AIX__ + if (UGLY_HACK_NULL_TOPFRAME && new_regloc.location.register_number == 0x20) { + new_regloc.location.register_number = 0x24; + } +#endif m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; regloc = new_regloc; UnwindLogMsg("supplying caller's register %s (%d) from the live " @@ -2368,6 +2380,40 @@ bool RegisterContextUnwind::ReadPC(addr_t &pc) { } } +#ifdef __AIX__ +bool RegisterContextUnwind::ReadLR(addr_t &lr) { + if (!IsValid()) + return false; + + bool above_trap_handler = false; + if (GetNextFrame().get() && GetNextFrame()->IsValid() && + GetNextFrame()->IsTrapHandlerFrame()) + above_trap_handler = true; + + if (ReadGPRValue(eRegisterKindLLDB, gpr_lr_ppc64le, lr)) { + // A lr value of 0 or 1 is impossible in the middle of the stack -- it + // indicates the end of a stack walk. + // On the currently executing frame (or such a frame interrupted + // asynchronously by sigtramp et al) this may occur if code has jumped + // through a NULL pointer -- we want to be able to unwind past that frame + // to help find the bug. + + ProcessSP process_sp (m_thread.GetProcess()); + if (process_sp) + { + ABI *abi = process_sp->GetABI().get(); + if (abi) + lr = abi->FixCodeAddress(lr); + } + + return !(m_all_registers_available == false && + above_trap_handler == false && (lr == 0 || lr == 1)); + } else { + return false; + } +} +#endif + void RegisterContextUnwind::UnwindLogMsg(const char *fmt, ...) { Log *log = GetLog(LLDBLog::Unwind); if (!log) diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp index 50dcb66b9719f..0926579ea2930 100644 --- a/lldb/source/Target/ThreadPlanCallFunction.cpp +++ b/lldb/source/Target/ThreadPlanCallFunction.cpp @@ -127,6 +127,40 @@ ThreadPlanCallFunction::ThreadPlanCallFunction( m_valid = true; } +ThreadPlanCallFunction::ThreadPlanCallFunction( + Thread &thread, const Address &function, const Address &toc, + const CompilerType &return_type, + llvm::ArrayRef args, const EvaluateExpressionOptions &options) + : ThreadPlan(ThreadPlan::eKindCallFunction, "Call function plan", thread, + eVoteNoOpinion, eVoteNoOpinion), + m_valid(false), m_stop_other_threads(options.GetStopOthers()), + m_unwind_on_error(options.DoesUnwindOnError()), + m_ignore_breakpoints(options.DoesIgnoreBreakpoints()), + m_debug_execution(options.GetDebug()), + m_trap_exceptions(options.GetTrapExceptions()), m_function_addr(function), + m_function_sp(0), m_takedown_done(false), + m_should_clear_objc_exception_bp(false), + m_should_clear_cxx_exception_bp(false), + m_stop_address(LLDB_INVALID_ADDRESS), m_return_type(return_type) { + lldb::addr_t start_load_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t function_load_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t toc_addr = LLDB_INVALID_ADDRESS; + ABI *abi = nullptr; + + if (!ConstructorSetup(thread, abi, start_load_addr, function_load_addr)) + return; + + toc_addr = toc.GetLoadAddress(&GetTarget()); + + if (!abi->PrepareTrivialCall(thread, m_function_sp, function_load_addr, + toc_addr, start_load_addr, args)) + return; + + ReportRegisterState("Function call was set up. Register state was:"); + + m_valid = true; +} + ThreadPlanCallFunction::ThreadPlanCallFunction( Thread &thread, const Address &function, const EvaluateExpressionOptions &options) diff --git a/lldb/source/Target/UnwindLLDB.cpp b/lldb/source/Target/UnwindLLDB.cpp index f43e940492b09..255b829738ba2 100644 --- a/lldb/source/Target/UnwindLLDB.cpp +++ b/lldb/source/Target/UnwindLLDB.cpp @@ -68,6 +68,10 @@ uint32_t UnwindLLDB::DoGetFrameCount() { return m_frames.size(); } +#ifdef __AIX__ +bool UGLY_HACK_NULL_TOPFRAME = false; +#endif + bool UnwindLLDB::AddFirstFrame() { if (m_frames.size() > 0) return true; @@ -91,6 +95,17 @@ bool UnwindLLDB::AddFirstFrame() { if (!reg_ctx_sp->ReadPC(first_cursor_sp->start_pc)) goto unwind_done; +#ifdef __AIX__ + lldb::addr_t lr; + if (!reg_ctx_sp->ReadLR(lr)) + goto unwind_done; + + if (first_cursor_sp->start_pc == 0) { + first_cursor_sp->start_pc = lr; + UGLY_HACK_NULL_TOPFRAME = true; + } +#endif + // Everything checks out, so release the auto pointer value and let the // cursor own it in its shared pointer first_cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp; diff --git a/lldb/source/Utility/ArchSpec.cpp b/lldb/source/Utility/ArchSpec.cpp index 07ef435ef451d..3868f77169cc6 100644 --- a/lldb/source/Utility/ArchSpec.cpp +++ b/lldb/source/Utility/ArchSpec.cpp @@ -14,6 +14,7 @@ #include "lldb/lldb-defines.h" #include "llvm/ADT/STLExtras.h" #include "llvm/BinaryFormat/COFF.h" +#include "llvm/BinaryFormat/XCOFF.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Compiler.h" @@ -459,10 +460,22 @@ static const ArchDefinition g_coff_arch_def = { "pe-coff", }; +static const ArchDefinitionEntry g_xcoff_arch_entries[] = { + {ArchSpec::eCore_ppc_generic, llvm::XCOFF::TCPU_COM, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, + {ArchSpec::eCore_ppc64_generic, llvm::XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu} +}; + +static const ArchDefinition g_xcoff_arch_def = { + eArchTypeXCOFF, + std::size(g_xcoff_arch_entries), + g_xcoff_arch_entries, + "xcoff", +}; + //===----------------------------------------------------------------------===// // Table of all ArchDefinitions static const ArchDefinition *g_arch_definitions[] = { - &g_macho_arch_def, &g_elf_arch_def, &g_coff_arch_def}; + &g_macho_arch_def, &g_elf_arch_def, &g_coff_arch_def, &g_xcoff_arch_def}; //===----------------------------------------------------------------------===// // Static helper functions. @@ -903,6 +916,9 @@ bool ArchSpec::SetArchitecture(ArchitectureType arch_type, uint32_t cpu, } else if (arch_type == eArchTypeCOFF && os == llvm::Triple::Win32) { m_triple.setVendor(llvm::Triple::PC); m_triple.setOS(llvm::Triple::Win32); + } else if (arch_type == eArchTypeXCOFF && os == llvm::Triple::AIX) { + m_triple.setVendor(llvm::Triple::IBM); + m_triple.setOS(llvm::Triple::AIX); } else { m_triple.setVendor(llvm::Triple::UnknownVendor); m_triple.setOS(llvm::Triple::UnknownOS); diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp index 9f79d2271b1e6..dbd3236536f8c 100644 --- a/lldb/source/Utility/StringExtractorGDBRemote.cpp +++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -227,6 +227,8 @@ StringExtractorGDBRemote::GetServerPacketType() const { return eServerPacketType_qLaunchGDBServer; if (PACKET_MATCHES("qLaunchSuccess")) return eServerPacketType_qLaunchSuccess; + if (PACKET_MATCHES("qLDXINFO")) + return eServerPacketType_qLDXINFO; break; case 'M': diff --git a/lldb/test/CMakeLists.txt b/lldb/test/CMakeLists.txt index 5ac474736eb63..413a1e5120288 100644 --- a/lldb/test/CMakeLists.txt +++ b/lldb/test/CMakeLists.txt @@ -155,7 +155,7 @@ if(TARGET clang) add_lldb_test_dependency(clang) # TestFullLtoStepping depends on LTO, and only runs when the compiler is clang. - add_lldb_test_dependency(LTO) + #add_lldb_test_dependency(LTO) if (TARGET libcxx OR ("libcxx" IN_LIST LLVM_ENABLE_RUNTIMES)) set(LLDB_HAS_LIBCXX ON) diff --git a/lldb/test/Shell/Expr/TestIRMemoryMap.test b/lldb/test/Shell/Expr/TestIRMemoryMap.test index 9dd0413be14cf..5ed61ad33ffc4 100644 --- a/lldb/test/Shell/Expr/TestIRMemoryMap.test +++ b/lldb/test/Shell/Expr/TestIRMemoryMap.test @@ -1,6 +1,6 @@ # UNSUPPORTED: system-windows -# RUN: %clangxx_host %p/Inputs/call-function.cpp -g -o %t +# RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t # RUN: lldb-test ir-memory-map %t %S/Inputs/ir-memory-map-basic # RUN: lldb-test ir-memory-map -host-only %t %S/Inputs/ir-memory-map-basic diff --git a/lldb/test/Shell/Process/TestEnvironment.test b/lldb/test/Shell/Process/TestEnvironment.test index e6d6e56fc9203..2ead258719f32 100644 --- a/lldb/test/Shell/Process/TestEnvironment.test +++ b/lldb/test/Shell/Process/TestEnvironment.test @@ -3,7 +3,7 @@ UNSUPPORTED: lldb-repro The double quotes around "BAR" ensure we don't match the command. -RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t +RUN: %clangxx_host -std=c++11 -I/compgpfs/build/xlcit/rings/openxlC/aix/wyvern_dev/ring0/latest/opt/IBM/openxlC/17.1.2/include/c++/v1/ %p/Inputs/env.cpp -o %t RUN: %lldb %t -o 'process launch --environment FOO="BAR"' | FileCheck %s RUN: %lldb %t -o 'env FOO="BAR"' -o 'process launch' | FileCheck %s diff --git a/lldb/tools/driver/CMakeLists.txt b/lldb/tools/driver/CMakeLists.txt index cd304a047dea6..78617be24f780 100644 --- a/lldb/tools/driver/CMakeLists.txt +++ b/lldb/tools/driver/CMakeLists.txt @@ -11,6 +11,11 @@ if(APPLE) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_BINARY_DIR}/lldb-Info.plist") endif() +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + add_lldb_tool(lldb Driver.cpp Platform.cpp diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp index 14371da64f2f2..f7eaf56738d7d 100644 --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -639,7 +639,7 @@ void sigwinch_handler(int signo) { } void sigint_handler(int signo) { -#ifdef _WIN32 // Restore handler as it is not persistent on Windows +#if defined(_WIN32) || defined(__AIX__) // Restore handler as it is not persistent on Windows signal(SIGINT, sigint_handler); #endif static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT; @@ -727,8 +727,11 @@ static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) { int main(int argc, char const *argv[]) { // Editline uses for example iswprint which is dependent on LC_CTYPE. + // FIXME: this caused unexpected SIGTRAP on AIX +#ifndef __AIX__ std::setlocale(LC_ALL, ""); std::setlocale(LC_CTYPE, ""); +#endif // Setup LLVM signal handlers and make sure we call llvm_shutdown() on // destruction. diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index f8f0d86453f58..2fa6f6c9a5369 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -6,6 +6,10 @@ if (HAVE_LIBPTHREAD) list(APPEND extra_libs pthread) endif () +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + add_definitions("-D_AIX") + add_definitions("-D_ALL_SOURCE") +endif() if(APPLE) configure_file( diff --git a/lldb/tools/lldb-server/CMakeLists.txt b/lldb/tools/lldb-server/CMakeLists.txt index 9030ed709a647..0d69ae32a008f 100644 --- a/lldb/tools/lldb-server/CMakeLists.txt +++ b/lldb/tools/lldb-server/CMakeLists.txt @@ -8,6 +8,10 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux|Android") list(APPEND LLDB_PLUGINS lldbPluginProcessLinux) endif() +if(CMAKE_SYSTEM_NAME MATCHES "AIX") + list(APPEND LLDB_PLUGINS lldbPluginProcessAIX) +endif() + if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") list(APPEND LLDB_PLUGINS lldbPluginProcessFreeBSD) endif() @@ -20,6 +24,8 @@ if(CMAKE_SYSTEM_NAME MATCHES "Darwin") list(APPEND LLDB_PLUGINS lldbPluginObjectFileMachO) elseif(CMAKE_SYSTEM_NAME MATCHES "Windows") list(APPEND LLDB_PLUGINS lldbPluginObjectFilePECOFF) +elseif(CMAKE_SYSTEM_NAME MATCHES "AIX") + list(APPEND LLDB_PLUGINS lldbPluginObjectFileXCOFF) else() list(APPEND LLDB_PLUGINS lldbPluginObjectFileELF) endif() @@ -54,6 +60,7 @@ add_lldb_tool(lldb-server lldbPluginInstructionMIPS lldbPluginInstructionMIPS64 lldbPluginInstructionRISCV + lldbPluginInstructionPPC64 ${LLDB_SYSTEM_LIBS} LINK_COMPONENTS diff --git a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp index 4233252a84dfc..91bb2083a88b5 100644 --- a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp +++ b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp @@ -14,6 +14,9 @@ using HostObjectFile = ObjectFileMachO; #elif defined(_WIN32) #include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" using HostObjectFile = ObjectFilePECOFF; +#elif defined(__AIX__) +#include "Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h" +using HostObjectFile = ObjectFileXCOFF; #else #include "Plugins/ObjectFile/ELF/ObjectFileELF.h" using HostObjectFile = ObjectFileELF; @@ -46,6 +49,10 @@ using HostObjectFile = ObjectFileELF; #include "Plugins/Instruction/MIPS/EmulateInstructionMIPS.h" #endif +#if defined(__AIX__) +#include "Plugins/Instruction/PPC64/EmulateInstructionPPC64.h" +#endif + #if defined(__riscv) #define LLDB_TARGET_RISCV #include "Plugins/Instruction/RISCV/EmulateInstructionRISCV.h" @@ -75,6 +82,10 @@ llvm::Error SystemInitializerLLGS::Initialize() { EmulateInstructionRISCV::Initialize(); #endif +#if defined(__AIX__) + EmulateInstructionPPC64::Initialize(); +#endif + return llvm::Error::success(); } @@ -97,5 +108,9 @@ void SystemInitializerLLGS::Terminate() { EmulateInstructionRISCV::Terminate(); #endif +#if defined(__AIX__) + EmulateInstructionPPC64::Terminate(); +#endif + SystemInitializerCommon::Terminate(); } diff --git a/lldb/tools/lldb-server/lldb-gdbserver.cpp b/lldb/tools/lldb-server/lldb-gdbserver.cpp index 563284730bc70..2a14f4f9c82aa 100644 --- a/lldb/tools/lldb-server/lldb-gdbserver.cpp +++ b/lldb/tools/lldb-server/lldb-gdbserver.cpp @@ -45,6 +45,8 @@ #include "Plugins/Process/NetBSD/NativeProcessNetBSD.h" #elif defined(_WIN32) #include "Plugins/Process/Windows/Common/NativeProcessWindows.h" +#elif defined(__AIX__) +#include "Plugins/Process/AIX/NativeProcessAIX.h" #endif #ifndef LLGS_PROGRAM_NAME @@ -70,6 +72,8 @@ typedef process_freebsd::NativeProcessFreeBSD::Manager NativeProcessManager; typedef process_netbsd::NativeProcessNetBSD::Manager NativeProcessManager; #elif defined(_WIN32) typedef NativeProcessWindows::Manager NativeProcessManager; +#elif defined(__AIX__) +typedef process_aix::NativeProcessAIX::Manager NativeProcessManager; #else // Dummy implementation to make sure the code compiles class NativeProcessManager : public NativeProcessProtocol::Manager { diff --git a/lldb/unittests/Host/FileSystemTest.cpp b/lldb/unittests/Host/FileSystemTest.cpp index 58887f6b2467e..89d0f5b87171a 100644 --- a/lldb/unittests/Host/FileSystemTest.cpp +++ b/lldb/unittests/Host/FileSystemTest.cpp @@ -59,7 +59,7 @@ class DummyFileSystem : public vfs::FileSystem { return I->second; } ErrorOr> - openFileForRead(const Twine &Path) override { + openFileForRead(const Twine &Path, bool IsText) override { auto S = status(Path); if (S) return std::unique_ptr(new DummyFile{*S}); diff --git a/lldb/unittests/Host/posix/TerminalTest.cpp b/lldb/unittests/Host/posix/TerminalTest.cpp index 5187a0c20a68b..f3de92c0852b1 100644 --- a/lldb/unittests/Host/posix/TerminalTest.cpp +++ b/lldb/unittests/Host/posix/TerminalTest.cpp @@ -94,15 +94,19 @@ TEST_F(TerminalTest, SetRaw) { TEST_F(TerminalTest, SetBaudRate) { struct termios terminfo; +#if (defined(__AIX__) && defined(B38400)) || !defined(__AIX__) ASSERT_THAT_ERROR(m_term.SetBaudRate(38400), llvm::Succeeded()); ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0); EXPECT_EQ(cfgetispeed(&terminfo), static_cast(B38400)); EXPECT_EQ(cfgetospeed(&terminfo), static_cast(B38400)); +#endif +#if (defined(__AIX__) && defined(B115200)) || !defined(__AIX__) ASSERT_THAT_ERROR(m_term.SetBaudRate(115200), llvm::Succeeded()); ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0); EXPECT_EQ(cfgetispeed(&terminfo), static_cast(B115200)); EXPECT_EQ(cfgetospeed(&terminfo), static_cast(B115200)); +#endif // uncommon value #if defined(B153600) diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h index 5a7cd8e38f2b7..fa9c6781e24f5 100644 --- a/llvm/include/llvm/Object/XCOFFObjectFile.h +++ b/llvm/include/llvm/Object/XCOFFObjectFile.h @@ -542,7 +542,6 @@ class XCOFFObjectFile : public ObjectFile { template const T *sectionHeaderTable() const; size_t getFileHeaderSize() const; - size_t getSectionHeaderSize() const; const XCOFFSectionHeader32 *toSection32(DataRefImpl Ref) const; const XCOFFSectionHeader64 *toSection64(DataRefImpl Ref) const; @@ -578,6 +577,9 @@ class XCOFFObjectFile : public ObjectFile { void checkSectionAddress(uintptr_t Addr, uintptr_t TableAddr) const; public: + size_t getSectionHeaderSize() const; + Expected getLoaderSectionAddress() const; + static constexpr uint64_t InvalidRelocOffset = std::numeric_limits::max(); diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp index bdd04b00f557b..9c96df1bbdc54 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -251,10 +251,16 @@ Expected DWARFUnit::getStringOffsetSectionItem(uint32_t Index) const { return DA.getRelocatedValue(ItemSize, &Offset); } +bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; + Error DWARFUnitHeader::extract(DWARFContext &Context, const DWARFDataExtractor &debug_info, uint64_t *offset_ptr, DWARFSectionKind SectionKind) { + if (UGLY_FLAG_FOR_AIX) { + // FIXME: hack to get version + *offset_ptr += 8; + } Offset = *offset_ptr; Error Err = Error::success(); IndexEntry = nullptr; @@ -267,8 +273,13 @@ Error DWARFUnitHeader::extract(DWARFContext &Context, AbbrOffset = debug_info.getRelocatedValue( FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err); } else { - AbbrOffset = debug_info.getRelocatedValue( - FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err); + if (UGLY_FLAG_FOR_AIX) { + AbbrOffset = debug_info.getRelocatedValue( + 8, offset_ptr, nullptr, &Err); + } else { + AbbrOffset = debug_info.getRelocatedValue( + FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err); + } FormParams.AddrSize = debug_info.getU8(offset_ptr, &Err); // Fake a unit type based on the section type. This isn't perfect, // but distinguishing compile and type units is generally enough. >From b1da5b1cf35829fcbf4ad6564c6005c755012e47 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 7 Aug 2024 12:18:45 -0500 Subject: [PATCH 02/47] Code license notice --- lldb/NOTICE.TXT | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 lldb/NOTICE.TXT diff --git a/lldb/NOTICE.TXT b/lldb/NOTICE.TXT new file mode 100644 index 0000000000000..d814272967476 --- /dev/null +++ b/lldb/NOTICE.TXT @@ -0,0 +1,7 @@ + +This product contains small piece of code to support AIX, taken from netbsd. + + * LICENSE: + * lldb/source/Host/common/LICENSE.aix-netbsd.txt (OpenSSL License) + * HOMEPAGE: + * https://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/crypto/external/bsd/openssl/dist >From 50ad673a78029fd6c47d90317e2c61ca2b59d5c5 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 7 Aug 2024 13:27:20 -0500 Subject: [PATCH 03/47] Reverting .tests --- lldb/test/Shell/Expr/TestIRMemoryMap.test | 2 +- lldb/test/Shell/Process/TestEnvironment.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/test/Shell/Expr/TestIRMemoryMap.test b/lldb/test/Shell/Expr/TestIRMemoryMap.test index 5ed61ad33ffc4..9dd0413be14cf 100644 --- a/lldb/test/Shell/Expr/TestIRMemoryMap.test +++ b/lldb/test/Shell/Expr/TestIRMemoryMap.test @@ -1,6 +1,6 @@ # UNSUPPORTED: system-windows -# RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t +# RUN: %clangxx_host %p/Inputs/call-function.cpp -g -o %t # RUN: lldb-test ir-memory-map %t %S/Inputs/ir-memory-map-basic # RUN: lldb-test ir-memory-map -host-only %t %S/Inputs/ir-memory-map-basic diff --git a/lldb/test/Shell/Process/TestEnvironment.test b/lldb/test/Shell/Process/TestEnvironment.test index 2ead258719f32..e6d6e56fc9203 100644 --- a/lldb/test/Shell/Process/TestEnvironment.test +++ b/lldb/test/Shell/Process/TestEnvironment.test @@ -3,7 +3,7 @@ UNSUPPORTED: lldb-repro The double quotes around "BAR" ensure we don't match the command. -RUN: %clangxx_host -std=c++11 -I/compgpfs/build/xlcit/rings/openxlC/aix/wyvern_dev/ring0/latest/opt/IBM/openxlC/17.1.2/include/c++/v1/ %p/Inputs/env.cpp -o %t +RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t RUN: %lldb %t -o 'process launch --environment FOO="BAR"' | FileCheck %s RUN: %lldb %t -o 'env FOO="BAR"' -o 'process launch' | FileCheck %s >From c1967be8fe14d469cb5ae9d41d115a7003ff39b6 Mon Sep 17 00:00:00 2001 From: Lakshmi Surekha Kovvuri Date: Thu, 22 Aug 2024 08:49:50 -0500 Subject: [PATCH 04/47] For TestSuite Run --- lldb/unittests/Host/FileSystemTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/unittests/Host/FileSystemTest.cpp b/lldb/unittests/Host/FileSystemTest.cpp index 89d0f5b87171a..58887f6b2467e 100644 --- a/lldb/unittests/Host/FileSystemTest.cpp +++ b/lldb/unittests/Host/FileSystemTest.cpp @@ -59,7 +59,7 @@ class DummyFileSystem : public vfs::FileSystem { return I->second; } ErrorOr> - openFileForRead(const Twine &Path, bool IsText) override { + openFileForRead(const Twine &Path) override { auto S = status(Path); if (S) return std::unique_ptr(new DummyFile{*S}); >From 758ab642d0974e799ac902d8ad240a3a90aeb24d Mon Sep 17 00:00:00 2001 From: Lakshmi Surekha Kovvuri Date: Fri, 30 Aug 2024 08:33:32 -0500 Subject: [PATCH 05/47] Changes made to AIX-specific files to eliminate errors encountered during CI when updating LLDB. --- .../Plugins/Process/AIX/NativeProcessAIX.cpp | 20 ++++++++++--------- .../Process/AIX/NativeRegisterContextAIX.cpp | 4 ++-- .../AIX/NativeRegisterContextAIX_ppc64.cpp | 10 +++++----- .../Plugins/Process/AIX/NativeThreadAIX.cpp | 2 +- .../GDBRemoteCommunicationClient.cpp | 4 ++-- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp index 882f20d30a3bf..5b01a66b0453f 100644 --- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -211,12 +211,14 @@ static Status EnsureFDFlags(int fd, int flags) { int status = fcntl(fd, F_GETFL); if (status == -1) { - error.SetErrorToErrno(); + error = Status::FromErrno(); + // error.SetErrorToErrno(); return error; } if (fcntl(fd, F_SETFL, status | flags) == -1) { - error.SetErrorToErrno(); + error = Status::FromErrno(); + // error.SetErrorToErrno(); return error; } @@ -813,7 +815,7 @@ Status NativeProcessAIX::Resume(const ResumeActionList &resume_actions) { Status error = ResumeThread(static_cast(*thread), action->state, signo); if (error.Fail()) - return Status("NativeProcessAIX::%s: failed to resume thread " + return Status::FromErrorStringWithFormat("NativeProcessAIX::%s: failed to resume thread " "for pid %" PRIu64 ", tid %" PRIu64 ", error = %s", __FUNCTION__, GetID(), thread->GetID(), error.AsCString()); @@ -826,7 +828,7 @@ Status NativeProcessAIX::Resume(const ResumeActionList &resume_actions) { break; default: - return Status("NativeProcessAIX::%s (): unexpected state %s specified " + return Status::FromErrorStringWithFormat("NativeProcessAIX::%s (): unexpected state %s specified " "for pid %" PRIu64 ", tid %" PRIu64, __FUNCTION__, StateAsCString(action->state), GetID(), thread->GetID()); @@ -840,7 +842,7 @@ Status NativeProcessAIX::Halt() { Status error; if (kill(GetID(), SIGSTOP) != 0) - error.SetErrorToErrno(); + error = Status::FromErrno(); return error; } @@ -874,7 +876,7 @@ Status NativeProcessAIX::Signal(int signo) { Host::GetSignalAsCString(signo), GetID()); if (kill(GetID(), signo)) - error.SetErrorToErrno(); + error = Status::FromErrno(); return error; } @@ -951,7 +953,7 @@ Status NativeProcessAIX::Kill() { } if (kill(GetID(), SIGKILL) != 0) { - error.SetErrorToErrno(); + error = Status::FromErrno(); return error; } @@ -1555,7 +1557,7 @@ Status NativeProcessAIX::GetLoadedModuleFileSpec(const char *module_path, return Status(); } } - return Status("Module file (%s) not found in /proc/%" PRIu64 "/maps file!", + return Status::FromErrorStringWithFormat("Module file (%s) not found in /proc/%" PRIu64 "/maps file!", module_file_spec.GetFilename().AsCString(), GetID()); } @@ -2011,7 +2013,7 @@ Status NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid, void *addr, } if (errno) { - error.SetErrorToErrno(); + error = Status::FromErrno(); ret = -1; } diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp index 0859f9501c1b6..071e55543cc3c 100644 --- a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp @@ -27,7 +27,7 @@ Status NativeRegisterContextAIX::ReadRegisterRaw(uint32_t reg_index, RegisterValue ®_value) { const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); if (!reg_info) - return Status("register %" PRIu32 " not found", reg_index); + return Status::FromErrorStringWithFormat("register %" PRIu32 " not found", reg_index); return DoReadRegisterValue(GetPtraceOffset(reg_index), reg_info->name, reg_info->byte_size, reg_value); @@ -82,7 +82,7 @@ NativeRegisterContextAIX::WriteRegisterRaw(uint32_t reg_index, assert(register_to_write_info_p && "register to write does not have valid RegisterInfo"); if (!register_to_write_info_p) - return Status("NativeRegisterContextAIX::%s failed to get RegisterInfo " + return Status::FromErrorStringWithFormat("NativeRegisterContextAIX::%s failed to get RegisterInfo " "for write register index %" PRIu32, __FUNCTION__, reg_to_write); diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp index 1996373791748..0132b52dec6f2 100644 --- a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp @@ -165,7 +165,7 @@ Status NativeRegisterContextAIX_ppc64::ReadRegister( Status error; if (!reg_info) { - error.SetErrorString("reg_info NULL"); + error.FromErrorString("reg_info NULL"); return error; } @@ -251,7 +251,7 @@ Status NativeRegisterContextAIX_ppc64::WriteRegister( const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; if (reg_index == LLDB_INVALID_REGNUM) - return Status("no lldb regnum for %s", reg_info && reg_info->name + return Status::FromErrorStringWithFormat("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : ""); @@ -389,14 +389,14 @@ Status NativeRegisterContextAIX_ppc64::WriteAllRegisterValues( Status error; if (!data_sp) { - error.SetErrorStringWithFormat( + error = Status::FromErrorStringWithFormat( "NativeRegisterContextAIX_ppc64::%s invalid data_sp provided", __FUNCTION__); return error; } if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { - error.SetErrorStringWithFormat( + error = Status::FromErrorStringWithFormat( "NativeRegisterContextAIX_ppc64::%s data_sp contained mismatched " "data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); @@ -405,7 +405,7 @@ Status NativeRegisterContextAIX_ppc64::WriteAllRegisterValues( const uint8_t *src = data_sp->GetBytes(); if (src == nullptr) { - error.SetErrorStringWithFormat("NativeRegisterContextAIX_ppc64::%s " + error = Status::FromErrorStringWithFormat("NativeRegisterContextAIX_ppc64::%s " "DataBuffer::GetBytes() returned a null " "pointer", __FUNCTION__); diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp index e07daccdff550..bb14b6ab4a05e 100644 --- a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp @@ -481,7 +481,7 @@ Status NativeThreadAIX::RequestStop() { Status err; errno = 0; if (::kill(pid, SIGSTOP) != 0) { - err.SetErrorToErrno(); + err = Status::FromErrno(); LLDB_LOGF(log, "NativeThreadAIX::%s kill(%" PRIu64 ", SIGSTOP) failed: %s", __FUNCTION__, pid, err.AsCString()); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 17926f8e4ab53..0aa68a4a09cbe 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -1728,11 +1728,11 @@ Status GDBRemoteCommunicationClient::GetLDXINFO(struct ld_xinfo *info_ptr) llvm::MutableArrayRef infoData((uint8_t *)info_ptr, sizeof(struct ld_xinfo)*64); size_t got_bytes = response.GetHexBytesAvail(infoData); if (got_bytes != sizeof(struct ld_xinfo)*64) { - error.SetErrorString("qLDXINFO ret bad size"); + error.FromErrorString("qLDXINFO ret bad size"); return error; } } else { - error.SetErrorString("qLDXINFO is not supported"); + error.FromErrorString("qLDXINFO is not supported"); } return error; } >From 33d561f4bb74a2efd0da163ebde416c9ad1c2925 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Tue, 10 Sep 2024 02:00:09 -0500 Subject: [PATCH 06/47] Removed non-required PTRACE defs --- lldb/include/lldb/Host/aix/Ptrace.h | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/lldb/include/lldb/Host/aix/Ptrace.h b/lldb/include/lldb/Host/aix/Ptrace.h index 88928f18102d7..393928a89add3 100644 --- a/lldb/include/lldb/Host/aix/Ptrace.h +++ b/lldb/include/lldb/Host/aix/Ptrace.h @@ -34,29 +34,11 @@ #ifndef PTRACE_SETREGSET #define PTRACE_SETREGSET 0x4205 #endif -#ifndef PTRACE_GET_THREAD_AREA -#define PTRACE_GET_THREAD_AREA (PT_COMMAND_MAX+5) -#endif -#ifndef PTRACE_ARCH_PRCTL -#define PTRACE_ARCH_PRCTL (PT_COMMAND_MAX+6) -#endif -#ifndef ARCH_GET_FS -#define ARCH_SET_GS 0x1001 -#define ARCH_SET_FS 0x1002 -#define ARCH_GET_FS 0x1003 -#define ARCH_GET_GS 0x1004 -#endif -#ifndef PTRACE_PEEKMTETAGS -#define PTRACE_PEEKMTETAGS (PT_COMMAND_MAX+7) -#endif -#ifndef PTRACE_POKEMTETAGS -#define PTRACE_POKEMTETAGS (PT_COMMAND_MAX+8) -#endif #ifndef PTRACE_GETVRREGS -#define PTRACE_GETVRREGS (PT_COMMAND_MAX+9) +#define PTRACE_GETVRREGS (PT_COMMAND_MAX+5) #endif #ifndef PTRACE_GETVSRREGS -#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+10) +#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+6) #endif #endif // liblldb_Host_aix_Ptrace_h_ >From 450793d7270999ecdd6714c4222663517dab3928 Mon Sep 17 00:00:00 2001 From: Lakshmi Surekha Kovvuri Date: Wed, 11 Sep 2024 02:52:41 -0500 Subject: [PATCH 07/47] Patch for running of unit testcases without hang --- lldb/unittests/Host/MainLoopTest.cpp | 4 +++- lldb/unittests/Host/PipeTest.cpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lldb/unittests/Host/MainLoopTest.cpp b/lldb/unittests/Host/MainLoopTest.cpp index 4084e90782fd5..9e92ec1470d4d 100644 --- a/lldb/unittests/Host/MainLoopTest.cpp +++ b/lldb/unittests/Host/MainLoopTest.cpp @@ -183,7 +183,7 @@ TEST_F(MainLoopTest, PendingCallbackAfterLoopExited) { loop.AddPendingCallback([&](MainLoopBase &loop) {}); } -#ifdef LLVM_ON_UNIX +#if defined(LLVM_ON_UNIX) && !defined(__AIX__) TEST_F(MainLoopTest, DetectsEOF) { PseudoTerminal term; @@ -202,7 +202,9 @@ TEST_F(MainLoopTest, DetectsEOF) { ASSERT_TRUE(loop.Run().Success()); ASSERT_EQ(1u, callback_count); } +// #endif +// #ifdef LLVM_ON_UNIX TEST_F(MainLoopTest, Signal) { MainLoop loop; Status error; diff --git a/lldb/unittests/Host/PipeTest.cpp b/lldb/unittests/Host/PipeTest.cpp index 506f3d225a21e..c1013aa7a7e4e 100644 --- a/lldb/unittests/Host/PipeTest.cpp +++ b/lldb/unittests/Host/PipeTest.cpp @@ -55,6 +55,7 @@ TEST_F(PipeTest, OpenAsReader) { } #endif +#if !defined(__AIX__) TEST_F(PipeTest, WriteWithTimeout) { Pipe pipe; ASSERT_THAT_ERROR(pipe.CreateNew(false).ToError(), llvm::Succeeded()); @@ -150,3 +151,4 @@ TEST_F(PipeTest, WriteWithTimeout) { .ToError(), llvm::Succeeded()); } +#endif >From 61e7843b431ff3657e3c4b39d1559401ff3de891 Mon Sep 17 00:00:00 2001 From: Lakshmi Surekha Kovvuri Date: Thu, 12 Sep 2024 13:22:03 -0500 Subject: [PATCH 08/47] changes applied to NativeProcessAIX.cpp file to solve build errors while making LLDB up to date --- .../Plugins/Process/AIX/NativeProcessAIX.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp index 5b01a66b0453f..fc84763857453 100644 --- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -862,7 +862,7 @@ Status NativeProcessAIX::Detach() { Status e = Detach(thread->GetID()); if (e.Fail()) error = - e; // Save the error, but still attempt to detach from other threads. + e.Clone(); // Save the error, but still attempt to detach from other threads. } return error; @@ -1240,7 +1240,7 @@ Status NativeProcessAIX::ReadMemoryTags(int32_t type, lldb::addr_t addr, llvm::Expected details = GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); if (!details) - return Status(details.takeError()); + return Status::FromError(details.takeError()); // Ignore 0 length read if (!len) @@ -1295,7 +1295,7 @@ Status NativeProcessAIX::WriteMemoryTags(int32_t type, lldb::addr_t addr, llvm::Expected details = GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); if (!details) - return Status(details.takeError()); + return Status::FromError(details.takeError()); // Ignore 0 length write if (!len) @@ -1312,18 +1312,18 @@ Status NativeProcessAIX::WriteMemoryTags(int32_t type, lldb::addr_t addr, llvm::Expected> unpacked_tags_or_err = details->manager->UnpackTagsData(tags); if (!unpacked_tags_or_err) - return Status(unpacked_tags_or_err.takeError()); + return Status::FromError(unpacked_tags_or_err.takeError()); llvm::Expected> repeated_tags_or_err = details->manager->RepeatTagsForRange(*unpacked_tags_or_err, range); if (!repeated_tags_or_err) - return Status(repeated_tags_or_err.takeError()); + return Status::FromError(repeated_tags_or_err.takeError()); // Repack them for ptrace to use llvm::Expected> final_tag_data = details->manager->PackTags(*repeated_tags_or_err); if (!final_tag_data) - return Status(final_tag_data.takeError()); + return Status::FromError(final_tag_data.takeError()); struct iovec tags_vec; uint8_t *src = final_tag_data->data(); @@ -1609,13 +1609,13 @@ Status NativeProcessAIX::ResumeThread(NativeThreadAIX &thread, // reflect it is running after this completes. switch (state) { case eStateRunning: { - const auto resume_result = thread.Resume(signo); + Status resume_result = thread.Resume(signo); if (resume_result.Success()) SetState(eStateRunning, true); return resume_result; } case eStateStepping: { - const auto step_result = thread.SingleStep(signo); + Status step_result = thread.SingleStep(signo); if (step_result.Success()) SetState(eStateRunning, true); return step_result; >From 627a5427daba3fc5ea03ae481874f4aa1b4d2ed0 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Fri, 13 Sep 2024 16:25:47 +0530 Subject: [PATCH 09/47] Revert "Removed non-required PTRACE defs" --- lldb/include/lldb/Host/aix/Ptrace.h | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/lldb/include/lldb/Host/aix/Ptrace.h b/lldb/include/lldb/Host/aix/Ptrace.h index 393928a89add3..88928f18102d7 100644 --- a/lldb/include/lldb/Host/aix/Ptrace.h +++ b/lldb/include/lldb/Host/aix/Ptrace.h @@ -34,11 +34,29 @@ #ifndef PTRACE_SETREGSET #define PTRACE_SETREGSET 0x4205 #endif +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA (PT_COMMAND_MAX+5) +#endif +#ifndef PTRACE_ARCH_PRCTL +#define PTRACE_ARCH_PRCTL (PT_COMMAND_MAX+6) +#endif +#ifndef ARCH_GET_FS +#define ARCH_SET_GS 0x1001 +#define ARCH_SET_FS 0x1002 +#define ARCH_GET_FS 0x1003 +#define ARCH_GET_GS 0x1004 +#endif +#ifndef PTRACE_PEEKMTETAGS +#define PTRACE_PEEKMTETAGS (PT_COMMAND_MAX+7) +#endif +#ifndef PTRACE_POKEMTETAGS +#define PTRACE_POKEMTETAGS (PT_COMMAND_MAX+8) +#endif #ifndef PTRACE_GETVRREGS -#define PTRACE_GETVRREGS (PT_COMMAND_MAX+5) +#define PTRACE_GETVRREGS (PT_COMMAND_MAX+9) #endif #ifndef PTRACE_GETVSRREGS -#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+6) +#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+10) #endif #endif // liblldb_Host_aix_Ptrace_h_ >From ea34b15d8568b4639b4e850ef032e684d82dd971 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Thu, 10 Oct 2024 00:38:18 -0500 Subject: [PATCH 10/47] Replaced __AIX__ with _AIX --- clang/test/SemaCXX/class-layout.cpp | 2 +- lldb/CMakeLists.txt | 2 +- lldb/include/lldb/Host/HostGetOpt.h | 2 +- lldb/include/lldb/Host/HostInfo.h | 2 +- lldb/include/lldb/Host/XML.h | 2 +- lldb/include/lldb/Host/common/GetOptInc.h | 4 ++-- lldb/include/lldb/Target/Process.h | 6 +++--- lldb/include/lldb/Target/RegisterContextUnwind.h | 2 +- lldb/source/Core/Mangled.cpp | 2 +- lldb/source/Core/Section.cpp | 2 +- lldb/source/Host/common/Host.cpp | 4 ++-- lldb/source/Host/common/XML.cpp | 2 +- lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp | 2 +- lldb/source/Host/posix/FileSystemPosix.cpp | 2 +- lldb/source/Host/posix/MainLoopPosix.cpp | 4 ++-- lldb/source/Host/posix/ProcessLauncherPosixFork.cpp | 2 +- lldb/source/Initialization/SystemInitializerCommon.cpp | 4 ++-- lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp | 4 ++-- .../DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 6 +++--- .../Plugins/Instruction/PPC64/EmulateInstructionPPC64.h | 2 +- lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp | 2 +- lldb/source/Plugins/Language/ObjC/Cocoa.cpp | 2 +- .../BSD-Archive/ObjectContainerBSDArchive.cpp | 2 +- .../Big-Archive/ObjectContainerBigArchive.cpp | 2 +- .../Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp | 2 +- lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp | 6 +++--- .../source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp | 6 +++--- lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp | 6 +++--- lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp | 4 ++-- .../Process/gdb-remote/GDBRemoteCommunicationClient.cpp | 4 ++-- .../Process/gdb-remote/GDBRemoteCommunicationClient.h | 4 ++-- .../gdb-remote/GDBRemoteCommunicationServerLLGS.cpp | 4 ++-- .../Plugins/Process/gdb-remote/ProcessGDBRemote.cpp | 4 ++-- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h | 4 ++-- lldb/source/Target/Process.cpp | 4 ++-- lldb/source/Target/RegisterContextUnwind.cpp | 8 ++++---- lldb/source/Target/UnwindLLDB.cpp | 4 ++-- lldb/tools/driver/Driver.cpp | 4 ++-- lldb/tools/lldb-server/SystemInitializerLLGS.cpp | 8 ++++---- lldb/tools/lldb-server/lldb-gdbserver.cpp | 4 ++-- lldb/unittests/Host/MainLoopTest.cpp | 2 +- lldb/unittests/Host/PipeTest.cpp | 2 +- lldb/unittests/Host/posix/TerminalTest.cpp | 4 ++-- 43 files changed, 75 insertions(+), 75 deletions(-) diff --git a/clang/test/SemaCXX/class-layout.cpp b/clang/test/SemaCXX/class-layout.cpp index 22fb34b8419c5..0931d905a9749 100644 --- a/clang/test/SemaCXX/class-layout.cpp +++ b/clang/test/SemaCXX/class-layout.cpp @@ -639,7 +639,7 @@ namespace PR37275 { #pragma pack(pop) } -#endif // !defined(__MVS__) && !defined(__AIX__) +#endif // !defined(__MVS__) && !defined(_AIX) namespace non_pod { struct t1 { diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt index 2e9ae0d0b3221..a4fd8bccf056d 100644 --- a/lldb/CMakeLists.txt +++ b/lldb/CMakeLists.txt @@ -39,7 +39,7 @@ include(LLDBConfig) include(AddLLDB) if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") - add_definitions("-D__AIX__") + add_definitions("-D_AIX") endif() # Define the LLDB_CONFIGURATION_xxx matching the build type. diff --git a/lldb/include/lldb/Host/HostGetOpt.h b/lldb/include/lldb/Host/HostGetOpt.h index f450e561d6afb..b2b436e64a692 100644 --- a/lldb/include/lldb/Host/HostGetOpt.h +++ b/lldb/include/lldb/Host/HostGetOpt.h @@ -9,7 +9,7 @@ #ifndef LLDB_HOST_HOSTGETOPT_H #define LLDB_HOST_HOSTGETOPT_H -#if !defined(_MSC_VER) && !defined(__NetBSD__) && !defined(__AIX__) +#if !defined(_MSC_VER) && !defined(__NetBSD__) && !defined(_AIX) #include #include diff --git a/lldb/include/lldb/Host/HostInfo.h b/lldb/include/lldb/Host/HostInfo.h index 156df8cf6901d..0f7ec0e0aa0d2 100644 --- a/lldb/include/lldb/Host/HostInfo.h +++ b/lldb/include/lldb/Host/HostInfo.h @@ -55,7 +55,7 @@ #elif defined(__APPLE__) #include "lldb/Host/macosx/HostInfoMacOSX.h" #define HOST_INFO_TYPE HostInfoMacOSX -#elif defined(__AIX__) +#elif defined(_AIX) #include "lldb/Host/aix/HostInfoAIX.h" #define HOST_INFO_TYPE HostInfoAIX #else diff --git a/lldb/include/lldb/Host/XML.h b/lldb/include/lldb/Host/XML.h index cf359f7726d5d..483589f1abc75 100644 --- a/lldb/include/lldb/Host/XML.h +++ b/lldb/include/lldb/Host/XML.h @@ -11,7 +11,7 @@ #include "lldb/Host/Config.h" -#if defined(__AIX__) +#if defined(_AIX) //FIXME for AIX #undef LLDB_ENABLE_LIBXML2 #endif diff --git a/lldb/include/lldb/Host/common/GetOptInc.h b/lldb/include/lldb/Host/common/GetOptInc.h index ebb475bfaf6b8..652e6174ff8b6 100644 --- a/lldb/include/lldb/Host/common/GetOptInc.h +++ b/lldb/include/lldb/Host/common/GetOptInc.h @@ -11,11 +11,11 @@ #include "lldb/lldb-defines.h" -#if defined(_MSC_VER) || defined(__AIX__) +#if defined(_MSC_VER) || defined(_AIX) #define REPLACE_GETOPT #define REPLACE_GETOPT_LONG #endif -#if defined(_MSC_VER) || defined(__NetBSD__) || defined(__AIX__) +#if defined(_MSC_VER) || defined(__NetBSD__) || defined(_AIX) #define REPLACE_GETOPT_LONG_ONLY #endif diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index 4a47ffd8d779d..d1527d316d678 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -65,7 +65,7 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/VersionTuple.h" -#if defined(__AIX__) +#if defined(_AIX) struct ld_xinfo; #endif @@ -1884,7 +1884,7 @@ class Process : public std::enable_shared_from_this, Status GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &range_info); -#if defined(__AIX__) +#if defined(_AIX) Status GetLDXINFO(struct ld_xinfo *info_ptr); #endif @@ -2823,7 +2823,7 @@ void PruneThreadPlans(); "Process::DoGetMemoryRegionInfo() not supported"); } -#if defined(__AIX__) +#if defined(_AIX) virtual Status DoGetLDXINFO(struct ld_xinfo *info_ptr) { return Status("Process::DoGetLDXINFO() not supported"); } diff --git a/lldb/include/lldb/Target/RegisterContextUnwind.h b/lldb/include/lldb/Target/RegisterContextUnwind.h index 46c06cb422caf..b6176f8e5727f 100644 --- a/lldb/include/lldb/Target/RegisterContextUnwind.h +++ b/lldb/include/lldb/Target/RegisterContextUnwind.h @@ -67,7 +67,7 @@ class RegisterContextUnwind : public lldb_private::RegisterContext { bool ReadPC(lldb::addr_t &start_pc); -#ifdef __AIX__ +#ifdef _AIX bool ReadLR(lldb::addr_t &lr); #endif diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp index 43c5b043ef7a2..8f2e3562f6577 100644 --- a/lldb/source/Core/Mangled.cpp +++ b/lldb/source/Core/Mangled.cpp @@ -167,7 +167,7 @@ static char *GetItaniumDemangledStr(const char *M) { "Expected demangled_size to return length including trailing null"); } -#if !defined(__AIX__) +#if !defined(_AIX) if (Log *log = GetLog(LLDBLog::Demangle)) { if (demangled_cstr) LLDB_LOGF(log, "demangled itanium: %s -> \"%s\"", M, demangled_cstr); diff --git a/lldb/source/Core/Section.cpp b/lldb/source/Core/Section.cpp index 9ed55853930a6..e0a9f7fcc7135 100644 --- a/lldb/source/Core/Section.cpp +++ b/lldb/source/Core/Section.cpp @@ -263,7 +263,7 @@ bool Section::ResolveContainedAddress(addr_t offset, Address &so_addr, bool Section::ContainsFileAddress(addr_t vm_addr) const { const addr_t file_addr = GetFileAddress(); -#ifdef __AIX__ +#ifdef _AIX if (file_addr == 0) return false; #endif diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 94b1d0fd57d07..dc48cb87b5ce6 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -358,7 +358,7 @@ bool Host::ResolveExecutableInBundle(FileSpec &file) { return false; } #ifndef _WIN32 -#if defined(__AIX__) +#if defined(_AIX) #include extern char **p_xargv; @@ -525,7 +525,7 @@ static int dladdr(const void *ptr, Dl_info *dl) FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSpec module_filespec; #if !defined(__ANDROID__) -#ifdef __AIX__ +#ifdef _AIX if (host_addr == reinterpret_cast(HostInfoBase::ComputeSharedLibraryDirectory)) { // FIXME: AIX dladdr return "lldb" for this case if (p_xargv[0]) { diff --git a/lldb/source/Host/common/XML.cpp b/lldb/source/Host/common/XML.cpp index 62cac78aaac23..fbc409105fe60 100644 --- a/lldb/source/Host/common/XML.cpp +++ b/lldb/source/Host/common/XML.cpp @@ -10,7 +10,7 @@ #include "lldb/Host/XML.h" #include "llvm/ADT/StringExtras.h" -#if defined(__AIX__) +#if defined(_AIX) #undef LLDB_ENABLE_LIBXML2 #endif diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index bd204c812b7e3..09c3fd2af6d3e 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -722,7 +722,7 @@ ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, ConnectionStatus ConnectionFileDescriptor::ConnectFile( llvm::StringRef s, socket_id_callback_type socket_id_callback, Status *error_ptr) { -#if !defined(__AIX__) +#if !defined(_AIX) #if LLDB_ENABLE_POSIX std::string addr_str = s.str(); // file:///PATH diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index 866fd8ac96c7b..21da5612ff6b8 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,7 +11,7 @@ // C includes #include #include -#if !defined(__AIX__) +#if !defined(_AIX) #include #endif #include diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp index d1eba52791a78..015570236b9d3 100644 --- a/lldb/source/Host/posix/MainLoopPosix.cpp +++ b/lldb/source/Host/posix/MainLoopPosix.cpp @@ -179,7 +179,7 @@ Status MainLoopPosix::RunImpl::Poll() { read_fds.push_back(pfd); } -#if defined(__AIX__) +#if defined(_AIX) sigset_t origmask; int timeout; @@ -325,7 +325,7 @@ MainLoopPosix::RegisterSignal(int signo, const Callback &callback, // If we're using kqueue, the signal needs to be unblocked in order to // receive it. If using pselect/ppoll, we need to block it, and later unblock // it as a part of the system call. -#if defined(__AIX__) +#if defined(_AIX) //FIXME: where is signal unblocked? ret = pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, &old_set); #else diff --git a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp index b8a96fbd19f02..f9f99decd39c2 100644 --- a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp +++ b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp @@ -193,7 +193,7 @@ struct ForkLaunchInfo { } // Start tracing this child that is about to exec. -#if !defined(__AIX__) +#if !defined(_AIX) if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1) ExitWithError(error_fd, "ptrace"); #else diff --git a/lldb/source/Initialization/SystemInitializerCommon.cpp b/lldb/source/Initialization/SystemInitializerCommon.cpp index 4b01442a94bac..2e2d622d9981c 100644 --- a/lldb/source/Initialization/SystemInitializerCommon.cpp +++ b/lldb/source/Initialization/SystemInitializerCommon.cpp @@ -19,7 +19,7 @@ #include "lldb/Version/Version.h" #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__OpenBSD__) || defined(__AIX__) + defined(__OpenBSD__) || defined(_AIX) #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" #endif @@ -79,7 +79,7 @@ llvm::Error SystemInitializerCommon::Initialize() { process_gdb_remote::ProcessGDBRemoteLog::Initialize(); #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__OpenBSD__) || defined(__AIX__) + defined(__OpenBSD__) || defined(_AIX) ProcessPOSIXLog::Initialize(); #endif #if defined(_WIN32) diff --git a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp index 88a82f4a0d20c..a3abb15ee625b 100644 --- a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp +++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp @@ -156,7 +156,7 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) return false; -#if defined(__AIX__) +#if defined(_AIX) assert(0); #else // Read TOC pointer value. @@ -279,7 +279,7 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) return false; -#if defined(__AIX__) +#if defined(_AIX) LLDB_LOGF(log, "Writing R2: 0x%" PRIx64, (uint64_t)toc_addr); if (!reg_ctx->WriteRegisterFromUnsigned(r2_reg_info, toc_addr)) return false; diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 62663974134b0..7f3a638d5b028 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -18,7 +18,7 @@ #include "lldb/Target/ThreadPlanStepInstruction.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -160,7 +160,7 @@ void DynamicLoaderAIXDYLD::DidAttach() { auto error = m_process->LoadModules(); LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}"); -#if defined(__AIX__) +#if defined(_AIX) // Get struct ld_xinfo (FIXME) struct ld_xinfo ldinfo[64]; Status status = m_process->GetLDXINFO(&(ldinfo[0])); @@ -221,7 +221,7 @@ void DynamicLoaderAIXDYLD::DidLaunch() { LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}"); } -#if defined(__AIX__) +#if defined(_AIX) // Get struct ld_xinfo (FIXME) struct ld_xinfo ldinfo[64]; Status status = m_process->GetLDXINFO(&(ldinfo[0])); diff --git a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h index 1576c9700e557..d98b2880ca3b4 100644 --- a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h +++ b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h @@ -39,7 +39,7 @@ class EmulateInstructionPPC64 : public EmulateInstruction { return true; case eInstructionTypePCModifying: -#if defined(__AIX__) +#if defined(_AIX) return true; #else return false; diff --git a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp index 690fb0d60a09a..9a52fb2f2adc5 100644 --- a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp +++ b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp @@ -194,7 +194,7 @@ void JITLoaderGDB::SetJITBreakpoint(lldb_private::ModuleList &module_list) { if (jit_addr == LLDB_INVALID_ADDRESS) return; -#if defined(__AIX__) +#if defined(_AIX) return; #endif diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index fb5bc2c58e6fb..71f2b127afb12 100644 --- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -1227,7 +1227,7 @@ bool lldb_private::formatters::ObjCSELSummaryProvider( time_t lldb_private::formatters::GetOSXEpoch() { static time_t epoch = 0; if (!epoch) { -#if !defined(__AIX__) +#if !defined(_AIX) #ifndef _WIN32 tzset(); tm tm_epoch; diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 5ea55772c3aba..4f747ab20c9ef 100644 --- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -8,7 +8,7 @@ #include "ObjectContainerBSDArchive.h" -#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__) +#if defined(_WIN32) || defined(__ANDROID__) || defined(_AIX) // Defines from ar, missing on Windows #define SARMAG 8 #define ARFMAG "`\n" diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp index 050ad73f1d19a..38756a0dd2969 100644 --- a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp @@ -8,7 +8,7 @@ #include "ObjectContainerBigArchive.h" -#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__) +#if defined(_WIN32) || defined(__ANDROID__) || defined(_AIX) // Defines from ar, missing on Windows #define ARMAG "!\n" #define SARMAG 8 diff --git a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp index d8834af2c33ef..9aab76c6c48ba 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp +++ b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp @@ -51,7 +51,7 @@ size_t ObjectFileMinidump::GetModuleSpecifications( const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, lldb_private::ModuleSpecList &specs) { -#if !defined(__AIX__) +#if !defined(_AIX) specs.Clear(); #endif return 0; diff --git a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp index 75cc54e4f0d48..d76d6adb1be2c 100644 --- a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp +++ b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp @@ -117,7 +117,7 @@ size_t ObjectFilePDB::GetModuleSpecifications( llvm::BumpPtrAllocator allocator; std::unique_ptr pdb_file = loadPDBFile(file.GetPath(), allocator); if (!pdb_file){ -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; @@ -127,7 +127,7 @@ size_t ObjectFilePDB::GetModuleSpecifications( auto info_stream = pdb_file->getPDBInfoStream(); if (!info_stream) { llvm::consumeError(info_stream.takeError()); -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; @@ -136,7 +136,7 @@ size_t ObjectFilePDB::GetModuleSpecifications( auto dbi_stream = pdb_file->getPDBDbiStream(); if (!dbi_stream) { llvm::consumeError(dbi_stream.takeError()); -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index 519ce2ca4a0b2..02a86234bd363 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -254,7 +254,7 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( lldb::offset_t length, lldb_private::ModuleSpecList &specs) { const size_t initial_count = specs.GetSize(); if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp)){ -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; @@ -272,7 +272,7 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( if (!binary) { LLDB_LOG_ERROR(log, binary.takeError(), "Failed to create binary for file ({1}): {0}", file); -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; @@ -281,7 +281,7 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( auto *COFFObj = llvm::dyn_cast(binary->get()); if (!COFFObj){ -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp index b6b08b73bec41..5c94477002978 100644 --- a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp +++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp @@ -31,7 +31,7 @@ // Define these constants from AIX mman.h for use when targeting remote aix // systems even when host has different values. -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -80,7 +80,7 @@ void PlatformAIX::Initialize() { PlatformPOSIX::Initialize(); if (g_initialize_count++ == 0) { -#if defined(__AIX__) +#if defined(_AIX) PlatformSP default_platform_sp(new PlatformAIX(true)); default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); Platform::SetHostPlatform(default_platform_sp); @@ -294,7 +294,7 @@ MmapArgList PlatformAIX::GetMmapArgumentList(const ArchSpec &arch, addr_t addr, addr_t length, unsigned prot, unsigned flags, addr_t fd, addr_t offset) { -#if defined(__AIX__) +#if defined(_AIX) unsigned flags_platform = MAP_VARIABLE | MAP_PRIVATE | MAP_ANONYMOUS; #else unsigned flags_platform = 0; diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index db271357d792a..ea758caa653a1 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -46,7 +46,7 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, function_options.include_inlines = false; SymbolContextList sc_list; -#if !defined(__AIX__) +#if !defined(_AIX) process->GetTarget().GetImages().FindFunctions( ConstString("mmap"), eFunctionNameTypeFull, function_options, sc_list); #else @@ -122,7 +122,7 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, MmapArgList args = process->GetTarget().GetPlatform()->GetMmapArgumentList( arch, addr, length, prot_arg, flags, fd, offset); -#if defined(__AIX__) +#if defined(_AIX) lldb::ThreadPlanSP call_plan_sp( new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(), toc_range.GetBaseAddress(), diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 443b7c7b2c7fb..fa0a3b5d4dc38 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -41,7 +41,7 @@ #include "llvm/Config/llvm-config.h" // for LLVM_ENABLE_ZLIB #include "llvm/Support/JSON.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -1715,7 +1715,7 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( return error; } -#if defined(__AIX__) +#if defined(_AIX) Status GDBRemoteCommunicationClient::GetLDXINFO(struct ld_xinfo *info_ptr) { Status error; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 520f37ac56716..1812fc9b7ca65 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -32,7 +32,7 @@ #include "llvm/Support/VersionTuple.h" -#if defined(__AIX__) +#if defined(_AIX) struct ld_xinfo; #endif @@ -200,7 +200,7 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase { Status GetMemoryRegionInfo(lldb::addr_t addr, MemoryRegionInfo &range_info); std::optional GetWatchpointSlotCount(); -#if defined(__AIX__) +#if defined(_AIX) Status GetLDXINFO(struct ld_xinfo *info_ptr); #endif diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 4f1ef0898ba08..27be61a474238 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -48,7 +48,7 @@ #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "lldb/Utility/StringExtractorGDBRemote.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -3011,7 +3011,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qLDXINFO(StringExtractorGDBRemote &pack return SendErrorResponse(0xff); } -#if defined(__AIX__) +#if defined(_AIX) // FIXME: buffer size struct ld_xinfo info[64]; if (ptrace64(PT_LDXINFO, m_current_process->GetID(), (long long)&(info[0]), sizeof(info), nullptr) != 0) { diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index ca381290d0e9f..5b7ce5f1424d9 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -92,7 +92,7 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/raw_ostream.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -2963,7 +2963,7 @@ Status ProcessGDBRemote::DoGetMemoryRegionInfo(addr_t load_addr, return error; } -#if defined(__AIX__) +#if defined(_AIX) Status ProcessGDBRemote::DoGetLDXINFO(struct ld_xinfo *info_ptr) { Status error(m_gdb_comm.GetLDXINFO(info_ptr)); return error; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 82200fbea21cd..2bf3a04d213d4 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -37,7 +37,7 @@ #include "GDBRemoteCommunicationClient.h" #include "GDBRemoteRegisterContext.h" -#if defined(__AIX__) +#if defined(_AIX) struct ld_xinfo; #endif @@ -427,7 +427,7 @@ class ProcessGDBRemote : public Process, Status DoGetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo ®ion_info) override; -#if defined(__AIX__) +#if defined(_AIX) Status DoGetLDXINFO(struct ld_xinfo *info_ptr) override; #endif diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index a9aef7ef21855..e6ae7fc559ef4 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -75,7 +75,7 @@ #include "lldb/Utility/State.h" #include "lldb/Utility/Timer.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -6188,7 +6188,7 @@ Status Process::GetMemoryRegionInfo(lldb::addr_t load_addr, return DoGetMemoryRegionInfo(load_addr, range_info); } -#if defined(__AIX__) +#if defined(_AIX) Status Process::GetLDXINFO(struct ld_xinfo *info_ptr) { return DoGetLDXINFO(info_ptr); } diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index fbdbc8c63a5d0..fdf269a3d3653 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -40,7 +40,7 @@ #include #include -#ifdef __AIX__ +#ifdef _AIX #include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" #endif @@ -1260,7 +1260,7 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( // Answer the question: Where did THIS frame save the CALLER frame ("previous" // frame)'s register value? -#ifdef __AIX__ +#ifdef _AIX extern bool UGLY_HACK_NULL_TOPFRAME; #endif @@ -1525,7 +1525,7 @@ RegisterContextUnwind::SavedLocationForRegister( new_regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterInLiveRegisterContext; new_regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); -#ifdef __AIX__ +#ifdef _AIX if (UGLY_HACK_NULL_TOPFRAME && new_regloc.location.register_number == 0x20) { new_regloc.location.register_number = 0x24; } @@ -2390,7 +2390,7 @@ bool RegisterContextUnwind::ReadPC(addr_t &pc) { } } -#ifdef __AIX__ +#ifdef _AIX bool RegisterContextUnwind::ReadLR(addr_t &lr) { if (!IsValid()) return false; diff --git a/lldb/source/Target/UnwindLLDB.cpp b/lldb/source/Target/UnwindLLDB.cpp index 8edf359cac497..764bea5bf86c6 100644 --- a/lldb/source/Target/UnwindLLDB.cpp +++ b/lldb/source/Target/UnwindLLDB.cpp @@ -68,7 +68,7 @@ uint32_t UnwindLLDB::DoGetFrameCount() { return m_frames.size(); } -#ifdef __AIX__ +#ifdef _AIX bool UGLY_HACK_NULL_TOPFRAME = false; #endif @@ -95,7 +95,7 @@ bool UnwindLLDB::AddFirstFrame() { if (!reg_ctx_sp->ReadPC(first_cursor_sp->start_pc)) goto unwind_done; -#ifdef __AIX__ +#ifdef _AIX lldb::addr_t lr; if (!reg_ctx_sp->ReadLR(lr)) goto unwind_done; diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp index 45837503e8b73..d17ed77485d31 100644 --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -640,7 +640,7 @@ void sigwinch_handler(int signo) { } void sigint_handler(int signo) { -#if defined(_WIN32) || defined(__AIX__) // Restore handler as it is not persistent on Windows +#if defined(_WIN32) || defined(_AIX) // Restore handler as it is not persistent on Windows signal(SIGINT, sigint_handler); #endif static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT; @@ -729,7 +729,7 @@ static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) { int main(int argc, char const *argv[]) { // Editline uses for example iswprint which is dependent on LC_CTYPE. // FIXME: this caused unexpected SIGTRAP on AIX -#ifndef __AIX__ +#ifndef _AIX std::setlocale(LC_ALL, ""); std::setlocale(LC_CTYPE, ""); #endif diff --git a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp index 91bb2083a88b5..52c2eae0c9033 100644 --- a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp +++ b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp @@ -14,7 +14,7 @@ using HostObjectFile = ObjectFileMachO; #elif defined(_WIN32) #include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" using HostObjectFile = ObjectFilePECOFF; -#elif defined(__AIX__) +#elif defined(_AIX) #include "Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h" using HostObjectFile = ObjectFileXCOFF; #else @@ -49,7 +49,7 @@ using HostObjectFile = ObjectFileELF; #include "Plugins/Instruction/MIPS/EmulateInstructionMIPS.h" #endif -#if defined(__AIX__) +#if defined(_AIX) #include "Plugins/Instruction/PPC64/EmulateInstructionPPC64.h" #endif @@ -82,7 +82,7 @@ llvm::Error SystemInitializerLLGS::Initialize() { EmulateInstructionRISCV::Initialize(); #endif -#if defined(__AIX__) +#if defined(_AIX) EmulateInstructionPPC64::Initialize(); #endif @@ -108,7 +108,7 @@ void SystemInitializerLLGS::Terminate() { EmulateInstructionRISCV::Terminate(); #endif -#if defined(__AIX__) +#if defined(_AIX) EmulateInstructionPPC64::Terminate(); #endif diff --git a/lldb/tools/lldb-server/lldb-gdbserver.cpp b/lldb/tools/lldb-server/lldb-gdbserver.cpp index 844a6370bdb2e..dcbb421a73e25 100644 --- a/lldb/tools/lldb-server/lldb-gdbserver.cpp +++ b/lldb/tools/lldb-server/lldb-gdbserver.cpp @@ -45,7 +45,7 @@ #include "Plugins/Process/NetBSD/NativeProcessNetBSD.h" #elif defined(_WIN32) #include "Plugins/Process/Windows/Common/NativeProcessWindows.h" -#elif defined(__AIX__) +#elif defined(_AIX) #include "Plugins/Process/AIX/NativeProcessAIX.h" #endif @@ -72,7 +72,7 @@ typedef process_freebsd::NativeProcessFreeBSD::Manager NativeProcessManager; typedef process_netbsd::NativeProcessNetBSD::Manager NativeProcessManager; #elif defined(_WIN32) typedef NativeProcessWindows::Manager NativeProcessManager; -#elif defined(__AIX__) +#elif defined(_AIX) typedef process_aix::NativeProcessAIX::Manager NativeProcessManager; #else // Dummy implementation to make sure the code compiles diff --git a/lldb/unittests/Host/MainLoopTest.cpp b/lldb/unittests/Host/MainLoopTest.cpp index c76476c947054..5c042261b9ef2 100644 --- a/lldb/unittests/Host/MainLoopTest.cpp +++ b/lldb/unittests/Host/MainLoopTest.cpp @@ -223,7 +223,7 @@ TEST_F(MainLoopTest, PendingCallbackAfterLoopExited) { loop.AddPendingCallback([&](MainLoopBase &loop) {}); } -#if defined(LLVM_ON_UNIX) && !defined(__AIX__) +#if defined(LLVM_ON_UNIX) && !defined(_AIX) TEST_F(MainLoopTest, DetectsEOF) { PseudoTerminal term; diff --git a/lldb/unittests/Host/PipeTest.cpp b/lldb/unittests/Host/PipeTest.cpp index c1013aa7a7e4e..00ffd33d68f7a 100644 --- a/lldb/unittests/Host/PipeTest.cpp +++ b/lldb/unittests/Host/PipeTest.cpp @@ -55,7 +55,7 @@ TEST_F(PipeTest, OpenAsReader) { } #endif -#if !defined(__AIX__) +#if !defined(_AIX) TEST_F(PipeTest, WriteWithTimeout) { Pipe pipe; ASSERT_THAT_ERROR(pipe.CreateNew(false).ToError(), llvm::Succeeded()); diff --git a/lldb/unittests/Host/posix/TerminalTest.cpp b/lldb/unittests/Host/posix/TerminalTest.cpp index f3de92c0852b1..64e6be64db80c 100644 --- a/lldb/unittests/Host/posix/TerminalTest.cpp +++ b/lldb/unittests/Host/posix/TerminalTest.cpp @@ -94,14 +94,14 @@ TEST_F(TerminalTest, SetRaw) { TEST_F(TerminalTest, SetBaudRate) { struct termios terminfo; -#if (defined(__AIX__) && defined(B38400)) || !defined(__AIX__) +#if (defined(_AIX) && defined(B38400)) || !defined(_AIX) ASSERT_THAT_ERROR(m_term.SetBaudRate(38400), llvm::Succeeded()); ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0); EXPECT_EQ(cfgetispeed(&terminfo), static_cast(B38400)); EXPECT_EQ(cfgetospeed(&terminfo), static_cast(B38400)); #endif -#if (defined(__AIX__) && defined(B115200)) || !defined(__AIX__) +#if (defined(_AIX) && defined(B115200)) || !defined(_AIX) ASSERT_THAT_ERROR(m_term.SetBaudRate(115200), llvm::Succeeded()); ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0); EXPECT_EQ(cfgetispeed(&terminfo), static_cast(B115200)); >From a8020a6a8692f059679195ae1a0ef5e0eeee94c8 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Thu, 10 Oct 2024 04:52:08 -0500 Subject: [PATCH 11/47] Removed from lldb/CMakeLists --- lldb/CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt index a4fd8bccf056d..59cdc4593463c 100644 --- a/lldb/CMakeLists.txt +++ b/lldb/CMakeLists.txt @@ -38,10 +38,6 @@ endif() include(LLDBConfig) include(AddLLDB) -if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") - add_definitions("-D_AIX") -endif() - # Define the LLDB_CONFIGURATION_xxx matching the build type. if(uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" ) add_definitions(-DLLDB_CONFIGURATION_DEBUG) >From 7609ad339bfab48412221be54edc2d2d146279c3 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Thu, 14 Nov 2024 13:23:59 -0600 Subject: [PATCH 12/47] Patch for the Merge conflict of xcoff first merge with llvm --- .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 253 +++++++++++++++++- 1 file changed, 252 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index 395a126a01fce..a4d9ea295b4c3 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -188,7 +188,258 @@ bool ObjectFileXCOFF::ParseHeader() { if (module_sp) { std::lock_guard guard(module_sp->GetMutex()); m_sect_headers.clear(); - lldb::offs + lldb::offset_t offset = 0; + + if (ParseXCOFFHeader(m_data, &offset, m_xcoff_header)) { + m_data.SetAddressByteSize(GetAddressByteSize()); + if (m_xcoff_header.auxhdrsize > 0) + ParseXCOFFOptionalHeader(m_data, &offset); + ParseSectionHeaders(offset); + } + return true; + } + + return false; +} + +bool ObjectFileXCOFF::ParseXCOFFHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + xcoff_header_t &xcoff_header) { + //FIXME: data.ValidOffsetForDataOfSize + xcoff_header.magic = data.GetU16(offset_ptr); + xcoff_header.nsects = data.GetU16(offset_ptr); + xcoff_header.modtime = data.GetU32(offset_ptr); + xcoff_header.symoff = data.GetU64(offset_ptr); + xcoff_header.auxhdrsize = data.GetU16(offset_ptr); + xcoff_header.flags = data.GetU16(offset_ptr); + xcoff_header.nsyms = data.GetU32(offset_ptr); + return true; +} + +bool ObjectFileXCOFF::ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr) { + lldb::offset_t init_offset = *offset_ptr; + //FIXME: data.ValidOffsetForDataOfSize + m_xcoff_aux_header.AuxMagic = data.GetU16(offset_ptr); + m_xcoff_aux_header.Version = data.GetU16(offset_ptr); + m_xcoff_aux_header.ReservedForDebugger = data.GetU32(offset_ptr); + m_xcoff_aux_header.TextStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.DataStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.TOCAnchorAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfEntryPoint = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTOC = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfLoader = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.ModuleType = data.GetU16(offset_ptr); + m_xcoff_aux_header.CpuFlag = data.GetU8(offset_ptr); + m_xcoff_aux_header.CpuType = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.DataPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.StackPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.FlagAndTDataAlignment = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.InitDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.BssDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.EntryPointAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxStackSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfTData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.XCOFF64Flag = data.GetU16(offset_ptr); + lldb::offset_t last_offset = *offset_ptr; + if ((last_offset - init_offset) < m_xcoff_header.auxhdrsize) + *offset_ptr += (m_xcoff_header.auxhdrsize - (last_offset - init_offset)); + return true; +} + +bool ObjectFileXCOFF::ParseSectionHeaders( + uint32_t section_header_data_offset) { + const uint32_t nsects = m_xcoff_header.nsects; + m_sect_headers.clear(); + + if (nsects > 0) { + const size_t section_header_byte_size = nsects * m_binary->getSectionHeaderSize(); + lldb_private::DataExtractor section_header_data = + ReadImageData(section_header_data_offset, section_header_byte_size); + + lldb::offset_t offset = 0; + //FIXME: section_header_data.ValidOffsetForDataOfSize + m_sect_headers.resize(nsects); + + for (uint32_t idx = 0; idx < nsects; ++idx) { + const void *name_data = section_header_data.GetData(&offset, 8); + if (name_data) { + memcpy(m_sect_headers[idx].name, name_data, 8); + m_sect_headers[idx].phyaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].vmaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].size = section_header_data.GetU64(&offset); + m_sect_headers[idx].offset = section_header_data.GetU64(&offset); + m_sect_headers[idx].reloff = section_header_data.GetU64(&offset); + m_sect_headers[idx].lineoff = section_header_data.GetU64(&offset); + m_sect_headers[idx].nreloc = section_header_data.GetU32(&offset); + m_sect_headers[idx].nline = section_header_data.GetU32(&offset); + m_sect_headers[idx].flags = section_header_data.GetU32(&offset); + offset += 4; + } else { + offset += (m_binary->getSectionHeaderSize() - 8); + } + } + } + + return !m_sect_headers.empty(); +} + +lldb_private::DataExtractor ObjectFileXCOFF::ReadImageData(uint32_t offset, size_t size) { + if (!size) + return {}; + + if (m_data.ValidOffsetForDataOfSize(offset, size)) + return lldb_private::DataExtractor(m_data, offset, size); + + assert(0); + ProcessSP process_sp(m_process_wp.lock()); + lldb_private::DataExtractor data; + if (process_sp) { + auto data_up = std::make_unique(size, 0); + Status readmem_error; + size_t bytes_read = + process_sp->ReadMemory(offset, data_up->GetBytes(), + data_up->GetByteSize(), readmem_error); + if (bytes_read == size) { + DataBufferSP buffer_sp(data_up.release()); + data.SetData(buffer_sp, 0, buffer_sp->GetByteSize()); + } + } + return data; +} + +bool ObjectFileXCOFF::SetLoadAddress(Target &target, lldb::addr_t value, + bool value_is_offset) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (section_sp && !section_sp->IsThreadSpecific()) { + bool use_offset = false; + if (strcmp(section_sp->GetName().AsCString(), ".text") == 0 || + strcmp(section_sp->GetName().AsCString(), ".data") == 0 || + strcmp(section_sp->GetName().AsCString(), ".bss") == 0) + use_offset = true; + + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, (use_offset ? + (section_sp->GetFileOffset() + value) : (section_sp->GetFileAddress() + value)))) + ++num_loaded_sections; + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (type_id == 1 && section_sp && strcmp(section_sp->GetName().AsCString(), ".text") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileOffset() + value)) + ++num_loaded_sections; + } + } else if (type_id == 2 && section_sp && strcmp(section_sp->GetName().AsCString(), ".data") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileAddress() + value)) + ++num_loaded_sections; + } + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +ByteOrder ObjectFileXCOFF::GetByteOrder() const { + return eByteOrderBig; +} + +bool ObjectFileXCOFF::IsExecutable() const { + return true; +} + +uint32_t ObjectFileXCOFF::GetAddressByteSize() const { + if (m_xcoff_header.magic == XCOFF::XCOFF64) + return 8; + else if (m_xcoff_header.magic == XCOFF::XCOFF32) + return 4; + return 4; +} + +AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) { + return AddressClass::eUnknown; +} + +lldb::SymbolType ObjectFileXCOFF::MapSymbolType(llvm::object::SymbolRef::Type sym_type) { + if (sym_type == llvm::object::SymbolRef::ST_Function) + return lldb::eSymbolTypeCode; + else if (sym_type == llvm::object::SymbolRef::ST_Data) + return lldb::eSymbolTypeData; + return lldb::eSymbolTypeInvalid; +} + +void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) { + SectionList *sect_list = GetSectionList(); + const uint32_t num_syms = m_xcoff_header.nsyms; + uint32_t sidx = 0; + if (num_syms > 0 && m_xcoff_header.symoff > 0) { + const uint32_t symbol_size = XCOFF::SymbolTableEntrySize; + const size_t symbol_data_size = num_syms * symbol_size; + lldb_private::DataExtractor symtab_data = + ReadImageData(m_xcoff_header.symoff, symbol_data_size); + + lldb::offset_t offset = 0; + std::string symbol_name; + Symbol *symbols = lldb_symtab.Resize(num_syms); + llvm::object::symbol_iterator SI = m_binary->symbol_begin(); + for (uint32_t i = 0; i < num_syms; ++i, ++SI) { + xcoff_symbol_t symbol; + const uint32_t symbol_offset = offset; + symbol.value = symtab_data.GetU64(&offset); + symbol.offset = symtab_data.GetU32(&offset); + Expected symbol_name_or_err = m_binary->getStringTableEntry(symbol.offset); + if (!symbol_name_or_err) { + consumeError(symbol_name_or_err.takeError()); + return; + } + StringRef symbol_name_str = symbol_name_or_err.get(); + symbol_name.assign(symbol_name_str.data()); symbol.sect = symtab_data.GetU16(&offset); symbol.type = symtab_data.GetU16(&offset); symbol.storage = symtab_data.GetU8(&offset); >From dd56fce276b60b40e1997292b3f554a20157661a Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 17 Nov 2024 00:15:01 -0600 Subject: [PATCH 13/47] Attach fix for AIX --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 130 ++++++++++++++++++ .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 5 +- 2 files changed, 134 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 7f3a638d5b028..acaa6a72edded 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -18,8 +18,13 @@ #include "lldb/Target/ThreadPlanStepInstruction.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" +#include "llvm/Support/FileSystem.h" #if defined(_AIX) #include +#include +#include +#include +#include #endif /*#include "llvm/ADT/Triple.h" @@ -131,14 +136,139 @@ bool DynamicLoaderAIXDYLD::NotifyBreakpointHit( lldb::user_id_t break_loc_id) { } + +void DynamicLoaderAIXDYLD::ResolveExecutableModule( + lldb::ModuleSP &module_sp) { + Log *log = GetLog(LLDBLog::DynamicLoader); + + if (m_process == nullptr) + return; + + auto &target = m_process->GetTarget(); + const auto platform_sp = target.GetPlatform(); + + ProcessInstanceInfo process_info; + if (!m_process->GetProcessInfo(process_info)) { + LLDB_LOGF(log, + "DynamicLoaderPOSIXDYLD::%s - failed to get process info for " + "pid %" PRIu64, + __FUNCTION__, m_process->GetID()); + return; + } + + char procinfo_path[64], exe_path[PATH_MAX], arg_buffer[8192]; + struct procsinfo64 procs_info; + int32long64_t pid = m_process->GetID(); + std::string proc_file = "/proc/" + std::to_string(pid) + "/psinfo"; + std::string cwd_link = "/proc/" + std::to_string(pid) + "/cwd"; + psinfo_t psinfo; + std::ifstream file(proc_file, std::ios::binary); + if(!file.is_open()) + { + LLDB_LOGF(log, "Error psinfo "); + } + file.read(reinterpret_cast(&psinfo), sizeof(psinfo_t)); + if(!file) + LLDB_LOGF(log, "Error psinfo: Failed to read "); + + std::string relative_path(psinfo.pr_fname); + LLDB_LOGF(log, "relative path %s",relative_path.c_str()); + + char cwd[PATH_MAX]; + char resolved_path[PATH_MAX]; + std::string executable_name; + bool found = 0; + if(readlink(cwd_link.c_str(), cwd, sizeof(cwd)) != -1){ + std::filesystem::path full_path = std::filesystem::path(cwd)/relative_path; + if(realpath(full_path.c_str(), resolved_path)) { + LLDB_LOGF(log, " RESOLVED PATH: %s", resolved_path); + found = 1; + } + else + perror("realpath error");} + + executable_name = resolved_path; + if(found == 0) { + std::string command_line(psinfo.pr_psargs); + LLDB_LOGF(log, "command line %s",command_line.c_str()); + if (!command_line.empty()) { + size_t space1 = command_line.find(' '); + executable_name = command_line.substr(0, space1); + LLDB_LOGF(log, "executable name %s",executable_name.c_str()); + } + } + + LLDB_LOGF(log, "executable name %s",executable_name.c_str()); + /*target.SetExecutableModule(target.GetOrCreateModule(lldb_private::FileSpec(resolved_path), + true),true);*/ + process_info.SetExecutableFile(lldb_private::FileSpec(executable_name), + true); + +/* snprintf(procinfo_path, sizeof(procinfo_path), "/proc/%d/object/a.out", pid); + ssize_t len = readlink(procinfo_path, exe_path, sizeof(exe_path) - 1); + exe_path[len] = '\0'; + int num_procs = getprocs64(&procs_info, sizeof(struct procsinfo64), NULL, 0, + &pid, + 1); + int result = getargs(pid, arg_buffer, sizeof(arg_buffer)); + std::vector args; + char *arg_start = arg_buffer; + while(*arg_start != '\0') { + args.emplace_back(arg_start); + arg_start += strlen(arg_start) + 1; + } + + LLDB_LOGF( + log, "1. DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s" + ", pid: %d, current_path: %s", + __FUNCTION__, m_process->GetID(), + args[0], pid, current_path.c_str()); + LLDB_LOGF( + log, "1. DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s" + "num_procs: %d, pid: %d", + __FUNCTION__, m_process->GetID(), + std::string(procs_info.pi_comm).c_str(), num_procs, pid); + if(num_procs <= 0) + perror("getprocs64 failed"); */ + + LLDB_LOGF( + log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s", + __FUNCTION__, m_process->GetID(), + process_info.GetExecutableFile().GetPath().c_str()); + + ModuleSpec module_spec(process_info.GetExecutableFile(), + process_info.GetArchitecture()); + if (module_sp && module_sp->MatchesModuleSpec(module_spec)) + return; + + const auto executable_search_paths(Target::GetDefaultExecutableSearchPaths()); + auto error = platform_sp->ResolveExecutable( + module_spec, module_sp, + !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr); + if (error.Fail()) { + StreamString stream; + module_spec.Dump(stream); + + LLDB_LOGF(log, + "DynamicLoaderPOSIXDYLD::%s - failed to resolve executable " + "with module spec \"%s\": %s", + __FUNCTION__, stream.GetData(), error.AsCString()); + return; + } + + target.SetExecutableModule(module_sp, eLoadDependentsNo); +} + void DynamicLoaderAIXDYLD::DidAttach() { Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); ModuleSP executable = GetTargetExecutable(); + ResolveExecutableModule(executable); if (!executable.get()) return; + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); // Try to fetch the load address of the file from the process, since there // could be randomization of the load address. diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h index ae4b7aca66dcc..0ffbe688e0069 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -24,7 +24,7 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { static void Initialize(); static void Terminate(); - static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; } + static llvm::StringRef GetPluginNameStatic() { return "aix-dyld"; } static llvm::StringRef GetPluginDescriptionStatic(); static DynamicLoader *CreateInstance(Process *process, bool force); @@ -46,6 +46,9 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { protected: lldb::addr_t GetLoadAddress(lldb::ModuleSP executable); + /// Loads Module from inferior process. + void ResolveExecutableModule(lldb::ModuleSP &module_sp); + private: std::map m_loaded_modules; }; >From 48b8b1b6532181acab0ee1710d5f4ab92903ae78 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 18 Nov 2024 02:56:31 -0600 Subject: [PATCH 14/47] Cleanup --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 65 +++++-------------- 1 file changed, 17 insertions(+), 48 deletions(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index acaa6a72edded..1a98bb9334043 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -156,81 +156,50 @@ void DynamicLoaderAIXDYLD::ResolveExecutableModule( return; } - char procinfo_path[64], exe_path[PATH_MAX], arg_buffer[8192]; - struct procsinfo64 procs_info; int32long64_t pid = m_process->GetID(); + char cwd[PATH_MAX], resolved_path[PATH_MAX]; + std::string executable_name; + bool path_resolved = false; + psinfo_t psinfo; + std::string proc_file = "/proc/" + std::to_string(pid) + "/psinfo"; std::string cwd_link = "/proc/" + std::to_string(pid) + "/cwd"; - psinfo_t psinfo; std::ifstream file(proc_file, std::ios::binary); if(!file.is_open()) - { - LLDB_LOGF(log, "Error psinfo "); - } + LLDB_LOGF(log, "Error: Unable to access process info "); + file.read(reinterpret_cast(&psinfo), sizeof(psinfo_t)); if(!file) - LLDB_LOGF(log, "Error psinfo: Failed to read "); + LLDB_LOGF(log, "Process info error: Failed to read "); std::string relative_path(psinfo.pr_fname); - LLDB_LOGF(log, "relative path %s",relative_path.c_str()); + LLDB_LOGF(log, "Relative path %s",relative_path.c_str()); - char cwd[PATH_MAX]; - char resolved_path[PATH_MAX]; - std::string executable_name; - bool found = 0; if(readlink(cwd_link.c_str(), cwd, sizeof(cwd)) != -1){ std::filesystem::path full_path = std::filesystem::path(cwd)/relative_path; if(realpath(full_path.c_str(), resolved_path)) { - LLDB_LOGF(log, " RESOLVED PATH: %s", resolved_path); - found = 1; + LLDB_LOGF(log, "Resolved Path using process info : %s", resolved_path); + path_resolved = true; } else - perror("realpath error");} + LLDB_LOGF(log, "Realpath error: Unable to resolve. "); + } executable_name = resolved_path; - if(found == 0) { + if(path_resolved == false) { std::string command_line(psinfo.pr_psargs); - LLDB_LOGF(log, "command line %s",command_line.c_str()); + LLDB_LOGF(log, "Command line: %s",command_line.c_str()); if (!command_line.empty()) { size_t space1 = command_line.find(' '); executable_name = command_line.substr(0, space1); - LLDB_LOGF(log, "executable name %s",executable_name.c_str()); + LLDB_LOGF(log, "Resolved path using command line arg %s",executable_name.c_str()); } } - LLDB_LOGF(log, "executable name %s",executable_name.c_str()); - /*target.SetExecutableModule(target.GetOrCreateModule(lldb_private::FileSpec(resolved_path), - true),true);*/ + LLDB_LOGF(log, "Executable Name %s",executable_name.c_str()); process_info.SetExecutableFile(lldb_private::FileSpec(executable_name), true); -/* snprintf(procinfo_path, sizeof(procinfo_path), "/proc/%d/object/a.out", pid); - ssize_t len = readlink(procinfo_path, exe_path, sizeof(exe_path) - 1); - exe_path[len] = '\0'; - int num_procs = getprocs64(&procs_info, sizeof(struct procsinfo64), NULL, 0, - &pid, - 1); - int result = getargs(pid, arg_buffer, sizeof(arg_buffer)); - std::vector args; - char *arg_start = arg_buffer; - while(*arg_start != '\0') { - args.emplace_back(arg_start); - arg_start += strlen(arg_start) + 1; - } - - LLDB_LOGF( - log, "1. DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s" - ", pid: %d, current_path: %s", - __FUNCTION__, m_process->GetID(), - args[0], pid, current_path.c_str()); - LLDB_LOGF( - log, "1. DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s" - "num_procs: %d, pid: %d", - __FUNCTION__, m_process->GetID(), - std::string(procs_info.pi_comm).c_str(), num_procs, pid); - if(num_procs <= 0) - perror("getprocs64 failed"); */ - LLDB_LOGF( log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s", __FUNCTION__, m_process->GetID(), >From d410734184a681b3e95949d3953142995682d7f6 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Tue, 19 Nov 2024 09:44:42 -0600 Subject: [PATCH 15/47] Patch in MainLoopPosix.cpp for runtime issue --- lldb/source/Host/posix/MainLoopPosix.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp index f68268f114075..4c617cdde67ba 100644 --- a/lldb/source/Host/posix/MainLoopPosix.cpp +++ b/lldb/source/Host/posix/MainLoopPosix.cpp @@ -149,7 +149,7 @@ Status MainLoopPosix::RunImpl::Poll() { int timeout; timeout = -1; - pthread_sigmask(SIG_SETMASK, &sigmask, &origmask); + pthread_sigmask(SIG_SETMASK, nullptr, &origmask); int ready = poll(read_fds.data(), read_fds.size(), timeout); pthread_sigmask(SIG_SETMASK, &origmask, nullptr); if (ready == -1 && errno != EINTR) >From 48f39dadbbdb4874fbd9b6350933dc67e8823339 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Thu, 5 Dec 2024 05:13:14 -0600 Subject: [PATCH 16/47] Patch for compilation failure in DomainSocket.cpp, AbstractSocket.cpp and AbstractSocket.h --- lldb/include/lldb/Host/aix/AbstractSocket.h | 2 +- lldb/source/Host/aix/AbstractSocket.cpp | 3 +-- lldb/source/Host/posix/DomainSocket.cpp | 4 ++++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lldb/include/lldb/Host/aix/AbstractSocket.h b/lldb/include/lldb/Host/aix/AbstractSocket.h index 78a567a6b9095..accfd01457a5e 100644 --- a/lldb/include/lldb/Host/aix/AbstractSocket.h +++ b/lldb/include/lldb/Host/aix/AbstractSocket.h @@ -14,7 +14,7 @@ namespace lldb_private { class AbstractSocket : public DomainSocket { public: - AbstractSocket(bool child_processes_inherit); + AbstractSocket(); protected: size_t GetNameOffset() const override; diff --git a/lldb/source/Host/aix/AbstractSocket.cpp b/lldb/source/Host/aix/AbstractSocket.cpp index bfb67d452f7ec..fddf78f54f46d 100644 --- a/lldb/source/Host/aix/AbstractSocket.cpp +++ b/lldb/source/Host/aix/AbstractSocket.cpp @@ -13,8 +13,7 @@ using namespace lldb; using namespace lldb_private; -AbstractSocket::AbstractSocket(bool child_processes_inherit) - : DomainSocket(ProtocolUnixAbstract, child_processes_inherit) {} +AbstractSocket::AbstractSocket() : DomainSocket(ProtocolUnixAbstract) {} size_t AbstractSocket::GetNameOffset() const { return 1; } diff --git a/lldb/source/Host/posix/DomainSocket.cpp b/lldb/source/Host/posix/DomainSocket.cpp index 9a0b385d998bf..6cbffb2d9c4bd 100644 --- a/lldb/source/Host/posix/DomainSocket.cpp +++ b/lldb/source/Host/posix/DomainSocket.cpp @@ -17,6 +17,10 @@ #include #include +#if defined(_AIX) +#include +#endif + using namespace lldb; using namespace lldb_private; >From 97531f7bf6e385f0f51d860c6eea17aeb32f6594 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Thu, 19 Dec 2024 06:38:36 -0600 Subject: [PATCH 17/47] Patch for merge conflict in ObjectFileXCOFF.cpp & ObjectFileXCOFF.h --- .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 253 +++++++++++++++++- 1 file changed, 252 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index 395a126a01fce..a4d9ea295b4c3 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -188,7 +188,258 @@ bool ObjectFileXCOFF::ParseHeader() { if (module_sp) { std::lock_guard guard(module_sp->GetMutex()); m_sect_headers.clear(); - lldb::offs + lldb::offset_t offset = 0; + + if (ParseXCOFFHeader(m_data, &offset, m_xcoff_header)) { + m_data.SetAddressByteSize(GetAddressByteSize()); + if (m_xcoff_header.auxhdrsize > 0) + ParseXCOFFOptionalHeader(m_data, &offset); + ParseSectionHeaders(offset); + } + return true; + } + + return false; +} + +bool ObjectFileXCOFF::ParseXCOFFHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + xcoff_header_t &xcoff_header) { + //FIXME: data.ValidOffsetForDataOfSize + xcoff_header.magic = data.GetU16(offset_ptr); + xcoff_header.nsects = data.GetU16(offset_ptr); + xcoff_header.modtime = data.GetU32(offset_ptr); + xcoff_header.symoff = data.GetU64(offset_ptr); + xcoff_header.auxhdrsize = data.GetU16(offset_ptr); + xcoff_header.flags = data.GetU16(offset_ptr); + xcoff_header.nsyms = data.GetU32(offset_ptr); + return true; +} + +bool ObjectFileXCOFF::ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr) { + lldb::offset_t init_offset = *offset_ptr; + //FIXME: data.ValidOffsetForDataOfSize + m_xcoff_aux_header.AuxMagic = data.GetU16(offset_ptr); + m_xcoff_aux_header.Version = data.GetU16(offset_ptr); + m_xcoff_aux_header.ReservedForDebugger = data.GetU32(offset_ptr); + m_xcoff_aux_header.TextStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.DataStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.TOCAnchorAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfEntryPoint = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTOC = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfLoader = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.ModuleType = data.GetU16(offset_ptr); + m_xcoff_aux_header.CpuFlag = data.GetU8(offset_ptr); + m_xcoff_aux_header.CpuType = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.DataPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.StackPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.FlagAndTDataAlignment = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.InitDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.BssDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.EntryPointAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxStackSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfTData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.XCOFF64Flag = data.GetU16(offset_ptr); + lldb::offset_t last_offset = *offset_ptr; + if ((last_offset - init_offset) < m_xcoff_header.auxhdrsize) + *offset_ptr += (m_xcoff_header.auxhdrsize - (last_offset - init_offset)); + return true; +} + +bool ObjectFileXCOFF::ParseSectionHeaders( + uint32_t section_header_data_offset) { + const uint32_t nsects = m_xcoff_header.nsects; + m_sect_headers.clear(); + + if (nsects > 0) { + const size_t section_header_byte_size = nsects * m_binary->getSectionHeaderSize(); + lldb_private::DataExtractor section_header_data = + ReadImageData(section_header_data_offset, section_header_byte_size); + + lldb::offset_t offset = 0; + //FIXME: section_header_data.ValidOffsetForDataOfSize + m_sect_headers.resize(nsects); + + for (uint32_t idx = 0; idx < nsects; ++idx) { + const void *name_data = section_header_data.GetData(&offset, 8); + if (name_data) { + memcpy(m_sect_headers[idx].name, name_data, 8); + m_sect_headers[idx].phyaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].vmaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].size = section_header_data.GetU64(&offset); + m_sect_headers[idx].offset = section_header_data.GetU64(&offset); + m_sect_headers[idx].reloff = section_header_data.GetU64(&offset); + m_sect_headers[idx].lineoff = section_header_data.GetU64(&offset); + m_sect_headers[idx].nreloc = section_header_data.GetU32(&offset); + m_sect_headers[idx].nline = section_header_data.GetU32(&offset); + m_sect_headers[idx].flags = section_header_data.GetU32(&offset); + offset += 4; + } else { + offset += (m_binary->getSectionHeaderSize() - 8); + } + } + } + + return !m_sect_headers.empty(); +} + +lldb_private::DataExtractor ObjectFileXCOFF::ReadImageData(uint32_t offset, size_t size) { + if (!size) + return {}; + + if (m_data.ValidOffsetForDataOfSize(offset, size)) + return lldb_private::DataExtractor(m_data, offset, size); + + assert(0); + ProcessSP process_sp(m_process_wp.lock()); + lldb_private::DataExtractor data; + if (process_sp) { + auto data_up = std::make_unique(size, 0); + Status readmem_error; + size_t bytes_read = + process_sp->ReadMemory(offset, data_up->GetBytes(), + data_up->GetByteSize(), readmem_error); + if (bytes_read == size) { + DataBufferSP buffer_sp(data_up.release()); + data.SetData(buffer_sp, 0, buffer_sp->GetByteSize()); + } + } + return data; +} + +bool ObjectFileXCOFF::SetLoadAddress(Target &target, lldb::addr_t value, + bool value_is_offset) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (section_sp && !section_sp->IsThreadSpecific()) { + bool use_offset = false; + if (strcmp(section_sp->GetName().AsCString(), ".text") == 0 || + strcmp(section_sp->GetName().AsCString(), ".data") == 0 || + strcmp(section_sp->GetName().AsCString(), ".bss") == 0) + use_offset = true; + + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, (use_offset ? + (section_sp->GetFileOffset() + value) : (section_sp->GetFileAddress() + value)))) + ++num_loaded_sections; + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (type_id == 1 && section_sp && strcmp(section_sp->GetName().AsCString(), ".text") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileOffset() + value)) + ++num_loaded_sections; + } + } else if (type_id == 2 && section_sp && strcmp(section_sp->GetName().AsCString(), ".data") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileAddress() + value)) + ++num_loaded_sections; + } + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +ByteOrder ObjectFileXCOFF::GetByteOrder() const { + return eByteOrderBig; +} + +bool ObjectFileXCOFF::IsExecutable() const { + return true; +} + +uint32_t ObjectFileXCOFF::GetAddressByteSize() const { + if (m_xcoff_header.magic == XCOFF::XCOFF64) + return 8; + else if (m_xcoff_header.magic == XCOFF::XCOFF32) + return 4; + return 4; +} + +AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) { + return AddressClass::eUnknown; +} + +lldb::SymbolType ObjectFileXCOFF::MapSymbolType(llvm::object::SymbolRef::Type sym_type) { + if (sym_type == llvm::object::SymbolRef::ST_Function) + return lldb::eSymbolTypeCode; + else if (sym_type == llvm::object::SymbolRef::ST_Data) + return lldb::eSymbolTypeData; + return lldb::eSymbolTypeInvalid; +} + +void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) { + SectionList *sect_list = GetSectionList(); + const uint32_t num_syms = m_xcoff_header.nsyms; + uint32_t sidx = 0; + if (num_syms > 0 && m_xcoff_header.symoff > 0) { + const uint32_t symbol_size = XCOFF::SymbolTableEntrySize; + const size_t symbol_data_size = num_syms * symbol_size; + lldb_private::DataExtractor symtab_data = + ReadImageData(m_xcoff_header.symoff, symbol_data_size); + + lldb::offset_t offset = 0; + std::string symbol_name; + Symbol *symbols = lldb_symtab.Resize(num_syms); + llvm::object::symbol_iterator SI = m_binary->symbol_begin(); + for (uint32_t i = 0; i < num_syms; ++i, ++SI) { + xcoff_symbol_t symbol; + const uint32_t symbol_offset = offset; + symbol.value = symtab_data.GetU64(&offset); + symbol.offset = symtab_data.GetU32(&offset); + Expected symbol_name_or_err = m_binary->getStringTableEntry(symbol.offset); + if (!symbol_name_or_err) { + consumeError(symbol_name_or_err.takeError()); + return; + } + StringRef symbol_name_str = symbol_name_or_err.get(); + symbol_name.assign(symbol_name_str.data()); symbol.sect = symtab_data.GetU16(&offset); symbol.type = symtab_data.GetU16(&offset); symbol.storage = symtab_data.GetU8(&offset); >From 71d2fcff8975831e7f0a657481220749b0a473dc Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Tue, 24 Dec 2024 02:05:35 -0600 Subject: [PATCH 18/47] Added upcoming clang-format and other merge changes --- .../posix/ConnectionFileDescriptorPosix.cpp | 9 ++-- lldb/source/Host/posix/DomainSocket.cpp | 5 ++- lldb/source/Host/posix/FileSystemPosix.cpp | 2 +- lldb/source/Host/posix/MainLoopPosix.cpp | 43 ++++++++----------- .../Host/posix/ProcessLauncherPosixFork.cpp | 2 +- lldb/source/Plugins/Language/ObjC/Cocoa.cpp | 17 +++----- .../BSD-Archive/ObjectContainerBSDArchive.cpp | 29 +++++++------ lldb/source/Utility/ArchSpec.cpp | 1 - 8 files changed, 49 insertions(+), 59 deletions(-) diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index 32d034e60d26c..e3d1300cf76ed 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -119,8 +119,7 @@ bool ConnectionFileDescriptor::IsConnected() const { ConnectionStatus ConnectionFileDescriptor::Connect(llvm::StringRef path, Status *error_ptr) { - return Connect( - path, [](llvm::StringRef) {}, error_ptr); + return Connect(path, [](llvm::StringRef) {}, error_ptr); } ConnectionStatus @@ -716,8 +715,7 @@ ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, ConnectionStatus ConnectionFileDescriptor::ConnectFile( llvm::StringRef s, socket_id_callback_type socket_id_callback, Status *error_ptr) { -#if !defined(_AIX) -#if LLDB_ENABLE_POSIX +#if LLDB_ENABLE_POSIX && !defined(_AIX) std::string addr_str = s.str(); // file:///PATH int fd = FileSystem::Instance().Open(addr_str.c_str(), O_RDWR); @@ -748,8 +746,7 @@ ConnectionStatus ConnectionFileDescriptor::ConnectFile( m_io_sp = std::make_shared(fd, File::eOpenOptionReadWrite, true); return eConnectionStatusSuccess; -#endif // LLDB_ENABLE_POSIX -#endif +#endif // LLDB_ENABLE_POSIX && !defined(_AIX) llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX"); } diff --git a/lldb/source/Host/posix/DomainSocket.cpp b/lldb/source/Host/posix/DomainSocket.cpp index 6cbffb2d9c4bd..28db5964a5a8a 100644 --- a/lldb/source/Host/posix/DomainSocket.cpp +++ b/lldb/source/Host/posix/DomainSocket.cpp @@ -89,8 +89,9 @@ Status DomainSocket::Connect(llvm::StringRef name) { m_socket = CreateSocket(kDomain, kType, 0, error); if (error.Fail()) return error; - if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(), - (struct sockaddr *)&saddr_un, saddr_un_len) < 0) + if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(), + (struct sockaddr *)&saddr_un, + saddr_un_len) < 0) SetLastError(error); return error; diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index 21da5612ff6b8..1a84f550662d7 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,7 +11,7 @@ // C includes #include #include -#if !defined(_AIX) +#ifndef _AIX #include #endif #include diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp index 125b954023dc0..e4ff928a58962 100644 --- a/lldb/source/Host/posix/MainLoopPosix.cpp +++ b/lldb/source/Host/posix/MainLoopPosix.cpp @@ -99,6 +99,7 @@ class MainLoopPosix::RunImpl { ~RunImpl() = default; Status Poll(); + int StartPoll(std::optional point); void ProcessReadEvents(); private: @@ -159,6 +160,22 @@ MainLoopPosix::RunImpl::RunImpl(MainLoopPosix &loop) : loop(loop) { read_fds.reserve(loop.m_read_fds.size()); } +int MainLoopPosix::RunImpl::StartPoll( + std::optional point) { +#if HAVE_PPOLL + return ppoll(read_fds.data(), read_fds.size(), ToTimeSpec(point), + /*sigmask=*/nullptr); +#else + using namespace std::chrono; + int timeout = -1; + if (point) { + nanoseconds dur = std::max(*point - steady_clock::now(), nanoseconds(0)); + timeout = ceil(dur).count(); + } + return poll(read_fds.data(), read_fds.size(), timeout); +#endif +} + Status MainLoopPosix::RunImpl::Poll() { read_fds.clear(); @@ -169,24 +186,10 @@ Status MainLoopPosix::RunImpl::Poll() { pfd.revents = 0; read_fds.push_back(pfd); } + int ready = StartPoll(loop.GetNextWakeupTime()); -#if defined(_AIX) - sigset_t origmask; - int timeout; - - timeout = -1; - pthread_sigmask(SIG_SETMASK, nullptr, &origmask); - int ready = poll(read_fds.data(), read_fds.size(), timeout); - pthread_sigmask(SIG_SETMASK, &origmask, nullptr); if (ready == -1 && errno != EINTR) return Status(errno, eErrorTypePOSIX); -#else - if (ppoll(read_fds.data(), read_fds.size(), - ToTimeSpec(loop.GetNextWakeupTime()), - /*sigmask=*/nullptr) == -1 && - errno != EINTR) - return Status(errno, eErrorTypePOSIX); -#endif return Status(); } @@ -291,16 +294,6 @@ MainLoopPosix::RegisterSignal(int signo, const Callback &callback, UNUSED_IF_ASSERT_DISABLED(ret); assert(ret == 0 && "sigaction failed"); -#if HAVE_SYS_EVENT_H - struct kevent ev; - EV_SET(&ev, signo, EVFILT_SIGNAL, EV_ADD, 0, 0, 0); - ret = kevent(m_kqueue, &ev, 1, nullptr, 0, nullptr); - assert(ret == 0); -#endif - - // If we're using kqueue, the signal needs to be unblocked in order to - // receive it. If using pselect/ppoll, we need to block it, and later unblock - // it as a part of the system call. ret = pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, &old_set); assert(ret == 0 && "pthread_sigmask failed"); info.was_blocked = sigismember(&old_set, signo); diff --git a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp index 52fc58aa21bf4..7b8b42a4b7fe0 100644 --- a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp +++ b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp @@ -197,7 +197,7 @@ struct ForkLaunchInfo { #else if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1) #endif - ExitWithError(error_fd, "ptrace"); + ExitWithError(error_fd, "ptrace"); } // Execute. We should never return... diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index 1d841a032aa6e..1d79edbede5d6 100644 --- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -31,7 +31,6 @@ #include "llvm/ADT/APInt.h" #include "llvm/ADT/bit.h" - using namespace lldb; using namespace lldb_private; using namespace lldb_private::formatters; @@ -267,21 +266,21 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider( if (class_name == "NSIndexSet" || class_name == "NSMutableIndexSet") { // Foundation version 2000 added a bitmask if the index set fit in 64 bits // and a Tagged Pointer version if the bitmask is small enough to fit in - // the tagged pointer payload. + // the tagged pointer payload. // It also changed the layout (but not the size) of the set descriptor. // First check whether this is a tagged pointer. The bitmask will be in // the payload of the tagged pointer. uint64_t payload; - if (runtime->GetFoundationVersion() >= 2000 - && descriptor->GetTaggedPointerInfo(nullptr, nullptr, &payload)) { + if (runtime->GetFoundationVersion() >= 2000 && + descriptor->GetTaggedPointerInfo(nullptr, nullptr, &payload)) { count = llvm::popcount(payload); break; } // The first 32 bits describe the index set in all cases: Status error; uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory( - valobj_addr + ptr_size, 4, 0, error); + valobj_addr + ptr_size, 4, 0, error); if (error.Fail()) return false; // Now check if the index is held in a bitmask in the object: @@ -292,7 +291,7 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider( if ((mode & 2) == 2) { // The bitfield is a 64 bit uint at the beginning of the data var. uint64_t bitfield = process_sp->ReadUnsignedIntegerFromMemory( - valobj_addr + 2 * ptr_size, 8, 0, error); + valobj_addr + 2 * ptr_size, 8, 0, error); if (error.Fail()) return false; count = llvm::popcount(bitfield); @@ -309,7 +308,7 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider( count = 0; break; } - + if ((mode & 2) == 2) mode = 1; // this means the set only has one range else @@ -1227,8 +1226,7 @@ bool lldb_private::formatters::ObjCSELSummaryProvider( time_t lldb_private::formatters::GetOSXEpoch() { static time_t epoch = 0; if (!epoch) { -#if !defined(_AIX) -#ifndef _WIN32 +#if !defined(_WIN32) && !defined(_AIX) tzset(); tm tm_epoch; tm_epoch.tm_sec = 0; @@ -1241,7 +1239,6 @@ time_t lldb_private::formatters::GetOSXEpoch() { tm_epoch.tm_gmtoff = 0; tm_epoch.tm_zone = nullptr; epoch = timegm(&tm_epoch); -#endif #endif } return epoch; diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 4f747ab20c9ef..b202898ff438a 100644 --- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -81,10 +81,10 @@ size_t ObjectContainerBSDArchive::Archive::ParseObjects() { std::unique_ptr mem_buffer = llvm::MemoryBuffer::getMemBuffer( - llvm::StringRef((const char *)data.GetDataStart(), - data.GetByteSize()), - llvm::StringRef(), - /*RequiresNullTerminator=*/false); + llvm::StringRef((const char *)data.GetDataStart(), + data.GetByteSize()), + llvm::StringRef(), + /*RequiresNullTerminator=*/false); auto exp_ar = llvm::object::Archive::create(mem_buffer->getMemBufferRef()); if (!exp_ar) { @@ -95,7 +95,7 @@ size_t ObjectContainerBSDArchive::Archive::ParseObjects() { llvm::Error iter_err = llvm::Error::success(); Object obj; - for (const auto &child: llvm_archive->children(iter_err)) { + for (const auto &child : llvm_archive->children(iter_err)) { obj.Clear(); auto exp_name = child.getName(); if (exp_name) { @@ -111,7 +111,9 @@ size_t ObjectContainerBSDArchive::Archive::ParseObjects() { obj.modification_time = std::chrono::duration_cast( std::chrono::time_point_cast( - exp_mtime.get()).time_since_epoch()).count(); + exp_mtime.get()) + .time_since_epoch()) + .count(); } else { LLDB_LOG_ERROR(l, exp_mtime.takeError(), "failed to get archive object time: {0}"); @@ -331,21 +333,21 @@ ObjectContainer *ObjectContainerBSDArchive::CreateInstance( ArchiveType ObjectContainerBSDArchive::MagicBytesMatch(const DataExtractor &data) { uint32_t offset = 0; - const char *armag = (const char *)data.PeekData(offset, - sizeof(ar_hdr) + SARMAG); + const char *armag = + (const char *)data.PeekData(offset, sizeof(ar_hdr) + SARMAG); if (armag == nullptr) return ArchiveType::Invalid; ArchiveType result = ArchiveType::Invalid; if (strncmp(armag, ArchiveMagic, SARMAG) == 0) - result = ArchiveType::Archive; + result = ArchiveType::Archive; else if (strncmp(armag, ThinArchiveMagic, SARMAG) == 0) - result = ArchiveType::ThinArchive; + result = ArchiveType::ThinArchive; else - return ArchiveType::Invalid; + return ArchiveType::Invalid; armag += offsetof(struct ar_hdr, ar_fmag) + SARMAG; if (strncmp(armag, ARFMAG, 2) == 0) - return result; + return result; return ArchiveType::Invalid; } @@ -443,7 +445,8 @@ size_t ObjectContainerBSDArchive::GetModuleSpecifications( return 0; const size_t initial_count = specs.GetSize(); - llvm::sys::TimePoint<> file_mod_time = FileSystem::Instance().GetModificationTime(file); + llvm::sys::TimePoint<> file_mod_time = + FileSystem::Instance().GetModificationTime(file); Archive::shared_ptr archive_sp( Archive::FindCachedArchive(file, ArchSpec(), file_mod_time, file_offset)); bool set_archive_arch = false; diff --git a/lldb/source/Utility/ArchSpec.cpp b/lldb/source/Utility/ArchSpec.cpp index ac91183a271cc..85bb85044ec15 100644 --- a/lldb/source/Utility/ArchSpec.cpp +++ b/lldb/source/Utility/ArchSpec.cpp @@ -14,7 +14,6 @@ #include "lldb/lldb-defines.h" #include "llvm/ADT/STLExtras.h" #include "llvm/BinaryFormat/COFF.h" -#include "llvm/BinaryFormat/XCOFF.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/BinaryFormat/XCOFF.h" >From 8fcf69ed77148f8b339b87f75ed97e5ce719b4ba Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Fri, 27 Dec 2024 06:50:27 -0600 Subject: [PATCH 19/47] Some Updates --- lldb/include/lldb/Host/aix/HostInfoAIX.h | 11 +-- lldb/source/Host/aix/HostInfoAIX.cpp | 65 +------------- .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 87 +++++++++---------- .../ObjectFile/XCOFF/ObjectFileXCOFF.h | 11 ++- 4 files changed, 50 insertions(+), 124 deletions(-) diff --git a/lldb/include/lldb/Host/aix/HostInfoAIX.h b/lldb/include/lldb/Host/aix/HostInfoAIX.h index ced4cf34d38a8..ba727e1d5f171 100644 --- a/lldb/include/lldb/Host/aix/HostInfoAIX.h +++ b/lldb/include/lldb/Host/aix/HostInfoAIX.h @@ -6,16 +6,14 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_Host_aix_HostInfoAIX_h_ -#define lldb_Host_aix_HostInfoAIX_h_ +#ifndef LLDB_HOST_AIX_HOSTINFOAIX_H_ +#define LLDB_HOST_AIX_HOSTINFOAIX_H_ #include "lldb/Host/posix/HostInfoPosix.h" #include "lldb/Utility/FileSpec.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/VersionTuple.h" -#include - namespace lldb_private { class HostInfoAIX : public HostInfoPosix { @@ -25,15 +23,10 @@ class HostInfoAIX : public HostInfoPosix { static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr); static void Terminate(); - static llvm::VersionTuple GetOSVersion(); - static std::optional GetOSBuildString(); static llvm::StringRef GetDistributionId(); static FileSpec GetProgramFileSpec(); protected: - static bool ComputeSupportExeDirectory(FileSpec &file_spec); - static bool ComputeSystemPluginsDirectory(FileSpec &file_spec); - static bool ComputeUserPluginsDirectory(FileSpec &file_spec); static void ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64); }; diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp index 8bda09e01741b..ef07b07c8cab2 100644 --- a/lldb/source/Host/aix/HostInfoAIX.cpp +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -29,8 +29,6 @@ namespace { struct HostInfoAIXFields { llvm::once_flag m_distribution_once_flag; std::string m_distribution_id; - llvm::once_flag m_os_version_once_flag; - llvm::VersionTuple m_os_version; }; } // namespace @@ -49,33 +47,6 @@ void HostInfoAIX::Terminate() { HostInfoBase::Terminate(); } -llvm::VersionTuple HostInfoAIX::GetOSVersion() { - assert(g_fields && "Missing call to Initialize?"); - llvm::call_once(g_fields->m_os_version_once_flag, []() { - struct utsname un; - if (uname(&un) != 0) - return; - - llvm::StringRef release = un.release; - // The kernel release string can include a lot of stuff (e.g. - // 4.9.0-6-amd64). We're only interested in the numbered prefix. - release = release.substr(0, release.find_first_not_of("0123456789.")); - g_fields->m_os_version.tryParse(release); - }); - - return g_fields->m_os_version; -} - -std::optional HostInfoAIX::GetOSBuildString() { - struct utsname un; - ::memset(&un, 0, sizeof(utsname)); - - if (uname(&un) < 0) - return std::nullopt; - - return std::string(un.release); -} - llvm::StringRef HostInfoAIX::GetDistributionId() { assert(g_fields && "Missing call to Initialize?"); // Try to run 'lbs_release -i', and use that response for the distribution @@ -122,8 +93,7 @@ llvm::StringRef HostInfoAIX::GetDistributionId() { if (strstr(distribution_id, distributor_id_key)) { // strip newlines std::string id_string(distribution_id + strlen(distributor_id_key)); - id_string.erase(std::remove(id_string.begin(), id_string.end(), '\n'), - id_string.end()); + llvm::erase(id_string, '\n'); // lower case it and convert whitespace to underscores std::transform( @@ -167,42 +137,11 @@ FileSpec HostInfoAIX::GetProgramFileSpec() { return g_program_filespec; } -bool HostInfoAIX::ComputeSupportExeDirectory(FileSpec &file_spec) { - if (HostInfoPosix::ComputeSupportExeDirectory(file_spec) && - file_spec.IsAbsolute() && FileSystem::Instance().Exists(file_spec)) - return true; - file_spec.SetDirectory(GetProgramFileSpec().GetDirectory()); - return !file_spec.GetDirectory().IsEmpty(); -} - -bool HostInfoAIX::ComputeSystemPluginsDirectory(FileSpec &file_spec) { - FileSpec temp_file("/usr/" LLDB_INSTALL_LIBDIR_BASENAME "/lldb/plugins"); - FileSystem::Instance().Resolve(temp_file); - file_spec.SetDirectory(temp_file.GetPath()); - return true; -} - -bool HostInfoAIX::ComputeUserPluginsDirectory(FileSpec &file_spec) { - // XDG Base Directory Specification - // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html If - // XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb. - const char *xdg_data_home = getenv("XDG_DATA_HOME"); - if (xdg_data_home && xdg_data_home[0]) { - std::string user_plugin_dir(xdg_data_home); - user_plugin_dir += "/lldb"; - file_spec.SetDirectory(user_plugin_dir.c_str()); - } else - file_spec.SetDirectory("~/.local/share/lldb"); - return true; -} - void HostInfoAIX::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64) { HostInfoPosix::ComputeHostArchitectureSupport(arch_32, arch_64); - const char *distribution_id = GetDistributionId().data(); - - // On Linux, "unknown" in the vendor slot isn't what we want for the default + // "unknown" in the vendor slot isn't what we want for the default // triple. It's probably an artifact of config.guess. if (arch_32.IsValid()) { if (arch_32.GetTriple().getVendor() == llvm::Triple::UnknownVendor) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index a4d9ea295b4c3..afd8027bab06c 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -1,4 +1,5 @@ -//===-- ObjectFileXCOFF.cpp -------------------------------------------------===// +//===-- ObjectFileXCOFF.cpp +//-------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,13 +8,6 @@ //===----------------------------------------------------------------------===// #include "ObjectFileXCOFF.h" - -#include -#include -#include -#include - -#include "lldb/Utility/FileSpecList.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" @@ -28,6 +22,7 @@ #include "lldb/Target/Target.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/FileSpecList.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RangeMap.h" @@ -38,12 +33,16 @@ #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/Object/XCOFFObjectFile.h" #include "llvm/Object/Decompressor.h" #include "llvm/Support/CRC.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Object/XCOFFObjectFile.h" +#include +#include +#include +#include using namespace llvm; using namespace lldb; @@ -69,21 +68,19 @@ void ObjectFileXCOFF::Terminate() { bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; ObjectFile *ObjectFileXCOFF::CreateInstance(const lldb::ModuleSP &module_sp, - DataBufferSP data_sp, - lldb::offset_t data_offset, - const lldb_private::FileSpec *file, - lldb::offset_t file_offset, - lldb::offset_t length) { + DataBufferSP data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t file_offset, + lldb::offset_t length) { if (!data_sp) { data_sp = MapFileData(*file, length, file_offset); if (!data_sp) return nullptr; data_offset = 0; } - if (!ObjectFileXCOFF::MagicBytesMatch(data_sp, data_offset, length)) return nullptr; - // Update the data to contain the entire file if it doesn't already if (data_sp->GetByteSize() < length) { data_sp = MapFileData(*file, length, file_offset); @@ -114,15 +111,15 @@ bool ObjectFileXCOFF::CreateBinary() { Log *log = GetLog(LLDBLog::Object); - auto binary = llvm::object::XCOFFObjectFile::createObjectFile(llvm::MemoryBufferRef( - toStringRef(m_data.GetData()), m_file.GetFilename().GetStringRef()), - file_magic::xcoff_object_64); + auto binary = llvm::object::ObjectFile::createObjectFile( + llvm::MemoryBufferRef(toStringRef(m_data.GetData()), + m_file.GetFilename().GetStringRef()), + file_magic::xcoff_object_64); if (!binary) { LLDB_LOG_ERROR(log, binary.takeError(), "Failed to create binary for file ({1}): {0}", m_file); return false; } - // Make sure we only handle COFF format. m_binary = llvm::unique_dyn_cast(std::move(*binary)); @@ -132,6 +129,7 @@ bool ObjectFileXCOFF::CreateBinary() { LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}", this, GetModule().get(), GetModule()->GetSpecificationDescription(), m_file.GetPath(), m_binary.get()); + return true; } @@ -148,9 +146,12 @@ size_t ObjectFileXCOFF::GetModuleSpecifications( const size_t initial_count = specs.GetSize(); if (ObjectFileXCOFF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) { - ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + ArchSpec arch_spec = + ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); ModuleSpec spec(file, arch_spec); - spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX); + spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, + LLDB_INVALID_CPUTYPE, + llvm::Triple::AIX); specs.Append(spec); } return specs.GetSize() - initial_count; @@ -158,11 +159,9 @@ size_t ObjectFileXCOFF::GetModuleSpecifications( static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) { switch (magic) { - /* TODO: 32bit not supported yet - case XCOFF::XCOFF32: - return sizeof(struct llvm::object::XCOFFFileHeader32); - */ - + // TODO: 32bit not supported. + // case XCOFF::XCOFF32: + // return sizeof(struct llvm::object::XCOFFFileHeader32); case XCOFF::XCOFF64: return sizeof(struct llvm::object::XCOFFFileHeader64); break; @@ -174,10 +173,12 @@ static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) { } bool ObjectFileXCOFF::MagicBytesMatch(DataBufferSP &data_sp, - lldb::addr_t data_offset, - lldb::addr_t data_length) { - lldb_private::DataExtractor data; + lldb::addr_t data_offset, + lldb::addr_t data_length) { + lldb_private::DataExtractor data; data.SetData(data_sp, data_offset, data_length); + // Need to set this as XCOFF is only compatible with Big Endian + data.SetByteOrder(eByteOrderBig); lldb::offset_t offset = 0; uint16_t magic = data.GetU16(&offset); return XCOFFHeaderSizeFromMagic(magic) != 0; @@ -386,13 +387,10 @@ bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, return changed; } -ByteOrder ObjectFileXCOFF::GetByteOrder() const { - return eByteOrderBig; -} -bool ObjectFileXCOFF::IsExecutable() const { - return true; -} +ByteOrder ObjectFileXCOFF::GetByteOrder() const { return eByteOrderBig; } + +bool ObjectFileXCOFF::IsExecutable() const { return true; } uint32_t ObjectFileXCOFF::GetAddressByteSize() const { if (m_xcoff_header.magic == XCOFF::XCOFF64) @@ -592,13 +590,12 @@ void ObjectFileXCOFF::Dump(Stream *s) { } ArchSpec ObjectFileXCOFF::GetArchitecture() { - ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + ArchSpec arch_spec = + ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); return arch_spec; } -UUID ObjectFileXCOFF::GetUUID() { - return UUID(); -} +UUID ObjectFileXCOFF::GetUUID() { return UUID(); } std::optional ObjectFileXCOFF::GetDebugLink() { return std::nullopt; @@ -724,16 +721,14 @@ lldb_private::Address ObjectFileXCOFF::GetBaseAddress() { } ObjectFile::Type ObjectFileXCOFF::CalculateType() { - if (m_xcoff_header.flags & XCOFF::F_EXEC) + if (m_binary->fileHeader64()->Flags & XCOFF::F_EXEC) return eTypeExecutable; - else if (m_xcoff_header.flags & XCOFF::F_SHROBJ) + else if (m_binary->fileHeader64()->Flags & XCOFF::F_SHROBJ) return eTypeSharedLibrary; return eTypeUnknown; } -ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { - return eStrataUnknown; -} +ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { return eStrataUnknown; } llvm::StringRef ObjectFileXCOFF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const { @@ -752,7 +747,7 @@ ObjectFileXCOFF::GetLoadableData(Target &target) { lldb::WritableDataBufferSP ObjectFileXCOFF::MapFileDataWritable(const FileSpec &file, uint64_t Size, - uint64_t Offset) { + uint64_t Offset) { return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size, Offset); } diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h index 5a12d16886489..f827fca3932f4 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h @@ -1,4 +1,5 @@ -//===-- ObjectFileXCOFF.h --------------------------------------- -*- C++ -*-===// +//===-- ObjectFileXCOFF.h --------------------------------------- -*- C++ +//-*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -9,16 +10,14 @@ #ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H #define LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H -#include - -#include - #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/UUID.h" #include "lldb/lldb-private.h" #include "llvm/Object/XCOFFObjectFile.h" +#include +#include /// \class ObjectFileXCOFF /// Generic XCOFF object file reader. @@ -240,4 +239,4 @@ class ObjectFileXCOFF : public lldb_private::ObjectFile { std::map> m_deps_base_members; }; -#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILE_H >From f8b05dfc9fc75177a63dfa2d6df4a9af143b09b8 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 5 Jan 2025 05:01:47 -0600 Subject: [PATCH 20/47] HostInfoAIX Cleanup --- lldb/include/lldb/Host/aix/HostInfoAIX.h | 4 - lldb/source/Host/aix/HostInfoAIX.cpp | 108 ----------------------- 2 files changed, 112 deletions(-) diff --git a/lldb/include/lldb/Host/aix/HostInfoAIX.h b/lldb/include/lldb/Host/aix/HostInfoAIX.h index ba727e1d5f171..5a52c42fa6199 100644 --- a/lldb/include/lldb/Host/aix/HostInfoAIX.h +++ b/lldb/include/lldb/Host/aix/HostInfoAIX.h @@ -23,12 +23,8 @@ class HostInfoAIX : public HostInfoPosix { static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr); static void Terminate(); - static llvm::StringRef GetDistributionId(); static FileSpec GetProgramFileSpec(); -protected: - static void ComputeHostArchitectureSupport(ArchSpec &arch_32, - ArchSpec &arch_64); }; } diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp index ef07b07c8cab2..2996fcb55f811 100644 --- a/lldb/source/Host/aix/HostInfoAIX.cpp +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -11,117 +11,25 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" - #include "llvm/Support/Threading.h" - #include #include #include #include #include - #include #include using namespace lldb_private; -namespace { -struct HostInfoAIXFields { - llvm::once_flag m_distribution_once_flag; - std::string m_distribution_id; -}; -} // namespace - -static HostInfoAIXFields *g_fields = nullptr; - void HostInfoAIX::Initialize(SharedLibraryDirectoryHelper *helper) { HostInfoPosix::Initialize(helper); - - g_fields = new HostInfoAIXFields(); } void HostInfoAIX::Terminate() { - assert(g_fields && "Missing call to Initialize?"); - delete g_fields; - g_fields = nullptr; HostInfoBase::Terminate(); } -llvm::StringRef HostInfoAIX::GetDistributionId() { - assert(g_fields && "Missing call to Initialize?"); - // Try to run 'lbs_release -i', and use that response for the distribution - // id. - llvm::call_once(g_fields->m_distribution_once_flag, []() { - Log *log = GetLog(LLDBLog::Host); - LLDB_LOGF(log, "attempting to determine AIX distribution..."); - - // check if the lsb_release command exists at one of the following paths - const char *const exe_paths[] = {"/bin/lsb_release", - "/usr/bin/lsb_release"}; - - for (size_t exe_index = 0; - exe_index < sizeof(exe_paths) / sizeof(exe_paths[0]); ++exe_index) { - const char *const get_distribution_info_exe = exe_paths[exe_index]; - if (access(get_distribution_info_exe, F_OK)) { - // this exe doesn't exist, move on to next exe - LLDB_LOGF(log, "executable doesn't exist: %s", - get_distribution_info_exe); - continue; - } - - // execute the distribution-retrieval command, read output - std::string get_distribution_id_command(get_distribution_info_exe); - get_distribution_id_command += " -i"; - - FILE *file = popen(get_distribution_id_command.c_str(), "r"); - if (!file) { - LLDB_LOGF(log, - "failed to run command: \"%s\", cannot retrieve " - "platform information", - get_distribution_id_command.c_str()); - break; - } - - // retrieve the distribution id string. - char distribution_id[256] = {'\0'}; - if (fgets(distribution_id, sizeof(distribution_id) - 1, file) != - nullptr) { - LLDB_LOGF(log, "distribution id command returned \"%s\"", - distribution_id); - - const char *const distributor_id_key = "Distributor ID:\t"; - if (strstr(distribution_id, distributor_id_key)) { - // strip newlines - std::string id_string(distribution_id + strlen(distributor_id_key)); - llvm::erase(id_string, '\n'); - - // lower case it and convert whitespace to underscores - std::transform( - id_string.begin(), id_string.end(), id_string.begin(), - [](char ch) { return tolower(isspace(ch) ? '_' : ch); }); - - g_fields->m_distribution_id = id_string; - LLDB_LOGF(log, "distribution id set to \"%s\"", - g_fields->m_distribution_id.c_str()); - } else { - LLDB_LOGF(log, "failed to find \"%s\" field in \"%s\"", - distributor_id_key, distribution_id); - } - } else { - LLDB_LOGF(log, - "failed to retrieve distribution id, \"%s\" returned no" - " lines", - get_distribution_id_command.c_str()); - } - - // clean up the file - pclose(file); - } - }); - - return g_fields->m_distribution_id; -} - FileSpec HostInfoAIX::GetProgramFileSpec() { static FileSpec g_program_filespec; @@ -136,19 +44,3 @@ FileSpec HostInfoAIX::GetProgramFileSpec() { return g_program_filespec; } - -void HostInfoAIX::ComputeHostArchitectureSupport(ArchSpec &arch_32, - ArchSpec &arch_64) { - HostInfoPosix::ComputeHostArchitectureSupport(arch_32, arch_64); - - // "unknown" in the vendor slot isn't what we want for the default - // triple. It's probably an artifact of config.guess. - if (arch_32.IsValid()) { - if (arch_32.GetTriple().getVendor() == llvm::Triple::UnknownVendor) - arch_32.GetTriple().setVendorName(llvm::StringRef()); - } - if (arch_64.IsValid()) { - if (arch_64.GetTriple().getVendor() == llvm::Triple::UnknownVendor) - arch_64.GetTriple().setVendorName(llvm::StringRef()); - } -} >From 57d080e44e80203a6ab848c362469954a7c9f067 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 5 Jan 2025 05:49:40 -0600 Subject: [PATCH 21/47] Cleanup HostInfoAIX Including the previous commit, Removed: GetDistributionID, ComputeHostArchitectureSupport and Reduced GetProgramFileSpec as it was not needed --- lldb/source/Host/aix/HostInfoAIX.cpp | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp index 2996fcb55f811..d09b9052668af 100644 --- a/lldb/source/Host/aix/HostInfoAIX.cpp +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -26,21 +26,9 @@ void HostInfoAIX::Initialize(SharedLibraryDirectoryHelper *helper) { HostInfoPosix::Initialize(helper); } -void HostInfoAIX::Terminate() { - HostInfoBase::Terminate(); -} +void HostInfoAIX::Terminate() { HostInfoBase::Terminate(); } FileSpec HostInfoAIX::GetProgramFileSpec() { static FileSpec g_program_filespec; - - if (!g_program_filespec) { - char exe_path[PATH_MAX]; - ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); - if (len > 0) { - exe_path[len] = 0; - g_program_filespec.SetFile(exe_path, FileSpec::Style::native); - } - } - return g_program_filespec; } >From 673713a9339de4e4ea395ee2e7f65dc1db43bcf9 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 5 Jan 2025 15:35:23 -0600 Subject: [PATCH 22/47] Removing headers --- lldb/include/lldb/Host/aix/HostInfoAIX.h | 2 -- lldb/source/Host/aix/HostInfoAIX.cpp | 12 ------------ 2 files changed, 14 deletions(-) diff --git a/lldb/include/lldb/Host/aix/HostInfoAIX.h b/lldb/include/lldb/Host/aix/HostInfoAIX.h index 5a52c42fa6199..331a274630850 100644 --- a/lldb/include/lldb/Host/aix/HostInfoAIX.h +++ b/lldb/include/lldb/Host/aix/HostInfoAIX.h @@ -11,8 +11,6 @@ #include "lldb/Host/posix/HostInfoPosix.h" #include "lldb/Utility/FileSpec.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/VersionTuple.h" namespace lldb_private { diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp index d09b9052668af..61b47462dd647 100644 --- a/lldb/source/Host/aix/HostInfoAIX.cpp +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -7,18 +7,6 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/aix/HostInfoAIX.h" -#include "lldb/Host/Config.h" -#include "lldb/Host/FileSystem.h" -#include "lldb/Utility/LLDBLog.h" -#include "lldb/Utility/Log.h" -#include "llvm/Support/Threading.h" -#include -#include -#include -#include -#include -#include -#include using namespace lldb_private; >From cdc31f3963365e4595247ff5a7155662df1ce1af Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 6 Jan 2025 09:28:56 -0600 Subject: [PATCH 23/47] Reverted merge blunder CMakeLists --- lldb/source/Host/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index f326bc07dc1f6..f4fca8acc4d83 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -141,7 +141,10 @@ else() elseif (CMAKE_SYSTEM_NAME MATCHES "AIX") add_host_subdirectory(aix + aix/AbstractSocket.cpp + aix/Host.cpp aix/HostInfoAIX.cpp + aix/Support.cpp ) endif() endif() >From 713a6cbbb97b9bc56b039ab050a1690eccc017e3 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 6 Jan 2025 09:39:36 -0600 Subject: [PATCH 24/47] Removed DomainSocket.cpp FileSystemPosix.cpp includes --- lldb/source/Host/posix/DomainSocket.cpp | 4 ---- lldb/source/Host/posix/FileSystemPosix.cpp | 3 --- 2 files changed, 7 deletions(-) diff --git a/lldb/source/Host/posix/DomainSocket.cpp b/lldb/source/Host/posix/DomainSocket.cpp index f30e84d83efca..be8fcdf2c8f2c 100644 --- a/lldb/source/Host/posix/DomainSocket.cpp +++ b/lldb/source/Host/posix/DomainSocket.cpp @@ -17,10 +17,6 @@ #include #include -#if defined(_AIX) -#include -#endif - using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index 1a84f550662d7..a631bb01209ec 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,9 +11,6 @@ // C includes #include #include -#ifndef _AIX -#include -#endif #include #include #include >From 0a706d29dabeefa62e354fc9358d650f89032048 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 6 Jan 2025 09:44:10 -0600 Subject: [PATCH 25/47] sys/mount.h --- lldb/source/Host/posix/FileSystemPosix.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index a631bb01209ec..945e2affc8371 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,6 +11,7 @@ // C includes #include #include +#include #include #include #include >From 84ebb4ec9b542c38fe1b60261a3253383e9fbf5d Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 6 Jan 2025 09:54:58 -0600 Subject: [PATCH 26/47] sys/mount.h --- lldb/source/Host/posix/FileSystemPosix.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index 945e2affc8371..1a84f550662d7 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,7 +11,9 @@ // C includes #include #include +#ifndef _AIX #include +#endif #include #include #include >From 844f7980040de9e13620e9d65a3fcaef56b6c8d6 Mon Sep 17 00:00:00 2001 From: Dhruv Srivastava Date: Thu, 9 Jan 2025 09:47:43 +0530 Subject: [PATCH 27/47] Removed _AIX from ConnectionFileDescriptorPosix.cpp --- lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index 2530c8fa353ba..0ed2016667162 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -715,7 +715,7 @@ ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, ConnectionStatus ConnectionFileDescriptor::ConnectFile( llvm::StringRef s, socket_id_callback_type socket_id_callback, Status *error_ptr) { -#if LLDB_ENABLE_POSIX && !defined(_AIX) +#if LLDB_ENABLE_POSIX std::string addr_str = s.str(); // file:///PATH int fd = FileSystem::Instance().Open(addr_str.c_str(), O_RDWR); @@ -756,7 +756,7 @@ ConnectionStatus ConnectionFileDescriptor::ConnectFile( m_io_sp = std::make_shared(fd, File::eOpenOptionReadWrite, true); return eConnectionStatusSuccess; -#endif // LLDB_ENABLE_POSIX && !defined(_AIX) +#endif // LLDB_ENABLE_POSIX llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX"); } >From 4fe42cda7c2f4990b18a39c1d6563094fb88775f Mon Sep 17 00:00:00 2001 From: ravindra shinde Date: Fri, 17 Jan 2025 13:58:13 +0530 Subject: [PATCH 28/47] [ObjectFileXCOFF] Fix access to protected member 'GetSectionLoadList' in Target - Added a public method to Target for accessing 'GetSectionLoadList' safely. - Updated ObjectFileXCOFF to use the new public method, ensuring compliance with encapsulation rules. This resolves the build error caused by direct access to the protected member. Signed-off-by: ravindra shinde --- lldb/include/lldb/Target/Target.h | 5 +++++ lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index f31ac381391b4..75f9c9c2e999c 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -522,6 +522,7 @@ class Target : public std::enable_shared_from_this, eBroadcastBitSymbolsChanged = (1 << 5), }; + // These two functions fill out the Broadcaster interface: static llvm::StringRef GetStaticBroadcasterClass(); @@ -1644,6 +1645,10 @@ class Target : public std::enable_shared_from_this, TargetStats &GetStatistics() { return m_stats; } +public: + SectionLoadList &GetSectionLoadListPublic() { + return GetSectionLoadList(); + } protected: /// Construct with optional file and arch. /// diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index afd8027bab06c..cf11e5fb8f5a3 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -340,7 +340,7 @@ bool ObjectFileXCOFF::SetLoadAddress(Target &target, lldb::addr_t value, strcmp(section_sp->GetName().AsCString(), ".bss") == 0) use_offset = true; - if (target.GetSectionLoadList().SetSectionLoadAddress( + if (target.GetSectionLoadListPublic().SetSectionLoadAddress( section_sp, (use_offset ? (section_sp->GetFileOffset() + value) : (section_sp->GetFileAddress() + value)))) ++num_loaded_sections; @@ -369,13 +369,13 @@ bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); if (type_id == 1 && section_sp && strcmp(section_sp->GetName().AsCString(), ".text") == 0) { if (!section_sp->IsThreadSpecific()) { - if (target.GetSectionLoadList().SetSectionLoadAddress( + if (target.GetSectionLoadListPublic().SetSectionLoadAddress( section_sp, section_sp->GetFileOffset() + value)) ++num_loaded_sections; } } else if (type_id == 2 && section_sp && strcmp(section_sp->GetName().AsCString(), ".data") == 0) { if (!section_sp->IsThreadSpecific()) { - if (target.GetSectionLoadList().SetSectionLoadAddress( + if (target.GetSectionLoadListPublic().SetSectionLoadAddress( section_sp, section_sp->GetFileAddress() + value)) ++num_loaded_sections; } >From e5ed4f21c5bbc709e5e2eff0f83995cc6d89de48 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 19 Jan 2025 03:43:11 -0600 Subject: [PATCH 29/47] Resolved cmake failure for SBProgress.cpp --- lldb/source/API/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index eb348e2b97232..0a03e000c0cae 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -85,6 +85,7 @@ add_lldb_library(liblldb STATIC ${option_framework} SBModuleSpec.cpp SBPlatform.cpp SBProcess.cpp + SBProgress.cpp SBProcessInfo.cpp SBProcessInfoList.cpp SBQueue.cpp >From 82dbcb0e776c438e5f40c9f8d8c8e8eb81b7febd Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 27 Jan 2025 06:35:19 -0600 Subject: [PATCH 30/47] Host.cpp ANDROID --- lldb/source/Host/common/Host.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 758e9f49ade2c..adf74df8aa90b 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -1,4 +1,4 @@ -//===-- Host.cpp ----------------------------------------------------------===// + // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -516,7 +516,6 @@ static int dladdr(const void *ptr, Dl_info *dl) FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSpec module_filespec; -#if !defined(__ANDROID__) #ifdef _AIX if (host_addr == reinterpret_cast(HostInfoBase::ComputeSharedLibraryDirectory)) { // FIXME: AIX dladdr return "lldb" for this case @@ -527,6 +526,7 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { } } #endif +#if !defined(__ANDROID__) Dl_info info; if (::dladdr(host_addr, &info)) { if (info.dli_fname) { @@ -534,6 +534,7 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSystem::Instance().Resolve(module_filespec); } } +#endif return module_filespec; } >From 60294eaa1611632afc94b9da503752e34ad2703d Mon Sep 17 00:00:00 2001 From: Ravindra Shinde Date: Tue, 4 Feb 2025 03:23:56 -0600 Subject: [PATCH 31/47] Resolving the fatal error while build Build is failing due to the fatal error: 'sys/syscall.h' file not found Signed-off-by: Ravindra Shinde --- lldb/source/Host/common/Host.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 40ce76d70d6e8..b5bd68b8539bd 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -18,8 +18,12 @@ #include #include #include + +#ifndef _AIX #include #include +#endif + #include #include #endif >From 2644be59b13a61c69cc635875c94b0b4645fe76c Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 10 Feb 2025 01:49:12 -0600 Subject: [PATCH 32/47] InferiorCallPOSIX.cpp --- lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index d1f9fe851119e..8e74cce097894 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -120,12 +120,13 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, arch, addr, length, prot_arg, flags, fd, offset); #if defined(_AIX) lldb::ThreadPlanSP call_plan_sp( - new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(), + new ThreadPlanCallFunction(*thread, mmap_addr, toc_range.GetBaseAddress(), void_ptr_type, args, options)); #else lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallFunction( *thread, mmap_addr, void_ptr_type, args, options)); +#endif if (call_plan_sp) { DiagnosticManager diagnostics; >From 4805b13cba964b58def39a66ad4c4309a9b2c501 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 12 Feb 2025 07:33:04 -0600 Subject: [PATCH 33/47] Merge branch gh-101657 --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 97 ------------------- .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 5 +- 2 files changed, 1 insertion(+), 101 deletions(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 1a98bb9334043..375d879c7a995 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -21,10 +21,6 @@ #include "llvm/Support/FileSystem.h" #if defined(_AIX) #include -#include -#include -#include -#include #endif /*#include "llvm/ADT/Triple.h" @@ -137,107 +133,14 @@ bool DynamicLoaderAIXDYLD::NotifyBreakpointHit( } -void DynamicLoaderAIXDYLD::ResolveExecutableModule( - lldb::ModuleSP &module_sp) { - Log *log = GetLog(LLDBLog::DynamicLoader); - - if (m_process == nullptr) - return; - - auto &target = m_process->GetTarget(); - const auto platform_sp = target.GetPlatform(); - - ProcessInstanceInfo process_info; - if (!m_process->GetProcessInfo(process_info)) { - LLDB_LOGF(log, - "DynamicLoaderPOSIXDYLD::%s - failed to get process info for " - "pid %" PRIu64, - __FUNCTION__, m_process->GetID()); - return; - } - - int32long64_t pid = m_process->GetID(); - char cwd[PATH_MAX], resolved_path[PATH_MAX]; - std::string executable_name; - bool path_resolved = false; - psinfo_t psinfo; - - std::string proc_file = "/proc/" + std::to_string(pid) + "/psinfo"; - std::string cwd_link = "/proc/" + std::to_string(pid) + "/cwd"; - std::ifstream file(proc_file, std::ios::binary); - if(!file.is_open()) - LLDB_LOGF(log, "Error: Unable to access process info "); - - file.read(reinterpret_cast(&psinfo), sizeof(psinfo_t)); - if(!file) - LLDB_LOGF(log, "Process info error: Failed to read "); - - std::string relative_path(psinfo.pr_fname); - LLDB_LOGF(log, "Relative path %s",relative_path.c_str()); - - if(readlink(cwd_link.c_str(), cwd, sizeof(cwd)) != -1){ - std::filesystem::path full_path = std::filesystem::path(cwd)/relative_path; - if(realpath(full_path.c_str(), resolved_path)) { - LLDB_LOGF(log, "Resolved Path using process info : %s", resolved_path); - path_resolved = true; - } - else - LLDB_LOGF(log, "Realpath error: Unable to resolve. "); - } - - executable_name = resolved_path; - if(path_resolved == false) { - std::string command_line(psinfo.pr_psargs); - LLDB_LOGF(log, "Command line: %s",command_line.c_str()); - if (!command_line.empty()) { - size_t space1 = command_line.find(' '); - executable_name = command_line.substr(0, space1); - LLDB_LOGF(log, "Resolved path using command line arg %s",executable_name.c_str()); - } - } - - LLDB_LOGF(log, "Executable Name %s",executable_name.c_str()); - process_info.SetExecutableFile(lldb_private::FileSpec(executable_name), - true); - - LLDB_LOGF( - log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s", - __FUNCTION__, m_process->GetID(), - process_info.GetExecutableFile().GetPath().c_str()); - - ModuleSpec module_spec(process_info.GetExecutableFile(), - process_info.GetArchitecture()); - if (module_sp && module_sp->MatchesModuleSpec(module_spec)) - return; - - const auto executable_search_paths(Target::GetDefaultExecutableSearchPaths()); - auto error = platform_sp->ResolveExecutable( - module_spec, module_sp, - !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr); - if (error.Fail()) { - StreamString stream; - module_spec.Dump(stream); - - LLDB_LOGF(log, - "DynamicLoaderPOSIXDYLD::%s - failed to resolve executable " - "with module spec \"%s\": %s", - __FUNCTION__, stream.GetData(), error.AsCString()); - return; - } - - target.SetExecutableModule(module_sp, eLoadDependentsNo); -} - void DynamicLoaderAIXDYLD::DidAttach() { Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); ModuleSP executable = GetTargetExecutable(); - ResolveExecutableModule(executable); if (!executable.get()) return; - LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); // Try to fetch the load address of the file from the process, since there // could be randomization of the load address. diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h index 0ffbe688e0069..ae4b7aca66dcc 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -24,7 +24,7 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { static void Initialize(); static void Terminate(); - static llvm::StringRef GetPluginNameStatic() { return "aix-dyld"; } + static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; } static llvm::StringRef GetPluginDescriptionStatic(); static DynamicLoader *CreateInstance(Process *process, bool force); @@ -46,9 +46,6 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { protected: lldb::addr_t GetLoadAddress(lldb::ModuleSP executable); - /// Loads Module from inferior process. - void ResolveExecutableModule(lldb::ModuleSP &module_sp); - private: std::map m_loaded_modules; }; >From cff574b36903e12385e5d6cddf4532ba279f47de Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 12 Feb 2025 07:52:04 -0600 Subject: [PATCH 34/47] Fix for Debugging Attach to AIX Process --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 97 +++++++++++++++++++ .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 5 +- 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 375d879c7a995..1a98bb9334043 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -21,6 +21,10 @@ #include "llvm/Support/FileSystem.h" #if defined(_AIX) #include +#include +#include +#include +#include #endif /*#include "llvm/ADT/Triple.h" @@ -133,14 +137,107 @@ bool DynamicLoaderAIXDYLD::NotifyBreakpointHit( } +void DynamicLoaderAIXDYLD::ResolveExecutableModule( + lldb::ModuleSP &module_sp) { + Log *log = GetLog(LLDBLog::DynamicLoader); + + if (m_process == nullptr) + return; + + auto &target = m_process->GetTarget(); + const auto platform_sp = target.GetPlatform(); + + ProcessInstanceInfo process_info; + if (!m_process->GetProcessInfo(process_info)) { + LLDB_LOGF(log, + "DynamicLoaderPOSIXDYLD::%s - failed to get process info for " + "pid %" PRIu64, + __FUNCTION__, m_process->GetID()); + return; + } + + int32long64_t pid = m_process->GetID(); + char cwd[PATH_MAX], resolved_path[PATH_MAX]; + std::string executable_name; + bool path_resolved = false; + psinfo_t psinfo; + + std::string proc_file = "/proc/" + std::to_string(pid) + "/psinfo"; + std::string cwd_link = "/proc/" + std::to_string(pid) + "/cwd"; + std::ifstream file(proc_file, std::ios::binary); + if(!file.is_open()) + LLDB_LOGF(log, "Error: Unable to access process info "); + + file.read(reinterpret_cast(&psinfo), sizeof(psinfo_t)); + if(!file) + LLDB_LOGF(log, "Process info error: Failed to read "); + + std::string relative_path(psinfo.pr_fname); + LLDB_LOGF(log, "Relative path %s",relative_path.c_str()); + + if(readlink(cwd_link.c_str(), cwd, sizeof(cwd)) != -1){ + std::filesystem::path full_path = std::filesystem::path(cwd)/relative_path; + if(realpath(full_path.c_str(), resolved_path)) { + LLDB_LOGF(log, "Resolved Path using process info : %s", resolved_path); + path_resolved = true; + } + else + LLDB_LOGF(log, "Realpath error: Unable to resolve. "); + } + + executable_name = resolved_path; + if(path_resolved == false) { + std::string command_line(psinfo.pr_psargs); + LLDB_LOGF(log, "Command line: %s",command_line.c_str()); + if (!command_line.empty()) { + size_t space1 = command_line.find(' '); + executable_name = command_line.substr(0, space1); + LLDB_LOGF(log, "Resolved path using command line arg %s",executable_name.c_str()); + } + } + + LLDB_LOGF(log, "Executable Name %s",executable_name.c_str()); + process_info.SetExecutableFile(lldb_private::FileSpec(executable_name), + true); + + LLDB_LOGF( + log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s", + __FUNCTION__, m_process->GetID(), + process_info.GetExecutableFile().GetPath().c_str()); + + ModuleSpec module_spec(process_info.GetExecutableFile(), + process_info.GetArchitecture()); + if (module_sp && module_sp->MatchesModuleSpec(module_spec)) + return; + + const auto executable_search_paths(Target::GetDefaultExecutableSearchPaths()); + auto error = platform_sp->ResolveExecutable( + module_spec, module_sp, + !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr); + if (error.Fail()) { + StreamString stream; + module_spec.Dump(stream); + + LLDB_LOGF(log, + "DynamicLoaderPOSIXDYLD::%s - failed to resolve executable " + "with module spec \"%s\": %s", + __FUNCTION__, stream.GetData(), error.AsCString()); + return; + } + + target.SetExecutableModule(module_sp, eLoadDependentsNo); +} + void DynamicLoaderAIXDYLD::DidAttach() { Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); ModuleSP executable = GetTargetExecutable(); + ResolveExecutableModule(executable); if (!executable.get()) return; + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); // Try to fetch the load address of the file from the process, since there // could be randomization of the load address. diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h index ae4b7aca66dcc..0ffbe688e0069 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -24,7 +24,7 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { static void Initialize(); static void Terminate(); - static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; } + static llvm::StringRef GetPluginNameStatic() { return "aix-dyld"; } static llvm::StringRef GetPluginDescriptionStatic(); static DynamicLoader *CreateInstance(Process *process, bool force); @@ -46,6 +46,9 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { protected: lldb::addr_t GetLoadAddress(lldb::ModuleSP executable); + /// Loads Module from inferior process. + void ResolveExecutableModule(lldb::ModuleSP &module_sp); + private: std::map m_loaded_modules; }; >From 303fa3bc078d7572702fb302726d4dd1bd13ddb2 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Fri, 21 Feb 2025 06:18:33 -0600 Subject: [PATCH 35/47] Merge branch 'llvm:main' into gh-101657 --- lldb/source/Plugins/Platform/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/lldb/source/Plugins/Platform/CMakeLists.txt b/lldb/source/Plugins/Platform/CMakeLists.txt index f5b0dbdd5e0a9..0220e734b36d1 100644 --- a/lldb/source/Plugins/Platform/CMakeLists.txt +++ b/lldb/source/Plugins/Platform/CMakeLists.txt @@ -9,4 +9,3 @@ add_subdirectory(OpenBSD) add_subdirectory(POSIX) add_subdirectory(QemuUser) add_subdirectory(Windows) -add_subdirectory(AIX) >From 6947dec02bb527f710c1bea3827b2c16d89f308a Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Fri, 21 Feb 2025 07:02:53 -0600 Subject: [PATCH 36/47] Merge branch 'llvm:main' into gh-101657 --- .../Plugins/Platform/AIX/PlatformAIX.cpp | 171 +----------------- 1 file changed, 1 insertion(+), 170 deletions(-) diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp index 0d66325d16267..21724d83133e9 100644 --- a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp +++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp @@ -130,12 +130,6 @@ void PlatformAIX::GetStatus(Stream &strm) { #endif } -void PlatformAIX::CalculateTrapHandlerSymbolNames() { - m_trap_handlers.push_back(ConstString("_sigtramp")); - m_trap_handlers.push_back(ConstString("__kernel_rt_sigreturn")); - m_trap_handlers.push_back(ConstString("__restore_rt")); -} - void PlatformAIX::CalculateTrapHandlerSymbolNames() {} lldb::UnwindPlanSP @@ -160,168 +154,5 @@ MmapArgList PlatformAIX::GetMmapArgumentList(const ArchSpec &arch, addr_t addr, } CompilerType PlatformAIX::GetSiginfoType(const llvm::Triple &triple) { - if (!m_type_system_up) - m_type_system_up.reset(new TypeSystemClang("siginfo", triple)); - TypeSystemClang *ast = m_type_system_up.get(); - - bool si_errno_then_code = true; - - switch (triple.getArch()) { - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - // mips has si_code and si_errno swapped - si_errno_then_code = false; - break; - default: - break; - } - - // generic types - CompilerType int_type = ast->GetBasicType(eBasicTypeInt); - CompilerType uint_type = ast->GetBasicType(eBasicTypeUnsignedInt); - CompilerType short_type = ast->GetBasicType(eBasicTypeShort); - CompilerType long_type = ast->GetBasicType(eBasicTypeLong); - CompilerType voidp_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); - - // platform-specific types - CompilerType &pid_type = int_type; - CompilerType &uid_type = uint_type; - CompilerType &clock_type = long_type; - CompilerType &band_type = long_type; - - CompilerType sigval_type = ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_sigval_t", - llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); - ast->StartTagDeclarationDefinition(sigval_type); - ast->AddFieldToRecordType(sigval_type, "sival_int", int_type, - lldb::eAccessPublic, 0); - ast->AddFieldToRecordType(sigval_type, "sival_ptr", voidp_type, - lldb::eAccessPublic, 0); - ast->CompleteTagDeclarationDefinition(sigval_type); - - CompilerType sigfault_bounds_type = ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", - llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); - ast->StartTagDeclarationDefinition(sigfault_bounds_type); - ast->AddFieldToRecordType(sigfault_bounds_type, "_addr_bnd", - ast->CreateStructForIdentifier(ConstString(), - { - {"_lower", voidp_type}, - {"_upper", voidp_type}, - }), - lldb::eAccessPublic, 0); - ast->AddFieldToRecordType(sigfault_bounds_type, "_pkey", uint_type, - lldb::eAccessPublic, 0); - ast->CompleteTagDeclarationDefinition(sigfault_bounds_type); - - // siginfo_t - CompilerType siginfo_type = ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_siginfo_t", - llvm::to_underlying(clang::TagTypeKind::Struct), lldb::eLanguageTypeC); - ast->StartTagDeclarationDefinition(siginfo_type); - ast->AddFieldToRecordType(siginfo_type, "si_signo", int_type, - lldb::eAccessPublic, 0); - - if (si_errno_then_code) { - ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type, - lldb::eAccessPublic, 0); - ast->AddFieldToRecordType(siginfo_type, "si_code", int_type, - lldb::eAccessPublic, 0); - } else { - ast->AddFieldToRecordType(siginfo_type, "si_code", int_type, - lldb::eAccessPublic, 0); - ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type, - lldb::eAccessPublic, 0); - } - - // the structure is padded on 64-bit arches to fix alignment - if (triple.isArch64Bit()) - ast->AddFieldToRecordType(siginfo_type, "__pad0", int_type, - lldb::eAccessPublic, 0); - - // union used to hold the signal data - CompilerType union_type = ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", - llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); - ast->StartTagDeclarationDefinition(union_type); - - ast->AddFieldToRecordType( - union_type, "_kill", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_pid", pid_type}, - {"si_uid", uid_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_timer", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_tid", int_type}, - {"si_overrun", int_type}, - {"si_sigval", sigval_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_rt", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_pid", pid_type}, - {"si_uid", uid_type}, - {"si_sigval", sigval_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_sigchld", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_pid", pid_type}, - {"si_uid", uid_type}, - {"si_status", int_type}, - {"si_utime", clock_type}, - {"si_stime", clock_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_sigfault", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_addr", voidp_type}, - {"si_addr_lsb", short_type}, - {"_bounds", sigfault_bounds_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_sigpoll", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_band", band_type}, - {"si_fd", int_type}, - }), - lldb::eAccessPublic, 0); - - // NB: SIGSYS is not present on ia64 but we don't seem to support that - ast->AddFieldToRecordType( - union_type, "_sigsys", - ast->CreateStructForIdentifier(ConstString(), - { - {"_call_addr", voidp_type}, - {"_syscall", int_type}, - {"_arch", uint_type}, - }), - lldb::eAccessPublic, 0); - - ast->CompleteTagDeclarationDefinition(union_type); - ast->AddFieldToRecordType(siginfo_type, "_sifields", union_type, - lldb::eAccessPublic, 0); - - ast->CompleteTagDeclarationDefinition(siginfo_type); - return siginfo_type; + return CompilerType(); } >From 24615119addcdf9fe5a8c5b2ebd0c15d75651279 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sat, 22 Feb 2025 03:42:26 -0600 Subject: [PATCH 37/47] Removed un-needed changes --- lldb/include/lldb/Host/aix/AbstractSocket.h | 25 --------------------- lldb/include/lldb/Host/aix/Uio.h | 23 ------------------- lldb/source/Host/CMakeLists.txt | 1 - lldb/source/Host/aix/AbstractSocket.cpp | 20 ----------------- 4 files changed, 69 deletions(-) delete mode 100644 lldb/include/lldb/Host/aix/AbstractSocket.h delete mode 100644 lldb/include/lldb/Host/aix/Uio.h delete mode 100644 lldb/source/Host/aix/AbstractSocket.cpp diff --git a/lldb/include/lldb/Host/aix/AbstractSocket.h b/lldb/include/lldb/Host/aix/AbstractSocket.h deleted file mode 100644 index accfd01457a5e..0000000000000 --- a/lldb/include/lldb/Host/aix/AbstractSocket.h +++ /dev/null @@ -1,25 +0,0 @@ -//===-- AbstractSocket.h ----------------------------------------*- 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 -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_AbstractSocket_h_ -#define liblldb_AbstractSocket_h_ - -#include "lldb/Host/posix/DomainSocket.h" - -namespace lldb_private { -class AbstractSocket : public DomainSocket { -public: - AbstractSocket(); - -protected: - size_t GetNameOffset() const override; - void DeleteSocketFile(llvm::StringRef name) override; -}; -} - -#endif // ifndef liblldb_AbstractSocket_h_ diff --git a/lldb/include/lldb/Host/aix/Uio.h b/lldb/include/lldb/Host/aix/Uio.h deleted file mode 100644 index acf79ecc6a1d0..0000000000000 --- a/lldb/include/lldb/Host/aix/Uio.h +++ /dev/null @@ -1,23 +0,0 @@ -//===-- Uio.h ---------------------------------------------------*- 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 -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_Host_aix_Uio_h_ -#define liblldb_Host_aix_Uio_h_ - -#include "lldb/Host/Config.h" -#include - -// We shall provide our own implementation of process_vm_readv if it is not -// present -#if !HAVE_PROCESS_VM_READV -ssize_t process_vm_readv(::pid_t pid, const struct iovec *local_iov, - unsigned long liovcnt, const struct iovec *remote_iov, - unsigned long riovcnt, unsigned long flags); -#endif - -#endif // liblldb_Host_aix_Uio_h_ diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index bb6b5befa16e4..5a14b4c629825 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -140,7 +140,6 @@ else() elseif (CMAKE_SYSTEM_NAME MATCHES "AIX") add_host_subdirectory(aix - aix/AbstractSocket.cpp aix/Host.cpp aix/HostInfoAIX.cpp aix/Support.cpp diff --git a/lldb/source/Host/aix/AbstractSocket.cpp b/lldb/source/Host/aix/AbstractSocket.cpp deleted file mode 100644 index fddf78f54f46d..0000000000000 --- a/lldb/source/Host/aix/AbstractSocket.cpp +++ /dev/null @@ -1,20 +0,0 @@ -//===-- AbstractSocket.cpp ------------------------------------------------===// -// -// 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 "lldb/Host/aix/AbstractSocket.h" - -#include "llvm/ADT/StringRef.h" - -using namespace lldb; -using namespace lldb_private; - -AbstractSocket::AbstractSocket() : DomainSocket(ProtocolUnixAbstract) {} - -size_t AbstractSocket::GetNameOffset() const { return 1; } - -void AbstractSocket::DeleteSocketFile(llvm::StringRef name) {} >From 25bea9ca48dc458c1dddd72f10a483e76926a04e Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Wed, 26 Feb 2025 01:10:15 -0600 Subject: [PATCH 38/47] Resolving coredump issue while attach with library calls --- lldb/include/lldb/Core/ModuleSpec.h | 2 ++ lldb/source/Core/ModuleList.cpp | 12 +++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lldb/include/lldb/Core/ModuleSpec.h b/lldb/include/lldb/Core/ModuleSpec.h index 4fe06412b6b0b..9d79992b48c7e 100644 --- a/lldb/include/lldb/Core/ModuleSpec.h +++ b/lldb/include/lldb/Core/ModuleSpec.h @@ -122,6 +122,8 @@ class ModuleSpec { ConstString &GetObjectName() { return m_object_name; } ConstString GetObjectName() const { return m_object_name; } + + void SetObjectName(ConstString objName) { m_object_name = objName; } uint64_t GetObjectOffset() const { return m_object_offset; } diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index 2b8ccab2406c6..862a2729c1afb 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -260,7 +260,17 @@ void ModuleList::ReplaceEquivalent( module_sp->GetArchitecture()); equivalent_module_spec.GetPlatformFileSpec() = module_sp->GetPlatformFileSpec(); - +#ifdef _AIX + // To remove the exact equivalent module, the object name must be + // specified. When the equivalent_module_spec object is created, its + // object name is initially set to NULL. This is because the module_sp's + // GetPath() returns a path in the format (/usr/ccs/libc.a), which does + // not include the object name. As a result, MatchesModuleSpec may return + // true even though the object name is NULL and doesn't match any loaded + // module. To fix this, set the object name of the equivalent_module_spec + // to be the same as the object name of the module_sp. */ + equivalent_module_spec.SetObjectName(module_sp->GetObjectName()); +#endif size_t idx = 0; while (idx < m_modules.size()) { ModuleSP test_module_sp(m_modules[idx]); >From 349ec0064668a0ee1d3af7c2f38fa7427b4b2d36 Mon Sep 17 00:00:00 2001 From: Dhruv Srivastava Date: Fri, 28 Feb 2025 23:44:40 +0530 Subject: [PATCH 39/47] [AIX][Coredump] AIX Coredump debugging Implementation (#25) Creates a general framework to be able to debug an AIX generated coredump file. At this point, we are only supporting 64-bit core files using this general framework. With this implementation, LLDB can recognise and debug any 64-bit AIX coredump file. Most of the generic debugging commands work after this: # bin/lldb --core /home/dhruv/LLDB/tests/core (lldb) target create --core "/home/dhruv/LLDB/tests/core" Core file '/home/dhruv/LLDB/tests/core' (powerpc64) was loaded. (lldb) bt * thread #1, stop reason = SIGSEGV * frame #0: 0x0000000100000940 coretest64`main at core.c:5 frame #1: 0x00000001000004ac coretest64`__start + 116 (lldb) process status Process 18446744071562067991 stopped * thread #1, stop reason = SIGSEGV frame #0: 0x0000000100000940 coretest64`main at core.c:5 2 char *str; 3 int a = 10; 4 str = "GfG"; -> 5 *(str+1) = 'n'; 6 return a; 7 } And others like memory read, image list, image dump sections, disassembly etc --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 62 ++++- .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 6 + .../Plugins/ObjectFile/AIXCore/CMakeLists.txt | 13 + .../ObjectFile/AIXCore/ObjectFileAIXCore.cpp | 254 ++++++++++++++++++ .../ObjectFile/AIXCore/ObjectFileAIXCore.h | 121 +++++++++ lldb/source/Plugins/ObjectFile/CMakeLists.txt | 1 + lldb/source/Plugins/Process/CMakeLists.txt | 1 + .../Plugins/Process/aix-core/AIXCore.cpp | 116 ++++++++ .../source/Plugins/Process/aix-core/AIXCore.h | 125 +++++++++ .../Plugins/Process/aix-core/CMakeLists.txt | 16 ++ .../Process/aix-core/ProcessAIXCore.cpp | 251 +++++++++++++++++ .../Plugins/Process/aix-core/ProcessAIXCore.h | 100 +++++++ .../aix-core/RegisterContextCoreAIX_ppc64.cpp | 136 ++++++++++ .../aix-core/RegisterContextCoreAIX_ppc64.h | 46 ++++ .../Process/aix-core/ThreadAIXCore.cpp | 127 +++++++++ .../Plugins/Process/aix-core/ThreadAIXCore.h | 110 ++++++++ 16 files changed, 1484 insertions(+), 1 deletion(-) create mode 100644 lldb/source/Plugins/ObjectFile/AIXCore/CMakeLists.txt create mode 100644 lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp create mode 100644 lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.h create mode 100644 lldb/source/Plugins/Process/aix-core/AIXCore.cpp create mode 100644 lldb/source/Plugins/Process/aix-core/AIXCore.h create mode 100644 lldb/source/Plugins/Process/aix-core/CMakeLists.txt create mode 100644 lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp create mode 100644 lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h create mode 100644 lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.cpp create mode 100644 lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.h create mode 100644 lldb/source/Plugins/Process/aix-core/ThreadAIXCore.cpp create mode 100644 lldb/source/Plugins/Process/aix-core/ThreadAIXCore.h diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 1a98bb9334043..7e44ffbb1c051 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -228,6 +228,65 @@ void DynamicLoaderAIXDYLD::ResolveExecutableModule( target.SetExecutableModule(module_sp, eLoadDependentsNo); } +bool DynamicLoaderAIXDYLD::IsCoreFile() const { + return !m_process->IsLiveDebugSession(); +} + +void DynamicLoaderAIXDYLD::FillCoreLoaderData(lldb_private::DataExtractor &data, + uint64_t loader_offset, uint64_t loader_size ) { + + static char *buffer = (char *)malloc(loader_size); + struct ld_info ldinfo[64]; + char *buffer_complete; + struct ld_info *ptr; + int i = 0; + + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); + ByteOrder byteorder = data.GetByteOrder(); + data.ExtractBytes(loader_offset, loader_size, eByteOrderBig, buffer); + buffer_complete = buffer + loader_size; + ldinfo[0].ldinfo_next = 1; + + while (ldinfo[i++].ldinfo_next != 0) { + + ptr = (struct ld_info *)buffer; + ldinfo[i].ldinfo_next = ptr->ldinfo_next; + ldinfo[i].ldinfo_flags = ptr->ldinfo_flags; + ldinfo[i].ldinfo_core = ptr->ldinfo_core; + ldinfo[i].ldinfo_textorg = ptr->ldinfo_textorg; + ldinfo[i].ldinfo_textsize = ptr->ldinfo_textsize; + ldinfo[i].ldinfo_dataorg = ptr->ldinfo_dataorg; + ldinfo[i].ldinfo_datasize = ptr->ldinfo_datasize; + + char *filename = &ptr->ldinfo_filename[0]; + char *membername = filename + (strlen(filename) + 1); + strcpy(ldinfo[i].ldinfo_filename, filename); + + buffer += ptr->ldinfo_next; + struct ld_info *ptr2 = &(ldinfo[i]); + char *pathName = ptr2->ldinfo_filename; + char pathWithMember[PATH_MAX] = {0}; + if (strlen(membername) > 0) { + sprintf(pathWithMember, "%s(%s)", pathName, membername); + } else { + sprintf(pathWithMember, "%s", pathName); + } + + FileSpec file(pathWithMember); + ModuleSpec module_spec(file, m_process->GetTarget().GetArchitecture()); + LLDB_LOGF(log, "Module :%s", pathWithMember); + if (ModuleSP module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, true /* notify */)) { + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr2->ldinfo_textorg, false, 1); + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr2->ldinfo_dataorg, false, 2); + // FIXME: .tdata, .bss + } + if (ptr2->ldinfo_next == 0) { + ptr2 = nullptr; + } + } +} + void DynamicLoaderAIXDYLD::DidAttach() { Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); @@ -361,7 +420,8 @@ void DynamicLoaderAIXDYLD::DidLaunch() { #endif } -Status DynamicLoaderAIXDYLD::CanLoadImage() { return Status(); } +Status DynamicLoaderAIXDYLD::CanLoadImage() { + return Status(); } ThreadPlanSP DynamicLoaderAIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h index 0ffbe688e0069..097f8d048b77f 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -33,6 +33,9 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { lldb::addr_t module_addr); void OnUnloadModule(lldb::addr_t module_addr); + void FillCoreLoaderData(lldb_private::DataExtractor &data, + uint64_t loader_offset, uint64_t loader_size); + void DidAttach() override; void DidLaunch() override; Status CanLoadImage() override; @@ -49,6 +52,9 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { /// Loads Module from inferior process. void ResolveExecutableModule(lldb::ModuleSP &module_sp); + /// Returns true if the process is for a core file. + bool IsCoreFile() const; + private: std::map m_loaded_modules; }; diff --git a/lldb/source/Plugins/ObjectFile/AIXCore/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/AIXCore/CMakeLists.txt new file mode 100644 index 0000000000000..5656b33a61726 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/AIXCore/CMakeLists.txt @@ -0,0 +1,13 @@ +add_lldb_library(lldbPluginObjectFileAIXCore PLUGIN + ObjectFileAIXCore.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + lldbTarget + lldbUtility + lldbPluginProcessUtility + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp new file mode 100644 index 0000000000000..5158fa4e25077 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp @@ -0,0 +1,254 @@ +//===-- ObjectFileAIXCore.cpp -------------------------------------------------===// +// +// 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 "ObjectFileAIXCore.h" + +#include +#include +#include +#include + +#include "lldb/Utility/FileSpecList.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Stream.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Object/XCOFFObjectFile.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ObjectFileAIXCore) + +enum CoreVersion : uint64_t {AIXCORE32 = 0xFEEDDB1, AIXCORE64 = 0xFEEDDB2}; + +bool m_is_core = false; + +// Static methods. +void ObjectFileAIXCore::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + CreateMemoryInstance, GetModuleSpecifications); +} + +void ObjectFileAIXCore::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ObjectFile *ObjectFileAIXCore::CreateInstance(const lldb::ModuleSP &module_sp, + DataBufferSP data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t file_offset, + lldb::offset_t length) { + + if(m_is_core) + { + + bool mapped_writable = false; + if (!data_sp) { + data_sp = MapFileDataWritable(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + mapped_writable = true; + } + + assert(data_sp); + + const uint8_t *magic = data_sp->GetBytes() + data_offset; + + // Update the data to contain the entire file if it doesn't already + if (data_sp->GetByteSize() < length) { + data_sp = MapFileDataWritable(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + mapped_writable = true; + magic = data_sp->GetBytes(); + } + + // If we didn't map the data as writable take ownership of the buffer. + if (!mapped_writable) { + data_sp = std::make_shared(data_sp->GetBytes(), + data_sp->GetByteSize()); + data_offset = 0; + magic = data_sp->GetBytes(); + } + + std::unique_ptr objfile_up(new ObjectFileAIXCore( + module_sp, data_sp, data_offset, file, file_offset, length)); + ArchSpec spec = objfile_up->GetArchitecture(); + objfile_up->SetModulesArchitecture(spec); + return objfile_up.release(); + + } +} + +ObjectFile *ObjectFileAIXCore::CreateMemoryInstance( + const lldb::ModuleSP &module_sp, WritableDataBufferSP data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) { + return nullptr; +} + +size_t ObjectFileAIXCore::GetModuleSpecifications( + const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, lldb::offset_t file_offset, + lldb::offset_t length, lldb_private::ModuleSpecList &specs) { + const size_t initial_count = specs.GetSize(); + + if (ObjectFileAIXCore::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) { + // Need new ArchType??? + ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + ModuleSpec spec(file, arch_spec); + spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX); + specs.Append(spec); + } + return specs.GetSize() - initial_count; +} + +static uint32_t AIXCoreHeaderCheckFromMagic(uint32_t magic) { + + Log *log = GetLog(LLDBLog::Modules); + switch (magic) { + case AIXCORE32: + LLDB_LOGF(log, "ObjectFileAIXCore: 32-bit not supported"); + break; + case AIXCORE64: + m_is_core = true; + return 1; + break; + } + return 0; +} + +bool ObjectFileAIXCore::MagicBytesMatch(DataBufferSP &data_sp, + lldb::addr_t data_offset, + lldb::addr_t data_length) { + lldb_private::DataExtractor data; + data.SetData(data_sp, data_offset, data_length); + lldb::offset_t offset = 0; + offset += 4; // Skipping to the coredump version + uint32_t magic = data.GetU32(&offset); + return AIXCoreHeaderCheckFromMagic(magic) != 0; +} + +bool ObjectFileAIXCore::ParseHeader() { + + return false; +} + +ByteOrder ObjectFileAIXCore::GetByteOrder() const { + return eByteOrderBig; +} + +bool ObjectFileAIXCore::IsExecutable() const { + return false; +} + +uint32_t ObjectFileAIXCore::GetAddressByteSize() const { + return 8; +} + +AddressClass ObjectFileAIXCore::GetAddressClass(addr_t file_addr) { + return AddressClass::eUnknown; +} + +lldb::SymbolType ObjectFileAIXCore::MapSymbolType(llvm::object::SymbolRef::Type sym_type) { + if (sym_type == llvm::object::SymbolRef::ST_Function) + return lldb::eSymbolTypeCode; + else if (sym_type == llvm::object::SymbolRef::ST_Data) + return lldb::eSymbolTypeData; + return lldb::eSymbolTypeInvalid; +} + +void ObjectFileAIXCore::ParseSymtab(Symtab &lldb_symtab) { +} + +bool ObjectFileAIXCore::IsStripped() { + return false; +} + +void ObjectFileAIXCore::CreateSections(SectionList &unified_section_list) { +} + +void ObjectFileAIXCore::Dump(Stream *s) { +} + +ArchSpec ObjectFileAIXCore::GetArchitecture() { + ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + return arch_spec; +} + +UUID ObjectFileAIXCore::GetUUID() { + return UUID(); +} + +uint32_t ObjectFileAIXCore::GetDependentModules(FileSpecList &files) { + + auto original_size = files.GetSize(); + return files.GetSize() - original_size; +} + +Address ObjectFileAIXCore::GetImageInfoAddress(Target *target) { + return Address(); +} + +lldb_private::Address ObjectFileAIXCore::GetBaseAddress() { + return lldb_private::Address(); +} +ObjectFile::Type ObjectFileAIXCore::CalculateType() { + return eTypeCoreFile; +} + +ObjectFile::Strata ObjectFileAIXCore::CalculateStrata() { + return eStrataUnknown; +} + +std::vector +ObjectFileAIXCore::GetLoadableData(Target &target) { + std::vector loadables; + return loadables; +} + +lldb::WritableDataBufferSP +ObjectFileAIXCore::MapFileDataWritable(const FileSpec &file, uint64_t Size, + uint64_t Offset) { + return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size, + Offset); +} + +ObjectFileAIXCore::ObjectFileAIXCore(const lldb::ModuleSP &module_sp, + DataBufferSP data_sp, lldb::offset_t data_offset, + const FileSpec *file, lldb::offset_t file_offset, + lldb::offset_t length) + : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset) + { + if (file) + m_file = *file; +} + +ObjectFileAIXCore::ObjectFileAIXCore(const lldb::ModuleSP &module_sp, + DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, + addr_t header_addr) + : ObjectFile(module_sp, process_sp, header_addr, header_data_sp) + { +} diff --git a/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.h b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.h new file mode 100644 index 0000000000000..5dbd78d919bb6 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.h @@ -0,0 +1,121 @@ +//===-- ObjectFileAIXCore.h --------------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_AIXCORE_OBJECTFILEAIXCORE_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_AIXCORE_OBJECTFILEAIXCORE_H + +#include + +#include + +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/UUID.h" +#include "lldb/lldb-private.h" +#include "llvm/Object/XCOFFObjectFile.h" + +/// \class ObjectFileAIXCore +/// Generic AIX CORE object file reader. +/// +/// This class provides a generic AIX Core (32/64 bit) reader plugin implementing +/// the ObjectFile protocol. +class ObjectFileAIXCore : public lldb_private::ObjectFile { +public: + // Static Functions + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "aix-core-obj"; } + + static llvm::StringRef GetPluginDescriptionStatic() { + return "AIX core object file reader."; + } + + static lldb_private::ObjectFile * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length); + + static lldb_private::ObjectFile *CreateMemoryInstance( + const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + + static size_t GetModuleSpecifications(const lldb_private::FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + lldb_private::ModuleSpecList &specs); + + static bool MagicBytesMatch(lldb::DataBufferSP &data_sp, lldb::addr_t offset, + lldb::addr_t length); + + static lldb::SymbolType MapSymbolType(llvm::object::SymbolRef::Type sym_type); + + // PluginInterface protocol + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + // ObjectFile Protocol. + bool ParseHeader() override; + + lldb::ByteOrder GetByteOrder() const override; + + bool IsExecutable() const override; + + uint32_t GetAddressByteSize() const override; + + lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override; + + void ParseSymtab(lldb_private::Symtab &symtab) override; + + bool IsStripped() override; + + void CreateSections(lldb_private::SectionList &unified_section_list) override; + + void Dump(lldb_private::Stream *s) override; + + lldb_private::ArchSpec GetArchitecture() override; + + lldb_private::UUID GetUUID() override; + + uint32_t GetDependentModules(lldb_private::FileSpecList &files) override; + + lldb_private::Address + GetImageInfoAddress(lldb_private::Target *target) override; + lldb_private::Address GetBaseAddress() override; + + ObjectFile::Type CalculateType() override; + + ObjectFile::Strata CalculateStrata() override; + + ObjectFileAIXCore(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + ObjectFileAIXCore(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + +protected: + + static bool ParseAIXCoreHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr + ); + + std::vector + GetLoadableData(lldb_private::Target &target) override; + + static lldb::WritableDataBufferSP + MapFileDataWritable(const lldb_private::FileSpec &file, uint64_t Size, + uint64_t Offset); + +}; + +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_AIXCORE_OBJECTFILEAIXCORE_H diff --git a/lldb/source/Plugins/ObjectFile/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/CMakeLists.txt index 7abd0c96f4fd7..1605356fdb7f1 100644 --- a/lldb/source/Plugins/ObjectFile/CMakeLists.txt +++ b/lldb/source/Plugins/ObjectFile/CMakeLists.txt @@ -9,3 +9,4 @@ add_subdirectory(PECOFF) add_subdirectory(XCOFF) add_subdirectory(Placeholder) add_subdirectory(wasm) +add_subdirectory(AIXCore) diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt index 058b4b9ad2157..0b66ea18c82ce 100644 --- a/lldb/source/Plugins/Process/CMakeLists.txt +++ b/lldb/source/Plugins/Process/CMakeLists.txt @@ -24,3 +24,4 @@ add_subdirectory(elf-core) add_subdirectory(mach-core) add_subdirectory(minidump) add_subdirectory(FreeBSDKernel) +add_subdirectory(aix-core) diff --git a/lldb/source/Plugins/Process/aix-core/AIXCore.cpp b/lldb/source/Plugins/Process/aix-core/AIXCore.cpp new file mode 100644 index 0000000000000..95e47b4d8be53 --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/AIXCore.cpp @@ -0,0 +1,116 @@ +//===-- AIXCore.cpp ------------------------------------------------===// +// +// 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 + +#include "lldb/Core/Section.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" + +#include "AIXCore.h" + +using namespace AIXCORE; +using namespace lldb; +using namespace lldb_private; + +AIXCore64Header::AIXCore64Header() { memset(this, 0, sizeof(AIXCore64Header)); } + + +bool AIXCore64Header::ParseRegisterContext(lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + // The data is arranged in this order in this coredump file + // so we have to fetch in this exact order. But need to change + // the context structure order according to Infos_ppc64 + for(int i = 0; i < 32; i++) + Fault.context.gpr[i] = data.GetU64(offset); + Fault.context.msr = data.GetU64(offset); + Fault.context.pc = data.GetU64(offset); + Fault.context.lr = data.GetU64(offset); + Fault.context.ctr = data.GetU64(offset); + Fault.context.cr = data.GetU32(offset); + Fault.context.xer = data.GetU32(offset); + Fault.context.fpscr = data.GetU32(offset); + Fault.context.fpscrx = data.GetU32(offset); + Fault.context.except[0] = data.GetU64(offset); + for(int i = 0; i < 32; i++) + Fault.context.fpr[i] = data.GetU64(offset); + Fault.context.fpeu = data.GetU8(offset); + Fault.context.fpinfo = data.GetU8(offset); + Fault.context.fpscr24_31 = data.GetU8(offset); + Fault.context.pad[0] = data.GetU8(offset); + Fault.context.excp_type = data.GetU32(offset); + + return true; +} +bool AIXCore64Header::ParseThreadContext(lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + + lldb::offset_t offset_to_regctx = *offset; + offset_to_regctx += sizeof(thrdentry64); + Fault.thread.ti_tid = data.GetU64(offset); + Fault.thread.ti_pid = data.GetU32(offset); + int ret = ParseRegisterContext(data, &offset_to_regctx); + return true; +} + +bool AIXCore64Header::ParseUserData(lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + User.process.pi_pid = data.GetU32(offset); + User.process.pi_ppid = data.GetU32(offset); + User.process.pi_sid = data.GetU32(offset); + User.process.pi_pgrp = data.GetU32(offset); + User.process.pi_uid = data.GetU32(offset); + User.process.pi_suid = data.GetU32(offset); + + *offset += 76; + + ByteOrder byteorder = data.GetByteOrder(); + size_t size = 33; + data.ExtractBytes(*offset, size, byteorder, User.process.pi_comm); + offset += size; + + return true; +} + +bool AIXCore64Header::ParseCoreHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + + SignalNum = data.GetU8(offset); + Flag = data.GetU8(offset); + Entries = data.GetU16(offset); + Version = data.GetU32(offset); + FDInfo = data.GetU64(offset); + + LoaderOffset = data.GetU64(offset); + LoaderSize = data.GetU64(offset); + NumberOfThreads = data.GetU32(offset); + Reserved0 = data.GetU32(offset); + ThreadContextOffset = data.GetU64(offset); + NumSegRegion = data.GetU64(offset); + SegRegionOffset = data.GetU64(offset); + StackOffset = data.GetU64(offset); + StackBaseAddr = data.GetU64(offset); + StackSize = data.GetU64(offset); + DataRegionOffset = data.GetU64(offset); + DataBaseAddr = data.GetU64(offset); + DataSize = data.GetU64(offset); + + *offset += 104; + lldb::offset_t offset_to_user = (*offset + sizeof(ThreadContext64)); + int ret = 0; + ret = ParseThreadContext(data, offset); + ret = ParseUserData(data, &offset_to_user); + + return true; + +} + diff --git a/lldb/source/Plugins/Process/aix-core/AIXCore.h b/lldb/source/Plugins/Process/aix-core/AIXCore.h new file mode 100644 index 0000000000000..3d78d5e92c7ab --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/AIXCore.h @@ -0,0 +1,125 @@ +//===-- AIXCore.h ----------------------------------------*- 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 +// +// Notes about AIX Process core dumps: +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_AIXCORE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_AIXCORE_H + +#include "llvm/ADT/StringRef.h" +#include +#include +#include + +#include +#include + +namespace AIXCORE { + +struct RegContext { + // The data is arranged in order as filled by AIXCore.cpp in this coredump file + // so we have to fetch in that exact order, refer there. + // But need to change + // the context structure in order according to Infos_ppc64 + uint64_t gpr[32]; /* 64-bit gprs */ + unsigned long pc; /* msr */ + unsigned long msr; /* iar */ + unsigned long origr3; /* iar */ + unsigned long ctr; /* CTR */ + unsigned long lr; /* LR */ + unsigned long xer; /* XER */ + unsigned long cr; /* CR */ + unsigned long softe; /* CR */ + unsigned long trap; /* CR */ + unsigned int fpscr; /* floating pt status reg */ + unsigned int fpscrx; /* software ext to fpscr */ + unsigned long except[1]; /* exception address */ + double fpr[32]; /* floating pt regs */ + char fpeu; /* floating pt ever used */ + char fpinfo; /* floating pt info */ + char fpscr24_31; /* bits 24-31 of 64-bit FPSCR */ + char pad[1]; + int excp_type; /* exception type */ +}; + + struct ThreadContext64 { + struct thrdentry64 thread; + struct RegContext context; + }; + + struct UserData { + + struct procentry64 process; + unsigned long long reserved[16]; + }; + + struct AIXCore64Header { + + int8_t SignalNum; /* signal number (cause of error) */ + int8_t Flag; /* flag to describe core dump type */ + uint16_t Entries; /* number of core dump modules */ + uint32_t Version; /* core file format number */ + uint64_t FDInfo; /* offset to fd region in file */ + + uint64_t LoaderOffset; /* offset to loader region in file */ + uint64_t LoaderSize; /* size of loader region */ + + uint32_t NumberOfThreads ; /* number of elements in thread table */ + uint32_t Reserved0; /* Padding */ + uint64_t ThreadContextOffset; /* offset to thread context table */ + + uint64_t NumSegRegion; /* n of elements in segregion */ + uint64_t SegRegionOffset; /* offset to start of segregion table */ + + uint64_t StackOffset; /* offset of user stack in file */ + uint64_t StackBaseAddr; /* base address of user stack region */ + uint64_t StackSize; /* size of user stack region */ + + uint64_t DataRegionOffset; /* offset to user data region */ + uint64_t DataBaseAddr; /* base address of user data region */ + uint64_t DataSize; /* size of user data region */ + uint64_t SDataBase; /* base address of sdata region */ + uint64_t SDataSize; /* size of sdata region */ + + uint64_t NumVMRegions; /* number of anonymously mapped areas */ + uint64_t VMOffset; /* offset to start of vm_infox table */ + + int32_t ProcessorImplementation; /* processor implementation */ + uint32_t NumElementsCTX; /* n of elements in extended ctx table*/ + uint64_t CPRSOffset; /* Checkpoint/Restart offset */ + uint64_t ExtendedContextOffset; /* extended context offset */ + uint64_t OffsetUserKey; /* Offset to user-key exception data */ + uint64_t OffsetLoaderTLS; /* offset to the loader region in file + when a process uses TLS data */ + uint64_t TLSLoaderSize; /* size of the above loader region */ + uint64_t ExtendedProcEntry; /* Extended procentry64 information */ + uint64_t Reserved[2]; + + struct ThreadContext64 Fault; + + struct UserData User; + + AIXCore64Header(); + + bool ParseCoreHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + bool ParseThreadContext(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + bool ParseUserData(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + bool ParseRegisterContext(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + bool ParseLoaderData(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + + }; + + +} + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_AIXCORE_H diff --git a/lldb/source/Plugins/Process/aix-core/CMakeLists.txt b/lldb/source/Plugins/Process/aix-core/CMakeLists.txt new file mode 100644 index 0000000000000..347717a362491 --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/CMakeLists.txt @@ -0,0 +1,16 @@ +add_definitions("-D_ALL_SOURCE") + +add_lldb_library(lldbPluginProcessAIXCore PLUGIN + ProcessAIXCore.cpp + AIXCore.cpp + ThreadAIXCore.cpp + RegisterContextCoreAIX_ppc64.cpp + + LINK_LIBS + lldbCore + lldbTarget + lldbPluginProcessUtility + LINK_COMPONENTS + BinaryFormat + Support + ) diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp new file mode 100644 index 0000000000000..9300aa14ac4db --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp @@ -0,0 +1,251 @@ +//===-- ProcessAIXCore.cpp ------------------------------------------------===// +// +// 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 + +#include +#include + +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Section.h" +#include "lldb/Target/ABI.h" +#include "lldb/Target/DynamicLoader.h" +#include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/UnixSignals.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" + +#include "llvm/Support/Threading.h" +#include "Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h" + +#include "ProcessAIXCore.h" +#include "AIXCore.h" +#include "ThreadAIXCore.h" + +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ProcessAIXCore) + +llvm::StringRef ProcessAIXCore::GetPluginDescriptionStatic() { + return "AIX core dump plug-in."; +} + +void ProcessAIXCore::Initialize() { + static llvm::once_flag g_once_flag; + + llvm::call_once(g_once_flag, []() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); + }); +} + +void ProcessAIXCore::Terminate() { + PluginManager::UnregisterPlugin(ProcessAIXCore::CreateInstance); +} + +lldb::ProcessSP ProcessAIXCore::CreateInstance(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const FileSpec *crash_file, + bool can_connect) { + lldb::ProcessSP process_sp; + if (crash_file && !can_connect) { + const size_t header_size = sizeof(AIXCORE::AIXCore64Header); + + auto data_sp = FileSystem::Instance().CreateDataBuffer( + crash_file->GetPath(), header_size, 0); + + if (data_sp && data_sp->GetByteSize() == header_size) { + AIXCORE::AIXCore64Header aixcore_header; + DataExtractor data(data_sp, lldb::eByteOrderBig, 4); + lldb::offset_t data_offset = 0; + if(aixcore_header.ParseCoreHeader(data, &data_offset)) { + process_sp = std::make_shared(target_sp, listener_sp, + *crash_file); + } + } + + } + return process_sp; +} + +// ProcessAIXCore constructor +ProcessAIXCore::ProcessAIXCore(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const FileSpec &core_file) + : PostMortemProcess(target_sp, listener_sp, core_file) {} + +// Destructor +ProcessAIXCore::~ProcessAIXCore() { + Clear(); + // We need to call finalize on the process before destroying ourselves to + // make sure all of the broadcaster cleanup goes as planned. If we destruct + // this class, then Process::~Process() might have problems trying to fully + // destroy the broadcaster. + Finalize(true /* destructing */); +} + +bool ProcessAIXCore::CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) { + + if (!m_core_module_sp && FileSystem::Instance().Exists(m_core_file)) { + ModuleSpec core_module_spec(m_core_file, target_sp->GetArchitecture()); + Status error(ModuleList::GetSharedModule(core_module_spec, m_core_module_sp, + nullptr, nullptr, nullptr)); + if (m_core_module_sp) { + ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); + if (core_objfile && core_objfile->GetType() == ObjectFile::eTypeCoreFile){ + return true; + } + } + } + return false; + +} + +ArchSpec ProcessAIXCore::GetArchitecture() { + + ArchSpec arch = m_core_module_sp->GetObjectFile()->GetArchitecture(); + + ArchSpec target_arch = GetTarget().GetArchitecture(); + arch.MergeFrom(target_arch); + + return arch; +} + +lldb_private::DynamicLoader *ProcessAIXCore::GetDynamicLoader() { + if (m_dyld_up.get() == nullptr) { + m_dyld_up.reset(DynamicLoader::FindPlugin( + this, DynamicLoaderAIXDYLD::GetPluginNameStatic())); + } + return m_dyld_up.get(); +} + +void ProcessAIXCore::ParseAIXCoreFile() { + + Log *log = GetLog(LLDBLog::Process); + AIXSigInfo siginfo; + ThreadData thread_data; + + const lldb_private::UnixSignals &unix_signals = *GetUnixSignals(); + const ArchSpec &arch = GetArchitecture(); + + siginfo.Parse(m_aixcore_header, arch, unix_signals); + thread_data.siginfo = siginfo; + SetID(m_aixcore_header.User.process.pi_pid); + + thread_data.name.assign (m_aixcore_header.User.process.pi_comm, + strnlen (m_aixcore_header.User.process.pi_comm, + sizeof (m_aixcore_header.User.process.pi_comm))); + + lldb::DataBufferSP data_buffer_sp(new lldb_private::DataBufferHeap(sizeof(m_aixcore_header.Fault.context), 0)); + + memcpy(static_cast(const_cast(data_buffer_sp->GetBytes())), + &m_aixcore_header.Fault.context, sizeof(m_aixcore_header.Fault.context)); + + lldb_private::DataExtractor data(data_buffer_sp, lldb::eByteOrderBig, 8); + + thread_data.gpregset = DataExtractor(data, 0, sizeof(m_aixcore_header.Fault.context)); + m_thread_data.push_back(thread_data); + LLDB_LOGF(log, "ProcessAIXCore: Parsing Complete!"); + +} + +// Process Control +Status ProcessAIXCore::DoLoadCore() { + + Status error; + if (!m_core_module_sp) { + error = Status::FromErrorString("invalid core module"); + return error; + } + + FileSpec file = m_core_module_sp->GetObjectFile()->GetFileSpec(); + + if (file) { + const size_t header_size = sizeof(AIXCORE::AIXCore64Header); + auto data_sp = FileSystem::Instance().CreateDataBuffer( + file.GetPath(), -1, 0); + if (data_sp && data_sp->GetByteSize() != 0) { + + DataExtractor data(data_sp, lldb::eByteOrderBig, 4); + lldb::offset_t data_offset = 0; + m_aixcore_header.ParseCoreHeader(data, &data_offset); + auto dyld = static_cast(GetDynamicLoader()); + dyld->FillCoreLoaderData(data, m_aixcore_header.LoaderOffset, + m_aixcore_header.LoaderSize); + + } else { + error = Status::FromErrorString("invalid data"); + return error; + } + } else { + error = Status::FromErrorString("invalid file"); + return error; + } + + m_thread_data_valid = true; + ParseAIXCoreFile(); + ArchSpec arch(m_core_module_sp->GetArchitecture()); + + ArchSpec target_arch = GetTarget().GetArchitecture(); + ArchSpec core_arch(m_core_module_sp->GetArchitecture()); + target_arch.MergeFrom(core_arch); + GetTarget().SetArchitecture(target_arch); + + lldb::ModuleSP exe_module_sp = GetTarget().GetExecutableModule(); + if (!exe_module_sp) { + ModuleSpec exe_module_spec; + exe_module_spec.GetArchitecture() = arch; + exe_module_spec.GetFileSpec().SetFile(m_aixcore_header.User.process.pi_comm, + FileSpec::Style::native); + exe_module_sp = GetTarget().GetOrCreateModule(exe_module_spec, true); + GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsNo); + } + + return error; +} + +bool ProcessAIXCore::DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) +{ + const ThreadData &td = m_thread_data[0]; + + lldb::ThreadSP thread_sp = + std::make_shared(*this, td); + new_thread_list.AddThread(thread_sp); + + return true; +} + +void ProcessAIXCore::RefreshStateAfterStop() {} + +// Process Memory +size_t ProcessAIXCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size, + Status &error) { + if (lldb::ABISP abi_sp = GetABI()) + addr = abi_sp->FixAnyAddress(addr); + + // Don't allow the caching that lldb_private::Process::ReadMemory does since + // in core files we have it all cached our our core file anyway. + return DoReadMemory(addr, buf, size, error); +} + +size_t ProcessAIXCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, + Status &error) { return 0; } + +Status ProcessAIXCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo ®ion_info) { + return Status(); +} + +Status ProcessAIXCore::DoDestroy() { return Status(); } diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h new file mode 100644 index 0000000000000..9880c491689ca --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h @@ -0,0 +1,100 @@ +//===-- ProcessAIXCore.h ----------------------------------------*- 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 +// +// Notes about AIX Process core dumps: +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_PROCESSAIXCORE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_PROCESSAIXCORE_H + +#include +#include + +#include "lldb/Target/PostMortemProcess.h" +#include "lldb/Utility/Status.h" +#include "lldb/Target/Process.h" +#include "AIXCore.h" +#include "ThreadAIXCore.h" + +struct ThreadData; + +class ProcessAIXCore : public lldb_private::PostMortemProcess { +public: + // Constructors and Destructors + static lldb::ProcessSP + CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, + const lldb_private::FileSpec *crash_file_path, + bool can_connect); + + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "aix-core"; } + + static llvm::StringRef GetPluginDescriptionStatic(); + + // Constructors and Destructors + ProcessAIXCore(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, + const lldb_private::FileSpec &core_file); + + ~ProcessAIXCore() override; + + // PluginInterface protocol + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + // Process Control + lldb_private::Status DoDestroy() override; + + lldb_private::Status WillResume() override { + return lldb_private::Status::FromErrorStringWithFormatv( + "error: {0} does not support resuming processes", GetPluginName()); + } + + bool WarnBeforeDetach() const override { return false; } + + lldb_private::ArchSpec GetArchitecture(); + + bool CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) override; + + // Creating a new process, or attaching to an existing one + lldb_private::Status DoLoadCore() override; + + bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list, + lldb_private::ThreadList &new_thread_list) override; + + lldb_private::Status + DoGetMemoryRegionInfo(lldb::addr_t load_addr, + lldb_private::MemoryRegionInfo ®ion_info) override; + + void RefreshStateAfterStop() override; + + lldb_private::DynamicLoader *GetDynamicLoader() override; + + // Process Memory + size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size, + lldb_private::Status &error) override; + + size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, + lldb_private::Status &error) override; + + void ParseAIXCoreFile(); + + +private: + lldb::ModuleSP m_core_module_sp; + std::string m_dyld_plugin_name; + + // True if m_thread_contexts contains valid entries + bool m_thread_data_valid = false; + AIXCORE::AIXCore64Header m_aixcore_header; + + std::vector m_thread_data; +}; + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_PROCESSAIXCORE_H diff --git a/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.cpp b/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.cpp new file mode 100644 index 0000000000000..b243017bf9a2a --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.cpp @@ -0,0 +1,136 @@ +//===-- RegisterContextCoreAIX_ppc64.cpp ------------------------------===// +// +// 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 "RegisterContextCoreAIX_ppc64.h" + +#include "lldb/Target/Thread.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" + +#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" +#include "Plugins/Process/elf-core/RegisterUtilities.h" + +#include + +using namespace lldb_private; + +RegisterContextCoreAIX_ppc64::RegisterContextCoreAIX_ppc64( + Thread &thread, RegisterInfoInterface *register_info, + const DataExtractor &gpregset) + : RegisterContextPOSIX_ppc64le(thread, 0, register_info) { + m_gpr_buffer = std::make_shared(gpregset.GetDataStart(), + gpregset.GetByteSize()); + m_gpr.SetData(m_gpr_buffer); + m_gpr.SetByteOrder(gpregset.GetByteOrder()); + + // This Code is for Registers like FPR, VSR, VMX and is disabled right now. + // It will be implemented as per need. + + /* ArchSpec arch = register_info->GetTargetArchitecture(); + DataExtractor fpregset;// = getRegset(notes, arch.GetTriple(), FPR_Desc); + m_fpr_buffer = std::make_shared(fpregset.GetDataStart(), + fpregset.GetByteSize()); + m_fpr.SetData(m_fpr_buffer); + m_fpr.SetByteOrder(fpregset.GetByteOrder()); + + DataExtractor vmxregset;// = getRegset(notes, arch.GetTriple(), PPC_VMX_Desc); + m_vmx_buffer = std::make_shared(vmxregset.GetDataStart(), + vmxregset.GetByteSize()); + m_vmx.SetData(m_vmx_buffer); + m_vmx.SetByteOrder(vmxregset.GetByteOrder()); + + DataExtractor vsxregset;// = getRegset(notes, arch.GetTriple(), PPC_VSX_Desc); + m_vsx_buffer = std::make_shared(vsxregset.GetDataStart(), + vsxregset.GetByteSize()); + m_vsx.SetData(m_vsx_buffer); + m_vsx.SetByteOrder(vsxregset.GetByteOrder());*/ +} + +size_t RegisterContextCoreAIX_ppc64::GetFPRSize() const { + return k_num_fpr_registers_ppc64le * sizeof(uint64_t); +} + +size_t RegisterContextCoreAIX_ppc64::GetVMXSize() const { + return (k_num_vmx_registers_ppc64le - 1) * sizeof(uint64_t) * 2 + + sizeof(uint32_t); +} + +size_t RegisterContextCoreAIX_ppc64::GetVSXSize() const { + return k_num_vsx_registers_ppc64le * sizeof(uint64_t) * 2; +} + +bool RegisterContextCoreAIX_ppc64::ReadRegister( + const RegisterInfo *reg_info, RegisterValue &value) { + lldb::offset_t offset = reg_info->byte_offset; + + if (IsFPR(reg_info->kinds[lldb::eRegisterKindLLDB])) { + uint64_t v; + offset -= GetGPRSize(); + offset = m_fpr.CopyData(offset, reg_info->byte_size, &v); + + if (offset == reg_info->byte_size) { + value.SetBytes(&v, reg_info->byte_size, m_fpr.GetByteOrder()); + return true; + } + } else if (IsVMX(reg_info->kinds[lldb::eRegisterKindLLDB])) { + uint32_t v[4]; + offset -= GetGPRSize() + GetFPRSize(); + offset = m_vmx.CopyData(offset, reg_info->byte_size, &v); + + if (offset == reg_info->byte_size) { + value.SetBytes(v, reg_info->byte_size, m_vmx.GetByteOrder()); + return true; + } + } else if (IsVSX(reg_info->kinds[lldb::eRegisterKindLLDB])) { + uint32_t v[4]; + lldb::offset_t tmp_offset; + offset -= GetGPRSize() + GetFPRSize() + GetVMXSize(); + + if (offset < GetVSXSize() / 2) { + tmp_offset = m_vsx.CopyData(offset / 2, reg_info->byte_size / 2, &v); + + if (tmp_offset != reg_info->byte_size / 2) { + return false; + } + + uint8_t *dst = (uint8_t *)&v + sizeof(uint64_t); + tmp_offset = m_fpr.CopyData(offset / 2, reg_info->byte_size / 2, dst); + + if (tmp_offset != reg_info->byte_size / 2) { + return false; + } + + value.SetBytes(&v, reg_info->byte_size, m_vsx.GetByteOrder()); + return true; + } else { + offset = + m_vmx.CopyData(offset - GetVSXSize() / 2, reg_info->byte_size, &v); + if (offset == reg_info->byte_size) { + value.SetBytes(v, reg_info->byte_size, m_vmx.GetByteOrder()); + return true; + } + } + } else { + uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); + + if (offset == reg_info->byte_offset + reg_info->byte_size) { + if (reg_info->byte_size < sizeof(v)) + value = (uint32_t)v; + else + value = v; + return true; + } + } + + return false; +} + +bool RegisterContextCoreAIX_ppc64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue &value) { + return false; +} diff --git a/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.h b/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.h new file mode 100644 index 0000000000000..8f1f71ce8d884 --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.h @@ -0,0 +1,46 @@ +//===-- RegisterContextCoreAIX_ppc64.h ----------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_REGISTERCONTEXTAIXCORE_PPC64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_REGISTERCONTEXTAIXCORE_PPC64_H + +#include "Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h" +#include "lldb/Utility/DataExtractor.h" + +class RegisterContextCoreAIX_ppc64 : public RegisterContextPOSIX_ppc64le { +public: + RegisterContextCoreAIX_ppc64( + lldb_private::Thread &thread, + lldb_private::RegisterInfoInterface *register_info, + const lldb_private::DataExtractor &gpregset); + + bool ReadRegister(const lldb_private::RegisterInfo *reg_info, + lldb_private::RegisterValue &value) override; + + bool WriteRegister(const lldb_private::RegisterInfo *reg_info, + const lldb_private::RegisterValue &value) override; + +protected: + size_t GetFPRSize() const; + + size_t GetVMXSize() const; + + size_t GetVSXSize() const; + +private: + lldb::DataBufferSP m_gpr_buffer; + lldb::DataBufferSP m_fpr_buffer; + lldb::DataBufferSP m_vmx_buffer; + lldb::DataBufferSP m_vsx_buffer; + lldb_private::DataExtractor m_gpr; + lldb_private::DataExtractor m_fpr; + lldb_private::DataExtractor m_vmx; + lldb_private::DataExtractor m_vsx; +}; + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_REGISTERCONTEXTAIXCORE_PPC64_H diff --git a/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.cpp b/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.cpp new file mode 100644 index 0000000000000..979e5199fe24d --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.cpp @@ -0,0 +1,127 @@ +//===-- ThreadAIXCore.cpp -------------------------------------------------===// +// +// 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 "lldb/Target/RegisterContext.h" +#include "lldb/Target/StopInfo.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/UnixSignals.h" +#include "lldb/Target/Unwind.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/ProcessInfo.h" + +#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h" +#include "Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h" +#include "RegisterContextCoreAIX_ppc64.h" + +#include "ProcessAIXCore.h" +#include "AIXCore.h" +#include "ThreadAIXCore.h" + +#include +#include + +using namespace lldb; +using namespace lldb_private; + +// Construct a Thread object with given data +ThreadAIXCore::ThreadAIXCore(Process &process, const ThreadData &td) + : Thread(process, td.tid), m_thread_name(td.name), m_thread_reg_ctx_sp(), + m_gpregset_data(td.gpregset), + m_siginfo(std::move(td.siginfo)) {} + +ThreadAIXCore::~ThreadAIXCore() { DestroyThread(); } + +void ThreadAIXCore::RefreshStateAfterStop() { + GetRegisterContext()->InvalidateIfNeeded(false); +} + +RegisterContextSP ThreadAIXCore::GetRegisterContext() { + if (!m_reg_context_sp) { + m_reg_context_sp = CreateRegisterContextForFrame(nullptr); + } + return m_reg_context_sp; +} + +RegisterContextSP +ThreadAIXCore::CreateRegisterContextForFrame(StackFrame *frame) { + RegisterContextSP reg_ctx_sp; + uint32_t concrete_frame_idx = 0; + + if (frame) + concrete_frame_idx = frame->GetConcreteFrameIndex(); + + bool is_linux = false; + if (concrete_frame_idx == 0) { + if (m_thread_reg_ctx_sp) + return m_thread_reg_ctx_sp; + + ProcessAIXCore *process = static_cast(GetProcess().get()); + ArchSpec arch = process->GetArchitecture(); + RegisterInfoInterface *reg_interface = nullptr; + + switch (arch.GetMachine()) { + case llvm::Triple::ppc64: + reg_interface = new RegisterInfoPOSIX_ppc64le(arch); + m_thread_reg_ctx_sp = std::make_shared( + *this, reg_interface, m_gpregset_data); + break; + default: + break; + } + reg_ctx_sp = m_thread_reg_ctx_sp; + } else { + reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame); + } + return reg_ctx_sp; +} + +bool ThreadAIXCore::CalculateStopInfo() { + ProcessSP process_sp(GetProcess()); + if (!process_sp) + return false; + + lldb::UnixSignalsSP unix_signals_sp(process_sp->GetUnixSignals()); + if (!unix_signals_sp) + return false; + + const char *sig_description; + std::string description = m_siginfo.GetDescription(*unix_signals_sp); + if (description.empty()) + sig_description = nullptr; + else + sig_description = description.c_str(); + + SetStopInfo(StopInfo::CreateStopReasonWithSignal( + *this, m_siginfo.si_signo, sig_description, m_siginfo.si_code)); + + SetStopInfo(m_stop_info_sp); + return true; +} + +void AIXSigInfo::Parse(const AIXCORE::AIXCore64Header data, const ArchSpec &arch, + const lldb_private::UnixSignals &unix_signals) { + si_signo = data.SignalNum; + sigfault.si_addr = data.Fault.context.pc; +} + +AIXSigInfo::AIXSigInfo() { memset(this, 0, sizeof(AIXSigInfo)); } + +size_t AIXSigInfo::GetSize(const lldb_private::ArchSpec &arch) { + return sizeof(AIXSigInfo); +} + +std::string AIXSigInfo::GetDescription( + const lldb_private::UnixSignals &unix_signals) const { + return unix_signals.GetSignalDescription(si_signo, 0, + sigfault.si_addr); + +} diff --git a/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.h b/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.h new file mode 100644 index 0000000000000..9ee157e9b2b9b --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.h @@ -0,0 +1,110 @@ +//===-- ThreadAIXCore.h -----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_THREADAIXCORE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_THREADAIXCORE_H + +#include "lldb/Target/Thread.h" +#include "lldb/Utility/DataExtractor.h" +#include "llvm/ADT/DenseMap.h" +#include +#include +#include "ProcessAIXCore.h" +#include "AIXCore.h" +#include "ThreadAIXCore.h" + +namespace lldb_private { +class ProcessInstanceInfo; +} + +struct AIXSigInfo { + + //COPY siginfo_t correctly for AIX version + int32_t si_signo; // Order matters for the first 3. + int32_t si_errno; + int32_t si_code; + struct alignas(8) { + lldb::addr_t si_addr; + int16_t si_addr_lsb; + union { + struct { + lldb::addr_t _lower; + lldb::addr_t _upper; + } _addr_bnd; + uint32_t _pkey; + } bounds; + } sigfault; + + enum SigInfoNoteType : uint8_t { eUnspecified, eNT_SIGINFO }; + SigInfoNoteType note_type; + + AIXSigInfo(); + + void Parse(const AIXCORE::AIXCore64Header data, + const lldb_private::ArchSpec &arch, + const lldb_private::UnixSignals &unix_signals); + + std::string + GetDescription(const lldb_private::UnixSignals &unix_signals) const; + + static size_t GetSize(const lldb_private::ArchSpec &arch); +}; + +struct ThreadData { + lldb_private::DataExtractor gpregset; + std::vector notes; + lldb::tid_t tid; + std::string name; + AIXSigInfo siginfo; + int prstatus_sig = 0; +}; + +class ThreadAIXCore : public lldb_private::Thread { +public: + ThreadAIXCore(lldb_private::Process &process, const ThreadData &td); + + ~ThreadAIXCore() override; + + void RefreshStateAfterStop() override; + + lldb::RegisterContextSP GetRegisterContext() override; + + lldb::RegisterContextSP + CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override; + + static bool ThreadIDIsValid(lldb::tid_t thread) { return thread != 0; } + + const char *GetName() override { + if (m_thread_name.empty()) + return nullptr; + return m_thread_name.c_str(); + } + + void SetName(const char *name) override { + if (name && name[0]) + m_thread_name.assign(name); + else + m_thread_name.clear(); + } + + void CreateStopFromSigInfo(const AIXSigInfo &siginfo, + const lldb_private::UnixSignals &unix_signals); + +protected: + // Member variables. + std::string m_thread_name; + lldb::RegisterContextSP m_thread_reg_ctx_sp; + + lldb_private::DataExtractor m_gpregset_data; + std::vector m_notes; + AIXSigInfo m_siginfo; + + bool CalculateStopInfo() override; +}; + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_THREADAIXCORE_H >From 57cb8058646103eeada1f92e039d9c54ccd4788f Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 17 Mar 2025 07:31:26 -0500 Subject: [PATCH 40/47] Merge branch 'llvm:main' into llvmgh-101657 --- lldb/cmake/modules/LLDBConfig.cmake | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake index 312791ce36fc7..9df71edd8b359 100644 --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -292,11 +292,7 @@ endif() # Figure out if lldb could use lldb-server. If so, then we'll # ensure we build lldb-server when an lldb target is being built. -<<<<<<< HEAD -if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD|OpenBSD|Windows|AIX") -======= if (CMAKE_SYSTEM_NAME MATCHES "AIX|Android|Darwin|FreeBSD|Linux|NetBSD|OpenBSD|Windows") ->>>>>>> upstream/main set(LLDB_CAN_USE_LLDB_SERVER ON) else() set(LLDB_CAN_USE_LLDB_SERVER OFF) >From 0767ef036d3f82d1429e04a319feb6627ea08158 Mon Sep 17 00:00:00 2001 From: Dhruv Srivastava Date: Tue, 18 Mar 2025 15:03:17 +0530 Subject: [PATCH 41/47] Error Handling (#32) * Error Handling for aix core module --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 12 +++++++----- .../ObjectFile/AIXCore/ObjectFileAIXCore.cpp | 15 +++++++-------- lldb/source/Plugins/Process/aix-core/AIXCore.cpp | 2 +- .../Plugins/Process/aix-core/ProcessAIXCore.cpp | 11 ++++++++--- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 7e44ffbb1c051..12f24c049f373 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -235,17 +235,19 @@ bool DynamicLoaderAIXDYLD::IsCoreFile() const { void DynamicLoaderAIXDYLD::FillCoreLoaderData(lldb_private::DataExtractor &data, uint64_t loader_offset, uint64_t loader_size ) { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); static char *buffer = (char *)malloc(loader_size); - struct ld_info ldinfo[64]; - char *buffer_complete; + if (buffer == NULL) { + LLDB_LOG(log, "Buffer allocation failed error: {0}", std::strerror(errno)); + return; + } + struct ld_info ldinfo[64] = {}; struct ld_info *ptr; int i = 0; - Log *log = GetLog(LLDBLog::DynamicLoader); - LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); ByteOrder byteorder = data.GetByteOrder(); data.ExtractBytes(loader_offset, loader_size, eByteOrderBig, buffer); - buffer_complete = buffer + loader_size; ldinfo[0].ldinfo_next = 1; while (ldinfo[i++].ldinfo_next != 0) { diff --git a/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp index 5158fa4e25077..0ba1056866937 100644 --- a/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp +++ b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp @@ -73,8 +73,6 @@ ObjectFile *ObjectFileAIXCore::CreateInstance(const lldb::ModuleSP &module_sp, assert(data_sp); - const uint8_t *magic = data_sp->GetBytes() + data_offset; - // Update the data to contain the entire file if it doesn't already if (data_sp->GetByteSize() < length) { data_sp = MapFileDataWritable(*file, length, file_offset); @@ -82,7 +80,6 @@ ObjectFile *ObjectFileAIXCore::CreateInstance(const lldb::ModuleSP &module_sp, return nullptr; data_offset = 0; mapped_writable = true; - magic = data_sp->GetBytes(); } // If we didn't map the data as writable take ownership of the buffer. @@ -90,7 +87,6 @@ ObjectFile *ObjectFileAIXCore::CreateInstance(const lldb::ModuleSP &module_sp, data_sp = std::make_shared(data_sp->GetBytes(), data_sp->GetByteSize()); data_offset = 0; - magic = data_sp->GetBytes(); } std::unique_ptr objfile_up(new ObjectFileAIXCore( @@ -124,19 +120,22 @@ size_t ObjectFileAIXCore::GetModuleSpecifications( return specs.GetSize() - initial_count; } -static uint32_t AIXCoreHeaderCheckFromMagic(uint32_t magic) { +static bool AIXCoreHeaderCheckFromMagic(uint32_t magic) { Log *log = GetLog(LLDBLog::Modules); + bool ret = false; switch (magic) { case AIXCORE32: LLDB_LOGF(log, "ObjectFileAIXCore: 32-bit not supported"); break; case AIXCORE64: m_is_core = true; - return 1; + ret = true; + break; + default: break; } - return 0; + return ret; } bool ObjectFileAIXCore::MagicBytesMatch(DataBufferSP &data_sp, @@ -147,7 +146,7 @@ bool ObjectFileAIXCore::MagicBytesMatch(DataBufferSP &data_sp, lldb::offset_t offset = 0; offset += 4; // Skipping to the coredump version uint32_t magic = data.GetU32(&offset); - return AIXCoreHeaderCheckFromMagic(magic) != 0; + return AIXCoreHeaderCheckFromMagic(magic); } bool ObjectFileAIXCore::ParseHeader() { diff --git a/lldb/source/Plugins/Process/aix-core/AIXCore.cpp b/lldb/source/Plugins/Process/aix-core/AIXCore.cpp index 95e47b4d8be53..bc496b5af273f 100644 --- a/lldb/source/Plugins/Process/aix-core/AIXCore.cpp +++ b/lldb/source/Plugins/Process/aix-core/AIXCore.cpp @@ -110,7 +110,7 @@ bool AIXCore64Header::ParseCoreHeader(lldb_private::DataExtractor &data, ret = ParseThreadContext(data, offset); ret = ParseUserData(data, &offset_to_user); - return true; + return ret; } diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp index 9300aa14ac4db..cfcbe1a216116 100644 --- a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp @@ -208,8 +208,10 @@ Status ProcessAIXCore::DoLoadCore() { exe_module_spec.GetArchitecture() = arch; exe_module_spec.GetFileSpec().SetFile(m_aixcore_header.User.process.pi_comm, FileSpec::Style::native); - exe_module_sp = GetTarget().GetOrCreateModule(exe_module_spec, true); - GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsNo); + exe_module_sp = + GetTarget().GetOrCreateModule(exe_module_spec, true /* notify */); + if (exe_module_sp) + GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsNo); } return error; @@ -232,8 +234,11 @@ void ProcessAIXCore::RefreshStateAfterStop() {} // Process Memory size_t ProcessAIXCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size, Status &error) { + if(addr == LLDB_INVALID_ADDRESS) + return 0; + if (lldb::ABISP abi_sp = GetABI()) - addr = abi_sp->FixAnyAddress(addr); + addr = abi_sp->FixAnyAddress(addr); // Don't allow the caching that lldb_private::Process::ReadMemory does since // in core files we have it all cached our our core file anyway. >From 8214e5d8cc52b486d3c3f5f4615848b1782cfcf8 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 26 Mar 2025 01:34:36 -0500 Subject: [PATCH 42/47] Merge branch 'llvm:main' into gh-101657 --- lldb/source/Host/common/Host.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 575bb46216d19..6cf1112511c3f 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -20,7 +20,6 @@ #include #include #include -#endif #include #endif >From d00d28ae68c731efe6f9392000be9822ee74ff0a Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Wed, 26 Mar 2025 04:08:23 -0500 Subject: [PATCH 43/47] First time attach resolution --- .../Plugins/Process/AIX/NativeProcessAIX.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp index fc84763857453..83b8ae5eb3258 100644 --- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -2000,7 +2000,21 @@ Status NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid, void *addr, } else if (req == PT_WRITE_BLOCK) { ptrace64(req, pid, (long long)addr, (int)data_size, (int *)result); } else if (req == PT_ATTACH) { + // Block SIGCHLD signal during attach to the process, + // to prevent interruptions. + // The ptrace operation may send SIGCHLD signals in certain cases + // during the attach, which can interfere. + static sigset_t signal_set; + sigemptyset (&signal_set); + sigaddset (&signal_set, SIGCHLD); + if(!pthread_sigmask( SIG_BLOCK, &signal_set, NULL)) + LLDB_LOG(log,"NativeProcessAIX::pthread_sigmask(SIG_BLOCK) Failed"); + ptrace64(req, pid, 0, 0, nullptr); + + //Unblocking the SIGCHLD after attach work. + if(!pthread_sigmask( SIG_UNBLOCK, &signal_set, NULL )) + LLDB_LOG(log,"NativeProcessAIX::pthread_sigmask(SIG_UNBLOCK) Failed"); } else if (req == PT_WATCH) { ptrace64(req, pid, (long long)addr, (int)data_size, nullptr); } else if (req == PT_DETACH) { >From 9ff945e62a906e9711022bf8f77b86a0aa05c64e Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Tue, 1 Apr 2025 04:54:51 -0500 Subject: [PATCH 44/47] Invalid DWARF rangelist --- lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index cf11e5fb8f5a3..65bd1ee9781d8 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -578,6 +578,7 @@ SectionType ObjectFileXCOFF::GetSectionType(llvm::StringRef sect_name, .Case(".dwinfo", eSectionTypeDWARFDebugInfo) .Case(".dwline", eSectionTypeDWARFDebugLine) .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev) + .Case(".dwrnges", eSectionTypeDWARFDebugRanges) .Default(eSectionTypeInvalid); if (section_type != eSectionTypeInvalid) >From b443dd5b26354da73cd4d785a093d9d1582b25a8 Mon Sep 17 00:00:00 2001 From: Dhruv Srivastava Date: Wed, 2 Apr 2025 11:57:28 +0530 Subject: [PATCH 45/47] Fix for stack memory access from core file (#40) * Fix for stack memory access in core file --- .../Process/aix-core/ProcessAIXCore.cpp | 74 ++++++++++++++++++- .../Plugins/Process/aix-core/ProcessAIXCore.h | 11 +++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp index cfcbe1a216116..bb2db66e2980e 100644 --- a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp @@ -94,6 +94,33 @@ ProcessAIXCore::~ProcessAIXCore() { Finalize(true /* destructing */); } +lldb::addr_t ProcessAIXCore::AddAddressRanges(AIXCORE::AIXCore64Header header) { + const lldb::addr_t addr = header.StackBaseAddr; + FileRange file_range(header.StackOffset, header.StackSize); + VMRangeToFileOffset::Entry range_entry(addr, header.StackSize, file_range); + + if (header.StackSize > 0) { + VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back(); + if (last_entry && + last_entry->GetRangeEnd() == range_entry.GetRangeBase() && + last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase() && + last_entry->GetByteSize() == last_entry->data.GetByteSize()) { + last_entry->SetRangeEnd(range_entry.GetRangeEnd()); + last_entry->data.SetRangeEnd(range_entry.data.GetRangeEnd()); + } else { + m_core_aranges.Append(range_entry); + } + } + + const uint32_t permissions = lldb::ePermissionsReadable | + lldb::ePermissionsWritable; + + m_core_range_infos.Append( + VMRangeToPermissions::Entry(addr, header.StackSize, permissions)); + + return addr; +} + bool ProcessAIXCore::CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) { @@ -170,6 +197,7 @@ Status ProcessAIXCore::DoLoadCore() { } FileSpec file = m_core_module_sp->GetObjectFile()->GetFileSpec(); + Log *log = GetLog(LLDBLog::Process); if (file) { const size_t header_size = sizeof(AIXCORE::AIXCore64Header); @@ -180,6 +208,9 @@ Status ProcessAIXCore::DoLoadCore() { DataExtractor data(data_sp, lldb::eByteOrderBig, 4); lldb::offset_t data_offset = 0; m_aixcore_header.ParseCoreHeader(data, &data_offset); + lldb::addr_t addr = AddAddressRanges(m_aixcore_header); + if (addr == LLDB_INVALID_ADDRESS) + LLDB_LOGF(log, "ProcessAIXCore: Invalid base address. Stack information will be limited"); auto dyld = static_cast(GetDynamicLoader()); dyld->FillCoreLoaderData(data, m_aixcore_header.LoaderOffset, m_aixcore_header.LoaderSize); @@ -246,7 +277,48 @@ size_t ProcessAIXCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size, } size_t ProcessAIXCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, - Status &error) { return 0; } + Status &error) { + ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); + if (core_objfile == nullptr) + return 0; + // Get the address range + const VMRangeToFileOffset::Entry *address_range = + m_core_aranges.FindEntryThatContains(addr); + if (address_range == nullptr || address_range->GetRangeEnd() < addr) { + error = Status::FromErrorStringWithFormat( + "core file does not contain 0x%" PRIx64, addr); + return 0; + } + + // Convert the address into core file offset + const lldb::addr_t offset = addr - address_range->GetRangeBase(); + const lldb::addr_t file_start = address_range->data.GetRangeBase(); + const lldb::addr_t file_end = address_range->data.GetRangeEnd(); + size_t bytes_to_read = size; // Number of bytes to read from the core file + size_t bytes_copied = 0; // Number of bytes actually read from the core file + // Number of bytes available in the core file from the given address + lldb::addr_t bytes_left = 0; + + // Don't proceed if core file doesn't contain the actual data for this + // address range. + if (file_start == file_end) + return 0; + + // Figure out how many on-disk bytes remain in this segment starting at the + // given offset + if (file_end > file_start + offset) + bytes_left = file_end - (file_start + offset); + + if (bytes_to_read > bytes_left) + bytes_to_read = bytes_left; + + // If there is data available on the core file read it + if (bytes_to_read) + bytes_copied = + core_objfile->CopyData(offset + file_start, bytes_to_read, buf); + + return bytes_copied; +} Status ProcessAIXCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo ®ion_info) { diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h index 9880c491689ca..ffd9e401ee192 100644 --- a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h @@ -85,11 +85,22 @@ class ProcessAIXCore : public lldb_private::PostMortemProcess { void ParseAIXCoreFile(); + lldb::addr_t AddAddressRanges(AIXCORE::AIXCore64Header header); private: lldb::ModuleSP m_core_module_sp; std::string m_dyld_plugin_name; + typedef lldb_private::Range FileRange; + typedef lldb_private::RangeDataVector + VMRangeToFileOffset; + typedef lldb_private::RangeDataVector + VMRangeToPermissions; + + // Address ranges found in the core + VMRangeToFileOffset m_core_aranges; + VMRangeToPermissions m_core_range_infos; + // True if m_thread_contexts contains valid entries bool m_thread_data_valid = false; AIXCORE::AIXCore64Header m_aixcore_header; >From 96db5e3257436a222ee38049528d682166421fa1 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 2 Apr 2025 01:46:46 -0500 Subject: [PATCH 46/47] Build fail: SBMutex --- lldb/source/API/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index 0045edf6743d1..2c8f2d583c054 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -83,6 +83,7 @@ add_lldb_library(liblldb STATIC ${option_framework} SBMemoryRegionInfoList.cpp SBModule.cpp SBModuleSpec.cpp + SBMutex.cpp SBPlatform.cpp SBProcess.cpp SBProgress.cpp >From d7a892ef207cde5430021b8705279cc08dc4e0f7 Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Wed, 30 Apr 2025 04:53:28 -0500 Subject: [PATCH 47/47] Added change for step command issue --- .../Plugins/Process/AIX/NativeProcessAIX.cpp | 87 +++++++++++++------ 1 file changed, 61 insertions(+), 26 deletions(-) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp index 83b8ae5eb3258..ace9e11927bee 100644 --- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -19,7 +19,7 @@ #include #include #include - +#include #include "NativeThreadAIX.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" //#include "Plugins/Process/Utility/LinuxProcMaps.h" @@ -79,6 +79,7 @@ using namespace lldb_private; using namespace lldb_private::process_aix; using namespace llvm; +typedef std::function)> AIXMapCallback; // Private bits we only need internally. static bool ProcessVmReadvSupported() { @@ -988,13 +989,6 @@ Status NativeProcessAIX::GetMemoryRegionInfo(lldb::addr_t load_addr, for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end(); ++it) { MemoryRegionInfo &proc_entry_info = it->first; - - // Sanity check assumption that /proc/{pid}/maps entries are ascending. - assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) && - "descending /proc/pid/maps entries detected, unexpected"); - prev_base_address = proc_entry_info.GetRange().GetRangeBase(); - UNUSED_IF_ASSERT_DISABLED(prev_base_address); - // If the target address comes before this entry, indicate distance to next // region. if (load_addr < proc_entry_info.GetRange().GetRangeBase()) { @@ -1029,9 +1023,59 @@ Status NativeProcessAIX::GetMemoryRegionInfo(lldb::addr_t load_addr, return error; } +// Parsing the AIX map file /proc/PID/map +// The map file contains an array of prmap structures +// which has all the information like size, startaddress, object name, permissions +bool ParseAIXMapRegions(const char *aix_map, AIXMapCallback const &callback) { + MemoryRegionInfo region; + struct prmap *prmapData = (struct prmap *)aix_map; + struct prmap *entry; + uint32_t perm_flag; + + for(entry = prmapData;!(entry->pr_size == 0 && entry->pr_vaddr == NULL); entry++) { + const char *o_name = aix_map + entry->pr_pathoff; + lldb::addr_t start_address = (lldb::addr_t )entry->pr_vaddr; + lldb::addr_t end_address = start_address + entry->pr_size; + region.GetRange().SetRangeBase(start_address); + region.GetRange().SetRangeEnd(end_address); + region.SetMapped(MemoryRegionInfo::OptionalBool::eYes); + perm_flag = entry->pr_mflags; + + if(perm_flag & MA_READ) + region.SetReadable(MemoryRegionInfo::OptionalBool::eYes); + else + region.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + + if(perm_flag & MA_WRITE) + region.SetWritable(MemoryRegionInfo::OptionalBool::eYes); + else + region.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + + if(perm_flag & MA_EXEC) + region.SetExecutable(MemoryRegionInfo::OptionalBool::eYes); + else + region.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + + if((perm_flag & MA_SLIBTEXT) || (perm_flag & MA_SLIBDATA)) + region.SetShared(MemoryRegionInfo::OptionalBool::eYes); + else if ((perm_flag & MA_PLIBTEXT) || (perm_flag & MA_PLIBDATA)) + region.SetShared(MemoryRegionInfo::OptionalBool::eNo); + else + region.SetShared(MemoryRegionInfo::OptionalBool::eDontKnow); + + if(o_name) + region.SetName(o_name); + + callback(region); + region.Clear(); + } + + return true; +} + + Status NativeProcessAIX::PopulateMemoryRegionCache() { Log *log = GetLog(POSIXLog::Process); - // If our cache is empty, pull the latest. There should always be at least // one memory region if memory region handling is supported. if (!m_mem_region_cache.empty()) { @@ -1041,7 +1085,7 @@ Status NativeProcessAIX::PopulateMemoryRegionCache() { } Status Result; -#if 0 + AIXMapCallback callback = [&](llvm::Expected Info) { if (Info) { FileSpec file_spec(Info->GetName().GetCString()); @@ -1050,26 +1094,17 @@ Status NativeProcessAIX::PopulateMemoryRegionCache() { return true; } - Result = Info.takeError(); + Result = Status::FromError(Info.takeError()); m_supports_mem_region = LazyBool::eLazyBoolNo; LLDB_LOG(log, "failed to parse proc maps: {0}", Result); return false; }; - // AIX kernel since 2.6.14 has /proc/{pid}/smaps - // if CONFIG_PROC_PAGE_MONITOR is enabled - auto BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "smaps"); - if (BufferOrError) - ParseAIXSMapRegions(BufferOrError.get()->getBuffer(), callback); - else { - BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "maps"); - if (!BufferOrError) { - m_supports_mem_region = LazyBool::eLazyBoolNo; - return BufferOrError.getError(); - } - - ParseAIXMapRegions(BufferOrError.get()->getBuffer(), callback); - } + auto BufferOrError = getProcFile(GetID(), "map"); + if (BufferOrError) { + std::unique_ptr MapBuffer = std::move(*BufferOrError); + ParseAIXMapRegions(MapBuffer->getBufferStart(), callback); + } if (Result.Fail()) return Result; @@ -1090,7 +1125,7 @@ Status NativeProcessAIX::PopulateMemoryRegionCache() { // We support memory retrieval, remember that. m_supports_mem_region = LazyBool::eLazyBoolYes; -#endif + return Status(); } From lldb-commits at lists.llvm.org Wed May 14 00:10:13 2025 From: lldb-commits at lists.llvm.org (Hemang Gadhavi via lldb-commits) Date: Wed, 14 May 2025 00:10:13 -0700 (PDT) Subject: [Lldb-commits] [lldb] Extending LLDB to work on AIX (PR #102601) In-Reply-To: Message-ID: <682441d5.170a0220.111eaf.1e56@mx.google.com> https://github.com/HemangGadhavi updated https://github.com/llvm/llvm-project/pull/102601 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Wed May 14 01:48:05 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 01:48:05 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Fix ForwardListFrontEnd::CalculateNumChildren (PR #139805) In-Reply-To: Message-ID: <682458c5.170a0220.10e5d2.1921@mx.google.com> labath wrote: I'm very much in favor of removing this dependence on the setting value, as I think it should be handled at a higher level. *However*, I fear this is going to make printing large std::forward_list very slow. Since computing the size of the list requires iterating through all the elements, which is a lot of pointer chasing, printing of large lists (like, 10k elements or more) could take a very long time (and I think that's the reason this limit was originally introduced). Fortunately, we already have a mechanism to prevent this -- we mave `GetNumChildren` overload with the `max` argument which basically says "if the number of children is larger than this, don't bother giving me the exact value". The general printing logic (in frame var and lldb-dap) should already know how to make use of this (I've made sure of that because I was supporting some formatters like this), but for std::forward_list, its summary provider will force the calculation of the size (because it prints the size in the summary). For this, I think the fix is to change the formatter to *not* print the exact size (all the time). For example, it could call `GetNumChildren(X)` and if the result is smaller than `X`, it can print the exact size (`size=x`). Otherwise it can just print the lower bound (`size>=X` ?). The value of `X` might be derived from the setting, but I think it'd also make sense have an independent constant, because not every client has to display the values according to this setting (for example, VSCode always prints the first 100 values). https://github.com/llvm/llvm-project/pull/139805 From lldb-commits at lists.llvm.org Wed May 14 02:02:39 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 02:02:39 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Refactor lldb-dap event handling. (PR #139669) In-Reply-To: Message-ID: <68245c2f.170a0220.111eaf.2422@mx.google.com> labath wrote: > I think our tests are not fully specifying their expected state. For example, lldb/test/API/tools/lldb-dap/console/TestDAP_console.py `TestDAP_console.test_diagnositcs` was performing an evaluate and then using `get_important` to fetch output events with category 'important'. > > With the change, the `important` output was always coming after the request was handled. I updated the test to use a `self.collect_important` instead of `get_important`. Previously, this could have been emitted while the request was being handled, but now the output would only ever be emitted after the request handler is finished. Okay, so it's kind of what I said, right? The "important" output was coming before the message was handled most of the time, although it wasn't guaranteed, and the test could fail if that happens. Now, it *always* comes too late. If that's true, then the test change to use `self.collect_important` could be made before the functionality change, right? > Thinking about this some more, would it be possible to treat everything as an `SBEvent`? We could use the `DAP::broadcaster` to create events for the DAP protocol messages we receive, right? Then when we listen for events we'd just need to check if the event was a `DAPBroadcasterBits::eBroadcastBitProtocolMessage` as the event type and handle protocol messages in the same loop we're handling events. > > This would have a similar effect as using a MainLoop but unifies the event thread with the DAP handler. We'd still need to transport thread to parse messages and add events to the broadcaster. Yeah, that should be possible, and it may make more sense in a world where the MainLoop cannot listen on all FD types (since you need the forwarding thread anyway). It's unfortunate that there's no synchronization operation (at least, not a portable one, FUTEX_FD seems kinda nice) that allows you do wait for condition variables and FDs, necessitating these forwarding threads. Since forwarding would add a bit of latency, one of the factors would be which kinds of operations do we want to make slower. https://github.com/llvm/llvm-project/pull/139669 From lldb-commits at lists.llvm.org Wed May 14 02:10:15 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 02:10:15 -0700 (PDT) Subject: [Lldb-commits] [lldb] Fix race condition during iteration through modules (#139283) (PR #139862) Message-ID: https://github.com/nd created https://github.com/llvm/llvm-project/pull/139862 Lock ensures modules don't change during iteration. Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Wed May 14 02:10:37 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 02:10:37 -0700 (PDT) Subject: [Lldb-commits] [lldb] Fix race condition during iteration through modules (#139283) (PR #139862) In-Reply-To: Message-ID: <68245e0d.170a0220.10baaf.24e0@mx.google.com> github-actions[bot] wrote: Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using `@` followed by their GitHub username. If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the [LLVM GitHub User Guide](https://llvm.org/docs/GitHub.html). You can also ask questions in a comment on this PR, on the [LLVM Discord](https://discord.com/invite/xS7Z362) or on the [forums](https://discourse.llvm.org/). https://github.com/llvm/llvm-project/pull/139862 From lldb-commits at lists.llvm.org Wed May 14 02:11:12 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 02:11:12 -0700 (PDT) Subject: [Lldb-commits] [lldb] Fix race condition during iteration through modules (#139283) (PR #139862) In-Reply-To: Message-ID: <68245e30.170a0220.7f76.0b28@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: None (nd)
Changes Lock ensures modules don't change during iteration. --- Full diff: https://github.com/llvm/llvm-project/pull/139862.diff 1 Files Affected: - (modified) lldb/source/Target/Target.cpp (+1) ``````````diff diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 7f61f8689fb95..485b49aeb64b4 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -1510,6 +1510,7 @@ bool Target::IgnoreWatchpointByID(lldb::watch_id_t watch_id, } ModuleSP Target::GetExecutableModule() { + std::lock_guard guard(m_images.GetMutex()); // search for the first executable in the module list for (size_t i = 0; i < m_images.GetSize(); ++i) { ModuleSP module_sp = m_images.GetModuleAtIndex(i); ``````````
https://github.com/llvm/llvm-project/pull/139862 From lldb-commits at lists.llvm.org Wed May 14 02:16:54 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 02:16:54 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Call Target::ClearAllLoadedSections earlier (PR #138892) In-Reply-To: Message-ID: <68245f86.a70a0220.348493.120d@mx.google.com> labath wrote: > Looks good to me, we should clear them on both attach & launch which is what the Darwin DynamicLoader plugin was doing. > > I was a little surprised that Minidump is picking up the host native DyanmicLoader plugin at all - seems like the static dynamic loader might make more sense, so it can say what binaries are loaded & where they're loaded - but I've never looked at the Minidump code, I'm sure there are reasons why it works this way. It originally did that, but then this changed last year in order to get access to thread-local data, which is also a responsibility of the dynamic loader class. At least for posix systems (I'm not sure about Darwin, as the dynamic loader is more tightly integrated into the OS) it also kind of makes sense because the dynamic loader can work off of an (elf) core file (if it contains enough information). For minidumps, some of that work is wasted though, because the minidump contains explicit load addresses of all modules. So, it would kind of make sense to separate the logic for loading the modules from "loading of TLS", but it's not quite clear how to do that as two are quite intertwined. https://github.com/llvm/llvm-project/pull/138892 From lldb-commits at lists.llvm.org Wed May 14 02:16:59 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 02:16:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] 97aa01b - [lldb] Call Target::ClearAllLoadedSections earlier (#138892) Message-ID: <68245f8b.170a0220.53196.2421@mx.google.com> Author: Pavel Labath Date: 2025-05-14T11:16:55+02:00 New Revision: 97aa01bef770ec651c86978d137933e09221dd00 URL: https://github.com/llvm/llvm-project/commit/97aa01bef770ec651c86978d137933e09221dd00 DIFF: https://github.com/llvm/llvm-project/commit/97aa01bef770ec651c86978d137933e09221dd00.diff LOG: [lldb] Call Target::ClearAllLoadedSections earlier (#138892) Minidump files contain explicit information about load addresses of modules, so it can load them itself. This works on other platforms, but fails on darwin because DynamicLoaderDarwin nukes the loaded module list on initialization (which happens after the core file plugin has done its work). This used to work until #109477, which enabled the dynamic loader plugins for minidump files in order to get them to provide access to TLS. Clearing the load list makes sense, but I think we could do it earlier in the process, so that both Process and DynamicLoader plugins get a chance to load modules. This patch does that by calling the function early in the launch/attach/load core flows. This fixes TestDynamicValue.py:test_from_core_file on darwin. Added: Modified: lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp lldb/source/Target/Process.cpp lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py Removed: ################################################################################ diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp index 578ab12268ea3..1270d57423c7b 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp @@ -872,7 +872,6 @@ void DynamicLoaderDarwin::PrivateInitialize(Process *process) { StateAsCString(m_process->GetState())); Clear(true); m_process = process; - m_process->GetTarget().ClearAllLoadedSections(); } // Member function that gets called when the process state changes. diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 13ff12b4ff953..7c5512598bbb6 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -2763,6 +2763,7 @@ Status Process::LaunchPrivate(ProcessLaunchInfo &launch_info, StateType &state, } if (state == eStateStopped || state == eStateCrashed) { + GetTarget().ClearAllLoadedSections(); DidLaunch(); // Now that we know the process type, update its signal responses from the @@ -2799,6 +2800,7 @@ Status Process::LaunchPrivate(ProcessLaunchInfo &launch_info, StateType &state, } Status Process::LoadCore() { + GetTarget().ClearAllLoadedSections(); Status error = DoLoadCore(); if (error.Success()) { ListenerSP listener_sp( @@ -3094,6 +3096,8 @@ void Process::CompleteAttach() { Log *log(GetLog(LLDBLog::Process | LLDBLog::Target)); LLDB_LOGF(log, "Process::%s()", __FUNCTION__); + GetTarget().ClearAllLoadedSections(); + // Let the process subclass figure out at much as it can about the process // before we go looking for a dynamic loader plug-in. ArchSpec process_arch; diff --git a/lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py b/lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py index cd95a9ff3fe8c..faa35421ff60b 100644 --- a/lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py +++ b/lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py @@ -282,7 +282,6 @@ def test_from_forward_decl(self): @no_debug_info_test @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24663") - @expectedFailureDarwin # dynamic loader unloads modules @expectedFailureAll(archs=["arm"]) # Minidump saving not implemented def test_from_core_file(self): """Test fetching C++ dynamic values from core files. Specifically, test From lldb-commits at lists.llvm.org Wed May 14 02:17:02 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 02:17:02 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Call Target::ClearAllLoadedSections earlier (PR #138892) In-Reply-To: Message-ID: <68245f8e.170a0220.2c12b8.25f3@mx.google.com> https://github.com/labath closed https://github.com/llvm/llvm-project/pull/138892 From lldb-commits at lists.llvm.org Wed May 14 02:29:56 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 02:29:56 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Merge/unify ABI-provided AArch64 unwind plans (PR #139545) In-Reply-To: Message-ID: <68246294.620a0220.3bdce.42d8@mx.google.com> labath wrote: > Nice unification, thanks. I'm sure the pc=lr rule was me not trusting the algorithms over in RegisterContextUnwind to do the right thing if the rule wasn't listed. Having just pushed all that code around for a day, I know this kind of thing is unneeded, but harmless if it's present. Well.. as it stands now, it's kind of needed because without it, your test would break in CompareUnwindPlansForIdenticalInitialPCLocation, as it doesn't recognise that `SetReturnAddressRegister(LR)` is equivalent to `SetRegisterLocationToRegister(PC, LR)`. This is kind of why I have suggested in https://discourse.llvm.org/t/unhappiness-with-the-lldb-unwinder-register-passing-up-the-stack-interrup-trap-sigtramp-frames/86058/3 to standardise on the `pc=lr` rules. I wrote that before I encountered this problem, but seeing we had plans which employed both of these strategies (and they both mostly worked) has made me more confident this could work. https://github.com/llvm/llvm-project/pull/139545 From lldb-commits at lists.llvm.org Wed May 14 02:29:59 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 02:29:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] adabc83 - [lldb] Merge/unify ABI-provided AArch64 unwind plans (#139545) Message-ID: <68246297.050a0220.1fa9bd.530b@mx.google.com> Author: Pavel Labath Date: 2025-05-14T11:29:56+02:00 New Revision: adabc83a92130e556d4d16adaee6e81e09fdf570 URL: https://github.com/llvm/llvm-project/commit/adabc83a92130e556d4d16adaee6e81e09fdf570 DIFF: https://github.com/llvm/llvm-project/commit/adabc83a92130e556d4d16adaee6e81e09fdf570.diff LOG: [lldb] Merge/unify ABI-provided AArch64 unwind plans (#139545) The macos and sysv ABIs return functionally equivalent unwind plans, so they can be implemented in the base AArch64 class. The only difference between them was that the macos plan provided a "pc=lr" rule whereas the sysv plan called SetReturnAddressRegister (which causes the unwind machinery to act as if that rule was present). This difference was enough to cause `CompareUnwindPlansForIdenticalInitialPCLocation` to return a different value and break the (temporarily reverted) TestUnwindFramelessFaulted test. While merging the two functions, I couldn't stop myself from simplifying them to use the generic register number schemes -- which exposed another bug in CompareUnwindPlansForIdenticalInitialPCLocation, namely that it was expecting all unwind plans to use the LLDB numbering scheme. This patch fixes that as well. Added: Modified: lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp lldb/source/Plugins/ABI/AArch64/ABIAArch64.h lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h lldb/source/Symbol/FuncUnwinders.cpp Removed: ################################################################################ diff --git a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp index 7d8d0a4d3d671..3bafb21f7c33a 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp +++ b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp @@ -19,6 +19,7 @@ #include using namespace lldb; +using namespace lldb_private; LLDB_PLUGIN_DEFINE(ABIAArch64) @@ -200,3 +201,44 @@ void ABIAArch64::AugmentRegisterInfo( lldb::eEncodingIEEE754, lldb::eFormatFloat); } } + +UnwindPlanSP ABIAArch64::CreateFunctionEntryUnwindPlan() { + UnwindPlan::Row row; + + // Our previous Call Frame Address is the stack pointer + row.GetCFAValue().SetIsRegisterPlusOffset(LLDB_REGNUM_GENERIC_SP, 0); + + // Our previous PC is in the LR, all other registers are the same. + row.SetRegisterLocationToRegister(LLDB_REGNUM_GENERIC_PC, + LLDB_REGNUM_GENERIC_RA, true); + + auto plan_sp = std::make_shared(eRegisterKindGeneric); + plan_sp->AppendRow(std::move(row)); + plan_sp->SetSourceName("arm64 at-func-entry default"); + plan_sp->SetSourcedFromCompiler(eLazyBoolNo); + plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); + plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo); + return plan_sp; +} + +UnwindPlanSP ABIAArch64::CreateDefaultUnwindPlan() { + UnwindPlan::Row row; + const int32_t ptr_size = 8; + + row.GetCFAValue().SetIsRegisterPlusOffset(LLDB_REGNUM_GENERIC_FP, + 2 * ptr_size); + row.SetUnspecifiedRegistersAreUndefined(true); + + row.SetRegisterLocationToAtCFAPlusOffset(LLDB_REGNUM_GENERIC_FP, + ptr_size * -2, true); + row.SetRegisterLocationToAtCFAPlusOffset(LLDB_REGNUM_GENERIC_PC, + ptr_size * -1, true); + + auto plan_sp = std::make_shared(eRegisterKindGeneric); + plan_sp->AppendRow(std::move(row)); + plan_sp->SetSourceName("arm64 default unwind plan"); + plan_sp->SetSourcedFromCompiler(eLazyBoolNo); + plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); + plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo); + return plan_sp; +} diff --git a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h index 52e42f1260a83..53702f4da580d 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h +++ b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h @@ -19,6 +19,9 @@ class ABIAArch64 : public lldb_private::MCBasedABI { lldb::addr_t FixCodeAddress(lldb::addr_t pc) override; lldb::addr_t FixDataAddress(lldb::addr_t pc) override; + lldb::UnwindPlanSP CreateFunctionEntryUnwindPlan() override; + lldb::UnwindPlanSP CreateDefaultUnwindPlan() override; + protected: virtual lldb::addr_t FixAddress(lldb::addr_t pc, lldb::addr_t mask) { return pc; diff --git a/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp index f86ab8cbb1195..094e0523a4edf 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp +++ b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp @@ -17,7 +17,6 @@ #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Value.h" -#include "lldb/Symbol/UnwindPlan.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Target.h" @@ -30,8 +29,6 @@ #include "lldb/Utility/Status.h" #include "lldb/ValueObject/ValueObjectConstResult.h" -#include "Utility/ARM64_DWARF_Registers.h" - using namespace lldb; using namespace lldb_private; @@ -344,48 +341,6 @@ ABIMacOSX_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, return error; } -UnwindPlanSP ABIMacOSX_arm64::CreateFunctionEntryUnwindPlan() { - uint32_t lr_reg_num = arm64_dwarf::lr; - uint32_t sp_reg_num = arm64_dwarf::sp; - uint32_t pc_reg_num = arm64_dwarf::pc; - - UnwindPlan::Row row; - - // Our previous Call Frame Address is the stack pointer - row.GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0); - - // Our previous PC is in the LR, all other registers are the same. - row.SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true); - - auto plan_sp = std::make_shared(eRegisterKindDWARF); - plan_sp->AppendRow(std::move(row)); - plan_sp->SetSourceName("arm64 at-func-entry default"); - plan_sp->SetSourcedFromCompiler(eLazyBoolNo); - return plan_sp; -} - -UnwindPlanSP ABIMacOSX_arm64::CreateDefaultUnwindPlan() { - uint32_t fp_reg_num = arm64_dwarf::fp; - uint32_t pc_reg_num = arm64_dwarf::pc; - - UnwindPlan::Row row; - const int32_t ptr_size = 8; - - row.GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size); - row.SetUnspecifiedRegistersAreUndefined(true); - - row.SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); - row.SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); - - auto plan_sp = std::make_shared(eRegisterKindDWARF); - plan_sp->AppendRow(std::move(row)); - plan_sp->SetSourceName("arm64-apple-darwin default unwind plan"); - plan_sp->SetSourcedFromCompiler(eLazyBoolNo); - plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); - plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo); - return plan_sp; -} - // AAPCS64 (Procedure Call Standard for the ARM 64-bit Architecture) says // registers x19 through x28 and sp are callee preserved. v8-v15 are non- // volatile (and specifically only the lower 8 bytes of these regs), the rest diff --git a/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h index 94a60327c6181..c8851709f50ad 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h +++ b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h @@ -27,10 +27,6 @@ class ABIMacOSX_arm64 : public ABIAArch64 { bool GetArgumentValues(lldb_private::Thread &thread, lldb_private::ValueList &values) const override; - lldb::UnwindPlanSP CreateFunctionEntryUnwindPlan() override; - - lldb::UnwindPlanSP CreateDefaultUnwindPlan() override; - bool RegisterIsVolatile(const lldb_private::RegisterInfo *reg_info) override; // The arm64 ABI requires that stack frames be 16 byte aligned. diff --git a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp index 6e07c0982be0e..aa9c20b6bb2cf 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp +++ b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp @@ -30,8 +30,6 @@ #include "lldb/Utility/Status.h" #include "lldb/ValueObject/ValueObjectConstResult.h" -#include "Utility/ARM64_DWARF_Registers.h" - using namespace lldb; using namespace lldb_private; @@ -385,48 +383,6 @@ Status ABISysV_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, return error; } -UnwindPlanSP ABISysV_arm64::CreateFunctionEntryUnwindPlan() { - uint32_t lr_reg_num = arm64_dwarf::lr; - uint32_t sp_reg_num = arm64_dwarf::sp; - - UnwindPlan::Row row; - - // Our previous Call Frame Address is the stack pointer, all other registers - // are the same. - row.GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0); - - auto plan_sp = std::make_shared(eRegisterKindDWARF); - plan_sp->AppendRow(std::move(row)); - plan_sp->SetReturnAddressRegister(lr_reg_num); - plan_sp->SetSourceName("arm64 at-func-entry default"); - plan_sp->SetSourcedFromCompiler(eLazyBoolNo); - plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); - plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo); - return plan_sp; -} - -UnwindPlanSP ABISysV_arm64::CreateDefaultUnwindPlan() { - uint32_t fp_reg_num = arm64_dwarf::fp; - uint32_t pc_reg_num = arm64_dwarf::pc; - - UnwindPlan::Row row; - const int32_t ptr_size = 8; - - row.GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size); - row.SetUnspecifiedRegistersAreUndefined(true); - - row.SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); - row.SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); - - auto plan_sp = std::make_shared(eRegisterKindDWARF); - plan_sp->AppendRow(std::move(row)); - plan_sp->SetSourceName("arm64 default unwind plan"); - plan_sp->SetSourcedFromCompiler(eLazyBoolNo); - plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); - plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo); - return plan_sp; -} - // AAPCS64 (Procedure Call Standard for the ARM 64-bit Architecture) says // registers x19 through x28 and sp are callee preserved. v8-v15 are non- // volatile (and specifically only the lower 8 bytes of these regs), the rest diff --git a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h index 2b8e608d4caab..213fbf7417b2c 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h +++ b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h @@ -30,10 +30,6 @@ class ABISysV_arm64 : public ABIAArch64 { SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value) override; - lldb::UnwindPlanSP CreateFunctionEntryUnwindPlan() override; - - lldb::UnwindPlanSP CreateDefaultUnwindPlan() override; - bool RegisterIsVolatile(const lldb_private::RegisterInfo *reg_info) override; // The arm64 ABI requires that stack frames be 16 byte aligned. diff --git a/lldb/source/Symbol/FuncUnwinders.cpp b/lldb/source/Symbol/FuncUnwinders.cpp index faec24cde7fdd..12a6d101d9930 100644 --- a/lldb/source/Symbol/FuncUnwinders.cpp +++ b/lldb/source/Symbol/FuncUnwinders.cpp @@ -365,33 +365,30 @@ FuncUnwinders::GetAssemblyUnwindPlan(Target &target, Thread &thread) { LazyBool FuncUnwinders::CompareUnwindPlansForIdenticalInitialPCLocation( Thread &thread, const std::shared_ptr &a, const std::shared_ptr &b) { - LazyBool plans_are_identical = eLazyBoolCalculate; + if (!a || !b) + return eLazyBoolCalculate; - RegisterNumber pc_reg(thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); - uint32_t pc_reg_lldb_regnum = pc_reg.GetAsKind(eRegisterKindLLDB); + const UnwindPlan::Row *a_first_row = a->GetRowAtIndex(0); + const UnwindPlan::Row *b_first_row = b->GetRowAtIndex(0); + if (!a_first_row || !b_first_row) + return eLazyBoolCalculate; - if (a && b) { - const UnwindPlan::Row *a_first_row = a->GetRowAtIndex(0); - const UnwindPlan::Row *b_first_row = b->GetRowAtIndex(0); + RegisterNumber pc_reg(thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + uint32_t a_pc_regnum = pc_reg.GetAsKind(a->GetRegisterKind()); + uint32_t b_pc_regnum = pc_reg.GetAsKind(b->GetRegisterKind()); - if (a_first_row && b_first_row) { - UnwindPlan::Row::AbstractRegisterLocation a_pc_regloc; - UnwindPlan::Row::AbstractRegisterLocation b_pc_regloc; + UnwindPlan::Row::AbstractRegisterLocation a_pc_regloc; + UnwindPlan::Row::AbstractRegisterLocation b_pc_regloc; - a_first_row->GetRegisterInfo(pc_reg_lldb_regnum, a_pc_regloc); - b_first_row->GetRegisterInfo(pc_reg_lldb_regnum, b_pc_regloc); + a_first_row->GetRegisterInfo(a_pc_regnum, a_pc_regloc); + b_first_row->GetRegisterInfo(b_pc_regnum, b_pc_regloc); - plans_are_identical = eLazyBoolYes; + if (a_first_row->GetCFAValue() != b_first_row->GetCFAValue()) + return eLazyBoolNo; + if (a_pc_regloc != b_pc_regloc) + return eLazyBoolNo; - if (a_first_row->GetCFAValue() != b_first_row->GetCFAValue()) { - plans_are_identical = eLazyBoolNo; - } - if (a_pc_regloc != b_pc_regloc) { - plans_are_identical = eLazyBoolNo; - } - } - } - return plans_are_identical; + return eLazyBoolYes; } std::shared_ptr From lldb-commits at lists.llvm.org Wed May 14 02:30:02 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 02:30:02 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Merge/unify ABI-provided AArch64 unwind plans (PR #139545) In-Reply-To: Message-ID: <6824629a.170a0220.215e7c.0f52@mx.google.com> https://github.com/labath closed https://github.com/llvm/llvm-project/pull/139545 From lldb-commits at lists.llvm.org Wed May 14 02:32:04 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 02:32:04 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Call Target::ClearAllLoadedSections earlier (PR #138892) In-Reply-To: Message-ID: <68246314.a70a0220.c58dc.3ece@mx.google.com> labath wrote: Yeah, this is kind of my fault as I introduced this way back when. I think at that point we didn't have test-specific headers, which made this option more appealing. https://github.com/llvm/llvm-project/pull/138892 From lldb-commits at lists.llvm.org Wed May 14 02:42:20 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 02:42:20 -0700 (PDT) Subject: [Lldb-commits] [clang] [clang-tools-extra] [lldb] [clang] Remove intrusive reference count from `DiagnosticOptions` (PR #139584) In-Reply-To: Message-ID: <6824657c.170a0220.2c158.257f@mx.google.com> https://github.com/cor3ntin approved this pull request. The clang parts look like a nice improvement, thanks! Please wait for a few other people to review it though. https://github.com/llvm/llvm-project/pull/139584 From lldb-commits at lists.llvm.org Wed May 14 02:44:07 2025 From: lldb-commits at lists.llvm.org (Oliver Hunt via lldb-commits) Date: Wed, 14 May 2025 02:44:07 -0700 (PDT) Subject: [Lldb-commits] [clang] [clang-tools-extra] [lldb] [clang] Remove intrusive reference count from `DiagnosticOptions` (PR #139584) In-Reply-To: Message-ID: <682465e7.170a0220.184159.02fc@mx.google.com> ================ @@ -2032,6 +2032,7 @@ class SourceManagerForFile { // as they are created in `createSourceManagerForFile` so that they can be // deleted in the reverse order as they are created. std::unique_ptr FileMgr; + std::unique_ptr DiagOpts; ---------------- ojhunt wrote: I don't like that in some cases we have a unique_ptr and later (ATSUnit) we use a shared_ptr<>. It leaves an author unable to know given some arbitrary DiagnosticOptions* what the lifetime and/or ownership rules are. https://github.com/llvm/llvm-project/pull/139584 From lldb-commits at lists.llvm.org Wed May 14 02:44:51 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 02:44:51 -0700 (PDT) Subject: [Lldb-commits] [clang] [clang-tools-extra] [lldb] [clang] Remove intrusive reference count from `DiagnosticOptions` (PR #139584) In-Reply-To: Message-ID: <68246613.170a0220.2bc884.2405@mx.google.com> ================ @@ -107,6 +107,7 @@ class ASTUnit { private: std::unique_ptr LangOpts; + std::shared_ptr DiagOpts; ---------------- cor3ntin wrote: Can that be unique_ptr ? https://github.com/llvm/llvm-project/pull/139584 From lldb-commits at lists.llvm.org Wed May 14 02:44:51 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 02:44:51 -0700 (PDT) Subject: [Lldb-commits] [clang] [clang-tools-extra] [lldb] [clang] Remove intrusive reference count from `DiagnosticOptions` (PR #139584) In-Reply-To: Message-ID: <68246613.630a0220.7f314.a202@mx.google.com> ================ @@ -837,6 +838,7 @@ class ASTUnit { static std::unique_ptr LoadFromCommandLine( const char **ArgBegin, const char **ArgEnd, std::shared_ptr PCHContainerOps, + std::shared_ptr DiagOpts, ---------------- cor3ntin wrote: We probably can pass by reference here https://github.com/llvm/llvm-project/pull/139584 From lldb-commits at lists.llvm.org Wed May 14 02:46:01 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 02:46:01 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Adding NativeThreadAIX (PR #139537) In-Reply-To: Message-ID: <68246659.170a0220.1d23f6.2bd2@mx.google.com> ================ @@ -0,0 +1,71 @@ +//===-- NativeThreadAIX.cpp ---------------------------------------------===// +// +// 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 "NativeThreadAIX.h" +#include "NativeProcessAIX.h" +#include "lldb/Utility/State.h" +#include +#include + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; + +NativeThreadAIX::NativeThreadAIX(NativeProcessAIX &process, lldb::tid_t tid) + : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid) {} + +std::string NativeThreadAIX::GetName() { + NativeProcessAIX &process = GetProcess(); + auto BufferOrError = getProcFile(process.GetID(), "psinfo"); + if (!BufferOrError) + return ""; + auto &Buffer = *BufferOrError; + if (Buffer->getBufferSize() < sizeof(psinfo_t)) + return ""; + const psinfo_t *psinfo = + reinterpret_cast(Buffer->getBufferStart()); + return std::string(psinfo->pr_fname); +} ---------------- labath wrote: > In that case, shall I go ahead with this? I think we can say it's up to you, but so far I haven't seen anything that would make me thing this is necessary. You're right that it causes the name field to disappear, but the usefulness of that field comes from the fact that it's different for every thread: ``` lldb) thread list Process 6708 stopped * thread #1: tid = 6708, 0x00007fffee7201ac libc.so.6`__select + 332, name = 'lldb', stop reason = signal SIGSTOP thread #2: tid = 6759, 0x00007fffee69c0a5 libc.so.6`__futex_abstimed_wait_common + 261, name = 'er.alarm-thread' thread #3: tid = 6760, 0x00007fffee69c0a5 libc.so.6`__futex_abstimed_wait_common + 261, name = 'dbg.evt-handler' thread #4: tid = 6765, 0x00007fffee70b15a libc.so.6`wait4 + 90, name = 'ait4(pid=6764)>' thread #5: tid = 6766, 0x00007fffee7201ac libc.so.6`__select + 332, name = 'b-remote.async>' thread #6: tid = 6771, 0x00007fffee69c0a5 libc.so.6`__futex_abstimed_wait_common + 261, name = 'intern-state' thread #7: tid = 6772, 0x00007fffee7201ac libc.so.6`__select + 332, name = '.process.stdio>' thread #8: tid = 6773, 0x00007fffee69c0a5 libc.so.6`__futex_abstimed_wait_common + 261, name = 'llvm-worker-0' thread #9: tid = 6774, 0x00007fffee69c0a5 libc.so.6`__futex_abstimed_wait_common + 261, name = 'llvm-worker-1' thread #10: tid = 6775, 0x00007fffee69c0a5 libc.so.6`__futex_abstimed_wait_common + 261, name = 'llvm-worker-2' thread #11: tid = 6776, 0x00007fffee69c0a5 libc.so.6`__futex_abstimed_wait_common + 261, name = 'llvm-worker-3' thread #12: tid = 6777, 0x00007fffee69c0a5 libc.so.6`__futex_abstimed_wait_common + 261, name = 'llvm-worker-4' ``` If all of these said `name='lldb'`, would the result be useful? I think not. And I think the same goes for the single-threaded use case: if there is just a single thread, then you don't need names as there's nothing to distinguish. https://github.com/llvm/llvm-project/pull/139537 From lldb-commits at lists.llvm.org Wed May 14 02:48:02 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 02:48:02 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Adding NativeThreadAIX (PR #139537) In-Reply-To: Message-ID: <682466d2.170a0220.1b247.2065@mx.google.com> ================ @@ -0,0 +1,71 @@ +//===-- NativeThreadAIX.cpp ---------------------------------------------===// +// +// 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 "NativeThreadAIX.h" +#include "NativeProcessAIX.h" +#include "lldb/Utility/State.h" +#include +#include + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; + +NativeThreadAIX::NativeThreadAIX(NativeProcessAIX &process, lldb::tid_t tid) + : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid) {} + +std::string NativeThreadAIX::GetName() { + NativeProcessAIX &process = GetProcess(); + auto BufferOrError = getProcFile(process.GetID(), "psinfo"); + if (!BufferOrError) + return ""; + auto &Buffer = *BufferOrError; + if (Buffer->getBufferSize() < sizeof(psinfo_t)) + return ""; + const psinfo_t *psinfo = + reinterpret_cast(Buffer->getBufferStart()); + return std::string(psinfo->pr_fname); +} ---------------- labath wrote: You also shouldn't expect that the "process stopped" output will contain the name of the process. That really is the name of the thread -- it just happens that on linux the main thread gets the name of the process. On macos for instance, this output doesn't contain the name of the process, even for the main thread: ``` (lldb) Process 6668 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP frame #0: 0x0000000185cf1b6c libsystem_kernel.dylib`__read_nocancel + 8 ``` https://github.com/llvm/llvm-project/pull/139537 From lldb-commits at lists.llvm.org Wed May 14 02:49:56 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 02:49:56 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Adding NativeThreadAIX (PR #139537) In-Reply-To: Message-ID: <68246744.170a0220.37cf9a.01c8@mx.google.com> https://github.com/labath approved this pull request. https://github.com/llvm/llvm-project/pull/139537 From lldb-commits at lists.llvm.org Wed May 14 03:01:32 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 03:01:32 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][NFC] Split RegisterContextUnwind::SavedLocationForRegister (PR #139817) In-Reply-To: Message-ID: <682469fc.170a0220.27a782.f7c5@mx.google.com> https://github.com/labath approved this pull request. https://github.com/llvm/llvm-project/pull/139817 From lldb-commits at lists.llvm.org Wed May 14 03:01:32 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 03:01:32 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][NFC] Split RegisterContextUnwind::SavedLocationForRegister (PR #139817) In-Reply-To: Message-ID: <682469fc.170a0220.5727b.0499@mx.google.com> ================ @@ -1243,303 +1243,285 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( return false; } -// Answer the question: Where did THIS frame save the CALLER frame ("previous" -// frame)'s register value? - -enum UnwindLLDB::RegisterSearchResult -RegisterContextUnwind::SavedLocationForRegister( - uint32_t lldb_regnum, - lldb_private::UnwindLLDB::ConcreteRegisterLocation ®loc) { +/// Search this stack frame's UnwindPlans for the AbstractRegisterLocation ---------------- labath wrote: The docstring should go in the header. If there are details you think are only relevant for the implementation (not the interface), they can stay here. https://github.com/llvm/llvm-project/pull/139817 From lldb-commits at lists.llvm.org Wed May 14 03:01:33 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 03:01:33 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][NFC] Split RegisterContextUnwind::SavedLocationForRegister (PR #139817) In-Reply-To: Message-ID: <682469fd.050a0220.1ed5ad.1d7a@mx.google.com> ================ @@ -1243,303 +1243,285 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( return false; } -// Answer the question: Where did THIS frame save the CALLER frame ("previous" -// frame)'s register value? - -enum UnwindLLDB::RegisterSearchResult -RegisterContextUnwind::SavedLocationForRegister( - uint32_t lldb_regnum, - lldb_private::UnwindLLDB::ConcreteRegisterLocation ®loc) { +/// Search this stack frame's UnwindPlans for the AbstractRegisterLocation +/// for this register. +/// +/// \param[out] kind +/// Set to the RegisterKind of the UnwindPlan which is the basis for +/// the returned AbstractRegisterLocation; if the location is in terms +/// of another register number, this Kind is needed to interpret it +/// correctly. +/// +/// \return +/// An empty optional indicaTes that there was an error in processing +/// the request. +/// +/// If there is no unwind rule for a volatile (caller-preserved) register, +/// the returned AbstractRegisterLocation will be IsUndefined, +/// indicating that we should stop searching. +/// +/// If there is no unwind rule for a non-volatile (callee-preserved) +/// register, the returned AbstractRegisterLocation will be IsSame. +/// In frame 0, IsSame means get the value from the live register context. +/// Else it means to continue descending down the stack to more-live frames +/// looking for a location/value. +/// +/// If an AbstractRegisterLocation is found in an UnwindPlan, that will +/// be returned, with no consideration of the current ABI rules for +/// registers. Functions using an alternate ABI calling convention +/// will work as long as the UnwindPlans are exhaustive about what +/// registers are volatile/non-volatile. +std::optional +RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, + lldb::RegisterKind &kind) { RegisterNumber regnum(m_thread, eRegisterKindLLDB, lldb_regnum); Log *log = GetLog(LLDBLog::Unwind); - // Have we already found this register location? - if (!m_registers.empty()) { - std::map::const_iterator - iterator; - iterator = m_registers.find(regnum.GetAsKind(eRegisterKindLLDB)); - if (iterator != m_registers.end()) { - regloc = iterator->second; - UnwindLogMsg("supplying caller's saved %s (%d)'s location, cached", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } - } - - // Look through the available UnwindPlans for the register location. - UnwindPlan::Row::AbstractRegisterLocation unwindplan_regloc; - bool have_unwindplan_regloc = false; - RegisterKind unwindplan_registerkind = kNumRegisterKinds; + // First, try to find a register location via the FastUnwindPlan if (m_fast_unwind_plan_sp) { const UnwindPlan::Row *active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); - unwindplan_registerkind = m_fast_unwind_plan_sp->GetRegisterKind(); - if (regnum.GetAsKind(unwindplan_registerkind) == LLDB_INVALID_REGNUM) { + kind = m_fast_unwind_plan_sp->GetRegisterKind(); + if (regnum.GetAsKind(kind) == LLDB_INVALID_REGNUM) { UnwindLogMsg("could not convert lldb regnum %s (%d) into %d RegisterKind " "reg numbering scheme", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - (int)unwindplan_registerkind); - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; + (int)kind); + return {}; } // The architecture default unwind plan marks unknown registers as // Undefined so that we don't forward them up the stack when a // jitted stack frame may have overwritten them. But when the // arch default unwind plan is used as the Fast Unwind Plan, we // need to recognize this & switch over to the Full Unwind Plan - // to see what unwind rule that (more knoweldgeable, probably) - // UnwindPlan has. If the full UnwindPlan says the register - // location is Undefined, then it really is. - if (active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind), + // to see what unwind rule that (more knowledgeable, probably) + // UnwindPlan has. + if (active_row->GetRegisterInfo(regnum.GetAsKind(kind), unwindplan_regloc) && !unwindplan_regloc.IsUndefined()) { UnwindLogMsg( "supplying caller's saved %s (%d)'s location using FastUnwindPlan", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - have_unwindplan_regloc = true; + return unwindplan_regloc; } } - if (!have_unwindplan_regloc) { - // m_full_unwind_plan_sp being NULL means that we haven't tried to find a - // full UnwindPlan yet - bool got_new_full_unwindplan = false; - if (!m_full_unwind_plan_sp) { - m_full_unwind_plan_sp = GetFullUnwindPlanForFrame(); - got_new_full_unwindplan = true; + // Second, try to find a register location via the FullUnwindPlan. + bool got_new_full_unwindplan = false; + if (!m_full_unwind_plan_sp) { + m_full_unwind_plan_sp = GetFullUnwindPlanForFrame(); + got_new_full_unwindplan = true; + } + if (m_full_unwind_plan_sp) { + RegisterNumber pc_regnum(m_thread, eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_PC); + + const UnwindPlan::Row *active_row = + m_full_unwind_plan_sp->GetRowForFunctionOffset( + m_current_offset_backed_up_one); + kind = m_full_unwind_plan_sp->GetRegisterKind(); + + if (got_new_full_unwindplan && active_row && log) { + StreamString active_row_strm; + ExecutionContext exe_ctx(m_thread.shared_from_this()); + active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, + m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); + UnwindLogMsg("Using full unwind plan '%s'", + m_full_unwind_plan_sp->GetSourceName().AsCString()); + UnwindLogMsg("active row: %s", active_row_strm.GetData()); } - if (m_full_unwind_plan_sp) { - RegisterNumber pc_regnum(m_thread, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_PC); + if (regnum.GetAsKind(kind) == LLDB_INVALID_REGNUM) { + if (kind == eRegisterKindGeneric) + UnwindLogMsg("could not convert lldb regnum %s (%d) into " + "eRegisterKindGeneric reg numbering scheme", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + else + UnwindLogMsg("could not convert lldb regnum %s (%d) into %d " + "RegisterKind reg numbering scheme", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), + (int)kind); + return {}; + } - const UnwindPlan::Row *active_row = - m_full_unwind_plan_sp->GetRowForFunctionOffset( - m_current_offset_backed_up_one); - unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind(); + if (regnum.IsValid() && active_row && + active_row->GetRegisterInfo(regnum.GetAsKind(kind), + unwindplan_regloc)) { + UnwindLogMsg( + "supplying caller's saved %s (%d)'s location using %s UnwindPlan", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), + m_full_unwind_plan_sp->GetSourceName().GetCString()); + return unwindplan_regloc; + } - if (got_new_full_unwindplan && active_row && log) { - StreamString active_row_strm; - ExecutionContext exe_ctx(m_thread.shared_from_this()); - active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), - &m_thread, - m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); - UnwindLogMsg("Using full unwind plan '%s'", - m_full_unwind_plan_sp->GetSourceName().AsCString()); - UnwindLogMsg("active row: %s", active_row_strm.GetData()); - } - RegisterNumber return_address_reg; - - // If we're fetching the saved pc and this UnwindPlan defines a - // ReturnAddress register (e.g. lr on arm), look for the return address - // register number in the UnwindPlan's row. - if (pc_regnum.IsValid() && pc_regnum == regnum && - m_full_unwind_plan_sp->GetReturnAddressRegister() != - LLDB_INVALID_REGNUM) { - // If this is a trap handler frame, we should have access to - // the complete register context when the interrupt/async - // signal was received, we should fetch the actual saved $pc - // value instead of the Return Address register. - // If $pc is not available, fall back to the RA reg. - UnwindPlan::Row::AbstractRegisterLocation scratch; - if (m_frame_type == eTrapHandlerFrame && active_row && - active_row->GetRegisterInfo( - pc_regnum.GetAsKind(unwindplan_registerkind), scratch)) { - UnwindLogMsg("Providing pc register instead of rewriting to " - "RA reg because this is a trap handler and there is " - "a location for the saved pc register value."); - } else { - return_address_reg.init( - m_thread, m_full_unwind_plan_sp->GetRegisterKind(), - m_full_unwind_plan_sp->GetReturnAddressRegister()); - regnum = return_address_reg; - UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a " - "RA reg; getting %s (%d) instead", - return_address_reg.GetName(), - return_address_reg.GetAsKind(eRegisterKindLLDB)); - } + // When asking for the caller's pc, and did not find a register + // location for PC above in the UnwindPlan. Check if we have a + // Return Address register on this target. + // + // On a Return Address Register architecture like arm/mips/riscv, + // the caller's pc is in the RA register, and will be spilled to + // stack before any other function is called. If no function + // has been called yet, the return address may still be in the + // live RA reg. + // + // There's a lot of variety of what we might see in an UnwindPlan. + // We may have + // ra=IsSame {unncessary} + // ra=StackAddr {caller's return addr spilled to stack} + // or no reg location for pc or ra at all, in a frameless function - + // the caller's return address is in live ra reg. + // + // If a function has been interrupted in a non-call way -- + // async signal/sigtramp, or a hardware exception / interrupt / fault -- + // then the "pc" and "ra" are two distinct values, and must be + // handled separately. The "pc" is the pc value at the point + // the function was interrupted. The "ra" is the return address + // register value at that point. + // The UnwindPlan for the sigtramp/trap handler will normally have + // register loations for both pc and lr, and so we'll have already + // fetched them above. + if (pc_regnum.IsValid() && pc_regnum == regnum) { + uint32_t return_address_regnum = LLDB_INVALID_REGNUM; + + // Get the return address register number from the UnwindPlan + // or the register set definition. + if (m_full_unwind_plan_sp->GetReturnAddressRegister() != + LLDB_INVALID_REGNUM) { + return_address_regnum = + m_full_unwind_plan_sp->GetReturnAddressRegister(); } else { - if (regnum.GetAsKind(unwindplan_registerkind) == LLDB_INVALID_REGNUM) { - if (unwindplan_registerkind == eRegisterKindGeneric) { - UnwindLogMsg("could not convert lldb regnum %s (%d) into " - "eRegisterKindGeneric reg numbering scheme", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - } else { - UnwindLogMsg("could not convert lldb regnum %s (%d) into %d " - "RegisterKind reg numbering scheme", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - (int)unwindplan_registerkind); - } - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - } - } - - // Check if the active_row has a register location listed. - if (regnum.IsValid() && active_row && - active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind), - unwindplan_regloc)) { - have_unwindplan_regloc = true; - UnwindLogMsg( - "supplying caller's saved %s (%d)'s location using %s UnwindPlan", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - m_full_unwind_plan_sp->GetSourceName().GetCString()); + RegisterNumber arch_default_ra_regnum(m_thread, eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_RA); + return_address_regnum = arch_default_ra_regnum.GetAsKind(kind); } - // This is frame 0 and we're retrieving the PC and it's saved in a Return - // Address register and it hasn't been saved anywhere yet -- that is, - // it's still live in the actual register. Handle this specially. - if (!have_unwindplan_regloc && return_address_reg.IsValid() && - return_address_reg.GetAsKind(eRegisterKindLLDB) != - LLDB_INVALID_REGNUM) { - if (IsFrameZero()) { - lldb_private::UnwindLLDB::ConcreteRegisterLocation new_regloc; - new_regloc.type = UnwindLLDB::ConcreteRegisterLocation:: - eRegisterInLiveRegisterContext; - new_regloc.location.register_number = - return_address_reg.GetAsKind(eRegisterKindLLDB); - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; - regloc = new_regloc; - UnwindLogMsg("supplying caller's register %s (%d) from the live " - "RegisterContext at frame 0, saved in %d", + // This system is using a return address register. + if (return_address_regnum != LLDB_INVALID_REGNUM) { + RegisterNumber return_address_reg; + return_address_reg.init(m_thread, + m_full_unwind_plan_sp->GetRegisterKind(), + return_address_regnum); + UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a " + "RA reg; getting %s (%d) instead", + return_address_reg.GetName(), + return_address_reg.GetAsKind(eRegisterKindLLDB)); + + // Do we have a location for the ra register? + if (active_row && + active_row->GetRegisterInfo(return_address_reg.GetAsKind(kind), + unwindplan_regloc)) { + UnwindLogMsg("supplying caller's saved %s (%d)'s location using " + "%s UnwindPlan", return_address_reg.GetName(), return_address_reg.GetAsKind(eRegisterKindLLDB), - return_address_reg.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } else if (BehavesLikeZerothFrame()) { - // This function was interrupted asynchronously -- it faulted, - // an async interrupt, a timer fired, a debugger expression etc. - // The caller's pc is in the Return Address register, but the - // UnwindPlan for this function may have no location rule for - // the RA reg. - // This means that the caller's return address is in the RA reg - // when the function was interrupted--descend down one stack frame - // to retrieve it from the trap handler's saved context. - unwindplan_regloc.SetSame(); - have_unwindplan_regloc = true; - } - } - - // If this architecture stores the return address in a register (it - // defines a Return Address register) and we're on a non-zero stack frame - // and the Full UnwindPlan says that the pc is stored in the - // RA registers (e.g. lr on arm), then we know that the full unwindplan is - // not trustworthy -- this - // is an impossible situation and the instruction emulation code has - // likely been misled. If this stack frame meets those criteria, we need - // to throw away the Full UnwindPlan that the instruction emulation came - // up with and fall back to the architecture's Default UnwindPlan so the - // stack walk can get past this point. - - // Special note: If the Full UnwindPlan was generated from the compiler, - // don't second-guess it when we're at a call site location. - - // arch_default_ra_regnum is the return address register # in the Full - // UnwindPlan register numbering - RegisterNumber arch_default_ra_regnum(m_thread, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_RA); - - if (arch_default_ra_regnum.GetAsKind(unwindplan_registerkind) != - LLDB_INVALID_REGNUM && - pc_regnum == regnum && unwindplan_regloc.IsInOtherRegister() && - unwindplan_regloc.GetRegisterNumber() == - arch_default_ra_regnum.GetAsKind(unwindplan_registerkind) && - m_full_unwind_plan_sp->GetSourcedFromCompiler() != eLazyBoolYes && - !m_all_registers_available) { - UnwindLogMsg("%s UnwindPlan tried to restore the pc from the link " - "register but this is a non-zero frame", - m_full_unwind_plan_sp->GetSourceName().GetCString()); - - // Throw away the full unwindplan; install the arch default unwindplan - if (ForceSwitchToFallbackUnwindPlan()) { - // Update for the possibly new unwind plan - unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind(); - const UnwindPlan::Row *active_row = - m_full_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); - - // Sanity check: Verify that we can fetch a pc value and CFA value - // with this unwind plan - - RegisterNumber arch_default_pc_reg(m_thread, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_PC); - bool can_fetch_pc_value = false; - bool can_fetch_cfa = false; - addr_t cfa_value; - if (active_row) { - if (arch_default_pc_reg.GetAsKind(unwindplan_registerkind) != - LLDB_INVALID_REGNUM && - active_row->GetRegisterInfo( - arch_default_pc_reg.GetAsKind(unwindplan_registerkind), - unwindplan_regloc)) { - can_fetch_pc_value = true; - } - if (ReadFrameAddress(unwindplan_registerkind, - active_row->GetCFAValue(), cfa_value)) { - can_fetch_cfa = true; - } - } - - have_unwindplan_regloc = can_fetch_pc_value && can_fetch_cfa; + m_full_unwind_plan_sp->GetSourceName().GetCString()); + // If we have "ra=IsSame", rewrite to "ra=InRegister(ra)" because the + // calling function thinks it is fetching "pc" and if we return an + // IsSame register location, it will try to read pc. + if (unwindplan_regloc.IsSame()) + unwindplan_regloc.SetInRegister(return_address_reg.GetAsKind(kind)); + return unwindplan_regloc; } else { - // We were unable to fall back to another unwind plan - have_unwindplan_regloc = false; + // No unwind rule for the return address reg on frame 0, or an + // interrupted function, means that the caller's address is still in + // RA reg (0th frame) or the trap handler below this one (sigtramp + // etc) has a save location for the RA reg. + if (BehavesLikeZerothFrame()) { + unwindplan_regloc.SetInRegister(return_address_reg.GetAsKind(kind)); + return unwindplan_regloc; + } } } } } ExecutionContext exe_ctx(m_thread.shared_from_this()); Process *process = exe_ctx.GetProcessPtr(); - if (!have_unwindplan_regloc) { - // If the UnwindPlan failed to give us an unwind location for this - // register, we may be able to fall back to some ABI-defined default. For - // example, some ABIs allow to determine the caller's SP via the CFA. Also, - // the ABI may set volatile registers to the undefined state. - ABI *abi = process ? process->GetABI().get() : nullptr; - if (abi) { - const RegisterInfo *reg_info = - GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB)); - if (reg_info && - abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) { + + // Third, try finding a register location via the ABI + // FallbackRegisterLocation. + // + // If the UnwindPlan failed to give us an unwind location for this + // register, we may be able to fall back to some ABI-defined default. For + // example, some ABIs allow to determine the caller's SP via the CFA. Also, + // the ABI willset volatile registers to the undefined state. + ABI *abi = process ? process->GetABI().get() : nullptr; + if (abi) { + const RegisterInfo *reg_info = + GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB)); + if (reg_info && + abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) { + if (!unwindplan_regloc.IsUndefined()) UnwindLogMsg( "supplying caller's saved %s (%d)'s location using ABI default", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - have_unwindplan_regloc = true; - } + // ABI defined volatile registers with no register location + // will be returned as IsUndefined, stopping the search down + // the stack. + return unwindplan_regloc; } } - if (!have_unwindplan_regloc) { - if (IsFrameZero()) { - // This is frame 0 - we should return the actual live register context - // value - lldb_private::UnwindLLDB::ConcreteRegisterLocation new_regloc; - new_regloc.type = - UnwindLLDB::ConcreteRegisterLocation::eRegisterInLiveRegisterContext; - new_regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; - regloc = new_regloc; - UnwindLogMsg("supplying caller's register %s (%d) from the live " - "RegisterContext at frame 0", + // We have no AbstractRegisterLocation, and the ABI says this is a + // non-volatile / callee-preserved register. Continue down the stack + // or to frame 0 & the live RegisterContext. + std::string unwindplan_name; + if (m_full_unwind_plan_sp) { + unwindplan_name += "via '"; + unwindplan_name += m_full_unwind_plan_sp->GetSourceName().AsCString(); + unwindplan_name += "'"; + } + UnwindLogMsg("no save location for %s (%d) %s", regnum.GetName(), + regnum.GetAsKind(eRegisterKindLLDB), unwindplan_name.c_str()); + + unwindplan_regloc.SetSame(); + return unwindplan_regloc; +} + +// Answer the question: Where did THIS frame save the CALLER frame ("previous" +// frame)'s register value? + +enum UnwindLLDB::RegisterSearchResult +RegisterContextUnwind::SavedLocationForRegister( + uint32_t lldb_regnum, + lldb_private::UnwindLLDB::ConcreteRegisterLocation ®loc) { + RegisterNumber regnum(m_thread, eRegisterKindLLDB, lldb_regnum); + Log *log = GetLog(LLDBLog::Unwind); + + // Have we already found this register location? + if (!m_registers.empty()) { + std::map::const_iterator + iterator; + iterator = m_registers.find(regnum.GetAsKind(eRegisterKindLLDB)); ---------------- labath wrote: this is one of the few officially sanctioned uses of auto ```suggestion auto iterator = m_registers.find(regnum.GetAsKind(eRegisterKindLLDB)); ``` https://github.com/llvm/llvm-project/pull/139817 From lldb-commits at lists.llvm.org Wed May 14 03:24:49 2025 From: lldb-commits at lists.llvm.org (David Spickett via lldb-commits) Date: Wed, 14 May 2025 03:24:49 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Provide lr value in faulting frame on arm64 (PR #138805) In-Reply-To: Message-ID: <68246f71.170a0220.301a26.06e0@mx.google.com> DavidSpickett wrote: > I also needed to remove the brk #0xf000 instruction because lldb is not able to step over it -- it just ends up spinning forever. FWICS, it's not actually necessary now that you're stepping through the test. Nonetheless, this is a bug -- one that @DavidSpickett might be interested in :) Yes I've been asked a few times about it. GDB also has problems with it, but probably does something slightly more useful. I'll speak to folks on that side and see how we could handle this. https://github.com/llvm/llvm-project/pull/138805 From lldb-commits at lists.llvm.org Wed May 14 03:37:36 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Wed, 14 May 2025 03:37:36 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Added 32-bit XCOFF Executable support (PR #139875) Message-ID: https://github.com/DhruvSrivastavaX created https://github.com/llvm/llvm-project/pull/139875 This PR is in reference to porting LLDB on AIX. Link to discussions on llvm discourse and github: 1. https://discourse.llvm.org/t/port-lldb-to-ibm-aix/80640 2. https://github.com/llvm/llvm-project/issues/101657 The complete changes for porting are present in this draft PR: https://github.com/llvm/llvm-project/pull/102601 **Description:** Adding support for XCOFF 32 bit file format as well in lldb, up to the point where 64-bit support is implemented. Added a new test case for the same. This is an incremental PR on top of the previous couple of XCOFF support commits. Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Wed May 14 03:38:09 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 03:38:09 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Added 32-bit XCOFF Executable support (PR #139875) In-Reply-To: Message-ID: <68247291.050a0220.cb9c3.4e14@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Dhruv Srivastava (DhruvSrivastavaX)
Changes This PR is in reference to porting LLDB on AIX. Link to discussions on llvm discourse and github: 1. https://discourse.llvm.org/t/port-lldb-to-ibm-aix/80640 2. https://github.com/llvm/llvm-project/issues/101657 The complete changes for porting are present in this draft PR: https://github.com/llvm/llvm-project/pull/102601 **Description:** Adding support for XCOFF 32 bit file format as well in lldb, up to the point where 64-bit support is implemented. Added a new test case for the same. This is an incremental PR on top of the previous couple of XCOFF support commits. --- Full diff: https://github.com/llvm/llvm-project/pull/139875.diff 3 Files Affected: - (modified) lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp (+37-17) - (modified) lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h (+13-1) - (added) lldb/test/Shell/ObjectFile/XCOFF/basic-info32.yaml (+110) ``````````diff diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index 1666677c360ba..1ad488ff20c24 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -39,7 +39,6 @@ using namespace lldb; using namespace lldb_private; LLDB_PLUGIN_DEFINE(ObjectFileXCOFF) - // FIXME: target 64bit at this moment. // Static methods. @@ -95,10 +94,11 @@ bool ObjectFileXCOFF::CreateBinary() { Log *log = GetLog(LLDBLog::Object); - auto binary = llvm::object::ObjectFile::createObjectFile( - llvm::MemoryBufferRef(toStringRef(m_data.GetData()), - m_file.GetFilename().GetStringRef()), - file_magic::xcoff_object_64); + auto memory_ref = llvm::MemoryBufferRef(toStringRef(m_data.GetData()), + m_file.GetFilename().GetStringRef()); + llvm::file_magic magic = llvm::identify_magic(memory_ref.getBuffer()); + + auto binary = llvm::object::ObjectFile::createObjectFile(memory_ref, magic); if (!binary) { LLDB_LOG_ERROR(log, binary.takeError(), "Failed to create binary for file ({1}): {0}", m_file); @@ -143,9 +143,9 @@ size_t ObjectFileXCOFF::GetModuleSpecifications( static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) { switch (magic) { - // TODO: 32bit not supported. - // case XCOFF::XCOFF32: - // return sizeof(struct llvm::object::XCOFFFileHeader32); + case XCOFF::XCOFF32: + return sizeof(struct llvm::object::XCOFFFileHeader32); + break; case XCOFF::XCOFF64: return sizeof(struct llvm::object::XCOFFFileHeader64); break; @@ -169,8 +169,9 @@ bool ObjectFileXCOFF::MagicBytesMatch(DataBufferSP &data_sp, } bool ObjectFileXCOFF::ParseHeader() { - // Only 64-bit is supported for now - return m_binary->fileHeader64()->Magic == XCOFF::XCOFF64; + if (m_binary->is64Bit()) + return m_binary->fileHeader64()->Magic == XCOFF::XCOFF64; + return m_binary->fileHeader64()->Magic == XCOFF::XCOFF32; } ByteOrder ObjectFileXCOFF::GetByteOrder() const { return eByteOrderBig; } @@ -178,8 +179,9 @@ ByteOrder ObjectFileXCOFF::GetByteOrder() const { return eByteOrderBig; } bool ObjectFileXCOFF::IsExecutable() const { return true; } uint32_t ObjectFileXCOFF::GetAddressByteSize() const { - // 32-bit not supported. return 8 for 64-bit XCOFF::XCOFF64 - return 8; + if (m_binary->is64Bit()) + return 8; + return 4; } AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) { @@ -191,20 +193,36 @@ void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) {} bool ObjectFileXCOFF::IsStripped() { return false; } void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) { + if (m_sections_up) return; m_sections_up = std::make_unique(); - ModuleSP module_sp(GetModule()); + if (m_binary->is64Bit()) + CreateSectionsWithBitness(unified_section_list); + else + CreateSectionsWithBitness(unified_section_list); +} + +template auto GetSections(llvm::object::XCOFFObjectFile *binary) { + if constexpr (T::Is64Bit) + return binary->sections64(); + else + return binary->sections32(); +} +template +void ObjectFileXCOFF::CreateSectionsWithBitness( + SectionList &unified_section_list) { + ModuleSP module_sp(GetModule()); if (!module_sp) return; std::lock_guard guard(module_sp->GetMutex()); int idx = 0; - for (const llvm::object::XCOFFSectionHeader64 §ion : - m_binary->sections64()) { + for (const typename T::SectionHeader §ion : + GetSections(m_binary.get())) { ConstString const_sect_name(section.Name); @@ -253,9 +271,11 @@ UUID ObjectFileXCOFF::GetUUID() { return UUID(); } uint32_t ObjectFileXCOFF::GetDependentModules(FileSpecList &files) { return 0; } ObjectFile::Type ObjectFileXCOFF::CalculateType() { - if (m_binary->fileHeader64()->Flags & XCOFF::F_EXEC) + if (m_binary->fileHeader64()->Flags & XCOFF::F_EXEC || + m_binary->fileHeader32()->Flags & XCOFF::F_EXEC) return eTypeExecutable; - else if (m_binary->fileHeader64()->Flags & XCOFF::F_SHROBJ) + else if (m_binary->fileHeader64()->Flags & XCOFF::F_SHROBJ || + m_binary->fileHeader32()->Flags & XCOFF::F_SHROBJ) return eTypeSharedLibrary; return eTypeUnknown; } diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h index 2d4f9f3f2dab8..d359fe6927240 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h @@ -97,6 +97,19 @@ class ObjectFileXCOFF : public lldb_private::ObjectFile { lldb::DataBufferSP header_data_sp, const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + struct XCOFF32 { + using SectionHeader = llvm::object::XCOFFSectionHeader32; + static constexpr bool Is64Bit = false; + }; + struct XCOFF64 { + using SectionHeader = llvm::object::XCOFFSectionHeader64; + static constexpr bool Is64Bit = true; + }; + + template + void + CreateSectionsWithBitness(lldb_private::SectionList &unified_section_list); + protected: static lldb::WritableDataBufferSP MapFileDataWritable(const lldb_private::FileSpec &file, uint64_t Size, @@ -104,7 +117,6 @@ class ObjectFileXCOFF : public lldb_private::ObjectFile { private: bool CreateBinary(); - std::unique_ptr m_binary; }; diff --git a/lldb/test/Shell/ObjectFile/XCOFF/basic-info32.yaml b/lldb/test/Shell/ObjectFile/XCOFF/basic-info32.yaml new file mode 100644 index 0000000000000..dd1569fe52994 --- /dev/null +++ b/lldb/test/Shell/ObjectFile/XCOFF/basic-info32.yaml @@ -0,0 +1,110 @@ +# RUN: yaml2obj %s -o %t +# RUN: lldb-test object-file %t | FileCheck %s + +# CHECK: Plugin name: xcoff +# CHECK: Architecture: powerpc64-ibm-aix +# CHECK: Executable: true +# CHECK: Stripped: false +# CHECK: Type: executable +# CHECK: Strata: unknown +# CHECK: Name: .text +# CHECK-NEXT: Type: code +# CHECK-NEXT: Permissions: r-x +# CHECK: Name: .data +# CHECK-NEXT: Type: data +# CHECK-NEXT: Permissions: rw- +# CHECK: Name: .bss +# CHECK-NEXT: Type: zero-fill +# CHECK-NEXT: Permissions: rw- +# CHECK: Name: .loader +# CHECK-NEXT: Type: regular +# CHECK-NEXT: Permissions: r-- +# CHECK: Name: .dwline +# CHECK-NEXT: Type: dwarf-line +# CHECK-NEXT: Permissions: r-- +# CHECK: Name: .dwinfo +# CHECK-NEXT: Type: dwarf-info +# CHECK-NEXT: Permissions: r-- +# CHECK: Name: .dwabrev +# CHECK-NEXT: Type: dwarf-abbrev +# CHECK-NEXT: Permissions: r-- + +--- !XCOFF +FileHeader: + MagicNumber: 0x1DF + NumberOfSections: 7 + CreationTime: 000000000 + Flags: 0x1002 +Sections: + - Name: .text + Address: 0x10000268 + Size: 0x512 + FileOffsetToData: 0x268 + FileOffsetToRelocations: 0xECC + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x24 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_TEXT ] + SectionData: 80C20000 + - Name: .data + Address: 0x2000077A + Size: 0x242 + FileOffsetToData: 0x77A + FileOffsetToRelocations: 0x1034 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x25 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_DATA ] + SectionData: '' + - Name: .bss + Address: 0x200009BC + Size: 0x10 + FileOffsetToData: 0x0 + FileOffsetToRelocations: 0x0 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x0 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_BSS ] + SectionData: '' + - Name: .loader + Address: 0x0 + Size: 0x3A4 + FileOffsetToData: 0x9BC + FileOffsetToRelocations: 0x0 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x0 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_LOADER ] + SectionData: 00000001 + - Name: .dwline + Address: 0x0 + Size: 0x73 + FileOffsetToData: 0xD60 + FileOffsetToRelocations: 0x11A6 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x5 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_DWARF ] + SectionData: FFFFFFFF + - Name: .dwinfo + Address: 0x0 + Size: 0xB4 + FileOffsetToData: 0xDD4 + FileOffsetToRelocations: 0x11D8 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x6 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_DWARF ] + SectionData: FFFFFFFF + - Name: .dwabrev + Address: 0x0 + Size: 0x43 + FileOffsetToData: 0xE88 + FileOffsetToRelocations: 0x0 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x0 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_DWARF ] + SectionData: 01110125 +StringTable: {} +... ``````````
https://github.com/llvm/llvm-project/pull/139875 From lldb-commits at lists.llvm.org Wed May 14 04:50:57 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 04:50:57 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <682483a1.170a0220.1d2365.2051@mx.google.com> https://github.com/labath edited https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Wed May 14 04:50:58 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 04:50:58 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <682483a2.170a0220.19bfd0.0ec3@mx.google.com> ================ @@ -111,7 +111,36 @@ ASTNodeUP DILParser::ParseUnaryExpression() { llvm_unreachable("invalid token kind"); } } - return ParsePrimaryExpression(); + return ParsePostfixExpression(); +} + +// Parse a postfix_expression. +// +// postfix_expression: +// primary_expression +// postfix_expression "[" expression "]" +// +ASTNodeUP DILParser::ParsePostfixExpression() { + ASTNodeUP lhs = ParsePrimaryExpression(); + while (CurToken().Is(Token::l_square)) { + uint32_t loc = CurToken().GetLocation(); + Token token = CurToken(); + switch (token.GetKind()) { + case Token::l_square: { ---------------- labath wrote: Okay... I *guess* that makes sense... https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Wed May 14 04:50:58 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 04:50:58 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <682483a2.170a0220.2c9f88.15cc@mx.google.com> https://github.com/labath commented: I'm sorry, I put this off because it wasn't clear how to respond immediately -- and then it dropped off my radar. I have a bunch of comments, but overall, I think this could work. My main objection is to the use of the APInt class. If you want to use it (which I'm fine with, but I also think a plain (u)int64_t would work for this purpose as well), then I think you should use it properly: using the operations defined on the class itself (e.g. `slt`/`ult`) -- instead of converting it to an plain integer first chance you get. As it stands now your parser will happily accept an incredibly long integer, but then you'll assert when `getZExtValue` cannot convert that to an uint64_t. There's also some confusion about whether the value is signed or unsigned. You can't just switch between `getZExtValue` and `getSExtValue` and expect the result to make sense (hint: `getSExtValue` of "0x80" parsed into an APInt is -128) https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Wed May 14 04:50:58 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 04:50:58 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <682483a2.a70a0220.14f131.221f@mx.google.com> ================ @@ -272,4 +272,67 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const ArraySubscriptNode *node) { + auto lhs_or_err = Evaluate(node->GetBase()); + if (!lhs_or_err) { + return lhs_or_err; + } + lldb::ValueObjectSP base = *lhs_or_err; + const llvm::APInt *index = node->GetIndex(); + + Status error; + if (base->GetCompilerType().IsReferenceType()) { + base = base->Dereference(error); + if (error.Fail()) + return error.ToError(); + } + + // Check to see if 'base' has a synthetic value; if so, try using that. + uint64_t child_idx = index->getZExtValue(); + if (base->HasSyntheticValue()) { + lldb::ValueObjectSP synthetic = base->GetSyntheticValue(); + if (synthetic && synthetic != base) { + uint32_t num_children = synthetic->GetNumChildrenIgnoringErrors(); ---------------- labath wrote: GetNumChildren can actually be an expensive operation (see https://github.com/llvm/llvm-project/pull/139805#issuecomment-2879353718). Just ask for the child with the given index and then deal with the error. https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Wed May 14 04:50:58 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 04:50:58 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <682483a2.170a0220.2ae179.2ccd@mx.google.com> ================ @@ -272,4 +272,67 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const ArraySubscriptNode *node) { + auto lhs_or_err = Evaluate(node->GetBase()); + if (!lhs_or_err) { + return lhs_or_err; + } ---------------- labath wrote: ```suggestion if (!lhs_or_err) return lhs_or_err; ``` https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Wed May 14 04:50:59 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 04:50:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <682483a3.170a0220.1fdb38.26a0@mx.google.com> ================ @@ -272,4 +272,67 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const ArraySubscriptNode *node) { + auto lhs_or_err = Evaluate(node->GetBase()); + if (!lhs_or_err) { + return lhs_or_err; + } + lldb::ValueObjectSP base = *lhs_or_err; + const llvm::APInt *index = node->GetIndex(); + + Status error; + if (base->GetCompilerType().IsReferenceType()) { + base = base->Dereference(error); + if (error.Fail()) + return error.ToError(); + } + + // Check to see if 'base' has a synthetic value; if so, try using that. + uint64_t child_idx = index->getZExtValue(); + if (base->HasSyntheticValue()) { + lldb::ValueObjectSP synthetic = base->GetSyntheticValue(); + if (synthetic && synthetic != base) { + uint32_t num_children = synthetic->GetNumChildrenIgnoringErrors(); + // Verify that the 'index' is not out-of-range for the declared type. + if (child_idx >= num_children) { + auto message = llvm::formatv( ---------------- labath wrote: I'm not sure this is actually correct, or expected. The type of message here is going to be `formatv_object`, and I wouldn't be surprised if it holds references to objects to objects that get destroyed at the full statement. Better explicitly make this a std::string. https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Wed May 14 04:50:59 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 04:50:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <682483a3.170a0220.215e02.2dca@mx.google.com> ================ @@ -111,7 +111,42 @@ ASTNodeUP DILParser::ParseUnaryExpression() { llvm_unreachable("invalid token kind"); } } - return ParsePrimaryExpression(); + return ParsePostfixExpression(); +} + +// Parse a postfix_expression. +// +// postfix_expression: +// primary_expression +// postfix_expression "[" integer_literal "]" +// +ASTNodeUP DILParser::ParsePostfixExpression() { + ASTNodeUP lhs = ParsePrimaryExpression(); + while (CurToken().Is(Token::l_square)) { + uint32_t loc = CurToken().GetLocation(); + Token token = CurToken(); + switch (token.GetKind()) { + case Token::l_square: { + m_dil_lexer.Advance(); + auto rhs = ParseIntegerConstant(); ---------------- labath wrote: make type explicit https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Wed May 14 04:50:59 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 04:50:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <682483a3.a70a0220.5274e.4fd4@mx.google.com> ================ @@ -272,4 +272,67 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const ArraySubscriptNode *node) { + auto lhs_or_err = Evaluate(node->GetBase()); + if (!lhs_or_err) { + return lhs_or_err; + } + lldb::ValueObjectSP base = *lhs_or_err; + const llvm::APInt *index = node->GetIndex(); + + Status error; + if (base->GetCompilerType().IsReferenceType()) { + base = base->Dereference(error); + if (error.Fail()) + return error.ToError(); + } + + // Check to see if 'base' has a synthetic value; if so, try using that. + uint64_t child_idx = index->getZExtValue(); + if (base->HasSyntheticValue()) { + lldb::ValueObjectSP synthetic = base->GetSyntheticValue(); + if (synthetic && synthetic != base) { ---------------- labath wrote: Can we simplify this? AFAICT, GetSyntheticValue should return null if there's no synthtic value, and it should never the same object, so could this be just `if (lldb::ValueObjectSP synthetic = base->GetSyntheticValue())` ? https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Wed May 14 04:50:59 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 04:50:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <682483a3.170a0220.37e90a.18a9@mx.google.com> ================ @@ -272,4 +272,67 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const ArraySubscriptNode *node) { + auto lhs_or_err = Evaluate(node->GetBase()); + if (!lhs_or_err) { + return lhs_or_err; + } + lldb::ValueObjectSP base = *lhs_or_err; + const llvm::APInt *index = node->GetIndex(); + + Status error; + if (base->GetCompilerType().IsReferenceType()) { + base = base->Dereference(error); + if (error.Fail()) + return error.ToError(); + } ---------------- labath wrote: What's the purpose of that ? GetChildAtIndex, GetChildMemberWithName, etc. work fine on reference types. https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Wed May 14 04:50:59 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 04:50:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <682483a3.a70a0220.313daf.3710@mx.google.com> ================ @@ -81,21 +100,28 @@ llvm::Expected DILLexer::Lex(llvm::StringRef expr, return Token(Token::eof, "", (uint32_t)expr.size()); uint32_t position = cur_pos - expr.begin(); + std::optional maybe_number = IsNumber(expr, remainder); + if (maybe_number) { + std::string number = (*maybe_number).str(); + return Token(Token::numeric_constant, number, position); + } ---------------- labath wrote: ```suggestion if (maybe_number) return Token(Token::numeric_constant, maybe_number->str(), position); ``` mainly because it avoids making a copy of the std::string object (without resorting to std::move) https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Wed May 14 04:50:59 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 04:50:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <682483a3.050a0220.3ae94.1f81@mx.google.com> ================ @@ -108,6 +110,26 @@ class UnaryOpNode : public ASTNode { ASTNodeUP m_operand; }; +class ArraySubscriptNode : public ASTNode { +public: + ArraySubscriptNode(uint32_t location, ASTNodeUP base, llvm::APInt index) + : ASTNode(location, NodeKind::eArraySubscriptNode), + m_base(std::move(base)), m_index(std::move(index)) {} + + llvm::Expected Accept(Visitor *v) const override; + + ASTNode *GetBase() const { return m_base.get(); } + const llvm::APInt *GetIndex() const { return &m_index; } ---------------- labath wrote: I think this should return a (const) reference to make it clear it can't be null. (I know the same can be said about the GetBase, and I'd actually do that there as well, but it's less of a surprise there since the object is already stored as a pointer) https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Wed May 14 04:50:59 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 04:50:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <682483a3.170a0220.103b38.2ef0@mx.google.com> ================ @@ -272,4 +272,67 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const ArraySubscriptNode *node) { + auto lhs_or_err = Evaluate(node->GetBase()); + if (!lhs_or_err) { + return lhs_or_err; + } + lldb::ValueObjectSP base = *lhs_or_err; + const llvm::APInt *index = node->GetIndex(); + + Status error; + if (base->GetCompilerType().IsReferenceType()) { + base = base->Dereference(error); + if (error.Fail()) + return error.ToError(); + } + + // Check to see if 'base' has a synthetic value; if so, try using that. + uint64_t child_idx = index->getZExtValue(); + if (base->HasSyntheticValue()) { + lldb::ValueObjectSP synthetic = base->GetSyntheticValue(); + if (synthetic && synthetic != base) { + uint32_t num_children = synthetic->GetNumChildrenIgnoringErrors(); + // Verify that the 'index' is not out-of-range for the declared type. + if (child_idx >= num_children) { + auto message = llvm::formatv( + "array index {0} is not valid for \"({1}) {2}\"", child_idx, + base->GetTypeName().AsCString(""), + base->GetName().AsCString()); + return llvm::make_error(m_expr, message, + node->GetLocation()); + } + + if (static_cast(child_idx) < + synthetic->GetNumChildrenIgnoringErrors()) { + lldb::ValueObjectSP child_valobj_sp = + synthetic->GetChildAtIndex(child_idx); + if (child_valobj_sp) { + return child_valobj_sp; + } + } + } + } + + auto base_type = base->GetCompilerType(); + if (!base_type.IsPointerType() && !base_type.IsArrayType()) ---------------- labath wrote: This is one of the (few) type checks that I think make sense, but I think this would read better if it was structured like: ``` if (pointer) ... else if (array) ... else /*not pointer or array*/ ``` https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Wed May 14 05:05:44 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 05:05:44 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <68248718.170a0220.3bc26a.0e18@mx.google.com> labath wrote: > Okay, I see the problem, I didn't really think that retrieving the type system when debugging Swift code would return C type system. Why is it like this though? It depends on how you retrieve the type system. You were iterating through the type systems of the target, which will return all of them because C and swift (and other languages) can coexist within the same process. There isn't such a thing as a "pure swift" application, so we should have a story for how the two will interact. Maybe story can be "we don't let the two interact", but it should be an explicit choice and we should thing through the consequences. > Is there a reliable way to get a type system of the main language? I don't think "main language" makes sense as a concept. The fact that Swift makes up 99% of your binary is not going to help you if what you really want to do is debug that 1% written in C. It *might* make sense to use the language of the currently selected frame but even there we need to be careful. The fact that you can access global variables means you can end up with non-local types even in this case. > I also found now that the function TypeSystem::GetBasicTypeFromAST that the code in Eval relies on is not even implemented in [TypeSystemSwift](https://github.com/swiftlang/llvm-project/blob/a5b0b3daf26fd41b2caf61551b72f74b0e2a4ab7/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwift.h#L296). I don't know why is that the case, but it wouldn't surprise me if that's somehow related to the fact that the BasicType enum is already very C specific. https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Wed May 14 05:23:23 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Wed, 14 May 2025 05:23:23 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Added 32-bit XCOFF Executable support (PR #139875) In-Reply-To: Message-ID: <68248b3b.170a0220.a1494.242f@mx.google.com> https://github.com/DhruvSrivastavaX updated https://github.com/llvm/llvm-project/pull/139875 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Wed May 14 06:05:24 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 06:05:24 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][test] Fix beginning/end of file test failed on Windows (PR #139278) In-Reply-To: Message-ID: <68249514.170a0220.ba589.3a49@mx.google.com> https://github.com/hapeeeeee updated https://github.com/llvm/llvm-project/pull/139278 >From 30318b28b158950b0f8d6c2732831eceb7cefc41 Mon Sep 17 00:00:00 2001 From: hapeeeeee <623151737 at qq.com> Date: Fri, 9 May 2025 22:53:03 +0800 Subject: [PATCH] [lldb][test] Fix beginning/end of file test failed on Windows --- lldb/test/Shell/Commands/Inputs/cross_platform.c | 15 +++++++++++++++ .../command-list-reach-beginning-of-file.test | 15 ++++----------- .../Commands/command-list-reach-end-of-file.test | 10 +--------- 3 files changed, 20 insertions(+), 20 deletions(-) create mode 100644 lldb/test/Shell/Commands/Inputs/cross_platform.c diff --git a/lldb/test/Shell/Commands/Inputs/cross_platform.c b/lldb/test/Shell/Commands/Inputs/cross_platform.c new file mode 100644 index 0000000000000..9349a94e0257f --- /dev/null +++ b/lldb/test/Shell/Commands/Inputs/cross_platform.c @@ -0,0 +1,15 @@ +#include +void doNothing() { printf("doNothing\n"); } + +void doSomethiing() { + doNothing(); + doNothing(); + doNothing(); +} + +int main() { + doSomethiing(); + doNothing(); + doSomethiing(); + return 0; +} diff --git a/lldb/test/Shell/Commands/command-list-reach-beginning-of-file.test b/lldb/test/Shell/Commands/command-list-reach-beginning-of-file.test index fa4a93e5904aa..aa27813bbc056 100644 --- a/lldb/test/Shell/Commands/command-list-reach-beginning-of-file.test +++ b/lldb/test/Shell/Commands/command-list-reach-beginning-of-file.test @@ -1,6 +1,4 @@ -# Source uses unistd.h. -# UNSUPPORTED: system-windows -# RUN: %clang_host -g -O0 %S/Inputs/sigchld.c -o %t.out +# RUN: %clang_host -g -O0 %S/Inputs/cross_platform.c -o %t.out # RUN: %lldb %t.out -b -s %s 2>&1 | FileCheck %s list @@ -9,17 +7,12 @@ list b main # CHECK: Breakpoint 1: + r # CHECK: int main() -list -# CHECK: if (child_pid == 0) - list - -# CHECK: int main() - -list -10 -# CHECK: #include +# CHECK: #include list - # CHECK: note: Reached beginning of the file, no more to page @@ -28,4 +21,4 @@ list - # CHECK: note: Reached beginning of the file, no more to page list -# CHECK: int main() +# CHECK: doNothing(); diff --git a/lldb/test/Shell/Commands/command-list-reach-end-of-file.test b/lldb/test/Shell/Commands/command-list-reach-end-of-file.test index edf4c521a9e76..3b6b144640921 100644 --- a/lldb/test/Shell/Commands/command-list-reach-end-of-file.test +++ b/lldb/test/Shell/Commands/command-list-reach-end-of-file.test @@ -1,6 +1,4 @@ -# Source uses unistd.h. -# UNSUPPORTED: system-windows -# RUN: %clang_host -g -O0 %S/Inputs/sigchld.c -o %t.out +# RUN: %clang_host -g -O0 %S/Inputs/cross_platform.c -o %t.out # RUN: %lldb %t.out -b -s %s 2>&1 | FileCheck %s list @@ -12,12 +10,6 @@ b main r # CHECK: int main() -list -# CHECK: if (child_pid == 0) - -list -# CHECK: printf("signo = %d\n", SIGCHLD); - list # CHECK: return 0; From lldb-commits at lists.llvm.org Wed May 14 06:08:04 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 06:08:04 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][test] Fix beginning/end of file test failed on Windows (PR #139278) In-Reply-To: Message-ID: <682495b4.170a0220.11ca71.2121@mx.google.com> https://github.com/hapeeeeee updated https://github.com/llvm/llvm-project/pull/139278 >From d1b295748d5bb4666140f37ec6896d8503239cf6 Mon Sep 17 00:00:00 2001 From: hapeeeeee <623151737 at qq.com> Date: Fri, 9 May 2025 22:53:03 +0800 Subject: [PATCH] [lldb][test] Fix beginning/end of file test failed on Windows --- lldb/test/Shell/Commands/Inputs/cross_platform.c | 15 +++++++++++++++ .../command-list-reach-beginning-of-file.test | 14 +++----------- .../Commands/command-list-reach-end-of-file.test | 10 +--------- 3 files changed, 19 insertions(+), 20 deletions(-) create mode 100644 lldb/test/Shell/Commands/Inputs/cross_platform.c diff --git a/lldb/test/Shell/Commands/Inputs/cross_platform.c b/lldb/test/Shell/Commands/Inputs/cross_platform.c new file mode 100644 index 0000000000000..9349a94e0257f --- /dev/null +++ b/lldb/test/Shell/Commands/Inputs/cross_platform.c @@ -0,0 +1,15 @@ +#include +void doNothing() { printf("doNothing\n"); } + +void doSomethiing() { + doNothing(); + doNothing(); + doNothing(); +} + +int main() { + doSomethiing(); + doNothing(); + doSomethiing(); + return 0; +} diff --git a/lldb/test/Shell/Commands/command-list-reach-beginning-of-file.test b/lldb/test/Shell/Commands/command-list-reach-beginning-of-file.test index fa4a93e5904aa..daa3a94892d63 100644 --- a/lldb/test/Shell/Commands/command-list-reach-beginning-of-file.test +++ b/lldb/test/Shell/Commands/command-list-reach-beginning-of-file.test @@ -1,6 +1,4 @@ -# Source uses unistd.h. -# UNSUPPORTED: system-windows -# RUN: %clang_host -g -O0 %S/Inputs/sigchld.c -o %t.out +# RUN: %clang_host -g -O0 %S/Inputs/cross_platform.c -o %t.out # RUN: %lldb %t.out -b -s %s 2>&1 | FileCheck %s list @@ -12,14 +10,8 @@ b main r # CHECK: int main() -list -# CHECK: if (child_pid == 0) - list - -# CHECK: int main() - -list -10 -# CHECK: #include +# CHECK: #include list - # CHECK: note: Reached beginning of the file, no more to page @@ -28,4 +20,4 @@ list - # CHECK: note: Reached beginning of the file, no more to page list -# CHECK: int main() +# CHECK: doNothing(); diff --git a/lldb/test/Shell/Commands/command-list-reach-end-of-file.test b/lldb/test/Shell/Commands/command-list-reach-end-of-file.test index edf4c521a9e76..3b6b144640921 100644 --- a/lldb/test/Shell/Commands/command-list-reach-end-of-file.test +++ b/lldb/test/Shell/Commands/command-list-reach-end-of-file.test @@ -1,6 +1,4 @@ -# Source uses unistd.h. -# UNSUPPORTED: system-windows -# RUN: %clang_host -g -O0 %S/Inputs/sigchld.c -o %t.out +# RUN: %clang_host -g -O0 %S/Inputs/cross_platform.c -o %t.out # RUN: %lldb %t.out -b -s %s 2>&1 | FileCheck %s list @@ -12,12 +10,6 @@ b main r # CHECK: int main() -list -# CHECK: if (child_pid == 0) - -list -# CHECK: printf("signo = %d\n", SIGCHLD); - list # CHECK: return 0; From lldb-commits at lists.llvm.org Wed May 14 06:08:37 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 06:08:37 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][test] Fix beginning/end of file test failed on Windows (PR #139278) In-Reply-To: Message-ID: <682495d5.050a0220.1417e0.37f8@mx.google.com> hapeeeeee wrote: > Seems fine, my only question is does the source actually need to be doing this much? > > Or in other words: the example should be as complex as it needs to be to show the bug. If that means just calling the same do-nothing function over and over to create more lines, that would be preferable. I have removed unnecessary code to ensure that the file used in the test case is as simple as possible. https://github.com/llvm/llvm-project/pull/139278 From lldb-commits at lists.llvm.org Wed May 14 06:38:29 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 06:38:29 -0700 (PDT) Subject: [Lldb-commits] [lldb] 7e7871d - [lldb] Clear loaded sections even earlier Message-ID: <68249cd5.170a0220.215e02.3c46@mx.google.com> Author: Pavel Labath Date: 2025-05-14T15:38:10+02:00 New Revision: 7e7871d3f58b9da72ca180fcd7f0d2da3f92ec4a URL: https://github.com/llvm/llvm-project/commit/7e7871d3f58b9da72ca180fcd7f0d2da3f92ec4a DIFF: https://github.com/llvm/llvm-project/commit/7e7871d3f58b9da72ca180fcd7f0d2da3f92ec4a.diff LOG: [lldb] Clear loaded sections even earlier Follow-up to #138892 fixing breakage on windows. Calling ClearAllLoadedSections earlier is necessary to avoid throwing out the work done by the windows process plugin. Added: Modified: lldb/source/Target/Process.cpp Removed: ################################################################################ diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 7c5512598bbb6..f136271a3b8a8 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -2675,6 +2675,7 @@ Status Process::LaunchPrivate(ProcessLaunchInfo &launch_info, StateType &state, m_jit_loaders_up.reset(); m_system_runtime_up.reset(); m_os_up.reset(); + GetTarget().ClearAllLoadedSections(); { std::lock_guard guard(m_process_input_reader_mutex); @@ -2763,7 +2764,6 @@ Status Process::LaunchPrivate(ProcessLaunchInfo &launch_info, StateType &state, } if (state == eStateStopped || state == eStateCrashed) { - GetTarget().ClearAllLoadedSections(); DidLaunch(); // Now that we know the process type, update its signal responses from the From lldb-commits at lists.llvm.org Wed May 14 07:21:22 2025 From: lldb-commits at lists.llvm.org (Vy Nguyen via lldb-commits) Date: Wed, 14 May 2025 07:21:22 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb]Make `list` command work with headers when possible. (PR #139002) In-Reply-To: Message-ID: <6824a6e2.170a0220.dfa74.30b4@mx.google.com> oontvoo wrote: @labath Hi, do you have any other comment on this? thanks! https://github.com/llvm/llvm-project/pull/139002 From lldb-commits at lists.llvm.org Wed May 14 07:34:56 2025 From: lldb-commits at lists.llvm.org (Kazu Hirata via lldb-commits) Date: Wed, 14 May 2025 07:34:56 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use llvm::unique (NFC) (PR #139910) Message-ID: https://github.com/kazutakahirata created https://github.com/llvm/llvm-project/pull/139910 While I am at it, this patch removes the "if" statement. std::vector::erase(first, last) doesn't do anything when first == last. Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Wed May 14 07:35:26 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 07:35:26 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use llvm::unique (NFC) (PR #139910) In-Reply-To: Message-ID: <6824aa2e.170a0220.b6a2b.4a87@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Kazu Hirata (kazutakahirata)
Changes While I am at it, this patch removes the "if" statement. std::vector::erase(first, last) doesn't do anything when first == last. --- Full diff: https://github.com/llvm/llvm-project/pull/139910.diff 1 Files Affected: - (modified) lldb/source/Target/DynamicRegisterInfo.cpp (+1-4) ``````````diff diff --git a/lldb/source/Target/DynamicRegisterInfo.cpp b/lldb/source/Target/DynamicRegisterInfo.cpp index 9ad98a41c688c..b964dc5877a97 100644 --- a/lldb/source/Target/DynamicRegisterInfo.cpp +++ b/lldb/source/Target/DynamicRegisterInfo.cpp @@ -497,10 +497,7 @@ void DynamicRegisterInfo::Finalize(const ArchSpec &arch) { pos != end; ++pos) { if (pos->second.size() > 1) { llvm::sort(pos->second); - reg_num_collection::iterator unique_end = - std::unique(pos->second.begin(), pos->second.end()); - if (unique_end != pos->second.end()) - pos->second.erase(unique_end, pos->second.end()); + pos->second.erase(llvm::unique(pos->second), pos->second.end()); } assert(!pos->second.empty()); if (pos->second.back() != LLDB_INVALID_REGNUM) ``````````
https://github.com/llvm/llvm-project/pull/139910 From lldb-commits at lists.llvm.org Wed May 14 07:43:00 2025 From: lldb-commits at lists.llvm.org (Jan Svoboda via lldb-commits) Date: Wed, 14 May 2025 07:43:00 -0700 (PDT) Subject: [Lldb-commits] [clang] [clang-tools-extra] [lldb] [clang] Remove intrusive reference count from `DiagnosticOptions` (PR #139584) In-Reply-To: Message-ID: <6824abf4.050a0220.9368e.87e2@mx.google.com> ================ @@ -2032,6 +2032,7 @@ class SourceManagerForFile { // as they are created in `createSourceManagerForFile` so that they can be // deleted in the reverse order as they are created. std::unique_ptr FileMgr; + std::unique_ptr DiagOpts; ---------------- jansvoboda11 wrote: I don't think I understand. Now that `DiagnosticOptions` are not intrusively reference-counted, raw pointers have clearer semantics than before (typically nullable non-owning borrow), no? I'd also argue that using values, references, raw pointers, `unique_ptr` and `shared_ptr` depending on the context is the clearest way to communicate lifetimes and ownership. Regardless, there's only one raw pointer to `DiagnosticOptions` remaining after my patch in `clang::tooling::ToolInvocation`, and that has exactly the semantics you'd expect: optional borrow where the owner is someone else and you expect them to keep the object alive long enough. https://github.com/llvm/llvm-project/pull/139584 From lldb-commits at lists.llvm.org Wed May 14 07:48:35 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 07:48:35 -0700 (PDT) Subject: [Lldb-commits] [lldb] Extend information for failed connection for gdb server (PR #139916) Message-ID: https://github.com/ita-sc created https://github.com/llvm/llvm-project/pull/139916 Before: ``` (lldb) r error: connect remote failed (Failed to connect port) error: Failed to connect port ``` After the patch: ``` (lldb) r error: connect remote failed (Failed to connect localhost:47140) error: Failed to connect localhost:47140 ``` >From 845a7365f4f0f2cc06a65ca36f8344f9f81ead77 Mon Sep 17 00:00:00 2001 From: Ivan Tetyushkin Date: Wed, 14 May 2025 14:47:41 +0000 Subject: [PATCH] Extend information for failed connection for gdb server Before: ``` (lldb) r error: connect remote failed (Failed to connect port) error: Failed to connect port ``` After the patch: ``` (lldb) r error: connect remote failed (Failed to connect localhost:47140) error: Failed to connect localhost:47140 ``` --- lldb/source/Host/common/TCPSocket.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/source/Host/common/TCPSocket.cpp b/lldb/source/Host/common/TCPSocket.cpp index d3282ab58b818..4148ad67b04bf 100644 --- a/lldb/source/Host/common/TCPSocket.cpp +++ b/lldb/source/Host/common/TCPSocket.cpp @@ -169,7 +169,8 @@ Status TCPSocket::Connect(llvm::StringRef name) { return error; } - error = Status::FromErrorString("Failed to connect port"); + error = Status::FromErrorStringWithFormatv("Failed to connect {0}:{1}", + host_port->hostname, host_port->port); return error; } From lldb-commits at lists.llvm.org Wed May 14 07:49:06 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 07:49:06 -0700 (PDT) Subject: [Lldb-commits] [lldb] Extend information for failed connection for gdb server (PR #139916) In-Reply-To: Message-ID: <6824ad62.170a0220.e08d5.46f6@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: None (ita-sc)
Changes Before: ``` (lldb) r error: connect remote failed (Failed to connect port) error: Failed to connect port ``` After the patch: ``` (lldb) r error: connect remote failed (Failed to connect localhost:47140) error: Failed to connect localhost:47140 ``` --- Full diff: https://github.com/llvm/llvm-project/pull/139916.diff 1 Files Affected: - (modified) lldb/source/Host/common/TCPSocket.cpp (+2-1) ``````````diff diff --git a/lldb/source/Host/common/TCPSocket.cpp b/lldb/source/Host/common/TCPSocket.cpp index d3282ab58b818..4148ad67b04bf 100644 --- a/lldb/source/Host/common/TCPSocket.cpp +++ b/lldb/source/Host/common/TCPSocket.cpp @@ -169,7 +169,8 @@ Status TCPSocket::Connect(llvm::StringRef name) { return error; } - error = Status::FromErrorString("Failed to connect port"); + error = Status::FromErrorStringWithFormatv("Failed to connect {0}:{1}", + host_port->hostname, host_port->port); return error; } ``````````
https://github.com/llvm/llvm-project/pull/139916 From lldb-commits at lists.llvm.org Wed May 14 07:50:16 2025 From: lldb-commits at lists.llvm.org (Jan Svoboda via lldb-commits) Date: Wed, 14 May 2025 07:50:16 -0700 (PDT) Subject: [Lldb-commits] [clang] [clang-tools-extra] [lldb] [clang] Remove intrusive reference count from `DiagnosticOptions` (PR #139584) In-Reply-To: Message-ID: <6824ada8.170a0220.27a782.3f35@mx.google.com> ================ @@ -107,6 +107,7 @@ class ASTUnit { private: std::unique_ptr LangOpts; + std::shared_ptr DiagOpts; ---------------- jansvoboda11 wrote: I was hoping it could be, but the situation is a bit weird. The documentation for `ASTUnit::LoadFromCommandLine()` says the `DiagnosticsEngine` parameter is expected to outlive the returned value. However, it's being passed in `IntrusiveRefCntPtr`, so the lifetime is not enforced, and of course some clients started to rely on `ASTUnit` taking shared ownership of that object. And the clients also use the `DiagnosticsEngine` object themselves after passing it to that function, so the ownership is indeed shared. And since `DiagnosticsEngine` now relies on `DiagnosticOptions` to live long enough, sharing ownership in `ASTUnit` was the best fit. Does that make sense? In general `ASTUnit` is a big pile of lifetime hacks which I'd like to clean up one day, but today is not the day. https://github.com/llvm/llvm-project/pull/139584 From lldb-commits at lists.llvm.org Wed May 14 07:50:35 2025 From: lldb-commits at lists.llvm.org (Jan Svoboda via lldb-commits) Date: Wed, 14 May 2025 07:50:35 -0700 (PDT) Subject: [Lldb-commits] [clang] [clang-tools-extra] [lldb] [clang] Remove intrusive reference count from `DiagnosticOptions` (PR #139584) In-Reply-To: Message-ID: <6824adbb.170a0220.2e4c97.44f8@mx.google.com> ================ @@ -837,6 +838,7 @@ class ASTUnit { static std::unique_ptr LoadFromCommandLine( const char **ArgBegin, const char **ArgEnd, std::shared_ptr PCHContainerOps, + std::shared_ptr DiagOpts, ---------------- jansvoboda11 wrote: Explained above. https://github.com/llvm/llvm-project/pull/139584 From lldb-commits at lists.llvm.org Wed May 14 07:52:04 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 07:52:04 -0700 (PDT) Subject: [Lldb-commits] [lldb] Extend information for failed connection for gdb server (PR #139916) In-Reply-To: Message-ID: <6824ae14.170a0220.1fbfb2.749c@mx.google.com> github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning:
You can test this locally with the following command: ``````````bash git-clang-format --diff HEAD~1 HEAD --extensions cpp -- lldb/source/Host/common/TCPSocket.cpp ``````````
View the diff from clang-format here. ``````````diff diff --git a/lldb/source/Host/common/TCPSocket.cpp b/lldb/source/Host/common/TCPSocket.cpp index 4148ad67b..b6e0f1117 100644 --- a/lldb/source/Host/common/TCPSocket.cpp +++ b/lldb/source/Host/common/TCPSocket.cpp @@ -169,8 +169,8 @@ Status TCPSocket::Connect(llvm::StringRef name) { return error; } - error = Status::FromErrorStringWithFormatv("Failed to connect {0}:{1}", - host_port->hostname, host_port->port); + error = Status::FromErrorStringWithFormatv( + "Failed to connect {0}:{1}", host_port->hostname, host_port->port); return error; } ``````````
https://github.com/llvm/llvm-project/pull/139916 From lldb-commits at lists.llvm.org Wed May 14 08:03:29 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 08:03:29 -0700 (PDT) Subject: [Lldb-commits] [lldb] Extend information for failed connection for gdb server (PR #139916) In-Reply-To: Message-ID: <6824b0c1.170a0220.e868f.7a67@mx.google.com> https://github.com/ita-sc updated https://github.com/llvm/llvm-project/pull/139916 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Wed May 14 08:09:07 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 08:09:07 -0700 (PDT) Subject: [Lldb-commits] [clang] [clang-tools-extra] [lldb] [clang] Remove intrusive reference count from `DiagnosticOptions` (PR #139584) In-Reply-To: Message-ID: <6824b213.170a0220.da692.9262@mx.google.com> ================ @@ -107,6 +107,7 @@ class ASTUnit { private: std::unique_ptr LangOpts; + std::shared_ptr DiagOpts; ---------------- cor3ntin wrote: Ouch, this is not great :smile: Can you leave a FIXME comment in the source? Thanks https://github.com/llvm/llvm-project/pull/139584 From lldb-commits at lists.llvm.org Wed May 14 08:24:08 2025 From: lldb-commits at lists.llvm.org (Jan Svoboda via lldb-commits) Date: Wed, 14 May 2025 08:24:08 -0700 (PDT) Subject: [Lldb-commits] [clang] [clang-tools-extra] [lldb] [clang] Remove intrusive reference count from `DiagnosticOptions` (PR #139584) In-Reply-To: Message-ID: <6824b598.170a0220.dfa74.83dc@mx.google.com> https://github.com/jansvoboda11 updated https://github.com/llvm/llvm-project/pull/139584 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Wed May 14 08:32:34 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 08:32:34 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb]Make `list` command work with headers when possible. (PR #139002) In-Reply-To: Message-ID: <6824b792.050a0220.b0a03.d823@mx.google.com> ================ @@ -714,6 +714,8 @@ uint32_t ModuleList::ResolveSymbolContextsForFileSpec( const FileSpec &file_spec, uint32_t line, bool check_inlines, SymbolContextItem resolve_scope, SymbolContextList &sc_list) const { std::lock_guard guard(m_modules_mutex); + // If we're looking for a header (not source), then need to check inline. + check_inlines = check_inlines || !file_spec.IsSourceImplementationFile(); ---------------- labath wrote: I don't think this should be done here. The breakpoint setting code also goes through this code path and it works fine without it. I suggest looking at how that works and emulating it. I suspect it involves looking at the `target.inline-breakpoint-strategy` setting. I think it'd make sense to do that here as well (if anyone disagrees with that, do chime in), even though the setting is called inline-*breakpoint*-strategy, as the setting is really about where we go to search when looking up a file. https://github.com/llvm/llvm-project/pull/139002 From lldb-commits at lists.llvm.org Wed May 14 08:48:17 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 08:48:17 -0700 (PDT) Subject: [Lldb-commits] [clang] [clang-tools-extra] [lldb] [clang] Remove intrusive reference count from `DiagnosticOptions` (PR #139584) In-Reply-To: Message-ID: <6824bb41.170a0220.185401.c8e0@mx.google.com> https://github.com/cor3ntin approved this pull request. https://github.com/llvm/llvm-project/pull/139584 From lldb-commits at lists.llvm.org Wed May 14 08:48:52 2025 From: lldb-commits at lists.llvm.org (Alexey Karyakin via lldb-commits) Date: Wed, 14 May 2025 08:48:52 -0700 (PDT) Subject: [Lldb-commits] =?utf-8?q?=5Blldb=5D_=5Bllvm=5D_Modify_the_localCa?= =?utf-8?q?che_API_to_require_an_explicit_commit_on_CachedFile=E2=80=A6_?= =?utf-8?b?KFBSICMxMzYxMjEp?= In-Reply-To: Message-ID: <6824bb64.050a0220.3201f7.e279@mx.google.com> quic-akaryaki wrote: @anjenner : an alternative way to report error would be to pass a "diagnostic object" to CachedFileStream that would collect errors happening during calling its destructors, report them later, and fail the compilation if any. That might have been a less intrusive way. https://github.com/llvm/llvm-project/pull/136121 From lldb-commits at lists.llvm.org Wed May 14 09:10:53 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 09:10:53 -0700 (PDT) Subject: [Lldb-commits] [lldb] 998dca4 - [lldb-dap] Add unit test for protocol enum types (#139848) Message-ID: <6824c08d.050a0220.18a33d.d1a2@mx.google.com> Author: Jonas Devlieghere Date: 2025-05-14T09:10:49-07:00 New Revision: 998dca42351f3292512af56207b603dc2fef565b URL: https://github.com/llvm/llvm-project/commit/998dca42351f3292512af56207b603dc2fef565b DIFF: https://github.com/llvm/llvm-project/commit/998dca42351f3292512af56207b603dc2fef565b.diff LOG: [lldb-dap] Add unit test for protocol enum types (#139848) Add dedicated unit tests for the protocol enum types. Added: Modified: lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp lldb/tools/lldb-dap/Protocol/ProtocolTypes.h lldb/unittests/DAP/ProtocolTypesTest.cpp Removed: ################################################################################ diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index fafd061334bc9..857503b3a0084 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -105,7 +105,7 @@ bool fromJSON(const json::Value &Params, ColumnType &CT, json::Path P) { .Case("string", eColumnTypeString) .Case("number", eColumnTypeNumber) .Case("boolean", eColumnTypeBoolean) - .Case("unixTimestampUTC ", eColumnTypeTimestamp) + .Case("unixTimestampUTC", eColumnTypeTimestamp) .Default(std::nullopt); if (!columnType) { P.report("unexpected value, expected 'string', 'number', 'boolean', or " @@ -482,6 +482,18 @@ bool fromJSON(const llvm::json::Value &Params, SteppingGranularity &SG, return true; } +llvm::json::Value toJSON(const SteppingGranularity &SG) { + switch (SG) { + case eSteppingGranularityStatement: + return "statement"; + case eSteppingGranularityLine: + return "line"; + case eSteppingGranularityInstruction: + return "instruction"; + } + llvm_unreachable("unhandled stepping granularity."); +} + bool fromJSON(const llvm::json::Value &Params, ValueFormat &VF, llvm::json::Path P) { json::ObjectMapper O(Params, P); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index f8d2b35ce3e14..757037a7b6ed2 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -339,6 +339,7 @@ enum SteppingGranularity : unsigned { }; bool fromJSON(const llvm::json::Value &, SteppingGranularity &, llvm::json::Path); +llvm::json::Value toJSON(const SteppingGranularity &); /// Provides formatting information for a value. struct ValueFormat { diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp index fd3e3be073183..d97bbaffa2bc0 100644 --- a/lldb/unittests/DAP/ProtocolTypesTest.cpp +++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp @@ -291,3 +291,201 @@ TEST(ProtocolTypesTest, Capabilities) { EXPECT_EQ(capabilities.lldbExtVersion, deserialized_capabilities->lldbExtVersion); } + +TEST(ProtocolTypesTest, PresentationHint) { + // Test all PresentationHint values. + std::vector> test_cases = { + {ePresentationHintNormal, "normal"}, + {ePresentationHintEmphasize, "emphasize"}, + {ePresentationHintDeemphasize, "deemphasize"}}; + + for (const auto &test_case : test_cases) { + // Serialize the PresentationHint to JSON. + llvm::json::Value serialized = toJSON(test_case.first); + ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String); + EXPECT_EQ(serialized.getAsString(), test_case.second); + + // Deserialize the JSON back to PresentationHint. + PresentationHint deserialized; + llvm::json::Path::Root root; + ASSERT_TRUE(fromJSON(serialized, deserialized, root)) + << llvm::toString(root.getError()); + EXPECT_EQ(deserialized, test_case.first); + } + + // Test invalid value. + llvm::json::Value invalid_value = "invalid_hint"; + PresentationHint deserialized_invalid; + llvm::json::Path::Root root; + EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root)); +} + +TEST(ProtocolTypesTest, SteppingGranularity) { + // Test all SteppingGranularity values. + std::vector> test_cases = { + {eSteppingGranularityStatement, "statement"}, + {eSteppingGranularityLine, "line"}, + {eSteppingGranularityInstruction, "instruction"}}; + + for (const auto &test_case : test_cases) { + // Serialize the SteppingGranularity to JSON. + llvm::json::Value serialized = toJSON(test_case.first); + ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String); + EXPECT_EQ(serialized.getAsString(), test_case.second); + + // Deserialize the JSON back to SteppingGranularity. + SteppingGranularity deserialized; + llvm::json::Path::Root root; + ASSERT_TRUE(fromJSON(serialized, deserialized, root)) + << llvm::toString(root.getError()); + EXPECT_EQ(deserialized, test_case.first); + } + + // Test invalid value. + llvm::json::Value invalid_value = "invalid_granularity"; + SteppingGranularity deserialized_invalid; + llvm::json::Path::Root root; + EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root)); +} + +TEST(ProtocolTypesTest, BreakpointReason) { + // Test all BreakpointReason values. + std::vector> test_cases = { + {BreakpointReason::eBreakpointReasonPending, "pending"}, + {BreakpointReason::eBreakpointReasonFailed, "failed"}}; + + for (const auto &test_case : test_cases) { + // Serialize the BreakpointReason to JSON. + llvm::json::Value serialized = toJSON(test_case.first); + ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String); + EXPECT_EQ(serialized.getAsString(), test_case.second); + + // Deserialize the JSON back to BreakpointReason. + BreakpointReason deserialized; + llvm::json::Path::Root root; + ASSERT_TRUE(fromJSON(serialized, deserialized, root)) + << llvm::toString(root.getError()); + EXPECT_EQ(deserialized, test_case.first); + } + + // Test invalid value. + llvm::json::Value invalid_value = "invalid_reason"; + BreakpointReason deserialized_invalid; + llvm::json::Path::Root root; + EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root)); +} + +TEST(ProtocolTypesTest, DataBreakpointAccessType) { + // Test all DataBreakpointAccessType values. + std::vector> test_cases = + {{eDataBreakpointAccessTypeRead, "read"}, + {eDataBreakpointAccessTypeWrite, "write"}, + {eDataBreakpointAccessTypeReadWrite, "readWrite"}}; + + for (const auto &test_case : test_cases) { + // Serialize the DataBreakpointAccessType to JSON. + llvm::json::Value serialized = toJSON(test_case.first); + ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String); + EXPECT_EQ(serialized.getAsString(), test_case.second); + + // Deserialize the JSON back to DataBreakpointAccessType. + DataBreakpointAccessType deserialized; + llvm::json::Path::Root root; + ASSERT_TRUE(fromJSON(serialized, deserialized, root)) + << llvm::toString(root.getError()); + EXPECT_EQ(deserialized, test_case.first); + } + + // Test invalid value + llvm::json::Value invalid_value = "invalid_access_type"; + DataBreakpointAccessType deserialized_invalid; + llvm::json::Path::Root root; + EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root)); +} + +TEST(ProtocolTypesTest, ColumnType) { + // Test all ColumnType values. + std::vector> test_cases = { + {eColumnTypeString, "string"}, + {eColumnTypeNumber, "number"}, + {eColumnTypeBoolean, "boolean"}, + {eColumnTypeTimestamp, "unixTimestampUTC"}}; + + for (const auto &test_case : test_cases) { + // Serialize the ColumnType to JSON. + llvm::json::Value serialized = toJSON(test_case.first); + ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String); + EXPECT_EQ(serialized.getAsString(), test_case.second); + + // Deserialize the JSON back to ColumnType. + ColumnType deserialized; + llvm::json::Path::Root root; + ASSERT_TRUE(fromJSON(serialized, deserialized, root)) + << llvm::toString(root.getError()); + EXPECT_EQ(deserialized, test_case.first); + } + + // Test invalid value. + llvm::json::Value invalid_value = "invalid_column_type"; + ColumnType deserialized_invalid; + llvm::json::Path::Root root; + EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root)); +} + +TEST(ProtocolTypesTest, BreakpointModeApplicability) { + // Test all BreakpointModeApplicability values. + std::vector> + test_cases = {{eBreakpointModeApplicabilitySource, "source"}, + {eBreakpointModeApplicabilityException, "exception"}, + {eBreakpointModeApplicabilityData, "data"}, + {eBreakpointModeApplicabilityInstruction, "instruction"}}; + + for (const auto &test_case : test_cases) { + // Serialize the BreakpointModeApplicability to JSON. + llvm::json::Value serialized = toJSON(test_case.first); + ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String); + EXPECT_EQ(serialized.getAsString(), test_case.second); + + // Deserialize the JSON back to BreakpointModeApplicability. + BreakpointModeApplicability deserialized; + llvm::json::Path::Root root; + ASSERT_TRUE(fromJSON(serialized, deserialized, root)) + << llvm::toString(root.getError()); + EXPECT_EQ(deserialized, test_case.first); + } + + // Test invalid value. + llvm::json::Value invalid_value = "invalid_applicability"; + BreakpointModeApplicability deserialized_invalid; + llvm::json::Path::Root root; + EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root)); +} + +TEST(ProtocolTypesTest, ChecksumAlgorithm) { + // Test all ChecksumAlgorithm values. + std::vector> test_cases = { + {eChecksumAlgorithmMD5, "MD5"}, + {eChecksumAlgorithmSHA1, "SHA1"}, + {eChecksumAlgorithmSHA256, "SHA256"}, + {eChecksumAlgorithmTimestamp, "timestamp"}}; + + for (const auto &test_case : test_cases) { + // Serialize the ChecksumAlgorithm to JSON. + llvm::json::Value serialized = toJSON(test_case.first); + ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String); + EXPECT_EQ(serialized.getAsString(), test_case.second); + + // Deserialize the JSON back to ChecksumAlgorithm. + ChecksumAlgorithm deserialized; + llvm::json::Path::Root root; + ASSERT_TRUE(fromJSON(serialized, deserialized, root)) + << llvm::toString(root.getError()); + EXPECT_EQ(deserialized, test_case.first); + } + + // Test invalid value. + llvm::json::Value invalid_value = "invalid_algorithm"; + ChecksumAlgorithm deserialized_invalid; + llvm::json::Path::Root root; + EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root)); +} From lldb-commits at lists.llvm.org Wed May 14 09:10:55 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 09:10:55 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for protocol enum types (PR #139848) In-Reply-To: Message-ID: <6824c08f.170a0220.e5844.bcd5@mx.google.com> https://github.com/JDevlieghere closed https://github.com/llvm/llvm-project/pull/139848 From lldb-commits at lists.llvm.org Wed May 14 09:15:19 2025 From: lldb-commits at lists.llvm.org (Chelsea Cassanova via lldb-commits) Date: Wed, 14 May 2025 09:15:19 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream RPC server interface emitters (PR #138032) In-Reply-To: Message-ID: <6824c197.620a0220.97895.bff2@mx.google.com> https://github.com/chelcassanova updated https://github.com/llvm/llvm-project/pull/138032 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Wed May 14 09:15:23 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 09:15:23 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding unit tests for Transport. (PR #139926) Message-ID: https://github.com/ashgti created https://github.com/llvm/llvm-project/pull/139926 This adds basic support for testing the Transport class and includes tests for 'Read'. >From 506e8107a397e2ae88d8b952c0a5351cda9fa161 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 14 May 2025 09:13:32 -0700 Subject: [PATCH] [lldb-dap] Adding unittests for Transport. This adds basic support for testing the Transport class and includes tests for 'Read'. --- lldb/unittests/DAP/CMakeLists.txt | 1 + lldb/unittests/DAP/TransportTest.cpp | 81 ++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 lldb/unittests/DAP/TransportTest.cpp diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index 8b240654046e2..110733e93b192 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -1,6 +1,7 @@ add_lldb_unittest(DAPTests JSONUtilsTest.cpp LLDBUtilsTest.cpp + TransportTest.cpp ProtocolTypesTest.cpp LINK_LIBS diff --git a/lldb/unittests/DAP/TransportTest.cpp b/lldb/unittests/DAP/TransportTest.cpp new file mode 100644 index 0000000000000..d27167cf9da61 --- /dev/null +++ b/lldb/unittests/DAP/TransportTest.cpp @@ -0,0 +1,81 @@ +//===-- LLDBUtilsTest.cpp -------------------------------------------------===// +// +// 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 "Transport.h" +#include "Protocol/ProtocolBase.h" +#include "lldb/Host/File.h" +#include "lldb/Host/Pipe.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include +#include + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; +using namespace lldb_dap; +using namespace lldb_dap::protocol; + +class TransportTest : public testing::Test { +protected: + Pipe input; + Pipe output; + std::unique_ptr transport; + + void SetUp() override { + ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), llvm::Succeeded()); + ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), llvm::Succeeded()); + transport = std::make_unique( + "stdio", nullptr, + std::make_shared(input.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(output.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + } + + void Write(StringRef json) { + std::string message = + formatv("Content-Length: {0}\r\n\r\n{1}", json.size(), json).str(); + ASSERT_THAT_EXPECTED(input.Write(message.data(), message.size()), + Succeeded()); + } +}; + +TEST_F(TransportTest, MalformedRequests) { + std::string malformed_header = "COnTent-LenGth: -1{}\r\n\r\nnotjosn"; + ASSERT_THAT_EXPECTED( + input.Write(malformed_header.data(), malformed_header.size()), + Succeeded()); + ASSERT_THAT_EXPECTED( + transport->Read(std::chrono::milliseconds(1)), + FailedWithMessage( + "expected 'Content-Length: ' and got 'COnTent-LenGth: '")); +} + +TEST_F(TransportTest, Read) { + Write(R"json({"seq": 1, "type": "request", "command": "abc"})json"); + ASSERT_THAT_EXPECTED(transport->Read(std::chrono::milliseconds(1)), + HasValue(testing::VariantWith( + testing::FieldsAre(1, "abc", std::nullopt)))); +} + +TEST_F(TransportTest, ReadWithTimeout) { + ASSERT_THAT_EXPECTED(transport->Read(std::chrono::milliseconds(1)), + Failed()); +} + +TEST_F(TransportTest, ReadWithEOF) { + input.CloseWriteFileDescriptor(); + ASSERT_THAT_EXPECTED(transport->Read(std::chrono::milliseconds(1)), + Failed()); +} From lldb-commits at lists.llvm.org Wed May 14 09:15:58 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 09:15:58 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding unit tests for Transport. (PR #139926) In-Reply-To: Message-ID: <6824c1be.170a0220.38245e.da66@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: John Harrison (ashgti)
Changes This adds basic support for testing the Transport class and includes tests for 'Read'. --- Full diff: https://github.com/llvm/llvm-project/pull/139926.diff 2 Files Affected: - (modified) lldb/unittests/DAP/CMakeLists.txt (+1) - (added) lldb/unittests/DAP/TransportTest.cpp (+81) ``````````diff diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index 8b240654046e2..110733e93b192 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -1,6 +1,7 @@ add_lldb_unittest(DAPTests JSONUtilsTest.cpp LLDBUtilsTest.cpp + TransportTest.cpp ProtocolTypesTest.cpp LINK_LIBS diff --git a/lldb/unittests/DAP/TransportTest.cpp b/lldb/unittests/DAP/TransportTest.cpp new file mode 100644 index 0000000000000..d27167cf9da61 --- /dev/null +++ b/lldb/unittests/DAP/TransportTest.cpp @@ -0,0 +1,81 @@ +//===-- LLDBUtilsTest.cpp -------------------------------------------------===// +// +// 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 "Transport.h" +#include "Protocol/ProtocolBase.h" +#include "lldb/Host/File.h" +#include "lldb/Host/Pipe.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include +#include + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; +using namespace lldb_dap; +using namespace lldb_dap::protocol; + +class TransportTest : public testing::Test { +protected: + Pipe input; + Pipe output; + std::unique_ptr transport; + + void SetUp() override { + ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), llvm::Succeeded()); + ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), llvm::Succeeded()); + transport = std::make_unique( + "stdio", nullptr, + std::make_shared(input.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(output.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + } + + void Write(StringRef json) { + std::string message = + formatv("Content-Length: {0}\r\n\r\n{1}", json.size(), json).str(); + ASSERT_THAT_EXPECTED(input.Write(message.data(), message.size()), + Succeeded()); + } +}; + +TEST_F(TransportTest, MalformedRequests) { + std::string malformed_header = "COnTent-LenGth: -1{}\r\n\r\nnotjosn"; + ASSERT_THAT_EXPECTED( + input.Write(malformed_header.data(), malformed_header.size()), + Succeeded()); + ASSERT_THAT_EXPECTED( + transport->Read(std::chrono::milliseconds(1)), + FailedWithMessage( + "expected 'Content-Length: ' and got 'COnTent-LenGth: '")); +} + +TEST_F(TransportTest, Read) { + Write(R"json({"seq": 1, "type": "request", "command": "abc"})json"); + ASSERT_THAT_EXPECTED(transport->Read(std::chrono::milliseconds(1)), + HasValue(testing::VariantWith( + testing::FieldsAre(1, "abc", std::nullopt)))); +} + +TEST_F(TransportTest, ReadWithTimeout) { + ASSERT_THAT_EXPECTED(transport->Read(std::chrono::milliseconds(1)), + Failed()); +} + +TEST_F(TransportTest, ReadWithEOF) { + input.CloseWriteFileDescriptor(); + ASSERT_THAT_EXPECTED(transport->Read(std::chrono::milliseconds(1)), + Failed()); +} ``````````
https://github.com/llvm/llvm-project/pull/139926 From lldb-commits at lists.llvm.org Wed May 14 09:16:46 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 09:16:46 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding unit tests for Transport. (PR #139926) In-Reply-To: Message-ID: <6824c1ee.170a0220.32a642.ce88@mx.google.com> https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/139926 >From 506e8107a397e2ae88d8b952c0a5351cda9fa161 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 14 May 2025 09:13:32 -0700 Subject: [PATCH 1/2] [lldb-dap] Adding unittests for Transport. This adds basic support for testing the Transport class and includes tests for 'Read'. --- lldb/unittests/DAP/CMakeLists.txt | 1 + lldb/unittests/DAP/TransportTest.cpp | 81 ++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 lldb/unittests/DAP/TransportTest.cpp diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index 8b240654046e2..110733e93b192 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -1,6 +1,7 @@ add_lldb_unittest(DAPTests JSONUtilsTest.cpp LLDBUtilsTest.cpp + TransportTest.cpp ProtocolTypesTest.cpp LINK_LIBS diff --git a/lldb/unittests/DAP/TransportTest.cpp b/lldb/unittests/DAP/TransportTest.cpp new file mode 100644 index 0000000000000..d27167cf9da61 --- /dev/null +++ b/lldb/unittests/DAP/TransportTest.cpp @@ -0,0 +1,81 @@ +//===-- LLDBUtilsTest.cpp -------------------------------------------------===// +// +// 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 "Transport.h" +#include "Protocol/ProtocolBase.h" +#include "lldb/Host/File.h" +#include "lldb/Host/Pipe.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include +#include + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; +using namespace lldb_dap; +using namespace lldb_dap::protocol; + +class TransportTest : public testing::Test { +protected: + Pipe input; + Pipe output; + std::unique_ptr transport; + + void SetUp() override { + ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), llvm::Succeeded()); + ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), llvm::Succeeded()); + transport = std::make_unique( + "stdio", nullptr, + std::make_shared(input.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(output.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + } + + void Write(StringRef json) { + std::string message = + formatv("Content-Length: {0}\r\n\r\n{1}", json.size(), json).str(); + ASSERT_THAT_EXPECTED(input.Write(message.data(), message.size()), + Succeeded()); + } +}; + +TEST_F(TransportTest, MalformedRequests) { + std::string malformed_header = "COnTent-LenGth: -1{}\r\n\r\nnotjosn"; + ASSERT_THAT_EXPECTED( + input.Write(malformed_header.data(), malformed_header.size()), + Succeeded()); + ASSERT_THAT_EXPECTED( + transport->Read(std::chrono::milliseconds(1)), + FailedWithMessage( + "expected 'Content-Length: ' and got 'COnTent-LenGth: '")); +} + +TEST_F(TransportTest, Read) { + Write(R"json({"seq": 1, "type": "request", "command": "abc"})json"); + ASSERT_THAT_EXPECTED(transport->Read(std::chrono::milliseconds(1)), + HasValue(testing::VariantWith( + testing::FieldsAre(1, "abc", std::nullopt)))); +} + +TEST_F(TransportTest, ReadWithTimeout) { + ASSERT_THAT_EXPECTED(transport->Read(std::chrono::milliseconds(1)), + Failed()); +} + +TEST_F(TransportTest, ReadWithEOF) { + input.CloseWriteFileDescriptor(); + ASSERT_THAT_EXPECTED(transport->Read(std::chrono::milliseconds(1)), + Failed()); +} >From 8d5ffc83c6fce70a3fe66fb726781e7bd2b08d77 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 14 May 2025 09:16:34 -0700 Subject: [PATCH 2/2] Fixing the filename in the top comment. --- lldb/unittests/DAP/TransportTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/unittests/DAP/TransportTest.cpp b/lldb/unittests/DAP/TransportTest.cpp index d27167cf9da61..b8eade5442814 100644 --- a/lldb/unittests/DAP/TransportTest.cpp +++ b/lldb/unittests/DAP/TransportTest.cpp @@ -1,4 +1,4 @@ -//===-- LLDBUtilsTest.cpp -------------------------------------------------===// +//===-- TransportTest.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. From lldb-commits at lists.llvm.org Wed May 14 09:17:16 2025 From: lldb-commits at lists.llvm.org (Chelsea Cassanova via lldb-commits) Date: Wed, 14 May 2025 09:17:16 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream RPC server interface emitters (PR #138032) In-Reply-To: Message-ID: <6824c20c.050a0220.460ce.e923@mx.google.com> https://github.com/chelcassanova updated https://github.com/llvm/llvm-project/pull/138032 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Wed May 14 09:23:30 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 09:23:30 -0700 (PDT) Subject: [Lldb-commits] [lldb] 5fb9dca - Revert "[lldb] Call Target::ClearAllLoadedSections earlier (#138892)" Message-ID: <6824c382.050a0220.30beba.d132@mx.google.com> Author: Pavel Labath Date: 2025-05-14T18:22:02+02:00 New Revision: 5fb9dca14aeaf12219ff149bf3a4f94c8dc58d8b URL: https://github.com/llvm/llvm-project/commit/5fb9dca14aeaf12219ff149bf3a4f94c8dc58d8b DIFF: https://github.com/llvm/llvm-project/commit/5fb9dca14aeaf12219ff149bf3a4f94c8dc58d8b.diff LOG: Revert "[lldb] Call Target::ClearAllLoadedSections earlier (#138892)" This reverts commit 97aa01bef770ec651c86978d137933e09221dd00 and 7e7871d3f58b9da72ca180fcd7f0d2da3f92ec4a due to failures on windows. Added: Modified: lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp lldb/source/Target/Process.cpp lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py Removed: ################################################################################ diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp index 1270d57423c7b..578ab12268ea3 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp @@ -872,6 +872,7 @@ void DynamicLoaderDarwin::PrivateInitialize(Process *process) { StateAsCString(m_process->GetState())); Clear(true); m_process = process; + m_process->GetTarget().ClearAllLoadedSections(); } // Member function that gets called when the process state changes. diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index f136271a3b8a8..13ff12b4ff953 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -2675,7 +2675,6 @@ Status Process::LaunchPrivate(ProcessLaunchInfo &launch_info, StateType &state, m_jit_loaders_up.reset(); m_system_runtime_up.reset(); m_os_up.reset(); - GetTarget().ClearAllLoadedSections(); { std::lock_guard guard(m_process_input_reader_mutex); @@ -2800,7 +2799,6 @@ Status Process::LaunchPrivate(ProcessLaunchInfo &launch_info, StateType &state, } Status Process::LoadCore() { - GetTarget().ClearAllLoadedSections(); Status error = DoLoadCore(); if (error.Success()) { ListenerSP listener_sp( @@ -3096,8 +3094,6 @@ void Process::CompleteAttach() { Log *log(GetLog(LLDBLog::Process | LLDBLog::Target)); LLDB_LOGF(log, "Process::%s()", __FUNCTION__); - GetTarget().ClearAllLoadedSections(); - // Let the process subclass figure out at much as it can about the process // before we go looking for a dynamic loader plug-in. ArchSpec process_arch; diff --git a/lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py b/lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py index faa35421ff60b..cd95a9ff3fe8c 100644 --- a/lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py +++ b/lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py @@ -282,6 +282,7 @@ def test_from_forward_decl(self): @no_debug_info_test @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24663") + @expectedFailureDarwin # dynamic loader unloads modules @expectedFailureAll(archs=["arm"]) # Minidump saving not implemented def test_from_core_file(self): """Test fetching C++ dynamic values from core files. Specifically, test From lldb-commits at lists.llvm.org Wed May 14 09:24:26 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Wed, 14 May 2025 09:24:26 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Fix offset computation in RegisterContextUnwind (PR #137155) In-Reply-To: Message-ID: <6824c3ba.170a0220.31c209.e660@mx.google.com> labath wrote: Jason, could you take a look at this as well? https://github.com/llvm/llvm-project/pull/137155 From lldb-commits at lists.llvm.org Wed May 14 09:26:10 2025 From: lldb-commits at lists.llvm.org (Chelsea Cassanova via lldb-commits) Date: Wed, 14 May 2025 09:26:10 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream RPC server interface emitters (PR #138032) In-Reply-To: Message-ID: <6824c422.170a0220.19c0e7.bf30@mx.google.com> chelcassanova wrote: Pushed again to address David's comments and remove most of the FIXMEs. There's one FIXME I've kept in for now: ``` // FIXME: SB class server references are stored as non-const references so // that we can actually change them as needed. If a parameter is marked // const, we will fail to compile because we cannot make an // SBFooServerReference from a `const SBFoo &`. // To work around this issue, we'll apply a `const_cast` if needed so we // can continue to generate callbacks for now, but we really should // rethink the way we store object IDs server-side to support // const-qualified parameters. ``` @bulbazord This is referring to how we emit storage for const SB parameters in callback functions. Currently it looks like it only gets applied to one function that gets generated. Any thoughts here? https://github.com/llvm/llvm-project/pull/138032 From lldb-commits at lists.llvm.org Wed May 14 09:27:03 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 09:27:03 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding unit tests for Transport. (PR #139926) In-Reply-To: Message-ID: <6824c457.630a0220.1d31d0.516b@mx.google.com> https://github.com/JDevlieghere approved this pull request. https://github.com/llvm/llvm-project/pull/139926 From lldb-commits at lists.llvm.org Wed May 14 09:29:06 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 09:29:06 -0700 (PDT) Subject: [Lldb-commits] [lldb] Extend information for failed connection for gdb server (PR #139916) In-Reply-To: Message-ID: <6824c4d2.170a0220.e637b.d935@mx.google.com> https://github.com/JDevlieghere edited https://github.com/llvm/llvm-project/pull/139916 From lldb-commits at lists.llvm.org Wed May 14 09:29:06 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 09:29:06 -0700 (PDT) Subject: [Lldb-commits] [lldb] Extend information for failed connection for gdb server (PR #139916) In-Reply-To: Message-ID: <6824c4d2.170a0220.385598.bbcf@mx.google.com> ================ @@ -169,7 +169,8 @@ Status TCPSocket::Connect(llvm::StringRef name) { return error; } - error = Status::FromErrorString("Failed to connect port"); + error = Status::FromErrorStringWithFormatv( + "Failed to connect {0}:{1}", host_port->hostname, host_port->port); ---------------- JDevlieghere wrote: ```suggestion error = Status::FromErrorStringWithFormatv( "Failed to connect to {0}:{1}", host_port->hostname, host_port->port); ``` https://github.com/llvm/llvm-project/pull/139916 From lldb-commits at lists.llvm.org Wed May 14 09:29:06 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 09:29:06 -0700 (PDT) Subject: [Lldb-commits] [lldb] Extend information for failed connection for gdb server (PR #139916) In-Reply-To: Message-ID: <6824c4d2.050a0220.1cee3c.c795@mx.google.com> https://github.com/JDevlieghere approved this pull request. LGTM modulo (pre-existing) typo. https://github.com/llvm/llvm-project/pull/139916 From lldb-commits at lists.llvm.org Wed May 14 09:32:37 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 09:32:37 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding unit tests for Transport. (PR #139926) In-Reply-To: Message-ID: <6824c5a5.050a0220.30beba.d345@mx.google.com> https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/139926 >From 506e8107a397e2ae88d8b952c0a5351cda9fa161 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 14 May 2025 09:13:32 -0700 Subject: [PATCH 1/3] [lldb-dap] Adding unittests for Transport. This adds basic support for testing the Transport class and includes tests for 'Read'. --- lldb/unittests/DAP/CMakeLists.txt | 1 + lldb/unittests/DAP/TransportTest.cpp | 81 ++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 lldb/unittests/DAP/TransportTest.cpp diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index 8b240654046e2..110733e93b192 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -1,6 +1,7 @@ add_lldb_unittest(DAPTests JSONUtilsTest.cpp LLDBUtilsTest.cpp + TransportTest.cpp ProtocolTypesTest.cpp LINK_LIBS diff --git a/lldb/unittests/DAP/TransportTest.cpp b/lldb/unittests/DAP/TransportTest.cpp new file mode 100644 index 0000000000000..d27167cf9da61 --- /dev/null +++ b/lldb/unittests/DAP/TransportTest.cpp @@ -0,0 +1,81 @@ +//===-- LLDBUtilsTest.cpp -------------------------------------------------===// +// +// 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 "Transport.h" +#include "Protocol/ProtocolBase.h" +#include "lldb/Host/File.h" +#include "lldb/Host/Pipe.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include +#include + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; +using namespace lldb_dap; +using namespace lldb_dap::protocol; + +class TransportTest : public testing::Test { +protected: + Pipe input; + Pipe output; + std::unique_ptr transport; + + void SetUp() override { + ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), llvm::Succeeded()); + ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), llvm::Succeeded()); + transport = std::make_unique( + "stdio", nullptr, + std::make_shared(input.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(output.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + } + + void Write(StringRef json) { + std::string message = + formatv("Content-Length: {0}\r\n\r\n{1}", json.size(), json).str(); + ASSERT_THAT_EXPECTED(input.Write(message.data(), message.size()), + Succeeded()); + } +}; + +TEST_F(TransportTest, MalformedRequests) { + std::string malformed_header = "COnTent-LenGth: -1{}\r\n\r\nnotjosn"; + ASSERT_THAT_EXPECTED( + input.Write(malformed_header.data(), malformed_header.size()), + Succeeded()); + ASSERT_THAT_EXPECTED( + transport->Read(std::chrono::milliseconds(1)), + FailedWithMessage( + "expected 'Content-Length: ' and got 'COnTent-LenGth: '")); +} + +TEST_F(TransportTest, Read) { + Write(R"json({"seq": 1, "type": "request", "command": "abc"})json"); + ASSERT_THAT_EXPECTED(transport->Read(std::chrono::milliseconds(1)), + HasValue(testing::VariantWith( + testing::FieldsAre(1, "abc", std::nullopt)))); +} + +TEST_F(TransportTest, ReadWithTimeout) { + ASSERT_THAT_EXPECTED(transport->Read(std::chrono::milliseconds(1)), + Failed()); +} + +TEST_F(TransportTest, ReadWithEOF) { + input.CloseWriteFileDescriptor(); + ASSERT_THAT_EXPECTED(transport->Read(std::chrono::milliseconds(1)), + Failed()); +} >From 8d5ffc83c6fce70a3fe66fb726781e7bd2b08d77 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 14 May 2025 09:16:34 -0700 Subject: [PATCH 2/3] Fixing the filename in the top comment. --- lldb/unittests/DAP/TransportTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/unittests/DAP/TransportTest.cpp b/lldb/unittests/DAP/TransportTest.cpp index d27167cf9da61..b8eade5442814 100644 --- a/lldb/unittests/DAP/TransportTest.cpp +++ b/lldb/unittests/DAP/TransportTest.cpp @@ -1,4 +1,4 @@ -//===-- LLDBUtilsTest.cpp -------------------------------------------------===// +//===-- TransportTest.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. >From 8de3cd6569f6a17de1f0607666953f06b1593e5b Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 14 May 2025 09:32:23 -0700 Subject: [PATCH 3/3] Also add a Write test. --- lldb/unittests/DAP/TransportTest.cpp | 29 ++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/lldb/unittests/DAP/TransportTest.cpp b/lldb/unittests/DAP/TransportTest.cpp index b8eade5442814..5c77b4bb26343 100644 --- a/lldb/unittests/DAP/TransportTest.cpp +++ b/lldb/unittests/DAP/TransportTest.cpp @@ -20,9 +20,11 @@ using namespace llvm; using namespace lldb; -using namespace lldb_private; using namespace lldb_dap; using namespace lldb_dap::protocol; +using lldb_private::File; +using lldb_private::NativeFile; +using lldb_private::Pipe; class TransportTest : public testing::Test { protected: @@ -31,8 +33,8 @@ class TransportTest : public testing::Test { std::unique_ptr transport; void SetUp() override { - ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), llvm::Succeeded()); - ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), llvm::Succeeded()); + ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); + ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); transport = std::make_unique( "stdio", nullptr, std::make_shared(input.GetReadFileDescriptor(), @@ -64,9 +66,10 @@ TEST_F(TransportTest, MalformedRequests) { TEST_F(TransportTest, Read) { Write(R"json({"seq": 1, "type": "request", "command": "abc"})json"); - ASSERT_THAT_EXPECTED(transport->Read(std::chrono::milliseconds(1)), - HasValue(testing::VariantWith( - testing::FieldsAre(1, "abc", std::nullopt)))); + ASSERT_THAT_EXPECTED( + transport->Read(std::chrono::milliseconds(1)), + HasValue(testing::VariantWith(testing::FieldsAre( + /*seq=*/1, /*command=*/"abc", /*arguments=*/std::nullopt)))); } TEST_F(TransportTest, ReadWithTimeout) { @@ -79,3 +82,17 @@ TEST_F(TransportTest, ReadWithEOF) { ASSERT_THAT_EXPECTED(transport->Read(std::chrono::milliseconds(1)), Failed()); } + +TEST_F(TransportTest, Write) { + ASSERT_THAT_ERROR(transport->Write(Event{"my-event", std::nullopt}), + Succeeded()); + output.CloseWriteFileDescriptor(); + char buf[1024]; + Expected bytes_read = + output.Read(buf, sizeof(buf), std::chrono::milliseconds(1)); + ASSERT_THAT_EXPECTED(bytes_read, Succeeded()); + ASSERT_EQ( + StringRef(buf, *bytes_read), + StringRef("Content-Length: 43\r\n\r\n" + R"json({"event":"my-event","seq":0,"type":"event"})json")); +} From lldb-commits at lists.llvm.org Wed May 14 09:35:01 2025 From: lldb-commits at lists.llvm.org (Chelsea Cassanova via lldb-commits) Date: Wed, 14 May 2025 09:35:01 -0700 (PDT) Subject: [Lldb-commits] [lldb] [DRAFT][lldb][RPC] Design doc for upstreaming PR (PR #138612) In-Reply-To: Message-ID: <6824c635.170a0220.291061.b0e2@mx.google.com> https://github.com/chelcassanova updated https://github.com/llvm/llvm-project/pull/138612 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Wed May 14 10:00:04 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 10:00:04 -0700 (PDT) Subject: [Lldb-commits] [lldb] 441d382 - [lldb-dap] Adding unit tests for Transport. (#139926) Message-ID: <6824cc14.170a0220.1fd770.92f7@mx.google.com> Author: John Harrison Date: 2025-05-14T10:00:01-07:00 New Revision: 441d382f9350c1345555c958244f252c00923824 URL: https://github.com/llvm/llvm-project/commit/441d382f9350c1345555c958244f252c00923824 DIFF: https://github.com/llvm/llvm-project/commit/441d382f9350c1345555c958244f252c00923824.diff LOG: [lldb-dap] Adding unit tests for Transport. (#139926) This adds basic support for testing the Transport class and includes tests for 'Read' and 'Write'. Added: lldb/unittests/DAP/TransportTest.cpp Modified: lldb/unittests/DAP/CMakeLists.txt Removed: ################################################################################ diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index 8b240654046e2..110733e93b192 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -1,6 +1,7 @@ add_lldb_unittest(DAPTests JSONUtilsTest.cpp LLDBUtilsTest.cpp + TransportTest.cpp ProtocolTypesTest.cpp LINK_LIBS diff --git a/lldb/unittests/DAP/TransportTest.cpp b/lldb/unittests/DAP/TransportTest.cpp new file mode 100644 index 0000000000000..5c77b4bb26343 --- /dev/null +++ b/lldb/unittests/DAP/TransportTest.cpp @@ -0,0 +1,98 @@ +//===-- TransportTest.cpp -------------------------------------------------===// +// +// 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 "Transport.h" +#include "Protocol/ProtocolBase.h" +#include "lldb/Host/File.h" +#include "lldb/Host/Pipe.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include +#include + +using namespace llvm; +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap::protocol; +using lldb_private::File; +using lldb_private::NativeFile; +using lldb_private::Pipe; + +class TransportTest : public testing::Test { +protected: + Pipe input; + Pipe output; + std::unique_ptr transport; + + void SetUp() override { + ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); + ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); + transport = std::make_unique( + "stdio", nullptr, + std::make_shared(input.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(output.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + } + + void Write(StringRef json) { + std::string message = + formatv("Content-Length: {0}\r\n\r\n{1}", json.size(), json).str(); + ASSERT_THAT_EXPECTED(input.Write(message.data(), message.size()), + Succeeded()); + } +}; + +TEST_F(TransportTest, MalformedRequests) { + std::string malformed_header = "COnTent-LenGth: -1{}\r\n\r\nnotjosn"; + ASSERT_THAT_EXPECTED( + input.Write(malformed_header.data(), malformed_header.size()), + Succeeded()); + ASSERT_THAT_EXPECTED( + transport->Read(std::chrono::milliseconds(1)), + FailedWithMessage( + "expected 'Content-Length: ' and got 'COnTent-LenGth: '")); +} + +TEST_F(TransportTest, Read) { + Write(R"json({"seq": 1, "type": "request", "command": "abc"})json"); + ASSERT_THAT_EXPECTED( + transport->Read(std::chrono::milliseconds(1)), + HasValue(testing::VariantWith(testing::FieldsAre( + /*seq=*/1, /*command=*/"abc", /*arguments=*/std::nullopt)))); +} + +TEST_F(TransportTest, ReadWithTimeout) { + ASSERT_THAT_EXPECTED(transport->Read(std::chrono::milliseconds(1)), + Failed()); +} + +TEST_F(TransportTest, ReadWithEOF) { + input.CloseWriteFileDescriptor(); + ASSERT_THAT_EXPECTED(transport->Read(std::chrono::milliseconds(1)), + Failed()); +} + +TEST_F(TransportTest, Write) { + ASSERT_THAT_ERROR(transport->Write(Event{"my-event", std::nullopt}), + Succeeded()); + output.CloseWriteFileDescriptor(); + char buf[1024]; + Expected bytes_read = + output.Read(buf, sizeof(buf), std::chrono::milliseconds(1)); + ASSERT_THAT_EXPECTED(bytes_read, Succeeded()); + ASSERT_EQ( + StringRef(buf, *bytes_read), + StringRef("Content-Length: 43\r\n\r\n" + R"json({"event":"my-event","seq":0,"type":"event"})json")); +} From lldb-commits at lists.llvm.org Wed May 14 10:00:10 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 10:00:10 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding unit tests for Transport. (PR #139926) In-Reply-To: Message-ID: <6824cc1a.170a0220.2bc56a.f810@mx.google.com> https://github.com/ashgti closed https://github.com/llvm/llvm-project/pull/139926 From lldb-commits at lists.llvm.org Wed May 14 10:07:58 2025 From: lldb-commits at lists.llvm.org (Kazu Hirata via lldb-commits) Date: Wed, 14 May 2025 10:07:58 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Simplify a string comparison (NFC) (PR #139932) Message-ID: https://github.com/kazutakahirata created https://github.com/llvm/llvm-project/pull/139932 None Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Wed May 14 10:08:32 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 10:08:32 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Simplify a string comparison (NFC) (PR #139932) In-Reply-To: Message-ID: <6824ce10.050a0220.c3feb.e3fe@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Kazu Hirata (kazutakahirata)
Changes --- Full diff: https://github.com/llvm/llvm-project/pull/139932.diff 1 Files Affected: - (modified) lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp (+1-2) ``````````diff diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp index a2722db5d24a0..451cf40e2818d 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp @@ -123,8 +123,7 @@ void ASTStructExtractor::ExtractFromTopLevelDecl(Decl *D) { FunctionDecl *function_decl = dyn_cast(D); if (m_ast_context && function_decl && - !m_function.m_wrapper_function_name.compare( - function_decl->getNameAsString())) { + m_function.m_wrapper_function_name == function_decl->getNameAsString()) { ExtractFromFunctionDecl(function_decl); } } ``````````
https://github.com/llvm/llvm-project/pull/139932 From lldb-commits at lists.llvm.org Wed May 14 10:14:17 2025 From: lldb-commits at lists.llvm.org (Chelsea Cassanova via lldb-commits) Date: Wed, 14 May 2025 10:14:17 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][cmake] Set `CMAKE_OSX_SYSROOT` when building debugserver with CMake 4 (PR #138020) In-Reply-To: Message-ID: <6824cf69.170a0220.152f79.f565@mx.google.com> chelcassanova wrote: @bulbazord @JDevlieghere Is it possible to take another pass over at this? I think this should be good to land now. https://github.com/llvm/llvm-project/pull/138020 From lldb-commits at lists.llvm.org Wed May 14 10:17:12 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Wed, 14 May 2025 10:17:12 -0700 (PDT) Subject: [Lldb-commits] [lldb] Complete the Implementation of DAP modules explorer. (PR #139934) Message-ID: https://github.com/da-viper created https://github.com/llvm/llvm-project/pull/139934 What it now looks like. It is a good idea to remove the, symbol status and name from the tree children ?. ![image](https://github.com/user-attachments/assets/329fabee-9b4a-490e-9450-3f01314674ea) Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Wed May 14 10:17:46 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 10:17:46 -0700 (PDT) Subject: [Lldb-commits] [lldb] Complete the Implementation of DAP modules explorer. (PR #139934) In-Reply-To: Message-ID: <6824d03a.a70a0220.165908.0afd@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Ebuka Ezike (da-viper)
Changes What it now looks like. It is a good idea to remove the, symbol status and name from the tree children ?. ![image](https://github.com/user-attachments/assets/329fabee-9b4a-490e-9450-3f01314674ea) --- Full diff: https://github.com/llvm/llvm-project/pull/139934.diff 4 Files Affected: - (modified) lldb/tools/lldb-dap/JSONUtils.cpp (+5-2) - (modified) lldb/tools/lldb-dap/package.json (+14) - (modified) lldb/tools/lldb-dap/src-ts/extension.ts (+9-1) - (modified) lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts (+62-36) ``````````diff diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 279e6d3d93814..31eb91f9f6b61 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -416,8 +416,11 @@ llvm::json::Value CreateModule(lldb::SBTarget &target, lldb::SBModule &module, } else { object.try_emplace("symbolStatus", "Symbols not found."); } - std::string loaded_addr = std::to_string( - module.GetObjectFileHeaderAddress().GetLoadAddress(target)); + std::string loaded_addr; + llvm::raw_string_ostream os_hex(loaded_addr); + os_hex << llvm::format_hex( + module.GetObjectFileHeaderAddress().GetLoadAddress(target), + sizeof(lldb::addr_t)); object.try_emplace("addressRange", loaded_addr); std::string version_str; uint32_t version_nums[3]; diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index e3e46526f379f..3c73534fd3180 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -244,6 +244,20 @@ } } ], + "commands": [ + { + "command": "lldb-dap.modules.copyProperty", + "title": "Copy Value" + } + ], + "menus": { + "view/item/context": [ + { + "command": "lldb-dap.modules.copyProperty", + "when": "view == lldb-dap.modules && viewItem == property" + } + ] + }, "breakpoints": [ { "language": "ada" diff --git a/lldb/tools/lldb-dap/src-ts/extension.ts b/lldb/tools/lldb-dap/src-ts/extension.ts index a5c0a09ae60cf..c8e5146e29cea 100644 --- a/lldb/tools/lldb-dap/src-ts/extension.ts +++ b/lldb/tools/lldb-dap/src-ts/extension.ts @@ -6,7 +6,10 @@ import { LaunchUriHandler } from "./uri-launch-handler"; import { LLDBDapConfigurationProvider } from "./debug-configuration-provider"; import { LLDBDapServer } from "./lldb-dap-server"; import { DebugSessionTracker } from "./debug-session-tracker"; -import { ModulesDataProvider } from "./ui/modules-data-provider"; +import { + ModulesDataProvider, + ModuleProperty, +} from "./ui/modules-data-provider"; /** * This class represents the extension and manages its life cycle. Other extensions @@ -40,6 +43,11 @@ export class LLDBDapExtension extends DisposableContext { ), vscode.window.registerUriHandler(new LaunchUriHandler()), ); + + vscode.commands.registerCommand( + "lldb-dap.modules.copyProperty", + (node: ModuleProperty) => vscode.env.clipboard.writeText(node.value), + ); } } diff --git a/lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts b/lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts index 478c162de8878..091c1d69ac647 100644 --- a/lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts +++ b/lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts @@ -2,60 +2,86 @@ import * as vscode from "vscode"; import { DebugProtocol } from "@vscode/debugprotocol"; import { DebugSessionTracker } from "../debug-session-tracker"; -/** A tree data provider for listing loaded modules for the active debug session. */ -export class ModulesDataProvider - implements vscode.TreeDataProvider -{ - private changeTreeData = new vscode.EventEmitter(); - readonly onDidChangeTreeData = this.changeTreeData.event; +export interface ModuleProperty { + key: string; + value: string; +} - constructor(private readonly tracker: DebugSessionTracker) { - tracker.onDidChangeModules(() => this.changeTreeData.fire()); - vscode.debug.onDidChangeActiveDebugSession(() => - this.changeTreeData.fire(), - ); +/** Type to represent both Module and ModuleProperty since TreeDataProvider + * expects one concrete type */ +type TreeData = DebugProtocol.Module | ModuleProperty; + +function isModule(type: TreeData): type is DebugProtocol.Module { + return (type as DebugProtocol.Module).id !== undefined; +} + +class ModuleItem extends vscode.TreeItem { + constructor(module: DebugProtocol.Module) { + super(module.name, vscode.TreeItemCollapsibleState.Collapsed); + this.description = module.symbolStatus; } - getTreeItem(module: DebugProtocol.Module): vscode.TreeItem { - let treeItem = new vscode.TreeItem(/*label=*/ module.name); - if (module.path) { - treeItem.description = `${module.id} -- ${module.path}`; - } else { - treeItem.description = `${module.id}`; - } + static getProperties(module: DebugProtocol.Module): ModuleProperty[] { + // does not include the name and symbol status as it is show in the parent. + let children: ModuleProperty[] = []; + children.push({ key: "id:", value: module.id.toString() }); - const tooltip = new vscode.MarkdownString(); - tooltip.appendMarkdown(`# ${module.name}\n\n`); - tooltip.appendMarkdown(`- **ID**: ${module.id}\n`); if (module.addressRange) { - tooltip.appendMarkdown( - `- **Load address**: 0x${Number(module.addressRange).toString(16)}\n`, - ); + children.push({ + key: "load address:", + value: module.addressRange, + }); } if (module.path) { - tooltip.appendMarkdown(`- **Path**: ${module.path}\n`); + children.push({ key: "path:", value: module.path }); } if (module.version) { - tooltip.appendMarkdown(`- **Version**: ${module.version}\n`); - } - if (module.symbolStatus) { - tooltip.appendMarkdown(`- **Symbol status**: ${module.symbolStatus}\n`); + children.push({ key: "version:", value: module.version }); } if (module.symbolFilePath) { - tooltip.appendMarkdown( - `- **Symbol file path**: ${module.symbolFilePath}\n`, - ); + children.push({ key: "symbol filepath:", value: module.symbolFilePath }); + } + return children; + } +} + +/** A tree data provider for listing loaded modules for the active debug session. */ +export class ModulesDataProvider implements vscode.TreeDataProvider { + private changeTreeData = new vscode.EventEmitter(); + readonly onDidChangeTreeData = this.changeTreeData.event; + + constructor(private readonly tracker: DebugSessionTracker) { + tracker.onDidChangeModules(() => this.changeTreeData.fire()); + vscode.debug.onDidChangeActiveDebugSession(() => + this.changeTreeData.fire(), + ); + } + + getTreeItem(module: TreeData): vscode.TreeItem { + if (isModule(module)) { + return new ModuleItem(module); } - treeItem.tooltip = tooltip; - return treeItem; + let item = new vscode.TreeItem(module.key); + item.description = module.value; + item.tooltip = `${module.key} ${module.value}`; + item.contextValue = "property"; + return item; } - getChildren(): DebugProtocol.Module[] { + getChildren(element?: TreeData): TreeData[] { if (!vscode.debug.activeDebugSession) { return []; } - return this.tracker.debugSessionModules(vscode.debug.activeDebugSession); + if (!element) { + return this.tracker.debugSessionModules(vscode.debug.activeDebugSession); + } + + if (isModule(element)) { + return ModuleItem.getProperties(element); + } + + return []; } } ``````````
https://github.com/llvm/llvm-project/pull/139934 From lldb-commits at lists.llvm.org Wed May 14 10:28:10 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 10:28:10 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][cmake] Set `CMAKE_OSX_SYSROOT` when building debugserver with CMake 4 (PR #138020) In-Reply-To: Message-ID: <6824d2aa.630a0220.4bc22.3252@mx.google.com> https://github.com/JDevlieghere edited https://github.com/llvm/llvm-project/pull/138020 From lldb-commits at lists.llvm.org Wed May 14 10:28:10 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 10:28:10 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][cmake] Set `CMAKE_OSX_SYSROOT` when building debugserver with CMake 4 (PR #138020) In-Reply-To: Message-ID: <6824d2aa.a70a0220.ee352.20d4@mx.google.com> https://github.com/JDevlieghere approved this pull request. LGTM modulo wording. https://github.com/llvm/llvm-project/pull/138020 From lldb-commits at lists.llvm.org Wed May 14 10:28:10 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 10:28:10 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][cmake] Set `CMAKE_OSX_SYSROOT` when building debugserver with CMake 4 (PR #138020) In-Reply-To: Message-ID: <6824d2aa.170a0220.12d8bf.e76a@mx.google.com> ================ @@ -154,6 +154,21 @@ endif() add_definitions(-DLLDB_USE_OS_LOG) +# Make sure we have the macOS SDK root as mig needs it and will silently +# fail to generate its output files without it. +if(CMAKE_OSX_SYSROOT) + set(MIG_SYSROOT ${CMAKE_OSX_SYSROOT}) +else() + execute_process(COMMAND xcrun --show-sdk-path + OUTPUT_VARIABLE MIG_SYSROOT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() + +if(NOT MIG_SYSROOT) + message(FATAL_ERROR "Unable to obtain macOS SDK root, debugserver cannot be built.") ---------------- JDevlieghere wrote: Let's make this more specific and actionable. ```suggestion message(FATAL_ERROR "Unable to obtain sysroot required by mig (Mach Interface Generator). Set CMAKE_OSX_SYSROOT to explicitly specify a sysroot.") ``` https://github.com/llvm/llvm-project/pull/138020 From lldb-commits at lists.llvm.org Wed May 14 10:31:33 2025 From: lldb-commits at lists.llvm.org (Chelsea Cassanova via lldb-commits) Date: Wed, 14 May 2025 10:31:33 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][cmake] Set `CMAKE_OSX_SYSROOT` when building debugserver with CMake 4 (PR #138020) In-Reply-To: Message-ID: <6824d375.170a0220.3c9a8f.f9e0@mx.google.com> https://github.com/chelcassanova updated https://github.com/llvm/llvm-project/pull/138020 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Wed May 14 10:33:54 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 10:33:54 -0700 (PDT) Subject: [Lldb-commits] [lldb] Complete the Implementation of DAP modules explorer. (PR #139934) In-Reply-To: Message-ID: <6824d402.170a0220.8749f.e24d@mx.google.com> https://github.com/JDevlieghere edited https://github.com/llvm/llvm-project/pull/139934 From lldb-commits at lists.llvm.org Wed May 14 10:33:54 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 10:33:54 -0700 (PDT) Subject: [Lldb-commits] [lldb] Complete the Implementation of DAP modules explorer. (PR #139934) In-Reply-To: Message-ID: <6824d402.a70a0220.f979.2156@mx.google.com> https://github.com/JDevlieghere commented: Looks great! https://github.com/llvm/llvm-project/pull/139934 From lldb-commits at lists.llvm.org Wed May 14 10:33:54 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 10:33:54 -0700 (PDT) Subject: [Lldb-commits] [lldb] Complete the Implementation of DAP modules explorer. (PR #139934) In-Reply-To: Message-ID: <6824d402.170a0220.1e7264.fe7c@mx.google.com> ================ @@ -416,8 +416,11 @@ llvm::json::Value CreateModule(lldb::SBTarget &target, lldb::SBModule &module, } else { object.try_emplace("symbolStatus", "Symbols not found."); } - std::string loaded_addr = std::to_string( - module.GetObjectFileHeaderAddress().GetLoadAddress(target)); + std::string loaded_addr; + llvm::raw_string_ostream os_hex(loaded_addr); + os_hex << llvm::format_hex( + module.GetObjectFileHeaderAddress().GetLoadAddress(target), + sizeof(lldb::addr_t)); ---------------- JDevlieghere wrote: I assumed the load address was a "number" but the [spec](https://microsoft.github.io/debug-adapter-protocol/specification#Types_Module) says it's a "string" in which case I agree it makes more sense to the hex conversion here. You can simplify this something like this: ``` object.try_emplace("addressRange", llvm::format({0:x}, module.GetObjectFileHeaderAddress().GetLoadAddress(target)).str()); ``` https://github.com/llvm/llvm-project/pull/139934 From lldb-commits at lists.llvm.org Wed May 14 10:33:58 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 10:33:58 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) Message-ID: https://github.com/ashgti created https://github.com/llvm/llvm-project/pull/139937 This is a very simple case that currently only validates we can create a DAP instance and send a message over the transport layer. More in-depth tests will require additional helpers and possibly refactors of DAP to make it more testable, however this is some ground work to have basic support for unit tests. >From 6f947e38ad4f744754cf13c1094c4e5e3fd249b6 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 14 May 2025 10:31:40 -0700 Subject: [PATCH] [lldb-dap] Setup DAP for unit testing. This is a very simple case that currently only validates we can create a DAP instance and send a message over the transport layer. More in-depth tests will require additional helpers and possibly refactors of DAP to make it more testable, however this is some ground work to have basic support for unit tests. --- lldb/tools/lldb-dap/DAP.h | 3 +- lldb/unittests/DAP/CMakeLists.txt | 1 + lldb/unittests/DAP/DAPTest.cpp | 63 +++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 lldb/unittests/DAP/DAPTest.cpp diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c2e4c2dea582e..2ff66d1cd0182 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -226,7 +226,8 @@ struct DAP { /// \param[in] default_repl_mode /// Default repl mode behavior, as configured by the binary. /// \param[in] pre_init_commands - /// LLDB commands to execute as soon as the debugger instance is allocaed. + /// LLDB commands to execute as soon as the debugger instance is + /// allocated. /// \param[in] transport /// Transport for this debug session. DAP(Log *log, const ReplMode default_repl_mode, diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index 110733e93b192..6074e9b872c49 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -3,6 +3,7 @@ add_lldb_unittest(DAPTests LLDBUtilsTest.cpp TransportTest.cpp ProtocolTypesTest.cpp + DAPTest.cpp LINK_LIBS lldbDAP diff --git a/lldb/unittests/DAP/DAPTest.cpp b/lldb/unittests/DAP/DAPTest.cpp new file mode 100644 index 0000000000000..9d2a9b944678e --- /dev/null +++ b/lldb/unittests/DAP/DAPTest.cpp @@ -0,0 +1,63 @@ +//===-- DAPTest.cpp -------------------------------------------------===// +// +// 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 "DAP.h" +#include "Protocol/ProtocolBase.h" +#include "Transport.h" +#include "lldb/Host/File.h" +#include "lldb/Host/Pipe.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include +#include + +using namespace llvm; +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap::protocol; +using lldb_private::File; +using lldb_private::NativeFile; +using lldb_private::Pipe; + +class DAPTest : public testing::Test { +protected: + Pipe input; + Pipe output; + std::unique_ptr toDAP; + std::unique_ptr fromDAP; + + void SetUp() override { + ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); + ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); + toDAP = std::make_unique( + "toDAP", nullptr, + std::make_shared(input.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(output.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + fromDAP = std::make_unique( + "fromDAP", nullptr, + std::make_shared(output.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(input.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + } +}; + +TEST_F(DAPTest, SendProtocolMessages) { + DAP dap{nullptr, ReplMode::Auto, {}, *toDAP}; + dap.Send(Event{"my-event", std::nullopt}); + ASSERT_THAT_EXPECTED(fromDAP->Read(std::chrono::milliseconds(1)), + HasValue(testing::VariantWith(testing::FieldsAre( + /*event=*/"my-event", /*body=*/std::nullopt)))); +} From lldb-commits at lists.llvm.org Wed May 14 10:34:33 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 10:34:33 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <6824d429.a70a0220.205d9e.e1c4@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: John Harrison (ashgti)
Changes This is a very simple case that currently only validates we can create a DAP instance and send a message over the transport layer. More in-depth tests will require additional helpers and possibly refactors of DAP to make it more testable, however this is some ground work to have basic support for unit tests. --- Full diff: https://github.com/llvm/llvm-project/pull/139937.diff 3 Files Affected: - (modified) lldb/tools/lldb-dap/DAP.h (+2-1) - (modified) lldb/unittests/DAP/CMakeLists.txt (+1) - (added) lldb/unittests/DAP/DAPTest.cpp (+63) ``````````diff diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c2e4c2dea582e..2ff66d1cd0182 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -226,7 +226,8 @@ struct DAP { /// \param[in] default_repl_mode /// Default repl mode behavior, as configured by the binary. /// \param[in] pre_init_commands - /// LLDB commands to execute as soon as the debugger instance is allocaed. + /// LLDB commands to execute as soon as the debugger instance is + /// allocated. /// \param[in] transport /// Transport for this debug session. DAP(Log *log, const ReplMode default_repl_mode, diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index 110733e93b192..6074e9b872c49 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -3,6 +3,7 @@ add_lldb_unittest(DAPTests LLDBUtilsTest.cpp TransportTest.cpp ProtocolTypesTest.cpp + DAPTest.cpp LINK_LIBS lldbDAP diff --git a/lldb/unittests/DAP/DAPTest.cpp b/lldb/unittests/DAP/DAPTest.cpp new file mode 100644 index 0000000000000..9d2a9b944678e --- /dev/null +++ b/lldb/unittests/DAP/DAPTest.cpp @@ -0,0 +1,63 @@ +//===-- DAPTest.cpp -------------------------------------------------===// +// +// 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 "DAP.h" +#include "Protocol/ProtocolBase.h" +#include "Transport.h" +#include "lldb/Host/File.h" +#include "lldb/Host/Pipe.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include +#include + +using namespace llvm; +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap::protocol; +using lldb_private::File; +using lldb_private::NativeFile; +using lldb_private::Pipe; + +class DAPTest : public testing::Test { +protected: + Pipe input; + Pipe output; + std::unique_ptr toDAP; + std::unique_ptr fromDAP; + + void SetUp() override { + ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); + ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); + toDAP = std::make_unique( + "toDAP", nullptr, + std::make_shared(input.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(output.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + fromDAP = std::make_unique( + "fromDAP", nullptr, + std::make_shared(output.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(input.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + } +}; + +TEST_F(DAPTest, SendProtocolMessages) { + DAP dap{nullptr, ReplMode::Auto, {}, *toDAP}; + dap.Send(Event{"my-event", std::nullopt}); + ASSERT_THAT_EXPECTED(fromDAP->Read(std::chrono::milliseconds(1)), + HasValue(testing::VariantWith(testing::FieldsAre( + /*event=*/"my-event", /*body=*/std::nullopt)))); +} ``````````
https://github.com/llvm/llvm-project/pull/139937 From lldb-commits at lists.llvm.org Wed May 14 10:35:24 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 10:35:24 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <6824d45c.170a0220.53b5e.0212@mx.google.com> https://github.com/JDevlieghere approved this pull request. Very excited to see more unit testing! https://github.com/llvm/llvm-project/pull/139937 From lldb-commits at lists.llvm.org Wed May 14 10:38:18 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 10:38:18 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <6824d50a.630a0220.d3eed.6723@mx.google.com> ashgti wrote: Should I rename `toDAP`/`fromDAP` to `to_dap`/`from_dap`? I think thats more inline with how lldb names variables, right? https://github.com/llvm/llvm-project/pull/139937 From lldb-commits at lists.llvm.org Wed May 14 10:38:41 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 10:38:41 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][cmake] Set `CMAKE_OSX_SYSROOT` when building debugserver with CMake 4 (PR #138020) In-Reply-To: Message-ID: <6824d521.170a0220.2ec3f6.01c4@mx.google.com> https://github.com/JDevlieghere approved this pull request. https://github.com/llvm/llvm-project/pull/138020 From lldb-commits at lists.llvm.org Wed May 14 10:39:11 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 10:39:11 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Simplify a string comparison (NFC) (PR #139932) In-Reply-To: Message-ID: <6824d53f.170a0220.8f2e5.ef4e@mx.google.com> https://github.com/JDevlieghere approved this pull request. https://github.com/llvm/llvm-project/pull/139932 From lldb-commits at lists.llvm.org Wed May 14 10:44:21 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 10:44:21 -0700 (PDT) Subject: [Lldb-commits] [lldb] Fix race condition during iteration through modules (#139283) (PR #139862) In-Reply-To: Message-ID: <6824d675.170a0220.dfa74.e182@mx.google.com> ================ @@ -1510,6 +1510,7 @@ bool Target::IgnoreWatchpointByID(lldb::watch_id_t watch_id, } ModuleSP Target::GetExecutableModule() { + std::lock_guard guard(m_images.GetMutex()); ---------------- JDevlieghere wrote: Let's use the `Modules()` iterable which allows us to use a for-based loop and does the locking for us: ``` // Search for the first executable in the module list. for (ModuleSP module_sp : m_images.Modules()) { lldb_private::ObjectFile *obj = module_sp->GetObjectFile(); ``` https://github.com/llvm/llvm-project/pull/139862 From lldb-commits at lists.llvm.org Wed May 14 10:44:37 2025 From: lldb-commits at lists.llvm.org (Alex Langford via lldb-commits) Date: Wed, 14 May 2025 10:44:37 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Simplify a string comparison (NFC) (PR #139932) In-Reply-To: Message-ID: <6824d685.170a0220.7e2ad.d97a@mx.google.com> https://github.com/bulbazord approved this pull request. https://github.com/llvm/llvm-project/pull/139932 From lldb-commits at lists.llvm.org Wed May 14 10:45:08 2025 From: lldb-commits at lists.llvm.org (Alex Langford via lldb-commits) Date: Wed, 14 May 2025 10:45:08 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][cmake] Set `CMAKE_OSX_SYSROOT` when building debugserver with CMake 4 (PR #138020) In-Reply-To: Message-ID: <6824d6a4.050a0220.2a492b.db28@mx.google.com> https://github.com/bulbazord approved this pull request. https://github.com/llvm/llvm-project/pull/138020 From lldb-commits at lists.llvm.org Wed May 14 10:45:45 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 10:45:45 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <6824d6c9.050a0220.10ef79.36d6@mx.google.com> JDevlieghere wrote: > Should I rename `toDAP`/`fromDAP` to `to_dap`/`from_dap`? I think thats more inline with how lldb names variables, right? Yes, good point. Currently we have a weird mix of styles. Once everything has been migrated to use the protocol classes, we should go through the code and fix the remaining inconsistencies. https://github.com/llvm/llvm-project/pull/139937 From lldb-commits at lists.llvm.org Wed May 14 10:46:04 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 10:46:04 -0700 (PDT) Subject: [Lldb-commits] [lldb] 28d732a - [lldb][cmake] Set `CMAKE_OSX_SYSROOT` when building debugserver with CMake 4 (#138020) Message-ID: <6824d6dc.170a0220.2c12b8.0c35@mx.google.com> Author: Chelsea Cassanova Date: 2025-05-14T10:46:01-07:00 New Revision: 28d732a24ef06bab3a2cd6c17975281155f63cd6 URL: https://github.com/llvm/llvm-project/commit/28d732a24ef06bab3a2cd6c17975281155f63cd6 DIFF: https://github.com/llvm/llvm-project/commit/28d732a24ef06bab3a2cd6c17975281155f63cd6.diff LOG: [lldb][cmake] Set `CMAKE_OSX_SYSROOT` when building debugserver with CMake 4 (#138020) CMake 4 no longer sets the `CMAKE_OSX_SYSROOT` variable by default. If you've updated to CMake 4 on macOS (e.g. with brew) and try building LLDB with CMake/ninja, this will yield an error when building debugserver that clang is unable to run since it tries to compile files that don't exist. These files are supposed to be generated by the `mig` process. `mig` needs the `CMAKE_OSX_SYSROOT` variable in order to work and without it, it silently fails to generate the files that later on need to be compiled. This commit sets this SDK path for mig and will fatal error out of config when building debugserver without having set CMAKE_OSX_SYSROOT. Added: Modified: lldb/tools/debugserver/source/CMakeLists.txt Removed: ################################################################################ diff --git a/lldb/tools/debugserver/source/CMakeLists.txt b/lldb/tools/debugserver/source/CMakeLists.txt index f7ff76c3e8e84..8340b5ad8948d 100644 --- a/lldb/tools/debugserver/source/CMakeLists.txt +++ b/lldb/tools/debugserver/source/CMakeLists.txt @@ -154,6 +154,21 @@ endif() add_definitions(-DLLDB_USE_OS_LOG) +# Make sure we have the macOS SDK root as mig needs it and will silently +# fail to generate its output files without it. +if(CMAKE_OSX_SYSROOT) + set(MIG_SYSROOT ${CMAKE_OSX_SYSROOT}) +else() + execute_process(COMMAND xcrun --show-sdk-path + OUTPUT_VARIABLE MIG_SYSROOT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() + +if(NOT MIG_SYSROOT) + message(FATAL_ERROR "Unable to obtain sysroot required by mig (Mach Interface Generator). Set CMAKE_OSX_SYSROOT to explicitly specify a sysroot.") +endif() + if(${CMAKE_OSX_SYSROOT} MATCHES ".Internal.sdk$") message(STATUS "LLDB debugserver energy support is enabled") add_definitions(-DLLDB_ENERGY) @@ -177,7 +192,7 @@ endif() separate_arguments(MIG_ARCH_FLAGS_SEPARTED NATIVE_COMMAND "${MIG_ARCH_FLAGS}") add_custom_command(OUTPUT ${generated_mach_interfaces} - VERBATIM COMMAND mig ${MIG_ARCH_FLAGS_SEPARTED} -isysroot ${CMAKE_OSX_SYSROOT} ${CMAKE_CURRENT_SOURCE_DIR}/MacOSX/dbgnub-mig.defs + VERBATIM COMMAND mig ${MIG_ARCH_FLAGS_SEPARTED} -isysroot ${MIG_SYSROOT} ${CMAKE_CURRENT_SOURCE_DIR}/MacOSX/dbgnub-mig.defs DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/MacOSX/dbgnub-mig.defs ) From lldb-commits at lists.llvm.org Wed May 14 10:46:07 2025 From: lldb-commits at lists.llvm.org (Chelsea Cassanova via lldb-commits) Date: Wed, 14 May 2025 10:46:07 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][cmake] Set `CMAKE_OSX_SYSROOT` when building debugserver with CMake 4 (PR #138020) In-Reply-To: Message-ID: <6824d6df.050a0220.23be6a.0fdd@mx.google.com> https://github.com/chelcassanova closed https://github.com/llvm/llvm-project/pull/138020 From lldb-commits at lists.llvm.org Wed May 14 10:47:05 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 10:47:05 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <6824d719.170a0220.39e82.0a4c@mx.google.com> https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/139937 >From 6f947e38ad4f744754cf13c1094c4e5e3fd249b6 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 14 May 2025 10:31:40 -0700 Subject: [PATCH 1/2] [lldb-dap] Setup DAP for unit testing. This is a very simple case that currently only validates we can create a DAP instance and send a message over the transport layer. More in-depth tests will require additional helpers and possibly refactors of DAP to make it more testable, however this is some ground work to have basic support for unit tests. --- lldb/tools/lldb-dap/DAP.h | 3 +- lldb/unittests/DAP/CMakeLists.txt | 1 + lldb/unittests/DAP/DAPTest.cpp | 63 +++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 lldb/unittests/DAP/DAPTest.cpp diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c2e4c2dea582e..2ff66d1cd0182 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -226,7 +226,8 @@ struct DAP { /// \param[in] default_repl_mode /// Default repl mode behavior, as configured by the binary. /// \param[in] pre_init_commands - /// LLDB commands to execute as soon as the debugger instance is allocaed. + /// LLDB commands to execute as soon as the debugger instance is + /// allocated. /// \param[in] transport /// Transport for this debug session. DAP(Log *log, const ReplMode default_repl_mode, diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index 110733e93b192..6074e9b872c49 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -3,6 +3,7 @@ add_lldb_unittest(DAPTests LLDBUtilsTest.cpp TransportTest.cpp ProtocolTypesTest.cpp + DAPTest.cpp LINK_LIBS lldbDAP diff --git a/lldb/unittests/DAP/DAPTest.cpp b/lldb/unittests/DAP/DAPTest.cpp new file mode 100644 index 0000000000000..9d2a9b944678e --- /dev/null +++ b/lldb/unittests/DAP/DAPTest.cpp @@ -0,0 +1,63 @@ +//===-- DAPTest.cpp -------------------------------------------------===// +// +// 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 "DAP.h" +#include "Protocol/ProtocolBase.h" +#include "Transport.h" +#include "lldb/Host/File.h" +#include "lldb/Host/Pipe.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include +#include + +using namespace llvm; +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap::protocol; +using lldb_private::File; +using lldb_private::NativeFile; +using lldb_private::Pipe; + +class DAPTest : public testing::Test { +protected: + Pipe input; + Pipe output; + std::unique_ptr toDAP; + std::unique_ptr fromDAP; + + void SetUp() override { + ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); + ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); + toDAP = std::make_unique( + "toDAP", nullptr, + std::make_shared(input.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(output.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + fromDAP = std::make_unique( + "fromDAP", nullptr, + std::make_shared(output.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(input.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + } +}; + +TEST_F(DAPTest, SendProtocolMessages) { + DAP dap{nullptr, ReplMode::Auto, {}, *toDAP}; + dap.Send(Event{"my-event", std::nullopt}); + ASSERT_THAT_EXPECTED(fromDAP->Read(std::chrono::milliseconds(1)), + HasValue(testing::VariantWith(testing::FieldsAre( + /*event=*/"my-event", /*body=*/std::nullopt)))); +} >From 8bc4880a338dd0d0f2daa64b77c8bdbf567270b2 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 14 May 2025 10:46:51 -0700 Subject: [PATCH 2/2] Adjusting the naming of variables. --- lldb/unittests/DAP/DAPTest.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lldb/unittests/DAP/DAPTest.cpp b/lldb/unittests/DAP/DAPTest.cpp index 9d2a9b944678e..8e8c2ea3ccbb0 100644 --- a/lldb/unittests/DAP/DAPTest.cpp +++ b/lldb/unittests/DAP/DAPTest.cpp @@ -29,22 +29,22 @@ class DAPTest : public testing::Test { protected: Pipe input; Pipe output; - std::unique_ptr toDAP; - std::unique_ptr fromDAP; + std::unique_ptr to_dap; + std::unique_ptr from_dap; void SetUp() override { ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); - toDAP = std::make_unique( - "toDAP", nullptr, + to_dap = std::make_unique( + "to_dap", nullptr, std::make_shared(input.GetReadFileDescriptor(), File::eOpenOptionReadOnly, NativeFile::Unowned), std::make_shared(output.GetWriteFileDescriptor(), File::eOpenOptionWriteOnly, NativeFile::Unowned)); - fromDAP = std::make_unique( - "fromDAP", nullptr, + from_dap = std::make_unique( + "from_dap", nullptr, std::make_shared(output.GetReadFileDescriptor(), File::eOpenOptionReadOnly, NativeFile::Unowned), @@ -55,9 +55,9 @@ class DAPTest : public testing::Test { }; TEST_F(DAPTest, SendProtocolMessages) { - DAP dap{nullptr, ReplMode::Auto, {}, *toDAP}; + DAP dap{nullptr, ReplMode::Auto, {}, *to_dap}; dap.Send(Event{"my-event", std::nullopt}); - ASSERT_THAT_EXPECTED(fromDAP->Read(std::chrono::milliseconds(1)), + ASSERT_THAT_EXPECTED(from_dap->Read(std::chrono::milliseconds(1)), HasValue(testing::VariantWith(testing::FieldsAre( /*event=*/"my-event", /*body=*/std::nullopt)))); } From lldb-commits at lists.llvm.org Wed May 14 10:48:14 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 10:48:14 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <6824d75e.170a0220.a5bf0.0be1@mx.google.com> ashgti wrote: Yea, thats my mistake. I made the protocol classes to match the names of the spec, but we don't really have to do that as long as the `toJSON`/`fromJSON` adjusts the names, they can be different. https://github.com/llvm/llvm-project/pull/139937 From lldb-commits at lists.llvm.org Wed May 14 10:51:30 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 10:51:30 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <6824d822.170a0220.17629f.f42f@mx.google.com> https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/139937 >From 6f947e38ad4f744754cf13c1094c4e5e3fd249b6 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 14 May 2025 10:31:40 -0700 Subject: [PATCH 1/3] [lldb-dap] Setup DAP for unit testing. This is a very simple case that currently only validates we can create a DAP instance and send a message over the transport layer. More in-depth tests will require additional helpers and possibly refactors of DAP to make it more testable, however this is some ground work to have basic support for unit tests. --- lldb/tools/lldb-dap/DAP.h | 3 +- lldb/unittests/DAP/CMakeLists.txt | 1 + lldb/unittests/DAP/DAPTest.cpp | 63 +++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 lldb/unittests/DAP/DAPTest.cpp diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c2e4c2dea582e..2ff66d1cd0182 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -226,7 +226,8 @@ struct DAP { /// \param[in] default_repl_mode /// Default repl mode behavior, as configured by the binary. /// \param[in] pre_init_commands - /// LLDB commands to execute as soon as the debugger instance is allocaed. + /// LLDB commands to execute as soon as the debugger instance is + /// allocated. /// \param[in] transport /// Transport for this debug session. DAP(Log *log, const ReplMode default_repl_mode, diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index 110733e93b192..6074e9b872c49 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -3,6 +3,7 @@ add_lldb_unittest(DAPTests LLDBUtilsTest.cpp TransportTest.cpp ProtocolTypesTest.cpp + DAPTest.cpp LINK_LIBS lldbDAP diff --git a/lldb/unittests/DAP/DAPTest.cpp b/lldb/unittests/DAP/DAPTest.cpp new file mode 100644 index 0000000000000..9d2a9b944678e --- /dev/null +++ b/lldb/unittests/DAP/DAPTest.cpp @@ -0,0 +1,63 @@ +//===-- DAPTest.cpp -------------------------------------------------===// +// +// 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 "DAP.h" +#include "Protocol/ProtocolBase.h" +#include "Transport.h" +#include "lldb/Host/File.h" +#include "lldb/Host/Pipe.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include +#include + +using namespace llvm; +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap::protocol; +using lldb_private::File; +using lldb_private::NativeFile; +using lldb_private::Pipe; + +class DAPTest : public testing::Test { +protected: + Pipe input; + Pipe output; + std::unique_ptr toDAP; + std::unique_ptr fromDAP; + + void SetUp() override { + ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); + ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); + toDAP = std::make_unique( + "toDAP", nullptr, + std::make_shared(input.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(output.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + fromDAP = std::make_unique( + "fromDAP", nullptr, + std::make_shared(output.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(input.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + } +}; + +TEST_F(DAPTest, SendProtocolMessages) { + DAP dap{nullptr, ReplMode::Auto, {}, *toDAP}; + dap.Send(Event{"my-event", std::nullopt}); + ASSERT_THAT_EXPECTED(fromDAP->Read(std::chrono::milliseconds(1)), + HasValue(testing::VariantWith(testing::FieldsAre( + /*event=*/"my-event", /*body=*/std::nullopt)))); +} >From 8bc4880a338dd0d0f2daa64b77c8bdbf567270b2 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 14 May 2025 10:46:51 -0700 Subject: [PATCH 2/3] Adjusting the naming of variables. --- lldb/unittests/DAP/DAPTest.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lldb/unittests/DAP/DAPTest.cpp b/lldb/unittests/DAP/DAPTest.cpp index 9d2a9b944678e..8e8c2ea3ccbb0 100644 --- a/lldb/unittests/DAP/DAPTest.cpp +++ b/lldb/unittests/DAP/DAPTest.cpp @@ -29,22 +29,22 @@ class DAPTest : public testing::Test { protected: Pipe input; Pipe output; - std::unique_ptr toDAP; - std::unique_ptr fromDAP; + std::unique_ptr to_dap; + std::unique_ptr from_dap; void SetUp() override { ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); - toDAP = std::make_unique( - "toDAP", nullptr, + to_dap = std::make_unique( + "to_dap", nullptr, std::make_shared(input.GetReadFileDescriptor(), File::eOpenOptionReadOnly, NativeFile::Unowned), std::make_shared(output.GetWriteFileDescriptor(), File::eOpenOptionWriteOnly, NativeFile::Unowned)); - fromDAP = std::make_unique( - "fromDAP", nullptr, + from_dap = std::make_unique( + "from_dap", nullptr, std::make_shared(output.GetReadFileDescriptor(), File::eOpenOptionReadOnly, NativeFile::Unowned), @@ -55,9 +55,9 @@ class DAPTest : public testing::Test { }; TEST_F(DAPTest, SendProtocolMessages) { - DAP dap{nullptr, ReplMode::Auto, {}, *toDAP}; + DAP dap{nullptr, ReplMode::Auto, {}, *to_dap}; dap.Send(Event{"my-event", std::nullopt}); - ASSERT_THAT_EXPECTED(fromDAP->Read(std::chrono::milliseconds(1)), + ASSERT_THAT_EXPECTED(from_dap->Read(std::chrono::milliseconds(1)), HasValue(testing::VariantWith(testing::FieldsAre( /*event=*/"my-event", /*body=*/std::nullopt)))); } >From 41f8f41a6cae98c6e0fe703f5b34f9f3f4acba9a Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 14 May 2025 10:51:12 -0700 Subject: [PATCH 3/3] Adding inline comments to improve readability. --- lldb/unittests/DAP/DAPTest.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lldb/unittests/DAP/DAPTest.cpp b/lldb/unittests/DAP/DAPTest.cpp index 8e8c2ea3ccbb0..e23fb32eebea9 100644 --- a/lldb/unittests/DAP/DAPTest.cpp +++ b/lldb/unittests/DAP/DAPTest.cpp @@ -55,8 +55,9 @@ class DAPTest : public testing::Test { }; TEST_F(DAPTest, SendProtocolMessages) { - DAP dap{nullptr, ReplMode::Auto, {}, *to_dap}; - dap.Send(Event{"my-event", std::nullopt}); + DAP dap{/*log=*/nullptr, /*default_repl_mode=*/ReplMode::Auto, + /*pre_init_commands=*/{}, /*transport=*/*to_dap}; + dap.Send(Event{/*event=*/"my-event", /*body=*/std::nullopt}); ASSERT_THAT_EXPECTED(from_dap->Read(std::chrono::milliseconds(1)), HasValue(testing::VariantWith(testing::FieldsAre( /*event=*/"my-event", /*body=*/std::nullopt)))); From lldb-commits at lists.llvm.org Wed May 14 10:53:03 2025 From: lldb-commits at lists.llvm.org (Alex Langford via lldb-commits) Date: Wed, 14 May 2025 10:53:03 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream RPC server interface emitters (PR #138032) In-Reply-To: Message-ID: <6824d87f.170a0220.8749f.e774@mx.google.com> bulbazord wrote: > Pushed again to address David's comments and remove most of the FIXMEs. There's one FIXME I've kept in for now: > > ``` > // FIXME: SB class server references are stored as non-const references so > // that we can actually change them as needed. If a parameter is marked > // const, we will fail to compile because we cannot make an > // SBFooServerReference from a `const SBFoo &`. > // To work around this issue, we'll apply a `const_cast` if needed so we > // can continue to generate callbacks for now, but we really should > // rethink the way we store object IDs server-side to support > // const-qualified parameters. > ``` > > @bulbazord This is referring to how we emit storage for const SB parameters in callback functions. Currently it looks like it only gets applied to one function that gets generated. Any thoughts here? Given it only applies to one function, it's probably okay to keep it around for now. The fact that we need a `const_cast` at all is concerning but I think we've done a reasonably alright job at explaining why it exists (though I am a partial author, so maybe my perspective is biased). https://github.com/llvm/llvm-project/pull/138032 From lldb-commits at lists.llvm.org Wed May 14 10:53:48 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 10:53:48 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream Python scripts (PR #138028) In-Reply-To: Message-ID: <6824d8ac.170a0220.27e633.f1f9@mx.google.com> ================ @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +# Usage: convert-lldb-header-to-rpc-header.py +# This scripts takes common LLDB headers (such as lldb-defines.h) and replaces references to LLDB +# with those for RPC. This happens for: +# - namespace definitions +# - namespace usage +# - version string macros +# - ifdef/ifndef lines ---------------- JDevlieghere wrote: Python has a PEP that describes how to document files/modules. We should use that here too. ```suggestion """ Usage: convert-lldb-header-to-rpc-header.py This scripts takes common LLDB headers (such as lldb-defines.h) and replaces references to LLDB with those for RPC. This happens for: - namespace definitions - namespace usage - version string macros - ifdef/ifndef lines """ ``` https://github.com/llvm/llvm-project/pull/138028 From lldb-commits at lists.llvm.org Wed May 14 10:53:49 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 10:53:49 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream Python scripts (PR #138028) In-Reply-To: Message-ID: <6824d8ad.170a0220.2e4c51.de7c@mx.google.com> ================ @@ -0,0 +1,16 @@ +// Copy lldb-rpc-defines.h from source. +# RUN: mkdir -p %t/input +# RUN: mkdir -p %t/output +# RUN: cp %p/../../../../../include/lldb/lldb-defines.h %t/input ---------------- JDevlieghere wrote: Is the goal to run this on the sources to catch regressions, or are we just using the source file as a meaningful input? If it's the latter, I would recommend copying the file into the Inputs directory and reducing it to the bare minimum needed for the test. https://github.com/llvm/llvm-project/pull/138028 From lldb-commits at lists.llvm.org Wed May 14 10:53:49 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 10:53:49 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][RPC] Upstream Python scripts (PR #138028) In-Reply-To: Message-ID: <6824d8ad.050a0220.c3feb.ede9@mx.google.com> ================ @@ -0,0 +1,20 @@ +// Copy lldb-defines.h from source. +# RUN: mkdir -p %t/input +# RUN: mkdir -p %t/output +# RUN: cp %p/../../../../../include/lldb/lldb-defines.h %t/input ---------------- JDevlieghere wrote: You're mixing two comment styles here, and lit doesn't actually treat these any differently (it just look for RUN lines). So let's settle on one and drop them everywhere else. ```suggestion // Copy lldb-defines.h from source. RUN: mkdir -p %t/input RUN: mkdir -p %t/output RUN: cp %p/../../../../../include/lldb/lldb-defines.h %t/input ``` or ```suggestion # Copy lldb-defines.h from source. RUN: mkdir -p %t/input RUN: mkdir -p %t/output RUN: cp %p/../../../../../include/lldb/lldb-defines.h %t/input ``` I think the latter is slightly more common. https://github.com/llvm/llvm-project/pull/138028 From lldb-commits at lists.llvm.org Wed May 14 10:56:30 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 10:56:30 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <6824d94e.170a0220.612d5.1536@mx.google.com> JDevlieghere wrote: > Yea, thats my mistake. I made the protocol classes to match the names of the spec, but we don't really have to do that as long as the `toJSON`/`fromJSON` adjusts the names, they can be different. I think we discussed this at some point in the past and I'm personally okay with saying that everything outside the protocol dir should follow the LLDB style and the Protocol dir matches the spec (although we're already diverging from that for the enums). https://github.com/llvm/llvm-project/pull/139937 From lldb-commits at lists.llvm.org Wed May 14 10:59:17 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 10:59:17 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Refactor lldb-dap event handling. (PR #139669) In-Reply-To: Message-ID: <6824d9f5.630a0220.1ca4c.7d99@mx.google.com> ashgti wrote: > Yeah, that should be possible, and it may make more sense in a world where the MainLoop cannot listen on all FD types (since you need the forwarding thread anyway). It's unfortunate that there's no synchronization operation (at least, not a portable one, FUTEX_FD seems kinda nice) that allows you do wait for condition variables and FDs, necessitating these forwarding threads. Since forwarding would add a bit of latency, one of the factors would be which kinds of operations do we want to make slower. We could adjust the lldb-dap VSCode extension to launch lldb-dap using a named pipe or local tcp port on Windows. Then we'd uniformly be able to support reading the input using the existing lldb NativeFile/Socket helpers. See https://code.visualstudio.com/api/references/vscode-api#DebugAdapterNamedPipeServer https://github.com/llvm/llvm-project/pull/139669 From lldb-commits at lists.llvm.org Wed May 14 11:11:10 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Wed, 14 May 2025 11:11:10 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Added 32-bit XCOFF Executable support (PR #139875) In-Reply-To: Message-ID: <6824dcbe.a70a0220.267ef6.f312@mx.google.com> https://github.com/DhruvSrivastavaX updated https://github.com/llvm/llvm-project/pull/139875 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Wed May 14 11:21:46 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 11:21:46 -0700 (PDT) Subject: [Lldb-commits] [lldb] 539265b - [lldb] Simplify a string comparison (NFC) (#139932) Message-ID: <6824df3a.170a0220.226e77.0c57@mx.google.com> Author: Kazu Hirata Date: 2025-05-14T11:21:42-07:00 New Revision: 539265b9044f8cda513e5e65d11f2630a32176cf URL: https://github.com/llvm/llvm-project/commit/539265b9044f8cda513e5e65d11f2630a32176cf DIFF: https://github.com/llvm/llvm-project/commit/539265b9044f8cda513e5e65d11f2630a32176cf.diff LOG: [lldb] Simplify a string comparison (NFC) (#139932) Added: Modified: lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp Removed: ################################################################################ diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp index a2722db5d24a0..451cf40e2818d 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp @@ -123,8 +123,7 @@ void ASTStructExtractor::ExtractFromTopLevelDecl(Decl *D) { FunctionDecl *function_decl = dyn_cast(D); if (m_ast_context && function_decl && - !m_function.m_wrapper_function_name.compare( - function_decl->getNameAsString())) { + m_function.m_wrapper_function_name == function_decl->getNameAsString()) { ExtractFromFunctionDecl(function_decl); } } From lldb-commits at lists.llvm.org Wed May 14 11:21:49 2025 From: lldb-commits at lists.llvm.org (Kazu Hirata via lldb-commits) Date: Wed, 14 May 2025 11:21:49 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Simplify a string comparison (NFC) (PR #139932) In-Reply-To: Message-ID: <6824df3d.170a0220.d7156.ec87@mx.google.com> https://github.com/kazutakahirata closed https://github.com/llvm/llvm-project/pull/139932 From lldb-commits at lists.llvm.org Wed May 14 12:01:20 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Wed, 14 May 2025 12:01:20 -0700 (PDT) Subject: [Lldb-commits] [lldb] Complete the Implementation of DAP modules explorer. (PR #139934) In-Reply-To: Message-ID: <6824e880.170a0220.17c21c.0fac@mx.google.com> https://github.com/da-viper updated https://github.com/llvm/llvm-project/pull/139934 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Wed May 14 12:14:05 2025 From: lldb-commits at lists.llvm.org (Oliver Hunt via lldb-commits) Date: Wed, 14 May 2025 12:14:05 -0700 (PDT) Subject: [Lldb-commits] [clang] [clang-tools-extra] [lldb] [clang] Remove intrusive reference count from `DiagnosticOptions` (PR #139584) In-Reply-To: Message-ID: <6824eb7d.170a0220.15da7d.0d5e@mx.google.com> ================ @@ -2032,6 +2032,7 @@ class SourceManagerForFile { // as they are created in `createSourceManagerForFile` so that they can be // deleted in the reverse order as they are created. std::unique_ptr FileMgr; + std::unique_ptr DiagOpts; ---------------- ojhunt wrote: @jansvoboda11 the problem is that now an author does not know if a given DiagnosticOption is a unique_ptr or a shared_ptr. A given DiagnosticOption* may or may not be protectable, etc depending on the context and origin of the object. Philosophically I prefer intrusive refcounts over shared_ptr because to me they make the lifetime much clearer as the lifetime rules are embedded in the type, but I don't think that's an issue in this PR. My understanding is that the goal of this PR is to say "For API purposes, a given DiagnosticOption reference is only live as long as the API object that vends it. As an implementation detail there are some cases where it can outlast the vending object, but that's not generally part of the user visible API." That's a perfectly reasonable change, but my concern is that by mixing and matching shared and unique_ptr an author loses the ability to reason about what a given object's lifetime is. It seems like the reason for shared_ptr is to deal with some slightly gross bits of the API, and I wonder if it's possible to fix those APIs so we can just use unique_ptr everywhere? https://github.com/llvm/llvm-project/pull/139584 From lldb-commits at lists.llvm.org Wed May 14 12:49:32 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 12:49:32 -0700 (PDT) Subject: [Lldb-commits] [lldb] Complete the Implementation of DAP modules explorer. (PR #139934) In-Reply-To: Message-ID: <6824f3cc.170a0220.a5c18.003d@mx.google.com> ================ @@ -416,8 +416,11 @@ llvm::json::Value CreateModule(lldb::SBTarget &target, lldb::SBModule &module, } else { object.try_emplace("symbolStatus", "Symbols not found."); } - std::string loaded_addr = std::to_string( - module.GetObjectFileHeaderAddress().GetLoadAddress(target)); + std::string loaded_addr; + llvm::raw_string_ostream os_hex(loaded_addr); + os_hex << llvm::format_hex( + module.GetObjectFileHeaderAddress().GetLoadAddress(target), + sizeof(lldb::addr_t)); ---------------- ashgti wrote: https://github.com/microsoft/debug-adapter-protocol/issues/424 was filed to clarify how the address range is supposed to be represented. It hasn't had any movement recently, so we could ping the issue to see if the folks that work on the DAP have any more recent thoughts. https://github.com/llvm/llvm-project/pull/139934 From lldb-commits at lists.llvm.org Wed May 14 12:52:51 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 12:52:51 -0700 (PDT) Subject: [Lldb-commits] [lldb] Complete the Implementation of DAP modules explorer. (PR #139934) In-Reply-To: Message-ID: <6824f493.170a0220.efc04.008b@mx.google.com> ================ @@ -244,6 +244,20 @@ } } ], + "commands": [ + { + "command": "lldb-dap.modules.copyProperty", + "title": "Copy Value" + } + ], + "menus": { + "view/item/context": [ ---------------- ashgti wrote: Can we also disable the `Copy Value` command from the command prompt? adding: ``` "commandPalette": [{"command": "lldb-dap.modules.copyProperty", "when": "false"}], ``` Should hide it, since its not useful without the context of a tree view item. https://github.com/llvm/llvm-project/pull/139934 From lldb-commits at lists.llvm.org Wed May 14 12:52:51 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 12:52:51 -0700 (PDT) Subject: [Lldb-commits] [lldb] Complete the Implementation of DAP modules explorer. (PR #139934) In-Reply-To: Message-ID: <6824f493.050a0220.148edb.fc90@mx.google.com> https://github.com/ashgti approved this pull request. https://github.com/llvm/llvm-project/pull/139934 From lldb-commits at lists.llvm.org Wed May 14 13:08:02 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 13:08:02 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <6824f822.050a0220.cb9fb.0cbc@mx.google.com> https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/139937 >From 6f947e38ad4f744754cf13c1094c4e5e3fd249b6 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 14 May 2025 10:31:40 -0700 Subject: [PATCH 1/4] [lldb-dap] Setup DAP for unit testing. This is a very simple case that currently only validates we can create a DAP instance and send a message over the transport layer. More in-depth tests will require additional helpers and possibly refactors of DAP to make it more testable, however this is some ground work to have basic support for unit tests. --- lldb/tools/lldb-dap/DAP.h | 3 +- lldb/unittests/DAP/CMakeLists.txt | 1 + lldb/unittests/DAP/DAPTest.cpp | 63 +++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 lldb/unittests/DAP/DAPTest.cpp diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c2e4c2dea582e..2ff66d1cd0182 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -226,7 +226,8 @@ struct DAP { /// \param[in] default_repl_mode /// Default repl mode behavior, as configured by the binary. /// \param[in] pre_init_commands - /// LLDB commands to execute as soon as the debugger instance is allocaed. + /// LLDB commands to execute as soon as the debugger instance is + /// allocated. /// \param[in] transport /// Transport for this debug session. DAP(Log *log, const ReplMode default_repl_mode, diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index 110733e93b192..6074e9b872c49 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -3,6 +3,7 @@ add_lldb_unittest(DAPTests LLDBUtilsTest.cpp TransportTest.cpp ProtocolTypesTest.cpp + DAPTest.cpp LINK_LIBS lldbDAP diff --git a/lldb/unittests/DAP/DAPTest.cpp b/lldb/unittests/DAP/DAPTest.cpp new file mode 100644 index 0000000000000..9d2a9b944678e --- /dev/null +++ b/lldb/unittests/DAP/DAPTest.cpp @@ -0,0 +1,63 @@ +//===-- DAPTest.cpp -------------------------------------------------===// +// +// 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 "DAP.h" +#include "Protocol/ProtocolBase.h" +#include "Transport.h" +#include "lldb/Host/File.h" +#include "lldb/Host/Pipe.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include +#include + +using namespace llvm; +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap::protocol; +using lldb_private::File; +using lldb_private::NativeFile; +using lldb_private::Pipe; + +class DAPTest : public testing::Test { +protected: + Pipe input; + Pipe output; + std::unique_ptr toDAP; + std::unique_ptr fromDAP; + + void SetUp() override { + ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); + ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); + toDAP = std::make_unique( + "toDAP", nullptr, + std::make_shared(input.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(output.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + fromDAP = std::make_unique( + "fromDAP", nullptr, + std::make_shared(output.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(input.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + } +}; + +TEST_F(DAPTest, SendProtocolMessages) { + DAP dap{nullptr, ReplMode::Auto, {}, *toDAP}; + dap.Send(Event{"my-event", std::nullopt}); + ASSERT_THAT_EXPECTED(fromDAP->Read(std::chrono::milliseconds(1)), + HasValue(testing::VariantWith(testing::FieldsAre( + /*event=*/"my-event", /*body=*/std::nullopt)))); +} >From 8bc4880a338dd0d0f2daa64b77c8bdbf567270b2 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 14 May 2025 10:46:51 -0700 Subject: [PATCH 2/4] Adjusting the naming of variables. --- lldb/unittests/DAP/DAPTest.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lldb/unittests/DAP/DAPTest.cpp b/lldb/unittests/DAP/DAPTest.cpp index 9d2a9b944678e..8e8c2ea3ccbb0 100644 --- a/lldb/unittests/DAP/DAPTest.cpp +++ b/lldb/unittests/DAP/DAPTest.cpp @@ -29,22 +29,22 @@ class DAPTest : public testing::Test { protected: Pipe input; Pipe output; - std::unique_ptr toDAP; - std::unique_ptr fromDAP; + std::unique_ptr to_dap; + std::unique_ptr from_dap; void SetUp() override { ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); - toDAP = std::make_unique( - "toDAP", nullptr, + to_dap = std::make_unique( + "to_dap", nullptr, std::make_shared(input.GetReadFileDescriptor(), File::eOpenOptionReadOnly, NativeFile::Unowned), std::make_shared(output.GetWriteFileDescriptor(), File::eOpenOptionWriteOnly, NativeFile::Unowned)); - fromDAP = std::make_unique( - "fromDAP", nullptr, + from_dap = std::make_unique( + "from_dap", nullptr, std::make_shared(output.GetReadFileDescriptor(), File::eOpenOptionReadOnly, NativeFile::Unowned), @@ -55,9 +55,9 @@ class DAPTest : public testing::Test { }; TEST_F(DAPTest, SendProtocolMessages) { - DAP dap{nullptr, ReplMode::Auto, {}, *toDAP}; + DAP dap{nullptr, ReplMode::Auto, {}, *to_dap}; dap.Send(Event{"my-event", std::nullopt}); - ASSERT_THAT_EXPECTED(fromDAP->Read(std::chrono::milliseconds(1)), + ASSERT_THAT_EXPECTED(from_dap->Read(std::chrono::milliseconds(1)), HasValue(testing::VariantWith(testing::FieldsAre( /*event=*/"my-event", /*body=*/std::nullopt)))); } >From 41f8f41a6cae98c6e0fe703f5b34f9f3f4acba9a Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 14 May 2025 10:51:12 -0700 Subject: [PATCH 3/4] Adding inline comments to improve readability. --- lldb/unittests/DAP/DAPTest.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lldb/unittests/DAP/DAPTest.cpp b/lldb/unittests/DAP/DAPTest.cpp index 8e8c2ea3ccbb0..e23fb32eebea9 100644 --- a/lldb/unittests/DAP/DAPTest.cpp +++ b/lldb/unittests/DAP/DAPTest.cpp @@ -55,8 +55,9 @@ class DAPTest : public testing::Test { }; TEST_F(DAPTest, SendProtocolMessages) { - DAP dap{nullptr, ReplMode::Auto, {}, *to_dap}; - dap.Send(Event{"my-event", std::nullopt}); + DAP dap{/*log=*/nullptr, /*default_repl_mode=*/ReplMode::Auto, + /*pre_init_commands=*/{}, /*transport=*/*to_dap}; + dap.Send(Event{/*event=*/"my-event", /*body=*/std::nullopt}); ASSERT_THAT_EXPECTED(from_dap->Read(std::chrono::milliseconds(1)), HasValue(testing::VariantWith(testing::FieldsAre( /*event=*/"my-event", /*body=*/std::nullopt)))); >From e6dfa922161b70228a38f2bcd52776efb64ae6c1 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 14 May 2025 13:07:10 -0700 Subject: [PATCH 4/4] Add some helper test bases classes and a Handler test as well. --- lldb/unittests/DAP/CMakeLists.txt | 6 +- lldb/unittests/DAP/DAPTest.cpp | 46 +++--------- .../Handler/DisconnectRequestHandlerTest.cpp | 34 +++++++++ lldb/unittests/DAP/TestBase.cpp | 70 +++++++++++++++++++ lldb/unittests/DAP/TestBase.h | 46 ++++++++++++ lldb/unittests/DAP/TransportTest.cpp | 24 +++---- 6 files changed, 174 insertions(+), 52 deletions(-) create mode 100644 lldb/unittests/DAP/Handler/DisconnectRequestHandlerTest.cpp create mode 100644 lldb/unittests/DAP/TestBase.cpp create mode 100644 lldb/unittests/DAP/TestBase.h diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index 6074e9b872c49..4b3447ae3310a 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -1,9 +1,11 @@ add_lldb_unittest(DAPTests + DAPTest.cpp + Handler/DisconnectRequestHandlerTest.cpp JSONUtilsTest.cpp LLDBUtilsTest.cpp - TransportTest.cpp ProtocolTypesTest.cpp - DAPTest.cpp + TestBase.cpp + TransportTest.cpp LINK_LIBS lldbDAP diff --git a/lldb/unittests/DAP/DAPTest.cpp b/lldb/unittests/DAP/DAPTest.cpp index e23fb32eebea9..5fb6bf7e564ab 100644 --- a/lldb/unittests/DAP/DAPTest.cpp +++ b/lldb/unittests/DAP/DAPTest.cpp @@ -1,4 +1,4 @@ -//===-- DAPTest.cpp -------------------------------------------------===// +//===-- DAPTest.cpp -------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,9 +8,8 @@ #include "DAP.h" #include "Protocol/ProtocolBase.h" +#include "TestBase.h" #include "Transport.h" -#include "lldb/Host/File.h" -#include "lldb/Host/Pipe.h" #include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" #include @@ -20,43 +19,18 @@ using namespace llvm; using namespace lldb; using namespace lldb_dap; +using namespace lldb_dap_tests; using namespace lldb_dap::protocol; -using lldb_private::File; -using lldb_private::NativeFile; -using lldb_private::Pipe; -class DAPTest : public testing::Test { -protected: - Pipe input; - Pipe output; - std::unique_ptr to_dap; - std::unique_ptr from_dap; - - void SetUp() override { - ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); - ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); - to_dap = std::make_unique( - "to_dap", nullptr, - std::make_shared(input.GetReadFileDescriptor(), - File::eOpenOptionReadOnly, - NativeFile::Unowned), - std::make_shared(output.GetWriteFileDescriptor(), - File::eOpenOptionWriteOnly, - NativeFile::Unowned)); - from_dap = std::make_unique( - "from_dap", nullptr, - std::make_shared(output.GetReadFileDescriptor(), - File::eOpenOptionReadOnly, - NativeFile::Unowned), - std::make_shared(input.GetWriteFileDescriptor(), - File::eOpenOptionWriteOnly, - NativeFile::Unowned)); - } -}; +class DAPTest : public TransportBase {}; TEST_F(DAPTest, SendProtocolMessages) { - DAP dap{/*log=*/nullptr, /*default_repl_mode=*/ReplMode::Auto, - /*pre_init_commands=*/{}, /*transport=*/*to_dap}; + DAP dap{ + /*log=*/nullptr, + /*default_repl_mode=*/ReplMode::Auto, + /*pre_init_commands=*/{}, + /*transport=*/*to_dap, + }; dap.Send(Event{/*event=*/"my-event", /*body=*/std::nullopt}); ASSERT_THAT_EXPECTED(from_dap->Read(std::chrono::milliseconds(1)), HasValue(testing::VariantWith(testing::FieldsAre( diff --git a/lldb/unittests/DAP/Handler/DisconnectRequestHandlerTest.cpp b/lldb/unittests/DAP/Handler/DisconnectRequestHandlerTest.cpp new file mode 100644 index 0000000000000..0ef763574e8df --- /dev/null +++ b/lldb/unittests/DAP/Handler/DisconnectRequestHandlerTest.cpp @@ -0,0 +1,34 @@ +//===-- DisconnectRequestHandlerTest.cpp ----------------------------------===// +// +// 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 "DAP.h" +#include "Handler/RequestHandler.h" +#include "Protocol/ProtocolBase.h" +#include "TestBase.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include + +using namespace llvm; +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap_tests; +using namespace lldb_dap::protocol; + +class DisconnectRequestHandlerTest : public DAPTestBase {}; + +TEST_F(DisconnectRequestHandlerTest, DisconnectingTriggersTerminated) { + DisconnectRequestHandler handler(*dap); + ASSERT_THAT_ERROR(handler.Run(std::nullopt), Succeeded()); + EXPECT_TRUE(dap->disconnecting); + std::vector messages = DrainOutput(); + EXPECT_THAT(messages, + testing::Contains(testing::VariantWith(testing::FieldsAre( + /*event=*/"terminated", /*body=*/std::nullopt)))); +} diff --git a/lldb/unittests/DAP/TestBase.cpp b/lldb/unittests/DAP/TestBase.cpp new file mode 100644 index 0000000000000..08dda62e217c3 --- /dev/null +++ b/lldb/unittests/DAP/TestBase.cpp @@ -0,0 +1,70 @@ +//===-- TestBase.cpp -------------------------------------------------===// +// +// 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 "TestBase.h" +#include "Protocol/ProtocolBase.h" +#include "lldb/Host/File.h" +#include "lldb/Host/Pipe.h" +#include "llvm/Testing/Support/Error.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap::protocol; +using namespace lldb_dap_tests; +using lldb_private::File; +using lldb_private::NativeFile; +using lldb_private::Pipe; + +void PipeBase::SetUp() { + ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); + ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); +} + +void TransportBase::SetUp() { + PipeBase::SetUp(); + to_dap = std::make_unique( + "to_dap", nullptr, + std::make_shared(input.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(output.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + from_dap = std::make_unique( + "from_dap", nullptr, + std::make_shared(output.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(input.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); +} + +void DAPTestBase::SetUp() { + TransportBase::SetUp(); + dap = std::make_unique( + /*log=*/nullptr, + /*default_repl_mode=*/ReplMode::Auto, + /*pre_init_commands=*/std::vector(), + /*transport=*/*to_dap); +} + +std::vector DAPTestBase::DrainOutput() { + std::vector msgs; + output.CloseWriteFileDescriptor(); + while (true) { + Expected next = from_dap->Read(std::chrono::milliseconds(1)); + if (!next) { + consumeError(next.takeError()); + break; + } + msgs.push_back(*next); + } + return msgs; +} \ No newline at end of file diff --git a/lldb/unittests/DAP/TestBase.h b/lldb/unittests/DAP/TestBase.h new file mode 100644 index 0000000000000..7f8b2fb5121c6 --- /dev/null +++ b/lldb/unittests/DAP/TestBase.h @@ -0,0 +1,46 @@ +//===-- TestBase.cpp ------------------------------------------------------===// +// +// 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 "DAP.h" +#include "Protocol/ProtocolBase.h" +#include "Transport.h" +#include "lldb/Host/Pipe.h" +#include "gtest/gtest.h" + +namespace lldb_dap_tests { + +/// A base class for tests that need a pair of pipes for communication. +class PipeBase : public testing::Test { +protected: + lldb_private::Pipe input; + lldb_private::Pipe output; + + void SetUp() override; +}; + +/// A base class for tests that need transport configured. +class TransportBase : public PipeBase { +protected: + std::unique_ptr to_dap; + std::unique_ptr from_dap; + + void SetUp() override; +}; + +class DAPTestBase : public TransportBase { +protected: + std::unique_ptr dap; + + void SetUp() override; + + /// Closes the DAP output pipe and returns the remaining protocol messages in + /// the buffer. + std::vector DrainOutput(); +}; + +} // namespace lldb_dap_tests diff --git a/lldb/unittests/DAP/TransportTest.cpp b/lldb/unittests/DAP/TransportTest.cpp index 5c77b4bb26343..e6dab42e30941 100644 --- a/lldb/unittests/DAP/TransportTest.cpp +++ b/lldb/unittests/DAP/TransportTest.cpp @@ -8,10 +8,10 @@ #include "Transport.h" #include "Protocol/ProtocolBase.h" +#include "TestBase.h" #include "lldb/Host/File.h" #include "lldb/Host/Pipe.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/FormatVariadic.h" #include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" #include @@ -21,20 +21,18 @@ using namespace llvm; using namespace lldb; using namespace lldb_dap; +using namespace lldb_dap_tests; using namespace lldb_dap::protocol; using lldb_private::File; using lldb_private::NativeFile; using lldb_private::Pipe; -class TransportTest : public testing::Test { +class TransportTest : public PipeBase { protected: - Pipe input; - Pipe output; std::unique_ptr transport; void SetUp() override { - ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); - ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); + PipeBase::SetUp(); transport = std::make_unique( "stdio", nullptr, std::make_shared(input.GetReadFileDescriptor(), @@ -44,13 +42,6 @@ class TransportTest : public testing::Test { File::eOpenOptionWriteOnly, NativeFile::Unowned)); } - - void Write(StringRef json) { - std::string message = - formatv("Content-Length: {0}\r\n\r\n{1}", json.size(), json).str(); - ASSERT_THAT_EXPECTED(input.Write(message.data(), message.size()), - Succeeded()); - } }; TEST_F(TransportTest, MalformedRequests) { @@ -65,7 +56,12 @@ TEST_F(TransportTest, MalformedRequests) { } TEST_F(TransportTest, Read) { - Write(R"json({"seq": 1, "type": "request", "command": "abc"})json"); + std::string json = + R"json({"seq": 1, "type": "request", "command": "abc"})json"; + std::string message = + formatv("Content-Length: {0}\r\n\r\n{1}", json.size(), json).str(); + ASSERT_THAT_EXPECTED(input.Write(message.data(), message.size()), + Succeeded()); ASSERT_THAT_EXPECTED( transport->Read(std::chrono::milliseconds(1)), HasValue(testing::VariantWith(testing::FieldsAre( From lldb-commits at lists.llvm.org Wed May 14 13:08:53 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 13:08:53 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <6824f855.170a0220.301af4.e1ec@mx.google.com> ashgti wrote: I added a few extra tests here and some extra base classes to help setup tests. LMKWYT https://github.com/llvm/llvm-project/pull/139937 From lldb-commits at lists.llvm.org Wed May 14 13:11:50 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 13:11:50 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <6824f906.170a0220.2e4c97.e2c4@mx.google.com> https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/139937 >From 6f947e38ad4f744754cf13c1094c4e5e3fd249b6 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 14 May 2025 10:31:40 -0700 Subject: [PATCH 1/5] [lldb-dap] Setup DAP for unit testing. This is a very simple case that currently only validates we can create a DAP instance and send a message over the transport layer. More in-depth tests will require additional helpers and possibly refactors of DAP to make it more testable, however this is some ground work to have basic support for unit tests. --- lldb/tools/lldb-dap/DAP.h | 3 +- lldb/unittests/DAP/CMakeLists.txt | 1 + lldb/unittests/DAP/DAPTest.cpp | 63 +++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 lldb/unittests/DAP/DAPTest.cpp diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c2e4c2dea582e..2ff66d1cd0182 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -226,7 +226,8 @@ struct DAP { /// \param[in] default_repl_mode /// Default repl mode behavior, as configured by the binary. /// \param[in] pre_init_commands - /// LLDB commands to execute as soon as the debugger instance is allocaed. + /// LLDB commands to execute as soon as the debugger instance is + /// allocated. /// \param[in] transport /// Transport for this debug session. DAP(Log *log, const ReplMode default_repl_mode, diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index 110733e93b192..6074e9b872c49 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -3,6 +3,7 @@ add_lldb_unittest(DAPTests LLDBUtilsTest.cpp TransportTest.cpp ProtocolTypesTest.cpp + DAPTest.cpp LINK_LIBS lldbDAP diff --git a/lldb/unittests/DAP/DAPTest.cpp b/lldb/unittests/DAP/DAPTest.cpp new file mode 100644 index 0000000000000..9d2a9b944678e --- /dev/null +++ b/lldb/unittests/DAP/DAPTest.cpp @@ -0,0 +1,63 @@ +//===-- DAPTest.cpp -------------------------------------------------===// +// +// 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 "DAP.h" +#include "Protocol/ProtocolBase.h" +#include "Transport.h" +#include "lldb/Host/File.h" +#include "lldb/Host/Pipe.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include +#include + +using namespace llvm; +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap::protocol; +using lldb_private::File; +using lldb_private::NativeFile; +using lldb_private::Pipe; + +class DAPTest : public testing::Test { +protected: + Pipe input; + Pipe output; + std::unique_ptr toDAP; + std::unique_ptr fromDAP; + + void SetUp() override { + ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); + ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); + toDAP = std::make_unique( + "toDAP", nullptr, + std::make_shared(input.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(output.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + fromDAP = std::make_unique( + "fromDAP", nullptr, + std::make_shared(output.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(input.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + } +}; + +TEST_F(DAPTest, SendProtocolMessages) { + DAP dap{nullptr, ReplMode::Auto, {}, *toDAP}; + dap.Send(Event{"my-event", std::nullopt}); + ASSERT_THAT_EXPECTED(fromDAP->Read(std::chrono::milliseconds(1)), + HasValue(testing::VariantWith(testing::FieldsAre( + /*event=*/"my-event", /*body=*/std::nullopt)))); +} >From 8bc4880a338dd0d0f2daa64b77c8bdbf567270b2 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 14 May 2025 10:46:51 -0700 Subject: [PATCH 2/5] Adjusting the naming of variables. --- lldb/unittests/DAP/DAPTest.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lldb/unittests/DAP/DAPTest.cpp b/lldb/unittests/DAP/DAPTest.cpp index 9d2a9b944678e..8e8c2ea3ccbb0 100644 --- a/lldb/unittests/DAP/DAPTest.cpp +++ b/lldb/unittests/DAP/DAPTest.cpp @@ -29,22 +29,22 @@ class DAPTest : public testing::Test { protected: Pipe input; Pipe output; - std::unique_ptr toDAP; - std::unique_ptr fromDAP; + std::unique_ptr to_dap; + std::unique_ptr from_dap; void SetUp() override { ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); - toDAP = std::make_unique( - "toDAP", nullptr, + to_dap = std::make_unique( + "to_dap", nullptr, std::make_shared(input.GetReadFileDescriptor(), File::eOpenOptionReadOnly, NativeFile::Unowned), std::make_shared(output.GetWriteFileDescriptor(), File::eOpenOptionWriteOnly, NativeFile::Unowned)); - fromDAP = std::make_unique( - "fromDAP", nullptr, + from_dap = std::make_unique( + "from_dap", nullptr, std::make_shared(output.GetReadFileDescriptor(), File::eOpenOptionReadOnly, NativeFile::Unowned), @@ -55,9 +55,9 @@ class DAPTest : public testing::Test { }; TEST_F(DAPTest, SendProtocolMessages) { - DAP dap{nullptr, ReplMode::Auto, {}, *toDAP}; + DAP dap{nullptr, ReplMode::Auto, {}, *to_dap}; dap.Send(Event{"my-event", std::nullopt}); - ASSERT_THAT_EXPECTED(fromDAP->Read(std::chrono::milliseconds(1)), + ASSERT_THAT_EXPECTED(from_dap->Read(std::chrono::milliseconds(1)), HasValue(testing::VariantWith(testing::FieldsAre( /*event=*/"my-event", /*body=*/std::nullopt)))); } >From 41f8f41a6cae98c6e0fe703f5b34f9f3f4acba9a Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 14 May 2025 10:51:12 -0700 Subject: [PATCH 3/5] Adding inline comments to improve readability. --- lldb/unittests/DAP/DAPTest.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lldb/unittests/DAP/DAPTest.cpp b/lldb/unittests/DAP/DAPTest.cpp index 8e8c2ea3ccbb0..e23fb32eebea9 100644 --- a/lldb/unittests/DAP/DAPTest.cpp +++ b/lldb/unittests/DAP/DAPTest.cpp @@ -55,8 +55,9 @@ class DAPTest : public testing::Test { }; TEST_F(DAPTest, SendProtocolMessages) { - DAP dap{nullptr, ReplMode::Auto, {}, *to_dap}; - dap.Send(Event{"my-event", std::nullopt}); + DAP dap{/*log=*/nullptr, /*default_repl_mode=*/ReplMode::Auto, + /*pre_init_commands=*/{}, /*transport=*/*to_dap}; + dap.Send(Event{/*event=*/"my-event", /*body=*/std::nullopt}); ASSERT_THAT_EXPECTED(from_dap->Read(std::chrono::milliseconds(1)), HasValue(testing::VariantWith(testing::FieldsAre( /*event=*/"my-event", /*body=*/std::nullopt)))); >From e6dfa922161b70228a38f2bcd52776efb64ae6c1 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 14 May 2025 13:07:10 -0700 Subject: [PATCH 4/5] Add some helper test bases classes and a Handler test as well. --- lldb/unittests/DAP/CMakeLists.txt | 6 +- lldb/unittests/DAP/DAPTest.cpp | 46 +++--------- .../Handler/DisconnectRequestHandlerTest.cpp | 34 +++++++++ lldb/unittests/DAP/TestBase.cpp | 70 +++++++++++++++++++ lldb/unittests/DAP/TestBase.h | 46 ++++++++++++ lldb/unittests/DAP/TransportTest.cpp | 24 +++---- 6 files changed, 174 insertions(+), 52 deletions(-) create mode 100644 lldb/unittests/DAP/Handler/DisconnectRequestHandlerTest.cpp create mode 100644 lldb/unittests/DAP/TestBase.cpp create mode 100644 lldb/unittests/DAP/TestBase.h diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index 6074e9b872c49..4b3447ae3310a 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -1,9 +1,11 @@ add_lldb_unittest(DAPTests + DAPTest.cpp + Handler/DisconnectRequestHandlerTest.cpp JSONUtilsTest.cpp LLDBUtilsTest.cpp - TransportTest.cpp ProtocolTypesTest.cpp - DAPTest.cpp + TestBase.cpp + TransportTest.cpp LINK_LIBS lldbDAP diff --git a/lldb/unittests/DAP/DAPTest.cpp b/lldb/unittests/DAP/DAPTest.cpp index e23fb32eebea9..5fb6bf7e564ab 100644 --- a/lldb/unittests/DAP/DAPTest.cpp +++ b/lldb/unittests/DAP/DAPTest.cpp @@ -1,4 +1,4 @@ -//===-- DAPTest.cpp -------------------------------------------------===// +//===-- DAPTest.cpp -------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,9 +8,8 @@ #include "DAP.h" #include "Protocol/ProtocolBase.h" +#include "TestBase.h" #include "Transport.h" -#include "lldb/Host/File.h" -#include "lldb/Host/Pipe.h" #include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" #include @@ -20,43 +19,18 @@ using namespace llvm; using namespace lldb; using namespace lldb_dap; +using namespace lldb_dap_tests; using namespace lldb_dap::protocol; -using lldb_private::File; -using lldb_private::NativeFile; -using lldb_private::Pipe; -class DAPTest : public testing::Test { -protected: - Pipe input; - Pipe output; - std::unique_ptr to_dap; - std::unique_ptr from_dap; - - void SetUp() override { - ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); - ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); - to_dap = std::make_unique( - "to_dap", nullptr, - std::make_shared(input.GetReadFileDescriptor(), - File::eOpenOptionReadOnly, - NativeFile::Unowned), - std::make_shared(output.GetWriteFileDescriptor(), - File::eOpenOptionWriteOnly, - NativeFile::Unowned)); - from_dap = std::make_unique( - "from_dap", nullptr, - std::make_shared(output.GetReadFileDescriptor(), - File::eOpenOptionReadOnly, - NativeFile::Unowned), - std::make_shared(input.GetWriteFileDescriptor(), - File::eOpenOptionWriteOnly, - NativeFile::Unowned)); - } -}; +class DAPTest : public TransportBase {}; TEST_F(DAPTest, SendProtocolMessages) { - DAP dap{/*log=*/nullptr, /*default_repl_mode=*/ReplMode::Auto, - /*pre_init_commands=*/{}, /*transport=*/*to_dap}; + DAP dap{ + /*log=*/nullptr, + /*default_repl_mode=*/ReplMode::Auto, + /*pre_init_commands=*/{}, + /*transport=*/*to_dap, + }; dap.Send(Event{/*event=*/"my-event", /*body=*/std::nullopt}); ASSERT_THAT_EXPECTED(from_dap->Read(std::chrono::milliseconds(1)), HasValue(testing::VariantWith(testing::FieldsAre( diff --git a/lldb/unittests/DAP/Handler/DisconnectRequestHandlerTest.cpp b/lldb/unittests/DAP/Handler/DisconnectRequestHandlerTest.cpp new file mode 100644 index 0000000000000..0ef763574e8df --- /dev/null +++ b/lldb/unittests/DAP/Handler/DisconnectRequestHandlerTest.cpp @@ -0,0 +1,34 @@ +//===-- DisconnectRequestHandlerTest.cpp ----------------------------------===// +// +// 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 "DAP.h" +#include "Handler/RequestHandler.h" +#include "Protocol/ProtocolBase.h" +#include "TestBase.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include + +using namespace llvm; +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap_tests; +using namespace lldb_dap::protocol; + +class DisconnectRequestHandlerTest : public DAPTestBase {}; + +TEST_F(DisconnectRequestHandlerTest, DisconnectingTriggersTerminated) { + DisconnectRequestHandler handler(*dap); + ASSERT_THAT_ERROR(handler.Run(std::nullopt), Succeeded()); + EXPECT_TRUE(dap->disconnecting); + std::vector messages = DrainOutput(); + EXPECT_THAT(messages, + testing::Contains(testing::VariantWith(testing::FieldsAre( + /*event=*/"terminated", /*body=*/std::nullopt)))); +} diff --git a/lldb/unittests/DAP/TestBase.cpp b/lldb/unittests/DAP/TestBase.cpp new file mode 100644 index 0000000000000..08dda62e217c3 --- /dev/null +++ b/lldb/unittests/DAP/TestBase.cpp @@ -0,0 +1,70 @@ +//===-- TestBase.cpp -------------------------------------------------===// +// +// 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 "TestBase.h" +#include "Protocol/ProtocolBase.h" +#include "lldb/Host/File.h" +#include "lldb/Host/Pipe.h" +#include "llvm/Testing/Support/Error.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap::protocol; +using namespace lldb_dap_tests; +using lldb_private::File; +using lldb_private::NativeFile; +using lldb_private::Pipe; + +void PipeBase::SetUp() { + ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); + ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); +} + +void TransportBase::SetUp() { + PipeBase::SetUp(); + to_dap = std::make_unique( + "to_dap", nullptr, + std::make_shared(input.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(output.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + from_dap = std::make_unique( + "from_dap", nullptr, + std::make_shared(output.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(input.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); +} + +void DAPTestBase::SetUp() { + TransportBase::SetUp(); + dap = std::make_unique( + /*log=*/nullptr, + /*default_repl_mode=*/ReplMode::Auto, + /*pre_init_commands=*/std::vector(), + /*transport=*/*to_dap); +} + +std::vector DAPTestBase::DrainOutput() { + std::vector msgs; + output.CloseWriteFileDescriptor(); + while (true) { + Expected next = from_dap->Read(std::chrono::milliseconds(1)); + if (!next) { + consumeError(next.takeError()); + break; + } + msgs.push_back(*next); + } + return msgs; +} \ No newline at end of file diff --git a/lldb/unittests/DAP/TestBase.h b/lldb/unittests/DAP/TestBase.h new file mode 100644 index 0000000000000..7f8b2fb5121c6 --- /dev/null +++ b/lldb/unittests/DAP/TestBase.h @@ -0,0 +1,46 @@ +//===-- TestBase.cpp ------------------------------------------------------===// +// +// 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 "DAP.h" +#include "Protocol/ProtocolBase.h" +#include "Transport.h" +#include "lldb/Host/Pipe.h" +#include "gtest/gtest.h" + +namespace lldb_dap_tests { + +/// A base class for tests that need a pair of pipes for communication. +class PipeBase : public testing::Test { +protected: + lldb_private::Pipe input; + lldb_private::Pipe output; + + void SetUp() override; +}; + +/// A base class for tests that need transport configured. +class TransportBase : public PipeBase { +protected: + std::unique_ptr to_dap; + std::unique_ptr from_dap; + + void SetUp() override; +}; + +class DAPTestBase : public TransportBase { +protected: + std::unique_ptr dap; + + void SetUp() override; + + /// Closes the DAP output pipe and returns the remaining protocol messages in + /// the buffer. + std::vector DrainOutput(); +}; + +} // namespace lldb_dap_tests diff --git a/lldb/unittests/DAP/TransportTest.cpp b/lldb/unittests/DAP/TransportTest.cpp index 5c77b4bb26343..e6dab42e30941 100644 --- a/lldb/unittests/DAP/TransportTest.cpp +++ b/lldb/unittests/DAP/TransportTest.cpp @@ -8,10 +8,10 @@ #include "Transport.h" #include "Protocol/ProtocolBase.h" +#include "TestBase.h" #include "lldb/Host/File.h" #include "lldb/Host/Pipe.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/FormatVariadic.h" #include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" #include @@ -21,20 +21,18 @@ using namespace llvm; using namespace lldb; using namespace lldb_dap; +using namespace lldb_dap_tests; using namespace lldb_dap::protocol; using lldb_private::File; using lldb_private::NativeFile; using lldb_private::Pipe; -class TransportTest : public testing::Test { +class TransportTest : public PipeBase { protected: - Pipe input; - Pipe output; std::unique_ptr transport; void SetUp() override { - ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); - ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); + PipeBase::SetUp(); transport = std::make_unique( "stdio", nullptr, std::make_shared(input.GetReadFileDescriptor(), @@ -44,13 +42,6 @@ class TransportTest : public testing::Test { File::eOpenOptionWriteOnly, NativeFile::Unowned)); } - - void Write(StringRef json) { - std::string message = - formatv("Content-Length: {0}\r\n\r\n{1}", json.size(), json).str(); - ASSERT_THAT_EXPECTED(input.Write(message.data(), message.size()), - Succeeded()); - } }; TEST_F(TransportTest, MalformedRequests) { @@ -65,7 +56,12 @@ TEST_F(TransportTest, MalformedRequests) { } TEST_F(TransportTest, Read) { - Write(R"json({"seq": 1, "type": "request", "command": "abc"})json"); + std::string json = + R"json({"seq": 1, "type": "request", "command": "abc"})json"; + std::string message = + formatv("Content-Length: {0}\r\n\r\n{1}", json.size(), json).str(); + ASSERT_THAT_EXPECTED(input.Write(message.data(), message.size()), + Succeeded()); ASSERT_THAT_EXPECTED( transport->Read(std::chrono::milliseconds(1)), HasValue(testing::VariantWith(testing::FieldsAre( >From ffcf631009e66ea69bcb26d6c996366e4ea84280 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 14 May 2025 13:11:27 -0700 Subject: [PATCH 5/5] Fix TestBase.cpp doc comment. --- lldb/unittests/DAP/TestBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/unittests/DAP/TestBase.cpp b/lldb/unittests/DAP/TestBase.cpp index 08dda62e217c3..96d1248e14917 100644 --- a/lldb/unittests/DAP/TestBase.cpp +++ b/lldb/unittests/DAP/TestBase.cpp @@ -1,4 +1,4 @@ -//===-- TestBase.cpp -------------------------------------------------===// +//===-- TestBase.cpp ------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. From lldb-commits at lists.llvm.org Wed May 14 13:15:43 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Wed, 14 May 2025 13:15:43 -0700 (PDT) Subject: [Lldb-commits] [lldb] Complete the Implementation of DAP modules explorer. (PR #139934) In-Reply-To: Message-ID: <6824f9ef.170a0220.18fbff.1998@mx.google.com> https://github.com/da-viper updated https://github.com/llvm/llvm-project/pull/139934 >From 7dbd5f7467cf1ab31caf935633062a7a66a49757 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Wed, 14 May 2025 17:32:47 +0100 Subject: [PATCH 1/4] [lldb][lldb-dap] clarify the todo. --- lldb/tools/lldb-dap/package.json | 14 +++ lldb/tools/lldb-dap/src-ts/extension.ts | 10 +- .../src-ts/ui/modules-data-provider.ts | 98 ++++++++++++------- 3 files changed, 85 insertions(+), 37 deletions(-) diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index e3e46526f379f..3c73534fd3180 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -244,6 +244,20 @@ } } ], + "commands": [ + { + "command": "lldb-dap.modules.copyProperty", + "title": "Copy Value" + } + ], + "menus": { + "view/item/context": [ + { + "command": "lldb-dap.modules.copyProperty", + "when": "view == lldb-dap.modules && viewItem == property" + } + ] + }, "breakpoints": [ { "language": "ada" diff --git a/lldb/tools/lldb-dap/src-ts/extension.ts b/lldb/tools/lldb-dap/src-ts/extension.ts index a5c0a09ae60cf..c8e5146e29cea 100644 --- a/lldb/tools/lldb-dap/src-ts/extension.ts +++ b/lldb/tools/lldb-dap/src-ts/extension.ts @@ -6,7 +6,10 @@ import { LaunchUriHandler } from "./uri-launch-handler"; import { LLDBDapConfigurationProvider } from "./debug-configuration-provider"; import { LLDBDapServer } from "./lldb-dap-server"; import { DebugSessionTracker } from "./debug-session-tracker"; -import { ModulesDataProvider } from "./ui/modules-data-provider"; +import { + ModulesDataProvider, + ModuleProperty, +} from "./ui/modules-data-provider"; /** * This class represents the extension and manages its life cycle. Other extensions @@ -40,6 +43,11 @@ export class LLDBDapExtension extends DisposableContext { ), vscode.window.registerUriHandler(new LaunchUriHandler()), ); + + vscode.commands.registerCommand( + "lldb-dap.modules.copyProperty", + (node: ModuleProperty) => vscode.env.clipboard.writeText(node.value), + ); } } diff --git a/lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts b/lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts index 478c162de8878..da527b04ba509 100644 --- a/lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts +++ b/lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts @@ -2,60 +2,86 @@ import * as vscode from "vscode"; import { DebugProtocol } from "@vscode/debugprotocol"; import { DebugSessionTracker } from "../debug-session-tracker"; -/** A tree data provider for listing loaded modules for the active debug session. */ -export class ModulesDataProvider - implements vscode.TreeDataProvider -{ - private changeTreeData = new vscode.EventEmitter(); - readonly onDidChangeTreeData = this.changeTreeData.event; +export interface ModuleProperty { + key: string; + value: string; +} - constructor(private readonly tracker: DebugSessionTracker) { - tracker.onDidChangeModules(() => this.changeTreeData.fire()); - vscode.debug.onDidChangeActiveDebugSession(() => - this.changeTreeData.fire(), - ); +/** Type to represent both Module and ModuleProperty since TreeDataProvider + * expects one concrete type */ +type TreeData = DebugProtocol.Module | ModuleProperty; + +function isModule(type: TreeData): type is DebugProtocol.Module { + return (type as DebugProtocol.Module).id !== undefined; +} + +class ModuleItem extends vscode.TreeItem { + constructor(module: DebugProtocol.Module) { + super(module.name, vscode.TreeItemCollapsibleState.Collapsed); + this.description = module.symbolStatus; } - getTreeItem(module: DebugProtocol.Module): vscode.TreeItem { - let treeItem = new vscode.TreeItem(/*label=*/ module.name); - if (module.path) { - treeItem.description = `${module.id} -- ${module.path}`; - } else { - treeItem.description = `${module.id}`; - } + static getProperties(module: DebugProtocol.Module): ModuleProperty[] { + // does not include the name and symbol status as it is show in the parent. + let children: ModuleProperty[] = []; + children.push({ key: "id:", value: module.id.toString() }); - const tooltip = new vscode.MarkdownString(); - tooltip.appendMarkdown(`# ${module.name}\n\n`); - tooltip.appendMarkdown(`- **ID**: ${module.id}\n`); if (module.addressRange) { - tooltip.appendMarkdown( - `- **Load address**: 0x${Number(module.addressRange).toString(16)}\n`, - ); + children.push({ + key: "load address:", + value: `0x${Number(module.addressRange).toString(16)}`, + }); } if (module.path) { - tooltip.appendMarkdown(`- **Path**: ${module.path}\n`); + children.push({ key: "path:", value: module.path }); } if (module.version) { - tooltip.appendMarkdown(`- **Version**: ${module.version}\n`); - } - if (module.symbolStatus) { - tooltip.appendMarkdown(`- **Symbol status**: ${module.symbolStatus}\n`); + children.push({ key: "version:", value: module.version }); } if (module.symbolFilePath) { - tooltip.appendMarkdown( - `- **Symbol file path**: ${module.symbolFilePath}\n`, - ); + children.push({ key: "symbol filepath:", value: module.symbolFilePath }); + } + return children; + } +} + +/** A tree data provider for listing loaded modules for the active debug session. */ +export class ModulesDataProvider implements vscode.TreeDataProvider { + private changeTreeData = new vscode.EventEmitter(); + readonly onDidChangeTreeData = this.changeTreeData.event; + + constructor(private readonly tracker: DebugSessionTracker) { + tracker.onDidChangeModules(() => this.changeTreeData.fire()); + vscode.debug.onDidChangeActiveDebugSession(() => + this.changeTreeData.fire(), + ); + } + + getTreeItem(module: TreeData): vscode.TreeItem { + if (isModule(module)) { + return new ModuleItem(module); } - treeItem.tooltip = tooltip; - return treeItem; + let item = new vscode.TreeItem(module.key); + item.description = module.value; + item.tooltip = `${module.key} ${module.value}`; + item.contextValue = "property"; + return item; } - getChildren(): DebugProtocol.Module[] { + getChildren(element?: TreeData): TreeData[] { if (!vscode.debug.activeDebugSession) { return []; } - return this.tracker.debugSessionModules(vscode.debug.activeDebugSession); + if (!element) { + return this.tracker.debugSessionModules(vscode.debug.activeDebugSession); + } + + if (isModule(element)) { + return ModuleItem.getProperties(element); + } + + return []; } } >From 3a5576d0e7380c434cdfdf64620f8b3a73c33bb5 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Wed, 14 May 2025 17:59:58 +0100 Subject: [PATCH 2/4] [lldb][lldb-dap] show load address in hex for all dap-clients. --- lldb/tools/lldb-dap/JSONUtils.cpp | 7 +++++-- lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 279e6d3d93814..31eb91f9f6b61 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -416,8 +416,11 @@ llvm::json::Value CreateModule(lldb::SBTarget &target, lldb::SBModule &module, } else { object.try_emplace("symbolStatus", "Symbols not found."); } - std::string loaded_addr = std::to_string( - module.GetObjectFileHeaderAddress().GetLoadAddress(target)); + std::string loaded_addr; + llvm::raw_string_ostream os_hex(loaded_addr); + os_hex << llvm::format_hex( + module.GetObjectFileHeaderAddress().GetLoadAddress(target), + sizeof(lldb::addr_t)); object.try_emplace("addressRange", loaded_addr); std::string version_str; uint32_t version_nums[3]; diff --git a/lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts b/lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts index da527b04ba509..091c1d69ac647 100644 --- a/lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts +++ b/lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts @@ -29,7 +29,7 @@ class ModuleItem extends vscode.TreeItem { if (module.addressRange) { children.push({ key: "load address:", - value: `0x${Number(module.addressRange).toString(16)}`, + value: module.addressRange, }); } if (module.path) { >From 5adba9bd7a078b28ac48a7c69633c7bdbbabe2e8 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Wed, 14 May 2025 20:01:02 +0100 Subject: [PATCH 3/4] [lldb][lldb-dap] add review changes. --- lldb/tools/lldb-dap/JSONUtils.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 31eb91f9f6b61..a8bd672583a5d 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -416,12 +416,11 @@ llvm::json::Value CreateModule(lldb::SBTarget &target, lldb::SBModule &module, } else { object.try_emplace("symbolStatus", "Symbols not found."); } - std::string loaded_addr; - llvm::raw_string_ostream os_hex(loaded_addr); - os_hex << llvm::format_hex( - module.GetObjectFileHeaderAddress().GetLoadAddress(target), - sizeof(lldb::addr_t)); - object.try_emplace("addressRange", loaded_addr); + std::string load_address = + llvm::formatv("{0:x}", + module.GetObjectFileHeaderAddress().GetLoadAddress(target)) + .str(); + object.try_emplace("addressRange", load_address); std::string version_str; uint32_t version_nums[3]; uint32_t num_versions = >From e155adb23d79938a2c609fc63081b6b9f45db8d0 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Wed, 14 May 2025 21:15:25 +0100 Subject: [PATCH 4/4] [lldb][lldb-dap] do not show copy context in the command palette --- lldb/tools/lldb-dap/package.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index 3c73534fd3180..d5ca604798799 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -251,6 +251,12 @@ } ], "menus": { + "commandPalette": [ + { + "command": "lldb-dap.modules.copyProperty", + "when": "false" + } + ], "view/item/context": [ { "command": "lldb-dap.modules.copyProperty", From lldb-commits at lists.llvm.org Wed May 14 13:18:50 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 13:18:50 -0700 (PDT) Subject: [Lldb-commits] [lldb] Complete the Implementation of DAP modules explorer. (PR #139934) In-Reply-To: Message-ID: <6824faaa.050a0220.2371d8.d9c6@mx.google.com> https://github.com/ashgti approved this pull request. https://github.com/llvm/llvm-project/pull/139934 From lldb-commits at lists.llvm.org Wed May 14 13:54:56 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 13:54:56 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <68250320.170a0220.e08d5.e98c@mx.google.com> https://github.com/JDevlieghere edited https://github.com/llvm/llvm-project/pull/139937 From lldb-commits at lists.llvm.org Wed May 14 13:54:56 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 13:54:56 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <68250320.170a0220.2bd230.138d@mx.google.com> https://github.com/JDevlieghere approved this pull request. I like the test base classes. https://github.com/llvm/llvm-project/pull/139937 From lldb-commits at lists.llvm.org Wed May 14 13:54:57 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 13:54:57 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <68250321.a70a0220.947f2.fff6@mx.google.com> ================ @@ -0,0 +1,70 @@ +//===-- TestBase.cpp ------------------------------------------------------===// +// +// 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 "TestBase.h" +#include "Protocol/ProtocolBase.h" +#include "lldb/Host/File.h" +#include "lldb/Host/Pipe.h" +#include "llvm/Testing/Support/Error.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap::protocol; +using namespace lldb_dap_tests; +using lldb_private::File; +using lldb_private::NativeFile; +using lldb_private::Pipe; + +void PipeBase::SetUp() { + ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); + ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); +} + +void TransportBase::SetUp() { + PipeBase::SetUp(); + to_dap = std::make_unique( + "to_dap", nullptr, + std::make_shared(input.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(output.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + from_dap = std::make_unique( + "from_dap", nullptr, + std::make_shared(output.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(input.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); +} + +void DAPTestBase::SetUp() { + TransportBase::SetUp(); + dap = std::make_unique( + /*log=*/nullptr, + /*default_repl_mode=*/ReplMode::Auto, + /*pre_init_commands=*/std::vector(), + /*transport=*/*to_dap); +} + +std::vector DAPTestBase::DrainOutput() { + std::vector msgs; + output.CloseWriteFileDescriptor(); + while (true) { + Expected next = from_dap->Read(std::chrono::milliseconds(1)); + if (!next) { + consumeError(next.takeError()); + break; + } + msgs.push_back(*next); + } + return msgs; +} ---------------- JDevlieghere wrote: newline https://github.com/llvm/llvm-project/pull/139937 From lldb-commits at lists.llvm.org Wed May 14 13:54:57 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 13:54:57 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <68250321.170a0220.37d80b.f53e@mx.google.com> ================ @@ -1,8 +1,11 @@ add_lldb_unittest(DAPTests + DAPTest.cpp + Handler/DisconnectRequestHandlerTest.cpp ---------------- JDevlieghere wrote: I somewhat regret the naming of the request handlers (*). Learning from our mistakes, maybe here we should just call it `Handler/DisconnectTest.cpp` to reduce the verbosity? (*) In hindsight, I wish I called them `RequestHandlerDisconnect` instead of `DisconnectRequestHandler`, though that doesn't apply here as all the unit test files end with `Test` and I think consistency is more important. https://github.com/llvm/llvm-project/pull/139937 From lldb-commits at lists.llvm.org Wed May 14 14:05:07 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 14:05:07 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <68250583.170a0220.234786.1c55@mx.google.com> https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/139937 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Wed May 14 14:05:16 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 14:05:16 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <6825058c.050a0220.60fde.458d@mx.google.com> ================ @@ -0,0 +1,70 @@ +//===-- TestBase.cpp ------------------------------------------------------===// +// +// 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 "TestBase.h" +#include "Protocol/ProtocolBase.h" +#include "lldb/Host/File.h" +#include "lldb/Host/Pipe.h" +#include "llvm/Testing/Support/Error.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap::protocol; +using namespace lldb_dap_tests; +using lldb_private::File; +using lldb_private::NativeFile; +using lldb_private::Pipe; + +void PipeBase::SetUp() { + ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); + ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); +} + +void TransportBase::SetUp() { + PipeBase::SetUp(); + to_dap = std::make_unique( + "to_dap", nullptr, + std::make_shared(input.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(output.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + from_dap = std::make_unique( + "from_dap", nullptr, + std::make_shared(output.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(input.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); +} + +void DAPTestBase::SetUp() { + TransportBase::SetUp(); + dap = std::make_unique( + /*log=*/nullptr, + /*default_repl_mode=*/ReplMode::Auto, + /*pre_init_commands=*/std::vector(), + /*transport=*/*to_dap); +} + +std::vector DAPTestBase::DrainOutput() { + std::vector msgs; + output.CloseWriteFileDescriptor(); + while (true) { + Expected next = from_dap->Read(std::chrono::milliseconds(1)); + if (!next) { + consumeError(next.takeError()); + break; + } + msgs.push_back(*next); + } + return msgs; +} ---------------- ashgti wrote: Done. https://github.com/llvm/llvm-project/pull/139937 From lldb-commits at lists.llvm.org Wed May 14 14:05:51 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 14:05:51 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <682505af.170a0220.3c883b.1949@mx.google.com> ================ @@ -1,8 +1,11 @@ add_lldb_unittest(DAPTests + DAPTest.cpp + Handler/DisconnectRequestHandlerTest.cpp ---------------- ashgti wrote: I renamed the file to `Handler/DisconnectTest.cpp` but should the test be `DisconnectTest` or should it be `DisconnectRequestHandlerTest` since thats the actual class I'm testing? https://github.com/llvm/llvm-project/pull/139937 From lldb-commits at lists.llvm.org Wed May 14 14:10:53 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 14:10:53 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <682506dd.170a0220.fe896.1731@mx.google.com> https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/139937 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Wed May 14 14:17:52 2025 From: lldb-commits at lists.llvm.org (Zequan Wu via lldb-commits) Date: Wed, 14 May 2025 14:17:52 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][Formatters] Add --pointer-match-depth option to `type summary add` command. (PR #138209) In-Reply-To: Message-ID: <68250880.170a0220.2d3ab9.2a6f@mx.google.com> ZequanWu wrote: Ping. https://github.com/llvm/llvm-project/pull/138209 From lldb-commits at lists.llvm.org Wed May 14 14:54:09 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Wed, 14 May 2025 14:54:09 -0700 (PDT) Subject: [Lldb-commits] [lldb] Lldb dap assembly breakpoint (PR #139969) Message-ID: https://github.com/eronnen created https://github.com/llvm/llvm-project/pull/139969 Enable breakpints from assembly sources Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Wed May 14 14:54:36 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Wed, 14 May 2025 14:54:36 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <6825111c.170a0220.2bc884.1b02@mx.google.com> https://github.com/eronnen edited https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Wed May 14 14:54:31 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Wed, 14 May 2025 14:54:31 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68251117.170a0220.39e87.04ac@mx.google.com> https://github.com/eronnen edited https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Wed May 14 14:57:06 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Wed, 14 May 2025 14:57:06 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <682511b2.170a0220.152f79.170a@mx.google.com> https://github.com/eronnen edited https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Wed May 14 15:00:38 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Wed, 14 May 2025 15:00:38 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <68251286.170a0220.fe896.1a3b@mx.google.com> ================ @@ -0,0 +1,35 @@ +//===-- DisconnectRequestHandlerTest.cpp ----------------------------------===// ---------------- JDevlieghere wrote: ```suggestion //===-- DisconnectTest.cpp ------------------------------------------------===// ``` https://github.com/llvm/llvm-project/pull/139937 From lldb-commits at lists.llvm.org Wed May 14 15:06:29 2025 From: lldb-commits at lists.llvm.org (Jason Molenda via lldb-commits) Date: Wed, 14 May 2025 15:06:29 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][NFC] Split RegisterContextUnwind::SavedLocationForRegister (PR #139817) In-Reply-To: Message-ID: <682513e5.170a0220.17c21c.1a08@mx.google.com> https://github.com/jasonmolenda updated https://github.com/llvm/llvm-project/pull/139817 >From e63e53adc0909f481a165eca958a3ac2ca4374ee Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 13 May 2025 17:11:08 -0700 Subject: [PATCH 1/7] [lldb][NFC] Split RegisterContextUnwind::SavedLocationForRegister RegisterContextUnwind::SavedLocationForRegister is around 450 lines that first find an abstract register location (e.g. "CFA-8") for a register by looking in the UnwindPlans. Then it evaluates the abstract register location to create a concrete register location (e.g. "stored at address 0x...", "live in register at frame 0"). There are some complicated cases in the first half of the method to handle return address register architectures correctly, in particular. Looking at the two halves, they're both exactly 226 lines long and there's little involvement between them except for passing an abstract register location along. (there were some parts in the "abstract register location" code that would set the concrete register location, unnecessarily) It's also a complex enough method that there are some bits of code that aren't actually doing anything at this point. This patch adds a RegisterContextUnwind::GetAbstractRegisterLocation method, which does the first half, and has a clearly defined return values. The code to convert an AbstractRegisterLocation into a ConcreteRegisterLocation remains in SavedLocationForRegister. It's a bit of a tricky patch to visually inspect, despite it not changing functionality, the reorganizations and rewrites make the diff unreadable. Nearly all the real changes are in the "find the abstract register location" first half of the method. I think reading the new code in its new form is the easiest way to inspect this PR. With a defined interface between the two of what is expected, it's pretty easy to look at the code and reason about whether it is written correctly. (whereas before, that was very difficult, for me at least.) --- .../lldb/Target/RegisterContextUnwind.h | 3 + lldb/source/Target/RegisterContextUnwind.cpp | 530 +++++++++--------- lldb/source/Target/RegisterNumber.cpp | 1 + 3 files changed, 259 insertions(+), 275 deletions(-) diff --git a/lldb/include/lldb/Target/RegisterContextUnwind.h b/lldb/include/lldb/Target/RegisterContextUnwind.h index 044a387fe5aa2..b10a364823b83 100644 --- a/lldb/include/lldb/Target/RegisterContextUnwind.h +++ b/lldb/include/lldb/Target/RegisterContextUnwind.h @@ -151,6 +151,9 @@ class RegisterContextUnwind : public lldb_private::RegisterContext { uint32_t lldb_regnum, lldb_private::UnwindLLDB::ConcreteRegisterLocation ®loc); + std::optional + GetAbstractRegisterLocation(uint32_t lldb_regnum, lldb::RegisterKind &kind); + bool ReadRegisterValueFromRegisterLocation( lldb_private::UnwindLLDB::ConcreteRegisterLocation regloc, const lldb_private::RegisterInfo *reg_info, diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index cf4b96c6eda9f..a3931abefb054 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1243,247 +1243,194 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( return false; } -// Answer the question: Where did THIS frame save the CALLER frame ("previous" -// frame)'s register value? - -enum UnwindLLDB::RegisterSearchResult -RegisterContextUnwind::SavedLocationForRegister( - uint32_t lldb_regnum, - lldb_private::UnwindLLDB::ConcreteRegisterLocation ®loc) { +// Search this stack frame's UnwindPlans for the AbstractRegisterLocation +// for this register. +// +// When an AbstractRegisterLocation is found in an UnwindPlan, that is +// returned, regardless of the ABI rules for volatile/non-volatile registers +// in effect. +// +// If there is no unwind rule for a volatile (caller-preserved) register +// the returned AbstractRegisterLocation will be IsUndefined, +// indicating that we should stop searching. +// +// If there is no unwind rule for a non-volatile (callee-preserved) +// register, the returned AbstractRegisterLocation will be IsSame. +// In frame 0, IsSame means get the value from the live register context. +// Else it means to continue descending down the stack to more-live frames +// looking for a location/value. +// +// An empty optional indicates that there was an error in processing. +std::optional +RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, + lldb::RegisterKind &kind) { RegisterNumber regnum(m_thread, eRegisterKindLLDB, lldb_regnum); Log *log = GetLog(LLDBLog::Unwind); - // Have we already found this register location? - if (!m_registers.empty()) { - std::map::const_iterator - iterator; - iterator = m_registers.find(regnum.GetAsKind(eRegisterKindLLDB)); - if (iterator != m_registers.end()) { - regloc = iterator->second; - UnwindLogMsg("supplying caller's saved %s (%d)'s location, cached", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } - } - - // Look through the available UnwindPlans for the register location. - UnwindPlan::Row::AbstractRegisterLocation unwindplan_regloc; - bool have_unwindplan_regloc = false; - RegisterKind unwindplan_registerkind = kNumRegisterKinds; + // First, try to find a register location via the FastUnwindPlan if (m_fast_unwind_plan_sp) { const UnwindPlan::Row *active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); - unwindplan_registerkind = m_fast_unwind_plan_sp->GetRegisterKind(); - if (regnum.GetAsKind(unwindplan_registerkind) == LLDB_INVALID_REGNUM) { + kind = m_fast_unwind_plan_sp->GetRegisterKind(); + if (regnum.GetAsKind(kind) == LLDB_INVALID_REGNUM) { UnwindLogMsg("could not convert lldb regnum %s (%d) into %d RegisterKind " "reg numbering scheme", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - (int)unwindplan_registerkind); - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; + (int)kind); + return {}; } // The architecture default unwind plan marks unknown registers as // Undefined so that we don't forward them up the stack when a // jitted stack frame may have overwritten them. But when the // arch default unwind plan is used as the Fast Unwind Plan, we // need to recognize this & switch over to the Full Unwind Plan - // to see what unwind rule that (more knoweldgeable, probably) - // UnwindPlan has. If the full UnwindPlan says the register - // location is Undefined, then it really is. - if (active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind), + // to see what unwind rule that (more knowledgeable, probably) + // UnwindPlan has. + if (active_row->GetRegisterInfo(regnum.GetAsKind(kind), unwindplan_regloc) && !unwindplan_regloc.IsUndefined()) { UnwindLogMsg( "supplying caller's saved %s (%d)'s location using FastUnwindPlan", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - have_unwindplan_regloc = true; + return unwindplan_regloc; } } - if (!have_unwindplan_regloc) { - // m_full_unwind_plan_sp being NULL means that we haven't tried to find a - // full UnwindPlan yet - bool got_new_full_unwindplan = false; - if (!m_full_unwind_plan_sp) { - m_full_unwind_plan_sp = GetFullUnwindPlanForFrame(); - got_new_full_unwindplan = true; - } + // Second, try to find a register location via the FullUnwindPlan. + bool got_new_full_unwindplan = false; + if (!m_full_unwind_plan_sp) { + m_full_unwind_plan_sp = GetFullUnwindPlanForFrame(); + got_new_full_unwindplan = true; + } + if (m_full_unwind_plan_sp) { + RegisterNumber pc_regnum(m_thread, eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_PC); - if (m_full_unwind_plan_sp) { - RegisterNumber pc_regnum(m_thread, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_PC); + const UnwindPlan::Row *active_row = + m_full_unwind_plan_sp->GetRowForFunctionOffset( + m_current_offset_backed_up_one); + kind = m_full_unwind_plan_sp->GetRegisterKind(); - const UnwindPlan::Row *active_row = - m_full_unwind_plan_sp->GetRowForFunctionOffset( - m_current_offset_backed_up_one); - unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind(); + if (got_new_full_unwindplan && active_row && log) { + StreamString active_row_strm; + ExecutionContext exe_ctx(m_thread.shared_from_this()); + active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, + m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); + UnwindLogMsg("Using full unwind plan '%s'", + m_full_unwind_plan_sp->GetSourceName().AsCString()); + UnwindLogMsg("active row: %s", active_row_strm.GetData()); + } - if (got_new_full_unwindplan && active_row && log) { - StreamString active_row_strm; - ExecutionContext exe_ctx(m_thread.shared_from_this()); - active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), - &m_thread, - m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); - UnwindLogMsg("Using full unwind plan '%s'", - m_full_unwind_plan_sp->GetSourceName().AsCString()); - UnwindLogMsg("active row: %s", active_row_strm.GetData()); + if (regnum.GetAsKind(kind) == LLDB_INVALID_REGNUM) { + if (kind == eRegisterKindGeneric) { + UnwindLogMsg("could not convert lldb regnum %s (%d) into " + "eRegisterKindGeneric reg numbering scheme", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + } else { + UnwindLogMsg("could not convert lldb regnum %s (%d) into %d " + "RegisterKind reg numbering scheme", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), + (int)kind); } + return {}; + } + + if (regnum.IsValid() && active_row && + active_row->GetRegisterInfo(regnum.GetAsKind(kind), + unwindplan_regloc)) { + UnwindLogMsg( + "supplying caller's saved %s (%d)'s location using %s UnwindPlan", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), + m_full_unwind_plan_sp->GetSourceName().GetCString()); + return unwindplan_regloc; + } + + // When asking for the caller's pc, check if we have a + // Return Address register on this target. + // + // On a Return Address Register architecture like arm/mips/riscv, + // the caller's pc is in the RA register, and will be spilled to + // stack before any other function can be called. We may have a + // register location saying + // pc=RAReg {caller's retrun addr is in RA register} + // ra=IsSame {caller's return addr is live in RA register} + // ra=StackAddr {caller's return addr spilled to stack} + // or none of the above, which means the caller's pc is live in the + // return address reg if this is frame 0, or the frame below is + // a trap/sigtramp/interrupt handler function. Any other mid-stack + // function must have an unwind rule for PC/RA giving a location/value. + // + // In the case of an interrupted function -- the function above sigtramp, + // or a function interrupted asynchronously, or that has faulted to + // a trap handler -- it is valid to ask both the "pc" value -- the + // instruction that was executing when the interrupt/fault happend -- + // and the RA Register value. If a frameless function (which doesn't + // create a stack frame, doesn't save the RA reg to stack) is interrupted, + // the trap handler will have a rule to provide the pc (the instruction + // that was executing) AND a rule to provide the RA Register, which we + // need to use to find the caller function: + // pc=StackAddr1 + // ra=StackAddr2 + // and we don't want to rewrite a request of "pc" to "ra" here, because + // they mean different things. + + if (pc_regnum.IsValid() && pc_regnum == regnum) { RegisterNumber return_address_reg; + uint32_t return_address_regnum = + LLDB_INVALID_REGNUM; // in full UnwindPlan's numbering + + // Get the return address register number from the UnwindPlan + // or the arch register set. + if (m_full_unwind_plan_sp->GetReturnAddressRegister() != + LLDB_INVALID_REGNUM) { + return_address_regnum = + m_full_unwind_plan_sp->GetReturnAddressRegister(); + } else { + RegisterNumber arch_default_ra_regnum(m_thread, eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_RA); + return_address_regnum = arch_default_ra_regnum.GetAsKind(kind); + } - // If we're fetching the saved pc and this UnwindPlan defines a - // ReturnAddress register (e.g. lr on arm), look for the return address - // register number in the UnwindPlan's row. - if (pc_regnum.IsValid() && pc_regnum == regnum && - m_full_unwind_plan_sp->GetReturnAddressRegister() != - LLDB_INVALID_REGNUM) { - // If this is a trap handler frame, we should have access to - // the complete register context when the interrupt/async - // signal was received, we should fetch the actual saved $pc - // value instead of the Return Address register. - // If $pc is not available, fall back to the RA reg. + if (return_address_regnum != LLDB_INVALID_REGNUM) { UnwindPlan::Row::AbstractRegisterLocation scratch; + // This is a sigtramp/interrupt handler - treat a + // request for "pc" and "ra" as distinct. if (m_frame_type == eTrapHandlerFrame && active_row && - active_row->GetRegisterInfo( - pc_regnum.GetAsKind(unwindplan_registerkind), scratch)) { + active_row->GetRegisterInfo(pc_regnum.GetAsKind(kind), scratch)) { UnwindLogMsg("Providing pc register instead of rewriting to " "RA reg because this is a trap handler and there is " "a location for the saved pc register value."); } else { - return_address_reg.init( - m_thread, m_full_unwind_plan_sp->GetRegisterKind(), - m_full_unwind_plan_sp->GetReturnAddressRegister()); + // This is a normal function, there's no rule for + // finding the caller's pc value, look for the caller's + // return address register value. + return_address_reg.init(m_thread, + m_full_unwind_plan_sp->GetRegisterKind(), + return_address_regnum); regnum = return_address_reg; UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a " "RA reg; getting %s (%d) instead", return_address_reg.GetName(), return_address_reg.GetAsKind(eRegisterKindLLDB)); - } - } else { - if (regnum.GetAsKind(unwindplan_registerkind) == LLDB_INVALID_REGNUM) { - if (unwindplan_registerkind == eRegisterKindGeneric) { - UnwindLogMsg("could not convert lldb regnum %s (%d) into " - "eRegisterKindGeneric reg numbering scheme", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - } else { - UnwindLogMsg("could not convert lldb regnum %s (%d) into %d " - "RegisterKind reg numbering scheme", + if (active_row && active_row->GetRegisterInfo(regnum.GetAsKind(kind), + unwindplan_regloc)) { + UnwindLogMsg("supplying caller's saved %s (%d)'s location using " + "%s UnwindPlan", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - (int)unwindplan_registerkind); - } - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - } - } - - // Check if the active_row has a register location listed. - if (regnum.IsValid() && active_row && - active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind), - unwindplan_regloc)) { - have_unwindplan_regloc = true; - UnwindLogMsg( - "supplying caller's saved %s (%d)'s location using %s UnwindPlan", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - m_full_unwind_plan_sp->GetSourceName().GetCString()); - } - - // This is frame 0 and we're retrieving the PC and it's saved in a Return - // Address register and it hasn't been saved anywhere yet -- that is, - // it's still live in the actual register. Handle this specially. - if (!have_unwindplan_regloc && return_address_reg.IsValid() && - return_address_reg.GetAsKind(eRegisterKindLLDB) != - LLDB_INVALID_REGNUM) { - if (IsFrameZero()) { - lldb_private::UnwindLLDB::ConcreteRegisterLocation new_regloc; - new_regloc.type = UnwindLLDB::ConcreteRegisterLocation:: - eRegisterInLiveRegisterContext; - new_regloc.location.register_number = - return_address_reg.GetAsKind(eRegisterKindLLDB); - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; - regloc = new_regloc; - UnwindLogMsg("supplying caller's register %s (%d) from the live " - "RegisterContext at frame 0, saved in %d", - return_address_reg.GetName(), - return_address_reg.GetAsKind(eRegisterKindLLDB), - return_address_reg.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } else if (BehavesLikeZerothFrame()) { - // This function was interrupted asynchronously -- it faulted, - // an async interrupt, a timer fired, a debugger expression etc. - // The caller's pc is in the Return Address register, but the - // UnwindPlan for this function may have no location rule for - // the RA reg. - // This means that the caller's return address is in the RA reg - // when the function was interrupted--descend down one stack frame - // to retrieve it from the trap handler's saved context. - unwindplan_regloc.SetSame(); - have_unwindplan_regloc = true; - } - } - - // If this architecture stores the return address in a register (it - // defines a Return Address register) and we're on a non-zero stack frame - // and the Full UnwindPlan says that the pc is stored in the - // RA registers (e.g. lr on arm), then we know that the full unwindplan is - // not trustworthy -- this - // is an impossible situation and the instruction emulation code has - // likely been misled. If this stack frame meets those criteria, we need - // to throw away the Full UnwindPlan that the instruction emulation came - // up with and fall back to the architecture's Default UnwindPlan so the - // stack walk can get past this point. - - // Special note: If the Full UnwindPlan was generated from the compiler, - // don't second-guess it when we're at a call site location. - - // arch_default_ra_regnum is the return address register # in the Full - // UnwindPlan register numbering - RegisterNumber arch_default_ra_regnum(m_thread, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_RA); - - if (arch_default_ra_regnum.GetAsKind(unwindplan_registerkind) != - LLDB_INVALID_REGNUM && - pc_regnum == regnum && unwindplan_regloc.IsInOtherRegister() && - unwindplan_regloc.GetRegisterNumber() == - arch_default_ra_regnum.GetAsKind(unwindplan_registerkind) && - m_full_unwind_plan_sp->GetSourcedFromCompiler() != eLazyBoolYes && - !m_all_registers_available) { - UnwindLogMsg("%s UnwindPlan tried to restore the pc from the link " - "register but this is a non-zero frame", - m_full_unwind_plan_sp->GetSourceName().GetCString()); - - // Throw away the full unwindplan; install the arch default unwindplan - if (ForceSwitchToFallbackUnwindPlan()) { - // Update for the possibly new unwind plan - unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind(); - const UnwindPlan::Row *active_row = - m_full_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); - - // Sanity check: Verify that we can fetch a pc value and CFA value - // with this unwind plan - - RegisterNumber arch_default_pc_reg(m_thread, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_PC); - bool can_fetch_pc_value = false; - bool can_fetch_cfa = false; - addr_t cfa_value; - if (active_row) { - if (arch_default_pc_reg.GetAsKind(unwindplan_registerkind) != - LLDB_INVALID_REGNUM && - active_row->GetRegisterInfo( - arch_default_pc_reg.GetAsKind(unwindplan_registerkind), - unwindplan_regloc)) { - can_fetch_pc_value = true; - } - if (ReadFrameAddress(unwindplan_registerkind, - active_row->GetCFAValue(), cfa_value)) { - can_fetch_cfa = true; + m_full_unwind_plan_sp->GetSourceName().GetCString()); + if (unwindplan_regloc.IsSame()) + unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + return unwindplan_regloc; + } else { + // No unwind rule for the return address reg on frame + // 0 means that the caller's address is still in RA reg. + if (BehavesLikeZerothFrame()) { + unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + return unwindplan_regloc; } } - - have_unwindplan_regloc = can_fetch_pc_value && can_fetch_cfa; - } else { - // We were unable to fall back to another unwind plan - have_unwindplan_regloc = false; } } } @@ -1491,55 +1438,84 @@ RegisterContextUnwind::SavedLocationForRegister( ExecutionContext exe_ctx(m_thread.shared_from_this()); Process *process = exe_ctx.GetProcessPtr(); - if (!have_unwindplan_regloc) { - // If the UnwindPlan failed to give us an unwind location for this - // register, we may be able to fall back to some ABI-defined default. For - // example, some ABIs allow to determine the caller's SP via the CFA. Also, - // the ABI may set volatile registers to the undefined state. - ABI *abi = process ? process->GetABI().get() : nullptr; - if (abi) { - const RegisterInfo *reg_info = - GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB)); - if (reg_info && - abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) { - UnwindLogMsg( - "supplying caller's saved %s (%d)'s location using ABI default", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - have_unwindplan_regloc = true; - } + + // Third, try finding a register location via the ABI + // FallbackRegisterLocation. + // + // If the UnwindPlan failed to give us an unwind location for this + // register, we may be able to fall back to some ABI-defined default. For + // example, some ABIs allow to determine the caller's SP via the CFA. Also, + // the ABI willset volatile registers to the undefined state. + ABI *abi = process ? process->GetABI().get() : nullptr; + if (abi) { + const RegisterInfo *reg_info = + GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB)); + if (reg_info && + abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) { + UnwindLogMsg( + "supplying caller's saved %s (%d)'s location using ABI default", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + return unwindplan_regloc; } } - if (!have_unwindplan_regloc) { - if (IsFrameZero()) { - // This is frame 0 - we should return the actual live register context - // value - lldb_private::UnwindLLDB::ConcreteRegisterLocation new_regloc; - new_regloc.type = - UnwindLLDB::ConcreteRegisterLocation::eRegisterInLiveRegisterContext; - new_regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; - regloc = new_regloc; - UnwindLogMsg("supplying caller's register %s (%d) from the live " - "RegisterContext at frame 0", + // We have no AbstractRegisterRule, and the ABI says this is a + // non-volatile / callee-preserved register. + std::string unwindplan_name; + if (m_full_unwind_plan_sp) { + unwindplan_name += "via '"; + unwindplan_name += m_full_unwind_plan_sp->GetSourceName().AsCString(); + unwindplan_name += "'"; + } + UnwindLogMsg("no save location for %s (%d) %s", regnum.GetName(), + regnum.GetAsKind(eRegisterKindLLDB), unwindplan_name.c_str()); + + unwindplan_regloc.SetSame(); + return unwindplan_regloc; +} + +// Answer the question: Where did THIS frame save the CALLER frame ("previous" +// frame)'s register value? + +enum UnwindLLDB::RegisterSearchResult +RegisterContextUnwind::SavedLocationForRegister( + uint32_t lldb_regnum, + lldb_private::UnwindLLDB::ConcreteRegisterLocation ®loc) { + RegisterNumber regnum(m_thread, eRegisterKindLLDB, lldb_regnum); + Log *log = GetLog(LLDBLog::Unwind); + + // Have we already found this register location? + if (!m_registers.empty()) { + std::map::const_iterator + iterator; + iterator = m_registers.find(regnum.GetAsKind(eRegisterKindLLDB)); + if (iterator != m_registers.end()) { + regloc = iterator->second; + UnwindLogMsg("supplying caller's saved %s (%d)'s location, cached", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } else { - std::string unwindplan_name; - if (m_full_unwind_plan_sp) { - unwindplan_name += "via '"; - unwindplan_name += m_full_unwind_plan_sp->GetSourceName().AsCString(); - unwindplan_name += "'"; - } - UnwindLogMsg("no save location for %s (%d) %s", regnum.GetName(), - regnum.GetAsKind(eRegisterKindLLDB), - unwindplan_name.c_str()); } + } + + RegisterKind abs_regkind; + std::optional abs_regloc = + GetAbstractRegisterLocation(lldb_regnum, abs_regkind); + + if (!abs_regloc) return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; + + if (abs_regloc->IsUndefined()) { + UnwindLogMsg( + "did not supply reg location for %s (%d) because it is volatile", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile; } - // unwindplan_regloc has valid contents about where to retrieve the register - if (unwindplan_regloc.IsUnspecified()) { + ExecutionContext exe_ctx(m_thread.shared_from_this()); + Process *process = exe_ctx.GetProcessPtr(); + // abs_regloc has valid contents about where to retrieve the register + if (abs_regloc->IsUnspecified()) { lldb_private::UnwindLLDB::ConcreteRegisterLocation new_regloc = {}; new_regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterNotSaved; m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; @@ -1548,15 +1524,23 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; } - if (unwindplan_regloc.IsUndefined()) { - UnwindLogMsg( - "did not supply reg location for %s (%d) because it is volatile", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile; - } - - if (unwindplan_regloc.IsSame()) { - if (!m_all_registers_available && + if (abs_regloc->IsSame()) { + if (IsFrameZero()) { + regloc.type = + UnwindLLDB::ConcreteRegisterLocation::eRegisterInLiveRegisterContext; + regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); + m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; + UnwindLogMsg("supplying caller's register %s (%d) from the live " + "RegisterContext at frame 0", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + return UnwindLLDB::RegisterSearchResult::eRegisterFound; + } + // PC/RA reg don't follow the usual "callee-saved aka non-volatile" versus + // "caller saved aka volatile" system. A stack frame can provide its caller + // return address, but if we don't find a rule for pc/RA mid-stack, we + // never want to iterate further down the stack looking for it. + // Defensively prevent iterating down the stack for these two. + if (!BehavesLikeZerothFrame() && (regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_PC || regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_RA)) { UnwindLogMsg("register %s (%d) is marked as 'IsSame' - it is a pc or " @@ -1564,20 +1548,19 @@ RegisterContextUnwind::SavedLocationForRegister( "registers available -- treat as if we have no information", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - } else { - regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterInRegister; - regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); - m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; - UnwindLogMsg( - "supplying caller's register %s (%d), saved in register %s (%d)", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; } + + regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterInRegister; + regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); + m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; + UnwindLogMsg( + "supplying caller's register %s (%d) value is unmodified in this frame", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsCFAPlusOffset()) { - int offset = unwindplan_regloc.GetOffset(); + if (abs_regloc->IsCFAPlusOffset()) { + int offset = abs_regloc->GetOffset(); regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred; regloc.location.inferred_value = m_cfa + offset; m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; @@ -1588,8 +1571,8 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsAtCFAPlusOffset()) { - int offset = unwindplan_regloc.GetOffset(); + if (abs_regloc->IsAtCFAPlusOffset()) { + int offset = abs_regloc->GetOffset(); regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterSavedAtMemoryLocation; regloc.location.target_memory_location = m_cfa + offset; @@ -1601,11 +1584,11 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsAFAPlusOffset()) { + if (abs_regloc->IsAFAPlusOffset()) { if (m_afa == LLDB_INVALID_ADDRESS) return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - int offset = unwindplan_regloc.GetOffset(); + int offset = abs_regloc->GetOffset(); regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred; regloc.location.inferred_value = m_afa + offset; m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; @@ -1616,11 +1599,11 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsAtAFAPlusOffset()) { + if (abs_regloc->IsAtAFAPlusOffset()) { if (m_afa == LLDB_INVALID_ADDRESS) return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - int offset = unwindplan_regloc.GetOffset(); + int offset = abs_regloc->GetOffset(); regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterSavedAtMemoryLocation; regloc.location.target_memory_location = m_afa + offset; @@ -1632,10 +1615,9 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsInOtherRegister()) { - uint32_t unwindplan_regnum = unwindplan_regloc.GetRegisterNumber(); - RegisterNumber row_regnum(m_thread, unwindplan_registerkind, - unwindplan_regnum); + if (abs_regloc->IsInOtherRegister()) { + RegisterNumber row_regnum(m_thread, abs_regkind, + abs_regloc->GetRegisterNumber()); if (row_regnum.GetAsKind(eRegisterKindLLDB) == LLDB_INVALID_REGNUM) { UnwindLogMsg("could not supply caller's %s (%d) location - was saved in " "another reg but couldn't convert that regnum", @@ -1652,16 +1634,14 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterFound; } - if (unwindplan_regloc.IsDWARFExpression() || - unwindplan_regloc.IsAtDWARFExpression()) { - DataExtractor dwarfdata(unwindplan_regloc.GetDWARFExpressionBytes(), - unwindplan_regloc.GetDWARFExpressionLength(), + if (abs_regloc->IsDWARFExpression() || abs_regloc->IsAtDWARFExpression()) { + DataExtractor dwarfdata(abs_regloc->GetDWARFExpressionBytes(), + abs_regloc->GetDWARFExpressionLength(), process->GetByteOrder(), process->GetAddressByteSize()); ModuleSP opcode_ctx; DWARFExpressionList dwarfexpr(opcode_ctx, dwarfdata, nullptr); - dwarfexpr.GetMutableExpressionAtAddress()->SetRegisterKind( - unwindplan_registerkind); + dwarfexpr.GetMutableExpressionAtAddress()->SetRegisterKind(abs_regkind); Value cfa_val = Scalar(m_cfa); cfa_val.SetValueType(Value::ValueType::LoadAddress); llvm::Expected result = @@ -1672,7 +1652,7 @@ RegisterContextUnwind::SavedLocationForRegister( } else { addr_t val; val = result->GetScalar().ULongLong(); - if (unwindplan_regloc.IsDWARFExpression()) { + if (abs_regloc->IsDWARFExpression()) { regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred; regloc.location.inferred_value = val; @@ -1698,9 +1678,9 @@ RegisterContextUnwind::SavedLocationForRegister( return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; } - if (unwindplan_regloc.IsConstant()) { + if (abs_regloc->IsConstant()) { regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred; - regloc.location.inferred_value = unwindplan_regloc.GetConstant(); + regloc.location.inferred_value = abs_regloc->GetConstant(); m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; UnwindLogMsg("supplying caller's register %s (%d) via constant value", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); diff --git a/lldb/source/Target/RegisterNumber.cpp b/lldb/source/Target/RegisterNumber.cpp index e5610bf588543..56dda8d8be8b8 100644 --- a/lldb/source/Target/RegisterNumber.cpp +++ b/lldb/source/Target/RegisterNumber.cpp @@ -47,6 +47,7 @@ const RegisterNumber &RegisterNumber::operator=(const RegisterNumber &rhs) { m_reg_ctx_sp = rhs.m_reg_ctx_sp; m_regnum = rhs.m_regnum; m_kind = rhs.m_kind; + m_kind_regnum_map.clear(); for (auto it : rhs.m_kind_regnum_map) m_kind_regnum_map[it.first] = it.second; m_name = rhs.m_name; >From c1aad81d5c5c7d2e9fce64f83197c05b827c6f22 Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 13 May 2025 17:37:42 -0700 Subject: [PATCH 2/7] Remove another bit of code in GetAbstractRegisterLocation that wasn't doing anything. --- lldb/source/Target/RegisterContextUnwind.cpp | 60 ++++++++------------ 1 file changed, 25 insertions(+), 35 deletions(-) diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index a3931abefb054..aae5de97de242 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1256,7 +1256,7 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( // // If there is no unwind rule for a non-volatile (callee-preserved) // register, the returned AbstractRegisterLocation will be IsSame. -// In frame 0, IsSame means get the value from the live register context. +// In frame 0, IsSame means get the value from the live register context. // Else it means to continue descending down the stack to more-live frames // looking for a location/value. // @@ -1394,42 +1394,32 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, } if (return_address_regnum != LLDB_INVALID_REGNUM) { - UnwindPlan::Row::AbstractRegisterLocation scratch; - // This is a sigtramp/interrupt handler - treat a - // request for "pc" and "ra" as distinct. - if (m_frame_type == eTrapHandlerFrame && active_row && - active_row->GetRegisterInfo(pc_regnum.GetAsKind(kind), scratch)) { - UnwindLogMsg("Providing pc register instead of rewriting to " - "RA reg because this is a trap handler and there is " - "a location for the saved pc register value."); + // This is a normal function, there's no rule for + // finding the caller's pc value, look for the caller's + // return address register value. + return_address_reg.init(m_thread, + m_full_unwind_plan_sp->GetRegisterKind(), + return_address_regnum); + regnum = return_address_reg; + UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a " + "RA reg; getting %s (%d) instead", + return_address_reg.GetName(), + return_address_reg.GetAsKind(eRegisterKindLLDB)); + if (active_row && active_row->GetRegisterInfo(regnum.GetAsKind(kind), + unwindplan_regloc)) { + UnwindLogMsg("supplying caller's saved %s (%d)'s location using " + "%s UnwindPlan", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), + m_full_unwind_plan_sp->GetSourceName().GetCString()); + if (unwindplan_regloc.IsSame()) + unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + return unwindplan_regloc; } else { - // This is a normal function, there's no rule for - // finding the caller's pc value, look for the caller's - // return address register value. - return_address_reg.init(m_thread, - m_full_unwind_plan_sp->GetRegisterKind(), - return_address_regnum); - regnum = return_address_reg; - UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a " - "RA reg; getting %s (%d) instead", - return_address_reg.GetName(), - return_address_reg.GetAsKind(eRegisterKindLLDB)); - if (active_row && active_row->GetRegisterInfo(regnum.GetAsKind(kind), - unwindplan_regloc)) { - UnwindLogMsg("supplying caller's saved %s (%d)'s location using " - "%s UnwindPlan", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), - m_full_unwind_plan_sp->GetSourceName().GetCString()); - if (unwindplan_regloc.IsSame()) - unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + // No unwind rule for the return address reg on frame + // 0 means that the caller's address is still in RA reg. + if (BehavesLikeZerothFrame()) { + unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); return unwindplan_regloc; - } else { - // No unwind rule for the return address reg on frame - // 0 means that the caller's address is still in RA reg. - if (BehavesLikeZerothFrame()) { - unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); - return unwindplan_regloc; - } } } } >From fde91220492202f7a8b56312cac5b7316975d69a Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 13 May 2025 17:41:45 -0700 Subject: [PATCH 3/7] Don't log a message when the ABI says this is a volatile register -- has an Undefined abstract register location. --- lldb/source/Target/RegisterContextUnwind.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index aae5de97de242..cf23df21f5044 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1441,7 +1441,8 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, const RegisterInfo *reg_info = GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB)); if (reg_info && - abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) { + abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc) && + !unwindplan_regloc.IsUndefined()) { UnwindLogMsg( "supplying caller's saved %s (%d)'s location using ABI default", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); >From 853da6655104080cb7022ca4e7f18ffae2e5df1b Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 13 May 2025 18:03:41 -0700 Subject: [PATCH 4/7] clarify comment. --- lldb/source/Target/RegisterContextUnwind.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index cf23df21f5044..64cb906f4d6c3 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1450,8 +1450,9 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, } } - // We have no AbstractRegisterRule, and the ABI says this is a - // non-volatile / callee-preserved register. + // We have no AbstractRegisterLocation, and the ABI says this is a + // non-volatile / callee-preserved register. Continue down the stack + // or to frame 0 & the live RegisterContext. std::string unwindplan_name; if (m_full_unwind_plan_sp) { unwindplan_name += "via '"; >From 1f40042126fb4941f365c6b0bb3f83961248695e Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 13 May 2025 22:02:17 -0700 Subject: [PATCH 5/7] make another pass over all the comments and rewrite/clarify a bunch of them. Tiny tweaks to the code to make it more readable. --- lldb/source/Target/RegisterContextUnwind.cpp | 143 ++++++++++--------- 1 file changed, 78 insertions(+), 65 deletions(-) diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index 64cb906f4d6c3..791671dc8e166 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1243,24 +1243,34 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( return false; } -// Search this stack frame's UnwindPlans for the AbstractRegisterLocation -// for this register. -// -// When an AbstractRegisterLocation is found in an UnwindPlan, that is -// returned, regardless of the ABI rules for volatile/non-volatile registers -// in effect. -// -// If there is no unwind rule for a volatile (caller-preserved) register -// the returned AbstractRegisterLocation will be IsUndefined, -// indicating that we should stop searching. -// -// If there is no unwind rule for a non-volatile (callee-preserved) -// register, the returned AbstractRegisterLocation will be IsSame. -// In frame 0, IsSame means get the value from the live register context. -// Else it means to continue descending down the stack to more-live frames -// looking for a location/value. -// -// An empty optional indicates that there was an error in processing. +/// Search this stack frame's UnwindPlans for the AbstractRegisterLocation +/// for this register. +/// +/// \param[out] kind +/// Set to the RegisterKind of the UnwindPlan which is the basis for +/// the returned AbstractRegisterLocation; if the location is in terms +/// of another register number, this Kind is needed to interpret it +/// correctly. +/// +/// \return +/// An empty optional indicaTes that there was an error in processing +/// the request. +/// +/// If there is no unwind rule for a volatile (caller-preserved) register, +/// the returned AbstractRegisterLocation will be IsUndefined, +/// indicating that we should stop searching. +/// +/// If there is no unwind rule for a non-volatile (callee-preserved) +/// register, the returned AbstractRegisterLocation will be IsSame. +/// In frame 0, IsSame means get the value from the live register context. +/// Else it means to continue descending down the stack to more-live frames +/// looking for a location/value. +/// +/// If an AbstractRegisterLocation is found in an UnwindPlan, that will +/// be returned, with no consideration of the current ABI rules for +/// registers. Functions using an alternate ABI calling convention +/// will work as long as the UnwindPlans are exhaustive about what +/// registers are volatile/non-volatile. std::optional RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, lldb::RegisterKind &kind) { @@ -1324,16 +1334,15 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, } if (regnum.GetAsKind(kind) == LLDB_INVALID_REGNUM) { - if (kind == eRegisterKindGeneric) { + if (kind == eRegisterKindGeneric) UnwindLogMsg("could not convert lldb regnum %s (%d) into " "eRegisterKindGeneric reg numbering scheme", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); - } else { + else UnwindLogMsg("could not convert lldb regnum %s (%d) into %d " "RegisterKind reg numbering scheme", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), (int)kind); - } return {}; } @@ -1347,42 +1356,37 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, return unwindplan_regloc; } - // When asking for the caller's pc, check if we have a + // When asking for the caller's pc, and did not find a register + // location for PC above in the UnwindPlan. Check if we have a // Return Address register on this target. // // On a Return Address Register architecture like arm/mips/riscv, // the caller's pc is in the RA register, and will be spilled to - // stack before any other function can be called. We may have a - // register location saying - // pc=RAReg {caller's retrun addr is in RA register} - // ra=IsSame {caller's return addr is live in RA register} - // ra=StackAddr {caller's return addr spilled to stack} - // or none of the above, which means the caller's pc is live in the - // return address reg if this is frame 0, or the frame below is - // a trap/sigtramp/interrupt handler function. Any other mid-stack - // function must have an unwind rule for PC/RA giving a location/value. + // stack before any other function is called. If no function + // has been called yet, the return address may still be in the + // live RA reg. // - // In the case of an interrupted function -- the function above sigtramp, - // or a function interrupted asynchronously, or that has faulted to - // a trap handler -- it is valid to ask both the "pc" value -- the - // instruction that was executing when the interrupt/fault happend -- - // and the RA Register value. If a frameless function (which doesn't - // create a stack frame, doesn't save the RA reg to stack) is interrupted, - // the trap handler will have a rule to provide the pc (the instruction - // that was executing) AND a rule to provide the RA Register, which we - // need to use to find the caller function: - // pc=StackAddr1 - // ra=StackAddr2 - // and we don't want to rewrite a request of "pc" to "ra" here, because - // they mean different things. - + // There's a lot of variety of what we might see in an UnwindPlan. + // We may have + // ra=IsSame {unncessary} + // ra=StackAddr {caller's return addr spilled to stack} + // or no unwindrule for pc or ra at all, in a frameless function - + // the caller's return address is in live ra reg. + // + // If a function has been interrupted in a non-call way -- + // async signal/sigtramp, or a hardware exception / interrupt / fault -- + // then the "pc" and "ra" are two distinct values, and must be + // handled separately. The "pc" is the pc value at the point + // the function was interrupted. The "ra" is the return address + // register value at that point. + // The UnwindPlan for the sigtramp/trap handler will normally have + // register loations for both pc and lr, and so we'll have already + // fetched them above. if (pc_regnum.IsValid() && pc_regnum == regnum) { - RegisterNumber return_address_reg; - uint32_t return_address_regnum = - LLDB_INVALID_REGNUM; // in full UnwindPlan's numbering + uint32_t return_address_regnum = LLDB_INVALID_REGNUM; // Get the return address register number from the UnwindPlan - // or the arch register set. + // or the register set definition. if (m_full_unwind_plan_sp->GetReturnAddressRegister() != LLDB_INVALID_REGNUM) { return_address_regnum = @@ -1393,32 +1397,38 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, return_address_regnum = arch_default_ra_regnum.GetAsKind(kind); } + // This system is using a return address register. if (return_address_regnum != LLDB_INVALID_REGNUM) { - // This is a normal function, there's no rule for - // finding the caller's pc value, look for the caller's - // return address register value. + RegisterNumber return_address_reg; return_address_reg.init(m_thread, m_full_unwind_plan_sp->GetRegisterKind(), return_address_regnum); - regnum = return_address_reg; UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a " "RA reg; getting %s (%d) instead", return_address_reg.GetName(), return_address_reg.GetAsKind(eRegisterKindLLDB)); - if (active_row && active_row->GetRegisterInfo(regnum.GetAsKind(kind), - unwindplan_regloc)) { + + // Do we have a location for the ra register? + if (active_row && + active_row->GetRegisterInfo(return_address_reg.GetAsKind(kind), + unwindplan_regloc)) { UnwindLogMsg("supplying caller's saved %s (%d)'s location using " "%s UnwindPlan", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), + return_address_reg.GetName(), + return_address_reg.GetAsKind(eRegisterKindLLDB), m_full_unwind_plan_sp->GetSourceName().GetCString()); + // If we have "ra=IsSame", rewrite to "ra=InRegister(ra)" because the + // calling function thinks it is fetching "pc" and if we return an + // IsSame register location, it will try to read pc. if (unwindplan_regloc.IsSame()) - unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + unwindplan_regloc.SetInRegister(return_address_reg.GetAsKind(kind)); return unwindplan_regloc; } else { - // No unwind rule for the return address reg on frame - // 0 means that the caller's address is still in RA reg. + // No unwind rule for the return address reg on frame 0, or an + // interrupted function, means that the caller's address is still in + // RA reg. if (BehavesLikeZerothFrame()) { - unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind)); + unwindplan_regloc.SetInRegister(return_address_reg.GetAsKind(kind)); return unwindplan_regloc; } } @@ -1441,11 +1451,14 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, const RegisterInfo *reg_info = GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB)); if (reg_info && - abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc) && - !unwindplan_regloc.IsUndefined()) { - UnwindLogMsg( - "supplying caller's saved %s (%d)'s location using ABI default", - regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) { + if (!unwindplan_regloc.IsUndefined()) + UnwindLogMsg( + "supplying caller's saved %s (%d)'s location using ABI default", + regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); + // ABI defined volatile registers with no register location + // will be returned as IsUndefined, stopping the search down + // the stack. return unwindplan_regloc; } } >From 967f99d89f874be9e89fd3de37c8ca2fc88e3fa3 Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 13 May 2025 22:18:09 -0700 Subject: [PATCH 6/7] tiny edit --- lldb/source/Target/RegisterContextUnwind.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index 791671dc8e166..97fefd8d09d69 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1370,7 +1370,7 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, // We may have // ra=IsSame {unncessary} // ra=StackAddr {caller's return addr spilled to stack} - // or no unwindrule for pc or ra at all, in a frameless function - + // or no reg location for pc or ra at all, in a frameless function - // the caller's return address is in live ra reg. // // If a function has been interrupted in a non-call way -- @@ -1426,7 +1426,8 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, } else { // No unwind rule for the return address reg on frame 0, or an // interrupted function, means that the caller's address is still in - // RA reg. + // RA reg (0th frame) or the trap handler below this one (sigtramp + // etc) has a save location for the RA reg. if (BehavesLikeZerothFrame()) { unwindplan_regloc.SetInRegister(return_address_reg.GetAsKind(kind)); return unwindplan_regloc; >From eb6d7420bf61360b38cf75f0e8367066cc1487c9 Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Wed, 14 May 2025 15:06:19 -0700 Subject: [PATCH 7/7] Update lldb/source/Target/RegisterContextUnwind.cpp Co-authored-by: Pavel Labath --- lldb/source/Target/RegisterContextUnwind.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index 97fefd8d09d69..76f59d7c3dbc9 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1492,10 +1492,7 @@ RegisterContextUnwind::SavedLocationForRegister( // Have we already found this register location? if (!m_registers.empty()) { - std::map::const_iterator - iterator; - iterator = m_registers.find(regnum.GetAsKind(eRegisterKindLLDB)); + auto iterator = m_registers.find(regnum.GetAsKind(eRegisterKindLLDB)); if (iterator != m_registers.end()) { regloc = iterator->second; UnwindLogMsg("supplying caller's saved %s (%d)'s location, cached", From lldb-commits at lists.llvm.org Wed May 14 15:38:34 2025 From: lldb-commits at lists.llvm.org (Jason Molenda via lldb-commits) Date: Wed, 14 May 2025 15:38:34 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][NFC] Split RegisterContextUnwind::SavedLocationForRegister (PR #139817) In-Reply-To: Message-ID: <68251b6a.050a0220.1747f5.08bf@mx.google.com> https://github.com/jasonmolenda updated https://github.com/llvm/llvm-project/pull/139817 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Wed May 14 15:58:07 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Wed, 14 May 2025 15:58:07 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <68251fff.050a0220.4ea4a.0b62@mx.google.com> https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/139937 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Wed May 14 16:08:20 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 16:08:20 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][Formatters] Add --pointer-match-depth option to `type summary add` command. (PR #138209) In-Reply-To: Message-ID: <68252264.170a0220.c19ce.1de0@mx.google.com> ================ @@ -366,6 +366,16 @@ The command to obtain the output shown in the example is: Initially, we will focus on summary strings, and then describe the Python binding mechanism. +Summary Format Matching On Pointers +---------------------- + +When a summary format is registered for a type ``T``, lldb will apply this +format to both ``T`` and ``T*``. -p options could prevent lldb from using this ---------------- jimingham wrote: This is a little unclear on the relationship between `-p` and `-d` and why you would use one over the other. How about something like: A summary formatter for a type ``T`` might or might not be appropriate to use for pointers to that type. If the formatter is only appropriate for the type and not its pointers, use the `-p` option to restrict it to just that type. If you want the formatter to also match pointers to the type, you can use the `-d` option to specify how many pointer layers the formatter should match. The default value is 1, so if you don't specify `-p` or `-d`, your formatter will be used on SBValues of type ``T`` and ``T*``. If you want to also match ``T**`` set `-d` to 2, etc. In all cases, the SBValue passed to the summary formatter will be the matched ValueObject. lldb doesn't dereference the matched value down to the SBValue of type ``T`` before passing it to your formatter. https://github.com/llvm/llvm-project/pull/138209 From lldb-commits at lists.llvm.org Wed May 14 16:09:34 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 16:09:34 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][Formatters] Add --pointer-match-depth option to `type summary add` command. (PR #138209) In-Reply-To: Message-ID: <682522ae.170a0220.21e2c5.17ac@mx.google.com> https://github.com/jimingham edited https://github.com/llvm/llvm-project/pull/138209 From lldb-commits at lists.llvm.org Wed May 14 23:42:48 2025 From: lldb-commits at lists.llvm.org (Kazu Hirata via lldb-commits) Date: Wed, 14 May 2025 23:42:48 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use std::optional::value_of (NFC) (PR #140011) Message-ID: https://github.com/kazutakahirata created https://github.com/llvm/llvm-project/pull/140011 None >From cb827a2d99f3d700378ddbe4064b60281c5ef85e Mon Sep 17 00:00:00 2001 From: Kazu Hirata Date: Wed, 14 May 2025 23:29:42 -0700 Subject: [PATCH] [lldb] Use std::optional::value_of (NFC) --- .../Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp | 4 ++-- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index a3e809f44ed23..e3a866e2b6d48 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -2479,8 +2479,8 @@ Function *DWARFASTParserClang::ParseFunctionFromDWARF( std::unique_ptr decl_up; if (decl_file || decl_line || decl_column) decl_up = std::make_unique( - die.GetCU()->GetFile(decl_file ? *decl_file : 0), - decl_line ? *decl_line : 0, decl_column ? *decl_column : 0); + die.GetCU()->GetFile(decl_file.value_or(0)), decl_line.value_or(0), + decl_column.value_or(0)); SymbolFileDWARF *dwarf = die.GetDWARF(); // Supply the type _only_ if it has already been parsed diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 907d63eb51afe..0fc7f79be70ec 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1358,15 +1358,15 @@ size_t SymbolFileDWARF::ParseBlocksRecursive(CompileUnit &comp_unit, if (decl_file || decl_line || decl_column) decl_up = std::make_unique( comp_unit.GetSupportFiles().GetFileSpecAtIndex( - decl_file ? *decl_file : 0), - decl_line ? *decl_line : 0, decl_column ? *decl_column : 0); + decl_file.value_or(0)), + decl_line.value_or(0), decl_column.value_or(0)); std::unique_ptr call_up; if (call_file || call_line || call_column) call_up = std::make_unique( comp_unit.GetSupportFiles().GetFileSpecAtIndex( - call_file ? *call_file : 0), - call_line ? *call_line : 0, call_column ? *call_column : 0); + call_file.value_or(0)), + call_line.value_or(0), call_column.value_or(0)); block->SetInlinedFunctionInfo(name, mangled_name, decl_up.get(), call_up.get()); From lldb-commits at lists.llvm.org Wed May 14 23:43:19 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Wed, 14 May 2025 23:43:19 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use std::optional::value_of (NFC) (PR #140011) In-Reply-To: Message-ID: <68258d07.170a0220.373d0.2f58@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Kazu Hirata (kazutakahirata)
Changes --- Full diff: https://github.com/llvm/llvm-project/pull/140011.diff 2 Files Affected: - (modified) lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp (+2-2) - (modified) lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp (+4-4) ``````````diff diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index a3e809f44ed23..e3a866e2b6d48 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -2479,8 +2479,8 @@ Function *DWARFASTParserClang::ParseFunctionFromDWARF( std::unique_ptr decl_up; if (decl_file || decl_line || decl_column) decl_up = std::make_unique( - die.GetCU()->GetFile(decl_file ? *decl_file : 0), - decl_line ? *decl_line : 0, decl_column ? *decl_column : 0); + die.GetCU()->GetFile(decl_file.value_or(0)), decl_line.value_or(0), + decl_column.value_or(0)); SymbolFileDWARF *dwarf = die.GetDWARF(); // Supply the type _only_ if it has already been parsed diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 907d63eb51afe..0fc7f79be70ec 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1358,15 +1358,15 @@ size_t SymbolFileDWARF::ParseBlocksRecursive(CompileUnit &comp_unit, if (decl_file || decl_line || decl_column) decl_up = std::make_unique( comp_unit.GetSupportFiles().GetFileSpecAtIndex( - decl_file ? *decl_file : 0), - decl_line ? *decl_line : 0, decl_column ? *decl_column : 0); + decl_file.value_or(0)), + decl_line.value_or(0), decl_column.value_or(0)); std::unique_ptr call_up; if (call_file || call_line || call_column) call_up = std::make_unique( comp_unit.GetSupportFiles().GetFileSpecAtIndex( - call_file ? *call_file : 0), - call_line ? *call_line : 0, call_column ? *call_column : 0); + call_file.value_or(0)), + call_line.value_or(0), call_column.value_or(0)); block->SetInlinedFunctionInfo(name, mangled_name, decl_up.get(), call_up.get()); ``````````
https://github.com/llvm/llvm-project/pull/140011 From lldb-commits at lists.llvm.org Wed May 14 23:52:13 2025 From: lldb-commits at lists.llvm.org (Kazu Hirata via lldb-commits) Date: Wed, 14 May 2025 23:52:13 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use std::optional::value_or (NFC) (PR #140011) In-Reply-To: Message-ID: <68258f1d.620a0220.39027e.586a@mx.google.com> https://github.com/kazutakahirata edited https://github.com/llvm/llvm-project/pull/140011 From lldb-commits at lists.llvm.org Thu May 15 00:11:41 2025 From: lldb-commits at lists.llvm.org (Alex Langford via lldb-commits) Date: Thu, 15 May 2025 00:11:41 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use std::optional::value_or (NFC) (PR #140011) In-Reply-To: Message-ID: <682593ad.050a0220.1cedd.2f1f@mx.google.com> https://github.com/bulbazord approved this pull request. https://github.com/llvm/llvm-project/pull/140011 From lldb-commits at lists.llvm.org Thu May 15 00:20:37 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 00:20:37 -0700 (PDT) Subject: [Lldb-commits] [lldb] Extending LLDB to work on AIX (PR #102601) In-Reply-To: Message-ID: <682595c5.170a0220.1f9df.1fe9@mx.google.com> https://github.com/ravindra-shinde2 updated https://github.com/llvm/llvm-project/pull/102601 >From 39d395f75c306a0d932a783eef039fd93d66e246 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 7 Aug 2024 12:10:43 -0500 Subject: [PATCH 01/48] LLDB Support for AIX --- clang/lib/CodeGen/CGObjCMac.cpp | 6 +- lldb/CMakeLists.txt | 4 + lldb/cmake/modules/LLDBConfig.cmake | 2 +- lldb/include/lldb/Core/Module.h | 3 + lldb/include/lldb/Core/ModuleSpec.h | 23 +- lldb/include/lldb/Host/HostGetOpt.h | 2 +- lldb/include/lldb/Host/HostInfo.h | 3 + lldb/include/lldb/Host/HostInfoBase.h | 2 +- lldb/include/lldb/Host/XML.h | 5 + lldb/include/lldb/Host/aix/AbstractSocket.h | 25 + lldb/include/lldb/Host/aix/Host.h | 22 + lldb/include/lldb/Host/aix/HostInfoAIX.h | 42 + lldb/include/lldb/Host/aix/Ptrace.h | 62 + lldb/include/lldb/Host/aix/Support.h | 29 + lldb/include/lldb/Host/aix/Uio.h | 23 + lldb/include/lldb/Host/common/GetOptInc.h | 6 +- lldb/include/lldb/Symbol/ObjectFile.h | 5 + lldb/include/lldb/Target/ABI.h | 6 + lldb/include/lldb/Target/DynamicLoader.h | 6 + lldb/include/lldb/Target/Process.h | 14 + .../lldb/Target/RegisterContextUnwind.h | 4 + .../lldb/Target/ThreadPlanCallFunction.h | 6 + .../lldb/Utility/StringExtractorGDBRemote.h | 1 + lldb/include/lldb/lldb-private-enumerations.h | 1 + lldb/source/API/CMakeLists.txt | 108 + lldb/source/API/SBBreakpoint.cpp | 6 +- lldb/source/API/SBBreakpointLocation.cpp | 6 +- lldb/source/API/SBBreakpointName.cpp | 4 +- lldb/source/Core/DynamicLoader.cpp | 10 + lldb/source/Core/Mangled.cpp | 2 + lldb/source/Core/Module.cpp | 12 + lldb/source/Core/Section.cpp | 4 + lldb/source/Expression/DWARFExpression.cpp | 10 +- lldb/source/Host/CMakeLists.txt | 13 + lldb/source/Host/aix/AbstractSocket.cpp | 21 + lldb/source/Host/aix/Host.cpp | 304 +++ lldb/source/Host/aix/HostInfoAIX.cpp | 215 ++ lldb/source/Host/aix/Support.cpp | 44 + lldb/source/Host/common/GetOptInc.cpp | 2 +- lldb/source/Host/common/Host.cpp | 180 +- .../source/Host/common/LICENSE.aix-netbsd.txt | 125 + lldb/source/Host/common/XML.cpp | 3 + .../posix/ConnectionFileDescriptorPosix.cpp | 2 + lldb/source/Host/posix/FileSystemPosix.cpp | 2 + lldb/source/Host/posix/MainLoopPosix.cpp | 17 + .../Host/posix/ProcessLauncherPosixFork.cpp | 5 + lldb/source/Initialization/CMakeLists.txt | 2 +- .../SystemInitializerCommon.cpp | 4 +- .../Plugins/ABI/PowerPC/ABISysV_ppc64.cpp | 131 +- .../Plugins/ABI/PowerPC/ABISysV_ppc64.h | 6 + .../DynamicLoader/AIX-DYLD/CMakeLists.txt | 11 + .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 272 +++ .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 55 + .../Plugins/DynamicLoader/CMakeLists.txt | 1 + .../DynamicLoaderDarwinKernel.cpp | 4 +- .../MacOSX-DYLD/DynamicLoaderDarwin.cpp | 2 +- .../PPC64/EmulateInstructionPPC64.cpp | 196 +- .../PPC64/EmulateInstructionPPC64.h | 14 + ...nstrumentationRuntimeMainThreadChecker.cpp | 2 +- .../TSan/InstrumentationRuntimeTSan.cpp | 14 +- .../UBSan/InstrumentationRuntimeUBSan.cpp | 2 +- .../Plugins/JITLoader/GDB/JITLoaderGDB.cpp | 4 + lldb/source/Plugins/Language/ObjC/Cocoa.cpp | 2 + .../MemoryHistory/asan/MemoryHistoryASan.cpp | 2 +- .../BSD-Archive/ObjectContainerBSDArchive.cpp | 2 +- .../Big-Archive/CMakeLists.txt | 10 + .../Big-Archive/ObjectContainerBigArchive.cpp | 522 +++++ .../Big-Archive/ObjectContainerBigArchive.h | 177 ++ .../Plugins/ObjectContainer/CMakeLists.txt | 1 + lldb/source/Plugins/ObjectFile/CMakeLists.txt | 1 + .../ObjectFile/Mach-O/ObjectFileMachO.cpp | 6 +- .../Minidump/ObjectFileMinidump.cpp | 2 + .../Plugins/ObjectFile/PDB/ObjectFilePDB.cpp | 15 +- .../ObjectFile/PECOFF/ObjectFilePECOFF.cpp | 18 +- .../Plugins/ObjectFile/XCOFF/CMakeLists.txt | 13 + .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 780 +++++++ .../ObjectFile/XCOFF/ObjectFileXCOFF.h | 243 ++ .../Python/OperatingSystemPython.cpp | 2 +- .../Plugins/Platform/AIX/CMakeLists.txt | 13 + .../Plugins/Platform/AIX/PlatformAIX.cpp | 471 ++++ .../source/Plugins/Platform/AIX/PlatformAIX.h | 74 + lldb/source/Plugins/Platform/CMakeLists.txt | 1 + .../source/Plugins/Process/AIX/CMakeLists.txt | 19 + .../Plugins/Process/AIX/NativeProcessAIX.cpp | 2048 +++++++++++++++++ .../Plugins/Process/AIX/NativeProcessAIX.h | 283 +++ .../Process/AIX/NativeRegisterContextAIX.cpp | 157 ++ .../Process/AIX/NativeRegisterContextAIX.h | 133 ++ .../AIX/NativeRegisterContextAIX_ppc64.cpp | 744 ++++++ .../AIX/NativeRegisterContextAIX_ppc64.h | 138 ++ .../Plugins/Process/AIX/NativeThreadAIX.cpp | 526 +++++ .../Plugins/Process/AIX/NativeThreadAIX.h | 126 + lldb/source/Plugins/Process/CMakeLists.txt | 3 + .../Process/Utility/InferiorCallPOSIX.cpp | 33 + .../Utility/RegisterInfoPOSIX_ppc64le.cpp | 4 + .../Plugins/Process/Utility/ThreadMemory.cpp | 2 +- .../Plugins/Process/gdb-remote/CMakeLists.txt | 5 + .../GDBRemoteCommunicationClient.cpp | 30 + .../gdb-remote/GDBRemoteCommunicationClient.h | 7 + .../GDBRemoteCommunicationServerLLGS.cpp | 28 + .../GDBRemoteCommunicationServerLLGS.h | 2 + .../Process/gdb-remote/ProcessGDBRemote.cpp | 13 +- .../Process/gdb-remote/ProcessGDBRemote.h | 8 + .../Process/mach-core/ProcessMachCore.cpp | 8 +- .../ScriptInterpreter/Python/CMakeLists.txt | 5 + .../SymbolFile/DWARF/DWARFFormValue.cpp | 4 + .../Plugins/SymbolFile/DWARF/DWARFUnit.cpp | 12 +- .../MacOSX/AppleGetThreadItemInfoHandler.cpp | 2 +- lldb/source/Symbol/DWARFCallFrameInfo.cpp | 4 +- lldb/source/Target/ABI.cpp | 9 + lldb/source/Target/CMakeLists.txt | 5 + lldb/source/Target/Process.cpp | 10 + lldb/source/Target/RegisterContextUnwind.cpp | 46 + lldb/source/Target/ThreadPlanCallFunction.cpp | 34 + lldb/source/Target/UnwindLLDB.cpp | 15 + lldb/source/Utility/ArchSpec.cpp | 18 +- .../Utility/StringExtractorGDBRemote.cpp | 2 + lldb/test/CMakeLists.txt | 2 +- lldb/test/Shell/Expr/TestIRMemoryMap.test | 2 +- lldb/test/Shell/Process/TestEnvironment.test | 2 +- lldb/tools/driver/CMakeLists.txt | 5 + lldb/tools/driver/Driver.cpp | 5 +- lldb/tools/lldb-dap/CMakeLists.txt | 4 + lldb/tools/lldb-server/CMakeLists.txt | 7 + .../lldb-server/SystemInitializerLLGS.cpp | 15 + lldb/tools/lldb-server/lldb-gdbserver.cpp | 4 + lldb/unittests/Host/FileSystemTest.cpp | 2 +- lldb/unittests/Host/posix/TerminalTest.cpp | 4 + llvm/include/llvm/Object/XCOFFObjectFile.h | 4 +- llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 15 +- 129 files changed, 8950 insertions(+), 76 deletions(-) create mode 100644 lldb/include/lldb/Host/aix/AbstractSocket.h create mode 100644 lldb/include/lldb/Host/aix/Host.h create mode 100644 lldb/include/lldb/Host/aix/HostInfoAIX.h create mode 100644 lldb/include/lldb/Host/aix/Ptrace.h create mode 100644 lldb/include/lldb/Host/aix/Support.h create mode 100644 lldb/include/lldb/Host/aix/Uio.h create mode 100644 lldb/source/Host/aix/AbstractSocket.cpp create mode 100644 lldb/source/Host/aix/Host.cpp create mode 100644 lldb/source/Host/aix/HostInfoAIX.cpp create mode 100644 lldb/source/Host/aix/Support.cpp create mode 100644 lldb/source/Host/common/LICENSE.aix-netbsd.txt create mode 100644 lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt create mode 100644 lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp create mode 100644 lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h create mode 100644 lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt create mode 100644 lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp create mode 100644 lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h create mode 100644 lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt create mode 100644 lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp create mode 100644 lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h create mode 100644 lldb/source/Plugins/Platform/AIX/CMakeLists.txt create mode 100644 lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp create mode 100644 lldb/source/Plugins/Platform/AIX/PlatformAIX.h create mode 100644 lldb/source/Plugins/Process/AIX/CMakeLists.txt create mode 100644 lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeProcessAIX.h create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h create mode 100644 lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeThreadAIX.h diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index 30f3911a8b03c..fc91981db68c1 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -5052,10 +5052,14 @@ std::string CGObjCCommonMac::GetSectionName(StringRef Section, case llvm::Triple::COFF: assert(Section.starts_with("__") && "expected the name to begin with __"); return ("." + Section.substr(2) + "$B").str(); + case llvm::Triple::XCOFF: + // Hack to allow "p 10+1" on AIX for lldb + assert(Section.substr(0, 2) == "__" && + "expected the name to begin with __"); + return Section.substr(2).str(); case llvm::Triple::Wasm: case llvm::Triple::GOFF: case llvm::Triple::SPIRV: - case llvm::Triple::XCOFF: case llvm::Triple::DXContainer: llvm::report_fatal_error( "Objective-C support is unimplemented for object file format"); diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt index 59cdc4593463c..2e9ae0d0b3221 100644 --- a/lldb/CMakeLists.txt +++ b/lldb/CMakeLists.txt @@ -38,6 +38,10 @@ endif() include(LLDBConfig) include(AddLLDB) +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + add_definitions("-D__AIX__") +endif() + # Define the LLDB_CONFIGURATION_xxx matching the build type. if(uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" ) add_definitions(-DLLDB_CONFIGURATION_DEBUG) diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake index a60921990cf77..a0f118a11984c 100644 --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -299,7 +299,7 @@ endif() # Figure out if lldb could use lldb-server. If so, then we'll # ensure we build lldb-server when an lldb target is being built. -if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD|Windows") +if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD|Windows|AIX") set(LLDB_CAN_USE_LLDB_SERVER ON) else() set(LLDB_CAN_USE_LLDB_SERVER OFF) diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 5589c1c9a350d..3829386562795 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -196,6 +196,9 @@ class Module : public std::enable_shared_from_this, bool SetLoadAddress(Target &target, lldb::addr_t value, bool value_is_offset, bool &changed); + bool SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, bool &changed, int type_id); + /// \copydoc SymbolContextScope::CalculateSymbolContext(SymbolContext*) /// /// \see SymbolContextScope diff --git a/lldb/include/lldb/Core/ModuleSpec.h b/lldb/include/lldb/Core/ModuleSpec.h index 4cbbbfa8a26e1..4fe06412b6b0b 100644 --- a/lldb/include/lldb/Core/ModuleSpec.h +++ b/lldb/include/lldb/Core/ModuleSpec.h @@ -21,6 +21,7 @@ #include #include +#include namespace lldb_private { @@ -41,8 +42,26 @@ class ModuleSpec { } ModuleSpec(const FileSpec &file_spec, const ArchSpec &arch) - : m_file(file_spec), m_arch(arch), m_object_offset(0), - m_object_size(FileSystem::Instance().GetByteSize(file_spec)) {} + : m_arch(arch), m_object_offset(0) { + // parse object inside module format for example: /usr/ccs/lib/libc.a(shr_64.o) + llvm::SmallString<256> path_with_object; + file_spec.GetPath(path_with_object); + if (strstr(path_with_object.c_str(), "(") != nullptr) { + char *part; + char *str = (char *)path_with_object.c_str(); + part = strtok(str, "()"); + assert(part); + llvm::StringRef file_name(part); + part = strtok(nullptr, "()"); + assert(part); + m_object_name = ConstString(part); + m_file = FileSpec(file_name); + m_object_size = FileSystem::Instance().GetByteSize(m_file); + } else { + m_file = file_spec; + m_object_size = FileSystem::Instance().GetByteSize(file_spec); + } + } FileSpec *GetFileSpecPtr() { return (m_file ? &m_file : nullptr); } diff --git a/lldb/include/lldb/Host/HostGetOpt.h b/lldb/include/lldb/Host/HostGetOpt.h index 52cfdf4dbb89c..f450e561d6afb 100644 --- a/lldb/include/lldb/Host/HostGetOpt.h +++ b/lldb/include/lldb/Host/HostGetOpt.h @@ -9,7 +9,7 @@ #ifndef LLDB_HOST_HOSTGETOPT_H #define LLDB_HOST_HOSTGETOPT_H -#if !defined(_MSC_VER) && !defined(__NetBSD__) +#if !defined(_MSC_VER) && !defined(__NetBSD__) && !defined(__AIX__) #include #include diff --git a/lldb/include/lldb/Host/HostInfo.h b/lldb/include/lldb/Host/HostInfo.h index b7010d69d88e7..156df8cf6901d 100644 --- a/lldb/include/lldb/Host/HostInfo.h +++ b/lldb/include/lldb/Host/HostInfo.h @@ -55,6 +55,9 @@ #elif defined(__APPLE__) #include "lldb/Host/macosx/HostInfoMacOSX.h" #define HOST_INFO_TYPE HostInfoMacOSX +#elif defined(__AIX__) +#include "lldb/Host/aix/HostInfoAIX.h" +#define HOST_INFO_TYPE HostInfoAIX #else #include "lldb/Host/posix/HostInfoPosix.h" #define HOST_INFO_TYPE HostInfoPosix diff --git a/lldb/include/lldb/Host/HostInfoBase.h b/lldb/include/lldb/Host/HostInfoBase.h index 705aad559f3b7..29e6acf39bfb2 100644 --- a/lldb/include/lldb/Host/HostInfoBase.h +++ b/lldb/include/lldb/Host/HostInfoBase.h @@ -149,6 +149,7 @@ class HostInfoBase { return {}; } + static bool ComputeSharedLibraryDirectory(FileSpec &file_spec); /// Returns the distribution id of the host /// /// This will be something like "ubuntu", "fedora", etc. on Linux. @@ -158,7 +159,6 @@ class HostInfoBase { static llvm::StringRef GetDistributionId() { return llvm::StringRef(); } protected: - static bool ComputeSharedLibraryDirectory(FileSpec &file_spec); static bool ComputeSupportExeDirectory(FileSpec &file_spec); static bool ComputeProcessTempFileDirectory(FileSpec &file_spec); static bool ComputeGlobalTempFileDirectory(FileSpec &file_spec); diff --git a/lldb/include/lldb/Host/XML.h b/lldb/include/lldb/Host/XML.h index da0f9cd7aa8c0..cf359f7726d5d 100644 --- a/lldb/include/lldb/Host/XML.h +++ b/lldb/include/lldb/Host/XML.h @@ -11,6 +11,11 @@ #include "lldb/Host/Config.h" +#if defined(__AIX__) +//FIXME for AIX +#undef LLDB_ENABLE_LIBXML2 +#endif + #if LLDB_ENABLE_LIBXML2 #include #endif diff --git a/lldb/include/lldb/Host/aix/AbstractSocket.h b/lldb/include/lldb/Host/aix/AbstractSocket.h new file mode 100644 index 0000000000000..78a567a6b9095 --- /dev/null +++ b/lldb/include/lldb/Host/aix/AbstractSocket.h @@ -0,0 +1,25 @@ +//===-- AbstractSocket.h ----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_AbstractSocket_h_ +#define liblldb_AbstractSocket_h_ + +#include "lldb/Host/posix/DomainSocket.h" + +namespace lldb_private { +class AbstractSocket : public DomainSocket { +public: + AbstractSocket(bool child_processes_inherit); + +protected: + size_t GetNameOffset() const override; + void DeleteSocketFile(llvm::StringRef name) override; +}; +} + +#endif // ifndef liblldb_AbstractSocket_h_ diff --git a/lldb/include/lldb/Host/aix/Host.h b/lldb/include/lldb/Host/aix/Host.h new file mode 100644 index 0000000000000..1e3487752995f --- /dev/null +++ b/lldb/include/lldb/Host/aix/Host.h @@ -0,0 +1,22 @@ +//===-- Host.h --------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_HOST_AIX_HOST_H +#define LLDB_HOST_AIX_HOST_H + +#include "lldb/lldb-types.h" +#include + +namespace lldb_private { + +// Get PID (i.e. the primary thread ID) corresponding to the specified TID. +std::optional getPIDForTID(lldb::pid_t tid); + +} // namespace lldb_private + +#endif // #ifndef LLDB_HOST_AIX_HOST_H diff --git a/lldb/include/lldb/Host/aix/HostInfoAIX.h b/lldb/include/lldb/Host/aix/HostInfoAIX.h new file mode 100644 index 0000000000000..ced4cf34d38a8 --- /dev/null +++ b/lldb/include/lldb/Host/aix/HostInfoAIX.h @@ -0,0 +1,42 @@ +//===-- HostInfoAIX.h -----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_Host_aix_HostInfoAIX_h_ +#define lldb_Host_aix_HostInfoAIX_h_ + +#include "lldb/Host/posix/HostInfoPosix.h" +#include "lldb/Utility/FileSpec.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VersionTuple.h" + +#include + +namespace lldb_private { + +class HostInfoAIX : public HostInfoPosix { + friend class HostInfoBase; + +public: + static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr); + static void Terminate(); + + static llvm::VersionTuple GetOSVersion(); + static std::optional GetOSBuildString(); + static llvm::StringRef GetDistributionId(); + static FileSpec GetProgramFileSpec(); + +protected: + static bool ComputeSupportExeDirectory(FileSpec &file_spec); + static bool ComputeSystemPluginsDirectory(FileSpec &file_spec); + static bool ComputeUserPluginsDirectory(FileSpec &file_spec); + static void ComputeHostArchitectureSupport(ArchSpec &arch_32, + ArchSpec &arch_64); +}; +} + +#endif diff --git a/lldb/include/lldb/Host/aix/Ptrace.h b/lldb/include/lldb/Host/aix/Ptrace.h new file mode 100644 index 0000000000000..88928f18102d7 --- /dev/null +++ b/lldb/include/lldb/Host/aix/Ptrace.h @@ -0,0 +1,62 @@ +//===-- Ptrace.h ------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +// This file defines ptrace functions & structures + +#ifndef liblldb_Host_aix_Ptrace_h_ +#define liblldb_Host_aix_Ptrace_h_ + +#include + +#define DEBUG_PTRACE_MAXBYTES 20 + +// Support ptrace extensions even when compiled without required kernel support +#ifndef PTRACE_GETREGS +#define PTRACE_GETREGS (PT_COMMAND_MAX+1) +#endif +#ifndef PTRACE_SETREGS +#define PTRACE_SETREGS (PT_COMMAND_MAX+2) +#endif +#ifndef PTRACE_GETFPREGS +#define PTRACE_GETFPREGS (PT_COMMAND_MAX+3) +#endif +#ifndef PTRACE_SETFPREGS +#define PTRACE_SETFPREGS (PT_COMMAND_MAX+4) +#endif +#ifndef PTRACE_GETREGSET +#define PTRACE_GETREGSET 0x4204 +#endif +#ifndef PTRACE_SETREGSET +#define PTRACE_SETREGSET 0x4205 +#endif +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA (PT_COMMAND_MAX+5) +#endif +#ifndef PTRACE_ARCH_PRCTL +#define PTRACE_ARCH_PRCTL (PT_COMMAND_MAX+6) +#endif +#ifndef ARCH_GET_FS +#define ARCH_SET_GS 0x1001 +#define ARCH_SET_FS 0x1002 +#define ARCH_GET_FS 0x1003 +#define ARCH_GET_GS 0x1004 +#endif +#ifndef PTRACE_PEEKMTETAGS +#define PTRACE_PEEKMTETAGS (PT_COMMAND_MAX+7) +#endif +#ifndef PTRACE_POKEMTETAGS +#define PTRACE_POKEMTETAGS (PT_COMMAND_MAX+8) +#endif +#ifndef PTRACE_GETVRREGS +#define PTRACE_GETVRREGS (PT_COMMAND_MAX+9) +#endif +#ifndef PTRACE_GETVSRREGS +#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+10) +#endif + +#endif // liblldb_Host_aix_Ptrace_h_ diff --git a/lldb/include/lldb/Host/aix/Support.h b/lldb/include/lldb/Host/aix/Support.h new file mode 100644 index 0000000000000..27d6c2b50a35b --- /dev/null +++ b/lldb/include/lldb/Host/aix/Support.h @@ -0,0 +1,29 @@ +//===-- Support.h -----------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_HOST_AIX_SUPPORT_H +#define LLDB_HOST_AIX_SUPPORT_H + +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MemoryBuffer.h" +#include + +namespace lldb_private { + +llvm::ErrorOr> +getProcFile(::pid_t pid, ::pid_t tid, const llvm::Twine &file); + +llvm::ErrorOr> +getProcFile(::pid_t pid, const llvm::Twine &file); + +llvm::ErrorOr> +getProcFile(const llvm::Twine &file); + +} // namespace lldb_private + +#endif // #ifndef LLDB_HOST_AIX_SUPPORT_H diff --git a/lldb/include/lldb/Host/aix/Uio.h b/lldb/include/lldb/Host/aix/Uio.h new file mode 100644 index 0000000000000..acf79ecc6a1d0 --- /dev/null +++ b/lldb/include/lldb/Host/aix/Uio.h @@ -0,0 +1,23 @@ +//===-- Uio.h ---------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Host_aix_Uio_h_ +#define liblldb_Host_aix_Uio_h_ + +#include "lldb/Host/Config.h" +#include + +// We shall provide our own implementation of process_vm_readv if it is not +// present +#if !HAVE_PROCESS_VM_READV +ssize_t process_vm_readv(::pid_t pid, const struct iovec *local_iov, + unsigned long liovcnt, const struct iovec *remote_iov, + unsigned long riovcnt, unsigned long flags); +#endif + +#endif // liblldb_Host_aix_Uio_h_ diff --git a/lldb/include/lldb/Host/common/GetOptInc.h b/lldb/include/lldb/Host/common/GetOptInc.h index 3fb9add479541..ebb475bfaf6b8 100644 --- a/lldb/include/lldb/Host/common/GetOptInc.h +++ b/lldb/include/lldb/Host/common/GetOptInc.h @@ -11,11 +11,11 @@ #include "lldb/lldb-defines.h" -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__AIX__) #define REPLACE_GETOPT #define REPLACE_GETOPT_LONG #endif -#if defined(_MSC_VER) || defined(__NetBSD__) +#if defined(_MSC_VER) || defined(__NetBSD__) || defined(__AIX__) #define REPLACE_GETOPT_LONG_ONLY #endif @@ -35,7 +35,7 @@ struct option { int val; }; -int getopt(int argc, char *const argv[], const char *optstring); +int getopt(int argc, char *const argv[], const char *optstring) throw(); // from getopt.h extern char *optarg; diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h index 8592323322e38..bf66ccec263d2 100644 --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/lldb/include/lldb/Symbol/ObjectFile.h @@ -401,6 +401,11 @@ class ObjectFile : public std::enable_shared_from_this, return false; } + virtual bool SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) { + return false; + } + /// Gets whether endian swapping should occur when extracting data from this /// object file. /// diff --git a/lldb/include/lldb/Target/ABI.h b/lldb/include/lldb/Target/ABI.h index 7b646d743346b..281a89951ef88 100644 --- a/lldb/include/lldb/Target/ABI.h +++ b/lldb/include/lldb/Target/ABI.h @@ -47,6 +47,12 @@ class ABI : public PluginInterface { lldb::addr_t returnAddress, llvm::ArrayRef args) const = 0; + virtual bool PrepareTrivialCall(lldb_private::Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t tocAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef args) const; + // Prepare trivial call used from ThreadPlanFunctionCallUsingABI // AD: // . Because i don't want to change other ABI's this is not declared pure diff --git a/lldb/include/lldb/Target/DynamicLoader.h b/lldb/include/lldb/Target/DynamicLoader.h index 0629e2faae7e9..7dccd317c2dca 100644 --- a/lldb/include/lldb/Target/DynamicLoader.h +++ b/lldb/include/lldb/Target/DynamicLoader.h @@ -359,6 +359,12 @@ class DynamicLoader : public PluginInterface { lldb::addr_t base_addr, bool base_addr_is_offset); + virtual void UpdateLoadedSectionsByType(lldb::ModuleSP module, + lldb::addr_t link_map_addr, + lldb::addr_t base_addr, + bool base_addr_is_offset, + int type_id); + // Utility method so base classes can share implementation of // UpdateLoadedSections void UpdateLoadedSectionsCommon(lldb::ModuleSP module, lldb::addr_t base_addr, diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index cf16fbc812aa4..886ca766112c8 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -63,6 +63,10 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/VersionTuple.h" +#if defined(__AIX__) +struct ld_xinfo; +#endif + namespace lldb_private { template struct Range; @@ -1915,6 +1919,10 @@ class Process : public std::enable_shared_from_this, Status GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &range_info); +#if defined(__AIX__) + Status GetLDXINFO(struct ld_xinfo *info_ptr); +#endif + /// Obtain all the mapped memory regions within this process. /// /// \param[out] region_list @@ -2855,6 +2863,12 @@ void PruneThreadPlans(); return Status("Process::DoGetMemoryRegionInfo() not supported"); } +#if defined(__AIX__) + virtual Status DoGetLDXINFO(struct ld_xinfo *info_ptr) { + return Status("Process::DoGetLDXINFO() not supported"); + } +#endif + /// Provide an override value in the subclass for lldb's /// CPU-based logic for whether watchpoint exceptions are /// received before or after an instruction executes. diff --git a/lldb/include/lldb/Target/RegisterContextUnwind.h b/lldb/include/lldb/Target/RegisterContextUnwind.h index ef8ae88403866..00a95853800ed 100644 --- a/lldb/include/lldb/Target/RegisterContextUnwind.h +++ b/lldb/include/lldb/Target/RegisterContextUnwind.h @@ -67,6 +67,10 @@ class RegisterContextUnwind : public lldb_private::RegisterContext { bool ReadPC(lldb::addr_t &start_pc); +#ifdef __AIX__ + bool ReadLR(lldb::addr_t &lr); +#endif + // Indicates whether this frame *behaves* like frame zero -- the currently // executing frame -- or not. This can be true in the middle of the stack // above asynchronous trap handlers (sigtramp) for instance. diff --git a/lldb/include/lldb/Target/ThreadPlanCallFunction.h b/lldb/include/lldb/Target/ThreadPlanCallFunction.h index cb6e7caebb4ad..7880db1592e04 100644 --- a/lldb/include/lldb/Target/ThreadPlanCallFunction.h +++ b/lldb/include/lldb/Target/ThreadPlanCallFunction.h @@ -27,6 +27,12 @@ class ThreadPlanCallFunction : public ThreadPlan { llvm::ArrayRef args, const EvaluateExpressionOptions &options); + ThreadPlanCallFunction(Thread &thread, const Address &function, + const Address &toc, + const CompilerType &return_type, + llvm::ArrayRef args, + const EvaluateExpressionOptions &options); + ThreadPlanCallFunction(Thread &thread, const Address &function, const EvaluateExpressionOptions &options); diff --git a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h index dd468ef5bddef..9953bd6c24588 100644 --- a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h +++ b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h @@ -61,6 +61,7 @@ class StringExtractorGDBRemote : public StringExtractor { eServerPacketType_qQueryGDBServer, eServerPacketType_qKillSpawnedProcess, eServerPacketType_qLaunchSuccess, + eServerPacketType_qLDXINFO, eServerPacketType_qModuleInfo, eServerPacketType_qProcessInfoPID, eServerPacketType_qSpeedTest, diff --git a/lldb/include/lldb/lldb-private-enumerations.h b/lldb/include/lldb/lldb-private-enumerations.h index c24a3538f58da..98c1e956bf8f7 100644 --- a/lldb/include/lldb/lldb-private-enumerations.h +++ b/lldb/include/lldb/lldb-private-enumerations.h @@ -65,6 +65,7 @@ enum ArchitectureType { eArchTypeMachO, eArchTypeELF, eArchTypeCOFF, + eArchTypeXCOFF, kNumArchTypes }; diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index a32bc58507d8e..3ecdb11daef7d 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -40,6 +40,113 @@ add_custom_target(lldb-sbapi-dwarf-enums DEPENDS ${sb_languages_file}) set_target_properties(lldb-sbapi-dwarf-enums PROPERTIES FOLDER "LLDB/Tablegenning") +if(CMAKE_SYSTEM_NAME MATCHES "AIX") +add_lldb_library(liblldb STATIC ${option_framework} + SBAddress.cpp + SBAddressRange.cpp + SBAddressRangeList.cpp + SBAttachInfo.cpp + SBBlock.cpp + SBBreakpoint.cpp + SBBreakpointLocation.cpp + SBBreakpointName.cpp + SBBreakpointOptionCommon.cpp + SBBroadcaster.cpp + SBCommandInterpreter.cpp + SBCommandInterpreterRunOptions.cpp + SBCommandReturnObject.cpp + SBCommunication.cpp + SBCompileUnit.cpp + SBSaveCoreOptions.cpp + SBData.cpp + SBDebugger.cpp + SBDeclaration.cpp + SBEnvironment.cpp + SBError.cpp + SBEvent.cpp + SBExecutionContext.cpp + SBExpressionOptions.cpp + SBFileSpec.cpp + SBFile.cpp + SBFileSpecList.cpp + SBFormat.cpp + SBFrame.cpp + SBFunction.cpp + SBHostOS.cpp + SBInstruction.cpp + SBInstructionList.cpp + SBLanguageRuntime.cpp + SBLaunchInfo.cpp + SBLineEntry.cpp + SBListener.cpp + SBMemoryRegionInfo.cpp + SBMemoryRegionInfoList.cpp + SBModule.cpp + SBModuleSpec.cpp + SBPlatform.cpp + SBProcess.cpp + SBProcessInfo.cpp + SBProcessInfoList.cpp + SBQueue.cpp + SBQueueItem.cpp + SBReproducer.cpp + SBScriptObject.cpp + SBSection.cpp + SBSourceManager.cpp + SBStatisticsOptions.cpp + SBStream.cpp + SBStringList.cpp + SBStructuredData.cpp + SBSymbol.cpp + SBSymbolContext.cpp + SBSymbolContextList.cpp + SBTarget.cpp + SBThread.cpp + SBThreadCollection.cpp + SBThreadPlan.cpp + SBTrace.cpp + SBTraceCursor.cpp + SBType.cpp + SBTypeCategory.cpp + SBTypeEnumMember.cpp + SBTypeFilter.cpp + SBTypeFormat.cpp + SBTypeNameSpecifier.cpp + SBTypeSummary.cpp + SBTypeSynthetic.cpp + SBValue.cpp + SBValueList.cpp + SBVariablesOptions.cpp + SBWatchpoint.cpp + SBWatchpointOptions.cpp + SBUnixSignals.cpp + SystemInitializerFull.cpp + ${lldb_python_wrapper} + ${lldb_lua_wrapper} + + DEPENDS + lldb-sbapi-dwarf-enums + + LINK_LIBS + lldbBreakpoint + lldbCore + lldbDataFormatters + lldbExpression + lldbHost + lldbInitialization + lldbInterpreter + lldbSymbol + lldbTarget + lldbUtility + lldbVersion + ${LLDB_ALL_PLUGINS} + LINK_COMPONENTS + Support + + ${option_install_prefix} +) + +else() add_lldb_library(liblldb SHARED ${option_framework} SBAddress.cpp SBAddressRange.cpp @@ -144,6 +251,7 @@ add_lldb_library(liblldb SHARED ${option_framework} ${option_install_prefix} ) +endif() # lib/pythonX.Y/dist-packages/lldb/_lldb.so is a symlink to lib/liblldb.so, # which depends on lib/libLLVM*.so (BUILD_SHARED_LIBS) or lib/libLLVM-10git.so diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp index 3d908047f9455..728fe04d14d92 100644 --- a/lldb/source/API/SBBreakpoint.cpp +++ b/lldb/source/API/SBBreakpoint.cpp @@ -342,7 +342,7 @@ uint32_t SBBreakpoint::GetIgnoreCount() const { return count; } -void SBBreakpoint::SetThreadID(tid_t tid) { +void SBBreakpoint::SetThreadID(lldb::tid_t tid) { LLDB_INSTRUMENT_VA(this, tid); BreakpointSP bkpt_sp = GetSP(); @@ -353,10 +353,10 @@ void SBBreakpoint::SetThreadID(tid_t tid) { } } -tid_t SBBreakpoint::GetThreadID() { +lldb::tid_t SBBreakpoint::GetThreadID() { LLDB_INSTRUMENT_VA(this); - tid_t tid = LLDB_INVALID_THREAD_ID; + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; BreakpointSP bkpt_sp = GetSP(); if (bkpt_sp) { std::lock_guard guard( diff --git a/lldb/source/API/SBBreakpointLocation.cpp b/lldb/source/API/SBBreakpointLocation.cpp index 75b66364d4f1a..fad9a4076a54f 100644 --- a/lldb/source/API/SBBreakpointLocation.cpp +++ b/lldb/source/API/SBBreakpointLocation.cpp @@ -302,7 +302,7 @@ bool SBBreakpointLocation::GetCommandLineCommands(SBStringList &commands) { return has_commands; } -void SBBreakpointLocation::SetThreadID(tid_t thread_id) { +void SBBreakpointLocation::SetThreadID(lldb::tid_t thread_id) { LLDB_INSTRUMENT_VA(this, thread_id); BreakpointLocationSP loc_sp = GetSP(); @@ -313,10 +313,10 @@ void SBBreakpointLocation::SetThreadID(tid_t thread_id) { } } -tid_t SBBreakpointLocation::GetThreadID() { +lldb::tid_t SBBreakpointLocation::GetThreadID() { LLDB_INSTRUMENT_VA(this); - tid_t tid = LLDB_INVALID_THREAD_ID; + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; BreakpointLocationSP loc_sp = GetSP(); if (loc_sp) { std::lock_guard guard( diff --git a/lldb/source/API/SBBreakpointName.cpp b/lldb/source/API/SBBreakpointName.cpp index 7f63aaf6fa7d5..5c7c0a8f6504b 100644 --- a/lldb/source/API/SBBreakpointName.cpp +++ b/lldb/source/API/SBBreakpointName.cpp @@ -347,7 +347,7 @@ bool SBBreakpointName::GetAutoContinue() { return bp_name->GetOptions().IsAutoContinue(); } -void SBBreakpointName::SetThreadID(tid_t tid) { +void SBBreakpointName::SetThreadID(lldb::tid_t tid) { LLDB_INSTRUMENT_VA(this, tid); BreakpointName *bp_name = GetBreakpointName(); @@ -361,7 +361,7 @@ void SBBreakpointName::SetThreadID(tid_t tid) { UpdateName(*bp_name); } -tid_t SBBreakpointName::GetThreadID() { +lldb::tid_t SBBreakpointName::GetThreadID() { LLDB_INSTRUMENT_VA(this); BreakpointName *bp_name = GetBreakpointName(); diff --git a/lldb/source/Core/DynamicLoader.cpp b/lldb/source/Core/DynamicLoader.cpp index 7758a87403b5a..ea43a7f98b69f 100644 --- a/lldb/source/Core/DynamicLoader.cpp +++ b/lldb/source/Core/DynamicLoader.cpp @@ -113,6 +113,16 @@ void DynamicLoader::UpdateLoadedSections(ModuleSP module, addr_t link_map_addr, UpdateLoadedSectionsCommon(module, base_addr, base_addr_is_offset); } +void DynamicLoader::UpdateLoadedSectionsByType(lldb::ModuleSP module, + lldb::addr_t link_map_addr, + lldb::addr_t base_addr, + bool base_addr_is_offset, + int type_id) { + bool changed; + module->SetLoadAddressByType(m_process->GetTarget(), base_addr, base_addr_is_offset, + changed, type_id); +} + void DynamicLoader::UpdateLoadedSectionsCommon(ModuleSP module, addr_t base_addr, bool base_addr_is_offset) { diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp index 387c4fac6b0f8..43c5b043ef7a2 100644 --- a/lldb/source/Core/Mangled.cpp +++ b/lldb/source/Core/Mangled.cpp @@ -167,12 +167,14 @@ static char *GetItaniumDemangledStr(const char *M) { "Expected demangled_size to return length including trailing null"); } +#if !defined(__AIX__) if (Log *log = GetLog(LLDBLog::Demangle)) { if (demangled_cstr) LLDB_LOGF(log, "demangled itanium: %s -> \"%s\"", M, demangled_cstr); else LLDB_LOGF(log, "demangled itanium: %s -> error: failed to demangle", M); } +#endif return demangled_cstr; } diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index f9d7832254f46..044a5d29978e8 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -1510,6 +1510,18 @@ bool Module::SetLoadAddress(Target &target, lldb::addr_t value, return false; } +bool Module::SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, bool &changed, int type_id) { + ObjectFile *object_file = GetObjectFile(); + if (object_file != nullptr) { + changed = object_file->SetLoadAddressByType(target, value, value_is_offset, type_id); + return true; + } else { + changed = false; + } + return false; +} + bool Module::MatchesModuleSpec(const ModuleSpec &module_ref) { const UUID &uuid = module_ref.GetUUID(); diff --git a/lldb/source/Core/Section.cpp b/lldb/source/Core/Section.cpp index 0763e88d4608f..9ed55853930a6 100644 --- a/lldb/source/Core/Section.cpp +++ b/lldb/source/Core/Section.cpp @@ -263,6 +263,10 @@ bool Section::ResolveContainedAddress(addr_t offset, Address &so_addr, bool Section::ContainsFileAddress(addr_t vm_addr) const { const addr_t file_addr = GetFileAddress(); +#ifdef __AIX__ + if (file_addr == 0) + return false; +#endif if (file_addr != LLDB_INVALID_ADDRESS && !IsThreadSpecific()) { if (file_addr <= vm_addr) { const addr_t offset = (vm_addr - file_addr) * m_target_byte_size; diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index 444e44b392891..c1feec990f989 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -130,7 +130,7 @@ static llvm::Error ReadRegisterValueAsScalar(RegisterContext *reg_ctx, /// Return the length in bytes of the set of operands for \p op. No guarantees /// are made on the state of \p data after this call. -static offset_t GetOpcodeDataSize(const DataExtractor &data, +static lldb::offset_t GetOpcodeDataSize(const DataExtractor &data, const lldb::offset_t data_offset, const uint8_t op, const DWARFUnit *dwarf_cu) { lldb::offset_t offset = data_offset; @@ -358,7 +358,7 @@ lldb::addr_t DWARFExpression::GetLocation_DW_OP_addr(const DWARFUnit *dwarf_cu, error = true; break; } - const offset_t op_arg_size = + const lldb::offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op, dwarf_cu); if (op_arg_size == LLDB_INVALID_OFFSET) { error = true; @@ -418,7 +418,7 @@ bool DWARFExpression::Update_DW_OP_addr(const DWARFUnit *dwarf_cu, m_data.SetData(encoder.GetDataBuffer()); return true; } - const offset_t op_arg_size = + const lldb::offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op, dwarf_cu); if (op_arg_size == LLDB_INVALID_OFFSET) break; @@ -435,7 +435,7 @@ bool DWARFExpression::ContainsThreadLocalStorage( if (op == DW_OP_form_tls_address || op == DW_OP_GNU_push_tls_address) return true; - const offset_t op_arg_size = + const lldb::offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op, dwarf_cu); if (op_arg_size == LLDB_INVALID_OFFSET) return false; @@ -515,7 +515,7 @@ bool DWARFExpression::LinkThreadLocalStorage( } if (!decoded_data) { - const offset_t op_arg_size = + const lldb::offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op, dwarf_cu); if (op_arg_size == LLDB_INVALID_OFFSET) return false; diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index c2e091ee8555b..5374b16881950 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -7,6 +7,11 @@ if (APPLE AND LLVM_ENABLE_LOCAL_SUBMODULE_VISIBILITY) endif() endif() +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + macro(add_host_subdirectory group) list(APPEND HOST_SOURCES ${ARGN}) source_group(${group} FILES ${ARGN}) @@ -133,6 +138,14 @@ else() openbsd/Host.cpp openbsd/HostInfoOpenBSD.cpp ) + + elseif (CMAKE_SYSTEM_NAME MATCHES "AIX") + add_host_subdirectory(aix + aix/AbstractSocket.cpp + aix/Host.cpp + aix/HostInfoAIX.cpp + aix/Support.cpp + ) endif() endif() diff --git a/lldb/source/Host/aix/AbstractSocket.cpp b/lldb/source/Host/aix/AbstractSocket.cpp new file mode 100644 index 0000000000000..bfb67d452f7ec --- /dev/null +++ b/lldb/source/Host/aix/AbstractSocket.cpp @@ -0,0 +1,21 @@ +//===-- AbstractSocket.cpp ------------------------------------------------===// +// +// 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 "lldb/Host/aix/AbstractSocket.h" + +#include "llvm/ADT/StringRef.h" + +using namespace lldb; +using namespace lldb_private; + +AbstractSocket::AbstractSocket(bool child_processes_inherit) + : DomainSocket(ProtocolUnixAbstract, child_processes_inherit) {} + +size_t AbstractSocket::GetNameOffset() const { return 1; } + +void AbstractSocket::DeleteSocketFile(llvm::StringRef name) {} diff --git a/lldb/source/Host/aix/Host.cpp b/lldb/source/Host/aix/Host.cpp new file mode 100644 index 0000000000000..d82cb9049d389 --- /dev/null +++ b/lldb/source/Host/aix/Host.cpp @@ -0,0 +1,304 @@ +//===-- source/Host/aix/Host.cpp ----------------------------------------===// +// +// 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/ScopedPrinter.h" + +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/ProcessInfo.h" +#include "lldb/Utility/Status.h" + +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Host/aix/Host.h" +#include "lldb/Host/aix/Support.h" +#include "lldb/Utility/DataExtractor.h" +#include "llvm/BinaryFormat/XCOFF.h" + +#include +#include + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; + +namespace { +enum class ProcessState { + Unknown, + Dead, + DiskSleep, + Idle, + Paging, + Parked, + Running, + Sleeping, + TracedOrStopped, + Zombie, +}; +} + +namespace lldb_private { +class ProcessLaunchInfo; +} + +static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo, + ProcessState &State, ::pid_t &TracerPid, + ::pid_t &Tgid) { + Log *log = GetLog(LLDBLog::Host); + + auto BufferOrError = getProcFile(Pid, "status"); + if (!BufferOrError) + return false; + + llvm::StringRef Rest = BufferOrError.get()->getBuffer(); + while (!Rest.empty()) { + llvm::StringRef Line; + std::tie(Line, Rest) = Rest.split('\n'); + + if (Line.consume_front("Gid:")) { + // Real, effective, saved set, and file system GIDs. Read the first two. + Line = Line.ltrim(); + uint32_t RGid, EGid; + Line.consumeInteger(10, RGid); + Line = Line.ltrim(); + Line.consumeInteger(10, EGid); + + ProcessInfo.SetGroupID(RGid); + ProcessInfo.SetEffectiveGroupID(EGid); + } else if (Line.consume_front("Uid:")) { + // Real, effective, saved set, and file system UIDs. Read the first two. + Line = Line.ltrim(); + uint32_t RUid, EUid; + Line.consumeInteger(10, RUid); + Line = Line.ltrim(); + Line.consumeInteger(10, EUid); + + ProcessInfo.SetUserID(RUid); + ProcessInfo.SetEffectiveUserID(EUid); + } else if (Line.consume_front("PPid:")) { + ::pid_t PPid; + Line.ltrim().consumeInteger(10, PPid); + ProcessInfo.SetParentProcessID(PPid); + } else if (Line.consume_front("State:")) { + State = llvm::StringSwitch(Line.ltrim().take_front(1)) + .Case("D", ProcessState::DiskSleep) + .Case("I", ProcessState::Idle) + .Case("R", ProcessState::Running) + .Case("S", ProcessState::Sleeping) + .CaseLower("T", ProcessState::TracedOrStopped) + .Case("W", ProcessState::Paging) + .Case("P", ProcessState::Parked) + .Case("X", ProcessState::Dead) + .Case("Z", ProcessState::Zombie) + .Default(ProcessState::Unknown); + if (State == ProcessState::Unknown) { + LLDB_LOG(log, "Unknown process state {0}", Line); + } + } else if (Line.consume_front("TracerPid:")) { + Line = Line.ltrim(); + Line.consumeInteger(10, TracerPid); + } else if (Line.consume_front("Tgid:")) { + Line = Line.ltrim(); + Line.consumeInteger(10, Tgid); + } + } + return true; +} + +static bool IsDirNumeric(const char *dname) { + for (; *dname; dname++) { + if (!isdigit(*dname)) + return false; + } + return true; +} + +static void GetProcessArgs(::pid_t pid, ProcessInstanceInfo &process_info) { + auto BufferOrError = getProcFile(pid, "cmdline"); + if (!BufferOrError) + return; + std::unique_ptr Cmdline = std::move(*BufferOrError); + + llvm::StringRef Arg0, Rest; + std::tie(Arg0, Rest) = Cmdline->getBuffer().split('\0'); + process_info.SetArg0(Arg0); + while (!Rest.empty()) { + llvm::StringRef Arg; + std::tie(Arg, Rest) = Rest.split('\0'); + process_info.GetArguments().AppendArgument(Arg); + } +} + +static void GetExePathAndArch(::pid_t pid, ProcessInstanceInfo &process_info) { + Log *log = GetLog(LLDBLog::Process); + std::string ExePath(PATH_MAX, '\0'); + std::string Basename(PATH_MAX, '\0'); + struct psinfo psinfoData; + + // We can't use getProcFile here because proc/[pid]/exe is a symbolic link. + llvm::SmallString<64> ProcExe; + (llvm::Twine("/proc/") + llvm::Twine(pid) + "/cwd").toVector(ProcExe); + + ssize_t len = readlink(ProcExe.c_str(), &ExePath[0], PATH_MAX); + if (len > 0) { + ExePath.resize(len); + + //FIXME: hack to get basename + struct stat statData; + + std::ostringstream oss; + + oss << "/proc/" << std::dec << pid << "/psinfo"; + assert(stat(oss.str().c_str(), &statData) == 0); + + const int fd = open(oss.str().c_str(), O_RDONLY); + assert (fd >= 0); + + ssize_t readNum = read(fd, &psinfoData, sizeof(psinfoData)); + assert (readNum >= 0); + + close (fd); + } else { + LLDB_LOG(log, "failed to read link exe link for {0}: {1}", pid, + Status(errno, eErrorTypePOSIX)); + ExePath.resize(0); + } + + llvm::StringRef PathRef = std::string(&(psinfoData.pr_psargs[0])); + + if (!PathRef.empty()) { + process_info.GetExecutableFile().SetFile(PathRef, FileSpec::Style::native); + ArchSpec arch_spec = ArchSpec(); + arch_spec.SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX); + process_info.SetArchitecture(arch_spec); + } +} + +static void GetProcessEnviron(::pid_t pid, ProcessInstanceInfo &process_info) { + // Get the process environment. + auto BufferOrError = getProcFile(pid, "environ"); + if (!BufferOrError) + return; + + std::unique_ptr Environ = std::move(*BufferOrError); + llvm::StringRef Rest = Environ->getBuffer(); + while (!Rest.empty()) { + llvm::StringRef Var; + std::tie(Var, Rest) = Rest.split('\0'); + process_info.GetEnvironment().insert(Var); + } +} + +static bool GetProcessAndStatInfo(::pid_t pid, + ProcessInstanceInfo &process_info, + ProcessState &State, ::pid_t &tracerpid) { + ::pid_t tgid; + tracerpid = 0; + process_info.Clear(); + + process_info.SetProcessID(pid); + + GetExePathAndArch(pid, process_info); + GetProcessArgs(pid, process_info); + GetProcessEnviron(pid, process_info); + + // Get User and Group IDs and get tracer pid. + if (!GetStatusInfo(pid, process_info, State, tracerpid, tgid)) + return false; + + return true; +} + +uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { + static const char procdir[] = "/proc/"; + + DIR *dirproc = opendir(procdir); + if (dirproc) { + struct dirent *direntry = nullptr; + const uid_t our_uid = getuid(); + const lldb::pid_t our_pid = getpid(); + bool all_users = match_info.GetMatchAllUsers(); + + while ((direntry = readdir(dirproc)) != nullptr) { + /* + if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name)) + continue; + */ + + lldb::pid_t pid = atoi(direntry->d_name); + + // Skip this process. + if (pid == our_pid) + continue; + + ::pid_t tracerpid; + ProcessState State; + ProcessInstanceInfo process_info; + + if (!GetProcessAndStatInfo(pid, process_info, State, tracerpid)) + continue; + + // Skip if process is being debugged. + if (tracerpid != 0) + continue; + + if (State == ProcessState::Zombie) + continue; + + // Check for user match if we're not matching all users and not running + // as root. + if (!all_users && (our_uid != 0) && (process_info.GetUserID() != our_uid)) + continue; + + if (match_info.Matches(process_info)) { + process_infos.push_back(process_info); + } + } + + closedir(dirproc); + } + + return process_infos.size(); +} + +bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { + ::pid_t tracerpid; + ProcessState State; + return GetProcessAndStatInfo(pid, process_info, State, tracerpid); +} + +Environment Host::GetEnvironment() { return Environment(environ); } + +Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) { + return Status("unimplemented"); +} + +std::optional lldb_private::getPIDForTID(lldb::pid_t tid) { + ::pid_t tracerpid, tgid = LLDB_INVALID_PROCESS_ID; + ProcessInstanceInfo process_info; + ProcessState state; + + if (!GetStatusInfo(tid, process_info, state, tracerpid, tgid) || + tgid == LLDB_INVALID_PROCESS_ID) + return std::nullopt; + return tgid; +} diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp new file mode 100644 index 0000000000000..8bda09e01741b --- /dev/null +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -0,0 +1,215 @@ +//===-- HostInfoAIX.cpp -------------------------------------------------===// +// +// 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 "lldb/Host/aix/HostInfoAIX.h" +#include "lldb/Host/Config.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" + +#include "llvm/Support/Threading.h" + +#include +#include +#include +#include +#include + +#include +#include + +using namespace lldb_private; + +namespace { +struct HostInfoAIXFields { + llvm::once_flag m_distribution_once_flag; + std::string m_distribution_id; + llvm::once_flag m_os_version_once_flag; + llvm::VersionTuple m_os_version; +}; +} // namespace + +static HostInfoAIXFields *g_fields = nullptr; + +void HostInfoAIX::Initialize(SharedLibraryDirectoryHelper *helper) { + HostInfoPosix::Initialize(helper); + + g_fields = new HostInfoAIXFields(); +} + +void HostInfoAIX::Terminate() { + assert(g_fields && "Missing call to Initialize?"); + delete g_fields; + g_fields = nullptr; + HostInfoBase::Terminate(); +} + +llvm::VersionTuple HostInfoAIX::GetOSVersion() { + assert(g_fields && "Missing call to Initialize?"); + llvm::call_once(g_fields->m_os_version_once_flag, []() { + struct utsname un; + if (uname(&un) != 0) + return; + + llvm::StringRef release = un.release; + // The kernel release string can include a lot of stuff (e.g. + // 4.9.0-6-amd64). We're only interested in the numbered prefix. + release = release.substr(0, release.find_first_not_of("0123456789.")); + g_fields->m_os_version.tryParse(release); + }); + + return g_fields->m_os_version; +} + +std::optional HostInfoAIX::GetOSBuildString() { + struct utsname un; + ::memset(&un, 0, sizeof(utsname)); + + if (uname(&un) < 0) + return std::nullopt; + + return std::string(un.release); +} + +llvm::StringRef HostInfoAIX::GetDistributionId() { + assert(g_fields && "Missing call to Initialize?"); + // Try to run 'lbs_release -i', and use that response for the distribution + // id. + llvm::call_once(g_fields->m_distribution_once_flag, []() { + Log *log = GetLog(LLDBLog::Host); + LLDB_LOGF(log, "attempting to determine AIX distribution..."); + + // check if the lsb_release command exists at one of the following paths + const char *const exe_paths[] = {"/bin/lsb_release", + "/usr/bin/lsb_release"}; + + for (size_t exe_index = 0; + exe_index < sizeof(exe_paths) / sizeof(exe_paths[0]); ++exe_index) { + const char *const get_distribution_info_exe = exe_paths[exe_index]; + if (access(get_distribution_info_exe, F_OK)) { + // this exe doesn't exist, move on to next exe + LLDB_LOGF(log, "executable doesn't exist: %s", + get_distribution_info_exe); + continue; + } + + // execute the distribution-retrieval command, read output + std::string get_distribution_id_command(get_distribution_info_exe); + get_distribution_id_command += " -i"; + + FILE *file = popen(get_distribution_id_command.c_str(), "r"); + if (!file) { + LLDB_LOGF(log, + "failed to run command: \"%s\", cannot retrieve " + "platform information", + get_distribution_id_command.c_str()); + break; + } + + // retrieve the distribution id string. + char distribution_id[256] = {'\0'}; + if (fgets(distribution_id, sizeof(distribution_id) - 1, file) != + nullptr) { + LLDB_LOGF(log, "distribution id command returned \"%s\"", + distribution_id); + + const char *const distributor_id_key = "Distributor ID:\t"; + if (strstr(distribution_id, distributor_id_key)) { + // strip newlines + std::string id_string(distribution_id + strlen(distributor_id_key)); + id_string.erase(std::remove(id_string.begin(), id_string.end(), '\n'), + id_string.end()); + + // lower case it and convert whitespace to underscores + std::transform( + id_string.begin(), id_string.end(), id_string.begin(), + [](char ch) { return tolower(isspace(ch) ? '_' : ch); }); + + g_fields->m_distribution_id = id_string; + LLDB_LOGF(log, "distribution id set to \"%s\"", + g_fields->m_distribution_id.c_str()); + } else { + LLDB_LOGF(log, "failed to find \"%s\" field in \"%s\"", + distributor_id_key, distribution_id); + } + } else { + LLDB_LOGF(log, + "failed to retrieve distribution id, \"%s\" returned no" + " lines", + get_distribution_id_command.c_str()); + } + + // clean up the file + pclose(file); + } + }); + + return g_fields->m_distribution_id; +} + +FileSpec HostInfoAIX::GetProgramFileSpec() { + static FileSpec g_program_filespec; + + if (!g_program_filespec) { + char exe_path[PATH_MAX]; + ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); + if (len > 0) { + exe_path[len] = 0; + g_program_filespec.SetFile(exe_path, FileSpec::Style::native); + } + } + + return g_program_filespec; +} + +bool HostInfoAIX::ComputeSupportExeDirectory(FileSpec &file_spec) { + if (HostInfoPosix::ComputeSupportExeDirectory(file_spec) && + file_spec.IsAbsolute() && FileSystem::Instance().Exists(file_spec)) + return true; + file_spec.SetDirectory(GetProgramFileSpec().GetDirectory()); + return !file_spec.GetDirectory().IsEmpty(); +} + +bool HostInfoAIX::ComputeSystemPluginsDirectory(FileSpec &file_spec) { + FileSpec temp_file("/usr/" LLDB_INSTALL_LIBDIR_BASENAME "/lldb/plugins"); + FileSystem::Instance().Resolve(temp_file); + file_spec.SetDirectory(temp_file.GetPath()); + return true; +} + +bool HostInfoAIX::ComputeUserPluginsDirectory(FileSpec &file_spec) { + // XDG Base Directory Specification + // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html If + // XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb. + const char *xdg_data_home = getenv("XDG_DATA_HOME"); + if (xdg_data_home && xdg_data_home[0]) { + std::string user_plugin_dir(xdg_data_home); + user_plugin_dir += "/lldb"; + file_spec.SetDirectory(user_plugin_dir.c_str()); + } else + file_spec.SetDirectory("~/.local/share/lldb"); + return true; +} + +void HostInfoAIX::ComputeHostArchitectureSupport(ArchSpec &arch_32, + ArchSpec &arch_64) { + HostInfoPosix::ComputeHostArchitectureSupport(arch_32, arch_64); + + const char *distribution_id = GetDistributionId().data(); + + // On Linux, "unknown" in the vendor slot isn't what we want for the default + // triple. It's probably an artifact of config.guess. + if (arch_32.IsValid()) { + if (arch_32.GetTriple().getVendor() == llvm::Triple::UnknownVendor) + arch_32.GetTriple().setVendorName(llvm::StringRef()); + } + if (arch_64.IsValid()) { + if (arch_64.GetTriple().getVendor() == llvm::Triple::UnknownVendor) + arch_64.GetTriple().setVendorName(llvm::StringRef()); + } +} diff --git a/lldb/source/Host/aix/Support.cpp b/lldb/source/Host/aix/Support.cpp new file mode 100644 index 0000000000000..1bf2662190127 --- /dev/null +++ b/lldb/source/Host/aix/Support.cpp @@ -0,0 +1,44 @@ +//===-- Support.cpp -------------------------------------------------------===// +// +// 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 "lldb/Host/aix/Support.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "llvm/Support/MemoryBuffer.h" + +llvm::ErrorOr> +lldb_private::getProcFile(::pid_t pid, ::pid_t tid, const llvm::Twine &file) { + Log *log = GetLog(LLDBLog::Host); + std::string File = + ("/proc/" + llvm::Twine(pid) + "/task/" + llvm::Twine(tid) + "/" + file) + .str(); + auto Ret = llvm::MemoryBuffer::getFileAsStream(File); + if (!Ret) + LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message()); + return Ret; +} + +llvm::ErrorOr> +lldb_private::getProcFile(::pid_t pid, const llvm::Twine &file) { + Log *log = GetLog(LLDBLog::Host); + std::string File = ("/proc/" + llvm::Twine(pid) + "/" + file).str(); + auto Ret = llvm::MemoryBuffer::getFileAsStream(File); + if (!Ret) + LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message()); + return Ret; +} + +llvm::ErrorOr> +lldb_private::getProcFile(const llvm::Twine &file) { + Log *log = GetLog(LLDBLog::Host); + std::string File = ("/proc/" + file).str(); + auto Ret = llvm::MemoryBuffer::getFileAsStream(File); + if (!Ret) + LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message()); + return Ret; +} diff --git a/lldb/source/Host/common/GetOptInc.cpp b/lldb/source/Host/common/GetOptInc.cpp index c2044b6873221..e0ae2aa1774b3 100644 --- a/lldb/source/Host/common/GetOptInc.cpp +++ b/lldb/source/Host/common/GetOptInc.cpp @@ -409,7 +409,7 @@ static int getopt_internal(int nargc, char *const *nargv, const char *options, * [eventually this will replace the BSD getopt] */ #if defined(REPLACE_GETOPT) -int getopt(int nargc, char *const *nargv, const char *options) { +int getopt(int nargc, char *const *nargv, const char *options) throw() { /* * We don't pass FLAG_PERMUTE to getopt_internal() since diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index e03d36e9cad4a..2fd7111a94fb2 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -357,9 +357,183 @@ bool Host::ResolveExecutableInBundle(FileSpec &file) { return false; } #ifndef _WIN32 +#if defined(__AIX__) + +#include +extern char **p_xargv; + +/* Fix missing Dl_info & dladdr in AIX + * The code is taken from netbsd.org (src/crypto/external/bsd/openssl/dist/crypto/dso/dso_dlfcn.c) + * except strlcpy & strlcat (those are taken from openbsd.org (src/lib/libc/string)) + */ +/*- + * See IBM's AIX Version 7.2, Technical Reference: + * Base Operating System and Extensions, Volume 1 and 2 + * https://www.ibm.com/support/knowledgecenter/ssw_aix_72/com.ibm.aix.base/technicalreferences.htm + */ +#include +#include + +/* strlcpy: + * Copy string src to buffer dst of size dsize. At most dsize-1 + * chars will be copied. Always NUL terminates (unless dsize == 0). + * Returns strlen(src); if retval >= dsize, truncation occurred. + */ +size_t strlcpy(char *dst, const char *src, size_t dsize) +{ + const char *osrc = src; + size_t nleft = dsize; + + /* Copy as many bytes as will fit. */ + if (nleft != 0) { + while (--nleft != 0) { + if ((*dst++ = *src++) == '\0') { + break; + } + } + } + + /* Not enough room in dst, add NUL and traverse rest of src. */ + if (nleft == 0) { + if (dsize != 0) { + *dst = '\0'; /* NUL-terminate dst */ + } + while (*src++) { + ; + } + } + + return src - osrc - 1; /* count does not include NUL */ +} + +/* strlcat: + * Appends src to string dst of size dsize (unlike strncat, dsize is the + * full size of dst, not space left). At most dsize-1 characters + * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). + * Returns strlen(src) + MIN(dsize, strlen(initial dst)). + * If retval >= dsize, truncation occurred. + */ +size_t strlcat(char *dst, const char *src, size_t dsize) +{ + const char *odst = dst; + const char *osrc = src; + size_t n = dsize; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end. */ + while (n-- != 0 && *dst != '\0') { + dst++; + } + dlen = dst - odst; + n = dsize - dlen; + + if (n-- == 0) { + return dlen + strlen(src); + } + while (*src != '\0') { + if (n != 0) { + *dst++ = *src; + n--; + } + src++; + } + *dst = '\0'; + + return dlen + src - osrc; /* count does not include NUL */ +} + +/* ~ 64 * (sizeof(struct ld_info) + _XOPEN_PATH_MAX + _XOPEN_NAME_MAX) */ +# define DLFCN_LDINFO_SIZE 86976 +typedef struct Dl_info { + const char *dli_fname; +} Dl_info; +/* + * This dladdr()-implementation will also find the ptrgl (Pointer Glue) virtual + * address of a function, which is just located in the DATA segment instead of + * the TEXT segment. + */ +static int dladdr(const void *ptr, Dl_info *dl) +{ + uintptr_t addr = (uintptr_t)ptr; + struct ld_info *ldinfos; + struct ld_info *next_ldi; + struct ld_info *this_ldi; + + if ((ldinfos = (struct ld_info *)malloc(DLFCN_LDINFO_SIZE)) == NULL) { + dl->dli_fname = NULL; + return 0; + } + + if ((loadquery(L_GETINFO, (void *)ldinfos, DLFCN_LDINFO_SIZE)) < 0) { + /*- + * Error handling is done through errno and dlerror() reading errno: + * ENOMEM (ldinfos buffer is too small), + * EINVAL (invalid flags), + * EFAULT (invalid ldinfos ptr) + */ + free((void *)ldinfos); + dl->dli_fname = NULL; + return 0; + } + next_ldi = ldinfos; + + do { + this_ldi = next_ldi; + if (((addr >= (uintptr_t)this_ldi->ldinfo_textorg) + && (addr < ((uintptr_t)this_ldi->ldinfo_textorg + + this_ldi->ldinfo_textsize))) + || ((addr >= (uintptr_t)this_ldi->ldinfo_dataorg) + && (addr < ((uintptr_t)this_ldi->ldinfo_dataorg + + this_ldi->ldinfo_datasize)))) { + char *buffer = NULL; + char *member = NULL; + size_t buffer_sz; + size_t member_len; + + buffer_sz = strlen(this_ldi->ldinfo_filename) + 1; + member = this_ldi->ldinfo_filename + buffer_sz; + if ((member_len = strlen(member)) > 0) { + buffer_sz += 1 + member_len + 1; + } + if ((buffer = (char *)malloc(buffer_sz)) != NULL) { + strlcpy(buffer, this_ldi->ldinfo_filename, buffer_sz); + if (member_len > 0) { + /* + * Need to respect a possible member name and not just + * returning the path name in this case. See docs: + * sys/ldr.h, loadquery() and dlopen()/RTLD_MEMBER. + */ + strlcat(buffer, "(", buffer_sz); + strlcat(buffer, member, buffer_sz); + strlcat(buffer, ")", buffer_sz); + } + dl->dli_fname = buffer; + } + break; + } else { + next_ldi = (struct ld_info *)((uintptr_t)this_ldi + + this_ldi->ldinfo_next); + } + } while (this_ldi->ldinfo_next); + free((void *)ldinfos); + return dl->dli_fname != NULL; +} + +#endif + FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSpec module_filespec; #if !defined(__ANDROID__) +#ifdef __AIX__ + if (host_addr == reinterpret_cast(HostInfoBase::ComputeSharedLibraryDirectory)) { + // FIXME: AIX dladdr return "lldb" for this case + if (p_xargv[0]) { + module_filespec.SetFile(p_xargv[0], FileSpec::Style::native); + FileSystem::Instance().Resolve(module_filespec); + return module_filespec; + } + } +#endif Dl_info info; if (::dladdr(host_addr, &info)) { if (info.dli_fname) { @@ -373,12 +547,6 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { #endif -#if !defined(__linux__) -bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) { - return false; -} -#endif - struct ShellInfo { ShellInfo() : process_reaped(false) {} diff --git a/lldb/source/Host/common/LICENSE.aix-netbsd.txt b/lldb/source/Host/common/LICENSE.aix-netbsd.txt new file mode 100644 index 0000000000000..9601ab43575f9 --- /dev/null +++ b/lldb/source/Host/common/LICENSE.aix-netbsd.txt @@ -0,0 +1,125 @@ + + LICENSE ISSUES + ============== + + The OpenSSL toolkit stays under a double license, i.e. both the conditions of + the OpenSSL License and the original SSLeay license apply to the toolkit. + See below for the actual license texts. + + OpenSSL License + --------------- + +/* ==================================================================== + * Copyright (c) 1998-2019 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core at openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay at cryptsoft.com). This product includes software written by Tim + * Hudson (tjh at cryptsoft.com). + * + */ + + Original SSLeay License + ----------------------- + +/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay at cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh at cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay at cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh at cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + diff --git a/lldb/source/Host/common/XML.cpp b/lldb/source/Host/common/XML.cpp index f480ef3166a44..62cac78aaac23 100644 --- a/lldb/source/Host/common/XML.cpp +++ b/lldb/source/Host/common/XML.cpp @@ -10,6 +10,9 @@ #include "lldb/Host/XML.h" #include "llvm/ADT/StringExtras.h" +#if defined(__AIX__) +#undef LLDB_ENABLE_LIBXML2 +#endif using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index fceeff08ed9d3..143254bb12901 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -721,6 +721,7 @@ ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, ConnectionStatus ConnectionFileDescriptor::ConnectFile( llvm::StringRef s, socket_id_callback_type socket_id_callback, Status *error_ptr) { +#if !defined(__AIX__) #if LLDB_ENABLE_POSIX std::string addr_str = s.str(); // file:///PATH @@ -753,6 +754,7 @@ ConnectionStatus ConnectionFileDescriptor::ConnectFile( m_io_sp = std::make_shared(fd, File::eOpenOptionReadWrite, true); return eConnectionStatusSuccess; #endif // LLDB_ENABLE_POSIX +#endif llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX"); } diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index cdb76da626bc9..a7c50f6a3c835 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,7 +11,9 @@ // C includes #include #include +#if !defined(__AIX__) #include +#endif #include #include #include diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp index 5fe4d015251c8..e5be0db4cf19b 100644 --- a/lldb/source/Host/posix/MainLoopPosix.cpp +++ b/lldb/source/Host/posix/MainLoopPosix.cpp @@ -179,9 +179,21 @@ Status MainLoopPosix::RunImpl::Poll() { read_fds.push_back(pfd); } +#if defined(__AIX__) + sigset_t origmask; + int timeout; + + timeout = -1; + pthread_sigmask(SIG_SETMASK, &sigmask, &origmask); + int ready = poll(read_fds.data(), read_fds.size(), timeout); + pthread_sigmask(SIG_SETMASK, &origmask, nullptr); + if (ready == -1 && errno != EINTR) + return Status(errno, eErrorTypePOSIX); +#else if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 && errno != EINTR) return Status(errno, eErrorTypePOSIX); +#endif return Status(); } @@ -312,8 +324,13 @@ MainLoopPosix::RegisterSignal(int signo, const Callback &callback, // If we're using kqueue, the signal needs to be unblocked in order to // receive it. If using pselect/ppoll, we need to block it, and later unblock // it as a part of the system call. +#if defined(__AIX__) + //FIXME: where is signal unblocked? + ret = pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, &old_set); +#else ret = pthread_sigmask(HAVE_SYS_EVENT_H ? SIG_UNBLOCK : SIG_BLOCK, &new_action.sa_mask, &old_set); +#endif assert(ret == 0 && "pthread_sigmask failed"); info.was_blocked = sigismember(&old_set, signo); auto insert_ret = m_signals.insert({signo, info}); diff --git a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp index 0a832ebad13a7..cd106f605b1f4 100644 --- a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp +++ b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp @@ -193,8 +193,13 @@ struct ForkLaunchInfo { } // Start tracing this child that is about to exec. +#if !defined(__AIX__) if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1) ExitWithError(error_fd, "ptrace"); +#else + if (ptrace64(PT_TRACE_ME, 0, 0, 0, nullptr) == -1) + ExitWithError(error_fd, "ptrace"); +#endif } // Execute. We should never return... diff --git a/lldb/source/Initialization/CMakeLists.txt b/lldb/source/Initialization/CMakeLists.txt index c1a167826f76f..9f94830c8509f 100644 --- a/lldb/source/Initialization/CMakeLists.txt +++ b/lldb/source/Initialization/CMakeLists.txt @@ -1,4 +1,4 @@ -if ( CMAKE_SYSTEM_NAME MATCHES "Linux|Android|FreeBSD|NetBSD" ) +if ( CMAKE_SYSTEM_NAME MATCHES "Linux|Android|FreeBSD|NetBSD|AIX" ) list(APPEND EXTRA_PLUGINS lldbPluginProcessPOSIX) endif() diff --git a/lldb/source/Initialization/SystemInitializerCommon.cpp b/lldb/source/Initialization/SystemInitializerCommon.cpp index 1a172a95aa147..4b01442a94bac 100644 --- a/lldb/source/Initialization/SystemInitializerCommon.cpp +++ b/lldb/source/Initialization/SystemInitializerCommon.cpp @@ -19,7 +19,7 @@ #include "lldb/Version/Version.h" #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__OpenBSD__) + defined(__OpenBSD__) || defined(__AIX__) #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" #endif @@ -79,7 +79,7 @@ llvm::Error SystemInitializerCommon::Initialize() { process_gdb_remote::ProcessGDBRemoteLog::Initialize(); #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__OpenBSD__) + defined(__OpenBSD__) || defined(__AIX__) ProcessPOSIXLog::Initialize(); #endif #if defined(_WIN32) diff --git a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp index eac058701313b..feb0d7c0e09be 100644 --- a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp +++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp @@ -156,6 +156,9 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) return false; +#if defined(__AIX__) + assert(0); +#else // Read TOC pointer value. reg_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0); @@ -171,6 +174,132 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, (uint64_t)reg_value); if (!process_sp->WritePointerToMemory(sp + stack_offset, reg_value, error)) return false; +#endif + + // Read the current SP value. + reg_value = reg_ctx->ReadRegisterAsUnsigned(sp_reg_info, 0); + + // Save current SP onto the stack. + LLDB_LOGF(log, "Writing SP at SP(0x%" PRIx64 ")+0: 0x%" PRIx64, (uint64_t)sp, + (uint64_t)reg_value); + if (!process_sp->WritePointerToMemory(sp, reg_value, error)) + return false; + + // %r1 is set to the actual stack value. + LLDB_LOGF(log, "Writing SP: 0x%" PRIx64, (uint64_t)sp); + + if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_info, sp)) + return false; + + // %pc is set to the address of the called function. + + LLDB_LOGF(log, "Writing IP: 0x%" PRIx64, (uint64_t)func_addr); + + if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_info, func_addr)) + return false; + + return true; +} + +bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, + addr_t func_addr, addr_t toc_addr, + addr_t return_addr, + llvm::ArrayRef args) const { + Log *log = GetLog(LLDBLog::Expressions); + + if (log) { + StreamString s; + s.Printf("ABISysV_ppc64::PrepareTrivialCall (tid = 0x%" PRIx64 + ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 + ", return_addr = 0x%" PRIx64, + thread.GetID(), (uint64_t)sp, (uint64_t)func_addr, + (uint64_t)return_addr); + + for (size_t i = 0; i < args.size(); ++i) + s.Printf(", arg%" PRIu64 " = 0x%" PRIx64, static_cast(i + 1), + args[i]); + s.PutCString(")"); + log->PutString(s.GetString()); + } + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return false; + + const RegisterInfo *reg_info = nullptr; + + if (args.size() > 8) // TODO handle more than 8 arguments + return false; + + for (size_t i = 0; i < args.size(); ++i) { + reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_ARG1 + i); + LLDB_LOGF(log, "About to write arg%" PRIu64 " (0x%" PRIx64 ") into %s", + static_cast(i + 1), args[i], reg_info->name); + if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) + return false; + } + + // First, align the SP + + LLDB_LOGF(log, "16-byte aligning SP: 0x%" PRIx64 " to 0x%" PRIx64, + (uint64_t)sp, (uint64_t)(sp & ~0xfull)); + + sp &= ~(0xfull); // 16-byte alignment + + sp -= 544; // allocate frame to save TOC, RA and SP. + + Status error; + uint64_t reg_value; + const RegisterInfo *pc_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + const RegisterInfo *sp_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); + ProcessSP process_sp(thread.GetProcess()); + const RegisterInfo *lr_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); + const RegisterInfo *r2_reg_info = reg_ctx->GetRegisterInfoAtIndex(2); + const RegisterInfo *r12_reg_info = reg_ctx->GetRegisterInfoAtIndex(12); + + // Save return address onto the stack. + LLDB_LOGF(log, + "Pushing the return address onto the stack: 0x%" PRIx64 + "(+16): 0x%" PRIx64, + (uint64_t)sp, (uint64_t)return_addr); + if (!process_sp->WritePointerToMemory(sp + 16, return_addr, error)) + return false; + + // Write the return address to link register. + LLDB_LOGF(log, "Writing LR: 0x%" PRIx64, (uint64_t)return_addr); + if (!reg_ctx->WriteRegisterFromUnsigned(lr_reg_info, return_addr)) + return false; + + // Write target address to %r12 register. + LLDB_LOGF(log, "Writing R12: 0x%" PRIx64, (uint64_t)func_addr); + if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) + return false; + +#if defined(__AIX__) + LLDB_LOGF(log, "Writing R2: 0x%" PRIx64, (uint64_t)toc_addr); + if (!reg_ctx->WriteRegisterFromUnsigned(r2_reg_info, toc_addr)) + return false; +#else + // Read TOC pointer value. + reg_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0); + + // Write TOC pointer onto the stack. + uint64_t stack_offset; + if (GetByteOrder() == lldb::eByteOrderLittle) + stack_offset = 24; + else + stack_offset = 40; + + LLDB_LOGF(log, "Writing R2 (TOC) at SP(0x%" PRIx64 ")+%d: 0x%" PRIx64, + (uint64_t)(sp + stack_offset), (int)stack_offset, + (uint64_t)reg_value); + if (!process_sp->WritePointerToMemory(sp + stack_offset, reg_value, error)) + return false; +#endif // Read the current SP value. reg_value = reg_ctx->ReadRegisterAsUnsigned(sp_reg_info, 0); @@ -641,7 +770,7 @@ class ReturnValueExtractor { DataExtractor de(&raw_data, sizeof(raw_data), m_byte_order, m_addr_size); - offset_t offset = 0; + lldb::offset_t offset = 0; std::optional byte_size = type.GetByteSize(m_process_sp.get()); if (!byte_size) return {}; diff --git a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h index bfa96cc0df703..d752a8ded9748 100644 --- a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h +++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h @@ -23,6 +23,12 @@ class ABISysV_ppc64 : public lldb_private::RegInfoBasedABI { lldb::addr_t returnAddress, llvm::ArrayRef args) const override; + bool PrepareTrivialCall(lldb_private::Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t tocAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef args) const override; + bool GetArgumentValues(lldb_private::Thread &thread, lldb_private::ValueList &values) const override; diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt new file mode 100644 index 0000000000000..02fe0d617955a --- /dev/null +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt @@ -0,0 +1,11 @@ +add_definitions("-D_ALL_SOURCE") + +add_lldb_library(lldbPluginDynamicLoaderAIXDYLD PLUGIN + DynamicLoaderAIXDYLD.cpp + + LINK_LIBS + lldbCore + lldbTarget + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp new file mode 100644 index 0000000000000..62663974134b0 --- /dev/null +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -0,0 +1,272 @@ +//===-- DynamicLoaderAIXDYLD.cpp --------------------------------------===// +// +// 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 "DynamicLoaderAIXDYLD.h" + +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Platform.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/ThreadPlanStepInstruction.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#if defined(__AIX__) +#include +#endif + +/*#include "llvm/ADT/Triple.h" +*/ + +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(DynamicLoaderAIXDYLD) + +DynamicLoaderAIXDYLD::DynamicLoaderAIXDYLD(Process *process) + : DynamicLoader(process) {} + +DynamicLoaderAIXDYLD::~DynamicLoaderAIXDYLD() = default; + +void DynamicLoaderAIXDYLD::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); +} + +void DynamicLoaderAIXDYLD::Terminate() {} + +llvm::StringRef DynamicLoaderAIXDYLD::GetPluginDescriptionStatic() { + return "Dynamic loader plug-in that watches for shared library " + "loads/unloads in AIX processes."; +} + +DynamicLoader *DynamicLoaderAIXDYLD::CreateInstance(Process *process, + bool force) { + bool should_create = force; + if (!should_create) { + const llvm::Triple &triple_ref = + process->GetTarget().GetArchitecture().GetTriple(); + if (triple_ref.getOS() == llvm::Triple::AIX) + should_create = true; + } + + if (should_create) + return new DynamicLoaderAIXDYLD(process); + + return nullptr; +} + +void DynamicLoaderAIXDYLD::OnLoadModule(lldb::ModuleSP module_sp, + const ModuleSpec module_spec, + lldb::addr_t module_addr) { + + // Resolve the module unless we already have one. + if (!module_sp) { + Status error; + module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, + true /* notify */, &error); + if (error.Fail()) + return; + } + + m_loaded_modules[module_sp] = module_addr; + UpdateLoadedSectionsCommon(module_sp, module_addr, false); + ModuleList module_list; + module_list.Append(module_sp); + m_process->GetTarget().ModulesDidLoad(module_list); +} + +void DynamicLoaderAIXDYLD::OnUnloadModule(lldb::addr_t module_addr) { + Address resolved_addr; + if (!m_process->GetTarget().ResolveLoadAddress(module_addr, resolved_addr)) + return; + + ModuleSP module_sp = resolved_addr.GetModule(); + if (module_sp) { + m_loaded_modules.erase(module_sp); + UnloadSectionsCommon(module_sp); + ModuleList module_list; + module_list.Append(module_sp); + m_process->GetTarget().ModulesDidUnload(module_list, false); + } +} + +lldb::addr_t DynamicLoaderAIXDYLD::GetLoadAddress(ModuleSP executable) { + // First, see if the load address is already cached. + auto it = m_loaded_modules.find(executable); + if (it != m_loaded_modules.end() && it->second != LLDB_INVALID_ADDRESS) + return it->second; + + lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; + + // Second, try to get it through the process plugins. For a remote process, + // the remote platform will be responsible for providing it. + FileSpec file_spec(executable->GetPlatformFileSpec()); + bool is_loaded = false; + Status status = + m_process->GetFileLoadAddress(file_spec, is_loaded, load_addr); + // Servers other than lldb server could respond with a bogus address. + if (status.Success() && is_loaded && load_addr != LLDB_INVALID_ADDRESS) { + m_loaded_modules[executable] = load_addr; + return load_addr; + } + + //// Hack to try set breakpoint + //Breakpoint *dyld_break = m_process->GetTarget().CreateBreakpoint(0x100000638, true, false).get(); + //dyld_break->SetCallback(DynamicLoaderAIXDYLD::NotifyBreakpointHit, this, true); + //dyld_break->SetBreakpointKind("hack-debug"); + + return LLDB_INVALID_ADDRESS; +} + +bool DynamicLoaderAIXDYLD::NotifyBreakpointHit( + void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, + lldb::user_id_t break_loc_id) { +} + +void DynamicLoaderAIXDYLD::DidAttach() { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); + + ModuleSP executable = GetTargetExecutable(); + + if (!executable.get()) + return; + + // Try to fetch the load address of the file from the process, since there + // could be randomization of the load address. + lldb::addr_t load_addr = GetLoadAddress(executable); + if (load_addr == LLDB_INVALID_ADDRESS) + return; + + // Request the process base address. + lldb::addr_t image_base = m_process->GetImageInfoAddress(); + if (image_base == load_addr) + return; + + // Rebase the process's modules if there is a mismatch. + UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_addr, false); + + ModuleList module_list; + module_list.Append(executable); + m_process->GetTarget().ModulesDidLoad(module_list); + auto error = m_process->LoadModules(); + LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}"); + +#if defined(__AIX__) + // Get struct ld_xinfo (FIXME) + struct ld_xinfo ldinfo[64]; + Status status = m_process->GetLDXINFO(&(ldinfo[0])); + if (status.Fail()) { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOG(log, "LDXINFO failed: {0}", status); + return; + } + struct ld_xinfo *ptr = &(ldinfo[0]); + bool skip_current = true; + while (ptr != nullptr) { + char *pathName = (char *)ptr + ptr->ldinfo_filename; + char *memberName = pathName + (strlen(pathName) + 1); + if (!skip_current) { + // FIXME: buffer size + char pathWithMember[128] = {0}; + if (strlen(memberName) > 0) { + sprintf(pathWithMember, "%s(%s)", pathName, memberName); + } else { + sprintf(pathWithMember, "%s", pathName); + } + FileSpec file(pathWithMember); + ModuleSpec module_spec(file, m_process->GetTarget().GetArchitecture()); + if (ModuleSP module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, true /* notify */)) { + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_textorg, false, 1); + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_dataorg, false, 2); + // FIXME: .tdata, .bss + } + } else { + skip_current = false; + } + if (ptr->ldinfo_next == 0) { + ptr = nullptr; + } else { + ptr = (struct ld_xinfo *)((char *)ptr + ptr->ldinfo_next); + } + } +#endif +} + +void DynamicLoaderAIXDYLD::DidLaunch() { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); + + ModuleSP executable = GetTargetExecutable(); + if (!executable.get()) + return; + + lldb::addr_t load_addr = GetLoadAddress(executable); + if (load_addr != LLDB_INVALID_ADDRESS) { + // Update the loaded sections so that the breakpoints can be resolved. + UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_addr, false); + + ModuleList module_list; + module_list.Append(executable); + m_process->GetTarget().ModulesDidLoad(module_list); + auto error = m_process->LoadModules(); + LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}"); + } + +#if defined(__AIX__) + // Get struct ld_xinfo (FIXME) + struct ld_xinfo ldinfo[64]; + Status status = m_process->GetLDXINFO(&(ldinfo[0])); + if (status.Fail()) { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOG(log, "LDXINFO failed: {0}", status); + return; + } + struct ld_xinfo *ptr = &(ldinfo[0]); + bool skip_current = true; + while (ptr != nullptr) { + char *pathName = (char *)ptr + ptr->ldinfo_filename; + char *memberName = pathName + (strlen(pathName) + 1); + if (!skip_current) { + // FIXME: buffer size + char pathWithMember[128] = {0}; + if (strlen(memberName) > 0) { + sprintf(pathWithMember, "%s(%s)", pathName, memberName); + } else { + sprintf(pathWithMember, "%s", pathName); + } + FileSpec file(pathWithMember); + ModuleSpec module_spec(file, m_process->GetTarget().GetArchitecture()); + if (ModuleSP module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, true /* notify */)) { + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_textorg, false, 1); + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_dataorg, false, 2); + // FIXME: .tdata, .bss + } + } else { + skip_current = false; + } + if (ptr->ldinfo_next == 0) { + ptr = nullptr; + } else { + ptr = (struct ld_xinfo *)((char *)ptr + ptr->ldinfo_next); + } + } +#endif +} + +Status DynamicLoaderAIXDYLD::CanLoadImage() { return Status(); } + +ThreadPlanSP +DynamicLoaderAIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, + bool stop) { + //FIXME + return ThreadPlanSP(); +} diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h new file mode 100644 index 0000000000000..ae4b7aca66dcc --- /dev/null +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -0,0 +1,55 @@ +//===-- DynamicLoaderAIXDYLD.h ------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_DYNAMICLOADER_AIX_DYLD_DYNAMICLOADERAIXDYLD_H +#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_AIX_DYLD_DYNAMICLOADERAIXDYLD_H + +#include "lldb/Target/DynamicLoader.h" +#include "lldb/lldb-forward.h" + +#include + +namespace lldb_private { + +class DynamicLoaderAIXDYLD : public DynamicLoader { +public: + DynamicLoaderAIXDYLD(Process *process); + + ~DynamicLoaderAIXDYLD() override; + + static void Initialize(); + static void Terminate(); + static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; } + static llvm::StringRef GetPluginDescriptionStatic(); + + static DynamicLoader *CreateInstance(Process *process, bool force); + + void OnLoadModule(lldb::ModuleSP module_sp, const ModuleSpec module_spec, + lldb::addr_t module_addr); + void OnUnloadModule(lldb::addr_t module_addr); + + void DidAttach() override; + void DidLaunch() override; + Status CanLoadImage() override; + lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread, + bool stop) override; + + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + static bool NotifyBreakpointHit(void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id); + +protected: + lldb::addr_t GetLoadAddress(lldb::ModuleSP executable); + +private: + std::map m_loaded_modules; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_AIX_DYLD_DYNAMICLOADERWAIXDYLD_H diff --git a/lldb/source/Plugins/DynamicLoader/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/CMakeLists.txt index 30607159acdc0..4f3fb693faae1 100644 --- a/lldb/source/Plugins/DynamicLoader/CMakeLists.txt +++ b/lldb/source/Plugins/DynamicLoader/CMakeLists.txt @@ -5,4 +5,5 @@ add_subdirectory(POSIX-DYLD) add_subdirectory(Static) add_subdirectory(Hexagon-DYLD) add_subdirectory(Windows-DYLD) +add_subdirectory(AIX-DYLD) add_subdirectory(wasm-DYLD) diff --git a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp index 20e5652c65bf8..26abea0fdd24d 100644 --- a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp +++ b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp @@ -256,7 +256,7 @@ DynamicLoaderDarwinKernel::SearchForKernelWithDebugHints(Process *process) { if (process->ReadMemoryFromInferior (kernel_addresses_64[i], uval, 8, read_err) == 8) { DataExtractor data (&uval, 8, process->GetByteOrder(), process->GetAddressByteSize()); - offset_t offset = 0; + lldb::offset_t offset = 0; uint64_t addr = data.GetU64 (&offset); if (CheckForKernelImageAtAddress(addr, process).IsValid()) { return addr; @@ -270,7 +270,7 @@ DynamicLoaderDarwinKernel::SearchForKernelWithDebugHints(Process *process) { if (process->ReadMemoryFromInferior (kernel_addresses_32[i], uval, 4, read_err) == 4) { DataExtractor data (&uval, 4, process->GetByteOrder(), process->GetAddressByteSize()); - offset_t offset = 0; + lldb::offset_t offset = 0; uint32_t addr = data.GetU32 (&offset); if (CheckForKernelImageAtAddress(addr, process).IsValid()) { return addr; diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp index 3863b6b3520db..624848dee6ec3 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp @@ -1151,7 +1151,7 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp, // TLS data for the pthread_key on a specific thread yet. If we have we // can re-use it since its location will not change unless the process // execs. - const tid_t tid = thread_sp->GetID(); + const lldb::tid_t tid = thread_sp->GetID(); auto tid_pos = m_tid_to_tls_map.find(tid); if (tid_pos != m_tid_to_tls_map.end()) { auto tls_pos = tid_pos->second.find(key); diff --git a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp index 3035c51341778..d14ae2daeb47d 100644 --- a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp +++ b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp @@ -146,7 +146,25 @@ EmulateInstructionPPC64::GetOpcodeForInstruction(uint32_t opcode) { {0xfc000000, 0x38000000, &EmulateInstructionPPC64::EmulateADDI, "addi RT, RA, SI"}, {0xfc000003, 0xe8000000, &EmulateInstructionPPC64::EmulateLD, - "ld RT, DS(RA)"}}; + "ld RT, DS(RA)"}, +// {0xffff0003, 0x40820000, &EmulateInstructionPPC64::EmulateBNE, +// "bne TARGET"}, + {0xfc000002, 0x48000000, &EmulateInstructionPPC64::EmulateB, + "b TARGET"}, + {0xfc000003, 0x48000002, &EmulateInstructionPPC64::EmulateBA, + "ba TARGET"}, + {0xfc000003, 0x48000003, &EmulateInstructionPPC64::EmulateBLA, + "bla TARGET"}, + {0xfc000002, 0x40000000, &EmulateInstructionPPC64::EmulateBC, + "bc BO,BI,TARGET"}, + {0xfc000002, 0x40000002, &EmulateInstructionPPC64::EmulateBCA, + "bca BO,BI,TARGET"}, + {0xfc0007fe, 0x4c000020, &EmulateInstructionPPC64::EmulateBCLR, + "bclr BO,BI,BH"}, + {0xfc0007fe, 0x4c000420, &EmulateInstructionPPC64::EmulateBCCTR, + "bcctr BO,BI,BH"}, + {0xfc0007fe, 0x4c000460, &EmulateInstructionPPC64::EmulateBCTAR, + "bctar BO,BI,BH"}}; static const size_t k_num_ppc_opcodes = std::size(g_opcodes); for (size_t i = 0; i < k_num_ppc_opcodes; ++i) { @@ -169,12 +187,13 @@ bool EmulateInstructionPPC64::EvaluateInstruction(uint32_t evaluate_options) { bool success = false; - uint32_t orig_pc_value = 0; + uint64_t orig_pc_value = 0; if (auto_advance_pc) { orig_pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); if (!success) return false; + LLDB_LOG(GetLog(LLDBLog::Unwind), "orig_pc_value:{0}", orig_pc_value); } // Call the Emulate... function. @@ -183,11 +202,13 @@ bool EmulateInstructionPPC64::EvaluateInstruction(uint32_t evaluate_options) { return false; if (auto_advance_pc) { - uint32_t new_pc_value = + uint64_t new_pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); if (!success) return false; + LLDB_LOG(GetLog(LLDBLog::Unwind), "new_pc_value:{0}", new_pc_value); + if (new_pc_value == orig_pc_value) { EmulateInstruction::Context context; context.type = eContextAdvancePC; @@ -389,5 +410,174 @@ bool EmulateInstructionPPC64::EmulateADDI(uint32_t opcode) { return false; WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_r1_ppc64le, r1 + si_val); LLDB_LOG(log, "EmulateADDI: success!"); + + // FIX the next-pc + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + + return true; +} + +bool EmulateInstructionPPC64::EmulateBC(uint32_t opcode) { + // FIXME:32bit M + uint32_t M = 0; + uint32_t target32 = Bits32(opcode, 15, 2) << 2; + uint64_t target = (uint64_t)target32 + ((target32 & 0x8000) ? 0xffffffffffff0000UL : 0); + uint32_t BO = Bits32(opcode, 25, 21); + bool success; + uint64_t ctr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success); + if ((~BO) & (1U << 2)) + ctr_value = ctr_value - 1; + bool ctr_ok = (bool)(BO & (1U << 2)) | ((bool)(ctr_value != 0) ^ (bool)(BO & (1U << 1))); + uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success); + uint32_t BI = Bits32(opcode, 20, 16); + bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U)); + + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + if (ctr_ok & cond_ok) + next_pc = pc_value + target; + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + Log *log = GetLog(LLDBLog::Unwind); + LLDB_LOG(log, "EmulateBC: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBCA(uint32_t opcode) { + // FIXME:32bit M + uint32_t M = 0; + uint32_t target32 = Bits32(opcode, 15, 2) << 2; + uint64_t target = (uint64_t)target32 + ((target32 & 0x8000) ? 0xffffffffffff0000UL : 0); + uint32_t BO = Bits32(opcode, 25, 21); + bool success; + uint64_t ctr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success); + if ((~BO) & (1U << 2)) + ctr_value = ctr_value - 1; + bool ctr_ok = (bool)(BO & (1U << 2)) | ((bool)(ctr_value != 0) ^ (bool)(BO & (1U << 1))); + uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success); + uint32_t BI = Bits32(opcode, 20, 16); + bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U)); + + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + if (ctr_ok & cond_ok) + next_pc = target; + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + Log *log = GetLog(LLDBLog::Unwind); + LLDB_LOG(log, "EmulateBCA: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBCLR(uint32_t opcode) { + // FIXME:32bit M + uint32_t M = 0; + uint32_t BO = Bits32(opcode, 25, 21); + bool success; + uint64_t ctr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success); + if ((~BO) & (1U << 2)) + ctr_value = ctr_value - 1; + bool ctr_ok = (bool)(BO & (1U << 2)) | ((bool)(ctr_value != 0) ^ (bool)(BO & (1U << 1))); + uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success); + uint32_t BI = Bits32(opcode, 20, 16); + bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U)); + + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + if (ctr_ok & cond_ok) { + next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success); + next_pc &= ~((1UL << 2) - 1); + } + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + Log *log = GetLog(LLDBLog::Unwind); + LLDB_LOG(log, "EmulateBCLR: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBCCTR(uint32_t opcode) { + // FIXME:32bit M + uint32_t M = 0; + uint32_t BO = Bits32(opcode, 25, 21); + bool success; + uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success); + uint32_t BI = Bits32(opcode, 20, 16); + bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U)); + + Log *log = GetLog(LLDBLog::Unwind); + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + if (cond_ok) { + next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success); + next_pc &= ~((1UL << 2) - 1); + if (next_pc < 0x4000000) { + LLDB_LOGF(log, "EmulateBCCTR: next address %lx out of range, emulate by goto LR!"); + next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success); + } + } + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + LLDB_LOG(log, "EmulateBCCTR: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBCTAR(uint32_t opcode) { + // Not supported yet. + LLDB_LOG(GetLog(LLDBLog::Unwind), "EmulateBCTAR: not supported!"); + assert(0); + return false; +} + +bool EmulateInstructionPPC64::EmulateB(uint32_t opcode) { + uint32_t target32 = Bits32(opcode, 25, 2) << 2; + uint64_t target = (uint64_t)target32 + ((target32 & 0x2000000) ? 0xfffffffffc000000UL : 0); + + bool success; + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + target; + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + Log *log = GetLog(LLDBLog::Unwind); + LLDB_LOG(log, "EmulateB: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBA(uint32_t opcode) { + Log *log = GetLog(LLDBLog::Unwind); + + bool success; + uint64_t next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success); + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + LLDB_LOG(log, "EmulateBA: emulate by branch to lr!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBLA(uint32_t opcode) { + Log *log = GetLog(LLDBLog::Unwind); + + bool success; + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + LLDB_LOG(log, "EmulateBLA: emulate by branch to lr!"); return true; } diff --git a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h index a9424f16b0ad0..1576c9700e557 100644 --- a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h +++ b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h @@ -39,6 +39,12 @@ class EmulateInstructionPPC64 : public EmulateInstruction { return true; case eInstructionTypePCModifying: +#if defined(__AIX__) + return true; +#else + return false; +#endif + case eInstructionTypeAll: return false; } @@ -84,6 +90,14 @@ class EmulateInstructionPPC64 : public EmulateInstruction { bool EmulateSTD(uint32_t opcode); bool EmulateOR(uint32_t opcode); bool EmulateADDI(uint32_t opcode); + bool EmulateB(uint32_t opcode); + bool EmulateBA(uint32_t opcode); + bool EmulateBLA(uint32_t opcode); + bool EmulateBC(uint32_t opcode); + bool EmulateBCA(uint32_t opcode); + bool EmulateBCLR(uint32_t opcode); + bool EmulateBCCTR(uint32_t opcode); + bool EmulateBCTAR(uint32_t opcode); }; } // namespace lldb_private diff --git a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp index b7cd2b1ac6bf6..876e74056face 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp @@ -261,7 +261,7 @@ InstrumentationRuntimeMainThreadChecker::GetBacktracesFromExtendedStopInfo( StructuredData::ObjectSP thread_id_obj = info->GetObjectForDotSeparatedPath("tid"); - tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; + lldb::tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; // We gather symbolication addresses above, so no need for HistoryThread to // try to infer the call addresses. diff --git a/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp b/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp index b2781aa5e7db1..7a827a3ea76f9 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp @@ -770,13 +770,13 @@ std::string InstrumentationRuntimeTSan::GetLocationDescription( Sprintf("Location is a %ld-byte heap object at 0x%llx", size, addr); } } else if (type == "stack") { - tid_t tid = loc->GetAsDictionary() + lldb::tid_t tid = loc->GetAsDictionary() ->GetValueForKey("thread_id") ->GetUnsignedIntegerValue(); result = Sprintf("Location is stack of thread %d", tid); } else if (type == "tls") { - tid_t tid = loc->GetAsDictionary() + lldb::tid_t tid = loc->GetAsDictionary() ->GetValueForKey("thread_id") ->GetUnsignedIntegerValue(); @@ -948,7 +948,7 @@ static std::string GenerateThreadName(const std::string &path, if (path == "mops") { size_t size = o->GetObjectForDotSeparatedPath("size")->GetUnsignedIntegerValue(); - tid_t thread_id = + lldb::tid_t thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); bool is_write = o->GetObjectForDotSeparatedPath("is_write")->GetBooleanValue(); @@ -979,7 +979,7 @@ static std::string GenerateThreadName(const std::string &path, } if (path == "threads") { - tid_t thread_id = + lldb::tid_t thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); result = Sprintf("Thread %zu created", thread_id); } @@ -987,7 +987,7 @@ static std::string GenerateThreadName(const std::string &path, if (path == "locs") { std::string type = std::string( o->GetAsDictionary()->GetValueForKey("type")->GetStringValue()); - tid_t thread_id = + lldb::tid_t thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); int fd = o->GetObjectForDotSeparatedPath("file_descriptor") ->GetSignedIntegerValue(); @@ -1007,7 +1007,7 @@ static std::string GenerateThreadName(const std::string &path, } if (path == "stacks") { - tid_t thread_id = + lldb::tid_t thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); result = Sprintf("Thread %" PRIu64, thread_id); } @@ -1034,7 +1034,7 @@ static void AddThreadsForPath(const std::string &path, StructuredData::ObjectSP thread_id_obj = o->GetObjectForDotSeparatedPath("thread_os_id"); - tid_t tid = + lldb::tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; ThreadSP new_thread_sp = diff --git a/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp index 1c58922e8d36c..de9719ad4a89e 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp @@ -321,7 +321,7 @@ InstrumentationRuntimeUBSan::GetBacktracesFromExtendedStopInfo( StructuredData::ObjectSP thread_id_obj = info->GetObjectForDotSeparatedPath("tid"); - tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; + lldb::tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; // We gather symbolication addresses above, so no need for HistoryThread to // try to infer the call addresses. diff --git a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp index 1688fb27430a7..690fb0d60a09a 100644 --- a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp +++ b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp @@ -194,6 +194,10 @@ void JITLoaderGDB::SetJITBreakpoint(lldb_private::ModuleList &module_list) { if (jit_addr == LLDB_INVALID_ADDRESS) return; +#if defined(__AIX__) + return; +#endif + m_jit_descriptor_addr = GetSymbolAddress( module_list, ConstString("__jit_debug_descriptor"), eSymbolTypeData); if (m_jit_descriptor_addr == LLDB_INVALID_ADDRESS) { diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index 341923108e321..fb5bc2c58e6fb 100644 --- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -1227,6 +1227,7 @@ bool lldb_private::formatters::ObjCSELSummaryProvider( time_t lldb_private::formatters::GetOSXEpoch() { static time_t epoch = 0; if (!epoch) { +#if !defined(__AIX__) #ifndef _WIN32 tzset(); tm tm_epoch; @@ -1240,6 +1241,7 @@ time_t lldb_private::formatters::GetOSXEpoch() { tm_epoch.tm_gmtoff = 0; tm_epoch.tm_zone = nullptr; epoch = timegm(&tm_epoch); +#endif #endif } return epoch; diff --git a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp index 6efd2516578ff..fe6c5a0544be3 100644 --- a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp +++ b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp @@ -107,7 +107,7 @@ static void CreateHistoryThreadFromValueObject(ProcessSP process_sp, return; int count = count_sp->GetValueAsUnsigned(0); - tid_t tid = tid_sp->GetValueAsUnsigned(0) + 1; + lldb::tid_t tid = tid_sp->GetValueAsUnsigned(0) + 1; if (count <= 0) return; diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 7aa5b8d81890a..5ea55772c3aba 100644 --- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -8,7 +8,7 @@ #include "ObjectContainerBSDArchive.h" -#if defined(_WIN32) || defined(__ANDROID__) +#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__) // Defines from ar, missing on Windows #define SARMAG 8 #define ARFMAG "`\n" diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt b/lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt new file mode 100644 index 0000000000000..612a36265b536 --- /dev/null +++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt @@ -0,0 +1,10 @@ +add_lldb_library(lldbPluginObjectContainerBigArchive PLUGIN + ObjectContainerBigArchive.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp new file mode 100644 index 0000000000000..050ad73f1d19a --- /dev/null +++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp @@ -0,0 +1,522 @@ +//===-- ObjectContainerBigArchive.cpp -------------------------------------===// +// +// 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 "ObjectContainerBigArchive.h" + +#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__) +// Defines from ar, missing on Windows +#define ARMAG "!\n" +#define SARMAG 8 +#define ARFMAG "`\n" + +typedef struct ar_hdr { + char ar_name[16]; + char ar_date[12]; + char ar_uid[6], ar_gid[6]; + char ar_mode[8]; + char ar_size[10]; + char ar_fmag[2]; +} ar_hdr; +#else +#include +#endif + +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/Timer.h" + +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Object/Archive.h" +#include "llvm/Support/Chrono.h" + +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ObjectContainerBigArchive) + +ObjectContainerBigArchive::Object::Object() : ar_name() {} + +void ObjectContainerBigArchive::Object::Clear() { + ar_name.Clear(); + modification_time = 0; + uid = 0; + gid = 0; + mode = 0; + size = 0; + file_offset = 0; + file_size = 0; +} + +lldb::offset_t +ObjectContainerBigArchive::Object::Extract(const DataExtractor &data, + lldb::offset_t offset) { + size_t ar_name_len = 0; + std::string str; + char *err; + + // File header + // + // The common format is as follows. + // + // Offset Length Name Format + // 0 16 File name ASCII right padded with spaces (no spaces + // allowed in file name) + // 16 12 File mod Decimal as cstring right padded with + // spaces + // 28 6 Owner ID Decimal as cstring right padded with + // spaces + // 34 6 Group ID Decimal as cstring right padded with + // spaces + // 40 8 File mode Octal as cstring right padded with + // spaces + // 48 10 File byte size Decimal as cstring right padded with + // spaces + // 58 2 File magic 0x60 0x0A + + // Make sure there is enough data for the file header and bail if not + if (!data.ValidOffsetForDataOfSize(offset, 60)) + return LLDB_INVALID_OFFSET; + + str.assign((const char *)data.GetData(&offset, 16), 16); + if (llvm::StringRef(str).starts_with("#1/")) { + // If the name is longer than 16 bytes, or contains an embedded space then + // it will use this format where the length of the name is here and the + // name characters are after this header. + ar_name_len = strtoul(str.c_str() + 3, &err, 10); + } else { + // Strip off any trailing spaces. + const size_t last_pos = str.find_last_not_of(' '); + if (last_pos != std::string::npos) { + if (last_pos + 1 < 16) + str.erase(last_pos + 1); + } + ar_name.SetCString(str.c_str()); + } + + str.assign((const char *)data.GetData(&offset, 12), 12); + modification_time = strtoul(str.c_str(), &err, 10); + + str.assign((const char *)data.GetData(&offset, 6), 6); + uid = strtoul(str.c_str(), &err, 10); + + str.assign((const char *)data.GetData(&offset, 6), 6); + gid = strtoul(str.c_str(), &err, 10); + + str.assign((const char *)data.GetData(&offset, 8), 8); + mode = strtoul(str.c_str(), &err, 8); + + str.assign((const char *)data.GetData(&offset, 10), 10); + size = strtoul(str.c_str(), &err, 10); + + str.assign((const char *)data.GetData(&offset, 2), 2); + if (str == ARFMAG) { + if (ar_name_len > 0) { + const void *ar_name_ptr = data.GetData(&offset, ar_name_len); + // Make sure there was enough data for the string value and bail if not + if (ar_name_ptr == nullptr) + return LLDB_INVALID_OFFSET; + str.assign((const char *)ar_name_ptr, ar_name_len); + ar_name.SetCString(str.c_str()); + } + file_offset = offset; + file_size = size - ar_name_len; + return offset; + } + return LLDB_INVALID_OFFSET; +} + +ObjectContainerBigArchive::Archive::Archive(const lldb_private::ArchSpec &arch, + const llvm::sys::TimePoint<> &time, + lldb::offset_t file_offset, + lldb_private::DataExtractor &data) + : m_arch(arch), m_modification_time(time), m_file_offset(file_offset), + m_objects(), m_data(data) {} + +ObjectContainerBigArchive::Archive::~Archive() = default; + +size_t ObjectContainerBigArchive::Archive::ParseObjects() { + DataExtractor &data = m_data; + std::string str; + lldb::offset_t offset = 0; + str.assign((const char *)data.GetData(&offset, (sizeof(llvm::object::BigArchiveMagic) - 1)), + (sizeof(llvm::object::BigArchiveMagic) - 1)); + if (str == llvm::object::BigArchiveMagic) { + llvm::Error err = llvm::Error::success(); + llvm::object::BigArchive bigAr(llvm::MemoryBufferRef(toStringRef(m_data.GetData()), llvm::StringRef("")), err); + if (err) + return 0; + + for (const llvm::object::Archive::Child &child : bigAr.children(err)) { + if (err) + continue; + if (!child.getParent()) + continue; + Object obj; + obj.Clear(); + // FIXME: check errors + llvm::Expected childNameOrErr = child.getName(); + if (!childNameOrErr) + continue; + obj.ar_name.SetCString(childNameOrErr->str().c_str()); + llvm::Expected> lastModifiedOrErr = child.getLastModified(); + if (!lastModifiedOrErr) + continue; + obj.modification_time = (uint32_t)llvm::sys::toTimeT(*(lastModifiedOrErr)); + llvm::Expected getUIDOrErr = child.getUID(); + if (!getUIDOrErr) + continue; + obj.uid = (uint16_t)*getUIDOrErr; + llvm::Expected getGIDOrErr = child.getGID(); + if (!getGIDOrErr) + continue; + obj.gid = (uint16_t)*getGIDOrErr; + llvm::Expected getAccessModeOrErr = child.getAccessMode(); + if (!getAccessModeOrErr) + continue; + obj.mode = (uint16_t)*getAccessModeOrErr; + llvm::Expected getRawSizeOrErr = child.getRawSize(); + if (!getRawSizeOrErr) + continue; + obj.size = (uint32_t)*getRawSizeOrErr; + + obj.file_offset = (lldb::offset_t)child.getDataOffset(); + + llvm::Expected getSizeOrErr = child.getSize(); + if (!getSizeOrErr) + continue; + obj.file_size = (lldb::offset_t)*getSizeOrErr; + + size_t obj_idx = m_objects.size(); + m_objects.push_back(obj); + // Insert all of the C strings out of order for now... + m_object_name_to_index_map.Append(obj.ar_name, obj_idx); + } + if (err) + return 0; + + // Now sort all of the object name pointers + m_object_name_to_index_map.Sort(); + } + return m_objects.size(); +} + +ObjectContainerBigArchive::Object * +ObjectContainerBigArchive::Archive::FindObject( + ConstString object_name, const llvm::sys::TimePoint<> &object_mod_time) { + const ObjectNameToIndexMap::Entry *match = + m_object_name_to_index_map.FindFirstValueForName(object_name); + if (!match) + return nullptr; + if (object_mod_time == llvm::sys::TimePoint<>()) + return &m_objects[match->value]; + + const uint64_t object_modification_date = llvm::sys::toTimeT(object_mod_time); + if (m_objects[match->value].modification_time == object_modification_date) + return &m_objects[match->value]; + + const ObjectNameToIndexMap::Entry *next_match = + m_object_name_to_index_map.FindNextValueForName(match); + while (next_match) { + if (m_objects[next_match->value].modification_time == + object_modification_date) + return &m_objects[next_match->value]; + next_match = m_object_name_to_index_map.FindNextValueForName(next_match); + } + + return nullptr; +} + +ObjectContainerBigArchive::Archive::shared_ptr +ObjectContainerBigArchive::Archive::FindCachedArchive( + const FileSpec &file, const ArchSpec &arch, + const llvm::sys::TimePoint<> &time, lldb::offset_t file_offset) { + std::lock_guard guard(Archive::GetArchiveCacheMutex()); + shared_ptr archive_sp; + Archive::Map &archive_map = Archive::GetArchiveCache(); + Archive::Map::iterator pos = archive_map.find(file); + // Don't cache a value for "archive_map.end()" below since we might delete an + // archive entry... + while (pos != archive_map.end() && pos->first == file) { + bool match = true; + if (arch.IsValid() && + !pos->second->GetArchitecture().IsCompatibleMatch(arch)) + match = false; + else if (file_offset != LLDB_INVALID_OFFSET && + pos->second->GetFileOffset() != file_offset) + match = false; + if (match) { + if (pos->second->GetModificationTime() == time) { + return pos->second; + } else { + // We have a file at the same path with the same architecture whose + // modification time doesn't match. It doesn't make sense for us to + // continue to use this Big archive since we cache only the object info + // which consists of file time info and also the file offset and file + // size of any contained objects. Since this information is now out of + // date, we won't get the correct information if we go and extract the + // file data, so we should remove the old and outdated entry. + archive_map.erase(pos); + pos = archive_map.find(file); + continue; // Continue to next iteration so we don't increment pos + // below... + } + } + ++pos; + } + return archive_sp; +} + +ObjectContainerBigArchive::Archive::shared_ptr +ObjectContainerBigArchive::Archive::ParseAndCacheArchiveForFile( + const FileSpec &file, const ArchSpec &arch, + const llvm::sys::TimePoint<> &time, lldb::offset_t file_offset, + DataExtractor &data) { + shared_ptr archive_sp(new Archive(arch, time, file_offset, data)); + if (archive_sp) { + const size_t num_objects = archive_sp->ParseObjects(); + if (num_objects > 0) { + std::lock_guard guard( + Archive::GetArchiveCacheMutex()); + Archive::GetArchiveCache().insert(std::make_pair(file, archive_sp)); + } else { + archive_sp.reset(); + } + } + return archive_sp; +} + +ObjectContainerBigArchive::Archive::Map & +ObjectContainerBigArchive::Archive::GetArchiveCache() { + static Archive::Map g_archive_map; + return g_archive_map; +} + +std::recursive_mutex & +ObjectContainerBigArchive::Archive::GetArchiveCacheMutex() { + static std::recursive_mutex g_archive_map_mutex; + return g_archive_map_mutex; +} + +void ObjectContainerBigArchive::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + GetModuleSpecifications); +} + +void ObjectContainerBigArchive::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ObjectContainer *ObjectContainerBigArchive::CreateInstance( + const lldb::ModuleSP &module_sp, DataBufferSP &data_sp, + lldb::offset_t data_offset, const FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length) { + ConstString object_name(module_sp->GetObjectName()); + if (!object_name) + return nullptr; + + if (data_sp) { + // We have data, which means this is the first 512 bytes of the file Check + // to see if the magic bytes match and if they do, read the entire table of + // contents for the archive and cache it + DataExtractor data; + data.SetData(data_sp, data_offset, length); + if (file && data_sp && ObjectContainerBigArchive::MagicBytesMatch(data)) { + LLDB_SCOPED_TIMERF( + "ObjectContainerBigArchive::CreateInstance (module = %s, file = " + "%p, file_offset = 0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")", + module_sp->GetFileSpec().GetPath().c_str(), + static_cast(file), static_cast(file_offset), + static_cast(length)); + + // Map the entire .a file to be sure that we don't lose any data if the + // file gets updated by a new build while this .a file is being used for + // debugging + DataBufferSP archive_data_sp = + FileSystem::Instance().CreateDataBuffer(*file, length, file_offset); + if (!archive_data_sp) + return nullptr; + + lldb::offset_t archive_data_offset = 0; + + Archive::shared_ptr archive_sp(Archive::FindCachedArchive( + *file, module_sp->GetArchitecture(), module_sp->GetModificationTime(), + file_offset)); + std::unique_ptr container_up( + new ObjectContainerBigArchive(module_sp, archive_data_sp, + archive_data_offset, file, file_offset, + length)); + + if (container_up) { + if (archive_sp) { + // We already have this archive in our cache, use it + container_up->SetArchive(archive_sp); + return container_up.release(); + } else if (container_up->ParseHeader()) + return container_up.release(); + } + } + } else { + // No data, just check for a cached archive + Archive::shared_ptr archive_sp(Archive::FindCachedArchive( + *file, module_sp->GetArchitecture(), module_sp->GetModificationTime(), + file_offset)); + if (archive_sp) { + std::unique_ptr container_up( + new ObjectContainerBigArchive(module_sp, data_sp, data_offset, file, + file_offset, length)); + + if (container_up) { + // We already have this archive in our cache, use it + container_up->SetArchive(archive_sp); + return container_up.release(); + } + } + } + return nullptr; +} + +bool ObjectContainerBigArchive::MagicBytesMatch(const DataExtractor &data) { + uint32_t offset = 0; + const char *armag = (const char *)data.PeekData(offset, (sizeof(llvm::object::BigArchiveMagic) - 1)); + if (armag && ::strncmp(armag, llvm::object::BigArchiveMagic, (sizeof(llvm::object::BigArchiveMagic) - 1)) == 0) + return true; + return false; +} + +ObjectContainerBigArchive::ObjectContainerBigArchive( + const lldb::ModuleSP &module_sp, DataBufferSP &data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t size) + : ObjectContainer(module_sp, file, file_offset, size, data_sp, data_offset), + m_archive_sp() {} +void ObjectContainerBigArchive::SetArchive(Archive::shared_ptr &archive_sp) { + m_archive_sp = archive_sp; +} + +ObjectContainerBigArchive::~ObjectContainerBigArchive() = default; + +bool ObjectContainerBigArchive::ParseHeader() { + if (m_archive_sp.get() == nullptr) { + if (m_data.GetByteSize() > 0) { + ModuleSP module_sp(GetModule()); + if (module_sp) { + m_archive_sp = Archive::ParseAndCacheArchiveForFile( + m_file, module_sp->GetArchitecture(), + module_sp->GetModificationTime(), m_offset, m_data); + } + // Clear the m_data that contains the entire archive data and let our + // m_archive_sp hold onto the data. + m_data.Clear(); + } + } + return m_archive_sp.get() != nullptr; +} + +void ObjectContainerBigArchive::Object::Dump(Stream *s) const { + printf("name = \"%s\"\n", ar_name.GetCString()); + printf("mtime = 0x%8.8" PRIx32 "\n", modification_time); + printf("size = 0x%8.8" PRIx32 " (%" PRIu32 ")\n", size, size); + printf("file_offset = 0x%16.16" PRIx64 " (%" PRIu64 ")\n", file_offset, + file_offset); + printf("file_size = 0x%16.16" PRIx64 " (%" PRIu64 ")\n\n", file_size, + file_size); +} + +ObjectFileSP ObjectContainerBigArchive::GetObjectFile(const FileSpec *file) { + ModuleSP module_sp(GetModule()); + if (module_sp) { + if (module_sp->GetObjectName() && m_archive_sp) { + Object *object = m_archive_sp->FindObject( + module_sp->GetObjectName(), module_sp->GetObjectModificationTime()); + if (object) { + lldb::offset_t data_offset = object->file_offset; + return ObjectFile::FindPlugin( + module_sp, file, m_offset + object->file_offset, object->file_size, + m_archive_sp->GetData().GetSharedDataBuffer(), data_offset); + } + } + } + return ObjectFileSP(); +} + +size_t ObjectContainerBigArchive::GetModuleSpecifications( + const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, lldb::offset_t file_offset, + lldb::offset_t file_size, lldb_private::ModuleSpecList &specs) { + + // We have data, which means this is the first 512 bytes of the file Check to + // see if the magic bytes match and if they do, read the entire table of + // contents for the archive and cache it + DataExtractor data; + data.SetData(data_sp, data_offset, data_sp->GetByteSize()); + if (!file || !data_sp || !ObjectContainerBigArchive::MagicBytesMatch(data)) + return 0; + + const size_t initial_count = specs.GetSize(); + llvm::sys::TimePoint<> file_mod_time = FileSystem::Instance().GetModificationTime(file); + Archive::shared_ptr archive_sp( + Archive::FindCachedArchive(file, ArchSpec(), file_mod_time, file_offset)); + bool set_archive_arch = false; + if (!archive_sp) { + set_archive_arch = true; + data_sp = + FileSystem::Instance().CreateDataBuffer(file, file_size, file_offset); + if (data_sp) { + data.SetData(data_sp, 0, data_sp->GetByteSize()); + archive_sp = Archive::ParseAndCacheArchiveForFile( + file, ArchSpec(), file_mod_time, file_offset, data); + } + } + + if (archive_sp) { + const size_t num_objects = archive_sp->GetNumObjects(); + for (size_t idx = 0; idx < num_objects; ++idx) { + const Object *object = archive_sp->GetObjectAtIndex(idx); + if (object) { + 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( + file, object_file_offset, file_size - object_file_offset, + specs)) { + ModuleSpec &spec = + specs.GetModuleSpecRefAtIndex(specs.GetSize() - 1); + llvm::sys::TimePoint<> object_mod_time( + std::chrono::seconds(object->modification_time)); + spec.GetObjectName() = object->ar_name; + spec.SetObjectOffset(object_file_offset); + spec.SetObjectSize(file_size - object_file_offset); + spec.GetObjectModificationTime() = object_mod_time; + } + } + } + } + } + const size_t end_count = specs.GetSize(); + size_t num_specs_added = end_count - initial_count; + if (set_archive_arch && num_specs_added > 0) { + // The archive was created but we didn't have an architecture so we need to + // set it + for (size_t i = initial_count; i < end_count; ++i) { + ModuleSpec module_spec; + if (specs.GetModuleSpecAtIndex(i, module_spec)) { + if (module_spec.GetArchitecture().IsValid()) { + archive_sp->SetArchitecture(module_spec.GetArchitecture()); + break; + } + } + } + } + return num_specs_added; +} diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h new file mode 100644 index 0000000000000..ad9b814048a87 --- /dev/null +++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h @@ -0,0 +1,177 @@ +//===-- ObjectContainerBigArchive.h -----------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BIG_ARCHIVE_OBJECTCONTAINERBIGARCHIVE_H +#define LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BIG_ARCHIVE_OBJECTCONTAINERBIGARCHIVE_H + +#include "lldb/Core/UniqueCStringMap.h" +#include "lldb/Symbol/ObjectContainer.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/FileSpec.h" + +#include "llvm/Support/Chrono.h" + +#include +#include +#include + +class ObjectContainerBigArchive : public lldb_private::ObjectContainer { +public: + ObjectContainerBigArchive(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + ~ObjectContainerBigArchive() override; + + // Static Functions + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "big-archive"; } + + static llvm::StringRef GetPluginDescriptionStatic() { + return "Big Archive object container reader."; + } + + static lldb_private::ObjectContainer * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + static size_t GetModuleSpecifications(const lldb_private::FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + lldb_private::ModuleSpecList &specs); + + static bool MagicBytesMatch(const lldb_private::DataExtractor &data); + + // Member Functions + bool ParseHeader() override; + + size_t GetNumObjects() const override { + if (m_archive_sp) + return m_archive_sp->GetNumObjects(); + return 0; + } + + lldb::ObjectFileSP GetObjectFile(const lldb_private::FileSpec *file) override; + + // PluginInterface protocol + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + +protected: + struct Object { + Object(); + + void Clear(); + + lldb::offset_t Extract(const lldb_private::DataExtractor &data, + lldb::offset_t offset); + /// Object name in the archive. + lldb_private::ConstString ar_name; + + /// Object modification time in the archive. + uint32_t modification_time = 0; + + /// Object user id in the archive. + uint16_t uid = 0; + + /// Object group id in the archive. + uint16_t gid = 0; + + /// Object octal file permissions in the archive. + uint16_t mode = 0; + + /// Object size in bytes in the archive. + uint32_t size = 0; + + /// File offset in bytes from the beginning of the file of the object data. + lldb::offset_t file_offset = 0; + + /// Length of the object data. + lldb::offset_t file_size = 0; + + void Dump(lldb_private::Stream *s) const; + }; + + class Archive { + public: + typedef std::shared_ptr shared_ptr; + typedef std::multimap Map; + + Archive(const lldb_private::ArchSpec &arch, + const llvm::sys::TimePoint<> &mod_time, lldb::offset_t file_offset, + lldb_private::DataExtractor &data); + + ~Archive(); + + static Map &GetArchiveCache(); + + static std::recursive_mutex &GetArchiveCacheMutex(); + + static Archive::shared_ptr FindCachedArchive( + const lldb_private::FileSpec &file, const lldb_private::ArchSpec &arch, + const llvm::sys::TimePoint<> &mod_time, lldb::offset_t file_offset); + + static Archive::shared_ptr ParseAndCacheArchiveForFile( + const lldb_private::FileSpec &file, const lldb_private::ArchSpec &arch, + const llvm::sys::TimePoint<> &mod_time, lldb::offset_t file_offset, + lldb_private::DataExtractor &data); + + size_t GetNumObjects() const { return m_objects.size(); } + + const Object *GetObjectAtIndex(size_t idx) { + if (idx < m_objects.size()) + return &m_objects[idx]; + return nullptr; + } + + size_t ParseObjects(); + + Object *FindObject(lldb_private::ConstString object_name, + const llvm::sys::TimePoint<> &object_mod_time); + + lldb::offset_t GetFileOffset() const { return m_file_offset; } + + const llvm::sys::TimePoint<> &GetModificationTime() { + return m_modification_time; + } + + const lldb_private::ArchSpec &GetArchitecture() const { return m_arch; } + + void SetArchitecture(const lldb_private::ArchSpec &arch) { m_arch = arch; } + + bool HasNoExternalReferences() const; + + lldb_private::DataExtractor &GetData() { return m_data; } + + protected: + typedef lldb_private::UniqueCStringMap ObjectNameToIndexMap; + // Member Variables + lldb_private::ArchSpec m_arch; + llvm::sys::TimePoint<> m_modification_time; + lldb::offset_t m_file_offset; + std::vector m_objects; + ObjectNameToIndexMap m_object_name_to_index_map; + lldb_private::DataExtractor m_data; ///< The data for this object container + ///so we don't lose data if the .a files + ///gets modified + }; + + void SetArchive(Archive::shared_ptr &archive_sp); + + Archive::shared_ptr m_archive_sp; +}; + +#endif // LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BIG_ARCHIVE_OBJECTCONTAINERBIGARCHIVE_H diff --git a/lldb/source/Plugins/ObjectContainer/CMakeLists.txt b/lldb/source/Plugins/ObjectContainer/CMakeLists.txt index cda0c8151dd8a..2492798bb13ef 100644 --- a/lldb/source/Plugins/ObjectContainer/CMakeLists.txt +++ b/lldb/source/Plugins/ObjectContainer/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(BSD-Archive) +add_subdirectory(Big-Archive) add_subdirectory(Universal-Mach-O) add_subdirectory(Mach-O-Fileset) diff --git a/lldb/source/Plugins/ObjectFile/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/CMakeLists.txt index 773241c8944c8..7abd0c96f4fd7 100644 --- a/lldb/source/Plugins/ObjectFile/CMakeLists.txt +++ b/lldb/source/Plugins/ObjectFile/CMakeLists.txt @@ -6,5 +6,6 @@ add_subdirectory(Mach-O) add_subdirectory(Minidump) add_subdirectory(PDB) add_subdirectory(PECOFF) +add_subdirectory(XCOFF) add_subdirectory(Placeholder) add_subdirectory(wasm) diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index ce095bcc48374..bcb6330cbb1f9 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -5673,7 +5673,7 @@ bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &value, return false; } -bool ObjectFileMachO::GetCorefileThreadExtraInfos(std::vector &tids) { +bool ObjectFileMachO::GetCorefileThreadExtraInfos(std::vector &tids) { tids.clear(); ModuleSP module_sp(GetModule()); if (module_sp) { @@ -5724,8 +5724,8 @@ bool ObjectFileMachO::GetCorefileThreadExtraInfos(std::vector &tids) { return false; } StructuredData::Dictionary *thread = *maybe_thread; - tid_t tid = LLDB_INVALID_THREAD_ID; - if (thread->GetValueForKeyAsInteger("thread_id", tid)) + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; + if (thread->GetValueForKeyAsInteger("thread_id", tid)) if (tid == 0) tid = LLDB_INVALID_THREAD_ID; tids.push_back(tid); diff --git a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp index faa144bfb5f6a..d27cdfc60de85 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp +++ b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp @@ -51,7 +51,9 @@ size_t ObjectFileMinidump::GetModuleSpecifications( const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, lldb_private::ModuleSpecList &specs) { +#if !defined(__AIX__) specs.Clear(); +#endif return 0; } diff --git a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp index f0832dbf07347..75cc54e4f0d48 100644 --- a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp +++ b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp @@ -116,18 +116,31 @@ size_t ObjectFilePDB::GetModuleSpecifications( ModuleSpec module_spec(file); llvm::BumpPtrAllocator allocator; std::unique_ptr pdb_file = loadPDBFile(file.GetPath(), allocator); - if (!pdb_file) + if (!pdb_file){ +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif + } auto info_stream = pdb_file->getPDBInfoStream(); if (!info_stream) { llvm::consumeError(info_stream.takeError()); +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif } auto dbi_stream = pdb_file->getPDBDbiStream(); if (!dbi_stream) { llvm::consumeError(dbi_stream.takeError()); +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif } lldb_private::UUID &uuid = module_spec.GetUUID(); diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index bda691ade8af0..db8fa78043fdc 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -252,8 +252,13 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, lldb_private::ModuleSpecList &specs) { const size_t initial_count = specs.GetSize(); - if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp)) + if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp)){ +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif + } Log *log = GetLog(LLDBLog::Object); @@ -266,12 +271,21 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( if (!binary) { LLDB_LOG_ERROR(log, binary.takeError(), "Failed to create binary for file ({1}): {0}", file); +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif } auto *COFFObj = llvm::dyn_cast(binary->get()); - if (!COFFObj) + if (!COFFObj){ +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif + } ModuleSpec module_spec(file); ArchSpec &spec = module_spec.GetArchitecture(); diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt new file mode 100644 index 0000000000000..8840248574c88 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt @@ -0,0 +1,13 @@ +add_lldb_library(lldbPluginObjectFileXCOFF PLUGIN + ObjectFileXCOFF.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + lldbTarget + LINK_COMPONENTS + BinaryFormat + Object + Support + ) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp new file mode 100644 index 0000000000000..a4d9ea295b4c3 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -0,0 +1,780 @@ +//===-- ObjectFileXCOFF.cpp -------------------------------------------------===// +// +// 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 "ObjectFileXCOFF.h" + +#include +#include +#include +#include + +#include "lldb/Utility/FileSpecList.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Progress.h" +#include "lldb/Core/Section.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/LZMA.h" +#include "lldb/Symbol/DWARFCallFrameInfo.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RangeMap.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/Timer.h" +#include "llvm/ADT/IntervalMap.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/Object/Decompressor.h" +#include "llvm/Support/CRC.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Object/XCOFFObjectFile.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ObjectFileXCOFF) + +char ObjectFileXCOFF::ID; + +// FIXME: target 64bit at this moment. + +// Static methods. +void ObjectFileXCOFF::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + CreateMemoryInstance, GetModuleSpecifications); +} + +void ObjectFileXCOFF::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; + +ObjectFile *ObjectFileXCOFF::CreateInstance(const lldb::ModuleSP &module_sp, + DataBufferSP data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t file_offset, + lldb::offset_t length) { + if (!data_sp) { + data_sp = MapFileData(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + } + + if (!ObjectFileXCOFF::MagicBytesMatch(data_sp, data_offset, length)) + return nullptr; + + // Update the data to contain the entire file if it doesn't already + if (data_sp->GetByteSize() < length) { + data_sp = MapFileData(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + } + auto objfile_up = std::make_unique( + module_sp, data_sp, data_offset, file, file_offset, length); + if (!objfile_up) + return nullptr; + + // Cache xcoff binary. + if (!objfile_up->CreateBinary()) + return nullptr; + + if (!objfile_up->ParseHeader()) + //FIXME objfile leak + return nullptr; + + UGLY_FLAG_FOR_AIX = true; + return objfile_up.release(); +} + +bool ObjectFileXCOFF::CreateBinary() { + if (m_binary) + return true; + + Log *log = GetLog(LLDBLog::Object); + + auto binary = llvm::object::XCOFFObjectFile::createObjectFile(llvm::MemoryBufferRef( + toStringRef(m_data.GetData()), m_file.GetFilename().GetStringRef()), + file_magic::xcoff_object_64); + if (!binary) { + LLDB_LOG_ERROR(log, binary.takeError(), + "Failed to create binary for file ({1}): {0}", m_file); + return false; + } + + // Make sure we only handle COFF format. + m_binary = + llvm::unique_dyn_cast(std::move(*binary)); + if (!m_binary) + return false; + + LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}", + this, GetModule().get(), GetModule()->GetSpecificationDescription(), + m_file.GetPath(), m_binary.get()); + return true; +} + +ObjectFile *ObjectFileXCOFF::CreateMemoryInstance( + const lldb::ModuleSP &module_sp, WritableDataBufferSP data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) { + return nullptr; +} + +size_t ObjectFileXCOFF::GetModuleSpecifications( + const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, lldb::offset_t file_offset, + lldb::offset_t length, lldb_private::ModuleSpecList &specs) { + const size_t initial_count = specs.GetSize(); + + if (ObjectFileXCOFF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) { + ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + ModuleSpec spec(file, arch_spec); + spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX); + specs.Append(spec); + } + return specs.GetSize() - initial_count; +} + +static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) { + switch (magic) { + /* TODO: 32bit not supported yet + case XCOFF::XCOFF32: + return sizeof(struct llvm::object::XCOFFFileHeader32); + */ + + case XCOFF::XCOFF64: + return sizeof(struct llvm::object::XCOFFFileHeader64); + break; + + default: + break; + } + return 0; +} + +bool ObjectFileXCOFF::MagicBytesMatch(DataBufferSP &data_sp, + lldb::addr_t data_offset, + lldb::addr_t data_length) { + lldb_private::DataExtractor data; + data.SetData(data_sp, data_offset, data_length); + lldb::offset_t offset = 0; + uint16_t magic = data.GetU16(&offset); + return XCOFFHeaderSizeFromMagic(magic) != 0; +} + +bool ObjectFileXCOFF::ParseHeader() { + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard guard(module_sp->GetMutex()); + m_sect_headers.clear(); + lldb::offset_t offset = 0; + + if (ParseXCOFFHeader(m_data, &offset, m_xcoff_header)) { + m_data.SetAddressByteSize(GetAddressByteSize()); + if (m_xcoff_header.auxhdrsize > 0) + ParseXCOFFOptionalHeader(m_data, &offset); + ParseSectionHeaders(offset); + } + return true; + } + + return false; +} + +bool ObjectFileXCOFF::ParseXCOFFHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + xcoff_header_t &xcoff_header) { + //FIXME: data.ValidOffsetForDataOfSize + xcoff_header.magic = data.GetU16(offset_ptr); + xcoff_header.nsects = data.GetU16(offset_ptr); + xcoff_header.modtime = data.GetU32(offset_ptr); + xcoff_header.symoff = data.GetU64(offset_ptr); + xcoff_header.auxhdrsize = data.GetU16(offset_ptr); + xcoff_header.flags = data.GetU16(offset_ptr); + xcoff_header.nsyms = data.GetU32(offset_ptr); + return true; +} + +bool ObjectFileXCOFF::ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr) { + lldb::offset_t init_offset = *offset_ptr; + //FIXME: data.ValidOffsetForDataOfSize + m_xcoff_aux_header.AuxMagic = data.GetU16(offset_ptr); + m_xcoff_aux_header.Version = data.GetU16(offset_ptr); + m_xcoff_aux_header.ReservedForDebugger = data.GetU32(offset_ptr); + m_xcoff_aux_header.TextStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.DataStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.TOCAnchorAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfEntryPoint = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTOC = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfLoader = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.ModuleType = data.GetU16(offset_ptr); + m_xcoff_aux_header.CpuFlag = data.GetU8(offset_ptr); + m_xcoff_aux_header.CpuType = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.DataPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.StackPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.FlagAndTDataAlignment = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.InitDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.BssDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.EntryPointAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxStackSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfTData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.XCOFF64Flag = data.GetU16(offset_ptr); + lldb::offset_t last_offset = *offset_ptr; + if ((last_offset - init_offset) < m_xcoff_header.auxhdrsize) + *offset_ptr += (m_xcoff_header.auxhdrsize - (last_offset - init_offset)); + return true; +} + +bool ObjectFileXCOFF::ParseSectionHeaders( + uint32_t section_header_data_offset) { + const uint32_t nsects = m_xcoff_header.nsects; + m_sect_headers.clear(); + + if (nsects > 0) { + const size_t section_header_byte_size = nsects * m_binary->getSectionHeaderSize(); + lldb_private::DataExtractor section_header_data = + ReadImageData(section_header_data_offset, section_header_byte_size); + + lldb::offset_t offset = 0; + //FIXME: section_header_data.ValidOffsetForDataOfSize + m_sect_headers.resize(nsects); + + for (uint32_t idx = 0; idx < nsects; ++idx) { + const void *name_data = section_header_data.GetData(&offset, 8); + if (name_data) { + memcpy(m_sect_headers[idx].name, name_data, 8); + m_sect_headers[idx].phyaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].vmaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].size = section_header_data.GetU64(&offset); + m_sect_headers[idx].offset = section_header_data.GetU64(&offset); + m_sect_headers[idx].reloff = section_header_data.GetU64(&offset); + m_sect_headers[idx].lineoff = section_header_data.GetU64(&offset); + m_sect_headers[idx].nreloc = section_header_data.GetU32(&offset); + m_sect_headers[idx].nline = section_header_data.GetU32(&offset); + m_sect_headers[idx].flags = section_header_data.GetU32(&offset); + offset += 4; + } else { + offset += (m_binary->getSectionHeaderSize() - 8); + } + } + } + + return !m_sect_headers.empty(); +} + +lldb_private::DataExtractor ObjectFileXCOFF::ReadImageData(uint32_t offset, size_t size) { + if (!size) + return {}; + + if (m_data.ValidOffsetForDataOfSize(offset, size)) + return lldb_private::DataExtractor(m_data, offset, size); + + assert(0); + ProcessSP process_sp(m_process_wp.lock()); + lldb_private::DataExtractor data; + if (process_sp) { + auto data_up = std::make_unique(size, 0); + Status readmem_error; + size_t bytes_read = + process_sp->ReadMemory(offset, data_up->GetBytes(), + data_up->GetByteSize(), readmem_error); + if (bytes_read == size) { + DataBufferSP buffer_sp(data_up.release()); + data.SetData(buffer_sp, 0, buffer_sp->GetByteSize()); + } + } + return data; +} + +bool ObjectFileXCOFF::SetLoadAddress(Target &target, lldb::addr_t value, + bool value_is_offset) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (section_sp && !section_sp->IsThreadSpecific()) { + bool use_offset = false; + if (strcmp(section_sp->GetName().AsCString(), ".text") == 0 || + strcmp(section_sp->GetName().AsCString(), ".data") == 0 || + strcmp(section_sp->GetName().AsCString(), ".bss") == 0) + use_offset = true; + + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, (use_offset ? + (section_sp->GetFileOffset() + value) : (section_sp->GetFileAddress() + value)))) + ++num_loaded_sections; + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (type_id == 1 && section_sp && strcmp(section_sp->GetName().AsCString(), ".text") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileOffset() + value)) + ++num_loaded_sections; + } + } else if (type_id == 2 && section_sp && strcmp(section_sp->GetName().AsCString(), ".data") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileAddress() + value)) + ++num_loaded_sections; + } + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +ByteOrder ObjectFileXCOFF::GetByteOrder() const { + return eByteOrderBig; +} + +bool ObjectFileXCOFF::IsExecutable() const { + return true; +} + +uint32_t ObjectFileXCOFF::GetAddressByteSize() const { + if (m_xcoff_header.magic == XCOFF::XCOFF64) + return 8; + else if (m_xcoff_header.magic == XCOFF::XCOFF32) + return 4; + return 4; +} + +AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) { + return AddressClass::eUnknown; +} + +lldb::SymbolType ObjectFileXCOFF::MapSymbolType(llvm::object::SymbolRef::Type sym_type) { + if (sym_type == llvm::object::SymbolRef::ST_Function) + return lldb::eSymbolTypeCode; + else if (sym_type == llvm::object::SymbolRef::ST_Data) + return lldb::eSymbolTypeData; + return lldb::eSymbolTypeInvalid; +} + +void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) { + SectionList *sect_list = GetSectionList(); + const uint32_t num_syms = m_xcoff_header.nsyms; + uint32_t sidx = 0; + if (num_syms > 0 && m_xcoff_header.symoff > 0) { + const uint32_t symbol_size = XCOFF::SymbolTableEntrySize; + const size_t symbol_data_size = num_syms * symbol_size; + lldb_private::DataExtractor symtab_data = + ReadImageData(m_xcoff_header.symoff, symbol_data_size); + + lldb::offset_t offset = 0; + std::string symbol_name; + Symbol *symbols = lldb_symtab.Resize(num_syms); + llvm::object::symbol_iterator SI = m_binary->symbol_begin(); + for (uint32_t i = 0; i < num_syms; ++i, ++SI) { + xcoff_symbol_t symbol; + const uint32_t symbol_offset = offset; + symbol.value = symtab_data.GetU64(&offset); + symbol.offset = symtab_data.GetU32(&offset); + Expected symbol_name_or_err = m_binary->getStringTableEntry(symbol.offset); + if (!symbol_name_or_err) { + consumeError(symbol_name_or_err.takeError()); + return; + } + StringRef symbol_name_str = symbol_name_or_err.get(); + symbol_name.assign(symbol_name_str.data()); + symbol.sect = symtab_data.GetU16(&offset); + symbol.type = symtab_data.GetU16(&offset); + symbol.storage = symtab_data.GetU8(&offset); + symbol.naux = symtab_data.GetU8(&offset); + // Allow C_HIDEXT TOC symbol, and check others. + if (symbol.storage == XCOFF::C_HIDEXT && strcmp(symbol_name.c_str(), "TOC") != 0) { + if (symbol.naux == 0) + continue; + if (symbol.naux > 1) { + i += symbol.naux; + offset += symbol.naux * symbol_size; + continue; + } + /* Allow XCOFF::C_HIDEXT with following SMC and AT: + StorageMappingClass: XMC_PR (0x0) + Auxiliary Type: AUX_CSECT (0xFB) + */ + xcoff_sym_csect_aux_entry_t symbol_aux; + symbol_aux.section_or_len_low_byte = symtab_data.GetU32(&offset); + symbol_aux.parameter_hash_index = symtab_data.GetU32(&offset); + symbol_aux.type_check_sect_num = symtab_data.GetU16(&offset); + symbol_aux.symbol_alignment_and_type = symtab_data.GetU8(&offset); + symbol_aux.storage_mapping_class = symtab_data.GetU8(&offset); + symbol_aux.section_or_len_high_byte = symtab_data.GetU32(&offset); + symbol_aux.pad = symtab_data.GetU8(&offset); + symbol_aux.aux_type = symtab_data.GetU8(&offset); + offset -= symbol.naux * symbol_size; + if (symbol_aux.storage_mapping_class != XCOFF::XMC_PR || symbol_aux.aux_type != XCOFF::AUX_CSECT) { + i += symbol.naux; + offset += symbol.naux * symbol_size; + continue; + } + } + // Remove the dot prefix for demangle + if (symbol_name_str.size() > 1 && symbol_name_str.data()[0] == '.') { + symbols[sidx].GetMangled().SetValue(ConstString(symbol_name.c_str() + 1)); + } else { + symbols[sidx].GetMangled().SetValue(ConstString(symbol_name.c_str())); + } + if ((int16_t)symbol.sect >= 1) { + Address symbol_addr(sect_list->GetSectionAtIndex((size_t)(symbol.sect - 1)), + (symbol.value - sect_list->GetSectionAtIndex((size_t)(symbol.sect - 1))->GetFileAddress())); + symbols[sidx].GetAddressRef() = symbol_addr; + + Expected sym_type_or_err = SI->getType(); + if (!sym_type_or_err) { + consumeError(sym_type_or_err.takeError()); + return; + } + symbols[sidx].SetType(MapSymbolType(sym_type_or_err.get())); + } + ++sidx; + + if (symbol.naux > 0) { + i += symbol.naux; + offset += symbol.naux * symbol_size; + } + } + lldb_symtab.Resize(sidx); + } +} + +bool ObjectFileXCOFF::IsStripped() { + return false; +} + +void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) { + if (m_sections_up) + return; + m_sections_up = std::make_unique(); + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard guard(module_sp->GetMutex()); + + const uint32_t nsects = m_sect_headers.size(); + ModuleSP module_sp(GetModule()); + for (uint32_t idx = 0; idx < nsects; ++idx) { + llvm::StringRef sect_name = GetSectionName(m_sect_headers[idx]); + ConstString const_sect_name(sect_name); + SectionType section_type = GetSectionType(sect_name, m_sect_headers[idx]); + + SectionSP section_sp(new Section( + module_sp, // Module to which this section belongs + this, // Object file to which this section belongs + idx + 1, // Section ID is the 1 based section index. + const_sect_name, // Name of this section + section_type, + m_sect_headers[idx].vmaddr, // File VM address == addresses as + // they are found in the object file + m_sect_headers[idx].size, // VM size in bytes of this section + m_sect_headers[idx].offset, // Offset to the data for this section in the file + m_sect_headers[idx].size, // Size in bytes of this section as found in the file + 0, // FIXME: alignment + m_sect_headers[idx].flags)); // Flags for this section + + // FIXME + uint32_t permissions = 0; + permissions |= ePermissionsReadable; + if (m_sect_headers[idx].flags & (XCOFF::STYP_DATA | XCOFF::STYP_BSS)) + permissions |= ePermissionsWritable; + if (m_sect_headers[idx].flags & XCOFF::STYP_TEXT) + permissions |= ePermissionsExecutable; + section_sp->SetPermissions(permissions); + + m_sections_up->AddSection(section_sp); + unified_section_list.AddSection(section_sp); + } + } +} + +llvm::StringRef ObjectFileXCOFF::GetSectionName(const section_header_t §) { + llvm::StringRef hdr_name(sect.name, std::size(sect.name)); + hdr_name = hdr_name.split('\0').first; + if (hdr_name.consume_front("/")) { + lldb::offset_t stroff; + if (!to_integer(hdr_name, stroff, 10)) + return ""; + lldb::offset_t string_file_offset = + m_xcoff_header.symoff + (m_xcoff_header.nsyms * static_cast(XCOFF::SymbolTableEntrySize)) + stroff; + if (const char *name = m_data.GetCStr(&string_file_offset)) + return name; + return ""; + } + return hdr_name; +} + +SectionType ObjectFileXCOFF::GetSectionType(llvm::StringRef sect_name, + const section_header_t §) { + if (sect.flags & XCOFF::STYP_TEXT) + return eSectionTypeCode; + if (sect.flags & XCOFF::STYP_DATA) + return eSectionTypeData; + if (sect.flags & XCOFF::STYP_BSS) + return eSectionTypeZeroFill; + if (sect.flags & XCOFF::STYP_DWARF) { + SectionType section_type = + llvm::StringSwitch(sect_name) + .Case(".dwinfo", eSectionTypeDWARFDebugInfo) + .Case(".dwline", eSectionTypeDWARFDebugLine) + .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev) + .Default(eSectionTypeInvalid); + + if (section_type != eSectionTypeInvalid) + return section_type; + } + return eSectionTypeOther; +} + +void ObjectFileXCOFF::Dump(Stream *s) { +} + +ArchSpec ObjectFileXCOFF::GetArchitecture() { + ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + return arch_spec; +} + +UUID ObjectFileXCOFF::GetUUID() { + return UUID(); +} + +std::optional ObjectFileXCOFF::GetDebugLink() { + return std::nullopt; +} + +uint32_t ObjectFileXCOFF::ParseDependentModules() { + ModuleSP module_sp(GetModule()); + if (!module_sp) + return 0; + + std::lock_guard guard(module_sp->GetMutex()); + if (m_deps_filespec) + return m_deps_filespec->GetSize(); + + // Cache coff binary if it is not done yet. + if (!CreateBinary()) + return 0; + + Log *log = GetLog(LLDBLog::Object); + LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}", + this, GetModule().get(), GetModule()->GetSpecificationDescription(), + m_file.GetPath(), m_binary.get()); + + m_deps_filespec = FileSpecList(); + + auto ImportFilesOrError = m_binary->getImportFileTable(); + if (!ImportFilesOrError) { + consumeError(ImportFilesOrError.takeError()); + return 0; + } + +#if 0 + StringRef ImportFileTable = ImportFilesOrError.get(); + const char *CurrentStr = ImportFileTable.data(); + const char *TableEnd = ImportFileTable.end(); + const char *Basename = nullptr; + + for (size_t StrIndex = 0; CurrentStr < TableEnd; + ++StrIndex, CurrentStr += strlen(CurrentStr) + 1) { + if (StrIndex >= 3 && StrIndex % 3 == 1) { + // base_name + llvm::StringRef dll_name(CurrentStr); + Basename = CurrentStr; + + // At this moment we only have the base name of the DLL. The full path can + // only be seen after the dynamic loading. Our best guess is Try to get it + // with the help of the object file's directory. + llvm::SmallString<128> dll_fullpath; + FileSpec dll_specs(dll_name); + // FIXME: hack to get libc.a loaded + if (strcmp(CurrentStr, "libc.a") == 0) { + dll_specs.GetDirectory().SetString("/usr/lib"); + } else { + dll_specs.GetDirectory().SetString(m_file.GetDirectory().GetCString()); + } + + if (!llvm::sys::fs::real_path(dll_specs.GetPath(), dll_fullpath)) + //m_deps_filespec->EmplaceBack(dll_fullpath); + m_deps_filespec->EmplaceBack("/usr/lib/libc.a(shr_64.o)"); + else { + // Known DLLs or DLL not found in the object file directory. + m_deps_filespec->EmplaceBack(dll_name); + } + } else if (StrIndex >= 3 && StrIndex % 3 == 2) { + // archive_member_name + if (strcmp(CurrentStr, "") == 0) { + continue; + } + assert(strcmp(Basename, "") != 0); + std::map>::iterator iter = m_deps_base_members.find(std::string(Basename)); + if (iter == m_deps_base_members.end()) { + m_deps_base_members[std::string(Basename)] = std::vector(); + iter = m_deps_base_members.find(std::string(Basename)); + } + iter->second.push_back(std::string(CurrentStr)); + } + } +#endif + return m_deps_filespec->GetSize(); +} + +uint32_t ObjectFileXCOFF::GetDependentModules(FileSpecList &files) { + auto num_modules = ParseDependentModules(); + auto original_size = files.GetSize(); + + for (unsigned i = 0; i < num_modules; ++i) + files.AppendIfUnique(m_deps_filespec->GetFileSpecAtIndex(i)); + + return files.GetSize() - original_size; +} + +Address ObjectFileXCOFF::GetImageInfoAddress(Target *target) { + return Address(); +} + +lldb_private::Address ObjectFileXCOFF::GetEntryPointAddress() { + if (m_entry_point_address.IsValid()) + return m_entry_point_address; + + if (!ParseHeader() || !IsExecutable()) + return m_entry_point_address; + + SectionList *section_list = GetSectionList(); + addr_t vm_addr = m_xcoff_aux_header.EntryPointAddr; + SectionSP section_sp( + section_list->FindSectionContainingFileAddress(vm_addr)); + if (section_sp) { + lldb::offset_t offset_ptr = section_sp->GetFileOffset() + (vm_addr - section_sp->GetFileAddress()); + vm_addr = m_data.GetU64(&offset_ptr); + } + + if (!section_list) + m_entry_point_address.SetOffset(vm_addr); + else + m_entry_point_address.ResolveAddressUsingFileSections(vm_addr, + section_list); + + return m_entry_point_address; +} + +lldb_private::Address ObjectFileXCOFF::GetBaseAddress() { + return lldb_private::Address(); +} + +ObjectFile::Type ObjectFileXCOFF::CalculateType() { + if (m_xcoff_header.flags & XCOFF::F_EXEC) + return eTypeExecutable; + else if (m_xcoff_header.flags & XCOFF::F_SHROBJ) + return eTypeSharedLibrary; + return eTypeUnknown; +} + +ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { + return eStrataUnknown; +} + +llvm::StringRef +ObjectFileXCOFF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const { + return llvm::StringRef(); +} + +void ObjectFileXCOFF::RelocateSection(lldb_private::Section *section) +{ +} + +std::vector +ObjectFileXCOFF::GetLoadableData(Target &target) { + std::vector loadables; + return loadables; +} + +lldb::WritableDataBufferSP +ObjectFileXCOFF::MapFileDataWritable(const FileSpec &file, uint64_t Size, + uint64_t Offset) { + return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size, + Offset); +} + +ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp, + DataBufferSP data_sp, lldb::offset_t data_offset, + const FileSpec *file, lldb::offset_t file_offset, + lldb::offset_t length) + : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset), + m_xcoff_header(), m_sect_headers(), m_deps_filespec(), m_deps_base_members(), + m_entry_point_address() { + ::memset(&m_xcoff_header, 0, sizeof(m_xcoff_header)); + if (file) + m_file = *file; +} + +ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp, + DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, + addr_t header_addr) + : ObjectFile(module_sp, process_sp, header_addr, header_data_sp), + m_xcoff_header(), m_sect_headers(), m_deps_filespec(), m_deps_base_members(), + m_entry_point_address() { + ::memset(&m_xcoff_header, 0, sizeof(m_xcoff_header)); +} diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h new file mode 100644 index 0000000000000..5a12d16886489 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h @@ -0,0 +1,243 @@ +//===-- ObjectFileXCOFF.h --------------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H + +#include + +#include + +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/UUID.h" +#include "lldb/lldb-private.h" +#include "llvm/Object/XCOFFObjectFile.h" + +/// \class ObjectFileXCOFF +/// Generic XCOFF object file reader. +/// +/// This class provides a generic XCOFF (32/64 bit) reader plugin implementing +/// the ObjectFile protocol. +class ObjectFileXCOFF : public lldb_private::ObjectFile { +public: + // Static Functions + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "xcoff"; } + + static llvm::StringRef GetPluginDescriptionStatic() { + return "XCOFF object file reader."; + } + + static lldb_private::ObjectFile * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length); + + static lldb_private::ObjectFile *CreateMemoryInstance( + const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + + static size_t GetModuleSpecifications(const lldb_private::FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + lldb_private::ModuleSpecList &specs); + + static bool MagicBytesMatch(lldb::DataBufferSP &data_sp, lldb::addr_t offset, + lldb::addr_t length); + + static lldb::SymbolType MapSymbolType(llvm::object::SymbolRef::Type sym_type); + + // PluginInterface protocol + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + // LLVM RTTI support + static char ID; + bool isA(const void *ClassID) const override { + return ClassID == &ID || ObjectFile::isA(ClassID); + } + static bool classof(const ObjectFile *obj) { return obj->isA(&ID); } + + // ObjectFile Protocol. + bool ParseHeader() override; + + bool SetLoadAddress(lldb_private::Target &target, lldb::addr_t value, + bool value_is_offset) override; + + bool SetLoadAddressByType(lldb_private::Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) override; + + lldb::ByteOrder GetByteOrder() const override; + + bool IsExecutable() const override; + + uint32_t GetAddressByteSize() const override; + + lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override; + + void ParseSymtab(lldb_private::Symtab &symtab) override; + + bool IsStripped() override; + + void CreateSections(lldb_private::SectionList &unified_section_list) override; + + void Dump(lldb_private::Stream *s) override; + + lldb_private::ArchSpec GetArchitecture() override; + + lldb_private::UUID GetUUID() override; + + /// Return the contents of the .gnu_debuglink section, if the object file + /// contains it. + std::optional GetDebugLink(); + + uint32_t GetDependentModules(lldb_private::FileSpecList &files) override; + + lldb_private::Address + GetImageInfoAddress(lldb_private::Target *target) override; + + lldb_private::Address GetEntryPointAddress() override; + + lldb_private::Address GetBaseAddress() override; + + ObjectFile::Type CalculateType() override; + + ObjectFile::Strata CalculateStrata() override; + + llvm::StringRef + StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const override; + + void RelocateSection(lldb_private::Section *section) override; + + lldb_private::DataExtractor ReadImageData(uint32_t offset, size_t size); + + ObjectFileXCOFF(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + ObjectFileXCOFF(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + +protected: + + typedef struct xcoff_header { + uint16_t magic; + uint16_t nsects; + uint32_t modtime; + uint64_t symoff; + uint32_t nsyms; + uint16_t auxhdrsize; + uint16_t flags; + } xcoff_header_t; + + typedef struct xcoff_aux_header { + uint16_t AuxMagic; + uint16_t Version; + uint32_t ReservedForDebugger; + uint64_t TextStartAddr; + uint64_t DataStartAddr; + uint64_t TOCAnchorAddr; + uint16_t SecNumOfEntryPoint; + uint16_t SecNumOfText; + uint16_t SecNumOfData; + uint16_t SecNumOfTOC; + uint16_t SecNumOfLoader; + uint16_t SecNumOfBSS; + uint16_t MaxAlignOfText; + uint16_t MaxAlignOfData; + uint16_t ModuleType; + uint8_t CpuFlag; + uint8_t CpuType; + uint8_t TextPageSize; + uint8_t DataPageSize; + uint8_t StackPageSize; + uint8_t FlagAndTDataAlignment; + uint64_t TextSize; + uint64_t InitDataSize; + uint64_t BssDataSize; + uint64_t EntryPointAddr; + uint64_t MaxStackSize; + uint64_t MaxDataSize; + uint16_t SecNumOfTData; + uint16_t SecNumOfTBSS; + uint16_t XCOFF64Flag; + } xcoff_aux_header_t; + + typedef struct section_header { + char name[8]; + uint64_t phyaddr; // Physical Addr + uint64_t vmaddr; // Virtual Addr + uint64_t size; // Section size + uint64_t offset; // File offset to raw data + uint64_t reloff; // Offset to relocations + uint64_t lineoff; // Offset to line table entries + uint32_t nreloc; // Number of relocation entries + uint32_t nline; // Number of line table entries + uint32_t flags; + } section_header_t; + + typedef struct xcoff_symbol { + uint64_t value; + uint32_t offset; + uint16_t sect; + uint16_t type; + uint8_t storage; + uint8_t naux; + } xcoff_symbol_t; + + typedef struct xcoff_sym_csect_aux_entry { + uint32_t section_or_len_low_byte; + uint32_t parameter_hash_index; + uint16_t type_check_sect_num; + uint8_t symbol_alignment_and_type; + uint8_t storage_mapping_class; + uint32_t section_or_len_high_byte; + uint8_t pad; + uint8_t aux_type; + } xcoff_sym_csect_aux_entry_t; + + static bool ParseXCOFFHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + xcoff_header_t &xcoff_header); + bool ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr); + bool ParseSectionHeaders(uint32_t offset); + + std::vector + GetLoadableData(lldb_private::Target &target) override; + + static lldb::WritableDataBufferSP + MapFileDataWritable(const lldb_private::FileSpec &file, uint64_t Size, + uint64_t Offset); + llvm::StringRef GetSectionName(const section_header_t §); + static lldb::SectionType GetSectionType(llvm::StringRef sect_name, + const section_header_t §); + + uint32_t ParseDependentModules(); + typedef std::vector SectionHeaderColl; + +private: + bool CreateBinary(); + + xcoff_header_t m_xcoff_header; + xcoff_aux_header_t m_xcoff_aux_header; + SectionHeaderColl m_sect_headers; + std::unique_ptr m_binary; + lldb_private::Address m_entry_point_address; + std::optional m_deps_filespec; + std::map> m_deps_base_members; +}; + +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H diff --git a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp index e026ffefd645e..106e38b6e25ae 100644 --- a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp +++ b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp @@ -227,7 +227,7 @@ ThreadSP OperatingSystemPython::CreateThreadFromThreadInfo( ThreadList &old_thread_list, std::vector &core_used_map, bool *did_create_ptr) { ThreadSP thread_sp; - tid_t tid = LLDB_INVALID_THREAD_ID; + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; if (!thread_dict.GetValueForKeyAsInteger("tid", tid)) return ThreadSP(); diff --git a/lldb/source/Plugins/Platform/AIX/CMakeLists.txt b/lldb/source/Plugins/Platform/AIX/CMakeLists.txt new file mode 100644 index 0000000000000..85ff0a315eabd --- /dev/null +++ b/lldb/source/Plugins/Platform/AIX/CMakeLists.txt @@ -0,0 +1,13 @@ +add_definitions("-D_ALL_SOURCE") + +add_lldb_library(lldbPluginPlatformAIX PLUGIN + PlatformAIX.cpp + + LINK_LIBS + lldbBreakpoint + lldbCore + lldbHost + lldbInterpreter + lldbTarget + lldbPluginPlatformPOSIX + ) diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp new file mode 100644 index 0000000000000..b6b08b73bec41 --- /dev/null +++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp @@ -0,0 +1,471 @@ +//===-- PlatformAIX.cpp -------------------------------------------------===// +// +// 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 "PlatformAIX.h" +#include "lldb/Host/Config.h" + +#include +#if LLDB_ENABLE_POSIX +#include +#endif + +#include "Utility/ARM64_DWARF_Registers.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/StreamString.h" + +// Define these constants from AIX mman.h for use when targeting remote aix +// systems even when host has different values. + +#if defined(__AIX__) +#include +#endif + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::platform_aix; + +LLDB_PLUGIN_DEFINE(PlatformAIX) + +static uint32_t g_initialize_count = 0; + + +PlatformSP PlatformAIX::CreateInstance(bool force, const ArchSpec *arch) { + Log *log = GetLog(LLDBLog::Platform); + LLDB_LOG(log, "force = {0}, arch=({1}, {2})", force, + arch ? arch->GetArchitectureName() : "", + arch ? arch->GetTriple().getTriple() : ""); + + bool create = force; + if (!create && arch && arch->IsValid()) { + const llvm::Triple &triple = arch->GetTriple(); + switch (triple.getOS()) { + case llvm::Triple::AIX: + create = true; + break; + + default: + break; + } + } + + LLDB_LOG(log, "create = {0}", create); + if (create) { + return PlatformSP(new PlatformAIX(false)); + } + return PlatformSP(); +} + +llvm::StringRef PlatformAIX::GetPluginDescriptionStatic(bool is_host) { + if (is_host) + return "Local AIX user platform plug-in."; + return "Remote AIX user platform plug-in."; +} + +void PlatformAIX::Initialize() { + PlatformPOSIX::Initialize(); + + if (g_initialize_count++ == 0) { +#if defined(__AIX__) + PlatformSP default_platform_sp(new PlatformAIX(true)); + default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); + Platform::SetHostPlatform(default_platform_sp); +#endif + PluginManager::RegisterPlugin( + PlatformAIX::GetPluginNameStatic(false), + PlatformAIX::GetPluginDescriptionStatic(false), + PlatformAIX::CreateInstance, nullptr); + } +} + +void PlatformAIX::Terminate() { + if (g_initialize_count > 0) { + if (--g_initialize_count == 0) { + PluginManager::UnregisterPlugin(PlatformAIX::CreateInstance); + } + } + + PlatformPOSIX::Terminate(); +} + +/// Default Constructor +PlatformAIX::PlatformAIX(bool is_host) + : PlatformPOSIX(is_host) // This is the local host platform +{ + if (is_host) { + ArchSpec hostArch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault); + m_supported_architectures.push_back(hostArch); + if (hostArch.GetTriple().isArch64Bit()) { + m_supported_architectures.push_back( + HostInfo::GetArchitecture(HostInfo::eArchKind32)); + } + } else { + m_supported_architectures = CreateArchList( + {llvm::Triple::x86_64, llvm::Triple::x86, llvm::Triple::arm, + llvm::Triple::aarch64, llvm::Triple::mips64, llvm::Triple::mips64, + llvm::Triple::hexagon, llvm::Triple::mips, llvm::Triple::mips64el, + llvm::Triple::mipsel, llvm::Triple::systemz}, + llvm::Triple::AIX); + } +} + +std::vector +PlatformAIX::GetSupportedArchitectures(const ArchSpec &process_host_arch) { + if (m_remote_platform_sp) + return m_remote_platform_sp->GetSupportedArchitectures(process_host_arch); + return m_supported_architectures; +} + +void PlatformAIX::GetStatus(Stream &strm) { + Platform::GetStatus(strm); + +#if LLDB_ENABLE_POSIX + // Display local kernel information only when we are running in host mode. + // Otherwise, we would end up printing non-AIX information (when running on + // Mac OS for example). + if (IsHost()) { + struct utsname un; + + if (uname(&un)) + return; + + strm.Printf(" Kernel: %s\n", un.sysname); + strm.Printf(" Release: %s\n", un.release); + strm.Printf(" Version: %s\n", un.version); + } +#endif +} + +uint32_t +PlatformAIX::GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) { + uint32_t resume_count = 0; + + // Always resume past the initial stop when we use eLaunchFlagDebug + if (launch_info.GetFlags().Test(eLaunchFlagDebug)) { + // Resume past the stop for the final exec into the true inferior. + ++resume_count; + } + + // If we're not launching a shell, we're done. + const FileSpec &shell = launch_info.GetShell(); + if (!shell) + return resume_count; + + std::string shell_string = shell.GetPath(); + // We're in a shell, so for sure we have to resume past the shell exec. + ++resume_count; + + // Figure out what shell we're planning on using. + const char *shell_name = strrchr(shell_string.c_str(), '/'); + if (shell_name == nullptr) + shell_name = shell_string.c_str(); + else + shell_name++; + + if (strcmp(shell_name, "csh") == 0 || strcmp(shell_name, "tcsh") == 0 || + strcmp(shell_name, "zsh") == 0 || strcmp(shell_name, "sh") == 0) { + // These shells seem to re-exec themselves. Add another resume. + ++resume_count; + } + + return resume_count; +} + +bool PlatformAIX::CanDebugProcess() { + if (IsHost()) { + return true; + } else { + // If we're connected, we can debug. + return IsConnected(); + } +} + +void PlatformAIX::CalculateTrapHandlerSymbolNames() { + m_trap_handlers.push_back(ConstString("_sigtramp")); + m_trap_handlers.push_back(ConstString("__kernel_rt_sigreturn")); + m_trap_handlers.push_back(ConstString("__restore_rt")); +} + +static lldb::UnwindPlanSP GetAArch64TrapHanlderUnwindPlan(ConstString name) { + UnwindPlanSP unwind_plan_sp; + if (name != "__kernel_rt_sigreturn") + return unwind_plan_sp; + + UnwindPlan::RowSP row = std::make_shared(); + row->SetOffset(0); + + // In the signal trampoline frame, sp points to an rt_sigframe[1], which is: + // - 128-byte siginfo struct + // - ucontext struct: + // - 8-byte long (uc_flags) + // - 8-byte pointer (uc_link) + // - 24-byte stack_t + // - 128-byte signal set + // - 8 bytes of padding because sigcontext has 16-byte alignment + // - sigcontext/mcontext_t + // [1] + // https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/signal.c + int32_t offset = 128 + 8 + 8 + 24 + 128 + 8; + // Then sigcontext[2] is: + // - 8 byte fault address + // - 31 8 byte registers + // - 8 byte sp + // - 8 byte pc + // [2] + // https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/sigcontext.h + + // Skip fault address + offset += 8; + row->GetCFAValue().SetIsRegisterPlusOffset(arm64_dwarf::sp, offset); + + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x0, 0 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x1, 1 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x2, 2 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x3, 3 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x4, 4 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x5, 5 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x6, 6 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x7, 7 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x8, 8 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x9, 9 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x10, 10 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x11, 11 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x12, 12 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x13, 13 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x14, 14 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x15, 15 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x16, 16 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x17, 17 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x18, 18 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x19, 19 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x20, 20 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x21, 21 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x22, 22 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x23, 23 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x24, 24 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x25, 25 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x26, 26 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x27, 27 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x28, 28 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::fp, 29 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x30, 30 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::sp, 31 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::pc, 32 * 8, false); + + // The sigcontext may also contain floating point and SVE registers. + // However this would require a dynamic unwind plan so they are not included + // here. + + unwind_plan_sp = std::make_shared(eRegisterKindDWARF); + unwind_plan_sp->AppendRow(row); + unwind_plan_sp->SetSourceName("AArch64 AIX sigcontext"); + unwind_plan_sp->SetSourcedFromCompiler(eLazyBoolYes); + // Because sp is the same throughout the function + unwind_plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolYes); + unwind_plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolYes); + + return unwind_plan_sp; +} + +lldb::UnwindPlanSP +PlatformAIX::GetTrapHandlerUnwindPlan(const llvm::Triple &triple, + ConstString name) { + if (triple.isAArch64()) + return GetAArch64TrapHanlderUnwindPlan(name); + + return {}; +} + +MmapArgList PlatformAIX::GetMmapArgumentList(const ArchSpec &arch, + addr_t addr, addr_t length, + unsigned prot, unsigned flags, + addr_t fd, addr_t offset) { +#if defined(__AIX__) + unsigned flags_platform = MAP_VARIABLE | MAP_PRIVATE | MAP_ANONYMOUS; +#else + unsigned flags_platform = 0; +#endif + MmapArgList args({addr, length, prot, flags_platform, fd, offset}); + return args; +} + +CompilerType PlatformAIX::GetSiginfoType(const llvm::Triple &triple) { + if (!m_type_system_up) + m_type_system_up.reset(new TypeSystemClang("siginfo", triple)); + TypeSystemClang *ast = m_type_system_up.get(); + + bool si_errno_then_code = true; + + switch (triple.getArch()) { + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + // mips has si_code and si_errno swapped + si_errno_then_code = false; + break; + default: + break; + } + + // generic types + CompilerType int_type = ast->GetBasicType(eBasicTypeInt); + CompilerType uint_type = ast->GetBasicType(eBasicTypeUnsignedInt); + CompilerType short_type = ast->GetBasicType(eBasicTypeShort); + CompilerType long_type = ast->GetBasicType(eBasicTypeLong); + CompilerType voidp_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); + + // platform-specific types + CompilerType &pid_type = int_type; + CompilerType &uid_type = uint_type; + CompilerType &clock_type = long_type; + CompilerType &band_type = long_type; + + CompilerType sigval_type = ast->CreateRecordType( + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_sigval_t", + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); + ast->StartTagDeclarationDefinition(sigval_type); + ast->AddFieldToRecordType(sigval_type, "sival_int", int_type, + lldb::eAccessPublic, 0); + ast->AddFieldToRecordType(sigval_type, "sival_ptr", voidp_type, + lldb::eAccessPublic, 0); + ast->CompleteTagDeclarationDefinition(sigval_type); + + CompilerType sigfault_bounds_type = ast->CreateRecordType( + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); + ast->StartTagDeclarationDefinition(sigfault_bounds_type); + ast->AddFieldToRecordType(sigfault_bounds_type, "_addr_bnd", + ast->CreateStructForIdentifier(ConstString(), + { + {"_lower", voidp_type}, + {"_upper", voidp_type}, + }), + lldb::eAccessPublic, 0); + ast->AddFieldToRecordType(sigfault_bounds_type, "_pkey", uint_type, + lldb::eAccessPublic, 0); + ast->CompleteTagDeclarationDefinition(sigfault_bounds_type); + + // siginfo_t + CompilerType siginfo_type = ast->CreateRecordType( + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_siginfo_t", + llvm::to_underlying(clang::TagTypeKind::Struct), lldb::eLanguageTypeC); + ast->StartTagDeclarationDefinition(siginfo_type); + ast->AddFieldToRecordType(siginfo_type, "si_signo", int_type, + lldb::eAccessPublic, 0); + + if (si_errno_then_code) { + ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type, + lldb::eAccessPublic, 0); + ast->AddFieldToRecordType(siginfo_type, "si_code", int_type, + lldb::eAccessPublic, 0); + } else { + ast->AddFieldToRecordType(siginfo_type, "si_code", int_type, + lldb::eAccessPublic, 0); + ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type, + lldb::eAccessPublic, 0); + } + + // the structure is padded on 64-bit arches to fix alignment + if (triple.isArch64Bit()) + ast->AddFieldToRecordType(siginfo_type, "__pad0", int_type, + lldb::eAccessPublic, 0); + + // union used to hold the signal data + CompilerType union_type = ast->CreateRecordType( + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); + ast->StartTagDeclarationDefinition(union_type); + + ast->AddFieldToRecordType( + union_type, "_kill", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_pid", pid_type}, + {"si_uid", uid_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_timer", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_tid", int_type}, + {"si_overrun", int_type}, + {"si_sigval", sigval_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_rt", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_pid", pid_type}, + {"si_uid", uid_type}, + {"si_sigval", sigval_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_sigchld", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_pid", pid_type}, + {"si_uid", uid_type}, + {"si_status", int_type}, + {"si_utime", clock_type}, + {"si_stime", clock_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_sigfault", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_addr", voidp_type}, + {"si_addr_lsb", short_type}, + {"_bounds", sigfault_bounds_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_sigpoll", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_band", band_type}, + {"si_fd", int_type}, + }), + lldb::eAccessPublic, 0); + + // NB: SIGSYS is not present on ia64 but we don't seem to support that + ast->AddFieldToRecordType( + union_type, "_sigsys", + ast->CreateStructForIdentifier(ConstString(), + { + {"_call_addr", voidp_type}, + {"_syscall", int_type}, + {"_arch", uint_type}, + }), + lldb::eAccessPublic, 0); + + ast->CompleteTagDeclarationDefinition(union_type); + ast->AddFieldToRecordType(siginfo_type, "_sifields", union_type, + lldb::eAccessPublic, 0); + + ast->CompleteTagDeclarationDefinition(siginfo_type); + return siginfo_type; +} diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.h b/lldb/source/Plugins/Platform/AIX/PlatformAIX.h new file mode 100644 index 0000000000000..3ae8089a48d71 --- /dev/null +++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.h @@ -0,0 +1,74 @@ +//===-- PlatformAIX.h -----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PLATFORM_AIX_PLATFORMAIX_H +#define LLDB_SOURCE_PLUGINS_PLATFORM_AIX_PLATFORMAIX_H + +#include "Plugins/Platform/POSIX/PlatformPOSIX.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" + +namespace lldb_private { +namespace platform_aix { + +class PlatformAIX : public PlatformPOSIX { +public: + PlatformAIX(bool is_host); + + static void Initialize(); + + static void Terminate(); + + // lldb_private::PluginInterface functions + static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch); + + static llvm::StringRef GetPluginNameStatic(bool is_host) { + return is_host ? Platform::GetHostPlatformName() : "remote-AIX"; + } + + static llvm::StringRef GetPluginDescriptionStatic(bool is_host); + + llvm::StringRef GetPluginName() override { + return GetPluginNameStatic(IsHost()); + } + + // lldb_private::Platform functions + llvm::StringRef GetDescription() override { + return GetPluginDescriptionStatic(IsHost()); + } + + void GetStatus(Stream &strm) override; + + std::vector + GetSupportedArchitectures(const ArchSpec &process_host_arch) override; + + uint32_t GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) override; + + bool CanDebugProcess() override; + + void CalculateTrapHandlerSymbolNames() override; + + lldb::UnwindPlanSP GetTrapHandlerUnwindPlan(const llvm::Triple &triple, + ConstString name) override; + + MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr, + lldb::addr_t length, unsigned prot, + unsigned flags, lldb::addr_t fd, + lldb::addr_t offset) override; + + CompilerType GetSiginfoType(const llvm::Triple &triple) override; + + std::vector m_supported_architectures; + +private: + std::unique_ptr m_type_system_up; +}; + +} // namespace platform_AIX +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_PLATFORM_AIX_PLATFORMAIX_H diff --git a/lldb/source/Plugins/Platform/CMakeLists.txt b/lldb/source/Plugins/Platform/CMakeLists.txt index 6869587f917eb..9d0afd97cff85 100644 --- a/lldb/source/Plugins/Platform/CMakeLists.txt +++ b/lldb/source/Plugins/Platform/CMakeLists.txt @@ -8,3 +8,4 @@ add_subdirectory(OpenBSD) add_subdirectory(POSIX) add_subdirectory(QemuUser) add_subdirectory(Windows) +add_subdirectory(AIX) diff --git a/lldb/source/Plugins/Process/AIX/CMakeLists.txt b/lldb/source/Plugins/Process/AIX/CMakeLists.txt new file mode 100644 index 0000000000000..e9d83266f5857 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/CMakeLists.txt @@ -0,0 +1,19 @@ +add_definitions("-D_ALL_SOURCE") + +add_lldb_library(lldbPluginProcessAIX + NativeProcessAIX.cpp + NativeRegisterContextAIX.cpp + NativeRegisterContextAIX_ppc64.cpp + NativeThreadAIX.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + lldbTarget + lldbUtility + lldbPluginProcessPOSIX + lldbPluginProcessUtility + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp new file mode 100644 index 0000000000000..882f20d30a3bf --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -0,0 +1,2048 @@ +//===-- NativeProcessAIX.cpp --------------------------------------------===// +// +// 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 "NativeProcessAIX.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "NativeThreadAIX.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +//#include "Plugins/Process/Utility/LinuxProcMaps.h" +//#include "Procfs.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/HostProcess.h" +#include "lldb/Host/ProcessLaunchInfo.h" +#include "lldb/Host/PseudoTerminal.h" +#include "lldb/Host/ThreadLauncher.h" +#include "lldb/Host/common/NativeRegisterContext.h" +#include "lldb/Host/aix/Ptrace.h" +//#include "lldb/Host/linux/Host.h" +//#include "lldb/Host/linux/Uio.h" +#include "lldb/Host/posix/ProcessLauncherPosixFork.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/State.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/StringExtractor.h" +#include "llvm/ADT/ScopeExit.h" +#include "llvm/Support/Errno.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Threading.h" + +#include +#include +#include +#include +//#include +#include +#include +#include +#include + +#ifdef __aarch64__ +#include +#include +#endif + +// Support hardware breakpoints in case it has not been defined +#ifndef TRAP_HWBKPT +#define TRAP_HWBKPT 4 +#endif + +#ifndef HWCAP2_MTE +#define HWCAP2_MTE (1 << 18) +#endif + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; +using namespace llvm; + +// Private bits we only need internally. + +static bool ProcessVmReadvSupported() { + static bool is_supported; + static llvm::once_flag flag; + + llvm::call_once(flag, [] { + Log *log = GetLog(POSIXLog::Process); + + uint32_t source = 0x47424742; + uint32_t dest = 0; + + struct iovec local, remote; + remote.iov_base = &source; + local.iov_base = &dest; + remote.iov_len = local.iov_len = sizeof source; + +#if 0 + // We shall try if cross-process-memory reads work by attempting to read a + // value from our own process. + ssize_t res = process_vm_readv(getpid(), &local, 1, &remote, 1, 0); + is_supported = (res == sizeof(source) && source == dest); + if (is_supported) + LLDB_LOG(log, + "Detected kernel support for process_vm_readv syscall. " + "Fast memory reads enabled."); + else + LLDB_LOG(log, + "syscall process_vm_readv failed (error: {0}). Fast memory " + "reads disabled.", + llvm::sys::StrError()); +#endif + }); + + return is_supported; +} + +static void MaybeLogLaunchInfo(const ProcessLaunchInfo &info) { + Log *log = GetLog(POSIXLog::Process); + if (!log) + return; + + if (const FileAction *action = info.GetFileActionForFD(STDIN_FILENO)) + LLDB_LOG(log, "setting STDIN to '{0}'", action->GetFileSpec()); + else + LLDB_LOG(log, "leaving STDIN as is"); + + if (const FileAction *action = info.GetFileActionForFD(STDOUT_FILENO)) + LLDB_LOG(log, "setting STDOUT to '{0}'", action->GetFileSpec()); + else + LLDB_LOG(log, "leaving STDOUT as is"); + + if (const FileAction *action = info.GetFileActionForFD(STDERR_FILENO)) + LLDB_LOG(log, "setting STDERR to '{0}'", action->GetFileSpec()); + else + LLDB_LOG(log, "leaving STDERR as is"); + + int i = 0; + for (const char **args = info.GetArguments().GetConstArgumentVector(); *args; + ++args, ++i) + LLDB_LOG(log, "arg {0}: '{1}'", i, *args); +} + +static void DisplayBytes(StreamString &s, void *bytes, uint32_t count) { + uint8_t *ptr = (uint8_t *)bytes; + const uint32_t loop_count = std::min(DEBUG_PTRACE_MAXBYTES, count); + for (uint32_t i = 0; i < loop_count; i++) { + s.Printf("[%x]", *ptr); + ptr++; + } +} + +static void PtraceDisplayBytes(int &req, void *data, size_t data_size) { + Log *log = GetLog(POSIXLog::Ptrace); + if (!log) + return; + StreamString buf; + + switch (req) { + case PTRACE_POKETEXT: { + DisplayBytes(buf, &data, 8); + LLDB_LOGV(log, "PTRACE_POKETEXT {0}", buf.GetData()); + break; + } + case PTRACE_POKEDATA: { + DisplayBytes(buf, &data, 8); + LLDB_LOGV(log, "PTRACE_POKEDATA {0}", buf.GetData()); + break; + } + case PTRACE_POKEUSER: { + DisplayBytes(buf, &data, 8); + LLDB_LOGV(log, "PTRACE_POKEUSER {0}", buf.GetData()); + break; + } + case PTRACE_SETREGS: { + DisplayBytes(buf, data, data_size); + LLDB_LOGV(log, "PTRACE_SETREGS {0}", buf.GetData()); + break; + } + case PTRACE_SETFPREGS: { + DisplayBytes(buf, data, data_size); + LLDB_LOGV(log, "PTRACE_SETFPREGS {0}", buf.GetData()); + break; + } +#if 0 + case PTRACE_SETSIGINFO: { + DisplayBytes(buf, data, sizeof(siginfo_t)); + LLDB_LOGV(log, "PTRACE_SETSIGINFO {0}", buf.GetData()); + break; + } +#endif + case PTRACE_SETREGSET: { + // Extract iov_base from data, which is a pointer to the struct iovec + DisplayBytes(buf, *(void **)data, data_size); + LLDB_LOGV(log, "PTRACE_SETREGSET {0}", buf.GetData()); + break; + } + default: {} + } +} + +static constexpr unsigned k_ptrace_word_size = sizeof(void *); +static_assert(sizeof(long) >= k_ptrace_word_size, + "Size of long must be larger than ptrace word size"); + +// Simple helper function to ensure flags are enabled on the given file +// descriptor. +static Status EnsureFDFlags(int fd, int flags) { + Status error; + + int status = fcntl(fd, F_GETFL); + if (status == -1) { + error.SetErrorToErrno(); + return error; + } + + if (fcntl(fd, F_SETFL, status | flags) == -1) { + error.SetErrorToErrno(); + return error; + } + + return error; +} + +#if 0 +static llvm::Error AddPtraceScopeNote(llvm::Error original_error) { + Expected ptrace_scope = GetPtraceScope(); + if (auto E = ptrace_scope.takeError()) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "error reading value of ptrace_scope: {0}", E); + + // The original error is probably more interesting than not being able to + // read or interpret ptrace_scope. + return original_error; + } + + // We only have suggestions to provide for 1-3. + switch (*ptrace_scope) { + case 1: + case 2: + return llvm::createStringError( + std::error_code(errno, std::generic_category()), + "The current value of ptrace_scope is %d, which can cause ptrace to " + "fail to attach to a running process. To fix this, run:\n" + "\tsudo sysctl -w kernel.yama.ptrace_scope=0\n" + "For more information, see: " + "https://www.kernel.org/doc/Documentation/security/Yama.txt.", + *ptrace_scope); + case 3: + return llvm::createStringError( + std::error_code(errno, std::generic_category()), + "The current value of ptrace_scope is 3, which will cause ptrace to " + "fail to attach to a running process. This value cannot be changed " + "without rebooting.\n" + "For more information, see: " + "https://www.kernel.org/doc/Documentation/security/Yama.txt."); + case 0: + default: + return original_error; + } +} +#endif + +NativeProcessAIX::Manager::Manager(MainLoop &mainloop) + : NativeProcessProtocol::Manager(mainloop) { + Status status; + m_sigchld_handle = mainloop.RegisterSignal( + SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status); + assert(m_sigchld_handle && status.Success()); +} + +// Public Static Methods + +llvm::Expected> +NativeProcessAIX::Manager::Launch(ProcessLaunchInfo &launch_info, + NativeDelegate &native_delegate) { + Log *log = GetLog(POSIXLog::Process); + + MaybeLogLaunchInfo(launch_info); + + Status status; + ::pid_t pid = ProcessLauncherPosixFork() + .LaunchProcess(launch_info, status) + .GetProcessId(); + LLDB_LOG(log, "pid = {0:x}", pid); + if (status.Fail()) { + LLDB_LOG(log, "failed to launch process: {0}", status); + return status.ToError(); + } + + // Wait for the child process to trap on its call to execve. + int wstatus = 0; + ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0); + assert(wpid == pid); + UNUSED_IF_ASSERT_DISABLED(wpid); + if (!WIFSTOPPED(wstatus)) { + LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}", + WaitStatus::Decode(wstatus)); + return llvm::make_error("Could not sync with inferior process", + llvm::inconvertibleErrorCode()); + } + LLDB_LOG(log, "inferior started, now in stopped state"); + + ProcessInstanceInfo Info; + if (!Host::GetProcessInfo(pid, Info)) { + return llvm::make_error("Cannot get process architectrue", + llvm::inconvertibleErrorCode()); + } + /*llvm::Expected arch_or = + NativeRegisterContextAIX::DetermineArchitecture(pid); + if (!arch_or) + return arch_or.takeError();*/ + + // Set the architecture to the exe architecture. + LLDB_LOG(log, "pid = {0}, detected architecture {1}", pid, + Info.GetArchitecture().GetArchitectureName()); + + return std::unique_ptr(new NativeProcessAIX( + pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate, + Info.GetArchitecture(), *this, {pid})); +} + +llvm::Expected> +NativeProcessAIX::Manager::Attach( + lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "pid = {0:x}", pid); + + ProcessInstanceInfo Info; + if (!Host::GetProcessInfo(pid, Info)) { + return llvm::make_error("Cannot get process architectrue", + llvm::inconvertibleErrorCode()); + } + auto tids_or = NativeProcessAIX::Attach(pid); + if (!tids_or) + return tids_or.takeError(); +#if 0 + ArrayRef<::pid_t> tids = *tids_or; + llvm::Expected arch_or = + NativeRegisterContextAIX::DetermineArchitecture(tids[0]); + if (!arch_or) + return arch_or.takeError(); +#endif + + return std::unique_ptr( + new NativeProcessAIX(pid, -1, native_delegate, Info.GetArchitecture(), *this, *tids_or)); +} + +lldb::addr_t NativeProcessAIX::GetSharedLibraryInfoAddress() { + // punt on this for now + return LLDB_INVALID_ADDRESS; +} + +NativeProcessAIX::Extension +NativeProcessAIX::Manager::GetSupportedExtensions() const { + NativeProcessAIX::Extension supported = + Extension::multiprocess | Extension::fork | Extension::vfork | + Extension::pass_signals | Extension::auxv | Extension::libraries_svr4 | + Extension::siginfo_read; + +#ifdef __aarch64__ + // At this point we do not have a process so read auxv directly. + if ((getauxval(AT_HWCAP2) & HWCAP2_MTE)) + supported |= Extension::memory_tagging; +#endif + + return supported; +} + +static std::optional> WaitPid() { + Log *log = GetLog(POSIXLog::Process); + + int status; + ::pid_t wait_pid = llvm::sys::RetryAfterSignal( + -1, ::waitpid, -1, &status, /*__WALL | __WNOTHREAD |*/ WNOHANG); + + if (wait_pid == 0) + return std::nullopt; + + if (wait_pid == -1) { + Status error(errno, eErrorTypePOSIX); + LLDB_LOG(log, "waitpid(-1, &status, _) failed: {1}", error); + return std::nullopt; + } + + WaitStatus wait_status = WaitStatus::Decode(status); + + LLDB_LOG(log, "waitpid(-1, &status, _) = {0}, status = {1}", wait_pid, + wait_status); + return std::make_pair(wait_pid, wait_status); +} + +void NativeProcessAIX::Manager::SigchldHandler() { + Log *log = GetLog(POSIXLog::Process); + while (true) { + auto wait_result = WaitPid(); + if (!wait_result) + return; + lldb::pid_t pid = wait_result->first; + WaitStatus status = wait_result->second; + + // Ask each process whether it wants to handle the event. Each event should + // be handled by exactly one process, but thread creation events require + // special handling. + // Thread creation consists of two events (one on the parent and one on the + // child thread) and they can arrive in any order nondeterministically. The + // parent event carries the information about the child thread, but not + // vice-versa. This means that if the child event arrives first, it may not + // be handled by any process (because it doesn't know the thread belongs to + // it). + bool handled = llvm::any_of(m_processes, [&](NativeProcessAIX *process) { + return process->TryHandleWaitStatus(pid, status); + }); + if (!handled) { + if (status.type == WaitStatus::Stop && status.status == SIGSTOP) { + // Store the thread creation event for later collection. + m_unowned_threads.insert(pid); + } else { + LLDB_LOG(log, "Ignoring waitpid event {0} for pid {1}", status, pid); + } + } + } +} + +void NativeProcessAIX::Manager::CollectThread(::pid_t tid) { + Log *log = GetLog(POSIXLog::Process); + + if (m_unowned_threads.erase(tid)) + return; // We've encountered this thread already. + + // The TID is not tracked yet, let's wait for it to appear. + int status = -1; + LLDB_LOG(log, + "received clone event for tid {0}. tid not tracked yet, " + "waiting for it to appear...", + tid); + ::pid_t wait_pid = + llvm::sys::RetryAfterSignal(-1, ::waitpid, tid, &status, P_ALL/*__WALL*/); + + // It's theoretically possible to get other events if the entire process was + // SIGKILLed before we got a chance to check this. In that case, we'll just + // clean everything up when we get the process exit event. + + LLDB_LOG(log, + "waitpid({0}, &status, __WALL) => {1} (errno: {2}, status = {3})", + tid, wait_pid, errno, WaitStatus::Decode(status)); +} + +// Public Instance Methods + +NativeProcessAIX::NativeProcessAIX(::pid_t pid, int terminal_fd, + NativeDelegate &delegate, + const ArchSpec &arch, Manager &manager, + llvm::ArrayRef<::pid_t> tids) + : NativeProcessProtocol(pid, terminal_fd, delegate), m_manager(manager), + m_arch(arch) { + manager.AddProcess(*this); + if (m_terminal_fd != -1) { + Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK); + assert(status.Success()); + } + + for (const auto &tid : tids) { + NativeThreadAIX &thread = AddThread(tid, /*resume*/ false); + ThreadWasCreated(thread); + } + + // Let our process instance know the thread has stopped. + SetCurrentThreadID(tids[0]); + SetState(StateType::eStateStopped, false); +} + +llvm::Expected> NativeProcessAIX::Attach(::pid_t pid) { + Log *log = GetLog(POSIXLog::Process); + + Status status; + if ((status = PtraceWrapper(PT_ATTACH, pid)).Fail()) { + return status.ToError(); + } + + int wpid = + llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, nullptr, WNOHANG); + if (wpid <= 0) { + return llvm::errorCodeToError( + std::error_code(errno, std::generic_category())); + } + + LLDB_LOG(log, "adding pid = {0}", pid); + + std::vector<::pid_t> tids; + tids.push_back(pid); + return std::move(tids); +} + +bool NativeProcessAIX::TryHandleWaitStatus(lldb::pid_t pid, + WaitStatus status) { + if (pid == GetID() && + (status.type == WaitStatus::Exit || status.type == WaitStatus::Signal)) { + // The process exited. We're done monitoring. Report to delegate. + SetExitStatus(status, true); + return true; + } + if (NativeThreadAIX *thread = GetThreadByID(pid)) { + MonitorCallback(*thread, status); + return true; + } + return false; +} + +// Handles all waitpid events from the inferior process. +void NativeProcessAIX::MonitorCallback(NativeThreadAIX &thread, + WaitStatus status) { + Log *log = GetLog(LLDBLog::Process); + + // Certain activities differ based on whether the pid is the tid of the main + // thread. + const bool is_main_thread = (thread.GetID() == GetID()); + + // Handle when the thread exits. + if (status.type == WaitStatus::Exit || status.type == WaitStatus::Signal) { + LLDB_LOG(log, + "got exit status({0}) , tid = {1} ({2} main thread), process " + "state = {3}", + status, thread.GetID(), is_main_thread ? "is" : "is not", + GetState()); + + // This is a thread that exited. Ensure we're not tracking it anymore. + StopTrackingThread(thread); + + assert(!is_main_thread && "Main thread exits handled elsewhere"); + return; + } + + int8_t signo = GetSignalInfo(status); + + // Get details on the signal raised. + if (signo) { + // We have retrieved the signal info. Dispatch appropriately. + if (signo == SIGTRAP) + MonitorSIGTRAP(status, thread); + else + MonitorSignal(status, thread); + } else { + assert(0); + } +} + + +void NativeProcessAIX::MonitorSIGTRAP(const WaitStatus status, + NativeThreadAIX &thread) { + Log *log = GetLog(POSIXLog::Process); + const bool is_main_thread = (thread.GetID() == GetID()); + + NativeRegisterContextAIX ®_ctx = thread.GetRegisterContext(); + const RegisterInfo *pc_info = reg_ctx.GetRegisterInfoByName("pc", 0); + RegisterValue pc_value; + + switch (status.status) { + case SIGTRAP: + // Determine the source of SIGTRAP by checking current instruction: + // if that is trap instruction, then this is breakpoint, otherwise + // this is watchpoint. + reg_ctx.ReadRegister(pc_info, pc_value); + + MonitorBreakpoint(thread); + break; + default: + LLDB_LOG(log, "received unknown SIGTRAP stop event ({0}, pid {1} tid {2}", + status.status, GetID(), thread.GetID()); + MonitorSignal(status, thread); + break; + } +} + +void NativeProcessAIX::MonitorTrace(NativeThreadAIX &thread) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "received trace event, pid = {0}", thread.GetID()); + + // This thread is currently stopped. + thread.SetStoppedByTrace(); + + StopRunningThreads(thread.GetID()); +} + +void NativeProcessAIX::MonitorBreakpoint(NativeThreadAIX &thread) { + Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints); + LLDB_LOG(log, "received breakpoint event, pid = {0}", thread.GetID()); + + // Mark the thread as stopped at breakpoint. + thread.SetStoppedByBreakpoint(); + FixupBreakpointPCAsNeeded(thread); + + if (m_threads_stepping_with_breakpoint.find(thread.GetID()) != + m_threads_stepping_with_breakpoint.end()) + thread.SetStoppedByTrace(); + + StopRunningThreads(thread.GetID()); +} + +void NativeProcessAIX::MonitorWatchpoint(NativeThreadAIX &thread, + uint32_t wp_index) { + Log *log = GetLog(LLDBLog::Process | LLDBLog::Watchpoints); + LLDB_LOG(log, "received watchpoint event, pid = {0}, wp_index = {1}", + thread.GetID(), wp_index); + + // Mark the thread as stopped at watchpoint. The address is at + // (lldb::addr_t)info->si_addr if we need it. + thread.SetStoppedByWatchpoint(wp_index); + + // We need to tell all other running threads before we notify the delegate + // about this stop. + StopRunningThreads(thread.GetID()); +} + +void NativeProcessAIX::MonitorSignal(const WaitStatus status, + NativeThreadAIX &thread) { + int8_t signo = GetSignalInfo(status); +#if 0 + const bool is_from_llgs = info.si_pid == getpid(); +#endif + + Log *log = GetLog(POSIXLog::Process); + + // POSIX says that process behaviour is undefined after it ignores a SIGFPE, + // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a kill(2) + // or raise(3). Similarly for tgkill(2) on AIX. + // + // IOW, user generated signals never generate what we consider to be a + // "crash". + // + // Similarly, ACK signals generated by this monitor. + + // Handle the signal. + LLDB_LOG(log, + "received signal {0} ({1}) with code NA, (siginfo pid = {2}, " + "waitpid pid = {3})", + Host::GetSignalAsCString(signo), signo, thread.GetID(), GetID()); + +#if 0 + // Check for thread stop notification. + // FIXME + if (is_from_llgs /*&& (info.si_code == SI_TKILL)*/ && (signo == SIGSTOP)) { + // This is a tgkill()-based stop. + LLDB_LOG(log, "pid {0} tid {1}, thread stopped", GetID(), thread.GetID()); + + // Check that we're not already marked with a stop reason. Note this thread + // really shouldn't already be marked as stopped - if we were, that would + // imply that the kernel signaled us with the thread stopping which we + // handled and marked as stopped, and that, without an intervening resume, + // we received another stop. It is more likely that we are missing the + // marking of a run state somewhere if we find that the thread was marked + // as stopped. + const StateType thread_state = thread.GetState(); + if (!StateIsStoppedState(thread_state, false)) { + // An inferior thread has stopped because of a SIGSTOP we have sent it. + // Generally, these are not important stops and we don't want to report + // them as they are just used to stop other threads when one thread (the + // one with the *real* stop reason) hits a breakpoint (watchpoint, + // etc...). However, in the case of an asynchronous Interrupt(), this + // *is* the real stop reason, so we leave the signal intact if this is + // the thread that was chosen as the triggering thread. + if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID) { + if (m_pending_notification_tid == thread.GetID()) + thread.SetStoppedBySignal(SIGSTOP, &info); + else + thread.SetStoppedWithNoReason(); + + SetCurrentThreadID(thread.GetID()); + SignalIfAllThreadsStopped(); + } else { + // We can end up here if stop was initiated by LLGS but by this time a + // thread stop has occurred - maybe initiated by another event. + Status error = ResumeThread(thread, thread.GetState(), 0); + if (error.Fail()) + LLDB_LOG(log, "failed to resume thread {0}: {1}", thread.GetID(), + error); + } + } else { + LLDB_LOG(log, + "pid {0} tid {1}, thread was already marked as a stopped " + "state (state={2}), leaving stop signal as is", + GetID(), thread.GetID(), thread_state); + SignalIfAllThreadsStopped(); + } + + // Done handling. + return; + } +#endif + + // Check if debugger should stop at this signal or just ignore it and resume + // the inferior. + if (m_signals_to_ignore.contains(signo) || signo == SIGCHLD) { + ResumeThread(thread, thread.GetState(), signo); + return; + } + + // This thread is stopped. + LLDB_LOG(log, "received signal {0}", Host::GetSignalAsCString(signo)); + thread.SetStoppedBySignal(signo); + + // Send a stop to the debugger after we get all other threads to stop. + StopRunningThreads(thread.GetID()); +} + +bool NativeProcessAIX::MonitorClone(NativeThreadAIX &parent, + lldb::pid_t child_pid, int event) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "parent_tid={0}, child_pid={1}, event={2}", parent.GetID(), + child_pid, event); + + // WaitForCloneNotification(child_pid); + + switch (event) { +#if 0 + case PTRACE_EVENT_CLONE: { + // PTRACE_EVENT_CLONE can either mean a new thread or a new process. + // Try to grab the new process' PGID to figure out which one it is. + // If PGID is the same as the PID, then it's a new process. Otherwise, + // it's a thread. + auto tgid_ret = getPIDForTID(child_pid); + if (tgid_ret != child_pid) { + // A new thread should have PGID matching our process' PID. + assert(!tgid_ret || tgid_ret.getValue() == GetID()); + + NativeThreadAIX &child_thread = AddThread(child_pid, /*resume*/ true); + ThreadWasCreated(child_thread); + + // Resume the parent. + ResumeThread(parent, parent.GetState(), LLDB_INVALID_SIGNAL_NUMBER); + break; + } + } + LLVM_FALLTHROUGH; + case PTRACE_EVENT_FORK: + case PTRACE_EVENT_VFORK: { + bool is_vfork = event == PTRACE_EVENT_VFORK; + std::unique_ptr child_process{new NativeProcessAIX( + static_cast<::pid_t>(child_pid), m_terminal_fd, m_delegate, m_arch, + m_main_loop, {static_cast<::pid_t>(child_pid)})}; + if (!is_vfork) + child_process->m_software_breakpoints = m_software_breakpoints; + + Extension expected_ext = is_vfork ? Extension::vfork : Extension::fork; + if (bool(m_enabled_extensions & expected_ext)) { + m_delegate.NewSubprocess(this, std::move(child_process)); + // NB: non-vfork clone() is reported as fork + parent.SetStoppedByFork(is_vfork, child_pid); + StopRunningThreads(parent.GetID()); + } else { + child_process->Detach(); + ResumeThread(parent, parent.GetState(), LLDB_INVALID_SIGNAL_NUMBER); + } + break; + } +#endif + default: + llvm_unreachable("unknown clone_info.event"); + } + + return true; +} + +bool NativeProcessAIX::SupportHardwareSingleStepping() const { + return false; +} + +Status NativeProcessAIX::Resume(const ResumeActionList &resume_actions) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "pid {0}", GetID()); + + bool software_single_step = !SupportHardwareSingleStepping(); + + if (software_single_step) { + for (const auto &thread : m_threads) { + assert(thread && "thread list should not contain NULL threads"); + + const ResumeAction *const action = + resume_actions.GetActionForThread(thread->GetID(), true); + if (action == nullptr) + continue; + + if (action->state == eStateStepping) { + Status error = SetupSoftwareSingleStepping( + static_cast(*thread)); + if (error.Fail()) + return error; + } + } + } + + for (const auto &thread : m_threads) { + assert(thread && "thread list should not contain NULL threads"); + + const ResumeAction *const action = + resume_actions.GetActionForThread(thread->GetID(), true); + + if (action == nullptr) { + LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(), + thread->GetID()); + continue; + } + + LLDB_LOG(log, "processing resume action state {0} for pid {1} tid {2}", + action->state, GetID(), thread->GetID()); + + switch (action->state) { + case eStateRunning: + case eStateStepping: { + // Run the thread, possibly feeding it the signal. + const int signo = action->signal; + Status error = ResumeThread(static_cast(*thread), + action->state, signo); + if (error.Fail()) + return Status("NativeProcessAIX::%s: failed to resume thread " + "for pid %" PRIu64 ", tid %" PRIu64 ", error = %s", + __FUNCTION__, GetID(), thread->GetID(), + error.AsCString()); + + break; + } + + case eStateSuspended: + case eStateStopped: + break; + + default: + return Status("NativeProcessAIX::%s (): unexpected state %s specified " + "for pid %" PRIu64 ", tid %" PRIu64, + __FUNCTION__, StateAsCString(action->state), GetID(), + thread->GetID()); + } + } + + return Status(); +} + +Status NativeProcessAIX::Halt() { + Status error; + + if (kill(GetID(), SIGSTOP) != 0) + error.SetErrorToErrno(); + + return error; +} + +Status NativeProcessAIX::Detach() { + Status error; + + // Tell ptrace to detach from the process. + if (GetID() == LLDB_INVALID_PROCESS_ID) + return error; + + // Cancel out any SIGSTOPs we may have sent while stopping the process. + // Otherwise, the process may stop as soon as we detach from it. + kill(GetID(), SIGCONT); + + for (const auto &thread : m_threads) { + Status e = Detach(thread->GetID()); + if (e.Fail()) + error = + e; // Save the error, but still attempt to detach from other threads. + } + + return error; +} + +Status NativeProcessAIX::Signal(int signo) { + Status error; + + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "sending signal {0} ({1}) to pid {1}", signo, + Host::GetSignalAsCString(signo), GetID()); + + if (kill(GetID(), signo)) + error.SetErrorToErrno(); + + return error; +} + +Status NativeProcessAIX::Interrupt() { + // Pick a running thread (or if none, a not-dead stopped thread) as the + // chosen thread that will be the stop-reason thread. + Log *log = GetLog(POSIXLog::Process); + + NativeThreadProtocol *running_thread = nullptr; + NativeThreadProtocol *stopped_thread = nullptr; + + LLDB_LOG(log, "selecting running thread for interrupt target"); + for (const auto &thread : m_threads) { + // If we have a running or stepping thread, we'll call that the target of + // the interrupt. + const auto thread_state = thread->GetState(); + if (thread_state == eStateRunning || thread_state == eStateStepping) { + running_thread = thread.get(); + break; + } else if (!stopped_thread && StateIsStoppedState(thread_state, true)) { + // Remember the first non-dead stopped thread. We'll use that as a + // backup if there are no running threads. + stopped_thread = thread.get(); + } + } + + if (!running_thread && !stopped_thread) { + Status error("found no running/stepping or live stopped threads as target " + "for interrupt"); + LLDB_LOG(log, "skipping due to error: {0}", error); + + return error; + } + + NativeThreadProtocol *deferred_signal_thread = + running_thread ? running_thread : stopped_thread; + + LLDB_LOG(log, "pid {0} {1} tid {2} chosen for interrupt target", GetID(), + running_thread ? "running" : "stopped", + deferred_signal_thread->GetID()); + + StopRunningThreads(deferred_signal_thread->GetID()); + + return Status(); +} + +Status NativeProcessAIX::Kill() { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "pid {0}", GetID()); + + Status error; + + switch (m_state) { + case StateType::eStateInvalid: + case StateType::eStateExited: + case StateType::eStateCrashed: + case StateType::eStateDetached: + case StateType::eStateUnloaded: + // Nothing to do - the process is already dead. + LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(), + m_state); + return error; + + case StateType::eStateConnected: + case StateType::eStateAttaching: + case StateType::eStateLaunching: + case StateType::eStateStopped: + case StateType::eStateRunning: + case StateType::eStateStepping: + case StateType::eStateSuspended: + // We can try to kill a process in these states. + break; + } + + if (kill(GetID(), SIGKILL) != 0) { + error.SetErrorToErrno(); + return error; + } + + return error; +} + +Status NativeProcessAIX::GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info) { + // FIXME review that the final memory region returned extends to the end of + // the virtual address space, + // with no perms if it is not mapped. + + // Use an approach that reads memory regions from /proc/{pid}/maps. Assume + // proc maps entries are in ascending order. + // FIXME assert if we find differently. + + if (m_supports_mem_region == LazyBool::eLazyBoolNo) { + // We're done. + return Status("unsupported"); + } + + Status error = PopulateMemoryRegionCache(); + if (error.Fail()) { + return error; + } + + lldb::addr_t prev_base_address = 0; + + // FIXME start by finding the last region that is <= target address using + // binary search. Data is sorted. + // There can be a ton of regions on pthreads apps with lots of threads. + for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end(); + ++it) { + MemoryRegionInfo &proc_entry_info = it->first; + + // Sanity check assumption that /proc/{pid}/maps entries are ascending. + assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) && + "descending /proc/pid/maps entries detected, unexpected"); + prev_base_address = proc_entry_info.GetRange().GetRangeBase(); + UNUSED_IF_ASSERT_DISABLED(prev_base_address); + + // If the target address comes before this entry, indicate distance to next + // region. + if (load_addr < proc_entry_info.GetRange().GetRangeBase()) { + range_info.GetRange().SetRangeBase(load_addr); + range_info.GetRange().SetByteSize( + proc_entry_info.GetRange().GetRangeBase() - load_addr); + range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); + + return error; + } else if (proc_entry_info.GetRange().Contains(load_addr)) { + // The target address is within the memory region we're processing here. + range_info = proc_entry_info; + return error; + } + + // The target memory address comes somewhere after the region we just + // parsed. + } + + // If we made it here, we didn't find an entry that contained the given + // address. Return the load_addr as start and the amount of bytes betwwen + // load address and the end of the memory as size. + range_info.GetRange().SetRangeBase(load_addr); + range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS); + range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); + return error; +} + +Status NativeProcessAIX::PopulateMemoryRegionCache() { + Log *log = GetLog(POSIXLog::Process); + + // If our cache is empty, pull the latest. There should always be at least + // one memory region if memory region handling is supported. + if (!m_mem_region_cache.empty()) { + LLDB_LOG(log, "reusing {0} cached memory region entries", + m_mem_region_cache.size()); + return Status(); + } + + Status Result; +#if 0 + AIXMapCallback callback = [&](llvm::Expected Info) { + if (Info) { + FileSpec file_spec(Info->GetName().GetCString()); + FileSystem::Instance().Resolve(file_spec); + m_mem_region_cache.emplace_back(*Info, file_spec); + return true; + } + + Result = Info.takeError(); + m_supports_mem_region = LazyBool::eLazyBoolNo; + LLDB_LOG(log, "failed to parse proc maps: {0}", Result); + return false; + }; + + // AIX kernel since 2.6.14 has /proc/{pid}/smaps + // if CONFIG_PROC_PAGE_MONITOR is enabled + auto BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "smaps"); + if (BufferOrError) + ParseAIXSMapRegions(BufferOrError.get()->getBuffer(), callback); + else { + BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "maps"); + if (!BufferOrError) { + m_supports_mem_region = LazyBool::eLazyBoolNo; + return BufferOrError.getError(); + } + + ParseAIXMapRegions(BufferOrError.get()->getBuffer(), callback); + } + + if (Result.Fail()) + return Result; + + if (m_mem_region_cache.empty()) { + // No entries after attempting to read them. This shouldn't happen if + // /proc/{pid}/maps is supported. Assume we don't support map entries via + // procfs. + m_supports_mem_region = LazyBool::eLazyBoolNo; + LLDB_LOG(log, + "failed to find any procfs maps entries, assuming no support " + "for memory region metadata retrieval"); + return Status("not supported"); + } + + LLDB_LOG(log, "read {0} memory region entries from /proc/{1}/maps", + m_mem_region_cache.size(), GetID()); + + // We support memory retrieval, remember that. + m_supports_mem_region = LazyBool::eLazyBoolYes; +#endif + return Status(); +} + +void NativeProcessAIX::DoStopIDBumped(uint32_t newBumpId) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "newBumpId={0}", newBumpId); + LLDB_LOG(log, "clearing {0} entries from memory region cache", + m_mem_region_cache.size()); + m_mem_region_cache.clear(); +} + +llvm::Expected +NativeProcessAIX::Syscall(llvm::ArrayRef args) { + PopulateMemoryRegionCache(); + auto region_it = llvm::find_if(m_mem_region_cache, [](const auto &pair) { + return pair.first.GetExecutable() == MemoryRegionInfo::eYes && + pair.first.GetShared() != MemoryRegionInfo::eYes; + }); + if (region_it == m_mem_region_cache.end()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "No executable memory region found!"); + + addr_t exe_addr = region_it->first.GetRange().GetRangeBase(); + + NativeThreadAIX &thread = *GetCurrentThread(); + assert(thread.GetState() == eStateStopped); + NativeRegisterContextAIX ®_ctx = thread.GetRegisterContext(); + + NativeRegisterContextAIX::SyscallData syscall_data = + *reg_ctx.GetSyscallData(); + + WritableDataBufferSP registers_sp; + if (llvm::Error Err = reg_ctx.ReadAllRegisterValues(registers_sp).ToError()) + return std::move(Err); + auto restore_regs = llvm::make_scope_exit( + [&] { reg_ctx.WriteAllRegisterValues(registers_sp); }); + + llvm::SmallVector memory(syscall_data.Insn.size()); + size_t bytes_read; + if (llvm::Error Err = + ReadMemory(exe_addr, memory.data(), memory.size(), bytes_read) + .ToError()) { + return std::move(Err); + } + + auto restore_mem = llvm::make_scope_exit( + [&] { WriteMemory(exe_addr, memory.data(), memory.size(), bytes_read); }); + + if (llvm::Error Err = reg_ctx.SetPC(exe_addr).ToError()) + return std::move(Err); + + for (const auto &zip : llvm::zip_first(args, syscall_data.Args)) { + if (llvm::Error Err = + reg_ctx + .WriteRegisterFromUnsigned(std::get<1>(zip), std::get<0>(zip)) + .ToError()) { + return std::move(Err); + } + } + if (llvm::Error Err = WriteMemory(exe_addr, syscall_data.Insn.data(), + syscall_data.Insn.size(), bytes_read) + .ToError()) + return std::move(Err); + + m_mem_region_cache.clear(); + + // With software single stepping the syscall insn buffer must also include a + // trap instruction to stop the process. + int req = SupportHardwareSingleStepping() ? PTRACE_SINGLESTEP : PTRACE_CONT; + if (llvm::Error Err = + PtraceWrapper(req, thread.GetID(), nullptr, nullptr).ToError()) + return std::move(Err); + + //FIXME + int status; + ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, ::waitpid, thread.GetID(), + &status, P_ALL/*__WALL*/); + if (wait_pid == -1) { + return llvm::errorCodeToError( + std::error_code(errno, std::generic_category())); + } + assert((unsigned)wait_pid == thread.GetID()); + + uint64_t result = reg_ctx.ReadRegisterAsUnsigned(syscall_data.Result, -ESRCH); + + // Values larger than this are actually negative errno numbers. + uint64_t errno_threshold = + (uint64_t(-1) >> (64 - 8 * m_arch.GetAddressByteSize())) - 0x1000; + if (result > errno_threshold) { + return llvm::errorCodeToError( + std::error_code(-result & 0xfff, std::generic_category())); + } + + return result; +} + +llvm::Expected +NativeProcessAIX::AllocateMemory(size_t size, uint32_t permissions) { + + std::optional mmap_data = + GetCurrentThread()->GetRegisterContext().GetMmapData(); + if (!mmap_data) + return llvm::make_error(); + + unsigned prot = PROT_NONE; + assert((permissions & (ePermissionsReadable | ePermissionsWritable | + ePermissionsExecutable)) == permissions && + "Unknown permission!"); + if (permissions & ePermissionsReadable) + prot |= PROT_READ; + if (permissions & ePermissionsWritable) + prot |= PROT_WRITE; + if (permissions & ePermissionsExecutable) + prot |= PROT_EXEC; + + llvm::Expected Result = + Syscall({mmap_data->SysMmap, 0, size, prot, MAP_ANONYMOUS | MAP_PRIVATE, + uint64_t(-1), 0}); + if (Result) + m_allocated_memory.try_emplace(*Result, size); + return Result; +} + +llvm::Error NativeProcessAIX::DeallocateMemory(lldb::addr_t addr) { + std::optional mmap_data = + GetCurrentThread()->GetRegisterContext().GetMmapData(); + if (!mmap_data) + return llvm::make_error(); + + auto it = m_allocated_memory.find(addr); + if (it == m_allocated_memory.end()) + return llvm::createStringError(llvm::errc::invalid_argument, + "Memory not allocated by the debugger."); + + llvm::Expected Result = + Syscall({mmap_data->SysMunmap, addr, it->second}); + if (!Result) + return Result.takeError(); + + m_allocated_memory.erase(it); + return llvm::Error::success(); +} + +Status NativeProcessAIX::ReadMemoryTags(int32_t type, lldb::addr_t addr, + size_t len, + std::vector &tags) { + llvm::Expected details = + GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); + if (!details) + return Status(details.takeError()); + + // Ignore 0 length read + if (!len) + return Status(); + + // lldb will align the range it requests but it is not required to by + // the protocol so we'll do it again just in case. + // Remove tag bits too. Ptrace calls may work regardless but that + // is not a guarantee. + MemoryTagManager::TagRange range(details->manager->RemoveTagBits(addr), len); + range = details->manager->ExpandToGranule(range); + + // Allocate enough space for all tags to be read + size_t num_tags = range.GetByteSize() / details->manager->GetGranuleSize(); + tags.resize(num_tags * details->manager->GetTagSizeInBytes()); + + struct iovec tags_iovec; + uint8_t *dest = tags.data(); + lldb::addr_t read_addr = range.GetRangeBase(); + + // This call can return partial data so loop until we error or + // get all tags back. + while (num_tags) { + tags_iovec.iov_base = dest; + tags_iovec.iov_len = num_tags; + + Status error = NativeProcessAIX::PtraceWrapper( + details->ptrace_read_req, GetCurrentThreadID(), + reinterpret_cast(read_addr), static_cast(&tags_iovec), + 0, nullptr); + + if (error.Fail()) { + // Discard partial reads + tags.resize(0); + return error; + } + + size_t tags_read = tags_iovec.iov_len; + assert(tags_read && (tags_read <= num_tags)); + + dest += tags_read * details->manager->GetTagSizeInBytes(); + read_addr += details->manager->GetGranuleSize() * tags_read; + num_tags -= tags_read; + } + + return Status(); +} + +Status NativeProcessAIX::WriteMemoryTags(int32_t type, lldb::addr_t addr, + size_t len, + const std::vector &tags) { + llvm::Expected details = + GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); + if (!details) + return Status(details.takeError()); + + // Ignore 0 length write + if (!len) + return Status(); + + // lldb will align the range it requests but it is not required to by + // the protocol so we'll do it again just in case. + // Remove tag bits too. Ptrace calls may work regardless but that + // is not a guarantee. + MemoryTagManager::TagRange range(details->manager->RemoveTagBits(addr), len); + range = details->manager->ExpandToGranule(range); + + // Not checking number of tags here, we may repeat them below + llvm::Expected> unpacked_tags_or_err = + details->manager->UnpackTagsData(tags); + if (!unpacked_tags_or_err) + return Status(unpacked_tags_or_err.takeError()); + + llvm::Expected> repeated_tags_or_err = + details->manager->RepeatTagsForRange(*unpacked_tags_or_err, range); + if (!repeated_tags_or_err) + return Status(repeated_tags_or_err.takeError()); + + // Repack them for ptrace to use + llvm::Expected> final_tag_data = + details->manager->PackTags(*repeated_tags_or_err); + if (!final_tag_data) + return Status(final_tag_data.takeError()); + + struct iovec tags_vec; + uint8_t *src = final_tag_data->data(); + lldb::addr_t write_addr = range.GetRangeBase(); + // unpacked tags size because the number of bytes per tag might not be 1 + size_t num_tags = repeated_tags_or_err->size(); + + // This call can partially write tags, so we loop until we + // error or all tags have been written. + while (num_tags > 0) { + tags_vec.iov_base = src; + tags_vec.iov_len = num_tags; + + Status error = NativeProcessAIX::PtraceWrapper( + details->ptrace_write_req, GetCurrentThreadID(), + reinterpret_cast(write_addr), static_cast(&tags_vec), 0, + nullptr); + + if (error.Fail()) { + // Don't attempt to restore the original values in the case of a partial + // write + return error; + } + + size_t tags_written = tags_vec.iov_len; + assert(tags_written && (tags_written <= num_tags)); + + src += tags_written * details->manager->GetTagSizeInBytes(); + write_addr += details->manager->GetGranuleSize() * tags_written; + num_tags -= tags_written; + } + + return Status(); +} + +size_t NativeProcessAIX::UpdateThreads() { + // The NativeProcessAIX monitoring threads are always up to date with + // respect to thread state and they keep the thread list populated properly. + // All this method needs to do is return the thread count. + return m_threads.size(); +} + +Status NativeProcessAIX::SetBreakpoint(lldb::addr_t addr, uint32_t size, + bool hardware) { + if (hardware) + return SetHardwareBreakpoint(addr, size); + else + return SetSoftwareBreakpoint(addr, size); +} + +Status NativeProcessAIX::RemoveBreakpoint(lldb::addr_t addr, bool hardware) { + if (hardware) + return RemoveHardwareBreakpoint(addr); + else + return NativeProcessProtocol::RemoveBreakpoint(addr); +} + +llvm::Expected> +NativeProcessAIX::GetSoftwareBreakpointTrapOpcode(size_t size_hint) { + // The ARM reference recommends the use of 0xe7fddefe and 0xdefe but the + // linux kernel does otherwise. + static const uint8_t g_arm_opcode[] = {0xf0, 0x01, 0xf0, 0xe7}; + static const uint8_t g_thumb_opcode[] = {0x01, 0xde}; + + switch (GetArchitecture().GetMachine()) { + case llvm::Triple::arm: + switch (size_hint) { + case 2: + return llvm::ArrayRef(g_thumb_opcode); + case 4: + return llvm::ArrayRef(g_arm_opcode); + default: + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Unrecognised trap opcode size hint!"); + } + default: + return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint); + } +} + +Status NativeProcessAIX::ReadMemory(lldb::addr_t addr, void *buf, size_t size, + size_t &bytes_read) { + unsigned char *dst = static_cast(buf); + size_t remainder; + long data; + + Log *log = GetLog(POSIXLog::Memory); + LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); + + for (bytes_read = 0; bytes_read < size; bytes_read += remainder) { + Status error = NativeProcessAIX::PtraceWrapper( + PT_READ_BLOCK, GetCurrentThreadID(), (void *)addr, nullptr, sizeof(data), &data); + if (error.Fail()) + return error; + + remainder = size - bytes_read; + remainder = remainder > k_ptrace_word_size ? k_ptrace_word_size : remainder; + + // Copy the data into our buffer + memcpy(dst, &data, remainder); + + LLDB_LOG(log, "[{0:x}]:{1:x}", addr, data); + addr += k_ptrace_word_size; + dst += k_ptrace_word_size; + } + return Status(); +} + +Status NativeProcessAIX::WriteMemory(lldb::addr_t addr, const void *buf, + size_t size, size_t &bytes_written) { + const unsigned char *src = static_cast(buf); + size_t remainder; + Status error; + + Log *log = GetLog(POSIXLog::Memory); + LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); + + error = NativeProcessAIX::PtraceWrapper( + PT_WRITE_BLOCK, GetCurrentThreadID(), (void *)addr, nullptr, (int)size, (long *)buf); + if (error.Fail()) + return error; + + bytes_written = size; + return error; +} + +int8_t NativeProcessAIX::GetSignalInfo(WaitStatus wstatus) const { + return wstatus.status; +} + +Status NativeProcessAIX::GetEventMessage(lldb::tid_t tid, + unsigned long *message) { + //FIXME + return PtraceWrapper(PT_CLEAR/*PTRACE_GETEVENTMSG*/, tid, nullptr, message); +} + +Status NativeProcessAIX::Detach(lldb::tid_t tid) { + if (tid == LLDB_INVALID_THREAD_ID) + return Status(); + + return PtraceWrapper(PT_DETACH, tid); +} + +bool NativeProcessAIX::HasThreadNoLock(lldb::tid_t thread_id) { + for (const auto &thread : m_threads) { + assert(thread && "thread list should not contain NULL threads"); + if (thread->GetID() == thread_id) { + // We have this thread. + return true; + } + } + + // We don't have this thread. + return false; +} + +void NativeProcessAIX::StopTrackingThread(NativeThreadAIX &thread) { + Log *const log = GetLog(POSIXLog::Thread); + lldb::tid_t thread_id = thread.GetID(); + LLDB_LOG(log, "tid: {0}", thread_id); + + auto it = llvm::find_if(m_threads, [&](const auto &thread_up) { + return thread_up.get() == &thread; + }); + assert(it != m_threads.end()); + m_threads.erase(it); + + NotifyTracersOfThreadDestroyed(thread_id); + SignalIfAllThreadsStopped(); +} + +void NativeProcessAIX::NotifyTracersProcessDidStop() { +} + +void NativeProcessAIX::NotifyTracersProcessWillResume() { +} + +Status NativeProcessAIX::NotifyTracersOfNewThread(lldb::tid_t tid) { + Log *log = GetLog(POSIXLog::Thread); + Status error; + return error; +} + +Status NativeProcessAIX::NotifyTracersOfThreadDestroyed(lldb::tid_t tid) { + Log *log = GetLog(POSIXLog::Thread); + Status error; + return error; +} + +NativeThreadAIX &NativeProcessAIX::AddThread(lldb::tid_t thread_id, + bool resume) { + Log *log = GetLog(POSIXLog::Thread); + LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id); + + assert(!HasThreadNoLock(thread_id) && + "attempted to add a thread by id that already exists"); + + // If this is the first thread, save it as the current thread + if (m_threads.empty()) + SetCurrentThreadID(thread_id); + + m_threads.push_back(std::make_unique(*this, thread_id)); + NativeThreadAIX &thread = + static_cast(*m_threads.back()); + + Status tracing_error = NotifyTracersOfNewThread(thread.GetID()); + if (tracing_error.Fail()) { + thread.SetStoppedByProcessorTrace(tracing_error.AsCString()); + StopRunningThreads(thread.GetID()); + } else if (resume) + ResumeThread(thread, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); + else + thread.SetStoppedBySignal(SIGSTOP); + + return thread; +} + +Status NativeProcessAIX::GetLoadedModuleFileSpec(const char *module_path, + FileSpec &file_spec) { + Status error = PopulateMemoryRegionCache(); + if (error.Fail()) + return error; + + FileSpec module_file_spec(module_path); + FileSystem::Instance().Resolve(module_file_spec); + + file_spec.Clear(); + for (const auto &it : m_mem_region_cache) { + if (it.second.GetFilename() == module_file_spec.GetFilename()) { + file_spec = it.second; + return Status(); + } + } + return Status("Module file (%s) not found in /proc/%" PRIu64 "/maps file!", + module_file_spec.GetFilename().AsCString(), GetID()); +} + +Status NativeProcessAIX::GetFileLoadAddress(const llvm::StringRef &file_name, + lldb::addr_t &load_addr) { + load_addr = LLDB_INVALID_ADDRESS; + + NativeThreadAIX &thread = *GetCurrentThread(); + NativeRegisterContextAIX ®_ctx = thread.GetRegisterContext(); + + // FIXME: buffer size + struct ld_xinfo info[64]; + if (ptrace64(PT_LDXINFO, reg_ctx.GetThread().GetID(), (long long)&(info[0]), sizeof(info), nullptr) == 0) { + load_addr = (unsigned long)info[0].ldinfo_textorg; + return Status(); + } + return Status("No load address found for specified file."); +} + +NativeThreadAIX *NativeProcessAIX::GetThreadByID(lldb::tid_t tid) { + return static_cast( + NativeProcessProtocol::GetThreadByID(tid)); +} + +NativeThreadAIX *NativeProcessAIX::GetCurrentThread() { + return static_cast( + NativeProcessProtocol::GetCurrentThread()); +} + +Status NativeProcessAIX::ResumeThread(NativeThreadAIX &thread, + lldb::StateType state, int signo) { + Log *const log = GetLog(POSIXLog::Thread); + LLDB_LOG(log, "tid: {0}", thread.GetID()); + + // Before we do the resume below, first check if we have a pending stop + // notification that is currently waiting for all threads to stop. This is + // potentially a buggy situation since we're ostensibly waiting for threads + // to stop before we send out the pending notification, and here we are + // resuming one before we send out the pending stop notification. + if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID) { + LLDB_LOG(log, + "about to resume tid {0} per explicit request but we have a " + "pending stop notification (tid {1}) that is actively " + "waiting for this thread to stop. Valid sequence of events?", + thread.GetID(), m_pending_notification_tid); + } + + // Request a resume. We expect this to be synchronous and the system to + // reflect it is running after this completes. + switch (state) { + case eStateRunning: { + const auto resume_result = thread.Resume(signo); + if (resume_result.Success()) + SetState(eStateRunning, true); + return resume_result; + } + case eStateStepping: { + const auto step_result = thread.SingleStep(signo); + if (step_result.Success()) + SetState(eStateRunning, true); + return step_result; + } + default: + LLDB_LOG(log, "Unhandled state {0}.", state); + llvm_unreachable("Unhandled state for resume"); + } +} + +//===----------------------------------------------------------------------===// + +void NativeProcessAIX::StopRunningThreads(const lldb::tid_t triggering_tid) { + Log *const log = GetLog(POSIXLog::Thread); + LLDB_LOG(log, "about to process event: (triggering_tid: {0})", + triggering_tid); + + m_pending_notification_tid = triggering_tid; + + // Request a stop for all the thread stops that need to be stopped and are + // not already known to be stopped. + for (const auto &thread : m_threads) { + if (StateIsRunningState(thread->GetState())) + static_cast(thread.get())->RequestStop(); + } + + SignalIfAllThreadsStopped(); + LLDB_LOG(log, "event processing done"); +} + +void NativeProcessAIX::SignalIfAllThreadsStopped() { + if (m_pending_notification_tid == LLDB_INVALID_THREAD_ID) + return; // No pending notification. Nothing to do. + + for (const auto &thread_sp : m_threads) { + if (StateIsRunningState(thread_sp->GetState())) + return; // Some threads are still running. Don't signal yet. + } + + // We have a pending notification and all threads have stopped. + Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints); + + // Clear any temporary breakpoints we used to implement software single + // stepping. + for (const auto &thread_info : m_threads_stepping_with_breakpoint) { + Status error = RemoveBreakpoint(thread_info.second); + if (error.Fail()) + LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}", + thread_info.first, error); + } + m_threads_stepping_with_breakpoint.clear(); + + // Notify the delegate about the stop + SetCurrentThreadID(m_pending_notification_tid); + SetState(StateType::eStateStopped, true); + m_pending_notification_tid = LLDB_INVALID_THREAD_ID; +} + +void NativeProcessAIX::ThreadWasCreated(NativeThreadAIX &thread) { + Log *const log = GetLog(POSIXLog::Thread); + LLDB_LOG(log, "tid: {0}", thread.GetID()); + + if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID && + StateIsRunningState(thread.GetState())) { + // We will need to wait for this new thread to stop as well before firing + // the notification. + thread.RequestStop(); + } +} + +#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT +#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h" +#undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT + +static void GetRegister(lldb::pid_t pid, long long addr, void *buf) { + uint64_t val = 0; + ptrace64(PT_READ_GPR, pid, addr, 0, (int *)&val); + *(uint64_t *)buf = llvm::byteswap(val); +} + +static void SetRegister(lldb::pid_t pid, long long addr, void *buf) { + uint64_t val = llvm::byteswap(*(uint64_t *)buf); + ptrace64(PT_WRITE_GPR, pid, addr, 0, (int *)&val); +} + +static void GetFPRegister(lldb::pid_t pid, long long addr, void *buf) { + uint64_t val = 0; + ptrace64(PT_READ_FPR, pid, addr, 0, (int *)&val); + *(uint64_t *)buf = llvm::byteswap(val); +} + +static void GetVMRegister(lldb::tid_t tid, long long addr, void *buf) { + uint64_t val = 0; + ptrace64(PTT_READ_VEC, tid, addr, 0, (int *)&val); + //*(uint64_t *)buf = llvm::byteswap(val); +} + +static void GetVSRegister(lldb::tid_t tid, long long addr, void *buf) { + uint64_t val = 0; + ptrace64(PTT_READ_VSX, tid, addr, 0, (int *)&val); + //*(uint64_t *)buf = llvm::byteswap(val); +} + +// Wrapper for ptrace to catch errors and log calls. Note that ptrace sets +// errno on error because -1 can be a valid result (i.e. for PTRACE_PEEK*) +Status NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid, void *addr, + void *data, size_t data_size, + long *result) { + Status error; + long int ret; + + Log *log = GetLog(POSIXLog::Ptrace); + + PtraceDisplayBytes(req, data, data_size); + + errno = 0; + + // for PTT_* + const char procdir[] = "/proc/"; + const char lwpdir[] = "/lwp/"; + std::string process_task_dir = procdir + std::to_string(pid) + lwpdir; + DIR *dirproc = opendir(process_task_dir.c_str()); + + lldb::tid_t tid = 0; + if (dirproc) { + struct dirent *direntry = nullptr; + while ((direntry = readdir(dirproc)) != nullptr) { + if (strcmp(direntry->d_name, ".") == 0 || strcmp(direntry->d_name, "..") == 0) { + continue; + } + tid = atoi(direntry->d_name); + break; + } + closedir(dirproc); + } + + if (req == PTRACE_GETREGS) { + GetRegister(pid, GPR0, &(((GPR *)data)->r0)); + GetRegister(pid, GPR1, &(((GPR *)data)->r1)); + GetRegister(pid, GPR2, &(((GPR *)data)->r2)); + GetRegister(pid, GPR3, &(((GPR *)data)->r3)); + GetRegister(pid, GPR4, &(((GPR *)data)->r4)); + GetRegister(pid, GPR5, &(((GPR *)data)->r5)); + GetRegister(pid, GPR6, &(((GPR *)data)->r6)); + GetRegister(pid, GPR7, &(((GPR *)data)->r7)); + GetRegister(pid, GPR8, &(((GPR *)data)->r8)); + GetRegister(pid, GPR9, &(((GPR *)data)->r9)); + GetRegister(pid, GPR10, &(((GPR *)data)->r10)); + GetRegister(pid, GPR11, &(((GPR *)data)->r11)); + GetRegister(pid, GPR12, &(((GPR *)data)->r12)); + GetRegister(pid, GPR13, &(((GPR *)data)->r13)); + GetRegister(pid, GPR14, &(((GPR *)data)->r14)); + GetRegister(pid, GPR15, &(((GPR *)data)->r15)); + GetRegister(pid, GPR16, &(((GPR *)data)->r16)); + GetRegister(pid, GPR17, &(((GPR *)data)->r17)); + GetRegister(pid, GPR18, &(((GPR *)data)->r18)); + GetRegister(pid, GPR19, &(((GPR *)data)->r19)); + GetRegister(pid, GPR20, &(((GPR *)data)->r20)); + GetRegister(pid, GPR21, &(((GPR *)data)->r21)); + GetRegister(pid, GPR22, &(((GPR *)data)->r22)); + GetRegister(pid, GPR23, &(((GPR *)data)->r23)); + GetRegister(pid, GPR24, &(((GPR *)data)->r24)); + GetRegister(pid, GPR25, &(((GPR *)data)->r25)); + GetRegister(pid, GPR26, &(((GPR *)data)->r26)); + GetRegister(pid, GPR27, &(((GPR *)data)->r27)); + GetRegister(pid, GPR28, &(((GPR *)data)->r28)); + GetRegister(pid, GPR29, &(((GPR *)data)->r29)); + GetRegister(pid, GPR30, &(((GPR *)data)->r30)); + GetRegister(pid, GPR31, &(((GPR *)data)->r31)); + GetRegister(pid, IAR, &(((GPR *)data)->pc)); + GetRegister(pid, MSR, &(((GPR *)data)->msr)); + //FIXME: origr3/softe/trap on AIX? + GetRegister(pid, CTR, &(((GPR *)data)->ctr)); + GetRegister(pid, LR, &(((GPR *)data)->lr)); + GetRegister(pid, XER, &(((GPR *)data)->xer)); + GetRegister(pid, CR, &(((GPR *)data)->cr)); + } else if (req == PTRACE_SETREGS) { + SetRegister(pid, GPR0, &(((GPR *)data)->r0)); + SetRegister(pid, GPR1, &(((GPR *)data)->r1)); + SetRegister(pid, GPR2, &(((GPR *)data)->r2)); + SetRegister(pid, GPR3, &(((GPR *)data)->r3)); + SetRegister(pid, GPR4, &(((GPR *)data)->r4)); + SetRegister(pid, GPR5, &(((GPR *)data)->r5)); + SetRegister(pid, GPR6, &(((GPR *)data)->r6)); + SetRegister(pid, GPR7, &(((GPR *)data)->r7)); + SetRegister(pid, GPR8, &(((GPR *)data)->r8)); + SetRegister(pid, GPR9, &(((GPR *)data)->r9)); + SetRegister(pid, GPR10, &(((GPR *)data)->r10)); + SetRegister(pid, GPR11, &(((GPR *)data)->r11)); + SetRegister(pid, GPR12, &(((GPR *)data)->r12)); + SetRegister(pid, GPR13, &(((GPR *)data)->r13)); + SetRegister(pid, GPR14, &(((GPR *)data)->r14)); + SetRegister(pid, GPR15, &(((GPR *)data)->r15)); + SetRegister(pid, GPR16, &(((GPR *)data)->r16)); + SetRegister(pid, GPR17, &(((GPR *)data)->r17)); + SetRegister(pid, GPR18, &(((GPR *)data)->r18)); + SetRegister(pid, GPR19, &(((GPR *)data)->r19)); + SetRegister(pid, GPR20, &(((GPR *)data)->r20)); + SetRegister(pid, GPR21, &(((GPR *)data)->r21)); + SetRegister(pid, GPR22, &(((GPR *)data)->r22)); + SetRegister(pid, GPR23, &(((GPR *)data)->r23)); + SetRegister(pid, GPR24, &(((GPR *)data)->r24)); + SetRegister(pid, GPR25, &(((GPR *)data)->r25)); + SetRegister(pid, GPR26, &(((GPR *)data)->r26)); + SetRegister(pid, GPR27, &(((GPR *)data)->r27)); + SetRegister(pid, GPR28, &(((GPR *)data)->r28)); + SetRegister(pid, GPR29, &(((GPR *)data)->r29)); + SetRegister(pid, GPR30, &(((GPR *)data)->r30)); + SetRegister(pid, GPR31, &(((GPR *)data)->r31)); + SetRegister(pid, IAR, &(((GPR *)data)->pc)); + SetRegister(pid, MSR, &(((GPR *)data)->msr)); + //FIXME: origr3/softe/trap on AIX? + SetRegister(pid, CTR, &(((GPR *)data)->ctr)); + SetRegister(pid, LR, &(((GPR *)data)->lr)); + SetRegister(pid, XER, &(((GPR *)data)->xer)); + SetRegister(pid, CR, &(((GPR *)data)->cr)); + } else if (req == PTRACE_GETFPREGS) { + GetFPRegister(pid, FPR0, &(((FPR *)data)->f0)); + GetFPRegister(pid, FPR1, &(((FPR *)data)->f1)); + GetFPRegister(pid, FPR2, &(((FPR *)data)->f2)); + GetFPRegister(pid, FPR3, &(((FPR *)data)->f3)); + GetFPRegister(pid, FPR4, &(((FPR *)data)->f4)); + GetFPRegister(pid, FPR5, &(((FPR *)data)->f5)); + GetFPRegister(pid, FPR6, &(((FPR *)data)->f6)); + GetFPRegister(pid, FPR7, &(((FPR *)data)->f7)); + GetFPRegister(pid, FPR8, &(((FPR *)data)->f8)); + GetFPRegister(pid, FPR9, &(((FPR *)data)->f9)); + GetFPRegister(pid, FPR10, &(((FPR *)data)->f10)); + GetFPRegister(pid, FPR11, &(((FPR *)data)->f11)); + GetFPRegister(pid, FPR12, &(((FPR *)data)->f12)); + GetFPRegister(pid, FPR13, &(((FPR *)data)->f13)); + GetFPRegister(pid, FPR14, &(((FPR *)data)->f14)); + GetFPRegister(pid, FPR15, &(((FPR *)data)->f15)); + GetFPRegister(pid, FPR16, &(((FPR *)data)->f16)); + GetFPRegister(pid, FPR17, &(((FPR *)data)->f17)); + GetFPRegister(pid, FPR18, &(((FPR *)data)->f18)); + GetFPRegister(pid, FPR19, &(((FPR *)data)->f19)); + GetFPRegister(pid, FPR20, &(((FPR *)data)->f20)); + GetFPRegister(pid, FPR21, &(((FPR *)data)->f21)); + GetFPRegister(pid, FPR22, &(((FPR *)data)->f22)); + GetFPRegister(pid, FPR23, &(((FPR *)data)->f23)); + GetFPRegister(pid, FPR24, &(((FPR *)data)->f24)); + GetFPRegister(pid, FPR25, &(((FPR *)data)->f25)); + GetFPRegister(pid, FPR26, &(((FPR *)data)->f26)); + GetFPRegister(pid, FPR27, &(((FPR *)data)->f27)); + GetFPRegister(pid, FPR28, &(((FPR *)data)->f28)); + GetFPRegister(pid, FPR29, &(((FPR *)data)->f29)); + GetFPRegister(pid, FPR30, &(((FPR *)data)->f30)); + GetFPRegister(pid, FPR31, &(((FPR *)data)->f31)); + GetFPRegister(pid, FPSCR, &(((FPR *)data)->fpscr)); + } else if (req == PTRACE_GETVRREGS && tid) { + GetVMRegister(tid, VR0, &(((VMX *)data)->vr0[0])); + GetVMRegister(tid, VR1, &(((VMX *)data)->vr1[0])); + GetVMRegister(tid, VR2, &(((VMX *)data)->vr2[0])); + GetVMRegister(tid, VR3, &(((VMX *)data)->vr3[0])); + GetVMRegister(tid, VR4, &(((VMX *)data)->vr4[0])); + GetVMRegister(tid, VR5, &(((VMX *)data)->vr5[0])); + GetVMRegister(tid, VR6, &(((VMX *)data)->vr6[0])); + GetVMRegister(tid, VR7, &(((VMX *)data)->vr7[0])); + GetVMRegister(tid, VR8, &(((VMX *)data)->vr8[0])); + GetVMRegister(tid, VR9, &(((VMX *)data)->vr9[0])); + GetVMRegister(tid, VR10, &(((VMX *)data)->vr10[0])); + GetVMRegister(tid, VR11, &(((VMX *)data)->vr11[0])); + GetVMRegister(tid, VR12, &(((VMX *)data)->vr12[0])); + GetVMRegister(tid, VR13, &(((VMX *)data)->vr13[0])); + GetVMRegister(tid, VR14, &(((VMX *)data)->vr14[0])); + GetVMRegister(tid, VR15, &(((VMX *)data)->vr15[0])); + GetVMRegister(tid, VR16, &(((VMX *)data)->vr16[0])); + GetVMRegister(tid, VR17, &(((VMX *)data)->vr17[0])); + GetVMRegister(tid, VR18, &(((VMX *)data)->vr18[0])); + GetVMRegister(tid, VR19, &(((VMX *)data)->vr19[0])); + GetVMRegister(tid, VR20, &(((VMX *)data)->vr20[0])); + GetVMRegister(tid, VR21, &(((VMX *)data)->vr21[0])); + GetVMRegister(tid, VR22, &(((VMX *)data)->vr22[0])); + GetVMRegister(tid, VR23, &(((VMX *)data)->vr23[0])); + GetVMRegister(tid, VR24, &(((VMX *)data)->vr24[0])); + GetVMRegister(tid, VR25, &(((VMX *)data)->vr25[0])); + GetVMRegister(tid, VR26, &(((VMX *)data)->vr26[0])); + GetVMRegister(tid, VR27, &(((VMX *)data)->vr27[0])); + GetVMRegister(tid, VR28, &(((VMX *)data)->vr28[0])); + GetVMRegister(tid, VR29, &(((VMX *)data)->vr29[0])); + GetVMRegister(tid, VR30, &(((VMX *)data)->vr30[0])); + GetVMRegister(tid, VR31, &(((VMX *)data)->vr31[0])); + GetVMRegister(tid, VSCR, &(((VMX *)data)->vscr[0])); + GetVMRegister(tid, VRSAVE, &(((VMX *)data)->vrsave)); + } else if (req == PTRACE_GETVSRREGS && tid) { + GetVSRegister(tid, VSR0, &(((VSX *)data)->vs0[0])); + GetVSRegister(tid, VSR1, &(((VSX *)data)->vs1[0])); + GetVSRegister(tid, VSR2, &(((VSX *)data)->vs2[0])); + GetVSRegister(tid, VSR3, &(((VSX *)data)->vs3[0])); + GetVSRegister(tid, VSR4, &(((VSX *)data)->vs4[0])); + GetVSRegister(tid, VSR5, &(((VSX *)data)->vs5[0])); + GetVSRegister(tid, VSR6, &(((VSX *)data)->vs6[0])); + GetVSRegister(tid, VSR7, &(((VSX *)data)->vs7[0])); + GetVSRegister(tid, VSR8, &(((VSX *)data)->vs8[0])); + GetVSRegister(tid, VSR9, &(((VSX *)data)->vs9[0])); + GetVSRegister(tid, VSR10, &(((VSX *)data)->vs10[0])); + GetVSRegister(tid, VSR11, &(((VSX *)data)->vs11[0])); + GetVSRegister(tid, VSR12, &(((VSX *)data)->vs12[0])); + GetVSRegister(tid, VSR13, &(((VSX *)data)->vs13[0])); + GetVSRegister(tid, VSR14, &(((VSX *)data)->vs14[0])); + GetVSRegister(tid, VSR15, &(((VSX *)data)->vs15[0])); + GetVSRegister(tid, VSR16, &(((VSX *)data)->vs16[0])); + GetVSRegister(tid, VSR17, &(((VSX *)data)->vs17[0])); + GetVSRegister(tid, VSR18, &(((VSX *)data)->vs18[0])); + GetVSRegister(tid, VSR19, &(((VSX *)data)->vs19[0])); + GetVSRegister(tid, VSR20, &(((VSX *)data)->vs20[0])); + GetVSRegister(tid, VSR21, &(((VSX *)data)->vs21[0])); + GetVSRegister(tid, VSR22, &(((VSX *)data)->vs22[0])); + GetVSRegister(tid, VSR23, &(((VSX *)data)->vs23[0])); + GetVSRegister(tid, VSR24, &(((VSX *)data)->vs24[0])); + GetVSRegister(tid, VSR25, &(((VSX *)data)->vs25[0])); + GetVSRegister(tid, VSR26, &(((VSX *)data)->vs26[0])); + GetVSRegister(tid, VSR27, &(((VSX *)data)->vs27[0])); + GetVSRegister(tid, VSR28, &(((VSX *)data)->vs28[0])); + GetVSRegister(tid, VSR29, &(((VSX *)data)->vs29[0])); + GetVSRegister(tid, VSR30, &(((VSX *)data)->vs30[0])); + GetVSRegister(tid, VSR31, &(((VSX *)data)->vs31[0])); + GetVSRegister(tid, VSR32, &(((VSX *)data)->vs32[0])); + GetVSRegister(tid, VSR33, &(((VSX *)data)->vs33[0])); + GetVSRegister(tid, VSR34, &(((VSX *)data)->vs34[0])); + GetVSRegister(tid, VSR35, &(((VSX *)data)->vs35[0])); + GetVSRegister(tid, VSR36, &(((VSX *)data)->vs36[0])); + GetVSRegister(tid, VSR37, &(((VSX *)data)->vs37[0])); + GetVSRegister(tid, VSR38, &(((VSX *)data)->vs38[0])); + GetVSRegister(tid, VSR39, &(((VSX *)data)->vs39[0])); + GetVSRegister(tid, VSR40, &(((VSX *)data)->vs40[0])); + GetVSRegister(tid, VSR41, &(((VSX *)data)->vs41[0])); + GetVSRegister(tid, VSR42, &(((VSX *)data)->vs42[0])); + GetVSRegister(tid, VSR43, &(((VSX *)data)->vs43[0])); + GetVSRegister(tid, VSR44, &(((VSX *)data)->vs44[0])); + GetVSRegister(tid, VSR45, &(((VSX *)data)->vs45[0])); + GetVSRegister(tid, VSR46, &(((VSX *)data)->vs46[0])); + GetVSRegister(tid, VSR47, &(((VSX *)data)->vs47[0])); + GetVSRegister(tid, VSR48, &(((VSX *)data)->vs48[0])); + GetVSRegister(tid, VSR49, &(((VSX *)data)->vs49[0])); + GetVSRegister(tid, VSR50, &(((VSX *)data)->vs50[0])); + GetVSRegister(tid, VSR51, &(((VSX *)data)->vs51[0])); + GetVSRegister(tid, VSR52, &(((VSX *)data)->vs52[0])); + GetVSRegister(tid, VSR53, &(((VSX *)data)->vs53[0])); + GetVSRegister(tid, VSR54, &(((VSX *)data)->vs54[0])); + GetVSRegister(tid, VSR55, &(((VSX *)data)->vs55[0])); + GetVSRegister(tid, VSR56, &(((VSX *)data)->vs56[0])); + GetVSRegister(tid, VSR57, &(((VSX *)data)->vs57[0])); + GetVSRegister(tid, VSR58, &(((VSX *)data)->vs58[0])); + GetVSRegister(tid, VSR59, &(((VSX *)data)->vs59[0])); + GetVSRegister(tid, VSR60, &(((VSX *)data)->vs60[0])); + GetVSRegister(tid, VSR61, &(((VSX *)data)->vs61[0])); + GetVSRegister(tid, VSR62, &(((VSX *)data)->vs62[0])); + GetVSRegister(tid, VSR63, &(((VSX *)data)->vs63[0])); + } else if (req < PT_COMMAND_MAX) { + if (req == PT_CONTINUE) { +#if 0 + // Use PTT_CONTINUE + const char procdir[] = "/proc/"; + const char lwpdir[] = "/lwp/"; + std::string process_task_dir = procdir + std::to_string(pid) + lwpdir; + DIR *dirproc = opendir(process_task_dir.c_str()); + + struct ptthreads64 pts; + int idx = 0; + lldb::tid_t tid = 0; + if (dirproc) { + struct dirent *direntry = nullptr; + while ((direntry = readdir(dirproc)) != nullptr) { + if (strcmp(direntry->d_name, ".") == 0 || strcmp(direntry->d_name, "..") == 0) { + continue; + } + tid = atoi(direntry->d_name); + pts.th[idx++] = tid; + } + closedir(dirproc); + } + pts.th[idx] = 0; + ret = ptrace64(PTT_CONTINUE, tid, (long long)1, (int)(size_t)data, (int *)&pts); +#else + int buf; + ptrace64(req, pid, 1, (int)(size_t)data, &buf); +#endif + } else if (req == PT_READ_BLOCK) { + ptrace64(req, pid, (long long)addr, (int)data_size, (int *)result); + } else if (req == PT_WRITE_BLOCK) { + ptrace64(req, pid, (long long)addr, (int)data_size, (int *)result); + } else if (req == PT_ATTACH) { + ptrace64(req, pid, 0, 0, nullptr); + } else if (req == PT_WATCH) { + ptrace64(req, pid, (long long)addr, (int)data_size, nullptr); + } else if (req == PT_DETACH) { + ptrace64(req, pid, 0, 0, nullptr); + } else { + assert(0 && "Not supported yet."); + } + } else { + assert(0 && "Not supported yet."); + } + + if (errno) { + error.SetErrorToErrno(); + ret = -1; + } + + LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3}, {4})={5:x}", req, pid, addr, data, + data_size, ret); + + PtraceDisplayBytes(req, data, data_size); + + if (error.Fail()) + LLDB_LOG(log, "ptrace() failed: {0}", error); + + return error; +} + +llvm::Expected NativeProcessAIX::TraceSupported() { + return NativeProcessProtocol::TraceSupported(); +} + +Error NativeProcessAIX::TraceStart(StringRef json_request, StringRef type) { + return NativeProcessProtocol::TraceStart(json_request, type); +} + +Error NativeProcessAIX::TraceStop(const TraceStopRequest &request) { + return NativeProcessProtocol::TraceStop(request); +} + +Expected NativeProcessAIX::TraceGetState(StringRef type) { + return NativeProcessProtocol::TraceGetState(type); +} + +Expected> NativeProcessAIX::TraceGetBinaryData( + const TraceGetBinaryDataRequest &request) { + return NativeProcessProtocol::TraceGetBinaryData(request); +} diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h new file mode 100644 index 0000000000000..bdb6f7c500885 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h @@ -0,0 +1,283 @@ +//===-- NativeProcessAIX.h ---------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeProcessAIX_H_ +#define liblldb_NativeProcessAIX_H_ + +#include +#include + +#include "lldb/Host/Debug.h" +#include "lldb/Host/HostThread.h" +#include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/lldb-types.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "lldb/Host/aix/Support.h" + +#include "NativeThreadAIX.h" +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h" + +namespace lldb_private { +class Status; +class Scalar; + +namespace process_aix { +/// \class NativeProcessAIX +/// Manages communication with the inferior (debugee) process. +/// +/// Upon construction, this class prepares and launches an inferior process +/// for debugging. +/// +/// Changes in the inferior process state are broadcasted. +class NativeProcessAIX : public NativeProcessProtocol, + private NativeProcessSoftwareSingleStep { +public: + class Manager : public NativeProcessProtocol::Manager { + public: + Manager(MainLoop &mainloop); + + llvm::Expected> + Launch(ProcessLaunchInfo &launch_info, + NativeDelegate &native_delegate) override; + + llvm::Expected> + Attach(lldb::pid_t pid, NativeDelegate &native_delegate) override; + + Extension GetSupportedExtensions() const override; + + void AddProcess(NativeProcessAIX &process) { + m_processes.insert(&process); + } + + void RemoveProcess(NativeProcessAIX &process) { + m_processes.erase(&process); + } + + // Collect an event for the given tid, waiting for it if necessary. + void CollectThread(::pid_t tid); + + private: + MainLoop::SignalHandleUP m_sigchld_handle; + + llvm::SmallPtrSet m_processes; + + // Threads (events) which haven't been claimed by any process. + llvm::DenseSet<::pid_t> m_unowned_threads; + + void SigchldHandler(); + }; + + // NativeProcessProtocol Interface + + ~NativeProcessAIX() override { m_manager.RemoveProcess(*this); } + + Status Resume(const ResumeActionList &resume_actions) override; + + Status Halt() override; + + Status Detach() override; + + Status Signal(int signo) override; + + Status Interrupt() override; + + Status Kill() override; + + lldb::addr_t GetSharedLibraryInfoAddress() override; + + Status GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info) override; + + Status ReadMemory(lldb::addr_t addr, void *buf, size_t size, + size_t &bytes_read) override; + + Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, + size_t &bytes_written) override; + + llvm::Expected AllocateMemory(size_t size, + uint32_t permissions) override; + + llvm::Error DeallocateMemory(lldb::addr_t addr) override; + + Status ReadMemoryTags(int32_t type, lldb::addr_t addr, size_t len, + std::vector &tags) override; + + Status WriteMemoryTags(int32_t type, lldb::addr_t addr, size_t len, + const std::vector &tags) override; + + size_t UpdateThreads() override; + + const ArchSpec &GetArchitecture() const override { return m_arch; } + + Status SetBreakpoint(lldb::addr_t addr, uint32_t size, + bool hardware) override; + + Status RemoveBreakpoint(lldb::addr_t addr, bool hardware = false) override; + + void DoStopIDBumped(uint32_t newBumpId) override; + + Status GetLoadedModuleFileSpec(const char *module_path, + FileSpec &file_spec) override; + + Status GetFileLoadAddress(const llvm::StringRef &file_name, + lldb::addr_t &load_addr) override; + + NativeThreadAIX *GetThreadByID(lldb::tid_t id); + NativeThreadAIX *GetCurrentThread(); + + llvm::ErrorOr> + GetAuxvData() const override { + // Not available on this target. + return llvm::errc::not_supported; + } + + /// Tracing + /// These methods implement the jLLDBTrace packets + /// \{ + llvm::Error TraceStart(llvm::StringRef json_request, + llvm::StringRef type) override; + + llvm::Error TraceStop(const TraceStopRequest &request) override; + + llvm::Expected + TraceGetState(llvm::StringRef type) override; + + llvm::Expected> + TraceGetBinaryData(const TraceGetBinaryDataRequest &request) override; + + llvm::Expected TraceSupported() override; + /// } + + // Interface used by NativeRegisterContext-derived classes. + static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr, + void *data = nullptr, size_t data_size = 0, + long *result = nullptr); + + bool SupportHardwareSingleStepping() const; + + /// Writes a siginfo_t structure corresponding to the given thread ID to the + /// memory region pointed to by \p siginfo. + int8_t GetSignalInfo(WaitStatus wstatus) const; + +protected: + llvm::Expected> + GetSoftwareBreakpointTrapOpcode(size_t size_hint) override; + + llvm::Expected Syscall(llvm::ArrayRef args); + +private: + Manager &m_manager; + /*MainLoop::SignalHandleUP m_sigchld_handle;*/ + ArchSpec m_arch; + /*MainLoop& m_main_loop;*/ + + LazyBool m_supports_mem_region = eLazyBoolCalculate; + std::vector> m_mem_region_cache; + + lldb::tid_t m_pending_notification_tid = LLDB_INVALID_THREAD_ID; + + /// Inferior memory (allocated by us) and its size. + llvm::DenseMap m_allocated_memory; + + // Private Instance Methods + NativeProcessAIX(::pid_t pid, int terminal_fd, NativeDelegate &delegate, + const ArchSpec &arch, Manager &manager, + llvm::ArrayRef<::pid_t> tids); + + // Returns a list of process threads that we have attached to. + static llvm::Expected> Attach(::pid_t pid); + + static Status SetDefaultPtraceOpts(const lldb::pid_t); + + bool TryHandleWaitStatus(lldb::pid_t pid, WaitStatus status); + + void MonitorCallback(NativeThreadAIX &thread, WaitStatus status); + + void MonitorSIGTRAP(const WaitStatus status, NativeThreadAIX &thread); + + void MonitorTrace(NativeThreadAIX &thread); + + void MonitorBreakpoint(NativeThreadAIX &thread); + + void MonitorWatchpoint(NativeThreadAIX &thread, uint32_t wp_index); + + void MonitorSignal(const WaitStatus status, NativeThreadAIX &thread); + + bool HasThreadNoLock(lldb::tid_t thread_id); + + void StopTrackingThread(NativeThreadAIX &thread); + + /// Create a new thread. + /// + /// If process tracing is enabled and the thread can't be traced, then the + /// thread is left stopped with a \a eStopReasonProcessorTrace status, and + /// then the process is stopped. + /// + /// \param[in] resume + /// If a tracing error didn't happen, then resume the thread after + /// creation if \b true, or leave it stopped with SIGSTOP if \b false. + NativeThreadAIX &AddThread(lldb::tid_t thread_id, bool resume); + + /// Start tracing a new thread if process tracing is enabled. + /// + /// Trace mechanisms should modify this method to provide automatic tracing + /// for new threads. + Status NotifyTracersOfNewThread(lldb::tid_t tid); + + /// Stop tracing threads upon a destroy event. + /// + /// Trace mechanisms should modify this method to provide automatic trace + /// stopping for threads being destroyed. + Status NotifyTracersOfThreadDestroyed(lldb::tid_t tid); + + void NotifyTracersProcessWillResume() override; + + void NotifyTracersProcessDidStop() override; + /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG) + /// corresponding to the given thread ID to the memory pointed to by @p + /// message. + Status GetEventMessage(lldb::tid_t tid, unsigned long *message); + + void NotifyThreadDeath(lldb::tid_t tid); + + Status Detach(lldb::tid_t tid); + + // This method is requests a stop on all threads which are still running. It + // sets up a + // deferred delegate notification, which will fire once threads report as + // stopped. The + // triggerring_tid will be set as the current thread (main stop reason). + void StopRunningThreads(lldb::tid_t triggering_tid); + + // Notify the delegate if all threads have stopped. + void SignalIfAllThreadsStopped(); + + // Resume the given thread, optionally passing it the given signal. The type + // of resume + // operation (continue, single-step) depends on the state parameter. + Status ResumeThread(NativeThreadAIX &thread, lldb::StateType state, + int signo); + + void ThreadWasCreated(NativeThreadAIX &thread); + + void SigchldHandler(); + + Status PopulateMemoryRegionCache(); + + // Handle a clone()-like event. + bool MonitorClone(NativeThreadAIX &parent, lldb::pid_t child_pid, + int event); +}; + +} // namespace process_aix +} // namespace lldb_private + +#endif // #ifndef liblldb_NativeProcessAIX_H_ diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp new file mode 100644 index 0000000000000..0859f9501c1b6 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp @@ -0,0 +1,157 @@ +//===-- NativeRegisterContextAIX.cpp ------------------------------------===// +// +// 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 "NativeRegisterContextAIX.h" + +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/Utility/RegisterValue.h" + +#include "Plugins/Process/AIX/NativeProcessAIX.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "lldb/Host/aix/Ptrace.h" + +using namespace lldb_private; +using namespace lldb_private::process_aix; + +lldb::ByteOrder NativeRegisterContextAIX::GetByteOrder() const { + return m_thread.GetProcess().GetByteOrder(); +} + +Status NativeRegisterContextAIX::ReadRegisterRaw(uint32_t reg_index, + RegisterValue ®_value) { + const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); + if (!reg_info) + return Status("register %" PRIu32 " not found", reg_index); + + return DoReadRegisterValue(GetPtraceOffset(reg_index), reg_info->name, + reg_info->byte_size, reg_value); +} + +Status +NativeRegisterContextAIX::WriteRegisterRaw(uint32_t reg_index, + const RegisterValue ®_value) { + uint32_t reg_to_write = reg_index; + RegisterValue value_to_write = reg_value; + + // Check if this is a subregister of a full register. + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index); + if (reg_info->invalidate_regs && + (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) { + Status error; + + RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + error = ReadRegister(full_reg_info, full_value); + if (error.Fail()) + return error; + + lldb::ByteOrder byte_order = GetByteOrder(); + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData( + *full_reg_info, dst, sizeof(dst), byte_order, error); + if (error.Success() && dest_size) { + uint8_t src[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = reg_value.GetAsMemoryData( + *reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) { + // Copy the src bytes to the destination. + memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(*full_reg_info); + reg_to_write = full_reg; + } + } + } + + const RegisterInfo *const register_to_write_info_p = + GetRegisterInfoAtIndex(reg_to_write); + assert(register_to_write_info_p && + "register to write does not have valid RegisterInfo"); + if (!register_to_write_info_p) + return Status("NativeRegisterContextAIX::%s failed to get RegisterInfo " + "for write register index %" PRIu32, + __FUNCTION__, reg_to_write); + + return DoWriteRegisterValue(GetPtraceOffset(reg_index), reg_info->name, + reg_value); +} + +Status NativeRegisterContextAIX::ReadGPR() { + return NativeProcessAIX::PtraceWrapper( + PTRACE_GETREGS, m_thread.GetID(), nullptr, GetGPRBuffer(), GetGPRSize()); +} + +Status NativeRegisterContextAIX::WriteGPR() { + return NativeProcessAIX::PtraceWrapper( + PTRACE_SETREGS, m_thread.GetID(), nullptr, GetGPRBuffer(), GetGPRSize()); +} + +Status NativeRegisterContextAIX::ReadFPR() { + return NativeProcessAIX::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(), + nullptr, GetFPRBuffer(), + GetFPRSize()); +} + +Status NativeRegisterContextAIX::WriteFPR() { + return NativeProcessAIX::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(), + nullptr, GetFPRBuffer(), + GetFPRSize()); +} + +Status NativeRegisterContextAIX::ReadRegisterSet(void *buf, size_t buf_size, + unsigned int regset) { + return NativeProcessAIX::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), + static_cast(®set), buf, + buf_size); +} + +Status NativeRegisterContextAIX::WriteRegisterSet(void *buf, size_t buf_size, + unsigned int regset) { + return NativeProcessAIX::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), + static_cast(®set), buf, + buf_size); +} + +Status NativeRegisterContextAIX::DoReadRegisterValue(uint32_t offset, + const char *reg_name, + uint32_t size, + RegisterValue &value) { + Log *log = GetLog(POSIXLog::Registers); + + long data; + Status error = NativeProcessAIX::PtraceWrapper( + PTRACE_PEEKUSER, m_thread.GetID(), reinterpret_cast(offset), + nullptr, 0, &data); + + if (error.Success()) + // First cast to an unsigned of the same size to avoid sign extension. + value.SetUInt(static_cast(data), size); + + LLDB_LOG(log, "{0}: {1:x}", reg_name, data); + return error; +} + +Status NativeRegisterContextAIX::DoWriteRegisterValue( + uint32_t offset, const char *reg_name, const RegisterValue &value) { + Log *log = GetLog(POSIXLog::Registers); + + void *buf = reinterpret_cast(value.GetAsUInt64()); + LLDB_LOG(log, "{0}: {1}", reg_name, buf); + + return NativeProcessAIX::PtraceWrapper( + PTRACE_POKEUSER, m_thread.GetID(), reinterpret_cast(offset), buf); +} diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h new file mode 100644 index 0000000000000..9c2a326856c0b --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h @@ -0,0 +1,133 @@ +//===-- NativeRegisterContextAIX.h ----------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_NativeRegisterContextAIX_h +#define lldb_NativeRegisterContextAIX_h + +#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h" +#include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/Target/MemoryTagManager.h" +#include "llvm/Support/Error.h" + +namespace lldb_private { +namespace process_aix { + +class NativeThreadAIX; + +class NativeRegisterContextAIX + : public virtual NativeRegisterContextRegisterInfo { +public: + // This function is implemented in the NativeRegisterContextAIX_* subclasses + // to create a new instance of the host specific NativeRegisterContextAIX. + // The implementations can't collide as only one NativeRegisterContextAIX_* + // variant should be compiled into the final executable. + static std::unique_ptr + CreateHostNativeRegisterContextAIX(const ArchSpec &target_arch, + NativeThreadAIX &native_thread); + + // Invalidates cached values in register context data structures + virtual void InvalidateAllRegisters(){} + + struct SyscallData { + /// The syscall instruction. If the architecture uses software + /// single-stepping, the instruction should also be followed by a trap to + /// ensure the process is stopped after the syscall. + llvm::ArrayRef Insn; + + /// Registers used for syscall arguments. The first register is used to + /// store the syscall number. + llvm::ArrayRef Args; + + uint32_t Result; ///< Register containing the syscall result. + }; + /// Return architecture-specific data needed to make inferior syscalls, if + /// they are supported. + virtual std::optional GetSyscallData() { return std::nullopt; } + + struct MmapData { + // Syscall numbers can be found (e.g.) in /usr/include/asm/unistd.h for the + // relevant architecture. + unsigned SysMmap; ///< mmap syscall number. + unsigned SysMunmap; ///< munmap syscall number + }; + /// Return the architecture-specific data needed to make mmap syscalls, if + /// they are supported. + virtual std::optional GetMmapData() { return std::nullopt; } + + struct MemoryTaggingDetails { + /// Object with tag handling utilities. If the function below returns + /// a valid structure, you can assume that this pointer is valid. + std::unique_ptr manager; + int ptrace_read_req; /// ptrace operation number for memory tag read + int ptrace_write_req; /// ptrace operation number for memory tag write + }; + /// Return architecture specific data needed to use memory tags, + /// if they are supported. + virtual llvm::Expected + GetMemoryTaggingDetails(int32_t type) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Architecture does not support memory tagging"); + } + +protected: + // NB: This constructor is here only because gcc<=6.5 requires a virtual base + // class initializer on abstract class (even though it is never used). It can + // be deleted once we move to gcc>=7.0. + NativeRegisterContextAIX(NativeThreadProtocol &thread) + : NativeRegisterContextRegisterInfo(thread, nullptr) {} + + lldb::ByteOrder GetByteOrder() const; + + virtual Status ReadRegisterRaw(uint32_t reg_index, RegisterValue ®_value); + + virtual Status WriteRegisterRaw(uint32_t reg_index, + const RegisterValue ®_value); + + virtual Status ReadRegisterSet(void *buf, size_t buf_size, + unsigned int regset); + + virtual Status WriteRegisterSet(void *buf, size_t buf_size, + unsigned int regset); + + virtual Status ReadGPR(); + + virtual Status WriteGPR(); + + virtual Status ReadFPR(); + + virtual Status WriteFPR(); + + virtual void *GetGPRBuffer() = 0; + + virtual size_t GetGPRSize() const { + return GetRegisterInfoInterface().GetGPRSize(); + } + + virtual void *GetFPRBuffer() = 0; + + virtual size_t GetFPRSize() = 0; + + virtual uint32_t GetPtraceOffset(uint32_t reg_index) { + return GetRegisterInfoAtIndex(reg_index)->byte_offset; + } + + // The Do*** functions are executed on the privileged thread and can perform + // ptrace + // operations directly. + virtual Status DoReadRegisterValue(uint32_t offset, const char *reg_name, + uint32_t size, RegisterValue &value); + + virtual Status DoWriteRegisterValue(uint32_t offset, const char *reg_name, + const RegisterValue &value); +}; + +} // namespace process_aix +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextAIX_h diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp new file mode 100644 index 0000000000000..1996373791748 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp @@ -0,0 +1,744 @@ +//===-- NativeRegisterContextAIX_ppc64.cpp ----------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// This implementation is related to the OpenPOWER ABI for Power Architecture +// 64-bit ELF V2 ABI + +#if defined(__powerpc64__) + +#include "NativeRegisterContextAIX_ppc64.h" + +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Status.h" +#include "lldb/Host/aix/Ptrace.h" + +#include "Plugins/Process/AIX/NativeProcessAIX.h" +#include "Plugins/Process/Linux/Procfs.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h" + +// System includes - They have to be included after framework includes because +// they define some macros which collide with variable names in other modules +#include +#include +#include +#include + +#define REG_CONTEXT_SIZE \ + (GetGPRSize() + GetFPRSize() + sizeof(m_vmx_ppc64le) + sizeof(m_vsx_ppc64le)) +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; + +static const uint32_t g_gpr_regnums_ppc64le[] = { + gpr_r0_ppc64le, gpr_r1_ppc64le, gpr_r2_ppc64le, gpr_r3_ppc64le, + gpr_r4_ppc64le, gpr_r5_ppc64le, gpr_r6_ppc64le, gpr_r7_ppc64le, + gpr_r8_ppc64le, gpr_r9_ppc64le, gpr_r10_ppc64le, gpr_r11_ppc64le, + gpr_r12_ppc64le, gpr_r13_ppc64le, gpr_r14_ppc64le, gpr_r15_ppc64le, + gpr_r16_ppc64le, gpr_r17_ppc64le, gpr_r18_ppc64le, gpr_r19_ppc64le, + gpr_r20_ppc64le, gpr_r21_ppc64le, gpr_r22_ppc64le, gpr_r23_ppc64le, + gpr_r24_ppc64le, gpr_r25_ppc64le, gpr_r26_ppc64le, gpr_r27_ppc64le, + gpr_r28_ppc64le, gpr_r29_ppc64le, gpr_r30_ppc64le, gpr_r31_ppc64le, + gpr_pc_ppc64le, gpr_msr_ppc64le, gpr_origr3_ppc64le, gpr_ctr_ppc64le, + gpr_lr_ppc64le, gpr_xer_ppc64le, gpr_cr_ppc64le, gpr_softe_ppc64le, + gpr_trap_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +static const uint32_t g_fpr_regnums_ppc64le[] = { + fpr_f0_ppc64le, fpr_f1_ppc64le, fpr_f2_ppc64le, fpr_f3_ppc64le, + fpr_f4_ppc64le, fpr_f5_ppc64le, fpr_f6_ppc64le, fpr_f7_ppc64le, + fpr_f8_ppc64le, fpr_f9_ppc64le, fpr_f10_ppc64le, fpr_f11_ppc64le, + fpr_f12_ppc64le, fpr_f13_ppc64le, fpr_f14_ppc64le, fpr_f15_ppc64le, + fpr_f16_ppc64le, fpr_f17_ppc64le, fpr_f18_ppc64le, fpr_f19_ppc64le, + fpr_f20_ppc64le, fpr_f21_ppc64le, fpr_f22_ppc64le, fpr_f23_ppc64le, + fpr_f24_ppc64le, fpr_f25_ppc64le, fpr_f26_ppc64le, fpr_f27_ppc64le, + fpr_f28_ppc64le, fpr_f29_ppc64le, fpr_f30_ppc64le, fpr_f31_ppc64le, + fpr_fpscr_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +static const uint32_t g_vmx_regnums_ppc64le[] = { + vmx_vr0_ppc64le, vmx_vr1_ppc64le, vmx_vr2_ppc64le, vmx_vr3_ppc64le, + vmx_vr4_ppc64le, vmx_vr5_ppc64le, vmx_vr6_ppc64le, vmx_vr7_ppc64le, + vmx_vr8_ppc64le, vmx_vr9_ppc64le, vmx_vr10_ppc64le, vmx_vr11_ppc64le, + vmx_vr12_ppc64le, vmx_vr13_ppc64le, vmx_vr14_ppc64le, vmx_vr15_ppc64le, + vmx_vr16_ppc64le, vmx_vr17_ppc64le, vmx_vr18_ppc64le, vmx_vr19_ppc64le, + vmx_vr20_ppc64le, vmx_vr21_ppc64le, vmx_vr22_ppc64le, vmx_vr23_ppc64le, + vmx_vr24_ppc64le, vmx_vr25_ppc64le, vmx_vr26_ppc64le, vmx_vr27_ppc64le, + vmx_vr28_ppc64le, vmx_vr29_ppc64le, vmx_vr30_ppc64le, vmx_vr31_ppc64le, + vmx_vscr_ppc64le, vmx_vrsave_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +static const uint32_t g_vsx_regnums_ppc64le[] = { + vsx_vs0_ppc64le, vsx_vs1_ppc64le, vsx_vs2_ppc64le, vsx_vs3_ppc64le, + vsx_vs4_ppc64le, vsx_vs5_ppc64le, vsx_vs6_ppc64le, vsx_vs7_ppc64le, + vsx_vs8_ppc64le, vsx_vs9_ppc64le, vsx_vs10_ppc64le, vsx_vs11_ppc64le, + vsx_vs12_ppc64le, vsx_vs13_ppc64le, vsx_vs14_ppc64le, vsx_vs15_ppc64le, + vsx_vs16_ppc64le, vsx_vs17_ppc64le, vsx_vs18_ppc64le, vsx_vs19_ppc64le, + vsx_vs20_ppc64le, vsx_vs21_ppc64le, vsx_vs22_ppc64le, vsx_vs23_ppc64le, + vsx_vs24_ppc64le, vsx_vs25_ppc64le, vsx_vs26_ppc64le, vsx_vs27_ppc64le, + vsx_vs28_ppc64le, vsx_vs29_ppc64le, vsx_vs30_ppc64le, vsx_vs31_ppc64le, + vsx_vs32_ppc64le, vsx_vs33_ppc64le, vsx_vs34_ppc64le, vsx_vs35_ppc64le, + vsx_vs36_ppc64le, vsx_vs37_ppc64le, vsx_vs38_ppc64le, vsx_vs39_ppc64le, + vsx_vs40_ppc64le, vsx_vs41_ppc64le, vsx_vs42_ppc64le, vsx_vs43_ppc64le, + vsx_vs44_ppc64le, vsx_vs45_ppc64le, vsx_vs46_ppc64le, vsx_vs47_ppc64le, + vsx_vs48_ppc64le, vsx_vs49_ppc64le, vsx_vs50_ppc64le, vsx_vs51_ppc64le, + vsx_vs52_ppc64le, vsx_vs53_ppc64le, vsx_vs54_ppc64le, vsx_vs55_ppc64le, + vsx_vs56_ppc64le, vsx_vs57_ppc64le, vsx_vs58_ppc64le, vsx_vs59_ppc64le, + vsx_vs60_ppc64le, vsx_vs61_ppc64le, vsx_vs62_ppc64le, vsx_vs63_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +// Number of register sets provided by this context. +static constexpr int k_num_register_sets = 4; + +static const RegisterSet g_reg_sets_ppc64le[k_num_register_sets] = { + {"General Purpose Registers", "gpr", k_num_gpr_registers_ppc64le, + g_gpr_regnums_ppc64le}, + {"Floating Point Registers", "fpr", k_num_fpr_registers_ppc64le, + g_fpr_regnums_ppc64le}, + {"AltiVec/VMX Registers", "vmx", k_num_vmx_registers_ppc64le, + g_vmx_regnums_ppc64le}, + {"VSX Registers", "vsx", k_num_vsx_registers_ppc64le, + g_vsx_regnums_ppc64le}, +}; + +std::unique_ptr +NativeRegisterContextAIX::CreateHostNativeRegisterContextAIX( + const ArchSpec &target_arch, NativeThreadAIX &native_thread) { + switch (target_arch.GetMachine()) { + case llvm::Triple::ppc64: + return std::make_unique(target_arch, + native_thread); + default: + llvm_unreachable("have no register context for architecture"); + } +} + +NativeRegisterContextAIX_ppc64::NativeRegisterContextAIX_ppc64( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + : NativeRegisterContextRegisterInfo( + native_thread, new RegisterInfoPOSIX_ppc64le(target_arch)), + NativeRegisterContextAIX(native_thread) { + if (target_arch.GetMachine() != llvm::Triple::ppc64) { + llvm_unreachable("Unhandled target architecture."); + } + + ::memset(&m_gpr_ppc64le, 0, sizeof(m_gpr_ppc64le)); + ::memset(&m_fpr_ppc64le, 0, sizeof(m_fpr_ppc64le)); + ::memset(&m_vmx_ppc64le, 0, sizeof(m_vmx_ppc64le)); + ::memset(&m_vsx_ppc64le, 0, sizeof(m_vsx_ppc64le)); + ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); +} + +uint32_t NativeRegisterContextAIX_ppc64::GetRegisterSetCount() const { + return k_num_register_sets; +} + +const RegisterSet * +NativeRegisterContextAIX_ppc64::GetRegisterSet(uint32_t set_index) const { + if (set_index < k_num_register_sets) + return &g_reg_sets_ppc64le[set_index]; + + return nullptr; +} + +uint32_t NativeRegisterContextAIX_ppc64::GetUserRegisterCount() const { + uint32_t count = 0; + for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) + count += g_reg_sets_ppc64le[set_index].num_registers; + return count; +} + +Status NativeRegisterContextAIX_ppc64::ReadRegister( + const RegisterInfo *reg_info, RegisterValue ®_value) { + Status error; + + if (!reg_info) { + error.SetErrorString("reg_info NULL"); + return error; + } + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (IsFPR(reg)) { + error = ReadFPR(); + if (error.Fail()) + return error; + + // Get pointer to m_fpr_ppc64le variable and set the data from it. + uint32_t fpr_offset = CalculateFprOffset(reg_info); + assert(fpr_offset < sizeof m_fpr_ppc64le); + uint8_t *src = (uint8_t *)&m_fpr_ppc64le + fpr_offset; + reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } else if (IsVSX(reg)) { + uint32_t vsx_offset = CalculateVsxOffset(reg_info); + assert(vsx_offset < sizeof(m_vsx_ppc64le)); + + if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) { + error = ReadVSX(); + if (error.Fail()) + return error; + + error = ReadFPR(); + if (error.Fail()) + return error; + + uint64_t value[2]; + uint8_t *dst, *src; + dst = (uint8_t *)&value; + src = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + dst += 8; + src = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + reg_value.SetFromMemoryData(*reg_info, &value, reg_info->byte_size, + eByteOrderLittle, error); + } else { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data from it. + uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2; + uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } + } else if (IsVMX(reg)) { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data from it. + uint32_t vmx_offset = CalculateVmxOffset(reg_info); + assert(vmx_offset < sizeof m_vmx_ppc64le); + uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } else if (IsGPR(reg)) { + error = ReadGPR(); + if (error.Fail()) + return error; + + uint8_t *src = (uint8_t *) &m_gpr_ppc64le + reg_info->byte_offset; + reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } else { + return Status("failed - register wasn't recognized to be a GPR, FPR, VSX " + "or VMX, read strategy unknown"); + } + + return error; +} + +Status NativeRegisterContextAIX_ppc64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue ®_value) { + Status error; + if (!reg_info) + return Status("reg_info NULL"); + + const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; + if (reg_index == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : ""); + + if (IsGPR(reg_index)) { + error = ReadGPR(); + if (error.Fail()) + return error; + + uint8_t *dst = (uint8_t *)&m_gpr_ppc64le + reg_info->byte_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + *(uint64_t *)dst = llvm::byteswap(*(uint64_t *)dst); + + error = WriteGPR(); + if (error.Fail()) + return error; + + return Status(); + } + + if (IsFPR(reg_index)) { + error = ReadFPR(); + if (error.Fail()) + return error; + + // Get pointer to m_fpr_ppc64le variable and set the data to it. + uint32_t fpr_offset = CalculateFprOffset(reg_info); + assert(fpr_offset < GetFPRSize()); + uint8_t *dst = (uint8_t *)&m_fpr_ppc64le + fpr_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + + error = WriteFPR(); + if (error.Fail()) + return error; + + return Status(); + } + + if (IsVMX(reg_index)) { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data to it. + uint32_t vmx_offset = CalculateVmxOffset(reg_info); + assert(vmx_offset < sizeof(m_vmx_ppc64le)); + uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + + error = WriteVMX(); + if (error.Fail()) + return error; + + return Status(); + } + + if (IsVSX(reg_index)) { + uint32_t vsx_offset = CalculateVsxOffset(reg_info); + assert(vsx_offset < sizeof(m_vsx_ppc64le)); + + if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) { + error = ReadVSX(); + if (error.Fail()) + return error; + + error = ReadFPR(); + if (error.Fail()) + return error; + + uint64_t value[2]; + ::memcpy(value, reg_value.GetBytes(), 16); + uint8_t *dst, *src; + src = (uint8_t *)value; + dst = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + src += 8; + dst = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + + WriteVSX(); + WriteFPR(); + } else { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data from it. + uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2; + uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + WriteVMX(); + } + + return Status(); + } + + return Status("failed - register wasn't recognized to be a GPR, FPR, VSX " + "or VMX, write strategy unknown"); +} + +Status NativeRegisterContextAIX_ppc64::ReadAllRegisterValues( + lldb::WritableDataBufferSP &data_sp) { + Status error; + + data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); + error = ReadGPR(); + if (error.Fail()) + return error; + + error = ReadFPR(); + if (error.Fail()) + return error; + + error = ReadVMX(); + if (error.Fail()) + return error; + + error = ReadVSX(); + if (error.Fail()) + return error; + + uint8_t *dst = data_sp->GetBytes(); + ::memcpy(dst, &m_gpr_ppc64le, GetGPRSize()); + dst += GetGPRSize(); + ::memcpy(dst, &m_fpr_ppc64le, GetFPRSize()); + dst += GetFPRSize(); + ::memcpy(dst, &m_vmx_ppc64le, sizeof(m_vmx_ppc64le)); + dst += sizeof(m_vmx_ppc64le); + ::memcpy(dst, &m_vsx_ppc64le, sizeof(m_vsx_ppc64le)); + + return error; +} + +Status NativeRegisterContextAIX_ppc64::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + Status error; + + if (!data_sp) { + error.SetErrorStringWithFormat( + "NativeRegisterContextAIX_ppc64::%s invalid data_sp provided", + __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { + error.SetErrorStringWithFormat( + "NativeRegisterContextAIX_ppc64::%s data_sp contained mismatched " + "data size, expected %" PRIu64 ", actual %" PRIu64, + __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); + return error; + } + + const uint8_t *src = data_sp->GetBytes(); + if (src == nullptr) { + error.SetErrorStringWithFormat("NativeRegisterContextAIX_ppc64::%s " + "DataBuffer::GetBytes() returned a null " + "pointer", + __FUNCTION__); + return error; + } + + ::memcpy(&m_gpr_ppc64le, src, GetGPRSize()); + error = WriteGPR(); + + if (error.Fail()) + return error; + + src += GetGPRSize(); + ::memcpy(&m_fpr_ppc64le, src, GetFPRSize()); + + error = WriteFPR(); + if (error.Fail()) + return error; + + src += GetFPRSize(); + ::memcpy(&m_vmx_ppc64le, src, sizeof(m_vmx_ppc64le)); + + error = WriteVMX(); + if (error.Fail()) + return error; + + src += sizeof(m_vmx_ppc64le); + ::memcpy(&m_vsx_ppc64le, src, sizeof(m_vsx_ppc64le)); + error = WriteVSX(); + + return error; +} + +bool NativeRegisterContextAIX_ppc64::IsGPR(unsigned reg) const { + return reg <= k_last_gpr_ppc64le; // GPR's come first. +} + +bool NativeRegisterContextAIX_ppc64::IsFPR(unsigned reg) const { + return (k_first_fpr_ppc64le <= reg && reg <= k_last_fpr_ppc64le); +} + +uint32_t NativeRegisterContextAIX_ppc64::CalculateFprOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - + GetRegisterInfoAtIndex(k_first_fpr_ppc64le)->byte_offset; +} + +uint32_t NativeRegisterContextAIX_ppc64::CalculateVmxOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - + GetRegisterInfoAtIndex(k_first_vmx_ppc64le)->byte_offset; +} + +uint32_t NativeRegisterContextAIX_ppc64::CalculateVsxOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - + GetRegisterInfoAtIndex(k_first_vsx_ppc64le)->byte_offset; +} + +Status NativeRegisterContextAIX_ppc64::ReadVMX() { + return NativeProcessAIX::PtraceWrapper(PTRACE_GETVRREGS, m_thread.GetID(), + nullptr, &m_vmx_ppc64le, + sizeof(m_vmx_ppc64le)); +} + +Status NativeRegisterContextAIX_ppc64::WriteVMX() { + //FIXME + int regset = 0/*NT_PPC_VMX*/; + return NativeProcessAIX::PtraceWrapper(PT_CLEAR/*PTRACE_SETVRREGS*/, m_thread.GetID(), + ®set, &m_vmx_ppc64le, + sizeof(m_vmx_ppc64le)); +} + +Status NativeRegisterContextAIX_ppc64::ReadVSX() { + return NativeProcessAIX::PtraceWrapper(PTRACE_GETVSRREGS, m_thread.GetID(), + nullptr, &m_vsx_ppc64le, + sizeof(m_vsx_ppc64le)); +} + +Status NativeRegisterContextAIX_ppc64::WriteVSX() { + //FIXME + int regset = 0/*NT_PPC_VSX*/; + return NativeProcessAIX::PtraceWrapper(PT_CLEAR/*PTRACE_SETVSRREGS*/, m_thread.GetID(), + ®set, &m_vsx_ppc64le, + sizeof(m_vsx_ppc64le)); +} + +bool NativeRegisterContextAIX_ppc64::IsVMX(unsigned reg) { + return (reg >= k_first_vmx_ppc64le) && (reg <= k_last_vmx_ppc64le); +} + +bool NativeRegisterContextAIX_ppc64::IsVSX(unsigned reg) { + return (reg >= k_first_vsx_ppc64le) && (reg <= k_last_vsx_ppc64le); +} + +uint32_t NativeRegisterContextAIX_ppc64::NumSupportedHardwareWatchpoints() { + Log *log = GetLog(POSIXLog::Watchpoints); + + // Read hardware breakpoint and watchpoint information. + Status error = ReadHardwareDebugInfo(); + + if (error.Fail()) + return 0; + + LLDB_LOG(log, "{0}", m_max_hwp_supported); + return m_max_hwp_supported; +} + +uint32_t NativeRegisterContextAIX_ppc64::SetHardwareWatchpoint( + lldb::addr_t addr, size_t size, uint32_t watch_flags) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size, + watch_flags); + + // Read hardware breakpoint and watchpoint information. + Status error = ReadHardwareDebugInfo(); + + if (error.Fail()) + return LLDB_INVALID_INDEX32; + + uint32_t control_value = 0, wp_index = 0; + lldb::addr_t real_addr = addr; + uint32_t rw_mode = 0; + + // Check if we are setting watchpoint other than read/write/access Update + // watchpoint flag to match ppc64le write-read bit configuration. + switch (watch_flags) { + case eWatchpointKindWrite: + //FIXME + //rw_mode = 0/*PPC_BREAKPOINT_TRIGGER_WRITE*/; + watch_flags = 2; + break; + // Watchpoint read not supported + case eWatchpointKindRead: + case (eWatchpointKindRead | eWatchpointKindWrite): + default: + return LLDB_INVALID_INDEX32; + } + + // Check if size has a valid hardware watchpoint length. + if (size != 8) + return LLDB_INVALID_INDEX32; + + // Check 8-byte alignment for hardware watchpoint target address. Below is a + // hack to recalculate address and size in order to make sure we can watch + // non 8-byte aligned addresses as well. + if (addr & 0x07) { + + addr_t begin = llvm::alignDown(addr, 8); + addr_t end = llvm::alignTo(addr + size, 8); + size = llvm::PowerOf2Ceil(end - begin); + + addr = addr & (~0x07); + } + + // Setup control value + control_value = watch_flags << 3; + control_value |= ((1 << size) - 1) << 5; + control_value |= (2 << 1) | 1; + + // Iterate over stored watchpoints and find a free wp_index + wp_index = LLDB_INVALID_INDEX32; + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + if ((m_hwp_regs[i].control & 1) == 0) { + wp_index = i; // Mark last free slot + } else if (m_hwp_regs[i].address == addr) { + return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints. + } + } + + if (wp_index == LLDB_INVALID_INDEX32) + return LLDB_INVALID_INDEX32; + + // Update watchpoint in local cache + m_hwp_regs[wp_index].real_addr = real_addr; + m_hwp_regs[wp_index].address = addr; + m_hwp_regs[wp_index].control = control_value; + //m_hwp_regs[wp_index].mode = rw_mode; + + // PTRACE call to set corresponding watchpoint register. + error = WriteHardwareDebugRegs(); + + if (error.Fail()) { + m_hwp_regs[wp_index].address = 0; + m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros(1); + + return LLDB_INVALID_INDEX32; + } + + return wp_index; +} + +bool NativeRegisterContextAIX_ppc64::ClearHardwareWatchpoint( + uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + // Read hardware breakpoint and watchpoint information. + Status error = ReadHardwareDebugInfo(); + + if (error.Fail()) + return false; + + if (wp_index >= m_max_hwp_supported) + return false; + + // Create a backup we can revert to in case of failure. + lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; + uint32_t tempControl = m_hwp_regs[wp_index].control; + long *tempSlot = reinterpret_cast(m_hwp_regs[wp_index].slot); + + // Update watchpoint in local cache + m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros(1); + m_hwp_regs[wp_index].address = 0; + m_hwp_regs[wp_index].slot = 0; + m_hwp_regs[wp_index].mode = 0; + + // Ptrace call to update hardware debug registers + //FIXME + error = NativeProcessAIX::PtraceWrapper(PT_CLEAR/*PPC_PTRACE_DELHWDEBUG*/, + m_thread.GetID(), 0, tempSlot); + + if (error.Fail()) { + m_hwp_regs[wp_index].control = tempControl; + m_hwp_regs[wp_index].address = tempAddr; + m_hwp_regs[wp_index].slot = reinterpret_cast(tempSlot); + + return false; + } + + return true; +} + +uint32_t +NativeRegisterContextAIX_ppc64::GetWatchpointSize(uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + unsigned control = (m_hwp_regs[wp_index].control >> 5) & 0xff; + if (llvm::isPowerOf2_32(control + 1)) { + return llvm::popcount(control); + } + + return 0; +} + +bool NativeRegisterContextAIX_ppc64::WatchpointIsEnabled( + uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + return !!((m_hwp_regs[wp_index].control & 0x1) == 0x1); +} + +Status NativeRegisterContextAIX_ppc64::GetWatchpointHitIndex( + uint32_t &wp_index, lldb::addr_t trap_addr) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr); + + uint32_t watch_size; + lldb::addr_t watch_addr; + + for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) { + watch_size = GetWatchpointSize(wp_index); + watch_addr = m_hwp_regs[wp_index].address; + + if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr && + trap_addr <= watch_addr + watch_size) { + m_hwp_regs[wp_index].hit_addr = trap_addr; + return Status(); + } + } + + wp_index = LLDB_INVALID_INDEX32; + return Status(); +} + +lldb::addr_t +NativeRegisterContextAIX_ppc64::GetWatchpointAddress(uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + if (wp_index >= m_max_hwp_supported) + return LLDB_INVALID_ADDRESS; + + if (WatchpointIsEnabled(wp_index)) + return m_hwp_regs[wp_index].real_addr; + else + return LLDB_INVALID_ADDRESS; +} + +lldb::addr_t +NativeRegisterContextAIX_ppc64::GetWatchpointHitAddress(uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + if (wp_index >= m_max_hwp_supported) + return LLDB_INVALID_ADDRESS; + + if (WatchpointIsEnabled(wp_index)) + return m_hwp_regs[wp_index].hit_addr; + + return LLDB_INVALID_ADDRESS; +} + +Status NativeRegisterContextAIX_ppc64::ReadHardwareDebugInfo() { + if (!m_refresh_hwdebug_info) { + return Status(); + } + + m_max_hwp_supported = 1; + m_max_hbp_supported = 0; + m_refresh_hwdebug_info = false; + + return Status(); +} + +Status NativeRegisterContextAIX_ppc64::WriteHardwareDebugRegs() { + Status error; + long ret; + + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + if ((m_hwp_regs[i].control & 1) == 0) + continue; + + error = NativeProcessAIX::PtraceWrapper(PT_WATCH, m_thread.GetID(), (void *)m_hwp_regs[i].address, nullptr, 8, &ret); + + if (error.Fail()) + return error; + + m_hwp_regs[i].slot = ret; + } + return error; +} + +#endif // defined(__powerpc64__) diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h new file mode 100644 index 0000000000000..a29f786f2313a --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h @@ -0,0 +1,138 @@ +//===-- NativeRegisterContextAIX_ppc64.h --------------------*- 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 +// +//===----------------------------------------------------------------------===// + +// This implementation is related to the OpenPOWER ABI for Power Architecture +// 64-bit ELF V2 ABI + +#if defined(__powerpc64__) + +#ifndef lldb_NativeRegisterContextAIX_ppc64_h +#define lldb_NativeRegisterContextAIX_ppc64_h + +#include "Plugins/Process/AIX/NativeRegisterContextAIX.h" +#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" + +#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT +#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h" +#undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT + +namespace lldb_private { +namespace process_aix { + +class NativeProcessAIX; + +class NativeRegisterContextAIX_ppc64 : public NativeRegisterContextAIX { +public: + NativeRegisterContextAIX_ppc64(const ArchSpec &target_arch, + NativeThreadProtocol &native_thread); + + uint32_t GetRegisterSetCount() const override; + + uint32_t GetUserRegisterCount() const override; + + const RegisterSet *GetRegisterSet(uint32_t set_index) const override; + + Status ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + + Status WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + + Status ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override; + + Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + // Hardware watchpoint management functions + + uint32_t NumSupportedHardwareWatchpoints() override; + + uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags) override; + + bool ClearHardwareWatchpoint(uint32_t hw_index) override; + + Status GetWatchpointHitIndex(uint32_t &wp_index, + lldb::addr_t trap_addr) override; + + lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override; + + lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; + + uint32_t GetWatchpointSize(uint32_t wp_index); + + bool WatchpointIsEnabled(uint32_t wp_index); + +protected: + bool IsVMX(unsigned reg); + + bool IsVSX(unsigned reg); + + Status ReadVMX(); + + Status WriteVMX(); + + Status ReadVSX(); + + Status WriteVSX(); + + void *GetGPRBuffer() override { return &m_gpr_ppc64le; } + + void *GetFPRBuffer() override { return &m_fpr_ppc64le; } + + size_t GetFPRSize() override { return sizeof(m_fpr_ppc64le); } + +private: + GPR m_gpr_ppc64le; // 64-bit general purpose registers. + FPR m_fpr_ppc64le; // floating-point registers including extended register. + VMX m_vmx_ppc64le; // VMX registers. + VSX m_vsx_ppc64le; // Last lower bytes from first VSX registers. + + bool IsGPR(unsigned reg) const; + + bool IsFPR(unsigned reg) const; + + bool IsVMX(unsigned reg) const; + + bool IsVSX(unsigned reg) const; + + uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const; + + uint32_t CalculateVmxOffset(const RegisterInfo *reg_info) const; + + uint32_t CalculateVsxOffset(const RegisterInfo *reg_info) const; + + Status ReadHardwareDebugInfo(); + + Status WriteHardwareDebugRegs(); + + // Debug register info for hardware watchpoints management. + struct DREG { + lldb::addr_t address; // Breakpoint/watchpoint address value. + lldb::addr_t hit_addr; // Address at which last watchpoint trigger + // exception occurred. + lldb::addr_t real_addr; // Address value that should cause target to stop. + uint32_t control; // Breakpoint/watchpoint control value. + uint32_t refcount; // Serves as enable/disable and reference counter. + long slot; // Saves the value returned from PTRACE_SETHWDEBUG. + int mode; // Defines if watchpoint is read/write/access. + }; + + std::array m_hwp_regs; + + // 16 is just a maximum value, query hardware for actual watchpoint count + uint32_t m_max_hwp_supported = 16; + uint32_t m_max_hbp_supported = 16; + bool m_refresh_hwdebug_info = true; +}; + +} // namespace process_aix +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextAIX_ppc64_h + +#endif // defined(__powerpc64__) diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp new file mode 100644 index 0000000000000..e07daccdff550 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp @@ -0,0 +1,526 @@ +//===-- NativeThreadAIX.cpp ---------------------------------------------===// +// +// 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 "NativeThreadAIX.h" + +#include +#include + +#include "NativeProcessAIX.h" +#include "NativeRegisterContextAIX.h" + +#include "lldb/Host/HostNativeThread.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" +#include "lldb/lldb-enumerations.h" + +#include "llvm/ADT/SmallString.h" + +#include "Plugins/Process/POSIX/CrashReason.h" + +#include +#include +#include + +#if 0 +#include +// Try to define a macro to encapsulate the tgkill syscall +#define tgkill(pid, tid, sig) \ + syscall(__NR_tgkill, static_cast<::pid_t>(pid), static_cast<::pid_t>(tid), \ + sig) +#endif + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; + +namespace { +void LogThreadStopInfo(Log &log, const ThreadStopInfo &stop_info, + const char *const header) { + switch (stop_info.reason) { + case eStopReasonNone: + log.Printf("%s: %s no stop reason", __FUNCTION__, header); + return; + case eStopReasonTrace: + log.Printf("%s: %s trace, stopping signal 0x%" PRIx32, __FUNCTION__, header, + stop_info.signo); + return; + case eStopReasonBreakpoint: + log.Printf("%s: %s breakpoint, stopping signal 0x%" PRIx32, __FUNCTION__, + header, stop_info.signo); + return; + case eStopReasonWatchpoint: + log.Printf("%s: %s watchpoint, stopping signal 0x%" PRIx32, __FUNCTION__, + header, stop_info.signo); + return; + case eStopReasonSignal: + log.Printf("%s: %s signal 0x%02" PRIx32, __FUNCTION__, header, + stop_info.signo); + return; + case eStopReasonException: + log.Printf("%s: %s exception type 0x%02" PRIx64, __FUNCTION__, header, + stop_info.details.exception.type); + return; + case eStopReasonExec: + log.Printf("%s: %s exec, stopping signal 0x%" PRIx32, __FUNCTION__, header, + stop_info.signo); + return; + case eStopReasonPlanComplete: + log.Printf("%s: %s plan complete", __FUNCTION__, header); + return; + case eStopReasonThreadExiting: + log.Printf("%s: %s thread exiting", __FUNCTION__, header); + return; + case eStopReasonInstrumentation: + log.Printf("%s: %s instrumentation", __FUNCTION__, header); + return; + case eStopReasonProcessorTrace: + log.Printf("%s: %s processor trace", __FUNCTION__, header); + return; + default: + log.Printf("%s: %s invalid stop reason %" PRIu32, __FUNCTION__, header, + static_cast(stop_info.reason)); + } +} +} + +NativeThreadAIX::NativeThreadAIX(NativeProcessAIX &process, + lldb::tid_t tid) + : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid), + m_stop_info(), + m_reg_context_up( + NativeRegisterContextAIX::CreateHostNativeRegisterContextAIX( + process.GetArchitecture(), *this)), + m_stop_description() {} + +std::string NativeThreadAIX::GetName() { + NativeProcessAIX &process = GetProcess(); + + auto BufferOrError = getProcFile(process.GetID(), GetID(), "comm"); + if (!BufferOrError) + return ""; + return std::string(BufferOrError.get()->getBuffer().rtrim('\n')); +} + +lldb::StateType NativeThreadAIX::GetState() { return m_state; } + +bool NativeThreadAIX::GetStopReason(ThreadStopInfo &stop_info, + std::string &description) { + Log *log = GetLog(LLDBLog::Thread); + + description.clear(); + + switch (m_state) { + case eStateStopped: + case eStateCrashed: + case eStateExited: + case eStateSuspended: + case eStateUnloaded: + if (log) + LogThreadStopInfo(*log, m_stop_info, "m_stop_info in thread:"); + stop_info = m_stop_info; + description = m_stop_description; + if (log) + LogThreadStopInfo(*log, stop_info, "returned stop_info:"); + + return true; + + case eStateInvalid: + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + case eStateRunning: + case eStateStepping: + case eStateDetached: + if (log) { + LLDB_LOGF(log, + "NativeThreadAIX::%s tid %" PRIu64 + " in state %s cannot answer stop reason", + __FUNCTION__, GetID(), StateAsCString(m_state)); + } + return false; + } + llvm_unreachable("unhandled StateType!"); +} + +Status NativeThreadAIX::SetWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags, bool hardware) { + if (!hardware) + return Status("not implemented"); + if (m_state == eStateLaunching) + return Status(); + Status error = RemoveWatchpoint(addr); + if (error.Fail()) + return error; + uint32_t wp_index = + m_reg_context_up->SetHardwareWatchpoint(addr, size, watch_flags); + if (wp_index == LLDB_INVALID_INDEX32) + return Status("Setting hardware watchpoint failed."); + m_watchpoint_index_map.insert({addr, wp_index}); + return Status(); +} + +Status NativeThreadAIX::RemoveWatchpoint(lldb::addr_t addr) { + auto wp = m_watchpoint_index_map.find(addr); + if (wp == m_watchpoint_index_map.end()) + return Status(); + uint32_t wp_index = wp->second; + m_watchpoint_index_map.erase(wp); + if (m_reg_context_up->ClearHardwareWatchpoint(wp_index)) + return Status(); + return Status("Clearing hardware watchpoint failed."); +} + +Status NativeThreadAIX::SetHardwareBreakpoint(lldb::addr_t addr, + size_t size) { + if (m_state == eStateLaunching) + return Status(); + + Status error = RemoveHardwareBreakpoint(addr); + if (error.Fail()) + return error; + + uint32_t bp_index = m_reg_context_up->SetHardwareBreakpoint(addr, size); + + if (bp_index == LLDB_INVALID_INDEX32) + return Status("Setting hardware breakpoint failed."); + + m_hw_break_index_map.insert({addr, bp_index}); + return Status(); +} + +Status NativeThreadAIX::RemoveHardwareBreakpoint(lldb::addr_t addr) { + auto bp = m_hw_break_index_map.find(addr); + if (bp == m_hw_break_index_map.end()) + return Status(); + + uint32_t bp_index = bp->second; + if (m_reg_context_up->ClearHardwareBreakpoint(bp_index)) { + m_hw_break_index_map.erase(bp); + return Status(); + } + + return Status("Clearing hardware breakpoint failed."); +} + +Status NativeThreadAIX::Resume(uint32_t signo) { + const StateType new_state = StateType::eStateRunning; + MaybeLogStateChange(new_state); + m_state = new_state; + + m_stop_info.reason = StopReason::eStopReasonNone; + m_stop_description.clear(); + + // If watchpoints have been set, but none on this thread, then this is a new + // thread. So set all existing watchpoints. + if (m_watchpoint_index_map.empty()) { + NativeProcessAIX &process = GetProcess(); + + const auto &watchpoint_map = process.GetWatchpointMap(); + m_reg_context_up->ClearAllHardwareWatchpoints(); + for (const auto &pair : watchpoint_map) { + const auto &wp = pair.second; + SetWatchpoint(wp.m_addr, wp.m_size, wp.m_watch_flags, wp.m_hardware); + } + } + + // Set all active hardware breakpoint on all threads. + if (m_hw_break_index_map.empty()) { + NativeProcessAIX &process = GetProcess(); + + const auto &hw_breakpoint_map = process.GetHardwareBreakpointMap(); + m_reg_context_up->ClearAllHardwareBreakpoints(); + for (const auto &pair : hw_breakpoint_map) { + const auto &bp = pair.second; + SetHardwareBreakpoint(bp.m_addr, bp.m_size); + } + } + + intptr_t data = 0; + + if (signo != LLDB_INVALID_SIGNAL_NUMBER) + data = signo; + + return NativeProcessAIX::PtraceWrapper(PT_CONTINUE, GetID(), nullptr, + reinterpret_cast(data)); +} + +Status NativeThreadAIX::SingleStep(uint32_t signo) { + const StateType new_state = StateType::eStateStepping; + MaybeLogStateChange(new_state); + m_state = new_state; + m_stop_info.reason = StopReason::eStopReasonNone; + + intptr_t data = 0; + if (signo != LLDB_INVALID_SIGNAL_NUMBER) + data = signo; + + // If hardware single-stepping is not supported, we just do a continue. The + // breakpoint on the next instruction has been setup in + // NativeProcessAIX::Resume. + return NativeProcessAIX::PtraceWrapper( + GetProcess().SupportHardwareSingleStepping() ? PT_STEP : PT_CONTINUE, + m_tid, nullptr, reinterpret_cast(data)); +} + +void NativeThreadAIX::SetStoppedBySignal(uint32_t signo, + const siginfo_t *info) { + Log *log = GetLog(LLDBLog::Thread); + LLDB_LOGF(log, "NativeThreadAIX::%s called with signal 0x%02" PRIx32, + __FUNCTION__, signo); + + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonSignal; + m_stop_info.signo = signo; + + m_stop_description.clear(); + switch (signo) { + case SIGSEGV: + case SIGBUS: + case SIGFPE: + case SIGILL: + break; + } +} + +void NativeThreadAIX::AnnotateSyncTagCheckFault(const siginfo_t *info) { + int32_t allocation_tag_type = 0; + switch (GetProcess().GetArchitecture().GetMachine()) { + default: + return; + } + + auto details = + GetRegisterContext().GetMemoryTaggingDetails(allocation_tag_type); + if (!details) { + llvm::consumeError(details.takeError()); + return; + } + + // We assume that the stop description is currently: + // signal SIGSEGV: sync tag check fault (fault address: ) + // Remove the closing ) + m_stop_description.pop_back(); + + std::stringstream ss; + lldb::addr_t fault_addr = reinterpret_cast(info->si_addr); + std::unique_ptr manager(std::move(details->manager)); + + ss << " logical tag: 0x" << std::hex << manager->GetLogicalTag(fault_addr); + + std::vector allocation_tag_data; + // The fault address may not be granule aligned. ReadMemoryTags will granule + // align any range you give it, potentially making it larger. + // To prevent this set len to 1. This always results in a range that is at + // most 1 granule in size and includes fault_addr. + Status status = GetProcess().ReadMemoryTags(allocation_tag_type, fault_addr, + 1, allocation_tag_data); + + if (status.Success()) { + llvm::Expected> allocation_tag = + manager->UnpackTagsData(allocation_tag_data, 1); + if (allocation_tag) { + ss << " allocation tag: 0x" << std::hex << allocation_tag->front() << ")"; + } else { + llvm::consumeError(allocation_tag.takeError()); + ss << ")"; + } + } else + ss << ")"; + + m_stop_description += ss.str(); +} + +bool NativeThreadAIX::IsStopped(int *signo) { + if (!StateIsStoppedState(m_state, false)) + return false; + + // If we are stopped by a signal, return the signo. + if (signo && m_state == StateType::eStateStopped && + m_stop_info.reason == StopReason::eStopReasonSignal) { + *signo = m_stop_info.signo; + } + + // Regardless, we are stopped. + return true; +} + +void NativeThreadAIX::SetStopped() { + // On every stop, clear any cached register data structures + GetRegisterContext().InvalidateAllRegisters(); + + const StateType new_state = StateType::eStateStopped; + MaybeLogStateChange(new_state); + m_state = new_state; + m_stop_description.clear(); +} + +void NativeThreadAIX::SetStoppedByExec() { + Log *log = GetLog(LLDBLog::Thread); + LLDB_LOGF(log, "NativeThreadAIX::%s()", __FUNCTION__); + + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonExec; + m_stop_info.signo = SIGSTOP; +} + +void NativeThreadAIX::SetStoppedByBreakpoint() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonBreakpoint; + m_stop_info.signo = SIGTRAP; + m_stop_description.clear(); +} + +void NativeThreadAIX::SetStoppedByWatchpoint(uint32_t wp_index) { + SetStopped(); + + lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); + + std::ostringstream ostr; + ostr << m_reg_context_up->GetWatchpointAddress(wp_index) << " "; + ostr << wp_index; + + /* + * MIPS: Last 3bits of the watchpoint address are masked by the kernel. For + * example: + * 'n' is at 0x120010d00 and 'm' is 0x120010d04. When a watchpoint is set at + * 'm', then + * watch exception is generated even when 'n' is read/written. To handle this + * case, + * find the base address of the load/store instruction and append it in the + * stop-info + * packet. + */ + ostr << " " << m_reg_context_up->GetWatchpointHitAddress(wp_index); + + m_stop_description = ostr.str(); + + m_stop_info.reason = StopReason::eStopReasonWatchpoint; + m_stop_info.signo = SIGTRAP; +} + +bool NativeThreadAIX::IsStoppedAtBreakpoint() { + return GetState() == StateType::eStateStopped && + m_stop_info.reason == StopReason::eStopReasonBreakpoint; +} + +bool NativeThreadAIX::IsStoppedAtWatchpoint() { + return GetState() == StateType::eStateStopped && + m_stop_info.reason == StopReason::eStopReasonWatchpoint; +} + +void NativeThreadAIX::SetStoppedByTrace() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonTrace; + m_stop_info.signo = SIGTRAP; +} + +void NativeThreadAIX::SetStoppedByFork(bool is_vfork, lldb::pid_t child_pid) { + SetStopped(); + + m_stop_info.reason = + is_vfork ? StopReason::eStopReasonVFork : StopReason::eStopReasonFork; + m_stop_info.details.fork.child_pid = child_pid; + m_stop_info.details.fork.child_tid = child_pid; +} + +void NativeThreadAIX::SetStoppedByVForkDone() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonVForkDone; +} + +void NativeThreadAIX::SetStoppedWithNoReason() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonNone; + m_stop_info.signo = 0; +} + +void NativeThreadAIX::SetStoppedByProcessorTrace( + llvm::StringRef description) { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonProcessorTrace; + m_stop_info.signo = 0; + m_stop_description = description.str(); +} + +void NativeThreadAIX::SetExited() { + const StateType new_state = StateType::eStateExited; + MaybeLogStateChange(new_state); + m_state = new_state; + + m_stop_info.reason = StopReason::eStopReasonThreadExiting; +} + +Status NativeThreadAIX::RequestStop() { + Log *log = GetLog(LLDBLog::Thread); + + NativeProcessAIX &process = GetProcess(); + + lldb::pid_t pid = process.GetID(); + lldb::tid_t tid = GetID(); + + LLDB_LOGF(log, + "NativeThreadAIX::%s requesting thread stop(pid: %" PRIu64 + ", tid: %" PRIu64 ")", + __FUNCTION__, pid, tid); + + Status err; + errno = 0; + if (::kill(pid, SIGSTOP) != 0) { + err.SetErrorToErrno(); + LLDB_LOGF(log, + "NativeThreadAIX::%s kill(%" PRIu64 ", SIGSTOP) failed: %s", + __FUNCTION__, pid, err.AsCString()); + } + return err; +} + +void NativeThreadAIX::MaybeLogStateChange(lldb::StateType new_state) { + Log *log = GetLog(LLDBLog::Thread); + // If we're not logging, we're done. + if (!log) + return; + + // If this is a state change to the same state, we're done. + lldb::StateType old_state = m_state; + if (new_state == old_state) + return; + + LLDB_LOG(log, "pid={0}, tid={1}: changing from state {2} to {3}", + m_process.GetID(), GetID(), old_state, new_state); +} + +NativeProcessAIX &NativeThreadAIX::GetProcess() { + return static_cast(m_process); +} + +const NativeProcessAIX &NativeThreadAIX::GetProcess() const { + return static_cast(m_process); +} + +llvm::Expected> +NativeThreadAIX::GetSiginfo() const { + auto siginfo_buf = + llvm::WritableMemoryBuffer::getNewUninitMemBuffer(sizeof(siginfo_t)); +#if 0 + Status error = + GetProcess().GetSignalInfo(GetID(), siginfo_buf->getBufferStart()); + if (!error.Success()) + return error.ToError(); +#endif + return std::move(siginfo_buf); +} diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h new file mode 100644 index 0000000000000..706a7ce69da8e --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h @@ -0,0 +1,126 @@ +//===-- NativeThreadAIX.h ----------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeThreadAIX_H_ +#define liblldb_NativeThreadAIX_H_ + +#include "Plugins/Process/AIX/NativeRegisterContextAIX.h" +#include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/lldb-private-forward.h" + +#include "llvm/ADT/StringRef.h" + +#include +#include +#include +#include + +namespace lldb_private { +namespace process_aix { + +class NativeProcessAIX; + +class NativeThreadAIX : public NativeThreadProtocol { + friend class NativeProcessAIX; + +public: + NativeThreadAIX(NativeProcessAIX &process, lldb::tid_t tid); + + // NativeThreadProtocol Interface + std::string GetName() override; + + lldb::StateType GetState() override; + + bool GetStopReason(ThreadStopInfo &stop_info, + std::string &description) override; + + NativeRegisterContextAIX &GetRegisterContext() override { + return *m_reg_context_up; + } + + Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, + bool hardware) override; + + Status RemoveWatchpoint(lldb::addr_t addr) override; + + Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override; + + Status RemoveHardwareBreakpoint(lldb::addr_t addr) override; + + NativeProcessAIX &GetProcess(); + + const NativeProcessAIX &GetProcess() const; + + llvm::Expected> + GetSiginfo() const override; + +private: + // Interface for friend classes + + /// Resumes the thread. If \p signo is anything but + /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. + Status Resume(uint32_t signo); + + /// Single steps the thread. If \p signo is anything but + /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. + Status SingleStep(uint32_t signo); + + void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr); + + /// Return true if the thread is stopped. + /// If stopped by a signal, indicate the signo in the signo argument. + /// Otherwise, return LLDB_INVALID_SIGNAL_NUMBER. + bool IsStopped(int *signo); + + void SetStoppedByExec(); + + void SetStoppedByBreakpoint(); + + void SetStoppedByWatchpoint(uint32_t wp_index); + + bool IsStoppedAtBreakpoint(); + + bool IsStoppedAtWatchpoint(); + + void SetStoppedByTrace(); + + void SetStoppedByFork(bool is_vfork, lldb::pid_t child_pid); + + void SetStoppedByVForkDone(); + + void SetStoppedWithNoReason(); + + void SetStoppedByProcessorTrace(llvm::StringRef description); + + void SetExited(); + + Status RequestStop(); + + // Private interface + void MaybeLogStateChange(lldb::StateType new_state); + + void SetStopped(); + + /// Extend m_stop_description with logical and allocation tag values. + /// If there is an error along the way just add the information we were able + /// to get. + void AnnotateSyncTagCheckFault(const siginfo_t *info); + + // Member Variables + lldb::StateType m_state; + ThreadStopInfo m_stop_info; + std::unique_ptr m_reg_context_up; + std::string m_stop_description; + using WatchpointIndexMap = std::map; + WatchpointIndexMap m_watchpoint_index_map; + WatchpointIndexMap m_hw_break_index_map; +}; +} // namespace process_aix +} // namespace lldb_private + +#endif // #ifndef liblldb_NativeThreadAIX_H_ diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt index a51d0f7afd175..01bb5f462eba4 100644 --- a/lldb/source/Plugins/Process/CMakeLists.txt +++ b/lldb/source/Plugins/Process/CMakeLists.txt @@ -7,6 +7,9 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD") add_subdirectory(NetBSD) add_subdirectory(POSIX) +elseif (CMAKE_SYSTEM_NAME MATCHES "AIX") + add_subdirectory(AIX) + add_subdirectory(POSIX) elseif (CMAKE_SYSTEM_NAME MATCHES "Windows") add_subdirectory(Windows/Common) elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin") diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 32c71d87c7f58..db271357d792a 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -46,8 +46,34 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, function_options.include_inlines = false; SymbolContextList sc_list; +#if !defined(__AIX__) process->GetTarget().GetImages().FindFunctions( ConstString("mmap"), eFunctionNameTypeFull, function_options, sc_list); +#else + process->GetTarget().GetImages().FindFunctions( + ConstString("mmap64"), eFunctionNameTypeFull, function_options, sc_list); + SymbolContextList toc_list; + process->GetTarget().GetImages().FindSymbolsWithNameAndType( + ConstString("TOC"), lldb::eSymbolTypeAny, toc_list); + + AddressRange toc_range; + if (sc_list.GetSize() > 0) { + SymbolContext sc; + if (sc_list.GetContextAtIndex(0, sc)) { + for (int i = 0; i < toc_list.GetSize(); ++i) { + SymbolContext tocSC; + if (toc_list.GetContextAtIndex(i, tocSC)) { + if (tocSC.module_sp == sc.module_sp) { + if (tocSC.GetAddressRange(eSymbolContextSymbol, 0, false, + toc_range)) { + break; + } + } + } + } + } + } +#endif const uint32_t count = sc_list.GetSize(); if (count > 0) { SymbolContext sc; @@ -96,9 +122,16 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, MmapArgList args = process->GetTarget().GetPlatform()->GetMmapArgumentList( arch, addr, length, prot_arg, flags, fd, offset); +#if defined(__AIX__) + lldb::ThreadPlanSP call_plan_sp( + new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(), + toc_range.GetBaseAddress(), + void_ptr_type, args, options)); +#else lldb::ThreadPlanSP call_plan_sp( new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(), void_ptr_type, args, options)); +#endif if (call_plan_sp) { DiagnosticManager diagnostics; diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp index 159fd2856443c..d9b41d595147f 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp @@ -23,6 +23,8 @@ static const lldb_private::RegisterInfo * GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { + //HH + case llvm::Triple::ppc64: case llvm::Triple::ppc64le: return g_register_infos_ppc64le; default: @@ -34,6 +36,8 @@ GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) { static uint32_t GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { + //HitchHike + case llvm::Triple::ppc64: case llvm::Triple::ppc64le: return static_cast(sizeof(g_register_infos_ppc64le) / sizeof(g_register_infos_ppc64le[0])); diff --git a/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp b/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp index 89ecc757a68f5..550b53688fd39 100644 --- a/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp +++ b/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp @@ -20,7 +20,7 @@ using namespace lldb; using namespace lldb_private; -ThreadMemory::ThreadMemory(Process &process, tid_t tid, +ThreadMemory::ThreadMemory(Process &process, lldb::tid_t tid, const ValueObjectSP &thread_info_valobj_sp) : Thread(process, tid), m_backing_thread_sp(), m_thread_info_valobj_sp(thread_info_valobj_sp), m_name(), m_queue(), diff --git a/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt b/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt index 6755999b18185..4eddbb5ec4cfd 100644 --- a/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt +++ b/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt @@ -6,6 +6,11 @@ lldb_tablegen(ProcessGDBRemotePropertiesEnum.inc -gen-lldb-property-enum-defs SOURCE ProcessGDBRemoteProperties.td TARGET LLDBPluginProcessGDBRemotePropertiesEnumGen) +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + set(LLDB_PLUGINS lldbPluginProcessUtility ) diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 74e392249a94e..b7ecf7a5dc328 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -40,6 +40,10 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/JSON.h" +#if defined(__AIX__) +#include +#endif + #if defined(HAVE_LIBCOMPRESSION) #include #endif @@ -1710,6 +1714,32 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( return error; } +#if defined(__AIX__) +Status GDBRemoteCommunicationClient::GetLDXINFO(struct ld_xinfo *info_ptr) +{ + Status error; + + char packet[64]; + const int packet_len = ::snprintf(packet, sizeof(packet), "qLDXINFO"); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response) == + PacketResult::Success && + response.GetResponseType() == StringExtractorGDBRemote::eResponse) { + llvm::MutableArrayRef infoData((uint8_t *)info_ptr, sizeof(struct ld_xinfo)*64); + size_t got_bytes = response.GetHexBytesAvail(infoData); + if (got_bytes != sizeof(struct ld_xinfo)*64) { + error.SetErrorString("qLDXINFO ret bad size"); + return error; + } + } else { + error.SetErrorString("qLDXINFO is not supported"); + } + return error; +} +#endif + Status GDBRemoteCommunicationClient::GetQXferMemoryMapRegionInfo( lldb::addr_t addr, MemoryRegionInfo ®ion) { Status error = LoadQXferMemoryMap(); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 898d176abc346..520f37ac56716 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -32,6 +32,10 @@ #include "llvm/Support/VersionTuple.h" +#if defined(__AIX__) +struct ld_xinfo; +#endif + namespace lldb_private { namespace process_gdb_remote { @@ -196,6 +200,9 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase { Status GetMemoryRegionInfo(lldb::addr_t addr, MemoryRegionInfo &range_info); std::optional GetWatchpointSlotCount(); +#if defined(__AIX__) + Status GetLDXINFO(struct ld_xinfo *info_ptr); +#endif std::optional GetWatchpointReportedAfter(); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index a0b08a219ae14..f019062986925 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -48,6 +48,9 @@ #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "lldb/Utility/StringExtractorGDBRemote.h" +#if defined(__AIX__) +#include +#endif using namespace lldb; using namespace lldb_private; @@ -193,6 +196,8 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { &GDBRemoteCommunicationServerLLGS::Handle_Z); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_z, &GDBRemoteCommunicationServerLLGS::Handle_z); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLDXINFO, + &GDBRemoteCommunicationServerLLGS::Handle_qLDXINFO); RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_QPassSignals, &GDBRemoteCommunicationServerLLGS::Handle_QPassSignals); @@ -3006,6 +3011,29 @@ GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) { } } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_qLDXINFO(StringExtractorGDBRemote &packet) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { + Log *log = GetLog(LLDBLog::Process); + LLDB_LOG(log, "qLDXINFO failed, no process available"); + return SendErrorResponse(0xff); + } + +#if defined(__AIX__) + // FIXME: buffer size + struct ld_xinfo info[64]; + if (ptrace64(PT_LDXINFO, m_current_process->GetID(), (long long)&(info[0]), sizeof(info), nullptr) != 0) { + return SendErrorResponse(0xff); + } + StreamGDBRemote response; + response.PutBytesAsRawHex8(&(info[0]), sizeof(info)); + return SendPacketNoLock(response.GetString()); +#else + return SendErrorResponse(0xff); +#endif +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index 646b6a102abf6..a464479e178de 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -211,6 +211,8 @@ class GDBRemoteCommunicationServerLLGS PacketResult Handle_z(StringExtractorGDBRemote &packet); + PacketResult Handle_qLDXINFO(StringExtractorGDBRemote &packet); + PacketResult Handle_s(StringExtractorGDBRemote &packet); PacketResult Handle_qXfer(StringExtractorGDBRemote &packet); diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 6f9c2cc1e4b4e..10fbaa2b3c837 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -92,6 +92,10 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/raw_ostream.h" +#if defined(__AIX__) +#include +#endif + #define DEBUGSERVER_BASENAME "debugserver" using namespace lldb; using namespace lldb_private; @@ -1513,7 +1517,7 @@ bool ProcessGDBRemote::DoUpdateThreadList(ThreadList &old_thread_list, ThreadList old_thread_list_copy(old_thread_list); if (num_thread_ids > 0) { for (size_t i = 0; i < num_thread_ids; ++i) { - tid_t tid = m_thread_ids[i]; + lldb::tid_t tid = m_thread_ids[i]; ThreadSP thread_sp( old_thread_list_copy.RemoveThreadByProtocolID(tid, false)); if (!thread_sp) { @@ -2945,6 +2949,13 @@ Status ProcessGDBRemote::DoGetMemoryRegionInfo(addr_t load_addr, return error; } +#if defined(__AIX__) +Status ProcessGDBRemote::DoGetLDXINFO(struct ld_xinfo *info_ptr) { + Status error(m_gdb_comm.GetLDXINFO(info_ptr)); + return error; +} +#endif + std::optional ProcessGDBRemote::GetWatchpointSlotCount() { return m_gdb_comm.GetWatchpointSlotCount(); } diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 2492795851388..82200fbea21cd 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -37,6 +37,10 @@ #include "GDBRemoteCommunicationClient.h" #include "GDBRemoteRegisterContext.h" +#if defined(__AIX__) +struct ld_xinfo; +#endif + #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" @@ -423,6 +427,10 @@ class ProcessGDBRemote : public Process, Status DoGetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo ®ion_info) override; +#if defined(__AIX__) + Status DoGetLDXINFO(struct ld_xinfo *info_ptr) override; +#endif + private: // For ProcessGDBRemote only std::string m_partial_profile_data; diff --git a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp index 1da7696c9a352..930c707604bb3 100644 --- a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp +++ b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp @@ -593,19 +593,19 @@ bool ProcessMachCore::DoUpdateThreadList(ThreadList &old_thread_list, ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); if (core_objfile) { - std::set used_tids; + std::set used_tids; const uint32_t num_threads = core_objfile->GetNumThreadContexts(); - std::vector tids; + std::vector tids; if (core_objfile->GetCorefileThreadExtraInfos(tids)) { assert(tids.size() == num_threads); // Find highest tid value. - tid_t highest_tid = 0; + lldb::tid_t highest_tid = 0; for (uint32_t i = 0; i < num_threads; i++) { if (tids[i] != LLDB_INVALID_THREAD_ID && tids[i] > highest_tid) highest_tid = tids[i]; } - tid_t current_unused_tid = highest_tid + 1; + lldb::tid_t current_unused_tid = highest_tid + 1; for (uint32_t i = 0; i < num_threads; i++) { if (tids[i] == LLDB_INVALID_THREAD_ID) { tids[i] = current_unused_tid++; diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt index 7523d65abf0f8..1ce60a0b66154 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt +++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt @@ -20,6 +20,11 @@ if (LLDB_ENABLE_LIBEDIT) endif() add_subdirectory(Interfaces) +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + add_lldb_library(lldbPluginScriptInterpreterPython PLUGIN PythonDataObjects.cpp diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp index e1f73f1997e36..92882cfc3da31 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -500,6 +500,8 @@ dw_addr_t DWARFFormValue::Address() const { &offset, index_size); } +bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; + std::pair DWARFFormValue::ReferencedUnitAndOffset() const { uint64_t value = m_value.value.uval; @@ -512,6 +514,8 @@ DWARFFormValue::ReferencedUnitAndOffset() const { assert(m_unit); // Unit must be valid for DW_FORM_ref forms that are compile // unit relative or we will get this wrong value += m_unit->GetOffset(); + if (UGLY_FLAG_FOR_AIX) + value -= 8; if (!m_unit->ContainsDIEOffset(value)) { m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( "DW_FORM_ref* DIE reference {0:x16} is outside of its CU", value); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index 66a762bf9b685..6721c1895a576 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -924,6 +924,12 @@ const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() { return *m_func_aranges_up; } +/* AIX-NOTE - TODO: Removed conflicting code due to merge conflicts + * Refer Patches: 27,28,29,30,35 and 76 + * and modify the code accordingly. */ + +bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; + llvm::Expected DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid, const DWARFDataExtractor &debug_info, @@ -1002,6 +1008,10 @@ const lldb_private::DWARFDataExtractor &DWARFUnit::GetData() const { uint32_t DWARFUnit::GetHeaderByteSize() const { switch (m_header.getUnitType()) { case llvm::dwarf::DW_UT_compile: + if (UGLY_FLAG_FOR_AIX) + return 11 + 4/*GetDWARFSizeOfOffset*/; + else + return GetVersion() < 5 ? 11 : 12; case llvm::dwarf::DW_UT_partial: return GetVersion() < 5 ? 11 : 12; case llvm::dwarf::DW_UT_skeleton: @@ -1016,7 +1026,7 @@ uint32_t DWARFUnit::GetHeaderByteSize() const { std::optional DWARFUnit::GetStringOffsetSectionItem(uint32_t index) const { - offset_t offset = GetStrOffsetsBase() + index * 4; + lldb::offset_t offset = GetStrOffsetsBase() + index * 4; return m_dwarf.GetDWARFContext().getOrLoadStrOffsetsData().GetU32(&offset); } diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp index 2064b73dc3ea5..824528fc3acfa 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp @@ -216,7 +216,7 @@ lldb::addr_t AppleGetThreadItemInfoHandler::SetupGetThreadItemInfoFunction( AppleGetThreadItemInfoHandler::GetThreadItemInfoReturnInfo AppleGetThreadItemInfoHandler::GetThreadItemInfo(Thread &thread, - tid_t thread_id, + lldb::tid_t thread_id, addr_t page_to_free, uint64_t page_to_free_size, Status &error) { diff --git a/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/lldb/source/Symbol/DWARFCallFrameInfo.cpp index f3df8a2c27f5a..de244e372579d 100644 --- a/lldb/source/Symbol/DWARFCallFrameInfo.cpp +++ b/lldb/source/Symbol/DWARFCallFrameInfo.cpp @@ -33,7 +33,7 @@ using namespace lldb_private::dwarf; // Used for calls when the value type is specified by a DWARF EH Frame pointer // encoding. static uint64_t -GetGNUEHPointer(const DataExtractor &DE, offset_t *offset_ptr, +GetGNUEHPointer(const DataExtractor &DE, lldb::offset_t *offset_ptr, uint32_t eh_ptr_enc, addr_t pc_rel_addr, addr_t text_addr, addr_t data_addr) //, BSDRelocs *data_relocs) const { @@ -588,7 +588,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset, if (cie->augmentation[0] == 'z') { uint32_t aug_data_len = (uint32_t)m_cfi_data.GetULEB128(&offset); if (aug_data_len != 0 && cie->lsda_addr_encoding != DW_EH_PE_omit) { - offset_t saved_offset = offset; + lldb::offset_t saved_offset = offset; lsda_data_file_address = GetGNUEHPointer(m_cfi_data, &offset, cie->lsda_addr_encoding, pc_rel_addr, text_addr, data_addr); diff --git a/lldb/source/Target/ABI.cpp b/lldb/source/Target/ABI.cpp index 110b5c86fc425..6df03533cda29 100644 --- a/lldb/source/Target/ABI.cpp +++ b/lldb/source/Target/ABI.cpp @@ -208,6 +208,15 @@ bool ABI::PrepareTrivialCall(Thread &thread, lldb::addr_t sp, llvm_unreachable("Should never get here!"); } +bool ABI::PrepareTrivialCall(Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t tocAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef args) const { + // dummy prepare trivial call + llvm_unreachable("Should never get here!"); +} + bool ABI::GetFallbackRegisterLocation( const RegisterInfo *reg_info, UnwindPlan::Row::RegisterLocation &unwind_regloc) { diff --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt index a42c44b761dc5..833489b16dfd7 100644 --- a/lldb/source/Target/CMakeLists.txt +++ b/lldb/source/Target/CMakeLists.txt @@ -1,3 +1,8 @@ +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + lldb_tablegen(TargetProperties.inc -gen-lldb-property-defs SOURCE TargetProperties.td TARGET LLDBTargetPropertiesGen) diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index e3c4f2ee398cc..e31245178b2f2 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -75,6 +75,10 @@ #include "lldb/Utility/State.h" #include "lldb/Utility/Timer.h" +#if defined(__AIX__) +#include +#endif + using namespace lldb; using namespace lldb_private; using namespace std::chrono; @@ -6206,6 +6210,12 @@ Status Process::GetMemoryRegionInfo(lldb::addr_t load_addr, return DoGetMemoryRegionInfo(load_addr, range_info); } +#if defined(__AIX__) +Status Process::GetLDXINFO(struct ld_xinfo *info_ptr) { + return DoGetLDXINFO(info_ptr); +} +#endif + Status Process::GetMemoryRegions(lldb_private::MemoryRegionInfos ®ion_list) { Status error; diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index a61228d092d89..57f42ea56cb18 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -40,6 +40,9 @@ #include #include +#ifdef __AIX__ +#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" +#endif using namespace lldb; using namespace lldb_private; @@ -1257,6 +1260,10 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( // Answer the question: Where did THIS frame save the CALLER frame ("previous" // frame)'s register value? +#ifdef __AIX__ +extern bool UGLY_HACK_NULL_TOPFRAME; +#endif + enum UnwindLLDB::RegisterSearchResult RegisterContextUnwind::SavedLocationForRegister( uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc) { @@ -1517,6 +1524,11 @@ RegisterContextUnwind::SavedLocationForRegister( new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext; new_regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); +#ifdef __AIX__ + if (UGLY_HACK_NULL_TOPFRAME && new_regloc.location.register_number == 0x20) { + new_regloc.location.register_number = 0x24; + } +#endif m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; regloc = new_regloc; UnwindLogMsg("supplying caller's register %s (%d) from the live " @@ -2368,6 +2380,40 @@ bool RegisterContextUnwind::ReadPC(addr_t &pc) { } } +#ifdef __AIX__ +bool RegisterContextUnwind::ReadLR(addr_t &lr) { + if (!IsValid()) + return false; + + bool above_trap_handler = false; + if (GetNextFrame().get() && GetNextFrame()->IsValid() && + GetNextFrame()->IsTrapHandlerFrame()) + above_trap_handler = true; + + if (ReadGPRValue(eRegisterKindLLDB, gpr_lr_ppc64le, lr)) { + // A lr value of 0 or 1 is impossible in the middle of the stack -- it + // indicates the end of a stack walk. + // On the currently executing frame (or such a frame interrupted + // asynchronously by sigtramp et al) this may occur if code has jumped + // through a NULL pointer -- we want to be able to unwind past that frame + // to help find the bug. + + ProcessSP process_sp (m_thread.GetProcess()); + if (process_sp) + { + ABI *abi = process_sp->GetABI().get(); + if (abi) + lr = abi->FixCodeAddress(lr); + } + + return !(m_all_registers_available == false && + above_trap_handler == false && (lr == 0 || lr == 1)); + } else { + return false; + } +} +#endif + void RegisterContextUnwind::UnwindLogMsg(const char *fmt, ...) { Log *log = GetLog(LLDBLog::Unwind); if (!log) diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp index 50dcb66b9719f..0926579ea2930 100644 --- a/lldb/source/Target/ThreadPlanCallFunction.cpp +++ b/lldb/source/Target/ThreadPlanCallFunction.cpp @@ -127,6 +127,40 @@ ThreadPlanCallFunction::ThreadPlanCallFunction( m_valid = true; } +ThreadPlanCallFunction::ThreadPlanCallFunction( + Thread &thread, const Address &function, const Address &toc, + const CompilerType &return_type, + llvm::ArrayRef args, const EvaluateExpressionOptions &options) + : ThreadPlan(ThreadPlan::eKindCallFunction, "Call function plan", thread, + eVoteNoOpinion, eVoteNoOpinion), + m_valid(false), m_stop_other_threads(options.GetStopOthers()), + m_unwind_on_error(options.DoesUnwindOnError()), + m_ignore_breakpoints(options.DoesIgnoreBreakpoints()), + m_debug_execution(options.GetDebug()), + m_trap_exceptions(options.GetTrapExceptions()), m_function_addr(function), + m_function_sp(0), m_takedown_done(false), + m_should_clear_objc_exception_bp(false), + m_should_clear_cxx_exception_bp(false), + m_stop_address(LLDB_INVALID_ADDRESS), m_return_type(return_type) { + lldb::addr_t start_load_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t function_load_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t toc_addr = LLDB_INVALID_ADDRESS; + ABI *abi = nullptr; + + if (!ConstructorSetup(thread, abi, start_load_addr, function_load_addr)) + return; + + toc_addr = toc.GetLoadAddress(&GetTarget()); + + if (!abi->PrepareTrivialCall(thread, m_function_sp, function_load_addr, + toc_addr, start_load_addr, args)) + return; + + ReportRegisterState("Function call was set up. Register state was:"); + + m_valid = true; +} + ThreadPlanCallFunction::ThreadPlanCallFunction( Thread &thread, const Address &function, const EvaluateExpressionOptions &options) diff --git a/lldb/source/Target/UnwindLLDB.cpp b/lldb/source/Target/UnwindLLDB.cpp index f43e940492b09..255b829738ba2 100644 --- a/lldb/source/Target/UnwindLLDB.cpp +++ b/lldb/source/Target/UnwindLLDB.cpp @@ -68,6 +68,10 @@ uint32_t UnwindLLDB::DoGetFrameCount() { return m_frames.size(); } +#ifdef __AIX__ +bool UGLY_HACK_NULL_TOPFRAME = false; +#endif + bool UnwindLLDB::AddFirstFrame() { if (m_frames.size() > 0) return true; @@ -91,6 +95,17 @@ bool UnwindLLDB::AddFirstFrame() { if (!reg_ctx_sp->ReadPC(first_cursor_sp->start_pc)) goto unwind_done; +#ifdef __AIX__ + lldb::addr_t lr; + if (!reg_ctx_sp->ReadLR(lr)) + goto unwind_done; + + if (first_cursor_sp->start_pc == 0) { + first_cursor_sp->start_pc = lr; + UGLY_HACK_NULL_TOPFRAME = true; + } +#endif + // Everything checks out, so release the auto pointer value and let the // cursor own it in its shared pointer first_cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp; diff --git a/lldb/source/Utility/ArchSpec.cpp b/lldb/source/Utility/ArchSpec.cpp index 07ef435ef451d..3868f77169cc6 100644 --- a/lldb/source/Utility/ArchSpec.cpp +++ b/lldb/source/Utility/ArchSpec.cpp @@ -14,6 +14,7 @@ #include "lldb/lldb-defines.h" #include "llvm/ADT/STLExtras.h" #include "llvm/BinaryFormat/COFF.h" +#include "llvm/BinaryFormat/XCOFF.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Compiler.h" @@ -459,10 +460,22 @@ static const ArchDefinition g_coff_arch_def = { "pe-coff", }; +static const ArchDefinitionEntry g_xcoff_arch_entries[] = { + {ArchSpec::eCore_ppc_generic, llvm::XCOFF::TCPU_COM, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, + {ArchSpec::eCore_ppc64_generic, llvm::XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu} +}; + +static const ArchDefinition g_xcoff_arch_def = { + eArchTypeXCOFF, + std::size(g_xcoff_arch_entries), + g_xcoff_arch_entries, + "xcoff", +}; + //===----------------------------------------------------------------------===// // Table of all ArchDefinitions static const ArchDefinition *g_arch_definitions[] = { - &g_macho_arch_def, &g_elf_arch_def, &g_coff_arch_def}; + &g_macho_arch_def, &g_elf_arch_def, &g_coff_arch_def, &g_xcoff_arch_def}; //===----------------------------------------------------------------------===// // Static helper functions. @@ -903,6 +916,9 @@ bool ArchSpec::SetArchitecture(ArchitectureType arch_type, uint32_t cpu, } else if (arch_type == eArchTypeCOFF && os == llvm::Triple::Win32) { m_triple.setVendor(llvm::Triple::PC); m_triple.setOS(llvm::Triple::Win32); + } else if (arch_type == eArchTypeXCOFF && os == llvm::Triple::AIX) { + m_triple.setVendor(llvm::Triple::IBM); + m_triple.setOS(llvm::Triple::AIX); } else { m_triple.setVendor(llvm::Triple::UnknownVendor); m_triple.setOS(llvm::Triple::UnknownOS); diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp index 9f79d2271b1e6..dbd3236536f8c 100644 --- a/lldb/source/Utility/StringExtractorGDBRemote.cpp +++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -227,6 +227,8 @@ StringExtractorGDBRemote::GetServerPacketType() const { return eServerPacketType_qLaunchGDBServer; if (PACKET_MATCHES("qLaunchSuccess")) return eServerPacketType_qLaunchSuccess; + if (PACKET_MATCHES("qLDXINFO")) + return eServerPacketType_qLDXINFO; break; case 'M': diff --git a/lldb/test/CMakeLists.txt b/lldb/test/CMakeLists.txt index 5ac474736eb63..413a1e5120288 100644 --- a/lldb/test/CMakeLists.txt +++ b/lldb/test/CMakeLists.txt @@ -155,7 +155,7 @@ if(TARGET clang) add_lldb_test_dependency(clang) # TestFullLtoStepping depends on LTO, and only runs when the compiler is clang. - add_lldb_test_dependency(LTO) + #add_lldb_test_dependency(LTO) if (TARGET libcxx OR ("libcxx" IN_LIST LLVM_ENABLE_RUNTIMES)) set(LLDB_HAS_LIBCXX ON) diff --git a/lldb/test/Shell/Expr/TestIRMemoryMap.test b/lldb/test/Shell/Expr/TestIRMemoryMap.test index 9dd0413be14cf..5ed61ad33ffc4 100644 --- a/lldb/test/Shell/Expr/TestIRMemoryMap.test +++ b/lldb/test/Shell/Expr/TestIRMemoryMap.test @@ -1,6 +1,6 @@ # UNSUPPORTED: system-windows -# RUN: %clangxx_host %p/Inputs/call-function.cpp -g -o %t +# RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t # RUN: lldb-test ir-memory-map %t %S/Inputs/ir-memory-map-basic # RUN: lldb-test ir-memory-map -host-only %t %S/Inputs/ir-memory-map-basic diff --git a/lldb/test/Shell/Process/TestEnvironment.test b/lldb/test/Shell/Process/TestEnvironment.test index e6d6e56fc9203..2ead258719f32 100644 --- a/lldb/test/Shell/Process/TestEnvironment.test +++ b/lldb/test/Shell/Process/TestEnvironment.test @@ -3,7 +3,7 @@ UNSUPPORTED: lldb-repro The double quotes around "BAR" ensure we don't match the command. -RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t +RUN: %clangxx_host -std=c++11 -I/compgpfs/build/xlcit/rings/openxlC/aix/wyvern_dev/ring0/latest/opt/IBM/openxlC/17.1.2/include/c++/v1/ %p/Inputs/env.cpp -o %t RUN: %lldb %t -o 'process launch --environment FOO="BAR"' | FileCheck %s RUN: %lldb %t -o 'env FOO="BAR"' -o 'process launch' | FileCheck %s diff --git a/lldb/tools/driver/CMakeLists.txt b/lldb/tools/driver/CMakeLists.txt index cd304a047dea6..78617be24f780 100644 --- a/lldb/tools/driver/CMakeLists.txt +++ b/lldb/tools/driver/CMakeLists.txt @@ -11,6 +11,11 @@ if(APPLE) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_BINARY_DIR}/lldb-Info.plist") endif() +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + add_lldb_tool(lldb Driver.cpp Platform.cpp diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp index 14371da64f2f2..f7eaf56738d7d 100644 --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -639,7 +639,7 @@ void sigwinch_handler(int signo) { } void sigint_handler(int signo) { -#ifdef _WIN32 // Restore handler as it is not persistent on Windows +#if defined(_WIN32) || defined(__AIX__) // Restore handler as it is not persistent on Windows signal(SIGINT, sigint_handler); #endif static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT; @@ -727,8 +727,11 @@ static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) { int main(int argc, char const *argv[]) { // Editline uses for example iswprint which is dependent on LC_CTYPE. + // FIXME: this caused unexpected SIGTRAP on AIX +#ifndef __AIX__ std::setlocale(LC_ALL, ""); std::setlocale(LC_CTYPE, ""); +#endif // Setup LLVM signal handlers and make sure we call llvm_shutdown() on // destruction. diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index f8f0d86453f58..2fa6f6c9a5369 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -6,6 +6,10 @@ if (HAVE_LIBPTHREAD) list(APPEND extra_libs pthread) endif () +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + add_definitions("-D_AIX") + add_definitions("-D_ALL_SOURCE") +endif() if(APPLE) configure_file( diff --git a/lldb/tools/lldb-server/CMakeLists.txt b/lldb/tools/lldb-server/CMakeLists.txt index 9030ed709a647..0d69ae32a008f 100644 --- a/lldb/tools/lldb-server/CMakeLists.txt +++ b/lldb/tools/lldb-server/CMakeLists.txt @@ -8,6 +8,10 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux|Android") list(APPEND LLDB_PLUGINS lldbPluginProcessLinux) endif() +if(CMAKE_SYSTEM_NAME MATCHES "AIX") + list(APPEND LLDB_PLUGINS lldbPluginProcessAIX) +endif() + if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") list(APPEND LLDB_PLUGINS lldbPluginProcessFreeBSD) endif() @@ -20,6 +24,8 @@ if(CMAKE_SYSTEM_NAME MATCHES "Darwin") list(APPEND LLDB_PLUGINS lldbPluginObjectFileMachO) elseif(CMAKE_SYSTEM_NAME MATCHES "Windows") list(APPEND LLDB_PLUGINS lldbPluginObjectFilePECOFF) +elseif(CMAKE_SYSTEM_NAME MATCHES "AIX") + list(APPEND LLDB_PLUGINS lldbPluginObjectFileXCOFF) else() list(APPEND LLDB_PLUGINS lldbPluginObjectFileELF) endif() @@ -54,6 +60,7 @@ add_lldb_tool(lldb-server lldbPluginInstructionMIPS lldbPluginInstructionMIPS64 lldbPluginInstructionRISCV + lldbPluginInstructionPPC64 ${LLDB_SYSTEM_LIBS} LINK_COMPONENTS diff --git a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp index 4233252a84dfc..91bb2083a88b5 100644 --- a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp +++ b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp @@ -14,6 +14,9 @@ using HostObjectFile = ObjectFileMachO; #elif defined(_WIN32) #include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" using HostObjectFile = ObjectFilePECOFF; +#elif defined(__AIX__) +#include "Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h" +using HostObjectFile = ObjectFileXCOFF; #else #include "Plugins/ObjectFile/ELF/ObjectFileELF.h" using HostObjectFile = ObjectFileELF; @@ -46,6 +49,10 @@ using HostObjectFile = ObjectFileELF; #include "Plugins/Instruction/MIPS/EmulateInstructionMIPS.h" #endif +#if defined(__AIX__) +#include "Plugins/Instruction/PPC64/EmulateInstructionPPC64.h" +#endif + #if defined(__riscv) #define LLDB_TARGET_RISCV #include "Plugins/Instruction/RISCV/EmulateInstructionRISCV.h" @@ -75,6 +82,10 @@ llvm::Error SystemInitializerLLGS::Initialize() { EmulateInstructionRISCV::Initialize(); #endif +#if defined(__AIX__) + EmulateInstructionPPC64::Initialize(); +#endif + return llvm::Error::success(); } @@ -97,5 +108,9 @@ void SystemInitializerLLGS::Terminate() { EmulateInstructionRISCV::Terminate(); #endif +#if defined(__AIX__) + EmulateInstructionPPC64::Terminate(); +#endif + SystemInitializerCommon::Terminate(); } diff --git a/lldb/tools/lldb-server/lldb-gdbserver.cpp b/lldb/tools/lldb-server/lldb-gdbserver.cpp index 563284730bc70..2a14f4f9c82aa 100644 --- a/lldb/tools/lldb-server/lldb-gdbserver.cpp +++ b/lldb/tools/lldb-server/lldb-gdbserver.cpp @@ -45,6 +45,8 @@ #include "Plugins/Process/NetBSD/NativeProcessNetBSD.h" #elif defined(_WIN32) #include "Plugins/Process/Windows/Common/NativeProcessWindows.h" +#elif defined(__AIX__) +#include "Plugins/Process/AIX/NativeProcessAIX.h" #endif #ifndef LLGS_PROGRAM_NAME @@ -70,6 +72,8 @@ typedef process_freebsd::NativeProcessFreeBSD::Manager NativeProcessManager; typedef process_netbsd::NativeProcessNetBSD::Manager NativeProcessManager; #elif defined(_WIN32) typedef NativeProcessWindows::Manager NativeProcessManager; +#elif defined(__AIX__) +typedef process_aix::NativeProcessAIX::Manager NativeProcessManager; #else // Dummy implementation to make sure the code compiles class NativeProcessManager : public NativeProcessProtocol::Manager { diff --git a/lldb/unittests/Host/FileSystemTest.cpp b/lldb/unittests/Host/FileSystemTest.cpp index 58887f6b2467e..89d0f5b87171a 100644 --- a/lldb/unittests/Host/FileSystemTest.cpp +++ b/lldb/unittests/Host/FileSystemTest.cpp @@ -59,7 +59,7 @@ class DummyFileSystem : public vfs::FileSystem { return I->second; } ErrorOr> - openFileForRead(const Twine &Path) override { + openFileForRead(const Twine &Path, bool IsText) override { auto S = status(Path); if (S) return std::unique_ptr(new DummyFile{*S}); diff --git a/lldb/unittests/Host/posix/TerminalTest.cpp b/lldb/unittests/Host/posix/TerminalTest.cpp index 5187a0c20a68b..f3de92c0852b1 100644 --- a/lldb/unittests/Host/posix/TerminalTest.cpp +++ b/lldb/unittests/Host/posix/TerminalTest.cpp @@ -94,15 +94,19 @@ TEST_F(TerminalTest, SetRaw) { TEST_F(TerminalTest, SetBaudRate) { struct termios terminfo; +#if (defined(__AIX__) && defined(B38400)) || !defined(__AIX__) ASSERT_THAT_ERROR(m_term.SetBaudRate(38400), llvm::Succeeded()); ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0); EXPECT_EQ(cfgetispeed(&terminfo), static_cast(B38400)); EXPECT_EQ(cfgetospeed(&terminfo), static_cast(B38400)); +#endif +#if (defined(__AIX__) && defined(B115200)) || !defined(__AIX__) ASSERT_THAT_ERROR(m_term.SetBaudRate(115200), llvm::Succeeded()); ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0); EXPECT_EQ(cfgetispeed(&terminfo), static_cast(B115200)); EXPECT_EQ(cfgetospeed(&terminfo), static_cast(B115200)); +#endif // uncommon value #if defined(B153600) diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h index 5a7cd8e38f2b7..fa9c6781e24f5 100644 --- a/llvm/include/llvm/Object/XCOFFObjectFile.h +++ b/llvm/include/llvm/Object/XCOFFObjectFile.h @@ -542,7 +542,6 @@ class XCOFFObjectFile : public ObjectFile { template const T *sectionHeaderTable() const; size_t getFileHeaderSize() const; - size_t getSectionHeaderSize() const; const XCOFFSectionHeader32 *toSection32(DataRefImpl Ref) const; const XCOFFSectionHeader64 *toSection64(DataRefImpl Ref) const; @@ -578,6 +577,9 @@ class XCOFFObjectFile : public ObjectFile { void checkSectionAddress(uintptr_t Addr, uintptr_t TableAddr) const; public: + size_t getSectionHeaderSize() const; + Expected getLoaderSectionAddress() const; + static constexpr uint64_t InvalidRelocOffset = std::numeric_limits::max(); diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp index bdd04b00f557b..9c96df1bbdc54 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -251,10 +251,16 @@ Expected DWARFUnit::getStringOffsetSectionItem(uint32_t Index) const { return DA.getRelocatedValue(ItemSize, &Offset); } +bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; + Error DWARFUnitHeader::extract(DWARFContext &Context, const DWARFDataExtractor &debug_info, uint64_t *offset_ptr, DWARFSectionKind SectionKind) { + if (UGLY_FLAG_FOR_AIX) { + // FIXME: hack to get version + *offset_ptr += 8; + } Offset = *offset_ptr; Error Err = Error::success(); IndexEntry = nullptr; @@ -267,8 +273,13 @@ Error DWARFUnitHeader::extract(DWARFContext &Context, AbbrOffset = debug_info.getRelocatedValue( FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err); } else { - AbbrOffset = debug_info.getRelocatedValue( - FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err); + if (UGLY_FLAG_FOR_AIX) { + AbbrOffset = debug_info.getRelocatedValue( + 8, offset_ptr, nullptr, &Err); + } else { + AbbrOffset = debug_info.getRelocatedValue( + FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err); + } FormParams.AddrSize = debug_info.getU8(offset_ptr, &Err); // Fake a unit type based on the section type. This isn't perfect, // but distinguishing compile and type units is generally enough. >From b1da5b1cf35829fcbf4ad6564c6005c755012e47 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 7 Aug 2024 12:18:45 -0500 Subject: [PATCH 02/48] Code license notice --- lldb/NOTICE.TXT | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 lldb/NOTICE.TXT diff --git a/lldb/NOTICE.TXT b/lldb/NOTICE.TXT new file mode 100644 index 0000000000000..d814272967476 --- /dev/null +++ b/lldb/NOTICE.TXT @@ -0,0 +1,7 @@ + +This product contains small piece of code to support AIX, taken from netbsd. + + * LICENSE: + * lldb/source/Host/common/LICENSE.aix-netbsd.txt (OpenSSL License) + * HOMEPAGE: + * https://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/crypto/external/bsd/openssl/dist >From 50ad673a78029fd6c47d90317e2c61ca2b59d5c5 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 7 Aug 2024 13:27:20 -0500 Subject: [PATCH 03/48] Reverting .tests --- lldb/test/Shell/Expr/TestIRMemoryMap.test | 2 +- lldb/test/Shell/Process/TestEnvironment.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/test/Shell/Expr/TestIRMemoryMap.test b/lldb/test/Shell/Expr/TestIRMemoryMap.test index 5ed61ad33ffc4..9dd0413be14cf 100644 --- a/lldb/test/Shell/Expr/TestIRMemoryMap.test +++ b/lldb/test/Shell/Expr/TestIRMemoryMap.test @@ -1,6 +1,6 @@ # UNSUPPORTED: system-windows -# RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t +# RUN: %clangxx_host %p/Inputs/call-function.cpp -g -o %t # RUN: lldb-test ir-memory-map %t %S/Inputs/ir-memory-map-basic # RUN: lldb-test ir-memory-map -host-only %t %S/Inputs/ir-memory-map-basic diff --git a/lldb/test/Shell/Process/TestEnvironment.test b/lldb/test/Shell/Process/TestEnvironment.test index 2ead258719f32..e6d6e56fc9203 100644 --- a/lldb/test/Shell/Process/TestEnvironment.test +++ b/lldb/test/Shell/Process/TestEnvironment.test @@ -3,7 +3,7 @@ UNSUPPORTED: lldb-repro The double quotes around "BAR" ensure we don't match the command. -RUN: %clangxx_host -std=c++11 -I/compgpfs/build/xlcit/rings/openxlC/aix/wyvern_dev/ring0/latest/opt/IBM/openxlC/17.1.2/include/c++/v1/ %p/Inputs/env.cpp -o %t +RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t RUN: %lldb %t -o 'process launch --environment FOO="BAR"' | FileCheck %s RUN: %lldb %t -o 'env FOO="BAR"' -o 'process launch' | FileCheck %s >From c1967be8fe14d469cb5ae9d41d115a7003ff39b6 Mon Sep 17 00:00:00 2001 From: Lakshmi Surekha Kovvuri Date: Thu, 22 Aug 2024 08:49:50 -0500 Subject: [PATCH 04/48] For TestSuite Run --- lldb/unittests/Host/FileSystemTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/unittests/Host/FileSystemTest.cpp b/lldb/unittests/Host/FileSystemTest.cpp index 89d0f5b87171a..58887f6b2467e 100644 --- a/lldb/unittests/Host/FileSystemTest.cpp +++ b/lldb/unittests/Host/FileSystemTest.cpp @@ -59,7 +59,7 @@ class DummyFileSystem : public vfs::FileSystem { return I->second; } ErrorOr> - openFileForRead(const Twine &Path, bool IsText) override { + openFileForRead(const Twine &Path) override { auto S = status(Path); if (S) return std::unique_ptr(new DummyFile{*S}); >From 758ab642d0974e799ac902d8ad240a3a90aeb24d Mon Sep 17 00:00:00 2001 From: Lakshmi Surekha Kovvuri Date: Fri, 30 Aug 2024 08:33:32 -0500 Subject: [PATCH 05/48] Changes made to AIX-specific files to eliminate errors encountered during CI when updating LLDB. --- .../Plugins/Process/AIX/NativeProcessAIX.cpp | 20 ++++++++++--------- .../Process/AIX/NativeRegisterContextAIX.cpp | 4 ++-- .../AIX/NativeRegisterContextAIX_ppc64.cpp | 10 +++++----- .../Plugins/Process/AIX/NativeThreadAIX.cpp | 2 +- .../GDBRemoteCommunicationClient.cpp | 4 ++-- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp index 882f20d30a3bf..5b01a66b0453f 100644 --- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -211,12 +211,14 @@ static Status EnsureFDFlags(int fd, int flags) { int status = fcntl(fd, F_GETFL); if (status == -1) { - error.SetErrorToErrno(); + error = Status::FromErrno(); + // error.SetErrorToErrno(); return error; } if (fcntl(fd, F_SETFL, status | flags) == -1) { - error.SetErrorToErrno(); + error = Status::FromErrno(); + // error.SetErrorToErrno(); return error; } @@ -813,7 +815,7 @@ Status NativeProcessAIX::Resume(const ResumeActionList &resume_actions) { Status error = ResumeThread(static_cast(*thread), action->state, signo); if (error.Fail()) - return Status("NativeProcessAIX::%s: failed to resume thread " + return Status::FromErrorStringWithFormat("NativeProcessAIX::%s: failed to resume thread " "for pid %" PRIu64 ", tid %" PRIu64 ", error = %s", __FUNCTION__, GetID(), thread->GetID(), error.AsCString()); @@ -826,7 +828,7 @@ Status NativeProcessAIX::Resume(const ResumeActionList &resume_actions) { break; default: - return Status("NativeProcessAIX::%s (): unexpected state %s specified " + return Status::FromErrorStringWithFormat("NativeProcessAIX::%s (): unexpected state %s specified " "for pid %" PRIu64 ", tid %" PRIu64, __FUNCTION__, StateAsCString(action->state), GetID(), thread->GetID()); @@ -840,7 +842,7 @@ Status NativeProcessAIX::Halt() { Status error; if (kill(GetID(), SIGSTOP) != 0) - error.SetErrorToErrno(); + error = Status::FromErrno(); return error; } @@ -874,7 +876,7 @@ Status NativeProcessAIX::Signal(int signo) { Host::GetSignalAsCString(signo), GetID()); if (kill(GetID(), signo)) - error.SetErrorToErrno(); + error = Status::FromErrno(); return error; } @@ -951,7 +953,7 @@ Status NativeProcessAIX::Kill() { } if (kill(GetID(), SIGKILL) != 0) { - error.SetErrorToErrno(); + error = Status::FromErrno(); return error; } @@ -1555,7 +1557,7 @@ Status NativeProcessAIX::GetLoadedModuleFileSpec(const char *module_path, return Status(); } } - return Status("Module file (%s) not found in /proc/%" PRIu64 "/maps file!", + return Status::FromErrorStringWithFormat("Module file (%s) not found in /proc/%" PRIu64 "/maps file!", module_file_spec.GetFilename().AsCString(), GetID()); } @@ -2011,7 +2013,7 @@ Status NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid, void *addr, } if (errno) { - error.SetErrorToErrno(); + error = Status::FromErrno(); ret = -1; } diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp index 0859f9501c1b6..071e55543cc3c 100644 --- a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp @@ -27,7 +27,7 @@ Status NativeRegisterContextAIX::ReadRegisterRaw(uint32_t reg_index, RegisterValue ®_value) { const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); if (!reg_info) - return Status("register %" PRIu32 " not found", reg_index); + return Status::FromErrorStringWithFormat("register %" PRIu32 " not found", reg_index); return DoReadRegisterValue(GetPtraceOffset(reg_index), reg_info->name, reg_info->byte_size, reg_value); @@ -82,7 +82,7 @@ NativeRegisterContextAIX::WriteRegisterRaw(uint32_t reg_index, assert(register_to_write_info_p && "register to write does not have valid RegisterInfo"); if (!register_to_write_info_p) - return Status("NativeRegisterContextAIX::%s failed to get RegisterInfo " + return Status::FromErrorStringWithFormat("NativeRegisterContextAIX::%s failed to get RegisterInfo " "for write register index %" PRIu32, __FUNCTION__, reg_to_write); diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp index 1996373791748..0132b52dec6f2 100644 --- a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp @@ -165,7 +165,7 @@ Status NativeRegisterContextAIX_ppc64::ReadRegister( Status error; if (!reg_info) { - error.SetErrorString("reg_info NULL"); + error.FromErrorString("reg_info NULL"); return error; } @@ -251,7 +251,7 @@ Status NativeRegisterContextAIX_ppc64::WriteRegister( const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; if (reg_index == LLDB_INVALID_REGNUM) - return Status("no lldb regnum for %s", reg_info && reg_info->name + return Status::FromErrorStringWithFormat("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : ""); @@ -389,14 +389,14 @@ Status NativeRegisterContextAIX_ppc64::WriteAllRegisterValues( Status error; if (!data_sp) { - error.SetErrorStringWithFormat( + error = Status::FromErrorStringWithFormat( "NativeRegisterContextAIX_ppc64::%s invalid data_sp provided", __FUNCTION__); return error; } if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { - error.SetErrorStringWithFormat( + error = Status::FromErrorStringWithFormat( "NativeRegisterContextAIX_ppc64::%s data_sp contained mismatched " "data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); @@ -405,7 +405,7 @@ Status NativeRegisterContextAIX_ppc64::WriteAllRegisterValues( const uint8_t *src = data_sp->GetBytes(); if (src == nullptr) { - error.SetErrorStringWithFormat("NativeRegisterContextAIX_ppc64::%s " + error = Status::FromErrorStringWithFormat("NativeRegisterContextAIX_ppc64::%s " "DataBuffer::GetBytes() returned a null " "pointer", __FUNCTION__); diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp index e07daccdff550..bb14b6ab4a05e 100644 --- a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp @@ -481,7 +481,7 @@ Status NativeThreadAIX::RequestStop() { Status err; errno = 0; if (::kill(pid, SIGSTOP) != 0) { - err.SetErrorToErrno(); + err = Status::FromErrno(); LLDB_LOGF(log, "NativeThreadAIX::%s kill(%" PRIu64 ", SIGSTOP) failed: %s", __FUNCTION__, pid, err.AsCString()); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 17926f8e4ab53..0aa68a4a09cbe 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -1728,11 +1728,11 @@ Status GDBRemoteCommunicationClient::GetLDXINFO(struct ld_xinfo *info_ptr) llvm::MutableArrayRef infoData((uint8_t *)info_ptr, sizeof(struct ld_xinfo)*64); size_t got_bytes = response.GetHexBytesAvail(infoData); if (got_bytes != sizeof(struct ld_xinfo)*64) { - error.SetErrorString("qLDXINFO ret bad size"); + error.FromErrorString("qLDXINFO ret bad size"); return error; } } else { - error.SetErrorString("qLDXINFO is not supported"); + error.FromErrorString("qLDXINFO is not supported"); } return error; } >From 33d561f4bb74a2efd0da163ebde416c9ad1c2925 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Tue, 10 Sep 2024 02:00:09 -0500 Subject: [PATCH 06/48] Removed non-required PTRACE defs --- lldb/include/lldb/Host/aix/Ptrace.h | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/lldb/include/lldb/Host/aix/Ptrace.h b/lldb/include/lldb/Host/aix/Ptrace.h index 88928f18102d7..393928a89add3 100644 --- a/lldb/include/lldb/Host/aix/Ptrace.h +++ b/lldb/include/lldb/Host/aix/Ptrace.h @@ -34,29 +34,11 @@ #ifndef PTRACE_SETREGSET #define PTRACE_SETREGSET 0x4205 #endif -#ifndef PTRACE_GET_THREAD_AREA -#define PTRACE_GET_THREAD_AREA (PT_COMMAND_MAX+5) -#endif -#ifndef PTRACE_ARCH_PRCTL -#define PTRACE_ARCH_PRCTL (PT_COMMAND_MAX+6) -#endif -#ifndef ARCH_GET_FS -#define ARCH_SET_GS 0x1001 -#define ARCH_SET_FS 0x1002 -#define ARCH_GET_FS 0x1003 -#define ARCH_GET_GS 0x1004 -#endif -#ifndef PTRACE_PEEKMTETAGS -#define PTRACE_PEEKMTETAGS (PT_COMMAND_MAX+7) -#endif -#ifndef PTRACE_POKEMTETAGS -#define PTRACE_POKEMTETAGS (PT_COMMAND_MAX+8) -#endif #ifndef PTRACE_GETVRREGS -#define PTRACE_GETVRREGS (PT_COMMAND_MAX+9) +#define PTRACE_GETVRREGS (PT_COMMAND_MAX+5) #endif #ifndef PTRACE_GETVSRREGS -#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+10) +#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+6) #endif #endif // liblldb_Host_aix_Ptrace_h_ >From 450793d7270999ecdd6714c4222663517dab3928 Mon Sep 17 00:00:00 2001 From: Lakshmi Surekha Kovvuri Date: Wed, 11 Sep 2024 02:52:41 -0500 Subject: [PATCH 07/48] Patch for running of unit testcases without hang --- lldb/unittests/Host/MainLoopTest.cpp | 4 +++- lldb/unittests/Host/PipeTest.cpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lldb/unittests/Host/MainLoopTest.cpp b/lldb/unittests/Host/MainLoopTest.cpp index 4084e90782fd5..9e92ec1470d4d 100644 --- a/lldb/unittests/Host/MainLoopTest.cpp +++ b/lldb/unittests/Host/MainLoopTest.cpp @@ -183,7 +183,7 @@ TEST_F(MainLoopTest, PendingCallbackAfterLoopExited) { loop.AddPendingCallback([&](MainLoopBase &loop) {}); } -#ifdef LLVM_ON_UNIX +#if defined(LLVM_ON_UNIX) && !defined(__AIX__) TEST_F(MainLoopTest, DetectsEOF) { PseudoTerminal term; @@ -202,7 +202,9 @@ TEST_F(MainLoopTest, DetectsEOF) { ASSERT_TRUE(loop.Run().Success()); ASSERT_EQ(1u, callback_count); } +// #endif +// #ifdef LLVM_ON_UNIX TEST_F(MainLoopTest, Signal) { MainLoop loop; Status error; diff --git a/lldb/unittests/Host/PipeTest.cpp b/lldb/unittests/Host/PipeTest.cpp index 506f3d225a21e..c1013aa7a7e4e 100644 --- a/lldb/unittests/Host/PipeTest.cpp +++ b/lldb/unittests/Host/PipeTest.cpp @@ -55,6 +55,7 @@ TEST_F(PipeTest, OpenAsReader) { } #endif +#if !defined(__AIX__) TEST_F(PipeTest, WriteWithTimeout) { Pipe pipe; ASSERT_THAT_ERROR(pipe.CreateNew(false).ToError(), llvm::Succeeded()); @@ -150,3 +151,4 @@ TEST_F(PipeTest, WriteWithTimeout) { .ToError(), llvm::Succeeded()); } +#endif >From 61e7843b431ff3657e3c4b39d1559401ff3de891 Mon Sep 17 00:00:00 2001 From: Lakshmi Surekha Kovvuri Date: Thu, 12 Sep 2024 13:22:03 -0500 Subject: [PATCH 08/48] changes applied to NativeProcessAIX.cpp file to solve build errors while making LLDB up to date --- .../Plugins/Process/AIX/NativeProcessAIX.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp index 5b01a66b0453f..fc84763857453 100644 --- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -862,7 +862,7 @@ Status NativeProcessAIX::Detach() { Status e = Detach(thread->GetID()); if (e.Fail()) error = - e; // Save the error, but still attempt to detach from other threads. + e.Clone(); // Save the error, but still attempt to detach from other threads. } return error; @@ -1240,7 +1240,7 @@ Status NativeProcessAIX::ReadMemoryTags(int32_t type, lldb::addr_t addr, llvm::Expected details = GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); if (!details) - return Status(details.takeError()); + return Status::FromError(details.takeError()); // Ignore 0 length read if (!len) @@ -1295,7 +1295,7 @@ Status NativeProcessAIX::WriteMemoryTags(int32_t type, lldb::addr_t addr, llvm::Expected details = GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); if (!details) - return Status(details.takeError()); + return Status::FromError(details.takeError()); // Ignore 0 length write if (!len) @@ -1312,18 +1312,18 @@ Status NativeProcessAIX::WriteMemoryTags(int32_t type, lldb::addr_t addr, llvm::Expected> unpacked_tags_or_err = details->manager->UnpackTagsData(tags); if (!unpacked_tags_or_err) - return Status(unpacked_tags_or_err.takeError()); + return Status::FromError(unpacked_tags_or_err.takeError()); llvm::Expected> repeated_tags_or_err = details->manager->RepeatTagsForRange(*unpacked_tags_or_err, range); if (!repeated_tags_or_err) - return Status(repeated_tags_or_err.takeError()); + return Status::FromError(repeated_tags_or_err.takeError()); // Repack them for ptrace to use llvm::Expected> final_tag_data = details->manager->PackTags(*repeated_tags_or_err); if (!final_tag_data) - return Status(final_tag_data.takeError()); + return Status::FromError(final_tag_data.takeError()); struct iovec tags_vec; uint8_t *src = final_tag_data->data(); @@ -1609,13 +1609,13 @@ Status NativeProcessAIX::ResumeThread(NativeThreadAIX &thread, // reflect it is running after this completes. switch (state) { case eStateRunning: { - const auto resume_result = thread.Resume(signo); + Status resume_result = thread.Resume(signo); if (resume_result.Success()) SetState(eStateRunning, true); return resume_result; } case eStateStepping: { - const auto step_result = thread.SingleStep(signo); + Status step_result = thread.SingleStep(signo); if (step_result.Success()) SetState(eStateRunning, true); return step_result; >From 627a5427daba3fc5ea03ae481874f4aa1b4d2ed0 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Fri, 13 Sep 2024 16:25:47 +0530 Subject: [PATCH 09/48] Revert "Removed non-required PTRACE defs" --- lldb/include/lldb/Host/aix/Ptrace.h | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/lldb/include/lldb/Host/aix/Ptrace.h b/lldb/include/lldb/Host/aix/Ptrace.h index 393928a89add3..88928f18102d7 100644 --- a/lldb/include/lldb/Host/aix/Ptrace.h +++ b/lldb/include/lldb/Host/aix/Ptrace.h @@ -34,11 +34,29 @@ #ifndef PTRACE_SETREGSET #define PTRACE_SETREGSET 0x4205 #endif +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA (PT_COMMAND_MAX+5) +#endif +#ifndef PTRACE_ARCH_PRCTL +#define PTRACE_ARCH_PRCTL (PT_COMMAND_MAX+6) +#endif +#ifndef ARCH_GET_FS +#define ARCH_SET_GS 0x1001 +#define ARCH_SET_FS 0x1002 +#define ARCH_GET_FS 0x1003 +#define ARCH_GET_GS 0x1004 +#endif +#ifndef PTRACE_PEEKMTETAGS +#define PTRACE_PEEKMTETAGS (PT_COMMAND_MAX+7) +#endif +#ifndef PTRACE_POKEMTETAGS +#define PTRACE_POKEMTETAGS (PT_COMMAND_MAX+8) +#endif #ifndef PTRACE_GETVRREGS -#define PTRACE_GETVRREGS (PT_COMMAND_MAX+5) +#define PTRACE_GETVRREGS (PT_COMMAND_MAX+9) #endif #ifndef PTRACE_GETVSRREGS -#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+6) +#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+10) #endif #endif // liblldb_Host_aix_Ptrace_h_ >From ea34b15d8568b4639b4e850ef032e684d82dd971 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Thu, 10 Oct 2024 00:38:18 -0500 Subject: [PATCH 10/48] Replaced __AIX__ with _AIX --- clang/test/SemaCXX/class-layout.cpp | 2 +- lldb/CMakeLists.txt | 2 +- lldb/include/lldb/Host/HostGetOpt.h | 2 +- lldb/include/lldb/Host/HostInfo.h | 2 +- lldb/include/lldb/Host/XML.h | 2 +- lldb/include/lldb/Host/common/GetOptInc.h | 4 ++-- lldb/include/lldb/Target/Process.h | 6 +++--- lldb/include/lldb/Target/RegisterContextUnwind.h | 2 +- lldb/source/Core/Mangled.cpp | 2 +- lldb/source/Core/Section.cpp | 2 +- lldb/source/Host/common/Host.cpp | 4 ++-- lldb/source/Host/common/XML.cpp | 2 +- lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp | 2 +- lldb/source/Host/posix/FileSystemPosix.cpp | 2 +- lldb/source/Host/posix/MainLoopPosix.cpp | 4 ++-- lldb/source/Host/posix/ProcessLauncherPosixFork.cpp | 2 +- lldb/source/Initialization/SystemInitializerCommon.cpp | 4 ++-- lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp | 4 ++-- .../DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 6 +++--- .../Plugins/Instruction/PPC64/EmulateInstructionPPC64.h | 2 +- lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp | 2 +- lldb/source/Plugins/Language/ObjC/Cocoa.cpp | 2 +- .../BSD-Archive/ObjectContainerBSDArchive.cpp | 2 +- .../Big-Archive/ObjectContainerBigArchive.cpp | 2 +- .../Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp | 2 +- lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp | 6 +++--- .../source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp | 6 +++--- lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp | 6 +++--- lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp | 4 ++-- .../Process/gdb-remote/GDBRemoteCommunicationClient.cpp | 4 ++-- .../Process/gdb-remote/GDBRemoteCommunicationClient.h | 4 ++-- .../gdb-remote/GDBRemoteCommunicationServerLLGS.cpp | 4 ++-- .../Plugins/Process/gdb-remote/ProcessGDBRemote.cpp | 4 ++-- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h | 4 ++-- lldb/source/Target/Process.cpp | 4 ++-- lldb/source/Target/RegisterContextUnwind.cpp | 8 ++++---- lldb/source/Target/UnwindLLDB.cpp | 4 ++-- lldb/tools/driver/Driver.cpp | 4 ++-- lldb/tools/lldb-server/SystemInitializerLLGS.cpp | 8 ++++---- lldb/tools/lldb-server/lldb-gdbserver.cpp | 4 ++-- lldb/unittests/Host/MainLoopTest.cpp | 2 +- lldb/unittests/Host/PipeTest.cpp | 2 +- lldb/unittests/Host/posix/TerminalTest.cpp | 4 ++-- 43 files changed, 75 insertions(+), 75 deletions(-) diff --git a/clang/test/SemaCXX/class-layout.cpp b/clang/test/SemaCXX/class-layout.cpp index 22fb34b8419c5..0931d905a9749 100644 --- a/clang/test/SemaCXX/class-layout.cpp +++ b/clang/test/SemaCXX/class-layout.cpp @@ -639,7 +639,7 @@ namespace PR37275 { #pragma pack(pop) } -#endif // !defined(__MVS__) && !defined(__AIX__) +#endif // !defined(__MVS__) && !defined(_AIX) namespace non_pod { struct t1 { diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt index 2e9ae0d0b3221..a4fd8bccf056d 100644 --- a/lldb/CMakeLists.txt +++ b/lldb/CMakeLists.txt @@ -39,7 +39,7 @@ include(LLDBConfig) include(AddLLDB) if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") - add_definitions("-D__AIX__") + add_definitions("-D_AIX") endif() # Define the LLDB_CONFIGURATION_xxx matching the build type. diff --git a/lldb/include/lldb/Host/HostGetOpt.h b/lldb/include/lldb/Host/HostGetOpt.h index f450e561d6afb..b2b436e64a692 100644 --- a/lldb/include/lldb/Host/HostGetOpt.h +++ b/lldb/include/lldb/Host/HostGetOpt.h @@ -9,7 +9,7 @@ #ifndef LLDB_HOST_HOSTGETOPT_H #define LLDB_HOST_HOSTGETOPT_H -#if !defined(_MSC_VER) && !defined(__NetBSD__) && !defined(__AIX__) +#if !defined(_MSC_VER) && !defined(__NetBSD__) && !defined(_AIX) #include #include diff --git a/lldb/include/lldb/Host/HostInfo.h b/lldb/include/lldb/Host/HostInfo.h index 156df8cf6901d..0f7ec0e0aa0d2 100644 --- a/lldb/include/lldb/Host/HostInfo.h +++ b/lldb/include/lldb/Host/HostInfo.h @@ -55,7 +55,7 @@ #elif defined(__APPLE__) #include "lldb/Host/macosx/HostInfoMacOSX.h" #define HOST_INFO_TYPE HostInfoMacOSX -#elif defined(__AIX__) +#elif defined(_AIX) #include "lldb/Host/aix/HostInfoAIX.h" #define HOST_INFO_TYPE HostInfoAIX #else diff --git a/lldb/include/lldb/Host/XML.h b/lldb/include/lldb/Host/XML.h index cf359f7726d5d..483589f1abc75 100644 --- a/lldb/include/lldb/Host/XML.h +++ b/lldb/include/lldb/Host/XML.h @@ -11,7 +11,7 @@ #include "lldb/Host/Config.h" -#if defined(__AIX__) +#if defined(_AIX) //FIXME for AIX #undef LLDB_ENABLE_LIBXML2 #endif diff --git a/lldb/include/lldb/Host/common/GetOptInc.h b/lldb/include/lldb/Host/common/GetOptInc.h index ebb475bfaf6b8..652e6174ff8b6 100644 --- a/lldb/include/lldb/Host/common/GetOptInc.h +++ b/lldb/include/lldb/Host/common/GetOptInc.h @@ -11,11 +11,11 @@ #include "lldb/lldb-defines.h" -#if defined(_MSC_VER) || defined(__AIX__) +#if defined(_MSC_VER) || defined(_AIX) #define REPLACE_GETOPT #define REPLACE_GETOPT_LONG #endif -#if defined(_MSC_VER) || defined(__NetBSD__) || defined(__AIX__) +#if defined(_MSC_VER) || defined(__NetBSD__) || defined(_AIX) #define REPLACE_GETOPT_LONG_ONLY #endif diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index 4a47ffd8d779d..d1527d316d678 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -65,7 +65,7 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/VersionTuple.h" -#if defined(__AIX__) +#if defined(_AIX) struct ld_xinfo; #endif @@ -1884,7 +1884,7 @@ class Process : public std::enable_shared_from_this, Status GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &range_info); -#if defined(__AIX__) +#if defined(_AIX) Status GetLDXINFO(struct ld_xinfo *info_ptr); #endif @@ -2823,7 +2823,7 @@ void PruneThreadPlans(); "Process::DoGetMemoryRegionInfo() not supported"); } -#if defined(__AIX__) +#if defined(_AIX) virtual Status DoGetLDXINFO(struct ld_xinfo *info_ptr) { return Status("Process::DoGetLDXINFO() not supported"); } diff --git a/lldb/include/lldb/Target/RegisterContextUnwind.h b/lldb/include/lldb/Target/RegisterContextUnwind.h index 46c06cb422caf..b6176f8e5727f 100644 --- a/lldb/include/lldb/Target/RegisterContextUnwind.h +++ b/lldb/include/lldb/Target/RegisterContextUnwind.h @@ -67,7 +67,7 @@ class RegisterContextUnwind : public lldb_private::RegisterContext { bool ReadPC(lldb::addr_t &start_pc); -#ifdef __AIX__ +#ifdef _AIX bool ReadLR(lldb::addr_t &lr); #endif diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp index 43c5b043ef7a2..8f2e3562f6577 100644 --- a/lldb/source/Core/Mangled.cpp +++ b/lldb/source/Core/Mangled.cpp @@ -167,7 +167,7 @@ static char *GetItaniumDemangledStr(const char *M) { "Expected demangled_size to return length including trailing null"); } -#if !defined(__AIX__) +#if !defined(_AIX) if (Log *log = GetLog(LLDBLog::Demangle)) { if (demangled_cstr) LLDB_LOGF(log, "demangled itanium: %s -> \"%s\"", M, demangled_cstr); diff --git a/lldb/source/Core/Section.cpp b/lldb/source/Core/Section.cpp index 9ed55853930a6..e0a9f7fcc7135 100644 --- a/lldb/source/Core/Section.cpp +++ b/lldb/source/Core/Section.cpp @@ -263,7 +263,7 @@ bool Section::ResolveContainedAddress(addr_t offset, Address &so_addr, bool Section::ContainsFileAddress(addr_t vm_addr) const { const addr_t file_addr = GetFileAddress(); -#ifdef __AIX__ +#ifdef _AIX if (file_addr == 0) return false; #endif diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 94b1d0fd57d07..dc48cb87b5ce6 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -358,7 +358,7 @@ bool Host::ResolveExecutableInBundle(FileSpec &file) { return false; } #ifndef _WIN32 -#if defined(__AIX__) +#if defined(_AIX) #include extern char **p_xargv; @@ -525,7 +525,7 @@ static int dladdr(const void *ptr, Dl_info *dl) FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSpec module_filespec; #if !defined(__ANDROID__) -#ifdef __AIX__ +#ifdef _AIX if (host_addr == reinterpret_cast(HostInfoBase::ComputeSharedLibraryDirectory)) { // FIXME: AIX dladdr return "lldb" for this case if (p_xargv[0]) { diff --git a/lldb/source/Host/common/XML.cpp b/lldb/source/Host/common/XML.cpp index 62cac78aaac23..fbc409105fe60 100644 --- a/lldb/source/Host/common/XML.cpp +++ b/lldb/source/Host/common/XML.cpp @@ -10,7 +10,7 @@ #include "lldb/Host/XML.h" #include "llvm/ADT/StringExtras.h" -#if defined(__AIX__) +#if defined(_AIX) #undef LLDB_ENABLE_LIBXML2 #endif diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index bd204c812b7e3..09c3fd2af6d3e 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -722,7 +722,7 @@ ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, ConnectionStatus ConnectionFileDescriptor::ConnectFile( llvm::StringRef s, socket_id_callback_type socket_id_callback, Status *error_ptr) { -#if !defined(__AIX__) +#if !defined(_AIX) #if LLDB_ENABLE_POSIX std::string addr_str = s.str(); // file:///PATH diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index 866fd8ac96c7b..21da5612ff6b8 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,7 +11,7 @@ // C includes #include #include -#if !defined(__AIX__) +#if !defined(_AIX) #include #endif #include diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp index d1eba52791a78..015570236b9d3 100644 --- a/lldb/source/Host/posix/MainLoopPosix.cpp +++ b/lldb/source/Host/posix/MainLoopPosix.cpp @@ -179,7 +179,7 @@ Status MainLoopPosix::RunImpl::Poll() { read_fds.push_back(pfd); } -#if defined(__AIX__) +#if defined(_AIX) sigset_t origmask; int timeout; @@ -325,7 +325,7 @@ MainLoopPosix::RegisterSignal(int signo, const Callback &callback, // If we're using kqueue, the signal needs to be unblocked in order to // receive it. If using pselect/ppoll, we need to block it, and later unblock // it as a part of the system call. -#if defined(__AIX__) +#if defined(_AIX) //FIXME: where is signal unblocked? ret = pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, &old_set); #else diff --git a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp index b8a96fbd19f02..f9f99decd39c2 100644 --- a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp +++ b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp @@ -193,7 +193,7 @@ struct ForkLaunchInfo { } // Start tracing this child that is about to exec. -#if !defined(__AIX__) +#if !defined(_AIX) if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1) ExitWithError(error_fd, "ptrace"); #else diff --git a/lldb/source/Initialization/SystemInitializerCommon.cpp b/lldb/source/Initialization/SystemInitializerCommon.cpp index 4b01442a94bac..2e2d622d9981c 100644 --- a/lldb/source/Initialization/SystemInitializerCommon.cpp +++ b/lldb/source/Initialization/SystemInitializerCommon.cpp @@ -19,7 +19,7 @@ #include "lldb/Version/Version.h" #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__OpenBSD__) || defined(__AIX__) + defined(__OpenBSD__) || defined(_AIX) #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" #endif @@ -79,7 +79,7 @@ llvm::Error SystemInitializerCommon::Initialize() { process_gdb_remote::ProcessGDBRemoteLog::Initialize(); #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__OpenBSD__) || defined(__AIX__) + defined(__OpenBSD__) || defined(_AIX) ProcessPOSIXLog::Initialize(); #endif #if defined(_WIN32) diff --git a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp index 88a82f4a0d20c..a3abb15ee625b 100644 --- a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp +++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp @@ -156,7 +156,7 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) return false; -#if defined(__AIX__) +#if defined(_AIX) assert(0); #else // Read TOC pointer value. @@ -279,7 +279,7 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) return false; -#if defined(__AIX__) +#if defined(_AIX) LLDB_LOGF(log, "Writing R2: 0x%" PRIx64, (uint64_t)toc_addr); if (!reg_ctx->WriteRegisterFromUnsigned(r2_reg_info, toc_addr)) return false; diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 62663974134b0..7f3a638d5b028 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -18,7 +18,7 @@ #include "lldb/Target/ThreadPlanStepInstruction.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -160,7 +160,7 @@ void DynamicLoaderAIXDYLD::DidAttach() { auto error = m_process->LoadModules(); LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}"); -#if defined(__AIX__) +#if defined(_AIX) // Get struct ld_xinfo (FIXME) struct ld_xinfo ldinfo[64]; Status status = m_process->GetLDXINFO(&(ldinfo[0])); @@ -221,7 +221,7 @@ void DynamicLoaderAIXDYLD::DidLaunch() { LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}"); } -#if defined(__AIX__) +#if defined(_AIX) // Get struct ld_xinfo (FIXME) struct ld_xinfo ldinfo[64]; Status status = m_process->GetLDXINFO(&(ldinfo[0])); diff --git a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h index 1576c9700e557..d98b2880ca3b4 100644 --- a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h +++ b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h @@ -39,7 +39,7 @@ class EmulateInstructionPPC64 : public EmulateInstruction { return true; case eInstructionTypePCModifying: -#if defined(__AIX__) +#if defined(_AIX) return true; #else return false; diff --git a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp index 690fb0d60a09a..9a52fb2f2adc5 100644 --- a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp +++ b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp @@ -194,7 +194,7 @@ void JITLoaderGDB::SetJITBreakpoint(lldb_private::ModuleList &module_list) { if (jit_addr == LLDB_INVALID_ADDRESS) return; -#if defined(__AIX__) +#if defined(_AIX) return; #endif diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index fb5bc2c58e6fb..71f2b127afb12 100644 --- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -1227,7 +1227,7 @@ bool lldb_private::formatters::ObjCSELSummaryProvider( time_t lldb_private::formatters::GetOSXEpoch() { static time_t epoch = 0; if (!epoch) { -#if !defined(__AIX__) +#if !defined(_AIX) #ifndef _WIN32 tzset(); tm tm_epoch; diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 5ea55772c3aba..4f747ab20c9ef 100644 --- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -8,7 +8,7 @@ #include "ObjectContainerBSDArchive.h" -#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__) +#if defined(_WIN32) || defined(__ANDROID__) || defined(_AIX) // Defines from ar, missing on Windows #define SARMAG 8 #define ARFMAG "`\n" diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp index 050ad73f1d19a..38756a0dd2969 100644 --- a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp @@ -8,7 +8,7 @@ #include "ObjectContainerBigArchive.h" -#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__) +#if defined(_WIN32) || defined(__ANDROID__) || defined(_AIX) // Defines from ar, missing on Windows #define ARMAG "!\n" #define SARMAG 8 diff --git a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp index d8834af2c33ef..9aab76c6c48ba 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp +++ b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp @@ -51,7 +51,7 @@ size_t ObjectFileMinidump::GetModuleSpecifications( const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, lldb_private::ModuleSpecList &specs) { -#if !defined(__AIX__) +#if !defined(_AIX) specs.Clear(); #endif return 0; diff --git a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp index 75cc54e4f0d48..d76d6adb1be2c 100644 --- a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp +++ b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp @@ -117,7 +117,7 @@ size_t ObjectFilePDB::GetModuleSpecifications( llvm::BumpPtrAllocator allocator; std::unique_ptr pdb_file = loadPDBFile(file.GetPath(), allocator); if (!pdb_file){ -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; @@ -127,7 +127,7 @@ size_t ObjectFilePDB::GetModuleSpecifications( auto info_stream = pdb_file->getPDBInfoStream(); if (!info_stream) { llvm::consumeError(info_stream.takeError()); -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; @@ -136,7 +136,7 @@ size_t ObjectFilePDB::GetModuleSpecifications( auto dbi_stream = pdb_file->getPDBDbiStream(); if (!dbi_stream) { llvm::consumeError(dbi_stream.takeError()); -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index 519ce2ca4a0b2..02a86234bd363 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -254,7 +254,7 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( lldb::offset_t length, lldb_private::ModuleSpecList &specs) { const size_t initial_count = specs.GetSize(); if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp)){ -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; @@ -272,7 +272,7 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( if (!binary) { LLDB_LOG_ERROR(log, binary.takeError(), "Failed to create binary for file ({1}): {0}", file); -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; @@ -281,7 +281,7 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( auto *COFFObj = llvm::dyn_cast(binary->get()); if (!COFFObj){ -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp index b6b08b73bec41..5c94477002978 100644 --- a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp +++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp @@ -31,7 +31,7 @@ // Define these constants from AIX mman.h for use when targeting remote aix // systems even when host has different values. -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -80,7 +80,7 @@ void PlatformAIX::Initialize() { PlatformPOSIX::Initialize(); if (g_initialize_count++ == 0) { -#if defined(__AIX__) +#if defined(_AIX) PlatformSP default_platform_sp(new PlatformAIX(true)); default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); Platform::SetHostPlatform(default_platform_sp); @@ -294,7 +294,7 @@ MmapArgList PlatformAIX::GetMmapArgumentList(const ArchSpec &arch, addr_t addr, addr_t length, unsigned prot, unsigned flags, addr_t fd, addr_t offset) { -#if defined(__AIX__) +#if defined(_AIX) unsigned flags_platform = MAP_VARIABLE | MAP_PRIVATE | MAP_ANONYMOUS; #else unsigned flags_platform = 0; diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index db271357d792a..ea758caa653a1 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -46,7 +46,7 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, function_options.include_inlines = false; SymbolContextList sc_list; -#if !defined(__AIX__) +#if !defined(_AIX) process->GetTarget().GetImages().FindFunctions( ConstString("mmap"), eFunctionNameTypeFull, function_options, sc_list); #else @@ -122,7 +122,7 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, MmapArgList args = process->GetTarget().GetPlatform()->GetMmapArgumentList( arch, addr, length, prot_arg, flags, fd, offset); -#if defined(__AIX__) +#if defined(_AIX) lldb::ThreadPlanSP call_plan_sp( new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(), toc_range.GetBaseAddress(), diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 443b7c7b2c7fb..fa0a3b5d4dc38 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -41,7 +41,7 @@ #include "llvm/Config/llvm-config.h" // for LLVM_ENABLE_ZLIB #include "llvm/Support/JSON.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -1715,7 +1715,7 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( return error; } -#if defined(__AIX__) +#if defined(_AIX) Status GDBRemoteCommunicationClient::GetLDXINFO(struct ld_xinfo *info_ptr) { Status error; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 520f37ac56716..1812fc9b7ca65 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -32,7 +32,7 @@ #include "llvm/Support/VersionTuple.h" -#if defined(__AIX__) +#if defined(_AIX) struct ld_xinfo; #endif @@ -200,7 +200,7 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase { Status GetMemoryRegionInfo(lldb::addr_t addr, MemoryRegionInfo &range_info); std::optional GetWatchpointSlotCount(); -#if defined(__AIX__) +#if defined(_AIX) Status GetLDXINFO(struct ld_xinfo *info_ptr); #endif diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 4f1ef0898ba08..27be61a474238 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -48,7 +48,7 @@ #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "lldb/Utility/StringExtractorGDBRemote.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -3011,7 +3011,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qLDXINFO(StringExtractorGDBRemote &pack return SendErrorResponse(0xff); } -#if defined(__AIX__) +#if defined(_AIX) // FIXME: buffer size struct ld_xinfo info[64]; if (ptrace64(PT_LDXINFO, m_current_process->GetID(), (long long)&(info[0]), sizeof(info), nullptr) != 0) { diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index ca381290d0e9f..5b7ce5f1424d9 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -92,7 +92,7 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/raw_ostream.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -2963,7 +2963,7 @@ Status ProcessGDBRemote::DoGetMemoryRegionInfo(addr_t load_addr, return error; } -#if defined(__AIX__) +#if defined(_AIX) Status ProcessGDBRemote::DoGetLDXINFO(struct ld_xinfo *info_ptr) { Status error(m_gdb_comm.GetLDXINFO(info_ptr)); return error; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 82200fbea21cd..2bf3a04d213d4 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -37,7 +37,7 @@ #include "GDBRemoteCommunicationClient.h" #include "GDBRemoteRegisterContext.h" -#if defined(__AIX__) +#if defined(_AIX) struct ld_xinfo; #endif @@ -427,7 +427,7 @@ class ProcessGDBRemote : public Process, Status DoGetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo ®ion_info) override; -#if defined(__AIX__) +#if defined(_AIX) Status DoGetLDXINFO(struct ld_xinfo *info_ptr) override; #endif diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index a9aef7ef21855..e6ae7fc559ef4 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -75,7 +75,7 @@ #include "lldb/Utility/State.h" #include "lldb/Utility/Timer.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -6188,7 +6188,7 @@ Status Process::GetMemoryRegionInfo(lldb::addr_t load_addr, return DoGetMemoryRegionInfo(load_addr, range_info); } -#if defined(__AIX__) +#if defined(_AIX) Status Process::GetLDXINFO(struct ld_xinfo *info_ptr) { return DoGetLDXINFO(info_ptr); } diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index fbdbc8c63a5d0..fdf269a3d3653 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -40,7 +40,7 @@ #include #include -#ifdef __AIX__ +#ifdef _AIX #include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" #endif @@ -1260,7 +1260,7 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( // Answer the question: Where did THIS frame save the CALLER frame ("previous" // frame)'s register value? -#ifdef __AIX__ +#ifdef _AIX extern bool UGLY_HACK_NULL_TOPFRAME; #endif @@ -1525,7 +1525,7 @@ RegisterContextUnwind::SavedLocationForRegister( new_regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterInLiveRegisterContext; new_regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); -#ifdef __AIX__ +#ifdef _AIX if (UGLY_HACK_NULL_TOPFRAME && new_regloc.location.register_number == 0x20) { new_regloc.location.register_number = 0x24; } @@ -2390,7 +2390,7 @@ bool RegisterContextUnwind::ReadPC(addr_t &pc) { } } -#ifdef __AIX__ +#ifdef _AIX bool RegisterContextUnwind::ReadLR(addr_t &lr) { if (!IsValid()) return false; diff --git a/lldb/source/Target/UnwindLLDB.cpp b/lldb/source/Target/UnwindLLDB.cpp index 8edf359cac497..764bea5bf86c6 100644 --- a/lldb/source/Target/UnwindLLDB.cpp +++ b/lldb/source/Target/UnwindLLDB.cpp @@ -68,7 +68,7 @@ uint32_t UnwindLLDB::DoGetFrameCount() { return m_frames.size(); } -#ifdef __AIX__ +#ifdef _AIX bool UGLY_HACK_NULL_TOPFRAME = false; #endif @@ -95,7 +95,7 @@ bool UnwindLLDB::AddFirstFrame() { if (!reg_ctx_sp->ReadPC(first_cursor_sp->start_pc)) goto unwind_done; -#ifdef __AIX__ +#ifdef _AIX lldb::addr_t lr; if (!reg_ctx_sp->ReadLR(lr)) goto unwind_done; diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp index 45837503e8b73..d17ed77485d31 100644 --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -640,7 +640,7 @@ void sigwinch_handler(int signo) { } void sigint_handler(int signo) { -#if defined(_WIN32) || defined(__AIX__) // Restore handler as it is not persistent on Windows +#if defined(_WIN32) || defined(_AIX) // Restore handler as it is not persistent on Windows signal(SIGINT, sigint_handler); #endif static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT; @@ -729,7 +729,7 @@ static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) { int main(int argc, char const *argv[]) { // Editline uses for example iswprint which is dependent on LC_CTYPE. // FIXME: this caused unexpected SIGTRAP on AIX -#ifndef __AIX__ +#ifndef _AIX std::setlocale(LC_ALL, ""); std::setlocale(LC_CTYPE, ""); #endif diff --git a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp index 91bb2083a88b5..52c2eae0c9033 100644 --- a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp +++ b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp @@ -14,7 +14,7 @@ using HostObjectFile = ObjectFileMachO; #elif defined(_WIN32) #include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" using HostObjectFile = ObjectFilePECOFF; -#elif defined(__AIX__) +#elif defined(_AIX) #include "Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h" using HostObjectFile = ObjectFileXCOFF; #else @@ -49,7 +49,7 @@ using HostObjectFile = ObjectFileELF; #include "Plugins/Instruction/MIPS/EmulateInstructionMIPS.h" #endif -#if defined(__AIX__) +#if defined(_AIX) #include "Plugins/Instruction/PPC64/EmulateInstructionPPC64.h" #endif @@ -82,7 +82,7 @@ llvm::Error SystemInitializerLLGS::Initialize() { EmulateInstructionRISCV::Initialize(); #endif -#if defined(__AIX__) +#if defined(_AIX) EmulateInstructionPPC64::Initialize(); #endif @@ -108,7 +108,7 @@ void SystemInitializerLLGS::Terminate() { EmulateInstructionRISCV::Terminate(); #endif -#if defined(__AIX__) +#if defined(_AIX) EmulateInstructionPPC64::Terminate(); #endif diff --git a/lldb/tools/lldb-server/lldb-gdbserver.cpp b/lldb/tools/lldb-server/lldb-gdbserver.cpp index 844a6370bdb2e..dcbb421a73e25 100644 --- a/lldb/tools/lldb-server/lldb-gdbserver.cpp +++ b/lldb/tools/lldb-server/lldb-gdbserver.cpp @@ -45,7 +45,7 @@ #include "Plugins/Process/NetBSD/NativeProcessNetBSD.h" #elif defined(_WIN32) #include "Plugins/Process/Windows/Common/NativeProcessWindows.h" -#elif defined(__AIX__) +#elif defined(_AIX) #include "Plugins/Process/AIX/NativeProcessAIX.h" #endif @@ -72,7 +72,7 @@ typedef process_freebsd::NativeProcessFreeBSD::Manager NativeProcessManager; typedef process_netbsd::NativeProcessNetBSD::Manager NativeProcessManager; #elif defined(_WIN32) typedef NativeProcessWindows::Manager NativeProcessManager; -#elif defined(__AIX__) +#elif defined(_AIX) typedef process_aix::NativeProcessAIX::Manager NativeProcessManager; #else // Dummy implementation to make sure the code compiles diff --git a/lldb/unittests/Host/MainLoopTest.cpp b/lldb/unittests/Host/MainLoopTest.cpp index c76476c947054..5c042261b9ef2 100644 --- a/lldb/unittests/Host/MainLoopTest.cpp +++ b/lldb/unittests/Host/MainLoopTest.cpp @@ -223,7 +223,7 @@ TEST_F(MainLoopTest, PendingCallbackAfterLoopExited) { loop.AddPendingCallback([&](MainLoopBase &loop) {}); } -#if defined(LLVM_ON_UNIX) && !defined(__AIX__) +#if defined(LLVM_ON_UNIX) && !defined(_AIX) TEST_F(MainLoopTest, DetectsEOF) { PseudoTerminal term; diff --git a/lldb/unittests/Host/PipeTest.cpp b/lldb/unittests/Host/PipeTest.cpp index c1013aa7a7e4e..00ffd33d68f7a 100644 --- a/lldb/unittests/Host/PipeTest.cpp +++ b/lldb/unittests/Host/PipeTest.cpp @@ -55,7 +55,7 @@ TEST_F(PipeTest, OpenAsReader) { } #endif -#if !defined(__AIX__) +#if !defined(_AIX) TEST_F(PipeTest, WriteWithTimeout) { Pipe pipe; ASSERT_THAT_ERROR(pipe.CreateNew(false).ToError(), llvm::Succeeded()); diff --git a/lldb/unittests/Host/posix/TerminalTest.cpp b/lldb/unittests/Host/posix/TerminalTest.cpp index f3de92c0852b1..64e6be64db80c 100644 --- a/lldb/unittests/Host/posix/TerminalTest.cpp +++ b/lldb/unittests/Host/posix/TerminalTest.cpp @@ -94,14 +94,14 @@ TEST_F(TerminalTest, SetRaw) { TEST_F(TerminalTest, SetBaudRate) { struct termios terminfo; -#if (defined(__AIX__) && defined(B38400)) || !defined(__AIX__) +#if (defined(_AIX) && defined(B38400)) || !defined(_AIX) ASSERT_THAT_ERROR(m_term.SetBaudRate(38400), llvm::Succeeded()); ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0); EXPECT_EQ(cfgetispeed(&terminfo), static_cast(B38400)); EXPECT_EQ(cfgetospeed(&terminfo), static_cast(B38400)); #endif -#if (defined(__AIX__) && defined(B115200)) || !defined(__AIX__) +#if (defined(_AIX) && defined(B115200)) || !defined(_AIX) ASSERT_THAT_ERROR(m_term.SetBaudRate(115200), llvm::Succeeded()); ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0); EXPECT_EQ(cfgetispeed(&terminfo), static_cast(B115200)); >From a8020a6a8692f059679195ae1a0ef5e0eeee94c8 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Thu, 10 Oct 2024 04:52:08 -0500 Subject: [PATCH 11/48] Removed from lldb/CMakeLists --- lldb/CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt index a4fd8bccf056d..59cdc4593463c 100644 --- a/lldb/CMakeLists.txt +++ b/lldb/CMakeLists.txt @@ -38,10 +38,6 @@ endif() include(LLDBConfig) include(AddLLDB) -if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") - add_definitions("-D_AIX") -endif() - # Define the LLDB_CONFIGURATION_xxx matching the build type. if(uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" ) add_definitions(-DLLDB_CONFIGURATION_DEBUG) >From 7609ad339bfab48412221be54edc2d2d146279c3 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Thu, 14 Nov 2024 13:23:59 -0600 Subject: [PATCH 12/48] Patch for the Merge conflict of xcoff first merge with llvm --- .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 253 +++++++++++++++++- 1 file changed, 252 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index 395a126a01fce..a4d9ea295b4c3 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -188,7 +188,258 @@ bool ObjectFileXCOFF::ParseHeader() { if (module_sp) { std::lock_guard guard(module_sp->GetMutex()); m_sect_headers.clear(); - lldb::offs + lldb::offset_t offset = 0; + + if (ParseXCOFFHeader(m_data, &offset, m_xcoff_header)) { + m_data.SetAddressByteSize(GetAddressByteSize()); + if (m_xcoff_header.auxhdrsize > 0) + ParseXCOFFOptionalHeader(m_data, &offset); + ParseSectionHeaders(offset); + } + return true; + } + + return false; +} + +bool ObjectFileXCOFF::ParseXCOFFHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + xcoff_header_t &xcoff_header) { + //FIXME: data.ValidOffsetForDataOfSize + xcoff_header.magic = data.GetU16(offset_ptr); + xcoff_header.nsects = data.GetU16(offset_ptr); + xcoff_header.modtime = data.GetU32(offset_ptr); + xcoff_header.symoff = data.GetU64(offset_ptr); + xcoff_header.auxhdrsize = data.GetU16(offset_ptr); + xcoff_header.flags = data.GetU16(offset_ptr); + xcoff_header.nsyms = data.GetU32(offset_ptr); + return true; +} + +bool ObjectFileXCOFF::ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr) { + lldb::offset_t init_offset = *offset_ptr; + //FIXME: data.ValidOffsetForDataOfSize + m_xcoff_aux_header.AuxMagic = data.GetU16(offset_ptr); + m_xcoff_aux_header.Version = data.GetU16(offset_ptr); + m_xcoff_aux_header.ReservedForDebugger = data.GetU32(offset_ptr); + m_xcoff_aux_header.TextStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.DataStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.TOCAnchorAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfEntryPoint = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTOC = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfLoader = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.ModuleType = data.GetU16(offset_ptr); + m_xcoff_aux_header.CpuFlag = data.GetU8(offset_ptr); + m_xcoff_aux_header.CpuType = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.DataPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.StackPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.FlagAndTDataAlignment = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.InitDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.BssDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.EntryPointAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxStackSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfTData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.XCOFF64Flag = data.GetU16(offset_ptr); + lldb::offset_t last_offset = *offset_ptr; + if ((last_offset - init_offset) < m_xcoff_header.auxhdrsize) + *offset_ptr += (m_xcoff_header.auxhdrsize - (last_offset - init_offset)); + return true; +} + +bool ObjectFileXCOFF::ParseSectionHeaders( + uint32_t section_header_data_offset) { + const uint32_t nsects = m_xcoff_header.nsects; + m_sect_headers.clear(); + + if (nsects > 0) { + const size_t section_header_byte_size = nsects * m_binary->getSectionHeaderSize(); + lldb_private::DataExtractor section_header_data = + ReadImageData(section_header_data_offset, section_header_byte_size); + + lldb::offset_t offset = 0; + //FIXME: section_header_data.ValidOffsetForDataOfSize + m_sect_headers.resize(nsects); + + for (uint32_t idx = 0; idx < nsects; ++idx) { + const void *name_data = section_header_data.GetData(&offset, 8); + if (name_data) { + memcpy(m_sect_headers[idx].name, name_data, 8); + m_sect_headers[idx].phyaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].vmaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].size = section_header_data.GetU64(&offset); + m_sect_headers[idx].offset = section_header_data.GetU64(&offset); + m_sect_headers[idx].reloff = section_header_data.GetU64(&offset); + m_sect_headers[idx].lineoff = section_header_data.GetU64(&offset); + m_sect_headers[idx].nreloc = section_header_data.GetU32(&offset); + m_sect_headers[idx].nline = section_header_data.GetU32(&offset); + m_sect_headers[idx].flags = section_header_data.GetU32(&offset); + offset += 4; + } else { + offset += (m_binary->getSectionHeaderSize() - 8); + } + } + } + + return !m_sect_headers.empty(); +} + +lldb_private::DataExtractor ObjectFileXCOFF::ReadImageData(uint32_t offset, size_t size) { + if (!size) + return {}; + + if (m_data.ValidOffsetForDataOfSize(offset, size)) + return lldb_private::DataExtractor(m_data, offset, size); + + assert(0); + ProcessSP process_sp(m_process_wp.lock()); + lldb_private::DataExtractor data; + if (process_sp) { + auto data_up = std::make_unique(size, 0); + Status readmem_error; + size_t bytes_read = + process_sp->ReadMemory(offset, data_up->GetBytes(), + data_up->GetByteSize(), readmem_error); + if (bytes_read == size) { + DataBufferSP buffer_sp(data_up.release()); + data.SetData(buffer_sp, 0, buffer_sp->GetByteSize()); + } + } + return data; +} + +bool ObjectFileXCOFF::SetLoadAddress(Target &target, lldb::addr_t value, + bool value_is_offset) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (section_sp && !section_sp->IsThreadSpecific()) { + bool use_offset = false; + if (strcmp(section_sp->GetName().AsCString(), ".text") == 0 || + strcmp(section_sp->GetName().AsCString(), ".data") == 0 || + strcmp(section_sp->GetName().AsCString(), ".bss") == 0) + use_offset = true; + + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, (use_offset ? + (section_sp->GetFileOffset() + value) : (section_sp->GetFileAddress() + value)))) + ++num_loaded_sections; + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (type_id == 1 && section_sp && strcmp(section_sp->GetName().AsCString(), ".text") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileOffset() + value)) + ++num_loaded_sections; + } + } else if (type_id == 2 && section_sp && strcmp(section_sp->GetName().AsCString(), ".data") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileAddress() + value)) + ++num_loaded_sections; + } + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +ByteOrder ObjectFileXCOFF::GetByteOrder() const { + return eByteOrderBig; +} + +bool ObjectFileXCOFF::IsExecutable() const { + return true; +} + +uint32_t ObjectFileXCOFF::GetAddressByteSize() const { + if (m_xcoff_header.magic == XCOFF::XCOFF64) + return 8; + else if (m_xcoff_header.magic == XCOFF::XCOFF32) + return 4; + return 4; +} + +AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) { + return AddressClass::eUnknown; +} + +lldb::SymbolType ObjectFileXCOFF::MapSymbolType(llvm::object::SymbolRef::Type sym_type) { + if (sym_type == llvm::object::SymbolRef::ST_Function) + return lldb::eSymbolTypeCode; + else if (sym_type == llvm::object::SymbolRef::ST_Data) + return lldb::eSymbolTypeData; + return lldb::eSymbolTypeInvalid; +} + +void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) { + SectionList *sect_list = GetSectionList(); + const uint32_t num_syms = m_xcoff_header.nsyms; + uint32_t sidx = 0; + if (num_syms > 0 && m_xcoff_header.symoff > 0) { + const uint32_t symbol_size = XCOFF::SymbolTableEntrySize; + const size_t symbol_data_size = num_syms * symbol_size; + lldb_private::DataExtractor symtab_data = + ReadImageData(m_xcoff_header.symoff, symbol_data_size); + + lldb::offset_t offset = 0; + std::string symbol_name; + Symbol *symbols = lldb_symtab.Resize(num_syms); + llvm::object::symbol_iterator SI = m_binary->symbol_begin(); + for (uint32_t i = 0; i < num_syms; ++i, ++SI) { + xcoff_symbol_t symbol; + const uint32_t symbol_offset = offset; + symbol.value = symtab_data.GetU64(&offset); + symbol.offset = symtab_data.GetU32(&offset); + Expected symbol_name_or_err = m_binary->getStringTableEntry(symbol.offset); + if (!symbol_name_or_err) { + consumeError(symbol_name_or_err.takeError()); + return; + } + StringRef symbol_name_str = symbol_name_or_err.get(); + symbol_name.assign(symbol_name_str.data()); symbol.sect = symtab_data.GetU16(&offset); symbol.type = symtab_data.GetU16(&offset); symbol.storage = symtab_data.GetU8(&offset); >From dd56fce276b60b40e1997292b3f554a20157661a Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 17 Nov 2024 00:15:01 -0600 Subject: [PATCH 13/48] Attach fix for AIX --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 130 ++++++++++++++++++ .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 5 +- 2 files changed, 134 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 7f3a638d5b028..acaa6a72edded 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -18,8 +18,13 @@ #include "lldb/Target/ThreadPlanStepInstruction.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" +#include "llvm/Support/FileSystem.h" #if defined(_AIX) #include +#include +#include +#include +#include #endif /*#include "llvm/ADT/Triple.h" @@ -131,14 +136,139 @@ bool DynamicLoaderAIXDYLD::NotifyBreakpointHit( lldb::user_id_t break_loc_id) { } + +void DynamicLoaderAIXDYLD::ResolveExecutableModule( + lldb::ModuleSP &module_sp) { + Log *log = GetLog(LLDBLog::DynamicLoader); + + if (m_process == nullptr) + return; + + auto &target = m_process->GetTarget(); + const auto platform_sp = target.GetPlatform(); + + ProcessInstanceInfo process_info; + if (!m_process->GetProcessInfo(process_info)) { + LLDB_LOGF(log, + "DynamicLoaderPOSIXDYLD::%s - failed to get process info for " + "pid %" PRIu64, + __FUNCTION__, m_process->GetID()); + return; + } + + char procinfo_path[64], exe_path[PATH_MAX], arg_buffer[8192]; + struct procsinfo64 procs_info; + int32long64_t pid = m_process->GetID(); + std::string proc_file = "/proc/" + std::to_string(pid) + "/psinfo"; + std::string cwd_link = "/proc/" + std::to_string(pid) + "/cwd"; + psinfo_t psinfo; + std::ifstream file(proc_file, std::ios::binary); + if(!file.is_open()) + { + LLDB_LOGF(log, "Error psinfo "); + } + file.read(reinterpret_cast(&psinfo), sizeof(psinfo_t)); + if(!file) + LLDB_LOGF(log, "Error psinfo: Failed to read "); + + std::string relative_path(psinfo.pr_fname); + LLDB_LOGF(log, "relative path %s",relative_path.c_str()); + + char cwd[PATH_MAX]; + char resolved_path[PATH_MAX]; + std::string executable_name; + bool found = 0; + if(readlink(cwd_link.c_str(), cwd, sizeof(cwd)) != -1){ + std::filesystem::path full_path = std::filesystem::path(cwd)/relative_path; + if(realpath(full_path.c_str(), resolved_path)) { + LLDB_LOGF(log, " RESOLVED PATH: %s", resolved_path); + found = 1; + } + else + perror("realpath error");} + + executable_name = resolved_path; + if(found == 0) { + std::string command_line(psinfo.pr_psargs); + LLDB_LOGF(log, "command line %s",command_line.c_str()); + if (!command_line.empty()) { + size_t space1 = command_line.find(' '); + executable_name = command_line.substr(0, space1); + LLDB_LOGF(log, "executable name %s",executable_name.c_str()); + } + } + + LLDB_LOGF(log, "executable name %s",executable_name.c_str()); + /*target.SetExecutableModule(target.GetOrCreateModule(lldb_private::FileSpec(resolved_path), + true),true);*/ + process_info.SetExecutableFile(lldb_private::FileSpec(executable_name), + true); + +/* snprintf(procinfo_path, sizeof(procinfo_path), "/proc/%d/object/a.out", pid); + ssize_t len = readlink(procinfo_path, exe_path, sizeof(exe_path) - 1); + exe_path[len] = '\0'; + int num_procs = getprocs64(&procs_info, sizeof(struct procsinfo64), NULL, 0, + &pid, + 1); + int result = getargs(pid, arg_buffer, sizeof(arg_buffer)); + std::vector args; + char *arg_start = arg_buffer; + while(*arg_start != '\0') { + args.emplace_back(arg_start); + arg_start += strlen(arg_start) + 1; + } + + LLDB_LOGF( + log, "1. DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s" + ", pid: %d, current_path: %s", + __FUNCTION__, m_process->GetID(), + args[0], pid, current_path.c_str()); + LLDB_LOGF( + log, "1. DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s" + "num_procs: %d, pid: %d", + __FUNCTION__, m_process->GetID(), + std::string(procs_info.pi_comm).c_str(), num_procs, pid); + if(num_procs <= 0) + perror("getprocs64 failed"); */ + + LLDB_LOGF( + log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s", + __FUNCTION__, m_process->GetID(), + process_info.GetExecutableFile().GetPath().c_str()); + + ModuleSpec module_spec(process_info.GetExecutableFile(), + process_info.GetArchitecture()); + if (module_sp && module_sp->MatchesModuleSpec(module_spec)) + return; + + const auto executable_search_paths(Target::GetDefaultExecutableSearchPaths()); + auto error = platform_sp->ResolveExecutable( + module_spec, module_sp, + !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr); + if (error.Fail()) { + StreamString stream; + module_spec.Dump(stream); + + LLDB_LOGF(log, + "DynamicLoaderPOSIXDYLD::%s - failed to resolve executable " + "with module spec \"%s\": %s", + __FUNCTION__, stream.GetData(), error.AsCString()); + return; + } + + target.SetExecutableModule(module_sp, eLoadDependentsNo); +} + void DynamicLoaderAIXDYLD::DidAttach() { Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); ModuleSP executable = GetTargetExecutable(); + ResolveExecutableModule(executable); if (!executable.get()) return; + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); // Try to fetch the load address of the file from the process, since there // could be randomization of the load address. diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h index ae4b7aca66dcc..0ffbe688e0069 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -24,7 +24,7 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { static void Initialize(); static void Terminate(); - static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; } + static llvm::StringRef GetPluginNameStatic() { return "aix-dyld"; } static llvm::StringRef GetPluginDescriptionStatic(); static DynamicLoader *CreateInstance(Process *process, bool force); @@ -46,6 +46,9 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { protected: lldb::addr_t GetLoadAddress(lldb::ModuleSP executable); + /// Loads Module from inferior process. + void ResolveExecutableModule(lldb::ModuleSP &module_sp); + private: std::map m_loaded_modules; }; >From 48b8b1b6532181acab0ee1710d5f4ab92903ae78 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 18 Nov 2024 02:56:31 -0600 Subject: [PATCH 14/48] Cleanup --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 65 +++++-------------- 1 file changed, 17 insertions(+), 48 deletions(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index acaa6a72edded..1a98bb9334043 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -156,81 +156,50 @@ void DynamicLoaderAIXDYLD::ResolveExecutableModule( return; } - char procinfo_path[64], exe_path[PATH_MAX], arg_buffer[8192]; - struct procsinfo64 procs_info; int32long64_t pid = m_process->GetID(); + char cwd[PATH_MAX], resolved_path[PATH_MAX]; + std::string executable_name; + bool path_resolved = false; + psinfo_t psinfo; + std::string proc_file = "/proc/" + std::to_string(pid) + "/psinfo"; std::string cwd_link = "/proc/" + std::to_string(pid) + "/cwd"; - psinfo_t psinfo; std::ifstream file(proc_file, std::ios::binary); if(!file.is_open()) - { - LLDB_LOGF(log, "Error psinfo "); - } + LLDB_LOGF(log, "Error: Unable to access process info "); + file.read(reinterpret_cast(&psinfo), sizeof(psinfo_t)); if(!file) - LLDB_LOGF(log, "Error psinfo: Failed to read "); + LLDB_LOGF(log, "Process info error: Failed to read "); std::string relative_path(psinfo.pr_fname); - LLDB_LOGF(log, "relative path %s",relative_path.c_str()); + LLDB_LOGF(log, "Relative path %s",relative_path.c_str()); - char cwd[PATH_MAX]; - char resolved_path[PATH_MAX]; - std::string executable_name; - bool found = 0; if(readlink(cwd_link.c_str(), cwd, sizeof(cwd)) != -1){ std::filesystem::path full_path = std::filesystem::path(cwd)/relative_path; if(realpath(full_path.c_str(), resolved_path)) { - LLDB_LOGF(log, " RESOLVED PATH: %s", resolved_path); - found = 1; + LLDB_LOGF(log, "Resolved Path using process info : %s", resolved_path); + path_resolved = true; } else - perror("realpath error");} + LLDB_LOGF(log, "Realpath error: Unable to resolve. "); + } executable_name = resolved_path; - if(found == 0) { + if(path_resolved == false) { std::string command_line(psinfo.pr_psargs); - LLDB_LOGF(log, "command line %s",command_line.c_str()); + LLDB_LOGF(log, "Command line: %s",command_line.c_str()); if (!command_line.empty()) { size_t space1 = command_line.find(' '); executable_name = command_line.substr(0, space1); - LLDB_LOGF(log, "executable name %s",executable_name.c_str()); + LLDB_LOGF(log, "Resolved path using command line arg %s",executable_name.c_str()); } } - LLDB_LOGF(log, "executable name %s",executable_name.c_str()); - /*target.SetExecutableModule(target.GetOrCreateModule(lldb_private::FileSpec(resolved_path), - true),true);*/ + LLDB_LOGF(log, "Executable Name %s",executable_name.c_str()); process_info.SetExecutableFile(lldb_private::FileSpec(executable_name), true); -/* snprintf(procinfo_path, sizeof(procinfo_path), "/proc/%d/object/a.out", pid); - ssize_t len = readlink(procinfo_path, exe_path, sizeof(exe_path) - 1); - exe_path[len] = '\0'; - int num_procs = getprocs64(&procs_info, sizeof(struct procsinfo64), NULL, 0, - &pid, - 1); - int result = getargs(pid, arg_buffer, sizeof(arg_buffer)); - std::vector args; - char *arg_start = arg_buffer; - while(*arg_start != '\0') { - args.emplace_back(arg_start); - arg_start += strlen(arg_start) + 1; - } - - LLDB_LOGF( - log, "1. DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s" - ", pid: %d, current_path: %s", - __FUNCTION__, m_process->GetID(), - args[0], pid, current_path.c_str()); - LLDB_LOGF( - log, "1. DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s" - "num_procs: %d, pid: %d", - __FUNCTION__, m_process->GetID(), - std::string(procs_info.pi_comm).c_str(), num_procs, pid); - if(num_procs <= 0) - perror("getprocs64 failed"); */ - LLDB_LOGF( log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s", __FUNCTION__, m_process->GetID(), >From d410734184a681b3e95949d3953142995682d7f6 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Tue, 19 Nov 2024 09:44:42 -0600 Subject: [PATCH 15/48] Patch in MainLoopPosix.cpp for runtime issue --- lldb/source/Host/posix/MainLoopPosix.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp index f68268f114075..4c617cdde67ba 100644 --- a/lldb/source/Host/posix/MainLoopPosix.cpp +++ b/lldb/source/Host/posix/MainLoopPosix.cpp @@ -149,7 +149,7 @@ Status MainLoopPosix::RunImpl::Poll() { int timeout; timeout = -1; - pthread_sigmask(SIG_SETMASK, &sigmask, &origmask); + pthread_sigmask(SIG_SETMASK, nullptr, &origmask); int ready = poll(read_fds.data(), read_fds.size(), timeout); pthread_sigmask(SIG_SETMASK, &origmask, nullptr); if (ready == -1 && errno != EINTR) >From 48f39dadbbdb4874fbd9b6350933dc67e8823339 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Thu, 5 Dec 2024 05:13:14 -0600 Subject: [PATCH 16/48] Patch for compilation failure in DomainSocket.cpp, AbstractSocket.cpp and AbstractSocket.h --- lldb/include/lldb/Host/aix/AbstractSocket.h | 2 +- lldb/source/Host/aix/AbstractSocket.cpp | 3 +-- lldb/source/Host/posix/DomainSocket.cpp | 4 ++++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lldb/include/lldb/Host/aix/AbstractSocket.h b/lldb/include/lldb/Host/aix/AbstractSocket.h index 78a567a6b9095..accfd01457a5e 100644 --- a/lldb/include/lldb/Host/aix/AbstractSocket.h +++ b/lldb/include/lldb/Host/aix/AbstractSocket.h @@ -14,7 +14,7 @@ namespace lldb_private { class AbstractSocket : public DomainSocket { public: - AbstractSocket(bool child_processes_inherit); + AbstractSocket(); protected: size_t GetNameOffset() const override; diff --git a/lldb/source/Host/aix/AbstractSocket.cpp b/lldb/source/Host/aix/AbstractSocket.cpp index bfb67d452f7ec..fddf78f54f46d 100644 --- a/lldb/source/Host/aix/AbstractSocket.cpp +++ b/lldb/source/Host/aix/AbstractSocket.cpp @@ -13,8 +13,7 @@ using namespace lldb; using namespace lldb_private; -AbstractSocket::AbstractSocket(bool child_processes_inherit) - : DomainSocket(ProtocolUnixAbstract, child_processes_inherit) {} +AbstractSocket::AbstractSocket() : DomainSocket(ProtocolUnixAbstract) {} size_t AbstractSocket::GetNameOffset() const { return 1; } diff --git a/lldb/source/Host/posix/DomainSocket.cpp b/lldb/source/Host/posix/DomainSocket.cpp index 9a0b385d998bf..6cbffb2d9c4bd 100644 --- a/lldb/source/Host/posix/DomainSocket.cpp +++ b/lldb/source/Host/posix/DomainSocket.cpp @@ -17,6 +17,10 @@ #include #include +#if defined(_AIX) +#include +#endif + using namespace lldb; using namespace lldb_private; >From 97531f7bf6e385f0f51d860c6eea17aeb32f6594 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Thu, 19 Dec 2024 06:38:36 -0600 Subject: [PATCH 17/48] Patch for merge conflict in ObjectFileXCOFF.cpp & ObjectFileXCOFF.h --- .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 253 +++++++++++++++++- 1 file changed, 252 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index 395a126a01fce..a4d9ea295b4c3 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -188,7 +188,258 @@ bool ObjectFileXCOFF::ParseHeader() { if (module_sp) { std::lock_guard guard(module_sp->GetMutex()); m_sect_headers.clear(); - lldb::offs + lldb::offset_t offset = 0; + + if (ParseXCOFFHeader(m_data, &offset, m_xcoff_header)) { + m_data.SetAddressByteSize(GetAddressByteSize()); + if (m_xcoff_header.auxhdrsize > 0) + ParseXCOFFOptionalHeader(m_data, &offset); + ParseSectionHeaders(offset); + } + return true; + } + + return false; +} + +bool ObjectFileXCOFF::ParseXCOFFHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + xcoff_header_t &xcoff_header) { + //FIXME: data.ValidOffsetForDataOfSize + xcoff_header.magic = data.GetU16(offset_ptr); + xcoff_header.nsects = data.GetU16(offset_ptr); + xcoff_header.modtime = data.GetU32(offset_ptr); + xcoff_header.symoff = data.GetU64(offset_ptr); + xcoff_header.auxhdrsize = data.GetU16(offset_ptr); + xcoff_header.flags = data.GetU16(offset_ptr); + xcoff_header.nsyms = data.GetU32(offset_ptr); + return true; +} + +bool ObjectFileXCOFF::ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr) { + lldb::offset_t init_offset = *offset_ptr; + //FIXME: data.ValidOffsetForDataOfSize + m_xcoff_aux_header.AuxMagic = data.GetU16(offset_ptr); + m_xcoff_aux_header.Version = data.GetU16(offset_ptr); + m_xcoff_aux_header.ReservedForDebugger = data.GetU32(offset_ptr); + m_xcoff_aux_header.TextStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.DataStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.TOCAnchorAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfEntryPoint = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTOC = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfLoader = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.ModuleType = data.GetU16(offset_ptr); + m_xcoff_aux_header.CpuFlag = data.GetU8(offset_ptr); + m_xcoff_aux_header.CpuType = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.DataPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.StackPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.FlagAndTDataAlignment = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.InitDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.BssDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.EntryPointAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxStackSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfTData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.XCOFF64Flag = data.GetU16(offset_ptr); + lldb::offset_t last_offset = *offset_ptr; + if ((last_offset - init_offset) < m_xcoff_header.auxhdrsize) + *offset_ptr += (m_xcoff_header.auxhdrsize - (last_offset - init_offset)); + return true; +} + +bool ObjectFileXCOFF::ParseSectionHeaders( + uint32_t section_header_data_offset) { + const uint32_t nsects = m_xcoff_header.nsects; + m_sect_headers.clear(); + + if (nsects > 0) { + const size_t section_header_byte_size = nsects * m_binary->getSectionHeaderSize(); + lldb_private::DataExtractor section_header_data = + ReadImageData(section_header_data_offset, section_header_byte_size); + + lldb::offset_t offset = 0; + //FIXME: section_header_data.ValidOffsetForDataOfSize + m_sect_headers.resize(nsects); + + for (uint32_t idx = 0; idx < nsects; ++idx) { + const void *name_data = section_header_data.GetData(&offset, 8); + if (name_data) { + memcpy(m_sect_headers[idx].name, name_data, 8); + m_sect_headers[idx].phyaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].vmaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].size = section_header_data.GetU64(&offset); + m_sect_headers[idx].offset = section_header_data.GetU64(&offset); + m_sect_headers[idx].reloff = section_header_data.GetU64(&offset); + m_sect_headers[idx].lineoff = section_header_data.GetU64(&offset); + m_sect_headers[idx].nreloc = section_header_data.GetU32(&offset); + m_sect_headers[idx].nline = section_header_data.GetU32(&offset); + m_sect_headers[idx].flags = section_header_data.GetU32(&offset); + offset += 4; + } else { + offset += (m_binary->getSectionHeaderSize() - 8); + } + } + } + + return !m_sect_headers.empty(); +} + +lldb_private::DataExtractor ObjectFileXCOFF::ReadImageData(uint32_t offset, size_t size) { + if (!size) + return {}; + + if (m_data.ValidOffsetForDataOfSize(offset, size)) + return lldb_private::DataExtractor(m_data, offset, size); + + assert(0); + ProcessSP process_sp(m_process_wp.lock()); + lldb_private::DataExtractor data; + if (process_sp) { + auto data_up = std::make_unique(size, 0); + Status readmem_error; + size_t bytes_read = + process_sp->ReadMemory(offset, data_up->GetBytes(), + data_up->GetByteSize(), readmem_error); + if (bytes_read == size) { + DataBufferSP buffer_sp(data_up.release()); + data.SetData(buffer_sp, 0, buffer_sp->GetByteSize()); + } + } + return data; +} + +bool ObjectFileXCOFF::SetLoadAddress(Target &target, lldb::addr_t value, + bool value_is_offset) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (section_sp && !section_sp->IsThreadSpecific()) { + bool use_offset = false; + if (strcmp(section_sp->GetName().AsCString(), ".text") == 0 || + strcmp(section_sp->GetName().AsCString(), ".data") == 0 || + strcmp(section_sp->GetName().AsCString(), ".bss") == 0) + use_offset = true; + + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, (use_offset ? + (section_sp->GetFileOffset() + value) : (section_sp->GetFileAddress() + value)))) + ++num_loaded_sections; + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (type_id == 1 && section_sp && strcmp(section_sp->GetName().AsCString(), ".text") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileOffset() + value)) + ++num_loaded_sections; + } + } else if (type_id == 2 && section_sp && strcmp(section_sp->GetName().AsCString(), ".data") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileAddress() + value)) + ++num_loaded_sections; + } + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +ByteOrder ObjectFileXCOFF::GetByteOrder() const { + return eByteOrderBig; +} + +bool ObjectFileXCOFF::IsExecutable() const { + return true; +} + +uint32_t ObjectFileXCOFF::GetAddressByteSize() const { + if (m_xcoff_header.magic == XCOFF::XCOFF64) + return 8; + else if (m_xcoff_header.magic == XCOFF::XCOFF32) + return 4; + return 4; +} + +AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) { + return AddressClass::eUnknown; +} + +lldb::SymbolType ObjectFileXCOFF::MapSymbolType(llvm::object::SymbolRef::Type sym_type) { + if (sym_type == llvm::object::SymbolRef::ST_Function) + return lldb::eSymbolTypeCode; + else if (sym_type == llvm::object::SymbolRef::ST_Data) + return lldb::eSymbolTypeData; + return lldb::eSymbolTypeInvalid; +} + +void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) { + SectionList *sect_list = GetSectionList(); + const uint32_t num_syms = m_xcoff_header.nsyms; + uint32_t sidx = 0; + if (num_syms > 0 && m_xcoff_header.symoff > 0) { + const uint32_t symbol_size = XCOFF::SymbolTableEntrySize; + const size_t symbol_data_size = num_syms * symbol_size; + lldb_private::DataExtractor symtab_data = + ReadImageData(m_xcoff_header.symoff, symbol_data_size); + + lldb::offset_t offset = 0; + std::string symbol_name; + Symbol *symbols = lldb_symtab.Resize(num_syms); + llvm::object::symbol_iterator SI = m_binary->symbol_begin(); + for (uint32_t i = 0; i < num_syms; ++i, ++SI) { + xcoff_symbol_t symbol; + const uint32_t symbol_offset = offset; + symbol.value = symtab_data.GetU64(&offset); + symbol.offset = symtab_data.GetU32(&offset); + Expected symbol_name_or_err = m_binary->getStringTableEntry(symbol.offset); + if (!symbol_name_or_err) { + consumeError(symbol_name_or_err.takeError()); + return; + } + StringRef symbol_name_str = symbol_name_or_err.get(); + symbol_name.assign(symbol_name_str.data()); symbol.sect = symtab_data.GetU16(&offset); symbol.type = symtab_data.GetU16(&offset); symbol.storage = symtab_data.GetU8(&offset); >From 71d2fcff8975831e7f0a657481220749b0a473dc Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Tue, 24 Dec 2024 02:05:35 -0600 Subject: [PATCH 18/48] Added upcoming clang-format and other merge changes --- .../posix/ConnectionFileDescriptorPosix.cpp | 9 ++-- lldb/source/Host/posix/DomainSocket.cpp | 5 ++- lldb/source/Host/posix/FileSystemPosix.cpp | 2 +- lldb/source/Host/posix/MainLoopPosix.cpp | 43 ++++++++----------- .../Host/posix/ProcessLauncherPosixFork.cpp | 2 +- lldb/source/Plugins/Language/ObjC/Cocoa.cpp | 17 +++----- .../BSD-Archive/ObjectContainerBSDArchive.cpp | 29 +++++++------ lldb/source/Utility/ArchSpec.cpp | 1 - 8 files changed, 49 insertions(+), 59 deletions(-) diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index 32d034e60d26c..e3d1300cf76ed 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -119,8 +119,7 @@ bool ConnectionFileDescriptor::IsConnected() const { ConnectionStatus ConnectionFileDescriptor::Connect(llvm::StringRef path, Status *error_ptr) { - return Connect( - path, [](llvm::StringRef) {}, error_ptr); + return Connect(path, [](llvm::StringRef) {}, error_ptr); } ConnectionStatus @@ -716,8 +715,7 @@ ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, ConnectionStatus ConnectionFileDescriptor::ConnectFile( llvm::StringRef s, socket_id_callback_type socket_id_callback, Status *error_ptr) { -#if !defined(_AIX) -#if LLDB_ENABLE_POSIX +#if LLDB_ENABLE_POSIX && !defined(_AIX) std::string addr_str = s.str(); // file:///PATH int fd = FileSystem::Instance().Open(addr_str.c_str(), O_RDWR); @@ -748,8 +746,7 @@ ConnectionStatus ConnectionFileDescriptor::ConnectFile( m_io_sp = std::make_shared(fd, File::eOpenOptionReadWrite, true); return eConnectionStatusSuccess; -#endif // LLDB_ENABLE_POSIX -#endif +#endif // LLDB_ENABLE_POSIX && !defined(_AIX) llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX"); } diff --git a/lldb/source/Host/posix/DomainSocket.cpp b/lldb/source/Host/posix/DomainSocket.cpp index 6cbffb2d9c4bd..28db5964a5a8a 100644 --- a/lldb/source/Host/posix/DomainSocket.cpp +++ b/lldb/source/Host/posix/DomainSocket.cpp @@ -89,8 +89,9 @@ Status DomainSocket::Connect(llvm::StringRef name) { m_socket = CreateSocket(kDomain, kType, 0, error); if (error.Fail()) return error; - if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(), - (struct sockaddr *)&saddr_un, saddr_un_len) < 0) + if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(), + (struct sockaddr *)&saddr_un, + saddr_un_len) < 0) SetLastError(error); return error; diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index 21da5612ff6b8..1a84f550662d7 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,7 +11,7 @@ // C includes #include #include -#if !defined(_AIX) +#ifndef _AIX #include #endif #include diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp index 125b954023dc0..e4ff928a58962 100644 --- a/lldb/source/Host/posix/MainLoopPosix.cpp +++ b/lldb/source/Host/posix/MainLoopPosix.cpp @@ -99,6 +99,7 @@ class MainLoopPosix::RunImpl { ~RunImpl() = default; Status Poll(); + int StartPoll(std::optional point); void ProcessReadEvents(); private: @@ -159,6 +160,22 @@ MainLoopPosix::RunImpl::RunImpl(MainLoopPosix &loop) : loop(loop) { read_fds.reserve(loop.m_read_fds.size()); } +int MainLoopPosix::RunImpl::StartPoll( + std::optional point) { +#if HAVE_PPOLL + return ppoll(read_fds.data(), read_fds.size(), ToTimeSpec(point), + /*sigmask=*/nullptr); +#else + using namespace std::chrono; + int timeout = -1; + if (point) { + nanoseconds dur = std::max(*point - steady_clock::now(), nanoseconds(0)); + timeout = ceil(dur).count(); + } + return poll(read_fds.data(), read_fds.size(), timeout); +#endif +} + Status MainLoopPosix::RunImpl::Poll() { read_fds.clear(); @@ -169,24 +186,10 @@ Status MainLoopPosix::RunImpl::Poll() { pfd.revents = 0; read_fds.push_back(pfd); } + int ready = StartPoll(loop.GetNextWakeupTime()); -#if defined(_AIX) - sigset_t origmask; - int timeout; - - timeout = -1; - pthread_sigmask(SIG_SETMASK, nullptr, &origmask); - int ready = poll(read_fds.data(), read_fds.size(), timeout); - pthread_sigmask(SIG_SETMASK, &origmask, nullptr); if (ready == -1 && errno != EINTR) return Status(errno, eErrorTypePOSIX); -#else - if (ppoll(read_fds.data(), read_fds.size(), - ToTimeSpec(loop.GetNextWakeupTime()), - /*sigmask=*/nullptr) == -1 && - errno != EINTR) - return Status(errno, eErrorTypePOSIX); -#endif return Status(); } @@ -291,16 +294,6 @@ MainLoopPosix::RegisterSignal(int signo, const Callback &callback, UNUSED_IF_ASSERT_DISABLED(ret); assert(ret == 0 && "sigaction failed"); -#if HAVE_SYS_EVENT_H - struct kevent ev; - EV_SET(&ev, signo, EVFILT_SIGNAL, EV_ADD, 0, 0, 0); - ret = kevent(m_kqueue, &ev, 1, nullptr, 0, nullptr); - assert(ret == 0); -#endif - - // If we're using kqueue, the signal needs to be unblocked in order to - // receive it. If using pselect/ppoll, we need to block it, and later unblock - // it as a part of the system call. ret = pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, &old_set); assert(ret == 0 && "pthread_sigmask failed"); info.was_blocked = sigismember(&old_set, signo); diff --git a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp index 52fc58aa21bf4..7b8b42a4b7fe0 100644 --- a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp +++ b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp @@ -197,7 +197,7 @@ struct ForkLaunchInfo { #else if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1) #endif - ExitWithError(error_fd, "ptrace"); + ExitWithError(error_fd, "ptrace"); } // Execute. We should never return... diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index 1d841a032aa6e..1d79edbede5d6 100644 --- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -31,7 +31,6 @@ #include "llvm/ADT/APInt.h" #include "llvm/ADT/bit.h" - using namespace lldb; using namespace lldb_private; using namespace lldb_private::formatters; @@ -267,21 +266,21 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider( if (class_name == "NSIndexSet" || class_name == "NSMutableIndexSet") { // Foundation version 2000 added a bitmask if the index set fit in 64 bits // and a Tagged Pointer version if the bitmask is small enough to fit in - // the tagged pointer payload. + // the tagged pointer payload. // It also changed the layout (but not the size) of the set descriptor. // First check whether this is a tagged pointer. The bitmask will be in // the payload of the tagged pointer. uint64_t payload; - if (runtime->GetFoundationVersion() >= 2000 - && descriptor->GetTaggedPointerInfo(nullptr, nullptr, &payload)) { + if (runtime->GetFoundationVersion() >= 2000 && + descriptor->GetTaggedPointerInfo(nullptr, nullptr, &payload)) { count = llvm::popcount(payload); break; } // The first 32 bits describe the index set in all cases: Status error; uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory( - valobj_addr + ptr_size, 4, 0, error); + valobj_addr + ptr_size, 4, 0, error); if (error.Fail()) return false; // Now check if the index is held in a bitmask in the object: @@ -292,7 +291,7 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider( if ((mode & 2) == 2) { // The bitfield is a 64 bit uint at the beginning of the data var. uint64_t bitfield = process_sp->ReadUnsignedIntegerFromMemory( - valobj_addr + 2 * ptr_size, 8, 0, error); + valobj_addr + 2 * ptr_size, 8, 0, error); if (error.Fail()) return false; count = llvm::popcount(bitfield); @@ -309,7 +308,7 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider( count = 0; break; } - + if ((mode & 2) == 2) mode = 1; // this means the set only has one range else @@ -1227,8 +1226,7 @@ bool lldb_private::formatters::ObjCSELSummaryProvider( time_t lldb_private::formatters::GetOSXEpoch() { static time_t epoch = 0; if (!epoch) { -#if !defined(_AIX) -#ifndef _WIN32 +#if !defined(_WIN32) && !defined(_AIX) tzset(); tm tm_epoch; tm_epoch.tm_sec = 0; @@ -1241,7 +1239,6 @@ time_t lldb_private::formatters::GetOSXEpoch() { tm_epoch.tm_gmtoff = 0; tm_epoch.tm_zone = nullptr; epoch = timegm(&tm_epoch); -#endif #endif } return epoch; diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 4f747ab20c9ef..b202898ff438a 100644 --- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -81,10 +81,10 @@ size_t ObjectContainerBSDArchive::Archive::ParseObjects() { std::unique_ptr mem_buffer = llvm::MemoryBuffer::getMemBuffer( - llvm::StringRef((const char *)data.GetDataStart(), - data.GetByteSize()), - llvm::StringRef(), - /*RequiresNullTerminator=*/false); + llvm::StringRef((const char *)data.GetDataStart(), + data.GetByteSize()), + llvm::StringRef(), + /*RequiresNullTerminator=*/false); auto exp_ar = llvm::object::Archive::create(mem_buffer->getMemBufferRef()); if (!exp_ar) { @@ -95,7 +95,7 @@ size_t ObjectContainerBSDArchive::Archive::ParseObjects() { llvm::Error iter_err = llvm::Error::success(); Object obj; - for (const auto &child: llvm_archive->children(iter_err)) { + for (const auto &child : llvm_archive->children(iter_err)) { obj.Clear(); auto exp_name = child.getName(); if (exp_name) { @@ -111,7 +111,9 @@ size_t ObjectContainerBSDArchive::Archive::ParseObjects() { obj.modification_time = std::chrono::duration_cast( std::chrono::time_point_cast( - exp_mtime.get()).time_since_epoch()).count(); + exp_mtime.get()) + .time_since_epoch()) + .count(); } else { LLDB_LOG_ERROR(l, exp_mtime.takeError(), "failed to get archive object time: {0}"); @@ -331,21 +333,21 @@ ObjectContainer *ObjectContainerBSDArchive::CreateInstance( ArchiveType ObjectContainerBSDArchive::MagicBytesMatch(const DataExtractor &data) { uint32_t offset = 0; - const char *armag = (const char *)data.PeekData(offset, - sizeof(ar_hdr) + SARMAG); + const char *armag = + (const char *)data.PeekData(offset, sizeof(ar_hdr) + SARMAG); if (armag == nullptr) return ArchiveType::Invalid; ArchiveType result = ArchiveType::Invalid; if (strncmp(armag, ArchiveMagic, SARMAG) == 0) - result = ArchiveType::Archive; + result = ArchiveType::Archive; else if (strncmp(armag, ThinArchiveMagic, SARMAG) == 0) - result = ArchiveType::ThinArchive; + result = ArchiveType::ThinArchive; else - return ArchiveType::Invalid; + return ArchiveType::Invalid; armag += offsetof(struct ar_hdr, ar_fmag) + SARMAG; if (strncmp(armag, ARFMAG, 2) == 0) - return result; + return result; return ArchiveType::Invalid; } @@ -443,7 +445,8 @@ size_t ObjectContainerBSDArchive::GetModuleSpecifications( return 0; const size_t initial_count = specs.GetSize(); - llvm::sys::TimePoint<> file_mod_time = FileSystem::Instance().GetModificationTime(file); + llvm::sys::TimePoint<> file_mod_time = + FileSystem::Instance().GetModificationTime(file); Archive::shared_ptr archive_sp( Archive::FindCachedArchive(file, ArchSpec(), file_mod_time, file_offset)); bool set_archive_arch = false; diff --git a/lldb/source/Utility/ArchSpec.cpp b/lldb/source/Utility/ArchSpec.cpp index ac91183a271cc..85bb85044ec15 100644 --- a/lldb/source/Utility/ArchSpec.cpp +++ b/lldb/source/Utility/ArchSpec.cpp @@ -14,7 +14,6 @@ #include "lldb/lldb-defines.h" #include "llvm/ADT/STLExtras.h" #include "llvm/BinaryFormat/COFF.h" -#include "llvm/BinaryFormat/XCOFF.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/BinaryFormat/XCOFF.h" >From 8fcf69ed77148f8b339b87f75ed97e5ce719b4ba Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Fri, 27 Dec 2024 06:50:27 -0600 Subject: [PATCH 19/48] Some Updates --- lldb/include/lldb/Host/aix/HostInfoAIX.h | 11 +-- lldb/source/Host/aix/HostInfoAIX.cpp | 65 +------------- .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 87 +++++++++---------- .../ObjectFile/XCOFF/ObjectFileXCOFF.h | 11 ++- 4 files changed, 50 insertions(+), 124 deletions(-) diff --git a/lldb/include/lldb/Host/aix/HostInfoAIX.h b/lldb/include/lldb/Host/aix/HostInfoAIX.h index ced4cf34d38a8..ba727e1d5f171 100644 --- a/lldb/include/lldb/Host/aix/HostInfoAIX.h +++ b/lldb/include/lldb/Host/aix/HostInfoAIX.h @@ -6,16 +6,14 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_Host_aix_HostInfoAIX_h_ -#define lldb_Host_aix_HostInfoAIX_h_ +#ifndef LLDB_HOST_AIX_HOSTINFOAIX_H_ +#define LLDB_HOST_AIX_HOSTINFOAIX_H_ #include "lldb/Host/posix/HostInfoPosix.h" #include "lldb/Utility/FileSpec.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/VersionTuple.h" -#include - namespace lldb_private { class HostInfoAIX : public HostInfoPosix { @@ -25,15 +23,10 @@ class HostInfoAIX : public HostInfoPosix { static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr); static void Terminate(); - static llvm::VersionTuple GetOSVersion(); - static std::optional GetOSBuildString(); static llvm::StringRef GetDistributionId(); static FileSpec GetProgramFileSpec(); protected: - static bool ComputeSupportExeDirectory(FileSpec &file_spec); - static bool ComputeSystemPluginsDirectory(FileSpec &file_spec); - static bool ComputeUserPluginsDirectory(FileSpec &file_spec); static void ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64); }; diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp index 8bda09e01741b..ef07b07c8cab2 100644 --- a/lldb/source/Host/aix/HostInfoAIX.cpp +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -29,8 +29,6 @@ namespace { struct HostInfoAIXFields { llvm::once_flag m_distribution_once_flag; std::string m_distribution_id; - llvm::once_flag m_os_version_once_flag; - llvm::VersionTuple m_os_version; }; } // namespace @@ -49,33 +47,6 @@ void HostInfoAIX::Terminate() { HostInfoBase::Terminate(); } -llvm::VersionTuple HostInfoAIX::GetOSVersion() { - assert(g_fields && "Missing call to Initialize?"); - llvm::call_once(g_fields->m_os_version_once_flag, []() { - struct utsname un; - if (uname(&un) != 0) - return; - - llvm::StringRef release = un.release; - // The kernel release string can include a lot of stuff (e.g. - // 4.9.0-6-amd64). We're only interested in the numbered prefix. - release = release.substr(0, release.find_first_not_of("0123456789.")); - g_fields->m_os_version.tryParse(release); - }); - - return g_fields->m_os_version; -} - -std::optional HostInfoAIX::GetOSBuildString() { - struct utsname un; - ::memset(&un, 0, sizeof(utsname)); - - if (uname(&un) < 0) - return std::nullopt; - - return std::string(un.release); -} - llvm::StringRef HostInfoAIX::GetDistributionId() { assert(g_fields && "Missing call to Initialize?"); // Try to run 'lbs_release -i', and use that response for the distribution @@ -122,8 +93,7 @@ llvm::StringRef HostInfoAIX::GetDistributionId() { if (strstr(distribution_id, distributor_id_key)) { // strip newlines std::string id_string(distribution_id + strlen(distributor_id_key)); - id_string.erase(std::remove(id_string.begin(), id_string.end(), '\n'), - id_string.end()); + llvm::erase(id_string, '\n'); // lower case it and convert whitespace to underscores std::transform( @@ -167,42 +137,11 @@ FileSpec HostInfoAIX::GetProgramFileSpec() { return g_program_filespec; } -bool HostInfoAIX::ComputeSupportExeDirectory(FileSpec &file_spec) { - if (HostInfoPosix::ComputeSupportExeDirectory(file_spec) && - file_spec.IsAbsolute() && FileSystem::Instance().Exists(file_spec)) - return true; - file_spec.SetDirectory(GetProgramFileSpec().GetDirectory()); - return !file_spec.GetDirectory().IsEmpty(); -} - -bool HostInfoAIX::ComputeSystemPluginsDirectory(FileSpec &file_spec) { - FileSpec temp_file("/usr/" LLDB_INSTALL_LIBDIR_BASENAME "/lldb/plugins"); - FileSystem::Instance().Resolve(temp_file); - file_spec.SetDirectory(temp_file.GetPath()); - return true; -} - -bool HostInfoAIX::ComputeUserPluginsDirectory(FileSpec &file_spec) { - // XDG Base Directory Specification - // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html If - // XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb. - const char *xdg_data_home = getenv("XDG_DATA_HOME"); - if (xdg_data_home && xdg_data_home[0]) { - std::string user_plugin_dir(xdg_data_home); - user_plugin_dir += "/lldb"; - file_spec.SetDirectory(user_plugin_dir.c_str()); - } else - file_spec.SetDirectory("~/.local/share/lldb"); - return true; -} - void HostInfoAIX::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64) { HostInfoPosix::ComputeHostArchitectureSupport(arch_32, arch_64); - const char *distribution_id = GetDistributionId().data(); - - // On Linux, "unknown" in the vendor slot isn't what we want for the default + // "unknown" in the vendor slot isn't what we want for the default // triple. It's probably an artifact of config.guess. if (arch_32.IsValid()) { if (arch_32.GetTriple().getVendor() == llvm::Triple::UnknownVendor) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index a4d9ea295b4c3..afd8027bab06c 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -1,4 +1,5 @@ -//===-- ObjectFileXCOFF.cpp -------------------------------------------------===// +//===-- ObjectFileXCOFF.cpp +//-------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,13 +8,6 @@ //===----------------------------------------------------------------------===// #include "ObjectFileXCOFF.h" - -#include -#include -#include -#include - -#include "lldb/Utility/FileSpecList.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" @@ -28,6 +22,7 @@ #include "lldb/Target/Target.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/FileSpecList.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RangeMap.h" @@ -38,12 +33,16 @@ #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/Object/XCOFFObjectFile.h" #include "llvm/Object/Decompressor.h" #include "llvm/Support/CRC.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Object/XCOFFObjectFile.h" +#include +#include +#include +#include using namespace llvm; using namespace lldb; @@ -69,21 +68,19 @@ void ObjectFileXCOFF::Terminate() { bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; ObjectFile *ObjectFileXCOFF::CreateInstance(const lldb::ModuleSP &module_sp, - DataBufferSP data_sp, - lldb::offset_t data_offset, - const lldb_private::FileSpec *file, - lldb::offset_t file_offset, - lldb::offset_t length) { + DataBufferSP data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t file_offset, + lldb::offset_t length) { if (!data_sp) { data_sp = MapFileData(*file, length, file_offset); if (!data_sp) return nullptr; data_offset = 0; } - if (!ObjectFileXCOFF::MagicBytesMatch(data_sp, data_offset, length)) return nullptr; - // Update the data to contain the entire file if it doesn't already if (data_sp->GetByteSize() < length) { data_sp = MapFileData(*file, length, file_offset); @@ -114,15 +111,15 @@ bool ObjectFileXCOFF::CreateBinary() { Log *log = GetLog(LLDBLog::Object); - auto binary = llvm::object::XCOFFObjectFile::createObjectFile(llvm::MemoryBufferRef( - toStringRef(m_data.GetData()), m_file.GetFilename().GetStringRef()), - file_magic::xcoff_object_64); + auto binary = llvm::object::ObjectFile::createObjectFile( + llvm::MemoryBufferRef(toStringRef(m_data.GetData()), + m_file.GetFilename().GetStringRef()), + file_magic::xcoff_object_64); if (!binary) { LLDB_LOG_ERROR(log, binary.takeError(), "Failed to create binary for file ({1}): {0}", m_file); return false; } - // Make sure we only handle COFF format. m_binary = llvm::unique_dyn_cast(std::move(*binary)); @@ -132,6 +129,7 @@ bool ObjectFileXCOFF::CreateBinary() { LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}", this, GetModule().get(), GetModule()->GetSpecificationDescription(), m_file.GetPath(), m_binary.get()); + return true; } @@ -148,9 +146,12 @@ size_t ObjectFileXCOFF::GetModuleSpecifications( const size_t initial_count = specs.GetSize(); if (ObjectFileXCOFF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) { - ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + ArchSpec arch_spec = + ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); ModuleSpec spec(file, arch_spec); - spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX); + spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, + LLDB_INVALID_CPUTYPE, + llvm::Triple::AIX); specs.Append(spec); } return specs.GetSize() - initial_count; @@ -158,11 +159,9 @@ size_t ObjectFileXCOFF::GetModuleSpecifications( static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) { switch (magic) { - /* TODO: 32bit not supported yet - case XCOFF::XCOFF32: - return sizeof(struct llvm::object::XCOFFFileHeader32); - */ - + // TODO: 32bit not supported. + // case XCOFF::XCOFF32: + // return sizeof(struct llvm::object::XCOFFFileHeader32); case XCOFF::XCOFF64: return sizeof(struct llvm::object::XCOFFFileHeader64); break; @@ -174,10 +173,12 @@ static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) { } bool ObjectFileXCOFF::MagicBytesMatch(DataBufferSP &data_sp, - lldb::addr_t data_offset, - lldb::addr_t data_length) { - lldb_private::DataExtractor data; + lldb::addr_t data_offset, + lldb::addr_t data_length) { + lldb_private::DataExtractor data; data.SetData(data_sp, data_offset, data_length); + // Need to set this as XCOFF is only compatible with Big Endian + data.SetByteOrder(eByteOrderBig); lldb::offset_t offset = 0; uint16_t magic = data.GetU16(&offset); return XCOFFHeaderSizeFromMagic(magic) != 0; @@ -386,13 +387,10 @@ bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, return changed; } -ByteOrder ObjectFileXCOFF::GetByteOrder() const { - return eByteOrderBig; -} -bool ObjectFileXCOFF::IsExecutable() const { - return true; -} +ByteOrder ObjectFileXCOFF::GetByteOrder() const { return eByteOrderBig; } + +bool ObjectFileXCOFF::IsExecutable() const { return true; } uint32_t ObjectFileXCOFF::GetAddressByteSize() const { if (m_xcoff_header.magic == XCOFF::XCOFF64) @@ -592,13 +590,12 @@ void ObjectFileXCOFF::Dump(Stream *s) { } ArchSpec ObjectFileXCOFF::GetArchitecture() { - ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + ArchSpec arch_spec = + ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); return arch_spec; } -UUID ObjectFileXCOFF::GetUUID() { - return UUID(); -} +UUID ObjectFileXCOFF::GetUUID() { return UUID(); } std::optional ObjectFileXCOFF::GetDebugLink() { return std::nullopt; @@ -724,16 +721,14 @@ lldb_private::Address ObjectFileXCOFF::GetBaseAddress() { } ObjectFile::Type ObjectFileXCOFF::CalculateType() { - if (m_xcoff_header.flags & XCOFF::F_EXEC) + if (m_binary->fileHeader64()->Flags & XCOFF::F_EXEC) return eTypeExecutable; - else if (m_xcoff_header.flags & XCOFF::F_SHROBJ) + else if (m_binary->fileHeader64()->Flags & XCOFF::F_SHROBJ) return eTypeSharedLibrary; return eTypeUnknown; } -ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { - return eStrataUnknown; -} +ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { return eStrataUnknown; } llvm::StringRef ObjectFileXCOFF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const { @@ -752,7 +747,7 @@ ObjectFileXCOFF::GetLoadableData(Target &target) { lldb::WritableDataBufferSP ObjectFileXCOFF::MapFileDataWritable(const FileSpec &file, uint64_t Size, - uint64_t Offset) { + uint64_t Offset) { return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size, Offset); } diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h index 5a12d16886489..f827fca3932f4 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h @@ -1,4 +1,5 @@ -//===-- ObjectFileXCOFF.h --------------------------------------- -*- C++ -*-===// +//===-- ObjectFileXCOFF.h --------------------------------------- -*- C++ +//-*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -9,16 +10,14 @@ #ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H #define LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H -#include - -#include - #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/UUID.h" #include "lldb/lldb-private.h" #include "llvm/Object/XCOFFObjectFile.h" +#include +#include /// \class ObjectFileXCOFF /// Generic XCOFF object file reader. @@ -240,4 +239,4 @@ class ObjectFileXCOFF : public lldb_private::ObjectFile { std::map> m_deps_base_members; }; -#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILE_H >From f8b05dfc9fc75177a63dfa2d6df4a9af143b09b8 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 5 Jan 2025 05:01:47 -0600 Subject: [PATCH 20/48] HostInfoAIX Cleanup --- lldb/include/lldb/Host/aix/HostInfoAIX.h | 4 - lldb/source/Host/aix/HostInfoAIX.cpp | 108 ----------------------- 2 files changed, 112 deletions(-) diff --git a/lldb/include/lldb/Host/aix/HostInfoAIX.h b/lldb/include/lldb/Host/aix/HostInfoAIX.h index ba727e1d5f171..5a52c42fa6199 100644 --- a/lldb/include/lldb/Host/aix/HostInfoAIX.h +++ b/lldb/include/lldb/Host/aix/HostInfoAIX.h @@ -23,12 +23,8 @@ class HostInfoAIX : public HostInfoPosix { static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr); static void Terminate(); - static llvm::StringRef GetDistributionId(); static FileSpec GetProgramFileSpec(); -protected: - static void ComputeHostArchitectureSupport(ArchSpec &arch_32, - ArchSpec &arch_64); }; } diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp index ef07b07c8cab2..2996fcb55f811 100644 --- a/lldb/source/Host/aix/HostInfoAIX.cpp +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -11,117 +11,25 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" - #include "llvm/Support/Threading.h" - #include #include #include #include #include - #include #include using namespace lldb_private; -namespace { -struct HostInfoAIXFields { - llvm::once_flag m_distribution_once_flag; - std::string m_distribution_id; -}; -} // namespace - -static HostInfoAIXFields *g_fields = nullptr; - void HostInfoAIX::Initialize(SharedLibraryDirectoryHelper *helper) { HostInfoPosix::Initialize(helper); - - g_fields = new HostInfoAIXFields(); } void HostInfoAIX::Terminate() { - assert(g_fields && "Missing call to Initialize?"); - delete g_fields; - g_fields = nullptr; HostInfoBase::Terminate(); } -llvm::StringRef HostInfoAIX::GetDistributionId() { - assert(g_fields && "Missing call to Initialize?"); - // Try to run 'lbs_release -i', and use that response for the distribution - // id. - llvm::call_once(g_fields->m_distribution_once_flag, []() { - Log *log = GetLog(LLDBLog::Host); - LLDB_LOGF(log, "attempting to determine AIX distribution..."); - - // check if the lsb_release command exists at one of the following paths - const char *const exe_paths[] = {"/bin/lsb_release", - "/usr/bin/lsb_release"}; - - for (size_t exe_index = 0; - exe_index < sizeof(exe_paths) / sizeof(exe_paths[0]); ++exe_index) { - const char *const get_distribution_info_exe = exe_paths[exe_index]; - if (access(get_distribution_info_exe, F_OK)) { - // this exe doesn't exist, move on to next exe - LLDB_LOGF(log, "executable doesn't exist: %s", - get_distribution_info_exe); - continue; - } - - // execute the distribution-retrieval command, read output - std::string get_distribution_id_command(get_distribution_info_exe); - get_distribution_id_command += " -i"; - - FILE *file = popen(get_distribution_id_command.c_str(), "r"); - if (!file) { - LLDB_LOGF(log, - "failed to run command: \"%s\", cannot retrieve " - "platform information", - get_distribution_id_command.c_str()); - break; - } - - // retrieve the distribution id string. - char distribution_id[256] = {'\0'}; - if (fgets(distribution_id, sizeof(distribution_id) - 1, file) != - nullptr) { - LLDB_LOGF(log, "distribution id command returned \"%s\"", - distribution_id); - - const char *const distributor_id_key = "Distributor ID:\t"; - if (strstr(distribution_id, distributor_id_key)) { - // strip newlines - std::string id_string(distribution_id + strlen(distributor_id_key)); - llvm::erase(id_string, '\n'); - - // lower case it and convert whitespace to underscores - std::transform( - id_string.begin(), id_string.end(), id_string.begin(), - [](char ch) { return tolower(isspace(ch) ? '_' : ch); }); - - g_fields->m_distribution_id = id_string; - LLDB_LOGF(log, "distribution id set to \"%s\"", - g_fields->m_distribution_id.c_str()); - } else { - LLDB_LOGF(log, "failed to find \"%s\" field in \"%s\"", - distributor_id_key, distribution_id); - } - } else { - LLDB_LOGF(log, - "failed to retrieve distribution id, \"%s\" returned no" - " lines", - get_distribution_id_command.c_str()); - } - - // clean up the file - pclose(file); - } - }); - - return g_fields->m_distribution_id; -} - FileSpec HostInfoAIX::GetProgramFileSpec() { static FileSpec g_program_filespec; @@ -136,19 +44,3 @@ FileSpec HostInfoAIX::GetProgramFileSpec() { return g_program_filespec; } - -void HostInfoAIX::ComputeHostArchitectureSupport(ArchSpec &arch_32, - ArchSpec &arch_64) { - HostInfoPosix::ComputeHostArchitectureSupport(arch_32, arch_64); - - // "unknown" in the vendor slot isn't what we want for the default - // triple. It's probably an artifact of config.guess. - if (arch_32.IsValid()) { - if (arch_32.GetTriple().getVendor() == llvm::Triple::UnknownVendor) - arch_32.GetTriple().setVendorName(llvm::StringRef()); - } - if (arch_64.IsValid()) { - if (arch_64.GetTriple().getVendor() == llvm::Triple::UnknownVendor) - arch_64.GetTriple().setVendorName(llvm::StringRef()); - } -} >From 57d080e44e80203a6ab848c362469954a7c9f067 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 5 Jan 2025 05:49:40 -0600 Subject: [PATCH 21/48] Cleanup HostInfoAIX Including the previous commit, Removed: GetDistributionID, ComputeHostArchitectureSupport and Reduced GetProgramFileSpec as it was not needed --- lldb/source/Host/aix/HostInfoAIX.cpp | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp index 2996fcb55f811..d09b9052668af 100644 --- a/lldb/source/Host/aix/HostInfoAIX.cpp +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -26,21 +26,9 @@ void HostInfoAIX::Initialize(SharedLibraryDirectoryHelper *helper) { HostInfoPosix::Initialize(helper); } -void HostInfoAIX::Terminate() { - HostInfoBase::Terminate(); -} +void HostInfoAIX::Terminate() { HostInfoBase::Terminate(); } FileSpec HostInfoAIX::GetProgramFileSpec() { static FileSpec g_program_filespec; - - if (!g_program_filespec) { - char exe_path[PATH_MAX]; - ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); - if (len > 0) { - exe_path[len] = 0; - g_program_filespec.SetFile(exe_path, FileSpec::Style::native); - } - } - return g_program_filespec; } >From 673713a9339de4e4ea395ee2e7f65dc1db43bcf9 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 5 Jan 2025 15:35:23 -0600 Subject: [PATCH 22/48] Removing headers --- lldb/include/lldb/Host/aix/HostInfoAIX.h | 2 -- lldb/source/Host/aix/HostInfoAIX.cpp | 12 ------------ 2 files changed, 14 deletions(-) diff --git a/lldb/include/lldb/Host/aix/HostInfoAIX.h b/lldb/include/lldb/Host/aix/HostInfoAIX.h index 5a52c42fa6199..331a274630850 100644 --- a/lldb/include/lldb/Host/aix/HostInfoAIX.h +++ b/lldb/include/lldb/Host/aix/HostInfoAIX.h @@ -11,8 +11,6 @@ #include "lldb/Host/posix/HostInfoPosix.h" #include "lldb/Utility/FileSpec.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/VersionTuple.h" namespace lldb_private { diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp index d09b9052668af..61b47462dd647 100644 --- a/lldb/source/Host/aix/HostInfoAIX.cpp +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -7,18 +7,6 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/aix/HostInfoAIX.h" -#include "lldb/Host/Config.h" -#include "lldb/Host/FileSystem.h" -#include "lldb/Utility/LLDBLog.h" -#include "lldb/Utility/Log.h" -#include "llvm/Support/Threading.h" -#include -#include -#include -#include -#include -#include -#include using namespace lldb_private; >From cdc31f3963365e4595247ff5a7155662df1ce1af Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 6 Jan 2025 09:28:56 -0600 Subject: [PATCH 23/48] Reverted merge blunder CMakeLists --- lldb/source/Host/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index f326bc07dc1f6..f4fca8acc4d83 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -141,7 +141,10 @@ else() elseif (CMAKE_SYSTEM_NAME MATCHES "AIX") add_host_subdirectory(aix + aix/AbstractSocket.cpp + aix/Host.cpp aix/HostInfoAIX.cpp + aix/Support.cpp ) endif() endif() >From 713a6cbbb97b9bc56b039ab050a1690eccc017e3 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 6 Jan 2025 09:39:36 -0600 Subject: [PATCH 24/48] Removed DomainSocket.cpp FileSystemPosix.cpp includes --- lldb/source/Host/posix/DomainSocket.cpp | 4 ---- lldb/source/Host/posix/FileSystemPosix.cpp | 3 --- 2 files changed, 7 deletions(-) diff --git a/lldb/source/Host/posix/DomainSocket.cpp b/lldb/source/Host/posix/DomainSocket.cpp index f30e84d83efca..be8fcdf2c8f2c 100644 --- a/lldb/source/Host/posix/DomainSocket.cpp +++ b/lldb/source/Host/posix/DomainSocket.cpp @@ -17,10 +17,6 @@ #include #include -#if defined(_AIX) -#include -#endif - using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index 1a84f550662d7..a631bb01209ec 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,9 +11,6 @@ // C includes #include #include -#ifndef _AIX -#include -#endif #include #include #include >From 0a706d29dabeefa62e354fc9358d650f89032048 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 6 Jan 2025 09:44:10 -0600 Subject: [PATCH 25/48] sys/mount.h --- lldb/source/Host/posix/FileSystemPosix.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index a631bb01209ec..945e2affc8371 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,6 +11,7 @@ // C includes #include #include +#include #include #include #include >From 84ebb4ec9b542c38fe1b60261a3253383e9fbf5d Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 6 Jan 2025 09:54:58 -0600 Subject: [PATCH 26/48] sys/mount.h --- lldb/source/Host/posix/FileSystemPosix.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index 945e2affc8371..1a84f550662d7 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,7 +11,9 @@ // C includes #include #include +#ifndef _AIX #include +#endif #include #include #include >From 844f7980040de9e13620e9d65a3fcaef56b6c8d6 Mon Sep 17 00:00:00 2001 From: Dhruv Srivastava Date: Thu, 9 Jan 2025 09:47:43 +0530 Subject: [PATCH 27/48] Removed _AIX from ConnectionFileDescriptorPosix.cpp --- lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index 2530c8fa353ba..0ed2016667162 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -715,7 +715,7 @@ ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, ConnectionStatus ConnectionFileDescriptor::ConnectFile( llvm::StringRef s, socket_id_callback_type socket_id_callback, Status *error_ptr) { -#if LLDB_ENABLE_POSIX && !defined(_AIX) +#if LLDB_ENABLE_POSIX std::string addr_str = s.str(); // file:///PATH int fd = FileSystem::Instance().Open(addr_str.c_str(), O_RDWR); @@ -756,7 +756,7 @@ ConnectionStatus ConnectionFileDescriptor::ConnectFile( m_io_sp = std::make_shared(fd, File::eOpenOptionReadWrite, true); return eConnectionStatusSuccess; -#endif // LLDB_ENABLE_POSIX && !defined(_AIX) +#endif // LLDB_ENABLE_POSIX llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX"); } >From 4fe42cda7c2f4990b18a39c1d6563094fb88775f Mon Sep 17 00:00:00 2001 From: ravindra shinde Date: Fri, 17 Jan 2025 13:58:13 +0530 Subject: [PATCH 28/48] [ObjectFileXCOFF] Fix access to protected member 'GetSectionLoadList' in Target - Added a public method to Target for accessing 'GetSectionLoadList' safely. - Updated ObjectFileXCOFF to use the new public method, ensuring compliance with encapsulation rules. This resolves the build error caused by direct access to the protected member. Signed-off-by: ravindra shinde --- lldb/include/lldb/Target/Target.h | 5 +++++ lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index f31ac381391b4..75f9c9c2e999c 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -522,6 +522,7 @@ class Target : public std::enable_shared_from_this, eBroadcastBitSymbolsChanged = (1 << 5), }; + // These two functions fill out the Broadcaster interface: static llvm::StringRef GetStaticBroadcasterClass(); @@ -1644,6 +1645,10 @@ class Target : public std::enable_shared_from_this, TargetStats &GetStatistics() { return m_stats; } +public: + SectionLoadList &GetSectionLoadListPublic() { + return GetSectionLoadList(); + } protected: /// Construct with optional file and arch. /// diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index afd8027bab06c..cf11e5fb8f5a3 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -340,7 +340,7 @@ bool ObjectFileXCOFF::SetLoadAddress(Target &target, lldb::addr_t value, strcmp(section_sp->GetName().AsCString(), ".bss") == 0) use_offset = true; - if (target.GetSectionLoadList().SetSectionLoadAddress( + if (target.GetSectionLoadListPublic().SetSectionLoadAddress( section_sp, (use_offset ? (section_sp->GetFileOffset() + value) : (section_sp->GetFileAddress() + value)))) ++num_loaded_sections; @@ -369,13 +369,13 @@ bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); if (type_id == 1 && section_sp && strcmp(section_sp->GetName().AsCString(), ".text") == 0) { if (!section_sp->IsThreadSpecific()) { - if (target.GetSectionLoadList().SetSectionLoadAddress( + if (target.GetSectionLoadListPublic().SetSectionLoadAddress( section_sp, section_sp->GetFileOffset() + value)) ++num_loaded_sections; } } else if (type_id == 2 && section_sp && strcmp(section_sp->GetName().AsCString(), ".data") == 0) { if (!section_sp->IsThreadSpecific()) { - if (target.GetSectionLoadList().SetSectionLoadAddress( + if (target.GetSectionLoadListPublic().SetSectionLoadAddress( section_sp, section_sp->GetFileAddress() + value)) ++num_loaded_sections; } >From e5ed4f21c5bbc709e5e2eff0f83995cc6d89de48 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 19 Jan 2025 03:43:11 -0600 Subject: [PATCH 29/48] Resolved cmake failure for SBProgress.cpp --- lldb/source/API/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index eb348e2b97232..0a03e000c0cae 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -85,6 +85,7 @@ add_lldb_library(liblldb STATIC ${option_framework} SBModuleSpec.cpp SBPlatform.cpp SBProcess.cpp + SBProgress.cpp SBProcessInfo.cpp SBProcessInfoList.cpp SBQueue.cpp >From 82dbcb0e776c438e5f40c9f8d8c8e8eb81b7febd Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 27 Jan 2025 06:35:19 -0600 Subject: [PATCH 30/48] Host.cpp ANDROID --- lldb/source/Host/common/Host.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 758e9f49ade2c..adf74df8aa90b 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -1,4 +1,4 @@ -//===-- Host.cpp ----------------------------------------------------------===// + // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -516,7 +516,6 @@ static int dladdr(const void *ptr, Dl_info *dl) FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSpec module_filespec; -#if !defined(__ANDROID__) #ifdef _AIX if (host_addr == reinterpret_cast(HostInfoBase::ComputeSharedLibraryDirectory)) { // FIXME: AIX dladdr return "lldb" for this case @@ -527,6 +526,7 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { } } #endif +#if !defined(__ANDROID__) Dl_info info; if (::dladdr(host_addr, &info)) { if (info.dli_fname) { @@ -534,6 +534,7 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSystem::Instance().Resolve(module_filespec); } } +#endif return module_filespec; } >From 60294eaa1611632afc94b9da503752e34ad2703d Mon Sep 17 00:00:00 2001 From: Ravindra Shinde Date: Tue, 4 Feb 2025 03:23:56 -0600 Subject: [PATCH 31/48] Resolving the fatal error while build Build is failing due to the fatal error: 'sys/syscall.h' file not found Signed-off-by: Ravindra Shinde --- lldb/source/Host/common/Host.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 40ce76d70d6e8..b5bd68b8539bd 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -18,8 +18,12 @@ #include #include #include + +#ifndef _AIX #include #include +#endif + #include #include #endif >From 2644be59b13a61c69cc635875c94b0b4645fe76c Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 10 Feb 2025 01:49:12 -0600 Subject: [PATCH 32/48] InferiorCallPOSIX.cpp --- lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index d1f9fe851119e..8e74cce097894 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -120,12 +120,13 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, arch, addr, length, prot_arg, flags, fd, offset); #if defined(_AIX) lldb::ThreadPlanSP call_plan_sp( - new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(), + new ThreadPlanCallFunction(*thread, mmap_addr, toc_range.GetBaseAddress(), void_ptr_type, args, options)); #else lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallFunction( *thread, mmap_addr, void_ptr_type, args, options)); +#endif if (call_plan_sp) { DiagnosticManager diagnostics; >From 4805b13cba964b58def39a66ad4c4309a9b2c501 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 12 Feb 2025 07:33:04 -0600 Subject: [PATCH 33/48] Merge branch gh-101657 --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 97 ------------------- .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 5 +- 2 files changed, 1 insertion(+), 101 deletions(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 1a98bb9334043..375d879c7a995 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -21,10 +21,6 @@ #include "llvm/Support/FileSystem.h" #if defined(_AIX) #include -#include -#include -#include -#include #endif /*#include "llvm/ADT/Triple.h" @@ -137,107 +133,14 @@ bool DynamicLoaderAIXDYLD::NotifyBreakpointHit( } -void DynamicLoaderAIXDYLD::ResolveExecutableModule( - lldb::ModuleSP &module_sp) { - Log *log = GetLog(LLDBLog::DynamicLoader); - - if (m_process == nullptr) - return; - - auto &target = m_process->GetTarget(); - const auto platform_sp = target.GetPlatform(); - - ProcessInstanceInfo process_info; - if (!m_process->GetProcessInfo(process_info)) { - LLDB_LOGF(log, - "DynamicLoaderPOSIXDYLD::%s - failed to get process info for " - "pid %" PRIu64, - __FUNCTION__, m_process->GetID()); - return; - } - - int32long64_t pid = m_process->GetID(); - char cwd[PATH_MAX], resolved_path[PATH_MAX]; - std::string executable_name; - bool path_resolved = false; - psinfo_t psinfo; - - std::string proc_file = "/proc/" + std::to_string(pid) + "/psinfo"; - std::string cwd_link = "/proc/" + std::to_string(pid) + "/cwd"; - std::ifstream file(proc_file, std::ios::binary); - if(!file.is_open()) - LLDB_LOGF(log, "Error: Unable to access process info "); - - file.read(reinterpret_cast(&psinfo), sizeof(psinfo_t)); - if(!file) - LLDB_LOGF(log, "Process info error: Failed to read "); - - std::string relative_path(psinfo.pr_fname); - LLDB_LOGF(log, "Relative path %s",relative_path.c_str()); - - if(readlink(cwd_link.c_str(), cwd, sizeof(cwd)) != -1){ - std::filesystem::path full_path = std::filesystem::path(cwd)/relative_path; - if(realpath(full_path.c_str(), resolved_path)) { - LLDB_LOGF(log, "Resolved Path using process info : %s", resolved_path); - path_resolved = true; - } - else - LLDB_LOGF(log, "Realpath error: Unable to resolve. "); - } - - executable_name = resolved_path; - if(path_resolved == false) { - std::string command_line(psinfo.pr_psargs); - LLDB_LOGF(log, "Command line: %s",command_line.c_str()); - if (!command_line.empty()) { - size_t space1 = command_line.find(' '); - executable_name = command_line.substr(0, space1); - LLDB_LOGF(log, "Resolved path using command line arg %s",executable_name.c_str()); - } - } - - LLDB_LOGF(log, "Executable Name %s",executable_name.c_str()); - process_info.SetExecutableFile(lldb_private::FileSpec(executable_name), - true); - - LLDB_LOGF( - log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s", - __FUNCTION__, m_process->GetID(), - process_info.GetExecutableFile().GetPath().c_str()); - - ModuleSpec module_spec(process_info.GetExecutableFile(), - process_info.GetArchitecture()); - if (module_sp && module_sp->MatchesModuleSpec(module_spec)) - return; - - const auto executable_search_paths(Target::GetDefaultExecutableSearchPaths()); - auto error = platform_sp->ResolveExecutable( - module_spec, module_sp, - !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr); - if (error.Fail()) { - StreamString stream; - module_spec.Dump(stream); - - LLDB_LOGF(log, - "DynamicLoaderPOSIXDYLD::%s - failed to resolve executable " - "with module spec \"%s\": %s", - __FUNCTION__, stream.GetData(), error.AsCString()); - return; - } - - target.SetExecutableModule(module_sp, eLoadDependentsNo); -} - void DynamicLoaderAIXDYLD::DidAttach() { Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); ModuleSP executable = GetTargetExecutable(); - ResolveExecutableModule(executable); if (!executable.get()) return; - LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); // Try to fetch the load address of the file from the process, since there // could be randomization of the load address. diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h index 0ffbe688e0069..ae4b7aca66dcc 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -24,7 +24,7 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { static void Initialize(); static void Terminate(); - static llvm::StringRef GetPluginNameStatic() { return "aix-dyld"; } + static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; } static llvm::StringRef GetPluginDescriptionStatic(); static DynamicLoader *CreateInstance(Process *process, bool force); @@ -46,9 +46,6 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { protected: lldb::addr_t GetLoadAddress(lldb::ModuleSP executable); - /// Loads Module from inferior process. - void ResolveExecutableModule(lldb::ModuleSP &module_sp); - private: std::map m_loaded_modules; }; >From cff574b36903e12385e5d6cddf4532ba279f47de Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 12 Feb 2025 07:52:04 -0600 Subject: [PATCH 34/48] Fix for Debugging Attach to AIX Process --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 97 +++++++++++++++++++ .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 5 +- 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 375d879c7a995..1a98bb9334043 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -21,6 +21,10 @@ #include "llvm/Support/FileSystem.h" #if defined(_AIX) #include +#include +#include +#include +#include #endif /*#include "llvm/ADT/Triple.h" @@ -133,14 +137,107 @@ bool DynamicLoaderAIXDYLD::NotifyBreakpointHit( } +void DynamicLoaderAIXDYLD::ResolveExecutableModule( + lldb::ModuleSP &module_sp) { + Log *log = GetLog(LLDBLog::DynamicLoader); + + if (m_process == nullptr) + return; + + auto &target = m_process->GetTarget(); + const auto platform_sp = target.GetPlatform(); + + ProcessInstanceInfo process_info; + if (!m_process->GetProcessInfo(process_info)) { + LLDB_LOGF(log, + "DynamicLoaderPOSIXDYLD::%s - failed to get process info for " + "pid %" PRIu64, + __FUNCTION__, m_process->GetID()); + return; + } + + int32long64_t pid = m_process->GetID(); + char cwd[PATH_MAX], resolved_path[PATH_MAX]; + std::string executable_name; + bool path_resolved = false; + psinfo_t psinfo; + + std::string proc_file = "/proc/" + std::to_string(pid) + "/psinfo"; + std::string cwd_link = "/proc/" + std::to_string(pid) + "/cwd"; + std::ifstream file(proc_file, std::ios::binary); + if(!file.is_open()) + LLDB_LOGF(log, "Error: Unable to access process info "); + + file.read(reinterpret_cast(&psinfo), sizeof(psinfo_t)); + if(!file) + LLDB_LOGF(log, "Process info error: Failed to read "); + + std::string relative_path(psinfo.pr_fname); + LLDB_LOGF(log, "Relative path %s",relative_path.c_str()); + + if(readlink(cwd_link.c_str(), cwd, sizeof(cwd)) != -1){ + std::filesystem::path full_path = std::filesystem::path(cwd)/relative_path; + if(realpath(full_path.c_str(), resolved_path)) { + LLDB_LOGF(log, "Resolved Path using process info : %s", resolved_path); + path_resolved = true; + } + else + LLDB_LOGF(log, "Realpath error: Unable to resolve. "); + } + + executable_name = resolved_path; + if(path_resolved == false) { + std::string command_line(psinfo.pr_psargs); + LLDB_LOGF(log, "Command line: %s",command_line.c_str()); + if (!command_line.empty()) { + size_t space1 = command_line.find(' '); + executable_name = command_line.substr(0, space1); + LLDB_LOGF(log, "Resolved path using command line arg %s",executable_name.c_str()); + } + } + + LLDB_LOGF(log, "Executable Name %s",executable_name.c_str()); + process_info.SetExecutableFile(lldb_private::FileSpec(executable_name), + true); + + LLDB_LOGF( + log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s", + __FUNCTION__, m_process->GetID(), + process_info.GetExecutableFile().GetPath().c_str()); + + ModuleSpec module_spec(process_info.GetExecutableFile(), + process_info.GetArchitecture()); + if (module_sp && module_sp->MatchesModuleSpec(module_spec)) + return; + + const auto executable_search_paths(Target::GetDefaultExecutableSearchPaths()); + auto error = platform_sp->ResolveExecutable( + module_spec, module_sp, + !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr); + if (error.Fail()) { + StreamString stream; + module_spec.Dump(stream); + + LLDB_LOGF(log, + "DynamicLoaderPOSIXDYLD::%s - failed to resolve executable " + "with module spec \"%s\": %s", + __FUNCTION__, stream.GetData(), error.AsCString()); + return; + } + + target.SetExecutableModule(module_sp, eLoadDependentsNo); +} + void DynamicLoaderAIXDYLD::DidAttach() { Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); ModuleSP executable = GetTargetExecutable(); + ResolveExecutableModule(executable); if (!executable.get()) return; + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); // Try to fetch the load address of the file from the process, since there // could be randomization of the load address. diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h index ae4b7aca66dcc..0ffbe688e0069 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -24,7 +24,7 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { static void Initialize(); static void Terminate(); - static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; } + static llvm::StringRef GetPluginNameStatic() { return "aix-dyld"; } static llvm::StringRef GetPluginDescriptionStatic(); static DynamicLoader *CreateInstance(Process *process, bool force); @@ -46,6 +46,9 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { protected: lldb::addr_t GetLoadAddress(lldb::ModuleSP executable); + /// Loads Module from inferior process. + void ResolveExecutableModule(lldb::ModuleSP &module_sp); + private: std::map m_loaded_modules; }; >From 303fa3bc078d7572702fb302726d4dd1bd13ddb2 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Fri, 21 Feb 2025 06:18:33 -0600 Subject: [PATCH 35/48] Merge branch 'llvm:main' into gh-101657 --- lldb/source/Plugins/Platform/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/lldb/source/Plugins/Platform/CMakeLists.txt b/lldb/source/Plugins/Platform/CMakeLists.txt index f5b0dbdd5e0a9..0220e734b36d1 100644 --- a/lldb/source/Plugins/Platform/CMakeLists.txt +++ b/lldb/source/Plugins/Platform/CMakeLists.txt @@ -9,4 +9,3 @@ add_subdirectory(OpenBSD) add_subdirectory(POSIX) add_subdirectory(QemuUser) add_subdirectory(Windows) -add_subdirectory(AIX) >From 6947dec02bb527f710c1bea3827b2c16d89f308a Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Fri, 21 Feb 2025 07:02:53 -0600 Subject: [PATCH 36/48] Merge branch 'llvm:main' into gh-101657 --- .../Plugins/Platform/AIX/PlatformAIX.cpp | 171 +----------------- 1 file changed, 1 insertion(+), 170 deletions(-) diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp index 0d66325d16267..21724d83133e9 100644 --- a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp +++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp @@ -130,12 +130,6 @@ void PlatformAIX::GetStatus(Stream &strm) { #endif } -void PlatformAIX::CalculateTrapHandlerSymbolNames() { - m_trap_handlers.push_back(ConstString("_sigtramp")); - m_trap_handlers.push_back(ConstString("__kernel_rt_sigreturn")); - m_trap_handlers.push_back(ConstString("__restore_rt")); -} - void PlatformAIX::CalculateTrapHandlerSymbolNames() {} lldb::UnwindPlanSP @@ -160,168 +154,5 @@ MmapArgList PlatformAIX::GetMmapArgumentList(const ArchSpec &arch, addr_t addr, } CompilerType PlatformAIX::GetSiginfoType(const llvm::Triple &triple) { - if (!m_type_system_up) - m_type_system_up.reset(new TypeSystemClang("siginfo", triple)); - TypeSystemClang *ast = m_type_system_up.get(); - - bool si_errno_then_code = true; - - switch (triple.getArch()) { - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - // mips has si_code and si_errno swapped - si_errno_then_code = false; - break; - default: - break; - } - - // generic types - CompilerType int_type = ast->GetBasicType(eBasicTypeInt); - CompilerType uint_type = ast->GetBasicType(eBasicTypeUnsignedInt); - CompilerType short_type = ast->GetBasicType(eBasicTypeShort); - CompilerType long_type = ast->GetBasicType(eBasicTypeLong); - CompilerType voidp_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); - - // platform-specific types - CompilerType &pid_type = int_type; - CompilerType &uid_type = uint_type; - CompilerType &clock_type = long_type; - CompilerType &band_type = long_type; - - CompilerType sigval_type = ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_sigval_t", - llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); - ast->StartTagDeclarationDefinition(sigval_type); - ast->AddFieldToRecordType(sigval_type, "sival_int", int_type, - lldb::eAccessPublic, 0); - ast->AddFieldToRecordType(sigval_type, "sival_ptr", voidp_type, - lldb::eAccessPublic, 0); - ast->CompleteTagDeclarationDefinition(sigval_type); - - CompilerType sigfault_bounds_type = ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", - llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); - ast->StartTagDeclarationDefinition(sigfault_bounds_type); - ast->AddFieldToRecordType(sigfault_bounds_type, "_addr_bnd", - ast->CreateStructForIdentifier(ConstString(), - { - {"_lower", voidp_type}, - {"_upper", voidp_type}, - }), - lldb::eAccessPublic, 0); - ast->AddFieldToRecordType(sigfault_bounds_type, "_pkey", uint_type, - lldb::eAccessPublic, 0); - ast->CompleteTagDeclarationDefinition(sigfault_bounds_type); - - // siginfo_t - CompilerType siginfo_type = ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_siginfo_t", - llvm::to_underlying(clang::TagTypeKind::Struct), lldb::eLanguageTypeC); - ast->StartTagDeclarationDefinition(siginfo_type); - ast->AddFieldToRecordType(siginfo_type, "si_signo", int_type, - lldb::eAccessPublic, 0); - - if (si_errno_then_code) { - ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type, - lldb::eAccessPublic, 0); - ast->AddFieldToRecordType(siginfo_type, "si_code", int_type, - lldb::eAccessPublic, 0); - } else { - ast->AddFieldToRecordType(siginfo_type, "si_code", int_type, - lldb::eAccessPublic, 0); - ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type, - lldb::eAccessPublic, 0); - } - - // the structure is padded on 64-bit arches to fix alignment - if (triple.isArch64Bit()) - ast->AddFieldToRecordType(siginfo_type, "__pad0", int_type, - lldb::eAccessPublic, 0); - - // union used to hold the signal data - CompilerType union_type = ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", - llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); - ast->StartTagDeclarationDefinition(union_type); - - ast->AddFieldToRecordType( - union_type, "_kill", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_pid", pid_type}, - {"si_uid", uid_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_timer", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_tid", int_type}, - {"si_overrun", int_type}, - {"si_sigval", sigval_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_rt", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_pid", pid_type}, - {"si_uid", uid_type}, - {"si_sigval", sigval_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_sigchld", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_pid", pid_type}, - {"si_uid", uid_type}, - {"si_status", int_type}, - {"si_utime", clock_type}, - {"si_stime", clock_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_sigfault", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_addr", voidp_type}, - {"si_addr_lsb", short_type}, - {"_bounds", sigfault_bounds_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_sigpoll", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_band", band_type}, - {"si_fd", int_type}, - }), - lldb::eAccessPublic, 0); - - // NB: SIGSYS is not present on ia64 but we don't seem to support that - ast->AddFieldToRecordType( - union_type, "_sigsys", - ast->CreateStructForIdentifier(ConstString(), - { - {"_call_addr", voidp_type}, - {"_syscall", int_type}, - {"_arch", uint_type}, - }), - lldb::eAccessPublic, 0); - - ast->CompleteTagDeclarationDefinition(union_type); - ast->AddFieldToRecordType(siginfo_type, "_sifields", union_type, - lldb::eAccessPublic, 0); - - ast->CompleteTagDeclarationDefinition(siginfo_type); - return siginfo_type; + return CompilerType(); } >From 24615119addcdf9fe5a8c5b2ebd0c15d75651279 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sat, 22 Feb 2025 03:42:26 -0600 Subject: [PATCH 37/48] Removed un-needed changes --- lldb/include/lldb/Host/aix/AbstractSocket.h | 25 --------------------- lldb/include/lldb/Host/aix/Uio.h | 23 ------------------- lldb/source/Host/CMakeLists.txt | 1 - lldb/source/Host/aix/AbstractSocket.cpp | 20 ----------------- 4 files changed, 69 deletions(-) delete mode 100644 lldb/include/lldb/Host/aix/AbstractSocket.h delete mode 100644 lldb/include/lldb/Host/aix/Uio.h delete mode 100644 lldb/source/Host/aix/AbstractSocket.cpp diff --git a/lldb/include/lldb/Host/aix/AbstractSocket.h b/lldb/include/lldb/Host/aix/AbstractSocket.h deleted file mode 100644 index accfd01457a5e..0000000000000 --- a/lldb/include/lldb/Host/aix/AbstractSocket.h +++ /dev/null @@ -1,25 +0,0 @@ -//===-- AbstractSocket.h ----------------------------------------*- 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 -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_AbstractSocket_h_ -#define liblldb_AbstractSocket_h_ - -#include "lldb/Host/posix/DomainSocket.h" - -namespace lldb_private { -class AbstractSocket : public DomainSocket { -public: - AbstractSocket(); - -protected: - size_t GetNameOffset() const override; - void DeleteSocketFile(llvm::StringRef name) override; -}; -} - -#endif // ifndef liblldb_AbstractSocket_h_ diff --git a/lldb/include/lldb/Host/aix/Uio.h b/lldb/include/lldb/Host/aix/Uio.h deleted file mode 100644 index acf79ecc6a1d0..0000000000000 --- a/lldb/include/lldb/Host/aix/Uio.h +++ /dev/null @@ -1,23 +0,0 @@ -//===-- Uio.h ---------------------------------------------------*- 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 -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_Host_aix_Uio_h_ -#define liblldb_Host_aix_Uio_h_ - -#include "lldb/Host/Config.h" -#include - -// We shall provide our own implementation of process_vm_readv if it is not -// present -#if !HAVE_PROCESS_VM_READV -ssize_t process_vm_readv(::pid_t pid, const struct iovec *local_iov, - unsigned long liovcnt, const struct iovec *remote_iov, - unsigned long riovcnt, unsigned long flags); -#endif - -#endif // liblldb_Host_aix_Uio_h_ diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index bb6b5befa16e4..5a14b4c629825 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -140,7 +140,6 @@ else() elseif (CMAKE_SYSTEM_NAME MATCHES "AIX") add_host_subdirectory(aix - aix/AbstractSocket.cpp aix/Host.cpp aix/HostInfoAIX.cpp aix/Support.cpp diff --git a/lldb/source/Host/aix/AbstractSocket.cpp b/lldb/source/Host/aix/AbstractSocket.cpp deleted file mode 100644 index fddf78f54f46d..0000000000000 --- a/lldb/source/Host/aix/AbstractSocket.cpp +++ /dev/null @@ -1,20 +0,0 @@ -//===-- AbstractSocket.cpp ------------------------------------------------===// -// -// 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 "lldb/Host/aix/AbstractSocket.h" - -#include "llvm/ADT/StringRef.h" - -using namespace lldb; -using namespace lldb_private; - -AbstractSocket::AbstractSocket() : DomainSocket(ProtocolUnixAbstract) {} - -size_t AbstractSocket::GetNameOffset() const { return 1; } - -void AbstractSocket::DeleteSocketFile(llvm::StringRef name) {} >From 25bea9ca48dc458c1dddd72f10a483e76926a04e Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Wed, 26 Feb 2025 01:10:15 -0600 Subject: [PATCH 38/48] Resolving coredump issue while attach with library calls --- lldb/include/lldb/Core/ModuleSpec.h | 2 ++ lldb/source/Core/ModuleList.cpp | 12 +++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lldb/include/lldb/Core/ModuleSpec.h b/lldb/include/lldb/Core/ModuleSpec.h index 4fe06412b6b0b..9d79992b48c7e 100644 --- a/lldb/include/lldb/Core/ModuleSpec.h +++ b/lldb/include/lldb/Core/ModuleSpec.h @@ -122,6 +122,8 @@ class ModuleSpec { ConstString &GetObjectName() { return m_object_name; } ConstString GetObjectName() const { return m_object_name; } + + void SetObjectName(ConstString objName) { m_object_name = objName; } uint64_t GetObjectOffset() const { return m_object_offset; } diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index 2b8ccab2406c6..862a2729c1afb 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -260,7 +260,17 @@ void ModuleList::ReplaceEquivalent( module_sp->GetArchitecture()); equivalent_module_spec.GetPlatformFileSpec() = module_sp->GetPlatformFileSpec(); - +#ifdef _AIX + // To remove the exact equivalent module, the object name must be + // specified. When the equivalent_module_spec object is created, its + // object name is initially set to NULL. This is because the module_sp's + // GetPath() returns a path in the format (/usr/ccs/libc.a), which does + // not include the object name. As a result, MatchesModuleSpec may return + // true even though the object name is NULL and doesn't match any loaded + // module. To fix this, set the object name of the equivalent_module_spec + // to be the same as the object name of the module_sp. */ + equivalent_module_spec.SetObjectName(module_sp->GetObjectName()); +#endif size_t idx = 0; while (idx < m_modules.size()) { ModuleSP test_module_sp(m_modules[idx]); >From 349ec0064668a0ee1d3af7c2f38fa7427b4b2d36 Mon Sep 17 00:00:00 2001 From: Dhruv Srivastava Date: Fri, 28 Feb 2025 23:44:40 +0530 Subject: [PATCH 39/48] [AIX][Coredump] AIX Coredump debugging Implementation (#25) Creates a general framework to be able to debug an AIX generated coredump file. At this point, we are only supporting 64-bit core files using this general framework. With this implementation, LLDB can recognise and debug any 64-bit AIX coredump file. Most of the generic debugging commands work after this: # bin/lldb --core /home/dhruv/LLDB/tests/core (lldb) target create --core "/home/dhruv/LLDB/tests/core" Core file '/home/dhruv/LLDB/tests/core' (powerpc64) was loaded. (lldb) bt * thread #1, stop reason = SIGSEGV * frame #0: 0x0000000100000940 coretest64`main at core.c:5 frame #1: 0x00000001000004ac coretest64`__start + 116 (lldb) process status Process 18446744071562067991 stopped * thread #1, stop reason = SIGSEGV frame #0: 0x0000000100000940 coretest64`main at core.c:5 2 char *str; 3 int a = 10; 4 str = "GfG"; -> 5 *(str+1) = 'n'; 6 return a; 7 } And others like memory read, image list, image dump sections, disassembly etc --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 62 ++++- .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 6 + .../Plugins/ObjectFile/AIXCore/CMakeLists.txt | 13 + .../ObjectFile/AIXCore/ObjectFileAIXCore.cpp | 254 ++++++++++++++++++ .../ObjectFile/AIXCore/ObjectFileAIXCore.h | 121 +++++++++ lldb/source/Plugins/ObjectFile/CMakeLists.txt | 1 + lldb/source/Plugins/Process/CMakeLists.txt | 1 + .../Plugins/Process/aix-core/AIXCore.cpp | 116 ++++++++ .../source/Plugins/Process/aix-core/AIXCore.h | 125 +++++++++ .../Plugins/Process/aix-core/CMakeLists.txt | 16 ++ .../Process/aix-core/ProcessAIXCore.cpp | 251 +++++++++++++++++ .../Plugins/Process/aix-core/ProcessAIXCore.h | 100 +++++++ .../aix-core/RegisterContextCoreAIX_ppc64.cpp | 136 ++++++++++ .../aix-core/RegisterContextCoreAIX_ppc64.h | 46 ++++ .../Process/aix-core/ThreadAIXCore.cpp | 127 +++++++++ .../Plugins/Process/aix-core/ThreadAIXCore.h | 110 ++++++++ 16 files changed, 1484 insertions(+), 1 deletion(-) create mode 100644 lldb/source/Plugins/ObjectFile/AIXCore/CMakeLists.txt create mode 100644 lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp create mode 100644 lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.h create mode 100644 lldb/source/Plugins/Process/aix-core/AIXCore.cpp create mode 100644 lldb/source/Plugins/Process/aix-core/AIXCore.h create mode 100644 lldb/source/Plugins/Process/aix-core/CMakeLists.txt create mode 100644 lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp create mode 100644 lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h create mode 100644 lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.cpp create mode 100644 lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.h create mode 100644 lldb/source/Plugins/Process/aix-core/ThreadAIXCore.cpp create mode 100644 lldb/source/Plugins/Process/aix-core/ThreadAIXCore.h diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 1a98bb9334043..7e44ffbb1c051 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -228,6 +228,65 @@ void DynamicLoaderAIXDYLD::ResolveExecutableModule( target.SetExecutableModule(module_sp, eLoadDependentsNo); } +bool DynamicLoaderAIXDYLD::IsCoreFile() const { + return !m_process->IsLiveDebugSession(); +} + +void DynamicLoaderAIXDYLD::FillCoreLoaderData(lldb_private::DataExtractor &data, + uint64_t loader_offset, uint64_t loader_size ) { + + static char *buffer = (char *)malloc(loader_size); + struct ld_info ldinfo[64]; + char *buffer_complete; + struct ld_info *ptr; + int i = 0; + + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); + ByteOrder byteorder = data.GetByteOrder(); + data.ExtractBytes(loader_offset, loader_size, eByteOrderBig, buffer); + buffer_complete = buffer + loader_size; + ldinfo[0].ldinfo_next = 1; + + while (ldinfo[i++].ldinfo_next != 0) { + + ptr = (struct ld_info *)buffer; + ldinfo[i].ldinfo_next = ptr->ldinfo_next; + ldinfo[i].ldinfo_flags = ptr->ldinfo_flags; + ldinfo[i].ldinfo_core = ptr->ldinfo_core; + ldinfo[i].ldinfo_textorg = ptr->ldinfo_textorg; + ldinfo[i].ldinfo_textsize = ptr->ldinfo_textsize; + ldinfo[i].ldinfo_dataorg = ptr->ldinfo_dataorg; + ldinfo[i].ldinfo_datasize = ptr->ldinfo_datasize; + + char *filename = &ptr->ldinfo_filename[0]; + char *membername = filename + (strlen(filename) + 1); + strcpy(ldinfo[i].ldinfo_filename, filename); + + buffer += ptr->ldinfo_next; + struct ld_info *ptr2 = &(ldinfo[i]); + char *pathName = ptr2->ldinfo_filename; + char pathWithMember[PATH_MAX] = {0}; + if (strlen(membername) > 0) { + sprintf(pathWithMember, "%s(%s)", pathName, membername); + } else { + sprintf(pathWithMember, "%s", pathName); + } + + FileSpec file(pathWithMember); + ModuleSpec module_spec(file, m_process->GetTarget().GetArchitecture()); + LLDB_LOGF(log, "Module :%s", pathWithMember); + if (ModuleSP module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, true /* notify */)) { + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr2->ldinfo_textorg, false, 1); + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr2->ldinfo_dataorg, false, 2); + // FIXME: .tdata, .bss + } + if (ptr2->ldinfo_next == 0) { + ptr2 = nullptr; + } + } +} + void DynamicLoaderAIXDYLD::DidAttach() { Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); @@ -361,7 +420,8 @@ void DynamicLoaderAIXDYLD::DidLaunch() { #endif } -Status DynamicLoaderAIXDYLD::CanLoadImage() { return Status(); } +Status DynamicLoaderAIXDYLD::CanLoadImage() { + return Status(); } ThreadPlanSP DynamicLoaderAIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h index 0ffbe688e0069..097f8d048b77f 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -33,6 +33,9 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { lldb::addr_t module_addr); void OnUnloadModule(lldb::addr_t module_addr); + void FillCoreLoaderData(lldb_private::DataExtractor &data, + uint64_t loader_offset, uint64_t loader_size); + void DidAttach() override; void DidLaunch() override; Status CanLoadImage() override; @@ -49,6 +52,9 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { /// Loads Module from inferior process. void ResolveExecutableModule(lldb::ModuleSP &module_sp); + /// Returns true if the process is for a core file. + bool IsCoreFile() const; + private: std::map m_loaded_modules; }; diff --git a/lldb/source/Plugins/ObjectFile/AIXCore/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/AIXCore/CMakeLists.txt new file mode 100644 index 0000000000000..5656b33a61726 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/AIXCore/CMakeLists.txt @@ -0,0 +1,13 @@ +add_lldb_library(lldbPluginObjectFileAIXCore PLUGIN + ObjectFileAIXCore.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + lldbTarget + lldbUtility + lldbPluginProcessUtility + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp new file mode 100644 index 0000000000000..5158fa4e25077 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp @@ -0,0 +1,254 @@ +//===-- ObjectFileAIXCore.cpp -------------------------------------------------===// +// +// 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 "ObjectFileAIXCore.h" + +#include +#include +#include +#include + +#include "lldb/Utility/FileSpecList.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Stream.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Object/XCOFFObjectFile.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ObjectFileAIXCore) + +enum CoreVersion : uint64_t {AIXCORE32 = 0xFEEDDB1, AIXCORE64 = 0xFEEDDB2}; + +bool m_is_core = false; + +// Static methods. +void ObjectFileAIXCore::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + CreateMemoryInstance, GetModuleSpecifications); +} + +void ObjectFileAIXCore::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ObjectFile *ObjectFileAIXCore::CreateInstance(const lldb::ModuleSP &module_sp, + DataBufferSP data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t file_offset, + lldb::offset_t length) { + + if(m_is_core) + { + + bool mapped_writable = false; + if (!data_sp) { + data_sp = MapFileDataWritable(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + mapped_writable = true; + } + + assert(data_sp); + + const uint8_t *magic = data_sp->GetBytes() + data_offset; + + // Update the data to contain the entire file if it doesn't already + if (data_sp->GetByteSize() < length) { + data_sp = MapFileDataWritable(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + mapped_writable = true; + magic = data_sp->GetBytes(); + } + + // If we didn't map the data as writable take ownership of the buffer. + if (!mapped_writable) { + data_sp = std::make_shared(data_sp->GetBytes(), + data_sp->GetByteSize()); + data_offset = 0; + magic = data_sp->GetBytes(); + } + + std::unique_ptr objfile_up(new ObjectFileAIXCore( + module_sp, data_sp, data_offset, file, file_offset, length)); + ArchSpec spec = objfile_up->GetArchitecture(); + objfile_up->SetModulesArchitecture(spec); + return objfile_up.release(); + + } +} + +ObjectFile *ObjectFileAIXCore::CreateMemoryInstance( + const lldb::ModuleSP &module_sp, WritableDataBufferSP data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) { + return nullptr; +} + +size_t ObjectFileAIXCore::GetModuleSpecifications( + const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, lldb::offset_t file_offset, + lldb::offset_t length, lldb_private::ModuleSpecList &specs) { + const size_t initial_count = specs.GetSize(); + + if (ObjectFileAIXCore::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) { + // Need new ArchType??? + ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + ModuleSpec spec(file, arch_spec); + spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX); + specs.Append(spec); + } + return specs.GetSize() - initial_count; +} + +static uint32_t AIXCoreHeaderCheckFromMagic(uint32_t magic) { + + Log *log = GetLog(LLDBLog::Modules); + switch (magic) { + case AIXCORE32: + LLDB_LOGF(log, "ObjectFileAIXCore: 32-bit not supported"); + break; + case AIXCORE64: + m_is_core = true; + return 1; + break; + } + return 0; +} + +bool ObjectFileAIXCore::MagicBytesMatch(DataBufferSP &data_sp, + lldb::addr_t data_offset, + lldb::addr_t data_length) { + lldb_private::DataExtractor data; + data.SetData(data_sp, data_offset, data_length); + lldb::offset_t offset = 0; + offset += 4; // Skipping to the coredump version + uint32_t magic = data.GetU32(&offset); + return AIXCoreHeaderCheckFromMagic(magic) != 0; +} + +bool ObjectFileAIXCore::ParseHeader() { + + return false; +} + +ByteOrder ObjectFileAIXCore::GetByteOrder() const { + return eByteOrderBig; +} + +bool ObjectFileAIXCore::IsExecutable() const { + return false; +} + +uint32_t ObjectFileAIXCore::GetAddressByteSize() const { + return 8; +} + +AddressClass ObjectFileAIXCore::GetAddressClass(addr_t file_addr) { + return AddressClass::eUnknown; +} + +lldb::SymbolType ObjectFileAIXCore::MapSymbolType(llvm::object::SymbolRef::Type sym_type) { + if (sym_type == llvm::object::SymbolRef::ST_Function) + return lldb::eSymbolTypeCode; + else if (sym_type == llvm::object::SymbolRef::ST_Data) + return lldb::eSymbolTypeData; + return lldb::eSymbolTypeInvalid; +} + +void ObjectFileAIXCore::ParseSymtab(Symtab &lldb_symtab) { +} + +bool ObjectFileAIXCore::IsStripped() { + return false; +} + +void ObjectFileAIXCore::CreateSections(SectionList &unified_section_list) { +} + +void ObjectFileAIXCore::Dump(Stream *s) { +} + +ArchSpec ObjectFileAIXCore::GetArchitecture() { + ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + return arch_spec; +} + +UUID ObjectFileAIXCore::GetUUID() { + return UUID(); +} + +uint32_t ObjectFileAIXCore::GetDependentModules(FileSpecList &files) { + + auto original_size = files.GetSize(); + return files.GetSize() - original_size; +} + +Address ObjectFileAIXCore::GetImageInfoAddress(Target *target) { + return Address(); +} + +lldb_private::Address ObjectFileAIXCore::GetBaseAddress() { + return lldb_private::Address(); +} +ObjectFile::Type ObjectFileAIXCore::CalculateType() { + return eTypeCoreFile; +} + +ObjectFile::Strata ObjectFileAIXCore::CalculateStrata() { + return eStrataUnknown; +} + +std::vector +ObjectFileAIXCore::GetLoadableData(Target &target) { + std::vector loadables; + return loadables; +} + +lldb::WritableDataBufferSP +ObjectFileAIXCore::MapFileDataWritable(const FileSpec &file, uint64_t Size, + uint64_t Offset) { + return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size, + Offset); +} + +ObjectFileAIXCore::ObjectFileAIXCore(const lldb::ModuleSP &module_sp, + DataBufferSP data_sp, lldb::offset_t data_offset, + const FileSpec *file, lldb::offset_t file_offset, + lldb::offset_t length) + : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset) + { + if (file) + m_file = *file; +} + +ObjectFileAIXCore::ObjectFileAIXCore(const lldb::ModuleSP &module_sp, + DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, + addr_t header_addr) + : ObjectFile(module_sp, process_sp, header_addr, header_data_sp) + { +} diff --git a/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.h b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.h new file mode 100644 index 0000000000000..5dbd78d919bb6 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.h @@ -0,0 +1,121 @@ +//===-- ObjectFileAIXCore.h --------------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_AIXCORE_OBJECTFILEAIXCORE_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_AIXCORE_OBJECTFILEAIXCORE_H + +#include + +#include + +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/UUID.h" +#include "lldb/lldb-private.h" +#include "llvm/Object/XCOFFObjectFile.h" + +/// \class ObjectFileAIXCore +/// Generic AIX CORE object file reader. +/// +/// This class provides a generic AIX Core (32/64 bit) reader plugin implementing +/// the ObjectFile protocol. +class ObjectFileAIXCore : public lldb_private::ObjectFile { +public: + // Static Functions + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "aix-core-obj"; } + + static llvm::StringRef GetPluginDescriptionStatic() { + return "AIX core object file reader."; + } + + static lldb_private::ObjectFile * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length); + + static lldb_private::ObjectFile *CreateMemoryInstance( + const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + + static size_t GetModuleSpecifications(const lldb_private::FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + lldb_private::ModuleSpecList &specs); + + static bool MagicBytesMatch(lldb::DataBufferSP &data_sp, lldb::addr_t offset, + lldb::addr_t length); + + static lldb::SymbolType MapSymbolType(llvm::object::SymbolRef::Type sym_type); + + // PluginInterface protocol + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + // ObjectFile Protocol. + bool ParseHeader() override; + + lldb::ByteOrder GetByteOrder() const override; + + bool IsExecutable() const override; + + uint32_t GetAddressByteSize() const override; + + lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override; + + void ParseSymtab(lldb_private::Symtab &symtab) override; + + bool IsStripped() override; + + void CreateSections(lldb_private::SectionList &unified_section_list) override; + + void Dump(lldb_private::Stream *s) override; + + lldb_private::ArchSpec GetArchitecture() override; + + lldb_private::UUID GetUUID() override; + + uint32_t GetDependentModules(lldb_private::FileSpecList &files) override; + + lldb_private::Address + GetImageInfoAddress(lldb_private::Target *target) override; + lldb_private::Address GetBaseAddress() override; + + ObjectFile::Type CalculateType() override; + + ObjectFile::Strata CalculateStrata() override; + + ObjectFileAIXCore(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + ObjectFileAIXCore(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + +protected: + + static bool ParseAIXCoreHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr + ); + + std::vector + GetLoadableData(lldb_private::Target &target) override; + + static lldb::WritableDataBufferSP + MapFileDataWritable(const lldb_private::FileSpec &file, uint64_t Size, + uint64_t Offset); + +}; + +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_AIXCORE_OBJECTFILEAIXCORE_H diff --git a/lldb/source/Plugins/ObjectFile/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/CMakeLists.txt index 7abd0c96f4fd7..1605356fdb7f1 100644 --- a/lldb/source/Plugins/ObjectFile/CMakeLists.txt +++ b/lldb/source/Plugins/ObjectFile/CMakeLists.txt @@ -9,3 +9,4 @@ add_subdirectory(PECOFF) add_subdirectory(XCOFF) add_subdirectory(Placeholder) add_subdirectory(wasm) +add_subdirectory(AIXCore) diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt index 058b4b9ad2157..0b66ea18c82ce 100644 --- a/lldb/source/Plugins/Process/CMakeLists.txt +++ b/lldb/source/Plugins/Process/CMakeLists.txt @@ -24,3 +24,4 @@ add_subdirectory(elf-core) add_subdirectory(mach-core) add_subdirectory(minidump) add_subdirectory(FreeBSDKernel) +add_subdirectory(aix-core) diff --git a/lldb/source/Plugins/Process/aix-core/AIXCore.cpp b/lldb/source/Plugins/Process/aix-core/AIXCore.cpp new file mode 100644 index 0000000000000..95e47b4d8be53 --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/AIXCore.cpp @@ -0,0 +1,116 @@ +//===-- AIXCore.cpp ------------------------------------------------===// +// +// 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 + +#include "lldb/Core/Section.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" + +#include "AIXCore.h" + +using namespace AIXCORE; +using namespace lldb; +using namespace lldb_private; + +AIXCore64Header::AIXCore64Header() { memset(this, 0, sizeof(AIXCore64Header)); } + + +bool AIXCore64Header::ParseRegisterContext(lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + // The data is arranged in this order in this coredump file + // so we have to fetch in this exact order. But need to change + // the context structure order according to Infos_ppc64 + for(int i = 0; i < 32; i++) + Fault.context.gpr[i] = data.GetU64(offset); + Fault.context.msr = data.GetU64(offset); + Fault.context.pc = data.GetU64(offset); + Fault.context.lr = data.GetU64(offset); + Fault.context.ctr = data.GetU64(offset); + Fault.context.cr = data.GetU32(offset); + Fault.context.xer = data.GetU32(offset); + Fault.context.fpscr = data.GetU32(offset); + Fault.context.fpscrx = data.GetU32(offset); + Fault.context.except[0] = data.GetU64(offset); + for(int i = 0; i < 32; i++) + Fault.context.fpr[i] = data.GetU64(offset); + Fault.context.fpeu = data.GetU8(offset); + Fault.context.fpinfo = data.GetU8(offset); + Fault.context.fpscr24_31 = data.GetU8(offset); + Fault.context.pad[0] = data.GetU8(offset); + Fault.context.excp_type = data.GetU32(offset); + + return true; +} +bool AIXCore64Header::ParseThreadContext(lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + + lldb::offset_t offset_to_regctx = *offset; + offset_to_regctx += sizeof(thrdentry64); + Fault.thread.ti_tid = data.GetU64(offset); + Fault.thread.ti_pid = data.GetU32(offset); + int ret = ParseRegisterContext(data, &offset_to_regctx); + return true; +} + +bool AIXCore64Header::ParseUserData(lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + User.process.pi_pid = data.GetU32(offset); + User.process.pi_ppid = data.GetU32(offset); + User.process.pi_sid = data.GetU32(offset); + User.process.pi_pgrp = data.GetU32(offset); + User.process.pi_uid = data.GetU32(offset); + User.process.pi_suid = data.GetU32(offset); + + *offset += 76; + + ByteOrder byteorder = data.GetByteOrder(); + size_t size = 33; + data.ExtractBytes(*offset, size, byteorder, User.process.pi_comm); + offset += size; + + return true; +} + +bool AIXCore64Header::ParseCoreHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + + SignalNum = data.GetU8(offset); + Flag = data.GetU8(offset); + Entries = data.GetU16(offset); + Version = data.GetU32(offset); + FDInfo = data.GetU64(offset); + + LoaderOffset = data.GetU64(offset); + LoaderSize = data.GetU64(offset); + NumberOfThreads = data.GetU32(offset); + Reserved0 = data.GetU32(offset); + ThreadContextOffset = data.GetU64(offset); + NumSegRegion = data.GetU64(offset); + SegRegionOffset = data.GetU64(offset); + StackOffset = data.GetU64(offset); + StackBaseAddr = data.GetU64(offset); + StackSize = data.GetU64(offset); + DataRegionOffset = data.GetU64(offset); + DataBaseAddr = data.GetU64(offset); + DataSize = data.GetU64(offset); + + *offset += 104; + lldb::offset_t offset_to_user = (*offset + sizeof(ThreadContext64)); + int ret = 0; + ret = ParseThreadContext(data, offset); + ret = ParseUserData(data, &offset_to_user); + + return true; + +} + diff --git a/lldb/source/Plugins/Process/aix-core/AIXCore.h b/lldb/source/Plugins/Process/aix-core/AIXCore.h new file mode 100644 index 0000000000000..3d78d5e92c7ab --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/AIXCore.h @@ -0,0 +1,125 @@ +//===-- AIXCore.h ----------------------------------------*- 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 +// +// Notes about AIX Process core dumps: +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_AIXCORE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_AIXCORE_H + +#include "llvm/ADT/StringRef.h" +#include +#include +#include + +#include +#include + +namespace AIXCORE { + +struct RegContext { + // The data is arranged in order as filled by AIXCore.cpp in this coredump file + // so we have to fetch in that exact order, refer there. + // But need to change + // the context structure in order according to Infos_ppc64 + uint64_t gpr[32]; /* 64-bit gprs */ + unsigned long pc; /* msr */ + unsigned long msr; /* iar */ + unsigned long origr3; /* iar */ + unsigned long ctr; /* CTR */ + unsigned long lr; /* LR */ + unsigned long xer; /* XER */ + unsigned long cr; /* CR */ + unsigned long softe; /* CR */ + unsigned long trap; /* CR */ + unsigned int fpscr; /* floating pt status reg */ + unsigned int fpscrx; /* software ext to fpscr */ + unsigned long except[1]; /* exception address */ + double fpr[32]; /* floating pt regs */ + char fpeu; /* floating pt ever used */ + char fpinfo; /* floating pt info */ + char fpscr24_31; /* bits 24-31 of 64-bit FPSCR */ + char pad[1]; + int excp_type; /* exception type */ +}; + + struct ThreadContext64 { + struct thrdentry64 thread; + struct RegContext context; + }; + + struct UserData { + + struct procentry64 process; + unsigned long long reserved[16]; + }; + + struct AIXCore64Header { + + int8_t SignalNum; /* signal number (cause of error) */ + int8_t Flag; /* flag to describe core dump type */ + uint16_t Entries; /* number of core dump modules */ + uint32_t Version; /* core file format number */ + uint64_t FDInfo; /* offset to fd region in file */ + + uint64_t LoaderOffset; /* offset to loader region in file */ + uint64_t LoaderSize; /* size of loader region */ + + uint32_t NumberOfThreads ; /* number of elements in thread table */ + uint32_t Reserved0; /* Padding */ + uint64_t ThreadContextOffset; /* offset to thread context table */ + + uint64_t NumSegRegion; /* n of elements in segregion */ + uint64_t SegRegionOffset; /* offset to start of segregion table */ + + uint64_t StackOffset; /* offset of user stack in file */ + uint64_t StackBaseAddr; /* base address of user stack region */ + uint64_t StackSize; /* size of user stack region */ + + uint64_t DataRegionOffset; /* offset to user data region */ + uint64_t DataBaseAddr; /* base address of user data region */ + uint64_t DataSize; /* size of user data region */ + uint64_t SDataBase; /* base address of sdata region */ + uint64_t SDataSize; /* size of sdata region */ + + uint64_t NumVMRegions; /* number of anonymously mapped areas */ + uint64_t VMOffset; /* offset to start of vm_infox table */ + + int32_t ProcessorImplementation; /* processor implementation */ + uint32_t NumElementsCTX; /* n of elements in extended ctx table*/ + uint64_t CPRSOffset; /* Checkpoint/Restart offset */ + uint64_t ExtendedContextOffset; /* extended context offset */ + uint64_t OffsetUserKey; /* Offset to user-key exception data */ + uint64_t OffsetLoaderTLS; /* offset to the loader region in file + when a process uses TLS data */ + uint64_t TLSLoaderSize; /* size of the above loader region */ + uint64_t ExtendedProcEntry; /* Extended procentry64 information */ + uint64_t Reserved[2]; + + struct ThreadContext64 Fault; + + struct UserData User; + + AIXCore64Header(); + + bool ParseCoreHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + bool ParseThreadContext(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + bool ParseUserData(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + bool ParseRegisterContext(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + bool ParseLoaderData(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + + }; + + +} + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_AIXCORE_H diff --git a/lldb/source/Plugins/Process/aix-core/CMakeLists.txt b/lldb/source/Plugins/Process/aix-core/CMakeLists.txt new file mode 100644 index 0000000000000..347717a362491 --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/CMakeLists.txt @@ -0,0 +1,16 @@ +add_definitions("-D_ALL_SOURCE") + +add_lldb_library(lldbPluginProcessAIXCore PLUGIN + ProcessAIXCore.cpp + AIXCore.cpp + ThreadAIXCore.cpp + RegisterContextCoreAIX_ppc64.cpp + + LINK_LIBS + lldbCore + lldbTarget + lldbPluginProcessUtility + LINK_COMPONENTS + BinaryFormat + Support + ) diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp new file mode 100644 index 0000000000000..9300aa14ac4db --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp @@ -0,0 +1,251 @@ +//===-- ProcessAIXCore.cpp ------------------------------------------------===// +// +// 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 + +#include +#include + +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Section.h" +#include "lldb/Target/ABI.h" +#include "lldb/Target/DynamicLoader.h" +#include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/UnixSignals.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" + +#include "llvm/Support/Threading.h" +#include "Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h" + +#include "ProcessAIXCore.h" +#include "AIXCore.h" +#include "ThreadAIXCore.h" + +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ProcessAIXCore) + +llvm::StringRef ProcessAIXCore::GetPluginDescriptionStatic() { + return "AIX core dump plug-in."; +} + +void ProcessAIXCore::Initialize() { + static llvm::once_flag g_once_flag; + + llvm::call_once(g_once_flag, []() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); + }); +} + +void ProcessAIXCore::Terminate() { + PluginManager::UnregisterPlugin(ProcessAIXCore::CreateInstance); +} + +lldb::ProcessSP ProcessAIXCore::CreateInstance(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const FileSpec *crash_file, + bool can_connect) { + lldb::ProcessSP process_sp; + if (crash_file && !can_connect) { + const size_t header_size = sizeof(AIXCORE::AIXCore64Header); + + auto data_sp = FileSystem::Instance().CreateDataBuffer( + crash_file->GetPath(), header_size, 0); + + if (data_sp && data_sp->GetByteSize() == header_size) { + AIXCORE::AIXCore64Header aixcore_header; + DataExtractor data(data_sp, lldb::eByteOrderBig, 4); + lldb::offset_t data_offset = 0; + if(aixcore_header.ParseCoreHeader(data, &data_offset)) { + process_sp = std::make_shared(target_sp, listener_sp, + *crash_file); + } + } + + } + return process_sp; +} + +// ProcessAIXCore constructor +ProcessAIXCore::ProcessAIXCore(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const FileSpec &core_file) + : PostMortemProcess(target_sp, listener_sp, core_file) {} + +// Destructor +ProcessAIXCore::~ProcessAIXCore() { + Clear(); + // We need to call finalize on the process before destroying ourselves to + // make sure all of the broadcaster cleanup goes as planned. If we destruct + // this class, then Process::~Process() might have problems trying to fully + // destroy the broadcaster. + Finalize(true /* destructing */); +} + +bool ProcessAIXCore::CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) { + + if (!m_core_module_sp && FileSystem::Instance().Exists(m_core_file)) { + ModuleSpec core_module_spec(m_core_file, target_sp->GetArchitecture()); + Status error(ModuleList::GetSharedModule(core_module_spec, m_core_module_sp, + nullptr, nullptr, nullptr)); + if (m_core_module_sp) { + ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); + if (core_objfile && core_objfile->GetType() == ObjectFile::eTypeCoreFile){ + return true; + } + } + } + return false; + +} + +ArchSpec ProcessAIXCore::GetArchitecture() { + + ArchSpec arch = m_core_module_sp->GetObjectFile()->GetArchitecture(); + + ArchSpec target_arch = GetTarget().GetArchitecture(); + arch.MergeFrom(target_arch); + + return arch; +} + +lldb_private::DynamicLoader *ProcessAIXCore::GetDynamicLoader() { + if (m_dyld_up.get() == nullptr) { + m_dyld_up.reset(DynamicLoader::FindPlugin( + this, DynamicLoaderAIXDYLD::GetPluginNameStatic())); + } + return m_dyld_up.get(); +} + +void ProcessAIXCore::ParseAIXCoreFile() { + + Log *log = GetLog(LLDBLog::Process); + AIXSigInfo siginfo; + ThreadData thread_data; + + const lldb_private::UnixSignals &unix_signals = *GetUnixSignals(); + const ArchSpec &arch = GetArchitecture(); + + siginfo.Parse(m_aixcore_header, arch, unix_signals); + thread_data.siginfo = siginfo; + SetID(m_aixcore_header.User.process.pi_pid); + + thread_data.name.assign (m_aixcore_header.User.process.pi_comm, + strnlen (m_aixcore_header.User.process.pi_comm, + sizeof (m_aixcore_header.User.process.pi_comm))); + + lldb::DataBufferSP data_buffer_sp(new lldb_private::DataBufferHeap(sizeof(m_aixcore_header.Fault.context), 0)); + + memcpy(static_cast(const_cast(data_buffer_sp->GetBytes())), + &m_aixcore_header.Fault.context, sizeof(m_aixcore_header.Fault.context)); + + lldb_private::DataExtractor data(data_buffer_sp, lldb::eByteOrderBig, 8); + + thread_data.gpregset = DataExtractor(data, 0, sizeof(m_aixcore_header.Fault.context)); + m_thread_data.push_back(thread_data); + LLDB_LOGF(log, "ProcessAIXCore: Parsing Complete!"); + +} + +// Process Control +Status ProcessAIXCore::DoLoadCore() { + + Status error; + if (!m_core_module_sp) { + error = Status::FromErrorString("invalid core module"); + return error; + } + + FileSpec file = m_core_module_sp->GetObjectFile()->GetFileSpec(); + + if (file) { + const size_t header_size = sizeof(AIXCORE::AIXCore64Header); + auto data_sp = FileSystem::Instance().CreateDataBuffer( + file.GetPath(), -1, 0); + if (data_sp && data_sp->GetByteSize() != 0) { + + DataExtractor data(data_sp, lldb::eByteOrderBig, 4); + lldb::offset_t data_offset = 0; + m_aixcore_header.ParseCoreHeader(data, &data_offset); + auto dyld = static_cast(GetDynamicLoader()); + dyld->FillCoreLoaderData(data, m_aixcore_header.LoaderOffset, + m_aixcore_header.LoaderSize); + + } else { + error = Status::FromErrorString("invalid data"); + return error; + } + } else { + error = Status::FromErrorString("invalid file"); + return error; + } + + m_thread_data_valid = true; + ParseAIXCoreFile(); + ArchSpec arch(m_core_module_sp->GetArchitecture()); + + ArchSpec target_arch = GetTarget().GetArchitecture(); + ArchSpec core_arch(m_core_module_sp->GetArchitecture()); + target_arch.MergeFrom(core_arch); + GetTarget().SetArchitecture(target_arch); + + lldb::ModuleSP exe_module_sp = GetTarget().GetExecutableModule(); + if (!exe_module_sp) { + ModuleSpec exe_module_spec; + exe_module_spec.GetArchitecture() = arch; + exe_module_spec.GetFileSpec().SetFile(m_aixcore_header.User.process.pi_comm, + FileSpec::Style::native); + exe_module_sp = GetTarget().GetOrCreateModule(exe_module_spec, true); + GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsNo); + } + + return error; +} + +bool ProcessAIXCore::DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) +{ + const ThreadData &td = m_thread_data[0]; + + lldb::ThreadSP thread_sp = + std::make_shared(*this, td); + new_thread_list.AddThread(thread_sp); + + return true; +} + +void ProcessAIXCore::RefreshStateAfterStop() {} + +// Process Memory +size_t ProcessAIXCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size, + Status &error) { + if (lldb::ABISP abi_sp = GetABI()) + addr = abi_sp->FixAnyAddress(addr); + + // Don't allow the caching that lldb_private::Process::ReadMemory does since + // in core files we have it all cached our our core file anyway. + return DoReadMemory(addr, buf, size, error); +} + +size_t ProcessAIXCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, + Status &error) { return 0; } + +Status ProcessAIXCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo ®ion_info) { + return Status(); +} + +Status ProcessAIXCore::DoDestroy() { return Status(); } diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h new file mode 100644 index 0000000000000..9880c491689ca --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h @@ -0,0 +1,100 @@ +//===-- ProcessAIXCore.h ----------------------------------------*- 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 +// +// Notes about AIX Process core dumps: +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_PROCESSAIXCORE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_PROCESSAIXCORE_H + +#include +#include + +#include "lldb/Target/PostMortemProcess.h" +#include "lldb/Utility/Status.h" +#include "lldb/Target/Process.h" +#include "AIXCore.h" +#include "ThreadAIXCore.h" + +struct ThreadData; + +class ProcessAIXCore : public lldb_private::PostMortemProcess { +public: + // Constructors and Destructors + static lldb::ProcessSP + CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, + const lldb_private::FileSpec *crash_file_path, + bool can_connect); + + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "aix-core"; } + + static llvm::StringRef GetPluginDescriptionStatic(); + + // Constructors and Destructors + ProcessAIXCore(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, + const lldb_private::FileSpec &core_file); + + ~ProcessAIXCore() override; + + // PluginInterface protocol + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + // Process Control + lldb_private::Status DoDestroy() override; + + lldb_private::Status WillResume() override { + return lldb_private::Status::FromErrorStringWithFormatv( + "error: {0} does not support resuming processes", GetPluginName()); + } + + bool WarnBeforeDetach() const override { return false; } + + lldb_private::ArchSpec GetArchitecture(); + + bool CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) override; + + // Creating a new process, or attaching to an existing one + lldb_private::Status DoLoadCore() override; + + bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list, + lldb_private::ThreadList &new_thread_list) override; + + lldb_private::Status + DoGetMemoryRegionInfo(lldb::addr_t load_addr, + lldb_private::MemoryRegionInfo ®ion_info) override; + + void RefreshStateAfterStop() override; + + lldb_private::DynamicLoader *GetDynamicLoader() override; + + // Process Memory + size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size, + lldb_private::Status &error) override; + + size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, + lldb_private::Status &error) override; + + void ParseAIXCoreFile(); + + +private: + lldb::ModuleSP m_core_module_sp; + std::string m_dyld_plugin_name; + + // True if m_thread_contexts contains valid entries + bool m_thread_data_valid = false; + AIXCORE::AIXCore64Header m_aixcore_header; + + std::vector m_thread_data; +}; + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_PROCESSAIXCORE_H diff --git a/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.cpp b/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.cpp new file mode 100644 index 0000000000000..b243017bf9a2a --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.cpp @@ -0,0 +1,136 @@ +//===-- RegisterContextCoreAIX_ppc64.cpp ------------------------------===// +// +// 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 "RegisterContextCoreAIX_ppc64.h" + +#include "lldb/Target/Thread.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" + +#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" +#include "Plugins/Process/elf-core/RegisterUtilities.h" + +#include + +using namespace lldb_private; + +RegisterContextCoreAIX_ppc64::RegisterContextCoreAIX_ppc64( + Thread &thread, RegisterInfoInterface *register_info, + const DataExtractor &gpregset) + : RegisterContextPOSIX_ppc64le(thread, 0, register_info) { + m_gpr_buffer = std::make_shared(gpregset.GetDataStart(), + gpregset.GetByteSize()); + m_gpr.SetData(m_gpr_buffer); + m_gpr.SetByteOrder(gpregset.GetByteOrder()); + + // This Code is for Registers like FPR, VSR, VMX and is disabled right now. + // It will be implemented as per need. + + /* ArchSpec arch = register_info->GetTargetArchitecture(); + DataExtractor fpregset;// = getRegset(notes, arch.GetTriple(), FPR_Desc); + m_fpr_buffer = std::make_shared(fpregset.GetDataStart(), + fpregset.GetByteSize()); + m_fpr.SetData(m_fpr_buffer); + m_fpr.SetByteOrder(fpregset.GetByteOrder()); + + DataExtractor vmxregset;// = getRegset(notes, arch.GetTriple(), PPC_VMX_Desc); + m_vmx_buffer = std::make_shared(vmxregset.GetDataStart(), + vmxregset.GetByteSize()); + m_vmx.SetData(m_vmx_buffer); + m_vmx.SetByteOrder(vmxregset.GetByteOrder()); + + DataExtractor vsxregset;// = getRegset(notes, arch.GetTriple(), PPC_VSX_Desc); + m_vsx_buffer = std::make_shared(vsxregset.GetDataStart(), + vsxregset.GetByteSize()); + m_vsx.SetData(m_vsx_buffer); + m_vsx.SetByteOrder(vsxregset.GetByteOrder());*/ +} + +size_t RegisterContextCoreAIX_ppc64::GetFPRSize() const { + return k_num_fpr_registers_ppc64le * sizeof(uint64_t); +} + +size_t RegisterContextCoreAIX_ppc64::GetVMXSize() const { + return (k_num_vmx_registers_ppc64le - 1) * sizeof(uint64_t) * 2 + + sizeof(uint32_t); +} + +size_t RegisterContextCoreAIX_ppc64::GetVSXSize() const { + return k_num_vsx_registers_ppc64le * sizeof(uint64_t) * 2; +} + +bool RegisterContextCoreAIX_ppc64::ReadRegister( + const RegisterInfo *reg_info, RegisterValue &value) { + lldb::offset_t offset = reg_info->byte_offset; + + if (IsFPR(reg_info->kinds[lldb::eRegisterKindLLDB])) { + uint64_t v; + offset -= GetGPRSize(); + offset = m_fpr.CopyData(offset, reg_info->byte_size, &v); + + if (offset == reg_info->byte_size) { + value.SetBytes(&v, reg_info->byte_size, m_fpr.GetByteOrder()); + return true; + } + } else if (IsVMX(reg_info->kinds[lldb::eRegisterKindLLDB])) { + uint32_t v[4]; + offset -= GetGPRSize() + GetFPRSize(); + offset = m_vmx.CopyData(offset, reg_info->byte_size, &v); + + if (offset == reg_info->byte_size) { + value.SetBytes(v, reg_info->byte_size, m_vmx.GetByteOrder()); + return true; + } + } else if (IsVSX(reg_info->kinds[lldb::eRegisterKindLLDB])) { + uint32_t v[4]; + lldb::offset_t tmp_offset; + offset -= GetGPRSize() + GetFPRSize() + GetVMXSize(); + + if (offset < GetVSXSize() / 2) { + tmp_offset = m_vsx.CopyData(offset / 2, reg_info->byte_size / 2, &v); + + if (tmp_offset != reg_info->byte_size / 2) { + return false; + } + + uint8_t *dst = (uint8_t *)&v + sizeof(uint64_t); + tmp_offset = m_fpr.CopyData(offset / 2, reg_info->byte_size / 2, dst); + + if (tmp_offset != reg_info->byte_size / 2) { + return false; + } + + value.SetBytes(&v, reg_info->byte_size, m_vsx.GetByteOrder()); + return true; + } else { + offset = + m_vmx.CopyData(offset - GetVSXSize() / 2, reg_info->byte_size, &v); + if (offset == reg_info->byte_size) { + value.SetBytes(v, reg_info->byte_size, m_vmx.GetByteOrder()); + return true; + } + } + } else { + uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); + + if (offset == reg_info->byte_offset + reg_info->byte_size) { + if (reg_info->byte_size < sizeof(v)) + value = (uint32_t)v; + else + value = v; + return true; + } + } + + return false; +} + +bool RegisterContextCoreAIX_ppc64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue &value) { + return false; +} diff --git a/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.h b/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.h new file mode 100644 index 0000000000000..8f1f71ce8d884 --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.h @@ -0,0 +1,46 @@ +//===-- RegisterContextCoreAIX_ppc64.h ----------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_REGISTERCONTEXTAIXCORE_PPC64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_REGISTERCONTEXTAIXCORE_PPC64_H + +#include "Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h" +#include "lldb/Utility/DataExtractor.h" + +class RegisterContextCoreAIX_ppc64 : public RegisterContextPOSIX_ppc64le { +public: + RegisterContextCoreAIX_ppc64( + lldb_private::Thread &thread, + lldb_private::RegisterInfoInterface *register_info, + const lldb_private::DataExtractor &gpregset); + + bool ReadRegister(const lldb_private::RegisterInfo *reg_info, + lldb_private::RegisterValue &value) override; + + bool WriteRegister(const lldb_private::RegisterInfo *reg_info, + const lldb_private::RegisterValue &value) override; + +protected: + size_t GetFPRSize() const; + + size_t GetVMXSize() const; + + size_t GetVSXSize() const; + +private: + lldb::DataBufferSP m_gpr_buffer; + lldb::DataBufferSP m_fpr_buffer; + lldb::DataBufferSP m_vmx_buffer; + lldb::DataBufferSP m_vsx_buffer; + lldb_private::DataExtractor m_gpr; + lldb_private::DataExtractor m_fpr; + lldb_private::DataExtractor m_vmx; + lldb_private::DataExtractor m_vsx; +}; + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_REGISTERCONTEXTAIXCORE_PPC64_H diff --git a/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.cpp b/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.cpp new file mode 100644 index 0000000000000..979e5199fe24d --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.cpp @@ -0,0 +1,127 @@ +//===-- ThreadAIXCore.cpp -------------------------------------------------===// +// +// 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 "lldb/Target/RegisterContext.h" +#include "lldb/Target/StopInfo.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/UnixSignals.h" +#include "lldb/Target/Unwind.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/ProcessInfo.h" + +#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h" +#include "Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h" +#include "RegisterContextCoreAIX_ppc64.h" + +#include "ProcessAIXCore.h" +#include "AIXCore.h" +#include "ThreadAIXCore.h" + +#include +#include + +using namespace lldb; +using namespace lldb_private; + +// Construct a Thread object with given data +ThreadAIXCore::ThreadAIXCore(Process &process, const ThreadData &td) + : Thread(process, td.tid), m_thread_name(td.name), m_thread_reg_ctx_sp(), + m_gpregset_data(td.gpregset), + m_siginfo(std::move(td.siginfo)) {} + +ThreadAIXCore::~ThreadAIXCore() { DestroyThread(); } + +void ThreadAIXCore::RefreshStateAfterStop() { + GetRegisterContext()->InvalidateIfNeeded(false); +} + +RegisterContextSP ThreadAIXCore::GetRegisterContext() { + if (!m_reg_context_sp) { + m_reg_context_sp = CreateRegisterContextForFrame(nullptr); + } + return m_reg_context_sp; +} + +RegisterContextSP +ThreadAIXCore::CreateRegisterContextForFrame(StackFrame *frame) { + RegisterContextSP reg_ctx_sp; + uint32_t concrete_frame_idx = 0; + + if (frame) + concrete_frame_idx = frame->GetConcreteFrameIndex(); + + bool is_linux = false; + if (concrete_frame_idx == 0) { + if (m_thread_reg_ctx_sp) + return m_thread_reg_ctx_sp; + + ProcessAIXCore *process = static_cast(GetProcess().get()); + ArchSpec arch = process->GetArchitecture(); + RegisterInfoInterface *reg_interface = nullptr; + + switch (arch.GetMachine()) { + case llvm::Triple::ppc64: + reg_interface = new RegisterInfoPOSIX_ppc64le(arch); + m_thread_reg_ctx_sp = std::make_shared( + *this, reg_interface, m_gpregset_data); + break; + default: + break; + } + reg_ctx_sp = m_thread_reg_ctx_sp; + } else { + reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame); + } + return reg_ctx_sp; +} + +bool ThreadAIXCore::CalculateStopInfo() { + ProcessSP process_sp(GetProcess()); + if (!process_sp) + return false; + + lldb::UnixSignalsSP unix_signals_sp(process_sp->GetUnixSignals()); + if (!unix_signals_sp) + return false; + + const char *sig_description; + std::string description = m_siginfo.GetDescription(*unix_signals_sp); + if (description.empty()) + sig_description = nullptr; + else + sig_description = description.c_str(); + + SetStopInfo(StopInfo::CreateStopReasonWithSignal( + *this, m_siginfo.si_signo, sig_description, m_siginfo.si_code)); + + SetStopInfo(m_stop_info_sp); + return true; +} + +void AIXSigInfo::Parse(const AIXCORE::AIXCore64Header data, const ArchSpec &arch, + const lldb_private::UnixSignals &unix_signals) { + si_signo = data.SignalNum; + sigfault.si_addr = data.Fault.context.pc; +} + +AIXSigInfo::AIXSigInfo() { memset(this, 0, sizeof(AIXSigInfo)); } + +size_t AIXSigInfo::GetSize(const lldb_private::ArchSpec &arch) { + return sizeof(AIXSigInfo); +} + +std::string AIXSigInfo::GetDescription( + const lldb_private::UnixSignals &unix_signals) const { + return unix_signals.GetSignalDescription(si_signo, 0, + sigfault.si_addr); + +} diff --git a/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.h b/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.h new file mode 100644 index 0000000000000..9ee157e9b2b9b --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.h @@ -0,0 +1,110 @@ +//===-- ThreadAIXCore.h -----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_THREADAIXCORE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_THREADAIXCORE_H + +#include "lldb/Target/Thread.h" +#include "lldb/Utility/DataExtractor.h" +#include "llvm/ADT/DenseMap.h" +#include +#include +#include "ProcessAIXCore.h" +#include "AIXCore.h" +#include "ThreadAIXCore.h" + +namespace lldb_private { +class ProcessInstanceInfo; +} + +struct AIXSigInfo { + + //COPY siginfo_t correctly for AIX version + int32_t si_signo; // Order matters for the first 3. + int32_t si_errno; + int32_t si_code; + struct alignas(8) { + lldb::addr_t si_addr; + int16_t si_addr_lsb; + union { + struct { + lldb::addr_t _lower; + lldb::addr_t _upper; + } _addr_bnd; + uint32_t _pkey; + } bounds; + } sigfault; + + enum SigInfoNoteType : uint8_t { eUnspecified, eNT_SIGINFO }; + SigInfoNoteType note_type; + + AIXSigInfo(); + + void Parse(const AIXCORE::AIXCore64Header data, + const lldb_private::ArchSpec &arch, + const lldb_private::UnixSignals &unix_signals); + + std::string + GetDescription(const lldb_private::UnixSignals &unix_signals) const; + + static size_t GetSize(const lldb_private::ArchSpec &arch); +}; + +struct ThreadData { + lldb_private::DataExtractor gpregset; + std::vector notes; + lldb::tid_t tid; + std::string name; + AIXSigInfo siginfo; + int prstatus_sig = 0; +}; + +class ThreadAIXCore : public lldb_private::Thread { +public: + ThreadAIXCore(lldb_private::Process &process, const ThreadData &td); + + ~ThreadAIXCore() override; + + void RefreshStateAfterStop() override; + + lldb::RegisterContextSP GetRegisterContext() override; + + lldb::RegisterContextSP + CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override; + + static bool ThreadIDIsValid(lldb::tid_t thread) { return thread != 0; } + + const char *GetName() override { + if (m_thread_name.empty()) + return nullptr; + return m_thread_name.c_str(); + } + + void SetName(const char *name) override { + if (name && name[0]) + m_thread_name.assign(name); + else + m_thread_name.clear(); + } + + void CreateStopFromSigInfo(const AIXSigInfo &siginfo, + const lldb_private::UnixSignals &unix_signals); + +protected: + // Member variables. + std::string m_thread_name; + lldb::RegisterContextSP m_thread_reg_ctx_sp; + + lldb_private::DataExtractor m_gpregset_data; + std::vector m_notes; + AIXSigInfo m_siginfo; + + bool CalculateStopInfo() override; +}; + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_THREADAIXCORE_H >From 57cb8058646103eeada1f92e039d9c54ccd4788f Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 17 Mar 2025 07:31:26 -0500 Subject: [PATCH 40/48] Merge branch 'llvm:main' into llvmgh-101657 --- lldb/cmake/modules/LLDBConfig.cmake | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake index 312791ce36fc7..9df71edd8b359 100644 --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -292,11 +292,7 @@ endif() # Figure out if lldb could use lldb-server. If so, then we'll # ensure we build lldb-server when an lldb target is being built. -<<<<<<< HEAD -if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD|OpenBSD|Windows|AIX") -======= if (CMAKE_SYSTEM_NAME MATCHES "AIX|Android|Darwin|FreeBSD|Linux|NetBSD|OpenBSD|Windows") ->>>>>>> upstream/main set(LLDB_CAN_USE_LLDB_SERVER ON) else() set(LLDB_CAN_USE_LLDB_SERVER OFF) >From 0767ef036d3f82d1429e04a319feb6627ea08158 Mon Sep 17 00:00:00 2001 From: Dhruv Srivastava Date: Tue, 18 Mar 2025 15:03:17 +0530 Subject: [PATCH 41/48] Error Handling (#32) * Error Handling for aix core module --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 12 +++++++----- .../ObjectFile/AIXCore/ObjectFileAIXCore.cpp | 15 +++++++-------- lldb/source/Plugins/Process/aix-core/AIXCore.cpp | 2 +- .../Plugins/Process/aix-core/ProcessAIXCore.cpp | 11 ++++++++--- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 7e44ffbb1c051..12f24c049f373 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -235,17 +235,19 @@ bool DynamicLoaderAIXDYLD::IsCoreFile() const { void DynamicLoaderAIXDYLD::FillCoreLoaderData(lldb_private::DataExtractor &data, uint64_t loader_offset, uint64_t loader_size ) { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); static char *buffer = (char *)malloc(loader_size); - struct ld_info ldinfo[64]; - char *buffer_complete; + if (buffer == NULL) { + LLDB_LOG(log, "Buffer allocation failed error: {0}", std::strerror(errno)); + return; + } + struct ld_info ldinfo[64] = {}; struct ld_info *ptr; int i = 0; - Log *log = GetLog(LLDBLog::DynamicLoader); - LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); ByteOrder byteorder = data.GetByteOrder(); data.ExtractBytes(loader_offset, loader_size, eByteOrderBig, buffer); - buffer_complete = buffer + loader_size; ldinfo[0].ldinfo_next = 1; while (ldinfo[i++].ldinfo_next != 0) { diff --git a/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp index 5158fa4e25077..0ba1056866937 100644 --- a/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp +++ b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp @@ -73,8 +73,6 @@ ObjectFile *ObjectFileAIXCore::CreateInstance(const lldb::ModuleSP &module_sp, assert(data_sp); - const uint8_t *magic = data_sp->GetBytes() + data_offset; - // Update the data to contain the entire file if it doesn't already if (data_sp->GetByteSize() < length) { data_sp = MapFileDataWritable(*file, length, file_offset); @@ -82,7 +80,6 @@ ObjectFile *ObjectFileAIXCore::CreateInstance(const lldb::ModuleSP &module_sp, return nullptr; data_offset = 0; mapped_writable = true; - magic = data_sp->GetBytes(); } // If we didn't map the data as writable take ownership of the buffer. @@ -90,7 +87,6 @@ ObjectFile *ObjectFileAIXCore::CreateInstance(const lldb::ModuleSP &module_sp, data_sp = std::make_shared(data_sp->GetBytes(), data_sp->GetByteSize()); data_offset = 0; - magic = data_sp->GetBytes(); } std::unique_ptr objfile_up(new ObjectFileAIXCore( @@ -124,19 +120,22 @@ size_t ObjectFileAIXCore::GetModuleSpecifications( return specs.GetSize() - initial_count; } -static uint32_t AIXCoreHeaderCheckFromMagic(uint32_t magic) { +static bool AIXCoreHeaderCheckFromMagic(uint32_t magic) { Log *log = GetLog(LLDBLog::Modules); + bool ret = false; switch (magic) { case AIXCORE32: LLDB_LOGF(log, "ObjectFileAIXCore: 32-bit not supported"); break; case AIXCORE64: m_is_core = true; - return 1; + ret = true; + break; + default: break; } - return 0; + return ret; } bool ObjectFileAIXCore::MagicBytesMatch(DataBufferSP &data_sp, @@ -147,7 +146,7 @@ bool ObjectFileAIXCore::MagicBytesMatch(DataBufferSP &data_sp, lldb::offset_t offset = 0; offset += 4; // Skipping to the coredump version uint32_t magic = data.GetU32(&offset); - return AIXCoreHeaderCheckFromMagic(magic) != 0; + return AIXCoreHeaderCheckFromMagic(magic); } bool ObjectFileAIXCore::ParseHeader() { diff --git a/lldb/source/Plugins/Process/aix-core/AIXCore.cpp b/lldb/source/Plugins/Process/aix-core/AIXCore.cpp index 95e47b4d8be53..bc496b5af273f 100644 --- a/lldb/source/Plugins/Process/aix-core/AIXCore.cpp +++ b/lldb/source/Plugins/Process/aix-core/AIXCore.cpp @@ -110,7 +110,7 @@ bool AIXCore64Header::ParseCoreHeader(lldb_private::DataExtractor &data, ret = ParseThreadContext(data, offset); ret = ParseUserData(data, &offset_to_user); - return true; + return ret; } diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp index 9300aa14ac4db..cfcbe1a216116 100644 --- a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp @@ -208,8 +208,10 @@ Status ProcessAIXCore::DoLoadCore() { exe_module_spec.GetArchitecture() = arch; exe_module_spec.GetFileSpec().SetFile(m_aixcore_header.User.process.pi_comm, FileSpec::Style::native); - exe_module_sp = GetTarget().GetOrCreateModule(exe_module_spec, true); - GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsNo); + exe_module_sp = + GetTarget().GetOrCreateModule(exe_module_spec, true /* notify */); + if (exe_module_sp) + GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsNo); } return error; @@ -232,8 +234,11 @@ void ProcessAIXCore::RefreshStateAfterStop() {} // Process Memory size_t ProcessAIXCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size, Status &error) { + if(addr == LLDB_INVALID_ADDRESS) + return 0; + if (lldb::ABISP abi_sp = GetABI()) - addr = abi_sp->FixAnyAddress(addr); + addr = abi_sp->FixAnyAddress(addr); // Don't allow the caching that lldb_private::Process::ReadMemory does since // in core files we have it all cached our our core file anyway. >From 8214e5d8cc52b486d3c3f5f4615848b1782cfcf8 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 26 Mar 2025 01:34:36 -0500 Subject: [PATCH 42/48] Merge branch 'llvm:main' into gh-101657 --- lldb/source/Host/common/Host.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 575bb46216d19..6cf1112511c3f 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -20,7 +20,6 @@ #include #include #include -#endif #include #endif >From d00d28ae68c731efe6f9392000be9822ee74ff0a Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Wed, 26 Mar 2025 04:08:23 -0500 Subject: [PATCH 43/48] First time attach resolution --- .../Plugins/Process/AIX/NativeProcessAIX.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp index fc84763857453..83b8ae5eb3258 100644 --- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -2000,7 +2000,21 @@ Status NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid, void *addr, } else if (req == PT_WRITE_BLOCK) { ptrace64(req, pid, (long long)addr, (int)data_size, (int *)result); } else if (req == PT_ATTACH) { + // Block SIGCHLD signal during attach to the process, + // to prevent interruptions. + // The ptrace operation may send SIGCHLD signals in certain cases + // during the attach, which can interfere. + static sigset_t signal_set; + sigemptyset (&signal_set); + sigaddset (&signal_set, SIGCHLD); + if(!pthread_sigmask( SIG_BLOCK, &signal_set, NULL)) + LLDB_LOG(log,"NativeProcessAIX::pthread_sigmask(SIG_BLOCK) Failed"); + ptrace64(req, pid, 0, 0, nullptr); + + //Unblocking the SIGCHLD after attach work. + if(!pthread_sigmask( SIG_UNBLOCK, &signal_set, NULL )) + LLDB_LOG(log,"NativeProcessAIX::pthread_sigmask(SIG_UNBLOCK) Failed"); } else if (req == PT_WATCH) { ptrace64(req, pid, (long long)addr, (int)data_size, nullptr); } else if (req == PT_DETACH) { >From 9ff945e62a906e9711022bf8f77b86a0aa05c64e Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Tue, 1 Apr 2025 04:54:51 -0500 Subject: [PATCH 44/48] Invalid DWARF rangelist --- lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index cf11e5fb8f5a3..65bd1ee9781d8 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -578,6 +578,7 @@ SectionType ObjectFileXCOFF::GetSectionType(llvm::StringRef sect_name, .Case(".dwinfo", eSectionTypeDWARFDebugInfo) .Case(".dwline", eSectionTypeDWARFDebugLine) .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev) + .Case(".dwrnges", eSectionTypeDWARFDebugRanges) .Default(eSectionTypeInvalid); if (section_type != eSectionTypeInvalid) >From b443dd5b26354da73cd4d785a093d9d1582b25a8 Mon Sep 17 00:00:00 2001 From: Dhruv Srivastava Date: Wed, 2 Apr 2025 11:57:28 +0530 Subject: [PATCH 45/48] Fix for stack memory access from core file (#40) * Fix for stack memory access in core file --- .../Process/aix-core/ProcessAIXCore.cpp | 74 ++++++++++++++++++- .../Plugins/Process/aix-core/ProcessAIXCore.h | 11 +++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp index cfcbe1a216116..bb2db66e2980e 100644 --- a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp @@ -94,6 +94,33 @@ ProcessAIXCore::~ProcessAIXCore() { Finalize(true /* destructing */); } +lldb::addr_t ProcessAIXCore::AddAddressRanges(AIXCORE::AIXCore64Header header) { + const lldb::addr_t addr = header.StackBaseAddr; + FileRange file_range(header.StackOffset, header.StackSize); + VMRangeToFileOffset::Entry range_entry(addr, header.StackSize, file_range); + + if (header.StackSize > 0) { + VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back(); + if (last_entry && + last_entry->GetRangeEnd() == range_entry.GetRangeBase() && + last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase() && + last_entry->GetByteSize() == last_entry->data.GetByteSize()) { + last_entry->SetRangeEnd(range_entry.GetRangeEnd()); + last_entry->data.SetRangeEnd(range_entry.data.GetRangeEnd()); + } else { + m_core_aranges.Append(range_entry); + } + } + + const uint32_t permissions = lldb::ePermissionsReadable | + lldb::ePermissionsWritable; + + m_core_range_infos.Append( + VMRangeToPermissions::Entry(addr, header.StackSize, permissions)); + + return addr; +} + bool ProcessAIXCore::CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) { @@ -170,6 +197,7 @@ Status ProcessAIXCore::DoLoadCore() { } FileSpec file = m_core_module_sp->GetObjectFile()->GetFileSpec(); + Log *log = GetLog(LLDBLog::Process); if (file) { const size_t header_size = sizeof(AIXCORE::AIXCore64Header); @@ -180,6 +208,9 @@ Status ProcessAIXCore::DoLoadCore() { DataExtractor data(data_sp, lldb::eByteOrderBig, 4); lldb::offset_t data_offset = 0; m_aixcore_header.ParseCoreHeader(data, &data_offset); + lldb::addr_t addr = AddAddressRanges(m_aixcore_header); + if (addr == LLDB_INVALID_ADDRESS) + LLDB_LOGF(log, "ProcessAIXCore: Invalid base address. Stack information will be limited"); auto dyld = static_cast(GetDynamicLoader()); dyld->FillCoreLoaderData(data, m_aixcore_header.LoaderOffset, m_aixcore_header.LoaderSize); @@ -246,7 +277,48 @@ size_t ProcessAIXCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size, } size_t ProcessAIXCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, - Status &error) { return 0; } + Status &error) { + ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); + if (core_objfile == nullptr) + return 0; + // Get the address range + const VMRangeToFileOffset::Entry *address_range = + m_core_aranges.FindEntryThatContains(addr); + if (address_range == nullptr || address_range->GetRangeEnd() < addr) { + error = Status::FromErrorStringWithFormat( + "core file does not contain 0x%" PRIx64, addr); + return 0; + } + + // Convert the address into core file offset + const lldb::addr_t offset = addr - address_range->GetRangeBase(); + const lldb::addr_t file_start = address_range->data.GetRangeBase(); + const lldb::addr_t file_end = address_range->data.GetRangeEnd(); + size_t bytes_to_read = size; // Number of bytes to read from the core file + size_t bytes_copied = 0; // Number of bytes actually read from the core file + // Number of bytes available in the core file from the given address + lldb::addr_t bytes_left = 0; + + // Don't proceed if core file doesn't contain the actual data for this + // address range. + if (file_start == file_end) + return 0; + + // Figure out how many on-disk bytes remain in this segment starting at the + // given offset + if (file_end > file_start + offset) + bytes_left = file_end - (file_start + offset); + + if (bytes_to_read > bytes_left) + bytes_to_read = bytes_left; + + // If there is data available on the core file read it + if (bytes_to_read) + bytes_copied = + core_objfile->CopyData(offset + file_start, bytes_to_read, buf); + + return bytes_copied; +} Status ProcessAIXCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo ®ion_info) { diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h index 9880c491689ca..ffd9e401ee192 100644 --- a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h @@ -85,11 +85,22 @@ class ProcessAIXCore : public lldb_private::PostMortemProcess { void ParseAIXCoreFile(); + lldb::addr_t AddAddressRanges(AIXCORE::AIXCore64Header header); private: lldb::ModuleSP m_core_module_sp; std::string m_dyld_plugin_name; + typedef lldb_private::Range FileRange; + typedef lldb_private::RangeDataVector + VMRangeToFileOffset; + typedef lldb_private::RangeDataVector + VMRangeToPermissions; + + // Address ranges found in the core + VMRangeToFileOffset m_core_aranges; + VMRangeToPermissions m_core_range_infos; + // True if m_thread_contexts contains valid entries bool m_thread_data_valid = false; AIXCORE::AIXCore64Header m_aixcore_header; >From 96db5e3257436a222ee38049528d682166421fa1 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 2 Apr 2025 01:46:46 -0500 Subject: [PATCH 46/48] Build fail: SBMutex --- lldb/source/API/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index 0045edf6743d1..2c8f2d583c054 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -83,6 +83,7 @@ add_lldb_library(liblldb STATIC ${option_framework} SBMemoryRegionInfoList.cpp SBModule.cpp SBModuleSpec.cpp + SBMutex.cpp SBPlatform.cpp SBProcess.cpp SBProgress.cpp >From d7a892ef207cde5430021b8705279cc08dc4e0f7 Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Wed, 30 Apr 2025 04:53:28 -0500 Subject: [PATCH 47/48] Added change for step command issue --- .../Plugins/Process/AIX/NativeProcessAIX.cpp | 87 +++++++++++++------ 1 file changed, 61 insertions(+), 26 deletions(-) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp index 83b8ae5eb3258..ace9e11927bee 100644 --- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -19,7 +19,7 @@ #include #include #include - +#include #include "NativeThreadAIX.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" //#include "Plugins/Process/Utility/LinuxProcMaps.h" @@ -79,6 +79,7 @@ using namespace lldb_private; using namespace lldb_private::process_aix; using namespace llvm; +typedef std::function)> AIXMapCallback; // Private bits we only need internally. static bool ProcessVmReadvSupported() { @@ -988,13 +989,6 @@ Status NativeProcessAIX::GetMemoryRegionInfo(lldb::addr_t load_addr, for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end(); ++it) { MemoryRegionInfo &proc_entry_info = it->first; - - // Sanity check assumption that /proc/{pid}/maps entries are ascending. - assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) && - "descending /proc/pid/maps entries detected, unexpected"); - prev_base_address = proc_entry_info.GetRange().GetRangeBase(); - UNUSED_IF_ASSERT_DISABLED(prev_base_address); - // If the target address comes before this entry, indicate distance to next // region. if (load_addr < proc_entry_info.GetRange().GetRangeBase()) { @@ -1029,9 +1023,59 @@ Status NativeProcessAIX::GetMemoryRegionInfo(lldb::addr_t load_addr, return error; } +// Parsing the AIX map file /proc/PID/map +// The map file contains an array of prmap structures +// which has all the information like size, startaddress, object name, permissions +bool ParseAIXMapRegions(const char *aix_map, AIXMapCallback const &callback) { + MemoryRegionInfo region; + struct prmap *prmapData = (struct prmap *)aix_map; + struct prmap *entry; + uint32_t perm_flag; + + for(entry = prmapData;!(entry->pr_size == 0 && entry->pr_vaddr == NULL); entry++) { + const char *o_name = aix_map + entry->pr_pathoff; + lldb::addr_t start_address = (lldb::addr_t )entry->pr_vaddr; + lldb::addr_t end_address = start_address + entry->pr_size; + region.GetRange().SetRangeBase(start_address); + region.GetRange().SetRangeEnd(end_address); + region.SetMapped(MemoryRegionInfo::OptionalBool::eYes); + perm_flag = entry->pr_mflags; + + if(perm_flag & MA_READ) + region.SetReadable(MemoryRegionInfo::OptionalBool::eYes); + else + region.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + + if(perm_flag & MA_WRITE) + region.SetWritable(MemoryRegionInfo::OptionalBool::eYes); + else + region.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + + if(perm_flag & MA_EXEC) + region.SetExecutable(MemoryRegionInfo::OptionalBool::eYes); + else + region.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + + if((perm_flag & MA_SLIBTEXT) || (perm_flag & MA_SLIBDATA)) + region.SetShared(MemoryRegionInfo::OptionalBool::eYes); + else if ((perm_flag & MA_PLIBTEXT) || (perm_flag & MA_PLIBDATA)) + region.SetShared(MemoryRegionInfo::OptionalBool::eNo); + else + region.SetShared(MemoryRegionInfo::OptionalBool::eDontKnow); + + if(o_name) + region.SetName(o_name); + + callback(region); + region.Clear(); + } + + return true; +} + + Status NativeProcessAIX::PopulateMemoryRegionCache() { Log *log = GetLog(POSIXLog::Process); - // If our cache is empty, pull the latest. There should always be at least // one memory region if memory region handling is supported. if (!m_mem_region_cache.empty()) { @@ -1041,7 +1085,7 @@ Status NativeProcessAIX::PopulateMemoryRegionCache() { } Status Result; -#if 0 + AIXMapCallback callback = [&](llvm::Expected Info) { if (Info) { FileSpec file_spec(Info->GetName().GetCString()); @@ -1050,26 +1094,17 @@ Status NativeProcessAIX::PopulateMemoryRegionCache() { return true; } - Result = Info.takeError(); + Result = Status::FromError(Info.takeError()); m_supports_mem_region = LazyBool::eLazyBoolNo; LLDB_LOG(log, "failed to parse proc maps: {0}", Result); return false; }; - // AIX kernel since 2.6.14 has /proc/{pid}/smaps - // if CONFIG_PROC_PAGE_MONITOR is enabled - auto BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "smaps"); - if (BufferOrError) - ParseAIXSMapRegions(BufferOrError.get()->getBuffer(), callback); - else { - BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "maps"); - if (!BufferOrError) { - m_supports_mem_region = LazyBool::eLazyBoolNo; - return BufferOrError.getError(); - } - - ParseAIXMapRegions(BufferOrError.get()->getBuffer(), callback); - } + auto BufferOrError = getProcFile(GetID(), "map"); + if (BufferOrError) { + std::unique_ptr MapBuffer = std::move(*BufferOrError); + ParseAIXMapRegions(MapBuffer->getBufferStart(), callback); + } if (Result.Fail()) return Result; @@ -1090,7 +1125,7 @@ Status NativeProcessAIX::PopulateMemoryRegionCache() { // We support memory retrieval, remember that. m_supports_mem_region = LazyBool::eLazyBoolYes; -#endif + return Status(); } >From 09e392a16dba25a5a8ddccf7893289a0a8798a3b Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Wed, 14 May 2025 00:52:06 -0500 Subject: [PATCH 48/48] Removing netbsd license dependency --- lldb/source/Host/common/Host.cpp | 165 ++----------------------------- 1 file changed, 7 insertions(+), 158 deletions(-) diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 6cf1112511c3f..7444163366fe5 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -349,168 +349,16 @@ bool Host::ResolveExecutableInBundle(FileSpec &file) { return false; } #include extern char **p_xargv; -/* Fix missing Dl_info & dladdr in AIX - * The code is taken from netbsd.org (src/crypto/external/bsd/openssl/dist/crypto/dso/dso_dlfcn.c) - * except strlcpy & strlcat (those are taken from openbsd.org (src/lib/libc/string)) - */ -/*- - * See IBM's AIX Version 7.2, Technical Reference: - * Base Operating System and Extensions, Volume 1 and 2 - * https://www.ibm.com/support/knowledgecenter/ssw_aix_72/com.ibm.aix.base/technicalreferences.htm - */ -#include -#include - -/* strlcpy: - * Copy string src to buffer dst of size dsize. At most dsize-1 - * chars will be copied. Always NUL terminates (unless dsize == 0). - * Returns strlen(src); if retval >= dsize, truncation occurred. - */ -size_t strlcpy(char *dst, const char *src, size_t dsize) -{ - const char *osrc = src; - size_t nleft = dsize; - - /* Copy as many bytes as will fit. */ - if (nleft != 0) { - while (--nleft != 0) { - if ((*dst++ = *src++) == '\0') { - break; - } - } - } - - /* Not enough room in dst, add NUL and traverse rest of src. */ - if (nleft == 0) { - if (dsize != 0) { - *dst = '\0'; /* NUL-terminate dst */ - } - while (*src++) { - ; - } - } - - return src - osrc - 1; /* count does not include NUL */ -} - -/* strlcat: - * Appends src to string dst of size dsize (unlike strncat, dsize is the - * full size of dst, not space left). At most dsize-1 characters - * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). - * Returns strlen(src) + MIN(dsize, strlen(initial dst)). - * If retval >= dsize, truncation occurred. - */ -size_t strlcat(char *dst, const char *src, size_t dsize) -{ - const char *odst = dst; - const char *osrc = src; - size_t n = dsize; - size_t dlen; - - /* Find the end of dst and adjust bytes left but don't go past end. */ - while (n-- != 0 && *dst != '\0') { - dst++; - } - dlen = dst - odst; - n = dsize - dlen; - - if (n-- == 0) { - return dlen + strlen(src); - } - while (*src != '\0') { - if (n != 0) { - *dst++ = *src; - n--; - } - src++; - } - *dst = '\0'; - - return dlen + src - osrc; /* count does not include NUL */ -} - -/* ~ 64 * (sizeof(struct ld_info) + _XOPEN_PATH_MAX + _XOPEN_NAME_MAX) */ -# define DLFCN_LDINFO_SIZE 86976 -typedef struct Dl_info { - const char *dli_fname; -} Dl_info; -/* - * This dladdr()-implementation will also find the ptrgl (Pointer Glue) virtual - * address of a function, which is just located in the DATA segment instead of - * the TEXT segment. - */ -static int dladdr(const void *ptr, Dl_info *dl) -{ - uintptr_t addr = (uintptr_t)ptr; - struct ld_info *ldinfos; - struct ld_info *next_ldi; - struct ld_info *this_ldi; - - if ((ldinfos = (struct ld_info *)malloc(DLFCN_LDINFO_SIZE)) == NULL) { - dl->dli_fname = NULL; - return 0; - } - - if ((loadquery(L_GETINFO, (void *)ldinfos, DLFCN_LDINFO_SIZE)) < 0) { - /*- - * Error handling is done through errno and dlerror() reading errno: - * ENOMEM (ldinfos buffer is too small), - * EINVAL (invalid flags), - * EFAULT (invalid ldinfos ptr) - */ - free((void *)ldinfos); - dl->dli_fname = NULL; - return 0; - } - next_ldi = ldinfos; - - do { - this_ldi = next_ldi; - if (((addr >= (uintptr_t)this_ldi->ldinfo_textorg) - && (addr < ((uintptr_t)this_ldi->ldinfo_textorg + - this_ldi->ldinfo_textsize))) - || ((addr >= (uintptr_t)this_ldi->ldinfo_dataorg) - && (addr < ((uintptr_t)this_ldi->ldinfo_dataorg + - this_ldi->ldinfo_datasize)))) { - char *buffer = NULL; - char *member = NULL; - size_t buffer_sz; - size_t member_len; - - buffer_sz = strlen(this_ldi->ldinfo_filename) + 1; - member = this_ldi->ldinfo_filename + buffer_sz; - if ((member_len = strlen(member)) > 0) { - buffer_sz += 1 + member_len + 1; - } - if ((buffer = (char *)malloc(buffer_sz)) != NULL) { - strlcpy(buffer, this_ldi->ldinfo_filename, buffer_sz); - if (member_len > 0) { - /* - * Need to respect a possible member name and not just - * returning the path name in this case. See docs: - * sys/ldr.h, loadquery() and dlopen()/RTLD_MEMBER. - */ - strlcat(buffer, "(", buffer_sz); - strlcat(buffer, member, buffer_sz); - strlcat(buffer, ")", buffer_sz); - } - dl->dli_fname = buffer; - } - break; - } else { - next_ldi = (struct ld_info *)((uintptr_t)this_ldi + - this_ldi->ldinfo_next); - } - } while (this_ldi->ldinfo_next); - free((void *)ldinfos); - return dl->dli_fname != NULL; -} - #endif FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSpec module_filespec; #ifdef _AIX + // TODO: As the current AIX LLDB is static, we don't need dladdr which is + // only for shared library, Below is the hack to find the module name + // for static LLDB + // FIXME: If LLDB is later built as shared library, we have to find the way simillar to dladdr + // since AIX does not support the dladdr API. if (host_addr == reinterpret_cast(HostInfoBase::ComputeSharedLibraryDirectory)) { // FIXME: AIX dladdr return "lldb" for this case if (p_xargv[0]) { @@ -519,7 +367,7 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { return module_filespec; } } -#endif +#else #if !defined(__ANDROID__) Dl_info info; if (::dladdr(host_addr, &info)) { @@ -528,6 +376,7 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSystem::Instance().Resolve(module_filespec); } } +#endif #endif return module_filespec; } From lldb-commits at lists.llvm.org Thu May 15 00:22:12 2025 From: lldb-commits at lists.llvm.org (Alex Langford via lldb-commits) Date: Thu, 15 May 2025 00:22:12 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use llvm::unique (NFC) (PR #139910) In-Reply-To: Message-ID: <68259624.630a0220.39e75f.8fdf@mx.google.com> https://github.com/bulbazord approved this pull request. Makes sense. `std::unique` doesn't invalidate the end iterator, so I believe this should be ok. https://github.com/llvm/llvm-project/pull/139910 From lldb-commits at lists.llvm.org Thu May 15 00:24:55 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 00:24:55 -0700 (PDT) Subject: [Lldb-commits] [lldb] Fix race condition during iteration through modules (#139283) (PR #139862) In-Reply-To: Message-ID: <682596c7.170a0220.1761f3.1de3@mx.google.com> https://github.com/nd updated https://github.com/llvm/llvm-project/pull/139862 >From f6b1c03607582e580f0b3167c0e337c35c31cbeb Mon Sep 17 00:00:00 2001 From: "Dmitry.Neverov" Date: Wed, 14 May 2025 11:09:07 +0200 Subject: [PATCH] [lldb] Fix race condition during iteration through modules (#139283) Use of ModuleIterable ensures modules don't change during iteration. --- lldb/source/Target/Target.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 7f61f8689fb95..9660fc97970b0 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -1511,8 +1511,7 @@ bool Target::IgnoreWatchpointByID(lldb::watch_id_t watch_id, ModuleSP Target::GetExecutableModule() { // search for the first executable in the module list - for (size_t i = 0; i < m_images.GetSize(); ++i) { - ModuleSP module_sp = m_images.GetModuleAtIndex(i); + for (ModuleSP module_sp : m_images.Modules()) { lldb_private::ObjectFile *obj = module_sp->GetObjectFile(); if (obj == nullptr) continue; From lldb-commits at lists.llvm.org Thu May 15 01:10:56 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Thu, 15 May 2025 01:10:56 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Migrate ScopesRequest to structured types (PR #138116) In-Reply-To: Message-ID: <6825a190.050a0220.cb9c3.5381@mx.google.com> https://github.com/da-viper updated https://github.com/llvm/llvm-project/pull/138116 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Thu May 15 01:50:21 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Thu, 15 May 2025 01:50:21 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Migrate ScopesRequest to structured types (PR #138116) In-Reply-To: Message-ID: <6825aacd.050a0220.460ce.3f74@mx.google.com> https://github.com/da-viper updated https://github.com/llvm/llvm-project/pull/138116 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Thu May 15 02:16:09 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 02:16:09 -0700 (PDT) Subject: [Lldb-commits] [lldb] 4ba8f4e - [lldb][lldb-dap] Migrate ScopesRequest to structured types (#138116) Message-ID: <6825b0d9.050a0220.10ef63.7064@mx.google.com> Author: Ebuka Ezike Date: 2025-05-15T10:16:05+01:00 New Revision: 4ba8f4e213c97733e3b61e5856b0e85e3d7d6a7f URL: https://github.com/llvm/llvm-project/commit/4ba8f4e213c97733e3b61e5856b0e85e3d7d6a7f DIFF: https://github.com/llvm/llvm-project/commit/4ba8f4e213c97733e3b61e5856b0e85e3d7d6a7f.diff LOG: [lldb][lldb-dap] Migrate ScopesRequest to structured types (#138116) Migrate ScopesRequest To use the Protocol Types Added: Modified: lldb/tools/lldb-dap/DAP.cpp lldb/tools/lldb-dap/DAP.h lldb/tools/lldb-dap/Handler/RequestHandler.h lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp lldb/tools/lldb-dap/JSONUtils.h lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp lldb/tools/lldb-dap/Protocol/ProtocolRequests.h lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp lldb/tools/lldb-dap/Protocol/ProtocolTypes.h lldb/unittests/DAP/ProtocolTypesTest.cpp Removed: ################################################################################ diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 51f9da854f4b6..56a0c38b00037 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -559,17 +559,6 @@ lldb::SBFrame DAP::GetLLDBFrame(const llvm::json::Object &arguments) { return GetLLDBFrame(frame_id); } -llvm::json::Value DAP::CreateTopLevelScopes() { - llvm::json::Array scopes; - scopes.emplace_back( - CreateScope("Locals", VARREF_LOCALS, variables.locals.GetSize(), false)); - scopes.emplace_back(CreateScope("Globals", VARREF_GLOBALS, - variables.globals.GetSize(), false)); - scopes.emplace_back(CreateScope("Registers", VARREF_REGS, - variables.registers.GetSize(), false)); - return llvm::json::Value(std::move(scopes)); -} - ReplMode DAP::DetectReplMode(lldb::SBFrame frame, std::string &expression, bool partial_expression) { // Check for the escape hatch prefix. diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c2e4c2dea582e..9065995f5d722 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -283,10 +283,10 @@ struct DAP { lldb::SBThread GetLLDBThread(const llvm::json::Object &arguments); lldb::SBFrame GetLLDBFrame(uint64_t frame_id); + /// TODO: remove this function when we finish migrating to the + /// new protocol types. lldb::SBFrame GetLLDBFrame(const llvm::json::Object &arguments); - llvm::json::Value CreateTopLevelScopes(); - void PopulateExceptionBreakpoints(); /// Attempt to determine if an expression is a variable expression or diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index b0002440cf72e..eaebaf6619bbd 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -452,11 +452,15 @@ class PauseRequestHandler : public LegacyRequestHandler { void operator()(const llvm::json::Object &request) const override; }; -class ScopesRequestHandler : public LegacyRequestHandler { +class ScopesRequestHandler final + : public RequestHandler> { public: - using LegacyRequestHandler::LegacyRequestHandler; + using RequestHandler::RequestHandler; static llvm::StringLiteral GetCommand() { return "scopes"; } - void operator()(const llvm::json::Object &request) const override; + + llvm::Expected + Run(const protocol::ScopesArguments &args) const override; }; class SetVariableRequestHandler final diff --git a/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp index 7d1608f59f9a4..aaad0e20f9c21 100644 --- a/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp @@ -7,69 +7,56 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" #include "RequestHandler.h" +using namespace lldb_dap::protocol; namespace lldb_dap { -// "ScopesRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Scopes request; value of command field is 'scopes'. The -// request returns the variable scopes for a given stackframe ID.", -// "properties": { -// "command": { -// "type": "string", -// "enum": [ "scopes" ] -// }, -// "arguments": { -// "$ref": "#/definitions/ScopesArguments" -// } -// }, -// "required": [ "command", "arguments" ] -// }] -// }, -// "ScopesArguments": { -// "type": "object", -// "description": "Arguments for 'scopes' request.", -// "properties": { -// "frameId": { -// "type": "integer", -// "description": "Retrieve the scopes for this stackframe." -// } -// }, -// "required": [ "frameId" ] -// }, -// "ScopesResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to 'scopes' request.", -// "properties": { -// "body": { -// "type": "object", -// "properties": { -// "scopes": { -// "type": "array", -// "items": { -// "$ref": "#/definitions/Scope" -// }, -// "description": "The scopes of the stackframe. If the array has -// length zero, there are no scopes available." -// } -// }, -// "required": [ "scopes" ] -// } -// }, -// "required": [ "body" ] -// }] -// } -void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - llvm::json::Object body; - const auto *arguments = request.getObject("arguments"); - lldb::SBFrame frame = dap.GetLLDBFrame(*arguments); +/// Creates a `protocol::Scope` struct. +/// +/// +/// \param[in] name +/// The value to place into the "name" key +/// +/// \param[in] variablesReference +/// The value to place into the "variablesReference" key +/// +/// \param[in] namedVariables +/// The value to place into the "namedVariables" key +/// +/// \param[in] expensive +/// The value to place into the "expensive" key +/// +/// \return +/// A `protocol::Scope` +static Scope CreateScope(const llvm::StringRef name, int64_t variablesReference, + int64_t namedVariables, bool expensive) { + Scope scope; + scope.name = name; + + // TODO: Support "arguments" and "return value" scope. + // At the moment lldb-dap includes the arguments and return_value into the + // "locals" scope. + // vscode only expands the first non-expensive scope, this causes friction + // if we add the arguments above the local scope as the locals scope will not + // be expanded if we enter a function with arguments. It becomes more + // annoying when the scope has arguments, return_value and locals. + if (variablesReference == VARREF_LOCALS) + scope.presentationHint = Scope::eScopePresentationHintLocals; + else if (variablesReference == VARREF_REGS) + scope.presentationHint = Scope::eScopePresentationHintRegisters; + + scope.variablesReference = variablesReference; + scope.namedVariables = namedVariables; + scope.expensive = expensive; + + return scope; +} + +llvm::Expected +ScopesRequestHandler::Run(const ScopesArguments &args) const { + lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId); + // As the user selects diff erent stack frames in the GUI, a "scopes" request // will be sent to the DAP. This is the only way we know that the user has // selected a frame in a thread. There are no other notifications that are @@ -78,9 +65,9 @@ void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { // are sent, this allows users to type commands in the debugger console // with a backtick character to run lldb commands and these lldb commands // will now have the right context selected as they are run. If the user - // types "`bt" into the debugger console and we had another thread selected + // types "`bt" into the debugger console, and we had another thread selected // in the LLDB library, we would show the wrong thing to the user. If the - // users switches threads with a lldb command like "`thread select 14", the + // users switch threads with a lldb command like "`thread select 14", the // GUI will not update as there are no "event" notification packets that // allow us to change the currently selected thread or frame in the GUI that // I am aware of. @@ -88,7 +75,6 @@ void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { frame.GetThread().GetProcess().SetSelectedThread(frame.GetThread()); frame.GetThread().SetSelectedFrame(frame.GetFrameID()); } - dap.variables.locals = frame.GetVariables(/*arguments=*/true, /*locals=*/true, /*statics=*/false, @@ -98,9 +84,15 @@ void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { /*statics=*/true, /*in_scope_only=*/true); dap.variables.registers = frame.GetRegisters(); - body.try_emplace("scopes", dap.CreateTopLevelScopes()); - response.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(response))); + + std::vector scopes = {CreateScope("Locals", VARREF_LOCALS, + dap.variables.locals.GetSize(), false), + CreateScope("Globals", VARREF_GLOBALS, + dap.variables.globals.GetSize(), false), + CreateScope("Registers", VARREF_REGS, + dap.variables.registers.GetSize(), false)}; + + return ScopesResponseBody{std::move(scopes)}; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h index 9c4dd0584bd21..783f291338d8c 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -238,27 +238,6 @@ llvm::json::Object CreateEventObject(const llvm::StringRef event_name); protocol::ExceptionBreakpointsFilter CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp); -/// Create a "Scope" JSON object as described in the debug adapter definition. -/// -/// \param[in] name -/// The value to place into the "name" key -// -/// \param[in] variablesReference -/// The value to place into the "variablesReference" key -// -/// \param[in] namedVariables -/// The value to place into the "namedVariables" key -// -/// \param[in] expensive -/// The value to place into the "expensive" key -/// -/// \return -/// A "Scope" JSON object with that follows the formal JSON -/// definition outlined by Microsoft. -llvm::json::Value CreateScope(const llvm::StringRef name, - int64_t variablesReference, - int64_t namedVariables, bool expensive); - /// Create a "Source" JSON object as described in the debug adapter definition. /// /// \param[in] file diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp index 316e146d43a0f..7efab87d39986 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp @@ -335,6 +335,20 @@ llvm::json::Value toJSON(const SetVariableResponseBody &SVR) { return llvm::json::Value(std::move(Body)); } +bool fromJSON(const llvm::json::Value &Params, ScopesArguments &SCA, + llvm::json::Path P) { + json::ObjectMapper O(Params, P); + return O && O.map("frameId", SCA.frameId); +} + +llvm::json::Value toJSON(const ScopesResponseBody &SCR) { + llvm::json::Array scopes; + for (const Scope &scope : SCR.scopes) { + scopes.emplace_back(toJSON(scope)); + } + + return llvm::json::Object{{"scopes", std::move(scopes)}}; +} bool fromJSON(const json::Value &Params, SourceArguments &SA, json::Path P) { json::ObjectMapper O(Params, P); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index 710fa5d2c57ed..4e08b4728453b 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -439,6 +439,19 @@ struct SetVariableResponseBody { }; llvm::json::Value toJSON(const SetVariableResponseBody &); +struct ScopesArguments { + /// Retrieve the scopes for the stack frame identified by `frameId`. The + /// `frameId` must have been obtained in the current suspended state. See + /// 'Lifetime of Object References' in the Overview section for details. + uint64_t frameId = LLDB_INVALID_FRAME_ID; +}; +bool fromJSON(const llvm::json::Value &, ScopesArguments &, llvm::json::Path); + +struct ScopesResponseBody { + std::vector scopes; +}; +llvm::json::Value toJSON(const ScopesResponseBody &); + /// Arguments for `source` request. struct SourceArguments { /// Specifies the source content to load. Either `source.path` or diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index 857503b3a0084..ce7519e3b16b8 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -16,17 +16,18 @@ using namespace llvm; namespace lldb_dap::protocol { -bool fromJSON(const json::Value &Params, PresentationHint &PH, json::Path P) { +bool fromJSON(const json::Value &Params, Source::PresentationHint &PH, + json::Path P) { auto rawHint = Params.getAsString(); if (!rawHint) { P.report("expected a string"); return false; } - std::optional hint = - StringSwitch>(*rawHint) - .Case("normal", ePresentationHintNormal) - .Case("emphasize", ePresentationHintEmphasize) - .Case("deemphasize", ePresentationHintDeemphasize) + std::optional hint = + StringSwitch>(*rawHint) + .Case("normal", Source::eSourcePresentationHintNormal) + .Case("emphasize", Source::eSourcePresentationHintEmphasize) + .Case("deemphasize", Source::eSourcePresentationHintDeemphasize) .Default(std::nullopt); if (!hint) { P.report("unexpected value"); @@ -43,13 +44,13 @@ bool fromJSON(const json::Value &Params, Source &S, json::Path P) { O.map("sourceReference", S.sourceReference); } -llvm::json::Value toJSON(PresentationHint hint) { +llvm::json::Value toJSON(Source::PresentationHint hint) { switch (hint) { - case ePresentationHintNormal: + case Source::eSourcePresentationHintNormal: return "normal"; - case ePresentationHintEmphasize: + case Source::eSourcePresentationHintEmphasize: return "emphasize"; - case ePresentationHintDeemphasize: + case Source::eSourcePresentationHintDeemphasize: return "deemphasize"; } llvm_unreachable("unhandled presentation hint."); @@ -435,6 +436,90 @@ json::Value toJSON(const Capabilities &C) { return result; } +bool fromJSON(const json::Value &Params, Scope::PresentationHint &PH, + json::Path P) { + auto rawHint = Params.getAsString(); + if (!rawHint) { + P.report("expected a string"); + return false; + } + const std::optional hint = + StringSwitch>(*rawHint) + .Case("arguments", Scope::eScopePresentationHintArguments) + .Case("locals", Scope::eScopePresentationHintLocals) + .Case("registers", Scope::eScopePresentationHintRegisters) + .Case("returnValue", Scope::eScopePresentationHintReturnValue) + .Default(std::nullopt); + if (!hint) { + P.report("unexpected value"); + return false; + } + PH = *hint; + return true; +} + +bool fromJSON(const json::Value &Params, Scope &S, json::Path P) { + json::ObjectMapper O(Params, P); + return O && O.map("name", S.name) && + O.mapOptional("presentationHint", S.presentationHint) && + O.map("variablesReference", S.variablesReference) && + O.mapOptional("namedVariables", S.namedVariables) && + O.map("indexedVariables", S.indexedVariables) && + O.mapOptional("source", S.source) && O.map("expensive", S.expensive) && + O.mapOptional("line", S.line) && O.mapOptional("column", S.column) && + O.mapOptional("endLine", S.endLine) && + O.mapOptional("endColumn", S.endColumn); +} + +llvm::json::Value toJSON(const Scope &SC) { + llvm::json::Object result{{"name", SC.name}, + {"variablesReference", SC.variablesReference}, + {"expensive", SC.expensive}}; + + if (SC.presentationHint.has_value()) { + llvm::StringRef presentationHint; + switch (*SC.presentationHint) { + case Scope::eScopePresentationHintArguments: + presentationHint = "arguments"; + break; + case Scope::eScopePresentationHintLocals: + presentationHint = "locals"; + break; + case Scope::eScopePresentationHintRegisters: + presentationHint = "registers"; + break; + case Scope::eScopePresentationHintReturnValue: + presentationHint = "returnValue"; + break; + } + + result.insert({"presentationHint", presentationHint}); + } + + if (SC.namedVariables.has_value()) + result.insert({"namedVariables", SC.namedVariables}); + + if (SC.indexedVariables.has_value()) + result.insert({"indexedVariables", SC.indexedVariables}); + + if (SC.source.has_value()) + result.insert({"source", SC.source}); + + if (SC.line.has_value()) + result.insert({"line", SC.line}); + + if (SC.column.has_value()) + result.insert({"column", SC.column}); + + if (SC.endLine.has_value()) + result.insert({"endLine", SC.endLine}); + + if (SC.endColumn.has_value()) + result.insert({"endColumn", SC.endColumn}); + + return result; +} + bool fromJSON(const llvm::json::Value &Params, Capabilities &C, llvm::json::Path P) { auto *Object = Params.getAsObject(); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index 757037a7b6ed2..3df77ee7374a7 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -27,6 +27,8 @@ #include #include +#define LLDB_DAP_INVALID_VARRERF UINT64_MAX + namespace lldb_dap::protocol { /// An `ExceptionBreakpointsFilter` is shown in the UI as an filter option for @@ -283,18 +285,16 @@ struct Capabilities { bool fromJSON(const llvm::json::Value &, Capabilities &, llvm::json::Path); llvm::json::Value toJSON(const Capabilities &); -enum PresentationHint : unsigned { - ePresentationHintNormal, - ePresentationHintEmphasize, - ePresentationHintDeemphasize -}; -bool fromJSON(const llvm::json::Value &, PresentationHint &, llvm::json::Path); -llvm::json::Value toJSON(PresentationHint hint); - /// A `Source` is a descriptor for source code. It is returned from the debug /// adapter as part of a `StackFrame` and it is used by clients when specifying /// breakpoints. struct Source { + enum PresentationHint : unsigned { + eSourcePresentationHintNormal, + eSourcePresentationHintEmphasize, + eSourcePresentationHintDeemphasize, + }; + /// The short name of the source. Every source returned from the debug adapter /// has a name. When sending a source to the debug adapter this name is /// optional. @@ -318,9 +318,82 @@ struct Source { // unsupported keys: origin, sources, adapterData, checksums }; +bool fromJSON(const llvm::json::Value &, Source::PresentationHint &, + llvm::json::Path); +llvm::json::Value toJSON(Source::PresentationHint); bool fromJSON(const llvm::json::Value &, Source &, llvm::json::Path); llvm::json::Value toJSON(const Source &); +/// A `Scope` is a named container for variables. Optionally a scope can map to +/// a source or a range within a source. +struct Scope { + enum PresentationHint : unsigned { + eScopePresentationHintArguments, + eScopePresentationHintLocals, + eScopePresentationHintRegisters, + eScopePresentationHintReturnValue + }; + /// Name of the scope such as 'Arguments', 'Locals', or 'Registers'. This + /// string is shown in the UI as is and can be translated. + //// + std::string name; + + /// A hint for how to present this scope in the UI. If this attribute is + /// missing, the scope is shown with a generic UI. + /// Values: + /// 'arguments': Scope contains method arguments. + /// 'locals': Scope contains local variables. + /// 'registers': Scope contains registers. Only a single `registers` scope + /// should be returned from a `scopes` request. + /// 'returnValue': Scope contains one or more return values. + /// etc. + std::optional presentationHint; + + /// The variables of this scope can be retrieved by passing the value of + /// `variablesReference` to the `variables` request as long as execution + /// remains suspended. See 'Lifetime of Object References' in the Overview + /// section for details. + //// + uint64_t variablesReference = LLDB_DAP_INVALID_VARRERF; + + /// The number of named variables in this scope. + /// The client can use this information to present the variables in a paged UI + /// and fetch them in chunks. + std::optional namedVariables; + + /// The number of indexed variables in this scope. + /// The client can use this information to present the variables in a paged UI + /// and fetch them in chunks. + std::optional indexedVariables; + + /// The source for this scope. + std::optional source; + + /// If true, the number of variables in this scope is large or expensive to + /// retrieve. + bool expensive = false; + + /// The start line of the range covered by this scope. + std::optional line; + + /// Start position of the range covered by the scope. It is measured in UTF-16 + /// code units and the client capability `columnsStartAt1` determines whether + /// it is 0- or 1-based. + std::optional column; + + /// The end line of the range covered by this scope. + std::optional endLine; + + /// End position of the range covered by the scope. It is measured in UTF-16 + /// code units and the client capability `columnsStartAt1` determines whether + /// it is 0- or 1-based. + std::optional endColumn; +}; +bool fromJSON(const llvm::json::Value &Params, Scope::PresentationHint &PH, + llvm::json::Path); +bool fromJSON(const llvm::json::Value &, Scope &, llvm::json::Path); +llvm::json::Value toJSON(const Scope &); + /// The granularity of one `step` in the stepping requests `next`, `stepIn`, /// `stepOut` and `stepBack`. enum SteppingGranularity : unsigned { diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp index d97bbaffa2bc0..0c119bdb544d8 100644 --- a/lldb/unittests/DAP/ProtocolTypesTest.cpp +++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp @@ -50,7 +50,7 @@ TEST(ProtocolTypesTest, Source) { source.name = "testName"; source.path = "/path/to/source"; source.sourceReference = 12345; - source.presentationHint = ePresentationHintEmphasize; + source.presentationHint = Source::eSourcePresentationHintEmphasize; llvm::Expected deserialized_source = roundtrip(source); ASSERT_THAT_EXPECTED(deserialized_source, llvm::Succeeded()); @@ -101,8 +101,8 @@ TEST(ProtocolTypesTest, Breakpoint) { breakpoint.id = 42; breakpoint.verified = true; breakpoint.message = "Breakpoint set successfully"; - breakpoint.source = - Source{"test.cpp", "/path/to/test.cpp", 123, ePresentationHintNormal}; + breakpoint.source = Source{"test.cpp", "/path/to/test.cpp", 123, + Source::eSourcePresentationHintNormal}; breakpoint.line = 10; breakpoint.column = 5; breakpoint.endLine = 15; @@ -292,12 +292,53 @@ TEST(ProtocolTypesTest, Capabilities) { deserialized_capabilities->lldbExtVersion); } +TEST(ProtocolTypesTest, Scope) { + Scope scope; + scope.name = "Locals"; + scope.presentationHint = Scope::eScopePresentationHintLocals; + scope.variablesReference = 1; + scope.namedVariables = 2; + scope.indexedVariables = std::nullopt; + scope.expensive = false; + scope.line = 2; + scope.column = 3; + scope.endLine = 10; + scope.endColumn = 20; + + scope.source = + Source{.name = "testName", + .path = "/path/to/source", + .sourceReference = 12345, + .presentationHint = Source::eSourcePresentationHintNormal}; + + llvm::Expected deserialized_scope = roundtrip(scope); + ASSERT_THAT_EXPECTED(deserialized_scope, llvm::Succeeded()); + EXPECT_EQ(scope.name, deserialized_scope->name); + EXPECT_EQ(scope.presentationHint, deserialized_scope->presentationHint); + EXPECT_EQ(scope.variablesReference, deserialized_scope->variablesReference); + EXPECT_EQ(scope.namedVariables, deserialized_scope->namedVariables); + EXPECT_EQ(scope.indexedVariables, deserialized_scope->indexedVariables); + EXPECT_EQ(scope.expensive, deserialized_scope->expensive); + EXPECT_EQ(scope.line, deserialized_scope->line); + EXPECT_EQ(scope.column, deserialized_scope->column); + EXPECT_EQ(scope.endLine, deserialized_scope->endLine); + EXPECT_EQ(scope.endColumn, deserialized_scope->endColumn); + + EXPECT_THAT(deserialized_scope->source.has_value(), true); + const Source &source = scope.source.value(); + const Source &deserialized_source = deserialized_scope->source.value(); + + EXPECT_EQ(source.path, deserialized_source.path); + EXPECT_EQ(source.sourceReference, deserialized_source.sourceReference); + EXPECT_EQ(source.presentationHint, deserialized_source.presentationHint); +} + TEST(ProtocolTypesTest, PresentationHint) { // Test all PresentationHint values. - std::vector> test_cases = { - {ePresentationHintNormal, "normal"}, - {ePresentationHintEmphasize, "emphasize"}, - {ePresentationHintDeemphasize, "deemphasize"}}; + std::vector> test_cases = + {{Source::eSourcePresentationHintNormal, "normal"}, + {Source::eSourcePresentationHintEmphasize, "emphasize"}, + {Source::eSourcePresentationHintDeemphasize, "deemphasize"}}; for (const auto &test_case : test_cases) { // Serialize the PresentationHint to JSON. @@ -306,7 +347,7 @@ TEST(ProtocolTypesTest, PresentationHint) { EXPECT_EQ(serialized.getAsString(), test_case.second); // Deserialize the JSON back to PresentationHint. - PresentationHint deserialized; + Source::PresentationHint deserialized; llvm::json::Path::Root root; ASSERT_TRUE(fromJSON(serialized, deserialized, root)) << llvm::toString(root.getError()); @@ -315,7 +356,7 @@ TEST(ProtocolTypesTest, PresentationHint) { // Test invalid value. llvm::json::Value invalid_value = "invalid_hint"; - PresentationHint deserialized_invalid; + Source::PresentationHint deserialized_invalid; llvm::json::Path::Root root; EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root)); } From lldb-commits at lists.llvm.org Thu May 15 02:16:15 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Thu, 15 May 2025 02:16:15 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Migrate ScopesRequest to structured types (PR #138116) In-Reply-To: Message-ID: <6825b0df.170a0220.53196.389a@mx.google.com> https://github.com/da-viper closed https://github.com/llvm/llvm-project/pull/138116 From lldb-commits at lists.llvm.org Thu May 15 02:37:56 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Thu, 15 May 2025 02:37:56 -0700 (PDT) Subject: [Lldb-commits] [lldb] [NFC][lldb][lldb-dap] fix C++20 extension warning (PR #140031) Message-ID: https://github.com/da-viper created https://github.com/llvm/llvm-project/pull/140031 warning for designated initializers >From 0a8d16445c531f7a65283ab2a9a7db522eeb3a5a Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Thu, 15 May 2025 10:36:39 +0100 Subject: [PATCH] [NFC][lldb][lldb-dap] fix C++20 extension warning warning for designated initializers --- lldb/unittests/DAP/ProtocolTypesTest.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp index 0c119bdb544d8..c34d98cf890ef 100644 --- a/lldb/unittests/DAP/ProtocolTypesTest.cpp +++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp @@ -305,11 +305,11 @@ TEST(ProtocolTypesTest, Scope) { scope.endLine = 10; scope.endColumn = 20; - scope.source = - Source{.name = "testName", - .path = "/path/to/source", - .sourceReference = 12345, - .presentationHint = Source::eSourcePresentationHintNormal}; + // scope.source = + scope.source->name = "testName"; + scope.source->path = "/path/to/source"; + scope.source->sourceReference = 12345; + scope.source->presentationHint = Source::eSourcePresentationHintNormal; llvm::Expected deserialized_scope = roundtrip(scope); ASSERT_THAT_EXPECTED(deserialized_scope, llvm::Succeeded()); From lldb-commits at lists.llvm.org Thu May 15 02:38:27 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 02:38:27 -0700 (PDT) Subject: [Lldb-commits] [lldb] [NFC][lldb][lldb-dap] fix C++20 extension warning (PR #140031) In-Reply-To: Message-ID: <6825b613.170a0220.43e58.12b7@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Ebuka Ezike (da-viper)
Changes warning for designated initializers --- Full diff: https://github.com/llvm/llvm-project/pull/140031.diff 1 Files Affected: - (modified) lldb/unittests/DAP/ProtocolTypesTest.cpp (+5-5) ``````````diff diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp index 0c119bdb544d8..c34d98cf890ef 100644 --- a/lldb/unittests/DAP/ProtocolTypesTest.cpp +++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp @@ -305,11 +305,11 @@ TEST(ProtocolTypesTest, Scope) { scope.endLine = 10; scope.endColumn = 20; - scope.source = - Source{.name = "testName", - .path = "/path/to/source", - .sourceReference = 12345, - .presentationHint = Source::eSourcePresentationHintNormal}; + // scope.source = + scope.source->name = "testName"; + scope.source->path = "/path/to/source"; + scope.source->sourceReference = 12345; + scope.source->presentationHint = Source::eSourcePresentationHintNormal; llvm::Expected deserialized_scope = roundtrip(scope); ASSERT_THAT_EXPECTED(deserialized_scope, llvm::Succeeded()); ``````````
https://github.com/llvm/llvm-project/pull/140031 From lldb-commits at lists.llvm.org Thu May 15 02:38:54 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Thu, 15 May 2025 02:38:54 -0700 (PDT) Subject: [Lldb-commits] [lldb] [NFC][lldb][lldb-dap] fix C++20 extension warning (PR #140031) In-Reply-To: Message-ID: <6825b62e.050a0220.12f3c2.4d3b@mx.google.com> https://github.com/da-viper updated https://github.com/llvm/llvm-project/pull/140031 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Thu May 15 02:48:49 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Thu, 15 May 2025 02:48:49 -0700 (PDT) Subject: [Lldb-commits] [lldb] [NFC][lldb][lldb-dap] fix C++20 extension warning (PR #140031) In-Reply-To: Message-ID: <6825b881.050a0220.3201f7.49af@mx.google.com> https://github.com/da-viper updated https://github.com/llvm/llvm-project/pull/140031 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Thu May 15 03:12:44 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Thu, 15 May 2025 03:12:44 -0700 (PDT) Subject: [Lldb-commits] [lldb] [NFC][lldb][lldb-dap] fix C++20 extension warning (PR #140031) In-Reply-To: Message-ID: <6825be1c.050a0220.242963.1a35@mx.google.com> https://github.com/da-viper edited https://github.com/llvm/llvm-project/pull/140031 From lldb-commits at lists.llvm.org Thu May 15 03:13:23 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 03:13:23 -0700 (PDT) Subject: [Lldb-commits] [lldb] e3867cb - [NFC][lldb][lldb-dap] fix C++20 extension warning (#140031) Message-ID: <6825be43.170a0220.28b116.44a2@mx.google.com> Author: Ebuka Ezike Date: 2025-05-15T11:13:19+01:00 New Revision: e3867cb07ed1ed319609fbea0ce15f40e2a0efad URL: https://github.com/llvm/llvm-project/commit/e3867cb07ed1ed319609fbea0ce15f40e2a0efad DIFF: https://github.com/llvm/llvm-project/commit/e3867cb07ed1ed319609fbea0ce15f40e2a0efad.diff LOG: [NFC][lldb][lldb-dap] fix C++20 extension warning (#140031) warning for designated initializers introduced in commit 4ba8f4e Added: Modified: lldb/unittests/DAP/ProtocolTypesTest.cpp Removed: ################################################################################ diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp index 0c119bdb544d8..5d5125dc78fba 100644 --- a/lldb/unittests/DAP/ProtocolTypesTest.cpp +++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp @@ -305,11 +305,12 @@ TEST(ProtocolTypesTest, Scope) { scope.endLine = 10; scope.endColumn = 20; - scope.source = - Source{.name = "testName", - .path = "/path/to/source", - .sourceReference = 12345, - .presentationHint = Source::eSourcePresentationHintNormal}; + Source source; + source.name = "testName"; + source.path = "/path/to/source"; + source.sourceReference = 12345; + source.presentationHint = Source::eSourcePresentationHintNormal; + scope.source = source; llvm::Expected deserialized_scope = roundtrip(scope); ASSERT_THAT_EXPECTED(deserialized_scope, llvm::Succeeded()); @@ -325,7 +326,6 @@ TEST(ProtocolTypesTest, Scope) { EXPECT_EQ(scope.endColumn, deserialized_scope->endColumn); EXPECT_THAT(deserialized_scope->source.has_value(), true); - const Source &source = scope.source.value(); const Source &deserialized_source = deserialized_scope->source.value(); EXPECT_EQ(source.path, deserialized_source.path); From lldb-commits at lists.llvm.org Thu May 15 03:13:26 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Thu, 15 May 2025 03:13:26 -0700 (PDT) Subject: [Lldb-commits] [lldb] [NFC][lldb][lldb-dap] fix C++20 extension warning (PR #140031) In-Reply-To: Message-ID: <6825be46.170a0220.1ec342.2329@mx.google.com> https://github.com/da-viper closed https://github.com/llvm/llvm-project/pull/140031 From lldb-commits at lists.llvm.org Thu May 15 03:15:09 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 03:15:09 -0700 (PDT) Subject: [Lldb-commits] [lldb] Fix race condition during iteration through modules (#139283) (PR #139862) In-Reply-To: Message-ID: <6825bead.170a0220.272872.0a41@mx.google.com> ================ @@ -1510,6 +1510,7 @@ bool Target::IgnoreWatchpointByID(lldb::watch_id_t watch_id, } ModuleSP Target::GetExecutableModule() { + std::lock_guard guard(m_images.GetMutex()); ---------------- neverov-test wrote: done https://github.com/llvm/llvm-project/pull/139862 From lldb-commits at lists.llvm.org Thu May 15 03:15:16 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 03:15:16 -0700 (PDT) Subject: [Lldb-commits] [lldb] Fix race condition during iteration through modules (#139283) (PR #139862) In-Reply-To: Message-ID: <6825beb4.170a0220.1b2f66.169b@mx.google.com> https://github.com/neverov-test deleted https://github.com/llvm/llvm-project/pull/139862 From lldb-commits at lists.llvm.org Thu May 15 03:35:01 2025 From: lldb-commits at lists.llvm.org (=?UTF-8?Q?Martin_Storsj=C3=B6?= via lldb-commits) Date: Thu, 15 May 2025 03:35:01 -0700 (PDT) Subject: [Lldb-commits] [clang] [flang] [lld] [lldb] [llvm] [mlir] [polly] [CMake] respect LLVMConfig.cmake's LLVM_DEFINITIONS in standalone builds (PR #138587) In-Reply-To: Message-ID: <6825c355.170a0220.a9650.1b23@mx.google.com> mstorsjo wrote: > I rebased this on top of #138783 and adjusted the title and description. Now it should be in a good state to push cmake changes for other projects. The changes look good, but it looks like the changes from #138783 still show up when viewing the changes; can you check that you've rebased past the merged #138783? (Also, I take it that no other subprojects than clang need the `cmake_push_check_state` change?) https://github.com/llvm/llvm-project/pull/138587 From lldb-commits at lists.llvm.org Thu May 15 04:21:30 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 04:21:30 -0700 (PDT) Subject: [Lldb-commits] [lldb] 42ee758 - Complete the Implementation of DAP modules explorer. (#139934) Message-ID: <6825ce3a.170a0220.211853.41b3@mx.google.com> Author: Ebuka Ezike Date: 2025-05-15T12:21:26+01:00 New Revision: 42ee758bec885deaad08162cc8e97a87d2aba100 URL: https://github.com/llvm/llvm-project/commit/42ee758bec885deaad08162cc8e97a87d2aba100 DIFF: https://github.com/llvm/llvm-project/commit/42ee758bec885deaad08162cc8e97a87d2aba100.diff LOG: Complete the Implementation of DAP modules explorer. (#139934) This extends the TreeView to show the module property as a tree item instead of rendering it through the markdown tooltip. ![image](https://github.com/user-attachments/assets/329fabee-9b4a-490e-9450-3f01314674ea) Added: Modified: lldb/tools/lldb-dap/JSONUtils.cpp lldb/tools/lldb-dap/package.json lldb/tools/lldb-dap/src-ts/extension.ts lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts Removed: ################################################################################ diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 279e6d3d93814..a8bd672583a5d 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -416,9 +416,11 @@ llvm::json::Value CreateModule(lldb::SBTarget &target, lldb::SBModule &module, } else { object.try_emplace("symbolStatus", "Symbols not found."); } - std::string loaded_addr = std::to_string( - module.GetObjectFileHeaderAddress().GetLoadAddress(target)); - object.try_emplace("addressRange", loaded_addr); + std::string load_address = + llvm::formatv("{0:x}", + module.GetObjectFileHeaderAddress().GetLoadAddress(target)) + .str(); + object.try_emplace("addressRange", load_address); std::string version_str; uint32_t version_nums[3]; uint32_t num_versions = diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index e3e46526f379f..d5ca604798799 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -244,6 +244,26 @@ } } ], + "commands": [ + { + "command": "lldb-dap.modules.copyProperty", + "title": "Copy Value" + } + ], + "menus": { + "commandPalette": [ + { + "command": "lldb-dap.modules.copyProperty", + "when": "false" + } + ], + "view/item/context": [ + { + "command": "lldb-dap.modules.copyProperty", + "when": "view == lldb-dap.modules && viewItem == property" + } + ] + }, "breakpoints": [ { "language": "ada" diff --git a/lldb/tools/lldb-dap/src-ts/extension.ts b/lldb/tools/lldb-dap/src-ts/extension.ts index a5c0a09ae60cf..c8e5146e29cea 100644 --- a/lldb/tools/lldb-dap/src-ts/extension.ts +++ b/lldb/tools/lldb-dap/src-ts/extension.ts @@ -6,7 +6,10 @@ import { LaunchUriHandler } from "./uri-launch-handler"; import { LLDBDapConfigurationProvider } from "./debug-configuration-provider"; import { LLDBDapServer } from "./lldb-dap-server"; import { DebugSessionTracker } from "./debug-session-tracker"; -import { ModulesDataProvider } from "./ui/modules-data-provider"; +import { + ModulesDataProvider, + ModuleProperty, +} from "./ui/modules-data-provider"; /** * This class represents the extension and manages its life cycle. Other extensions @@ -40,6 +43,11 @@ export class LLDBDapExtension extends DisposableContext { ), vscode.window.registerUriHandler(new LaunchUriHandler()), ); + + vscode.commands.registerCommand( + "lldb-dap.modules.copyProperty", + (node: ModuleProperty) => vscode.env.clipboard.writeText(node.value), + ); } } diff --git a/lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts b/lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts index 478c162de8878..091c1d69ac647 100644 --- a/lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts +++ b/lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts @@ -2,60 +2,86 @@ import * as vscode from "vscode"; import { DebugProtocol } from "@vscode/debugprotocol"; import { DebugSessionTracker } from "../debug-session-tracker"; -/** A tree data provider for listing loaded modules for the active debug session. */ -export class ModulesDataProvider - implements vscode.TreeDataProvider -{ - private changeTreeData = new vscode.EventEmitter(); - readonly onDidChangeTreeData = this.changeTreeData.event; +export interface ModuleProperty { + key: string; + value: string; +} - constructor(private readonly tracker: DebugSessionTracker) { - tracker.onDidChangeModules(() => this.changeTreeData.fire()); - vscode.debug.onDidChangeActiveDebugSession(() => - this.changeTreeData.fire(), - ); +/** Type to represent both Module and ModuleProperty since TreeDataProvider + * expects one concrete type */ +type TreeData = DebugProtocol.Module | ModuleProperty; + +function isModule(type: TreeData): type is DebugProtocol.Module { + return (type as DebugProtocol.Module).id !== undefined; +} + +class ModuleItem extends vscode.TreeItem { + constructor(module: DebugProtocol.Module) { + super(module.name, vscode.TreeItemCollapsibleState.Collapsed); + this.description = module.symbolStatus; } - getTreeItem(module: DebugProtocol.Module): vscode.TreeItem { - let treeItem = new vscode.TreeItem(/*label=*/ module.name); - if (module.path) { - treeItem.description = `${module.id} -- ${module.path}`; - } else { - treeItem.description = `${module.id}`; - } + static getProperties(module: DebugProtocol.Module): ModuleProperty[] { + // does not include the name and symbol status as it is show in the parent. + let children: ModuleProperty[] = []; + children.push({ key: "id:", value: module.id.toString() }); - const tooltip = new vscode.MarkdownString(); - tooltip.appendMarkdown(`# ${module.name}\n\n`); - tooltip.appendMarkdown(`- **ID**: ${module.id}\n`); if (module.addressRange) { - tooltip.appendMarkdown( - `- **Load address**: 0x${Number(module.addressRange).toString(16)}\n`, - ); + children.push({ + key: "load address:", + value: module.addressRange, + }); } if (module.path) { - tooltip.appendMarkdown(`- **Path**: ${module.path}\n`); + children.push({ key: "path:", value: module.path }); } if (module.version) { - tooltip.appendMarkdown(`- **Version**: ${module.version}\n`); - } - if (module.symbolStatus) { - tooltip.appendMarkdown(`- **Symbol status**: ${module.symbolStatus}\n`); + children.push({ key: "version:", value: module.version }); } if (module.symbolFilePath) { - tooltip.appendMarkdown( - `- **Symbol file path**: ${module.symbolFilePath}\n`, - ); + children.push({ key: "symbol filepath:", value: module.symbolFilePath }); + } + return children; + } +} + +/** A tree data provider for listing loaded modules for the active debug session. */ +export class ModulesDataProvider implements vscode.TreeDataProvider { + private changeTreeData = new vscode.EventEmitter(); + readonly onDidChangeTreeData = this.changeTreeData.event; + + constructor(private readonly tracker: DebugSessionTracker) { + tracker.onDidChangeModules(() => this.changeTreeData.fire()); + vscode.debug.onDidChangeActiveDebugSession(() => + this.changeTreeData.fire(), + ); + } + + getTreeItem(module: TreeData): vscode.TreeItem { + if (isModule(module)) { + return new ModuleItem(module); } - treeItem.tooltip = tooltip; - return treeItem; + let item = new vscode.TreeItem(module.key); + item.description = module.value; + item.tooltip = `${module.key} ${module.value}`; + item.contextValue = "property"; + return item; } - getChildren(): DebugProtocol.Module[] { + getChildren(element?: TreeData): TreeData[] { if (!vscode.debug.activeDebugSession) { return []; } - return this.tracker.debugSessionModules(vscode.debug.activeDebugSession); + if (!element) { + return this.tracker.debugSessionModules(vscode.debug.activeDebugSession); + } + + if (isModule(element)) { + return ModuleItem.getProperties(element); + } + + return []; } } From lldb-commits at lists.llvm.org Thu May 15 04:21:35 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Thu, 15 May 2025 04:21:35 -0700 (PDT) Subject: [Lldb-commits] [lldb] Complete the Implementation of DAP modules explorer. (PR #139934) In-Reply-To: Message-ID: <6825ce3f.170a0220.301a26.1389@mx.google.com> https://github.com/da-viper closed https://github.com/llvm/llvm-project/pull/139934 From lldb-commits at lists.llvm.org Thu May 15 04:42:18 2025 From: lldb-commits at lists.llvm.org (Michael Buch via lldb-commits) Date: Thu, 15 May 2025 04:42:18 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Add support for displaying `__float128` variables (PR #98369) In-Reply-To: Message-ID: <6825d31a.050a0220.27a24d.e6a1@mx.google.com> ================ @@ -666,7 +667,9 @@ lldb::offset_t lldb_private::DumpDataExtractor( const unsigned format_precision = 0; const llvm::fltSemantics &semantics = - GetFloatSemantics(target_sp, item_byte_size); + item_format == eFormatFloat128 && item_byte_size == 16 + ? llvm::APFloat::IEEEquad() + : GetFloatSemantics(target_sp, item_byte_size); ---------------- Michael137 wrote: Why can't this byte_size check be part of `GetFloatSemantics`? https://github.com/llvm/llvm-project/pull/98369 From lldb-commits at lists.llvm.org Thu May 15 05:09:57 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Thu, 15 May 2025 05:09:57 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Adding NativeThreadAIX (PR #139537) In-Reply-To: Message-ID: <6825d995.630a0220.523ba.9ace@mx.google.com> ================ @@ -0,0 +1,71 @@ +//===-- NativeThreadAIX.cpp ---------------------------------------------===// +// +// 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 "NativeThreadAIX.h" +#include "NativeProcessAIX.h" +#include "lldb/Utility/State.h" +#include +#include + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; + +NativeThreadAIX::NativeThreadAIX(NativeProcessAIX &process, lldb::tid_t tid) + : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid) {} + +std::string NativeThreadAIX::GetName() { + NativeProcessAIX &process = GetProcess(); + auto BufferOrError = getProcFile(process.GetID(), "psinfo"); + if (!BufferOrError) + return ""; + auto &Buffer = *BufferOrError; + if (Buffer->getBufferSize() < sizeof(psinfo_t)) + return ""; + const psinfo_t *psinfo = + reinterpret_cast(Buffer->getBufferStart()); + return std::string(psinfo->pr_fname); +} ---------------- DhruvSrivastavaX wrote: Yes true, I agree with that. Okay, in that case I can drop this change out for now and we can decide on whether to add it or not later. https://github.com/llvm/llvm-project/pull/139537 From lldb-commits at lists.llvm.org Thu May 15 05:12:16 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Thu, 15 May 2025 05:12:16 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Adding NativeThreadAIX (PR #139537) In-Reply-To: Message-ID: <6825da20.050a0220.1e1fc3.2e41@mx.google.com> https://github.com/DhruvSrivastavaX updated https://github.com/llvm/llvm-project/pull/139537 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Thu May 15 05:13:45 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Thu, 15 May 2025 05:13:45 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Adding NativeThreadAIX (PR #139537) In-Reply-To: Message-ID: <6825da79.620a0220.2665b5.33fc@mx.google.com> DhruvSrivastavaX wrote: Shall I merge it now? @labath https://github.com/llvm/llvm-project/pull/139537 From lldb-commits at lists.llvm.org Thu May 15 05:15:17 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 05:15:17 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Adding NativeThreadAIX (PR #139537) In-Reply-To: Message-ID: <6825dad5.170a0220.12d964.2502@mx.google.com> github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning:
You can test this locally with the following command: ``````````bash git-clang-format --diff HEAD~1 HEAD --extensions cpp,h -- lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp lldb/source/Plugins/Process/AIX/NativeThreadAIX.h ``````````
View the diff from clang-format here. ``````````diff diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp index 7108ba9fb..3bb608168 100644 --- a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp @@ -17,9 +17,7 @@ using namespace lldb_private::process_aix; NativeThreadAIX::NativeThreadAIX(NativeProcessAIX &process, lldb::tid_t tid) : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid) {} -std::string NativeThreadAIX::GetName() { - return ""; -} +std::string NativeThreadAIX::GetName() { return ""; } lldb::StateType NativeThreadAIX::GetState() { return m_state; } ``````````
https://github.com/llvm/llvm-project/pull/139537 From lldb-commits at lists.llvm.org Thu May 15 05:20:37 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Thu, 15 May 2025 05:20:37 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Adding NativeThreadAIX (PR #139537) In-Reply-To: Message-ID: <6825dc15.170a0220.279afb.1430@mx.google.com> https://github.com/DhruvSrivastavaX updated https://github.com/llvm/llvm-project/pull/139537 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Thu May 15 06:22:25 2025 From: lldb-commits at lists.llvm.org (Tim Gymnich via lldb-commits) Date: Thu, 15 May 2025 06:22:25 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use std::optional::value_or (NFC) (PR #140011) In-Reply-To: Message-ID: <6825ea91.170a0220.211853.6160@mx.google.com> https://github.com/tgymnich approved this pull request. https://github.com/llvm/llvm-project/pull/140011 From lldb-commits at lists.llvm.org Thu May 15 07:16:04 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 07:16:04 -0700 (PDT) Subject: [Lldb-commits] [lldb] 1f570b1 - [lldb] Use llvm::unique (NFC) (#139910) Message-ID: <6825f724.050a0220.50d4d.7437@mx.google.com> Author: Kazu Hirata Date: 2025-05-15T07:15:59-07:00 New Revision: 1f570b1c2df6ec93a90ec8f0751fe8355644f1c6 URL: https://github.com/llvm/llvm-project/commit/1f570b1c2df6ec93a90ec8f0751fe8355644f1c6 DIFF: https://github.com/llvm/llvm-project/commit/1f570b1c2df6ec93a90ec8f0751fe8355644f1c6.diff LOG: [lldb] Use llvm::unique (NFC) (#139910) While I am at it, this patch removes the "if" statement. std::vector::erase(first, last) doesn't do anything when first == last. Added: Modified: lldb/source/Target/DynamicRegisterInfo.cpp Removed: ################################################################################ diff --git a/lldb/source/Target/DynamicRegisterInfo.cpp b/lldb/source/Target/DynamicRegisterInfo.cpp index 9ad98a41c688c..b964dc5877a97 100644 --- a/lldb/source/Target/DynamicRegisterInfo.cpp +++ b/lldb/source/Target/DynamicRegisterInfo.cpp @@ -497,10 +497,7 @@ void DynamicRegisterInfo::Finalize(const ArchSpec &arch) { pos != end; ++pos) { if (pos->second.size() > 1) { llvm::sort(pos->second); - reg_num_collection::iterator unique_end = - std::unique(pos->second.begin(), pos->second.end()); - if (unique_end != pos->second.end()) - pos->second.erase(unique_end, pos->second.end()); + pos->second.erase(llvm::unique(pos->second), pos->second.end()); } assert(!pos->second.empty()); if (pos->second.back() != LLDB_INVALID_REGNUM) From lldb-commits at lists.llvm.org Thu May 15 07:16:06 2025 From: lldb-commits at lists.llvm.org (Kazu Hirata via lldb-commits) Date: Thu, 15 May 2025 07:16:06 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use llvm::unique (NFC) (PR #139910) In-Reply-To: Message-ID: <6825f726.050a0220.1fa9bd.d448@mx.google.com> https://github.com/kazutakahirata closed https://github.com/llvm/llvm-project/pull/139910 From lldb-commits at lists.llvm.org Thu May 15 07:17:24 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 07:17:24 -0700 (PDT) Subject: [Lldb-commits] [lldb] 9f569fe - [lldb] Use std::optional::value_or (NFC) (#140011) Message-ID: <6825f774.a70a0220.313daf.a5be@mx.google.com> Author: Kazu Hirata Date: 2025-05-15T07:17:18-07:00 New Revision: 9f569fe2e7b68db856716a1ae3b0a6738a281d1e URL: https://github.com/llvm/llvm-project/commit/9f569fe2e7b68db856716a1ae3b0a6738a281d1e DIFF: https://github.com/llvm/llvm-project/commit/9f569fe2e7b68db856716a1ae3b0a6738a281d1e.diff LOG: [lldb] Use std::optional::value_or (NFC) (#140011) Added: Modified: lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp Removed: ################################################################################ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index a3e809f44ed23..e3a866e2b6d48 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -2479,8 +2479,8 @@ Function *DWARFASTParserClang::ParseFunctionFromDWARF( std::unique_ptr decl_up; if (decl_file || decl_line || decl_column) decl_up = std::make_unique( - die.GetCU()->GetFile(decl_file ? *decl_file : 0), - decl_line ? *decl_line : 0, decl_column ? *decl_column : 0); + die.GetCU()->GetFile(decl_file.value_or(0)), decl_line.value_or(0), + decl_column.value_or(0)); SymbolFileDWARF *dwarf = die.GetDWARF(); // Supply the type _only_ if it has already been parsed diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 907d63eb51afe..0fc7f79be70ec 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1358,15 +1358,15 @@ size_t SymbolFileDWARF::ParseBlocksRecursive(CompileUnit &comp_unit, if (decl_file || decl_line || decl_column) decl_up = std::make_unique( comp_unit.GetSupportFiles().GetFileSpecAtIndex( - decl_file ? *decl_file : 0), - decl_line ? *decl_line : 0, decl_column ? *decl_column : 0); + decl_file.value_or(0)), + decl_line.value_or(0), decl_column.value_or(0)); std::unique_ptr call_up; if (call_file || call_line || call_column) call_up = std::make_unique( comp_unit.GetSupportFiles().GetFileSpecAtIndex( - call_file ? *call_file : 0), - call_line ? *call_line : 0, call_column ? *call_column : 0); + call_file.value_or(0)), + call_line.value_or(0), call_column.value_or(0)); block->SetInlinedFunctionInfo(name, mangled_name, decl_up.get(), call_up.get()); From lldb-commits at lists.llvm.org Thu May 15 07:17:25 2025 From: lldb-commits at lists.llvm.org (Kazu Hirata via lldb-commits) Date: Thu, 15 May 2025 07:17:25 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use std::optional::value_or (NFC) (PR #140011) In-Reply-To: Message-ID: <6825f775.170a0220.1154e.d110@mx.google.com> https://github.com/kazutakahirata closed https://github.com/llvm/llvm-project/pull/140011 From lldb-commits at lists.llvm.org Thu May 15 07:23:16 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Thu, 15 May 2025 07:23:16 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Retcon SBValue::GetChildAtIndex(synthetic=true) (PR #140065) Message-ID: https://github.com/labath created https://github.com/llvm/llvm-project/pull/140065 The motivation here is being (un)able to treat pointer values as an array consistently. This works for pointers to simple/scalar values, but for aggregates, we get a very surprising result: - GetChildAtIndex(x, ??, true) returns the `x` child of the zeroth array member (the one you get by dereferencing the pointer/array) for all `x` which are smaller than the number of children of that value. - for other values of `x`, we get `v[x]`, where `v` is treated like a (C) pointer This patch reimagines this interface so that the value of `true` always treats (pointer and array) values as pointers. For `false`, we always dereference pointers, while in the case of arrays, we only return the values as far as the array bounds will allow. This has the potential to break existing code, but I have a suspicion that code was already broken to begin with, which is why I think this would be better than introducing a new API and keeping the old (and surprising behavior). If our own test coverage is any indication, breakage should be minimal. >From 542da1ac1389bb74e2da3385ce1b8d48d47032b4 Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Thu, 15 May 2025 14:55:09 +0200 Subject: [PATCH] [lldb] Retcon SBValue::GetChildAtIndex(synthetic=true) The motivation here is being (un)able to treat pointer values as an array consistently. This works for pointers to simple/scalar values, but for aggregates, we get a very surprising result: - GetChildAtIndex(x, ??, true) returns the `x` child of the zeroth array member (the one you get by dereferencing the pointer/array) for all `x` which are smaller than the number of children of that value. - for other values of `x`, we get `v[x]`, where `v` is treated like a (C) pointer This patch reimagines this interface so that the value of `true` always treats (pointer and array) values as pointers. For `false`, we always dereference pointers, while in the case of arrays, we only return the values as far as the array bounds will allow. This has the potential to break existing code, but I have a suspicion that code was already broken to begin with, which is why I think this would be better than introducing a new API and keeping the old (and surprising behavior). If our own test coverage is any indication, breakage should be minimal. --- lldb/include/lldb/API/SBValue.h | 39 ++++++++----------- lldb/source/API/SBValue.cpp | 15 ++++--- .../sbvalue_synthetic/TestSBValueSynthetic.py | 21 ++++++++++ .../API/python_api/sbvalue_synthetic/main.cpp | 6 +++ 4 files changed, 51 insertions(+), 30 deletions(-) diff --git a/lldb/include/lldb/API/SBValue.h b/lldb/include/lldb/API/SBValue.h index 75d20a4378f09..ad87639960fa0 100644 --- a/lldb/include/lldb/API/SBValue.h +++ b/lldb/include/lldb/API/SBValue.h @@ -160,31 +160,26 @@ class LLDB_API SBValue { /// members (empty base classes are omitted), and all members of the /// current class will then follow the base classes. /// - /// Pointers differ depending on what they point to. If the pointer - /// points to a simple type, the child at index zero - /// is the only child value available, unless \a synthetic_allowed - /// is \b true, in which case the pointer will be used as an array - /// and can create 'synthetic' child values using positive or - /// negative indexes. If the pointer points to an aggregate type - /// (an array, class, union, struct), then the pointee is - /// transparently skipped and any children are going to be the indexes - /// of the child values within the aggregate type. For example if - /// we have a 'Point' type and we have a SBValue that contains a - /// pointer to a 'Point' type, then the child at index zero will be - /// the 'x' member, and the child at index 1 will be the 'y' member - /// (the child at index zero won't be a 'Point' instance). + /// For array and pointers the behavior of the function depends on the value + /// of the \a use_synthetic argument. If \b false, the function returns + /// members of the array as given by the array bounds. If the value is a + /// pointer to a simple type, the child at index zero is the only child + /// value available. If the pointer points to an aggregate type (an array, + /// class, union, etc.), then the pointee is transparently skipped and any + /// children are going to be the indexes of the child values within the + /// aggregate type. For example if we have a 'Point' type and we have a + /// SBValue that contains a pointer to a 'Point' type, then the child at + /// index zero will be the 'x' member, and the child at index 1 will be the + /// 'y' member (the child at index zero won't be a 'Point' instance). If \a + /// use_synthetic is \b true, pointer values will be used as a (C) array and + /// and the function will create 'synthetic' child values using positive or + /// negative indexes. In case of arrays, the function will return values + /// which are outside of the array bounds. /// /// If you actually need an SBValue that represents the type pointed /// to by a SBValue for which GetType().IsPointeeType() returns true, /// regardless of the pointee type, you can do that with SBValue::Dereference. /// - /// Arrays have a preset number of children that can be accessed by - /// index and will returns invalid child values for indexes that are - /// out of bounds unless the \a synthetic_allowed is \b true. In this - /// case the array can create 'synthetic' child values for indexes - /// that aren't in the array bounds using positive or negative - /// indexes. - /// /// \param[in] idx /// The index of the child value to get /// @@ -193,7 +188,7 @@ class LLDB_API SBValue { /// and also if the target can be run to figure out the dynamic /// type of the child value. /// - /// \param[in] can_create_synthetic + /// \param[in] use_synthetic /// If \b true, then allow child values to be created by index /// for pointers and arrays for indexes that normally wouldn't /// be allowed. @@ -202,7 +197,7 @@ class LLDB_API SBValue { /// A new SBValue object that represents the child member value. lldb::SBValue GetChildAtIndex(uint32_t idx, lldb::DynamicValueType use_dynamic, - bool can_create_synthetic); + bool use_synthetic); // Matches children of this object only and will match base classes and // member names if this is a clang typed object. diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp index e5cdc8f311450..feb3f9eae6f33 100644 --- a/lldb/source/API/SBValue.cpp +++ b/lldb/source/API/SBValue.cpp @@ -680,19 +680,18 @@ SBValue SBValue::GetChildAtIndex(uint32_t idx) { SBValue SBValue::GetChildAtIndex(uint32_t idx, lldb::DynamicValueType use_dynamic, - bool can_create_synthetic) { - LLDB_INSTRUMENT_VA(this, idx, use_dynamic, can_create_synthetic); - - lldb::ValueObjectSP child_sp; - + bool use_synthetic) { + LLDB_INSTRUMENT_VA(this, idx, use_dynamic, use_synthetic); ValueLocker locker; lldb::ValueObjectSP value_sp(GetSP(locker)); + + lldb::ValueObjectSP child_sp; if (value_sp) { const bool can_create = true; - child_sp = value_sp->GetChildAtIndex(idx); - if (can_create_synthetic && !child_sp) { + if (use_synthetic && (value_sp->IsPointerType() || value_sp->IsArrayType())) child_sp = value_sp->GetSyntheticArrayMember(idx, can_create); - } + else + child_sp = value_sp->GetChildAtIndex(idx); } SBValue sb_value; diff --git a/lldb/test/API/python_api/sbvalue_synthetic/TestSBValueSynthetic.py b/lldb/test/API/python_api/sbvalue_synthetic/TestSBValueSynthetic.py index 2fd1e0ce9c6a3..7c9b9b97e0a70 100644 --- a/lldb/test/API/python_api/sbvalue_synthetic/TestSBValueSynthetic.py +++ b/lldb/test/API/python_api/sbvalue_synthetic/TestSBValueSynthetic.py @@ -21,3 +21,24 @@ def test_str(self): has_formatted = self.frame().FindVariable("has_foo") self.expect(str(formatted), exe=False, substrs=["synth_child"]) self.expect(str(has_formatted), exe=False, substrs=["synth_child"]) + + def test_synth_arr(self): + self.build() + lldbutil.run_to_source_breakpoint( + self, "break here", lldb.SBFileSpec("main.cpp") + ) + point_arr = self.frame().FindVariable("point_arr"); + point_ptr = self.frame().FindVariable("point_ptr"); + for v in [point_arr, point_ptr]: + for i in range(3): + child = v.GetChildAtIndex(i, lldb.eDynamicDontRunTarget, True) + check = ValueCheck(name=f"[{i}]", type="Point", children=[ValueCheck(name="x", value=str(2*i+1)), ValueCheck(name="y", value=str(2*i+2))]) + check.check_value(self, child, f"{child}, child {i} of {v.GetName()}") + + int_arr = self.frame().FindVariable("int_arr"); + int_ptr = self.frame().FindVariable("int_ptr"); + for v in [int_arr, int_ptr]: + for i in range(3): + child = v.GetChildAtIndex(i, lldb.eDynamicDontRunTarget, True) + check = ValueCheck(name=f"[{i}]", type="int", value=str(i+1)) + check.check_value(self, child, f"{child}, child {i} of {v.GetName()}") diff --git a/lldb/test/API/python_api/sbvalue_synthetic/main.cpp b/lldb/test/API/python_api/sbvalue_synthetic/main.cpp index 52c6474d7a1b2..5ec272b7bc12e 100644 --- a/lldb/test/API/python_api/sbvalue_synthetic/main.cpp +++ b/lldb/test/API/python_api/sbvalue_synthetic/main.cpp @@ -6,8 +6,14 @@ struct HasFoo { Foo f; }; +struct Point { int x; int y; }; + int main() { Foo foo; HasFoo has_foo; + Point point_arr[] = {{1,2},{3,4},{5,6}}; + int int_arr[] = {1,2,3,4,5,6}; + Point *point_ptr = point_arr; + int *int_ptr = int_arr; return 0; // break here } From lldb-commits at lists.llvm.org Thu May 15 07:23:50 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 07:23:50 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Retcon SBValue::GetChildAtIndex(synthetic=true) (PR #140065) In-Reply-To: Message-ID: <6825f8f6.170a0220.f6a50.9188@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Pavel Labath (labath)
Changes The motivation here is being (un)able to treat pointer values as an array consistently. This works for pointers to simple/scalar values, but for aggregates, we get a very surprising result: - GetChildAtIndex(x, ??, true) returns the `x` child of the zeroth array member (the one you get by dereferencing the pointer/array) for all `x` which are smaller than the number of children of that value. - for other values of `x`, we get `v[x]`, where `v` is treated like a (C) pointer This patch reimagines this interface so that the value of `true` always treats (pointer and array) values as pointers. For `false`, we always dereference pointers, while in the case of arrays, we only return the values as far as the array bounds will allow. This has the potential to break existing code, but I have a suspicion that code was already broken to begin with, which is why I think this would be better than introducing a new API and keeping the old (and surprising behavior). If our own test coverage is any indication, breakage should be minimal. --- Full diff: https://github.com/llvm/llvm-project/pull/140065.diff 4 Files Affected: - (modified) lldb/include/lldb/API/SBValue.h (+17-22) - (modified) lldb/source/API/SBValue.cpp (+7-8) - (modified) lldb/test/API/python_api/sbvalue_synthetic/TestSBValueSynthetic.py (+21) - (modified) lldb/test/API/python_api/sbvalue_synthetic/main.cpp (+6) ``````````diff diff --git a/lldb/include/lldb/API/SBValue.h b/lldb/include/lldb/API/SBValue.h index 75d20a4378f09..ad87639960fa0 100644 --- a/lldb/include/lldb/API/SBValue.h +++ b/lldb/include/lldb/API/SBValue.h @@ -160,31 +160,26 @@ class LLDB_API SBValue { /// members (empty base classes are omitted), and all members of the /// current class will then follow the base classes. /// - /// Pointers differ depending on what they point to. If the pointer - /// points to a simple type, the child at index zero - /// is the only child value available, unless \a synthetic_allowed - /// is \b true, in which case the pointer will be used as an array - /// and can create 'synthetic' child values using positive or - /// negative indexes. If the pointer points to an aggregate type - /// (an array, class, union, struct), then the pointee is - /// transparently skipped and any children are going to be the indexes - /// of the child values within the aggregate type. For example if - /// we have a 'Point' type and we have a SBValue that contains a - /// pointer to a 'Point' type, then the child at index zero will be - /// the 'x' member, and the child at index 1 will be the 'y' member - /// (the child at index zero won't be a 'Point' instance). + /// For array and pointers the behavior of the function depends on the value + /// of the \a use_synthetic argument. If \b false, the function returns + /// members of the array as given by the array bounds. If the value is a + /// pointer to a simple type, the child at index zero is the only child + /// value available. If the pointer points to an aggregate type (an array, + /// class, union, etc.), then the pointee is transparently skipped and any + /// children are going to be the indexes of the child values within the + /// aggregate type. For example if we have a 'Point' type and we have a + /// SBValue that contains a pointer to a 'Point' type, then the child at + /// index zero will be the 'x' member, and the child at index 1 will be the + /// 'y' member (the child at index zero won't be a 'Point' instance). If \a + /// use_synthetic is \b true, pointer values will be used as a (C) array and + /// and the function will create 'synthetic' child values using positive or + /// negative indexes. In case of arrays, the function will return values + /// which are outside of the array bounds. /// /// If you actually need an SBValue that represents the type pointed /// to by a SBValue for which GetType().IsPointeeType() returns true, /// regardless of the pointee type, you can do that with SBValue::Dereference. /// - /// Arrays have a preset number of children that can be accessed by - /// index and will returns invalid child values for indexes that are - /// out of bounds unless the \a synthetic_allowed is \b true. In this - /// case the array can create 'synthetic' child values for indexes - /// that aren't in the array bounds using positive or negative - /// indexes. - /// /// \param[in] idx /// The index of the child value to get /// @@ -193,7 +188,7 @@ class LLDB_API SBValue { /// and also if the target can be run to figure out the dynamic /// type of the child value. /// - /// \param[in] can_create_synthetic + /// \param[in] use_synthetic /// If \b true, then allow child values to be created by index /// for pointers and arrays for indexes that normally wouldn't /// be allowed. @@ -202,7 +197,7 @@ class LLDB_API SBValue { /// A new SBValue object that represents the child member value. lldb::SBValue GetChildAtIndex(uint32_t idx, lldb::DynamicValueType use_dynamic, - bool can_create_synthetic); + bool use_synthetic); // Matches children of this object only and will match base classes and // member names if this is a clang typed object. diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp index e5cdc8f311450..feb3f9eae6f33 100644 --- a/lldb/source/API/SBValue.cpp +++ b/lldb/source/API/SBValue.cpp @@ -680,19 +680,18 @@ SBValue SBValue::GetChildAtIndex(uint32_t idx) { SBValue SBValue::GetChildAtIndex(uint32_t idx, lldb::DynamicValueType use_dynamic, - bool can_create_synthetic) { - LLDB_INSTRUMENT_VA(this, idx, use_dynamic, can_create_synthetic); - - lldb::ValueObjectSP child_sp; - + bool use_synthetic) { + LLDB_INSTRUMENT_VA(this, idx, use_dynamic, use_synthetic); ValueLocker locker; lldb::ValueObjectSP value_sp(GetSP(locker)); + + lldb::ValueObjectSP child_sp; if (value_sp) { const bool can_create = true; - child_sp = value_sp->GetChildAtIndex(idx); - if (can_create_synthetic && !child_sp) { + if (use_synthetic && (value_sp->IsPointerType() || value_sp->IsArrayType())) child_sp = value_sp->GetSyntheticArrayMember(idx, can_create); - } + else + child_sp = value_sp->GetChildAtIndex(idx); } SBValue sb_value; diff --git a/lldb/test/API/python_api/sbvalue_synthetic/TestSBValueSynthetic.py b/lldb/test/API/python_api/sbvalue_synthetic/TestSBValueSynthetic.py index 2fd1e0ce9c6a3..7c9b9b97e0a70 100644 --- a/lldb/test/API/python_api/sbvalue_synthetic/TestSBValueSynthetic.py +++ b/lldb/test/API/python_api/sbvalue_synthetic/TestSBValueSynthetic.py @@ -21,3 +21,24 @@ def test_str(self): has_formatted = self.frame().FindVariable("has_foo") self.expect(str(formatted), exe=False, substrs=["synth_child"]) self.expect(str(has_formatted), exe=False, substrs=["synth_child"]) + + def test_synth_arr(self): + self.build() + lldbutil.run_to_source_breakpoint( + self, "break here", lldb.SBFileSpec("main.cpp") + ) + point_arr = self.frame().FindVariable("point_arr"); + point_ptr = self.frame().FindVariable("point_ptr"); + for v in [point_arr, point_ptr]: + for i in range(3): + child = v.GetChildAtIndex(i, lldb.eDynamicDontRunTarget, True) + check = ValueCheck(name=f"[{i}]", type="Point", children=[ValueCheck(name="x", value=str(2*i+1)), ValueCheck(name="y", value=str(2*i+2))]) + check.check_value(self, child, f"{child}, child {i} of {v.GetName()}") + + int_arr = self.frame().FindVariable("int_arr"); + int_ptr = self.frame().FindVariable("int_ptr"); + for v in [int_arr, int_ptr]: + for i in range(3): + child = v.GetChildAtIndex(i, lldb.eDynamicDontRunTarget, True) + check = ValueCheck(name=f"[{i}]", type="int", value=str(i+1)) + check.check_value(self, child, f"{child}, child {i} of {v.GetName()}") diff --git a/lldb/test/API/python_api/sbvalue_synthetic/main.cpp b/lldb/test/API/python_api/sbvalue_synthetic/main.cpp index 52c6474d7a1b2..5ec272b7bc12e 100644 --- a/lldb/test/API/python_api/sbvalue_synthetic/main.cpp +++ b/lldb/test/API/python_api/sbvalue_synthetic/main.cpp @@ -6,8 +6,14 @@ struct HasFoo { Foo f; }; +struct Point { int x; int y; }; + int main() { Foo foo; HasFoo has_foo; + Point point_arr[] = {{1,2},{3,4},{5,6}}; + int int_arr[] = {1,2,3,4,5,6}; + Point *point_ptr = point_arr; + int *int_ptr = int_arr; return 0; // break here } ``````````
https://github.com/llvm/llvm-project/pull/140065 From lldb-commits at lists.llvm.org Thu May 15 07:24:24 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Thu, 15 May 2025 07:24:24 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Adding NativeThreadAIX (PR #139537) In-Reply-To: Message-ID: <6825f918.a70a0220.25f73e.9f3e@mx.google.com> https://github.com/labath approved this pull request. Ship it. https://github.com/llvm/llvm-project/pull/139537 From lldb-commits at lists.llvm.org Thu May 15 07:25:35 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 07:25:35 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Retcon SBValue::GetChildAtIndex(synthetic=true) (PR #140065) In-Reply-To: Message-ID: <6825f95f.170a0220.2d5d49.aad9@mx.google.com> github-actions[bot] wrote: :warning: Python code formatter, darker found issues in your code. :warning:
You can test this locally with the following command: ``````````bash darker --check --diff -r HEAD~1...HEAD lldb/test/API/python_api/sbvalue_synthetic/TestSBValueSynthetic.py ``````````
View the diff from darker here. ``````````diff --- TestSBValueSynthetic.py 2025-05-15 12:55:09.000000 +0000 +++ TestSBValueSynthetic.py 2025-05-15 14:25:08.027332 +0000 @@ -25,20 +25,27 @@ def test_synth_arr(self): self.build() lldbutil.run_to_source_breakpoint( self, "break here", lldb.SBFileSpec("main.cpp") ) - point_arr = self.frame().FindVariable("point_arr"); - point_ptr = self.frame().FindVariable("point_ptr"); + point_arr = self.frame().FindVariable("point_arr") + point_ptr = self.frame().FindVariable("point_ptr") for v in [point_arr, point_ptr]: - for i in range(3): - child = v.GetChildAtIndex(i, lldb.eDynamicDontRunTarget, True) - check = ValueCheck(name=f"[{i}]", type="Point", children=[ValueCheck(name="x", value=str(2*i+1)), ValueCheck(name="y", value=str(2*i+2))]) - check.check_value(self, child, f"{child}, child {i} of {v.GetName()}") + for i in range(3): + child = v.GetChildAtIndex(i, lldb.eDynamicDontRunTarget, True) + check = ValueCheck( + name=f"[{i}]", + type="Point", + children=[ + ValueCheck(name="x", value=str(2 * i + 1)), + ValueCheck(name="y", value=str(2 * i + 2)), + ], + ) + check.check_value(self, child, f"{child}, child {i} of {v.GetName()}") - int_arr = self.frame().FindVariable("int_arr"); - int_ptr = self.frame().FindVariable("int_ptr"); + int_arr = self.frame().FindVariable("int_arr") + int_ptr = self.frame().FindVariable("int_ptr") for v in [int_arr, int_ptr]: - for i in range(3): - child = v.GetChildAtIndex(i, lldb.eDynamicDontRunTarget, True) - check = ValueCheck(name=f"[{i}]", type="int", value=str(i+1)) - check.check_value(self, child, f"{child}, child {i} of {v.GetName()}") + for i in range(3): + child = v.GetChildAtIndex(i, lldb.eDynamicDontRunTarget, True) + check = ValueCheck(name=f"[{i}]", type="int", value=str(i + 1)) + check.check_value(self, child, f"{child}, child {i} of {v.GetName()}") ``````````
https://github.com/llvm/llvm-project/pull/140065 From lldb-commits at lists.llvm.org Thu May 15 07:25:35 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 07:25:35 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Retcon SBValue::GetChildAtIndex(synthetic=true) (PR #140065) In-Reply-To: Message-ID: <6825f95f.170a0220.774df.986c@mx.google.com> github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning:
You can test this locally with the following command: ``````````bash git-clang-format --diff HEAD~1 HEAD --extensions h,cpp -- lldb/include/lldb/API/SBValue.h lldb/source/API/SBValue.cpp lldb/test/API/python_api/sbvalue_synthetic/main.cpp ``````````
View the diff from clang-format here. ``````````diff diff --git a/lldb/test/API/python_api/sbvalue_synthetic/main.cpp b/lldb/test/API/python_api/sbvalue_synthetic/main.cpp index 5ec272b7b..d9b65f017 100644 --- a/lldb/test/API/python_api/sbvalue_synthetic/main.cpp +++ b/lldb/test/API/python_api/sbvalue_synthetic/main.cpp @@ -6,13 +6,16 @@ struct HasFoo { Foo f; }; -struct Point { int x; int y; }; +struct Point { + int x; + int y; +}; int main() { Foo foo; HasFoo has_foo; - Point point_arr[] = {{1,2},{3,4},{5,6}}; - int int_arr[] = {1,2,3,4,5,6}; + Point point_arr[] = {{1, 2}, {3, 4}, {5, 6}}; + int int_arr[] = {1, 2, 3, 4, 5, 6}; Point *point_ptr = point_arr; int *int_ptr = int_arr; return 0; // break here ``````````
https://github.com/llvm/llvm-project/pull/140065 From lldb-commits at lists.llvm.org Thu May 15 07:31:47 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Thu, 15 May 2025 07:31:47 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Retcon SBValue::GetChildAtIndex(synthetic=true) (PR #140065) In-Reply-To: Message-ID: <6825fad3.170a0220.1b53f7.97ba@mx.google.com> https://github.com/labath updated https://github.com/llvm/llvm-project/pull/140065 >From 59829616c0897325795f667a8cd3bdcb309ff91c Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Thu, 15 May 2025 14:55:09 +0200 Subject: [PATCH] [lldb] Retcon SBValue::GetChildAtIndex(synthetic=true) The motivation here is being (un)able to treat pointer values as an array consistently. This works for pointers to simple/scalar values, but for aggregates, we get a very surprising result: - GetChildAtIndex(x, ??, true) returns the `x` child of the zeroth array member (the one you get by dereferencing the pointer/array) for all `x` which are smaller than the number of children of that value. - for other values of `x`, we get `v[x]`, where `v` is treated like a (C) pointer This patch reimagines this interface so that the value of `true` always treats (pointer and array) values as pointers. For `false`, we always dereference pointers, while in the case of arrays, we only return the values as far as the array bounds will allow. This has the potential to break existing code, but I have a suspicion that code was already broken to begin with, which is why I think this would be better than introducing a new API and keeping the old (and surprising behavior). If our own test coverage is any indication, breakage should be minimal. --- lldb/include/lldb/API/SBValue.h | 39 ++++++++----------- lldb/source/API/SBValue.cpp | 15 ++++--- .../sbvalue_synthetic/TestSBValueSynthetic.py | 28 +++++++++++++ .../API/python_api/sbvalue_synthetic/main.cpp | 9 +++++ 4 files changed, 61 insertions(+), 30 deletions(-) diff --git a/lldb/include/lldb/API/SBValue.h b/lldb/include/lldb/API/SBValue.h index 75d20a4378f09..ad87639960fa0 100644 --- a/lldb/include/lldb/API/SBValue.h +++ b/lldb/include/lldb/API/SBValue.h @@ -160,31 +160,26 @@ class LLDB_API SBValue { /// members (empty base classes are omitted), and all members of the /// current class will then follow the base classes. /// - /// Pointers differ depending on what they point to. If the pointer - /// points to a simple type, the child at index zero - /// is the only child value available, unless \a synthetic_allowed - /// is \b true, in which case the pointer will be used as an array - /// and can create 'synthetic' child values using positive or - /// negative indexes. If the pointer points to an aggregate type - /// (an array, class, union, struct), then the pointee is - /// transparently skipped and any children are going to be the indexes - /// of the child values within the aggregate type. For example if - /// we have a 'Point' type and we have a SBValue that contains a - /// pointer to a 'Point' type, then the child at index zero will be - /// the 'x' member, and the child at index 1 will be the 'y' member - /// (the child at index zero won't be a 'Point' instance). + /// For array and pointers the behavior of the function depends on the value + /// of the \a use_synthetic argument. If \b false, the function returns + /// members of the array as given by the array bounds. If the value is a + /// pointer to a simple type, the child at index zero is the only child + /// value available. If the pointer points to an aggregate type (an array, + /// class, union, etc.), then the pointee is transparently skipped and any + /// children are going to be the indexes of the child values within the + /// aggregate type. For example if we have a 'Point' type and we have a + /// SBValue that contains a pointer to a 'Point' type, then the child at + /// index zero will be the 'x' member, and the child at index 1 will be the + /// 'y' member (the child at index zero won't be a 'Point' instance). If \a + /// use_synthetic is \b true, pointer values will be used as a (C) array and + /// and the function will create 'synthetic' child values using positive or + /// negative indexes. In case of arrays, the function will return values + /// which are outside of the array bounds. /// /// If you actually need an SBValue that represents the type pointed /// to by a SBValue for which GetType().IsPointeeType() returns true, /// regardless of the pointee type, you can do that with SBValue::Dereference. /// - /// Arrays have a preset number of children that can be accessed by - /// index and will returns invalid child values for indexes that are - /// out of bounds unless the \a synthetic_allowed is \b true. In this - /// case the array can create 'synthetic' child values for indexes - /// that aren't in the array bounds using positive or negative - /// indexes. - /// /// \param[in] idx /// The index of the child value to get /// @@ -193,7 +188,7 @@ class LLDB_API SBValue { /// and also if the target can be run to figure out the dynamic /// type of the child value. /// - /// \param[in] can_create_synthetic + /// \param[in] use_synthetic /// If \b true, then allow child values to be created by index /// for pointers and arrays for indexes that normally wouldn't /// be allowed. @@ -202,7 +197,7 @@ class LLDB_API SBValue { /// A new SBValue object that represents the child member value. lldb::SBValue GetChildAtIndex(uint32_t idx, lldb::DynamicValueType use_dynamic, - bool can_create_synthetic); + bool use_synthetic); // Matches children of this object only and will match base classes and // member names if this is a clang typed object. diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp index e5cdc8f311450..feb3f9eae6f33 100644 --- a/lldb/source/API/SBValue.cpp +++ b/lldb/source/API/SBValue.cpp @@ -680,19 +680,18 @@ SBValue SBValue::GetChildAtIndex(uint32_t idx) { SBValue SBValue::GetChildAtIndex(uint32_t idx, lldb::DynamicValueType use_dynamic, - bool can_create_synthetic) { - LLDB_INSTRUMENT_VA(this, idx, use_dynamic, can_create_synthetic); - - lldb::ValueObjectSP child_sp; - + bool use_synthetic) { + LLDB_INSTRUMENT_VA(this, idx, use_dynamic, use_synthetic); ValueLocker locker; lldb::ValueObjectSP value_sp(GetSP(locker)); + + lldb::ValueObjectSP child_sp; if (value_sp) { const bool can_create = true; - child_sp = value_sp->GetChildAtIndex(idx); - if (can_create_synthetic && !child_sp) { + if (use_synthetic && (value_sp->IsPointerType() || value_sp->IsArrayType())) child_sp = value_sp->GetSyntheticArrayMember(idx, can_create); - } + else + child_sp = value_sp->GetChildAtIndex(idx); } SBValue sb_value; diff --git a/lldb/test/API/python_api/sbvalue_synthetic/TestSBValueSynthetic.py b/lldb/test/API/python_api/sbvalue_synthetic/TestSBValueSynthetic.py index 2fd1e0ce9c6a3..8b36308de63da 100644 --- a/lldb/test/API/python_api/sbvalue_synthetic/TestSBValueSynthetic.py +++ b/lldb/test/API/python_api/sbvalue_synthetic/TestSBValueSynthetic.py @@ -21,3 +21,31 @@ def test_str(self): has_formatted = self.frame().FindVariable("has_foo") self.expect(str(formatted), exe=False, substrs=["synth_child"]) self.expect(str(has_formatted), exe=False, substrs=["synth_child"]) + + def test_synth_arr(self): + self.build() + lldbutil.run_to_source_breakpoint( + self, "break here", lldb.SBFileSpec("main.cpp") + ) + point_arr = self.frame().FindVariable("point_arr") + point_ptr = self.frame().FindVariable("point_ptr") + for v in [point_arr, point_ptr]: + for i in range(3): + child = v.GetChildAtIndex(i, lldb.eDynamicDontRunTarget, True) + check = ValueCheck( + name=f"[{i}]", + type="Point", + children=[ + ValueCheck(name="x", value=str(2 * i + 1)), + ValueCheck(name="y", value=str(2 * i + 2)), + ], + ) + check.check_value(self, child, f"{child}, child {i} of {v.GetName()}") + + int_arr = self.frame().FindVariable("int_arr") + int_ptr = self.frame().FindVariable("int_ptr") + for v in [int_arr, int_ptr]: + for i in range(3): + child = v.GetChildAtIndex(i, lldb.eDynamicDontRunTarget, True) + check = ValueCheck(name=f"[{i}]", type="int", value=str(i + 1)) + check.check_value(self, child, f"{child}, child {i} of {v.GetName()}") diff --git a/lldb/test/API/python_api/sbvalue_synthetic/main.cpp b/lldb/test/API/python_api/sbvalue_synthetic/main.cpp index 52c6474d7a1b2..d9b65f017a30a 100644 --- a/lldb/test/API/python_api/sbvalue_synthetic/main.cpp +++ b/lldb/test/API/python_api/sbvalue_synthetic/main.cpp @@ -6,8 +6,17 @@ struct HasFoo { Foo f; }; +struct Point { + int x; + int y; +}; + int main() { Foo foo; HasFoo has_foo; + Point point_arr[] = {{1, 2}, {3, 4}, {5, 6}}; + int int_arr[] = {1, 2, 3, 4, 5, 6}; + Point *point_ptr = point_arr; + int *int_ptr = int_arr; return 0; // break here } From lldb-commits at lists.llvm.org Thu May 15 07:51:15 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Thu, 15 May 2025 07:51:15 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Adding NativeThreadAIX (PR #139537) In-Reply-To: Message-ID: <6825ff63.170a0220.d7ca5.c186@mx.google.com> https://github.com/DhruvSrivastavaX updated https://github.com/llvm/llvm-project/pull/139537 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Thu May 15 08:26:22 2025 From: lldb-commits at lists.llvm.org (Vy Nguyen via lldb-commits) Date: Thu, 15 May 2025 08:26:22 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb]Make `list` command work with headers when possible. (PR #139002) In-Reply-To: Message-ID: <6826079e.170a0220.1c14cd.1052@mx.google.com> https://github.com/oontvoo updated https://github.com/llvm/llvm-project/pull/139002 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Thu May 15 08:26:36 2025 From: lldb-commits at lists.llvm.org (Vy Nguyen via lldb-commits) Date: Thu, 15 May 2025 08:26:36 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb]Make `list` command work with headers when possible. (PR #139002) In-Reply-To: Message-ID: <682607ac.170a0220.11ca71.e0a8@mx.google.com> ================ @@ -714,6 +714,8 @@ uint32_t ModuleList::ResolveSymbolContextsForFileSpec( const FileSpec &file_spec, uint32_t line, bool check_inlines, SymbolContextItem resolve_scope, SymbolContextList &sc_list) const { std::lock_guard guard(m_modules_mutex); + // If we're looking for a header (not source), then need to check inline. + check_inlines = check_inlines || !file_spec.IsSourceImplementationFile(); ---------------- oontvoo wrote: Done! Thanks for the pointer! :) https://github.com/llvm/llvm-project/pull/139002 From lldb-commits at lists.llvm.org Thu May 15 08:27:12 2025 From: lldb-commits at lists.llvm.org (Vy Nguyen via lldb-commits) Date: Thu, 15 May 2025 08:27:12 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb]Make `list` command work with headers when possible. (PR #139002) In-Reply-To: Message-ID: <682607d0.170a0220.19af70.155e@mx.google.com> https://github.com/oontvoo updated https://github.com/llvm/llvm-project/pull/139002 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Thu May 15 09:14:56 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Thu, 15 May 2025 09:14:56 -0700 (PDT) Subject: [Lldb-commits] [lldb] Fix race condition during iteration through modules (#139283) (PR #139862) In-Reply-To: Message-ID: <68261300.050a0220.997be.52ab@mx.google.com> https://github.com/JDevlieghere approved this pull request. Thank you! https://github.com/llvm/llvm-project/pull/139862 From lldb-commits at lists.llvm.org Thu May 15 09:58:00 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 09:58:00 -0700 (PDT) Subject: [Lldb-commits] [clang] [flang] [lld] [lldb] [llvm] [mlir] [polly] [CMake] respect LLVMConfig.cmake's LLVM_DEFINITIONS in standalone builds (PR #138587) In-Reply-To: Message-ID: <68261d18.050a0220.1fb92d.0f30@mx.google.com> https://github.com/jeremyd2019 updated https://github.com/llvm/llvm-project/pull/138587 >From 052580cd9ee141cd8c79e9588ad1c71e31f58cb3 Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Mon, 5 May 2025 14:11:44 -0700 Subject: [PATCH 1/7] [CMake] respect LLVMConfig.cmake's LLVM_DEFINITIONS In #138329, _GNU_SOURCE was added for Cygwin, but when building Clang standalone against an installed LLVM this definition was not picked up, resulting in undefined strnlen. Follow the documentation in https://llvm.org/docs/CMake.html#developing-llvm-passes-out-of-source and add the LLVM_DEFINITIONS in standalone projects' cmakes. --- clang/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clang/CMakeLists.txt b/clang/CMakeLists.txt index f12712f55fb96..ab2ac9bc6b9ad 100644 --- a/clang/CMakeLists.txt +++ b/clang/CMakeLists.txt @@ -68,6 +68,10 @@ if(CLANG_BUILT_STANDALONE) option(CLANG_ENABLE_BOOTSTRAP "Generate the clang bootstrap target" OFF) option(LLVM_ENABLE_LIBXML2 "Use libxml2 if available." ON) + separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS}) + add_definitions(${LLVM_DEFINITIONS_LIST}) + list(APPEND CMAKE_REQUIRED_DEFINITIONS ${LLVM_DEFINITIONS_LIST}) + include(AddLLVM) include(TableGen) include(HandleLLVMOptions) >From a59bbb92c54d81d06754d49190d7a46ba269b1ef Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Wed, 7 May 2025 11:24:55 -0700 Subject: [PATCH 2/7] fixup! [CMake] respect LLVMConfig.cmake's LLVM_DEFINITIONS bolt --- bolt/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bolt/CMakeLists.txt b/bolt/CMakeLists.txt index 52c796518ac05..5c7d51e1e398c 100644 --- a/bolt/CMakeLists.txt +++ b/bolt/CMakeLists.txt @@ -46,6 +46,10 @@ if(BOLT_BUILT_STANDALONE) set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin) set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX}) + separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS}) + add_definitions(${LLVM_DEFINITIONS_LIST}) + list(APPEND CMAKE_REQUIRED_DEFINITIONS ${LLVM_DEFINITIONS_LIST}) + include(AddLLVM) include(TableGen) include_directories(${LLVM_INCLUDE_DIRS}) >From 595f483ff1403f282217ff4999f7640465b5dada Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Wed, 7 May 2025 11:27:53 -0700 Subject: [PATCH 3/7] fixup! [CMake] respect LLVMConfig.cmake's LLVM_DEFINITIONS flang --- flang/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/flang/CMakeLists.txt b/flang/CMakeLists.txt index f358a93fdd792..56a96f590f0a3 100644 --- a/flang/CMakeLists.txt +++ b/flang/CMakeLists.txt @@ -140,6 +140,11 @@ if (FLANG_STANDALONE_BUILD) if (NOT DEFINED LLVM_MAIN_SRC_DIR) set(LLVM_MAIN_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../llvm") endif() + + separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS}) + add_definitions(${LLVM_DEFINITIONS_LIST}) + list(APPEND CMAKE_REQUIRED_DEFINITIONS ${LLVM_DEFINITIONS_LIST}) + include(AddLLVM) include(HandleLLVMOptions) include(VersionFromVCS) >From 8eeb00ff57a90ae7e4a775f7fa85a4d3529f143d Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Wed, 7 May 2025 11:28:22 -0700 Subject: [PATCH 4/7] fixup! [CMake] respect LLVMConfig.cmake's LLVM_DEFINITIONS lld --- lld/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lld/CMakeLists.txt b/lld/CMakeLists.txt index 9b202cc5d4899..80e25204a65ee 100644 --- a/lld/CMakeLists.txt +++ b/lld/CMakeLists.txt @@ -39,6 +39,10 @@ if(LLD_BUILT_STANDALONE) set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin) set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX}) + separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS}) + add_definitions(${LLVM_DEFINITIONS_LIST}) + list(APPEND CMAKE_REQUIRED_DEFINITIONS ${LLVM_DEFINITIONS_LIST}) + include(AddLLVM) include(TableGen) include(HandleLLVMOptions) >From e2510293883ff6499890de1a4a5de4c1d53beac3 Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Wed, 7 May 2025 11:31:01 -0700 Subject: [PATCH 5/7] fixup! [CMake] respect LLVMConfig.cmake's LLVM_DEFINITIONS lldb --- lldb/cmake/modules/LLDBStandalone.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lldb/cmake/modules/LLDBStandalone.cmake b/lldb/cmake/modules/LLDBStandalone.cmake index c9367214848fd..1a4cdbfbb1cc7 100644 --- a/lldb/cmake/modules/LLDBStandalone.cmake +++ b/lldb/cmake/modules/LLDBStandalone.cmake @@ -85,6 +85,10 @@ endif() # CMake modules to be in that directory as well. list(APPEND CMAKE_MODULE_PATH "${LLVM_DIR}") +separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS}) +add_definitions(${LLVM_DEFINITIONS_LIST}) +list(APPEND CMAKE_REQUIRED_DEFINITIONS ${LLVM_DEFINITIONS_LIST}) + include(AddLLVM) include(TableGen) include(HandleLLVMOptions) >From f9f30f2871fd3f5eedcf90b6f41c8e17b9d19ff3 Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Wed, 7 May 2025 11:31:41 -0700 Subject: [PATCH 6/7] fixup! [CMake] respect LLVMConfig.cmake's LLVM_DEFINITIONS mlir --- mlir/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mlir/CMakeLists.txt b/mlir/CMakeLists.txt index 9e786154a2b40..daedc2be22588 100644 --- a/mlir/CMakeLists.txt +++ b/mlir/CMakeLists.txt @@ -21,6 +21,11 @@ set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to conform to") if(MLIR_STANDALONE_BUILD) find_package(LLVM CONFIG REQUIRED) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${LLVM_CMAKE_DIR}) + + separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS}) + add_definitions(${LLVM_DEFINITIONS_LIST}) + list(APPEND CMAKE_REQUIRED_DEFINITIONS ${LLVM_DEFINITIONS_LIST}) + include(HandleLLVMOptions) include(AddLLVM) include(TableGen) >From be29dee4f077212da72ffa28815dafe9a0491f85 Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Wed, 7 May 2025 11:32:11 -0700 Subject: [PATCH 7/7] fixup! [CMake] respect LLVMConfig.cmake's LLVM_DEFINITIONS polly --- polly/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/polly/CMakeLists.txt b/polly/CMakeLists.txt index c3232752d307c..52d1be6fe295a 100644 --- a/polly/CMakeLists.txt +++ b/polly/CMakeLists.txt @@ -13,6 +13,11 @@ if(POLLY_STANDALONE_BUILD) # Where is LLVM installed? find_package(LLVM CONFIG REQUIRED) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${LLVM_CMAKE_DIR}) + + separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS}) + add_definitions(${LLVM_DEFINITIONS_LIST}) + list(APPEND CMAKE_REQUIRED_DEFINITIONS ${LLVM_DEFINITIONS_LIST}) + include(HandleLLVMOptions) include(AddLLVM) From lldb-commits at lists.llvm.org Thu May 15 10:01:15 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 10:01:15 -0700 (PDT) Subject: [Lldb-commits] [clang] [flang] [lld] [lldb] [llvm] [mlir] [polly] [CMake] respect LLVMConfig.cmake's LLVM_DEFINITIONS in standalone builds (PR #138587) In-Reply-To: Message-ID: <68261ddb.170a0220.3037c1.0651@mx.google.com> jeremyd2019 wrote: > > I rebased this on top of #138783 and adjusted the title and description. Now it should be in a good state to push cmake changes for other projects. > > The changes look good, but it looks like the changes from #138783 still show up when viewing the changes; can you check that you've rebased past the merged #138783? I had not - I have now though. > (Also, I take it that no other subprojects than clang need the `cmake_push_check_state` change?) No, the other projects were not messing with `_GNU_SOURCE` like clang was. https://github.com/llvm/llvm-project/pull/138587 From lldb-commits at lists.llvm.org Thu May 15 10:29:14 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Thu, 15 May 2025 10:29:14 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding additional asserts to unit tests. (PR #140107) Message-ID: https://github.com/ashgti created https://github.com/llvm/llvm-project/pull/140107 Adding an assert that the 'continue' request succeeds caused a number of tests to fail. This showed a number of tests that were not specifying if they should be stopped or not at key points in the test. This is likely contributing to these tests being flaky since the debugger is not in the expected state. Additionally, I spent a little time trying to improve the readability of the dap_server.py and lldbdap_testcase.py. Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Thu May 15 10:29:51 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 10:29:51 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding additional asserts to unit tests. (PR #140107) In-Reply-To: Message-ID: <6826248f.170a0220.2d0568.1142@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: John Harrison (ashgti)
Changes Adding an assert that the 'continue' request succeeds caused a number of tests to fail. This showed a number of tests that were not specifying if they should be stopped or not at key points in the test. This is likely contributing to these tests being flaky since the debugger is not in the expected state. Additionally, I spent a little time trying to improve the readability of the dap_server.py and lldbdap_testcase.py. --- Patch is 55.89 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/140107.diff 18 Files Affected: - (modified) lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py (+130-98) - (modified) lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py (+57-170) - (modified) lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py (+9-7) - (modified) lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py (+2-5) - (modified) lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py (+1-3) - (modified) lldb/test/API/tools/lldb-dap/commands/TestDAP_commands.py (+3-2) - (modified) lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py (+5-5) - (modified) lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py (+5-5) - (modified) lldb/test/API/tools/lldb-dap/exception/TestDAP_exception.py (+1) - (modified) lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py (+11-10) - (modified) lldb/test/API/tools/lldb-dap/module/TestDAP_module.py (+2-2) - (modified) lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py (+21-22) - (modified) lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py (-5) - (modified) lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py (+1-1) - (modified) lldb/tools/lldb-dap/DAPError.cpp (+9) - (modified) lldb/tools/lldb-dap/DAPError.h (+10-1) - (modified) lldb/tools/lldb-dap/Handler/ContinueRequestHandler.cpp (+4-1) - (modified) lldb/tools/lldb-dap/Handler/RequestHandler.h (+40-33) ``````````diff diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index 73f7b0e91d57a..205b30ff4d2ec 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -12,6 +12,13 @@ import sys import threading import time +from typing import Any, Optional, Union, BinaryIO, TextIO + +## DAP type references +Event = dict[str, Any] +Request = dict[str, Any] +Response = dict[str, Any] +ProtocolMessage = Union[Event, Request, Response] def dump_memory(base_addr, data, num_per_line, outfile): @@ -98,55 +105,40 @@ def dump_dap_log(log_file): print("========= END =========", file=sys.stderr) -def read_packet_thread(vs_comm, log_file): - done = False - try: - while not done: - packet = read_packet(vs_comm.recv, trace_file=vs_comm.trace_file) - # `packet` will be `None` on EOF. We want to pass it down to - # handle_recv_packet anyway so the main thread can handle unexpected - # termination of lldb-dap and stop waiting for new packets. - done = not vs_comm.handle_recv_packet(packet) - finally: - # Wait for the process to fully exit before dumping the log file to - # ensure we have the entire log contents. - if vs_comm.process is not None: - try: - # Do not wait forever, some logs are better than none. - vs_comm.process.wait(timeout=20) - except subprocess.TimeoutExpired: - pass - dump_dap_log(log_file) - - class DebugCommunication(object): - def __init__(self, recv, send, init_commands, log_file=None): - self.trace_file = None + def __init__( + self, + recv: BinaryIO, + send: BinaryIO, + init_commands: list[str], + log_file: Optional[TextIO] = None, + ): + # For debugging test failures, try setting `trace_file = sys.stderr`. + self.trace_file: Optional[TextIO] = None + self.log_file = log_file self.send = send self.recv = recv - self.recv_packets = [] + self.recv_packets: list[Optional[ProtocolMessage]] = [] self.recv_condition = threading.Condition() - self.recv_thread = threading.Thread( - target=read_packet_thread, args=(self, log_file) - ) + self.recv_thread = threading.Thread(target=self._read_packet_thread) self.process_event_body = None - self.exit_status = None + self.exit_status: Optional[int] = None self.initialize_body = None - self.thread_stop_reasons = {} - self.progress_events = [] + self.progress_events: list[Event] = [] self.reverse_requests = [] self.sequence = 1 self.threads = None + self.thread_stop_reasons = {} self.recv_thread.start() self.output_condition = threading.Condition() - self.output = {} + self.output: dict[str, list[str]] = {} self.configuration_done_sent = False self.frame_scopes = {} self.init_commands = init_commands self.disassembled_instructions = {} @classmethod - def encode_content(cls, s): + def encode_content(cls, s: str) -> bytes: return ("Content-Length: %u\r\n\r\n%s" % (len(s), s)).encode("utf-8") @classmethod @@ -156,6 +148,18 @@ def validate_response(cls, command, response): if command["seq"] != response["request_seq"]: raise ValueError("seq mismatch in response") + def _read_packet_thread(self): + done = False + try: + while not done: + packet = read_packet(self.recv, trace_file=self.trace_file) + # `packet` will be `None` on EOF. We want to pass it down to + # handle_recv_packet anyway so the main thread can handle unexpected + # termination of lldb-dap and stop waiting for new packets. + done = not self._handle_recv_packet(packet) + finally: + dump_dap_log(self.log_file) + def get_modules(self): module_list = self.request_modules()["body"]["modules"] modules = {} @@ -190,13 +194,13 @@ def collect_output(self, category, timeout_secs, pattern, clear=True): break return collected_output if collected_output else None - def enqueue_recv_packet(self, packet): + def _enqueue_recv_packet(self, packet: Optional[ProtocolMessage]): self.recv_condition.acquire() self.recv_packets.append(packet) self.recv_condition.notify() self.recv_condition.release() - def handle_recv_packet(self, packet): + def _handle_recv_packet(self, packet: Optional[ProtocolMessage]) -> bool: """Called by the read thread that is waiting for all incoming packets to store the incoming packet in "self.recv_packets" in a thread safe way. This function will then signal the "self.recv_condition" to @@ -205,7 +209,7 @@ def handle_recv_packet(self, packet): """ # If EOF, notify the read thread by enqueuing a None. if not packet: - self.enqueue_recv_packet(None) + self._enqueue_recv_packet(None) return False # Check the packet to see if is an event packet @@ -235,6 +239,18 @@ def handle_recv_packet(self, packet): # When a new process is attached or launched, remember the # details that are available in the body of the event self.process_event_body = body + elif event == "exited": + # Process exited, mark the status to indicate the process is not + # alive. + self.exit_status = body["exitCode"] + elif event == "continued": + # When the process continues, clear the known threads and + # thread_stop_reasons. + all_threads_continued = body.get("allThreadsContinued", True) + tid = body["threadId"] + if tid in self.thread_stop_reasons: + del self.thread_stop_reasons[tid] + self._process_continued(all_threads_continued) elif event == "stopped": # Each thread that stops with a reason will send a # 'stopped' event. We need to remember the thread stop @@ -252,10 +268,16 @@ def handle_recv_packet(self, packet): elif packet_type == "response": if packet["command"] == "disconnect": keepGoing = False - self.enqueue_recv_packet(packet) + self._enqueue_recv_packet(packet) return keepGoing - def send_packet(self, command_dict, set_sequence=True): + def _process_continued(self, all_threads_continued: bool): + self.threads = None + self.frame_scopes = {} + if all_threads_continued: + self.thread_stop_reasons = {} + + def send_packet(self, command_dict: Request, set_sequence=True): """Take the "command_dict" python dictionary and encode it as a JSON string and send the contents as a packet to the VSCode debug adapter""" @@ -273,7 +295,12 @@ def send_packet(self, command_dict, set_sequence=True): self.send.write(self.encode_content(json_str)) self.send.flush() - def recv_packet(self, filter_type=None, filter_event=None, timeout=None): + def recv_packet( + self, + filter_type: Optional[str] = None, + filter_event: Optional[Union[str, list[str]]] = None, + timeout: Optional[float] = None, + ) -> Optional[ProtocolMessage]: """Get a JSON packet from the VSCode debug adapter. This function assumes a thread that reads packets is running and will deliver any received packets by calling handle_recv_packet(...). This @@ -309,8 +336,6 @@ def recv_packet(self, filter_type=None, filter_event=None, timeout=None): finally: self.recv_condition.release() - return None - def send_recv(self, command): """Send a command python dictionary as JSON and receive the JSON response. Validates that the response is the correct sequence and @@ -360,47 +385,36 @@ def send_recv(self, command): return None - def wait_for_event(self, filter=None, timeout=None): - while True: - return self.recv_packet( - filter_type="event", filter_event=filter, timeout=timeout - ) - return None - - def wait_for_events(self, events, timeout=None): - """Wait for a list of events in `events` in any order. - Return the events not hit before the timeout expired""" - events = events[:] # Make a copy to avoid modifying the input - while events: - event_dict = self.wait_for_event(filter=events, timeout=timeout) - if event_dict is None: - break - events.remove(event_dict["event"]) - return events + def wait_for_event( + self, filter: Union[str, list[str]], timeout: Optional[float] = None + ) -> Optional[Event]: + """Wait for the first event that matches the filter.""" + return self.recv_packet( + filter_type="event", filter_event=filter, timeout=timeout + ) - def wait_for_stopped(self, timeout=None): + def wait_for_stopped( + self, timeout: Optional[float] = None + ) -> Optional[list[Event]]: stopped_events = [] stopped_event = self.wait_for_event( filter=["stopped", "exited"], timeout=timeout ) - exited = False while stopped_event: stopped_events.append(stopped_event) # If we exited, then we are done if stopped_event["event"] == "exited": - self.exit_status = stopped_event["body"]["exitCode"] - exited = True break # Otherwise we stopped and there might be one or more 'stopped' # events for each thread that stopped with a reason, so keep # checking for more 'stopped' events and return all of them - stopped_event = self.wait_for_event(filter="stopped", timeout=0.25) - if exited: - self.threads = [] + stopped_event = self.wait_for_event( + filter=["stopped", "exited"], timeout=0.25 + ) return stopped_events - def wait_for_breakpoint_events(self, timeout=None): - breakpoint_events = [] + def wait_for_breakpoint_events(self, timeout: Optional[float] = None): + breakpoint_events: list[Event] = [] while True: event = self.wait_for_event("breakpoint", timeout=timeout) if not event: @@ -408,14 +422,14 @@ def wait_for_breakpoint_events(self, timeout=None): breakpoint_events.append(event) return breakpoint_events - def wait_for_exited(self): - event_dict = self.wait_for_event("exited") + def wait_for_exited(self, timeout: Optional[float] = None): + event_dict = self.wait_for_event("exited", timeout=timeout) if event_dict is None: raise ValueError("didn't get exited event") return event_dict - def wait_for_terminated(self): - event_dict = self.wait_for_event("terminated") + def wait_for_terminated(self, timeout: Optional[float] = None): + event_dict = self.wait_for_event("terminated", timeout) if event_dict is None: raise ValueError("didn't get terminated event") return event_dict @@ -576,6 +590,7 @@ def replay_packets(self, replay_file_path): def request_attach( self, + /, program=None, pid=None, waitFor=None, @@ -671,7 +686,7 @@ def _process_stopped(self): self.threads = None self.frame_scopes = {} - def request_continue(self, threadId=None): + def request_continue(self, threadId=None, singleThread=False): if self.exit_status is not None: raise ValueError("request_continue called after process exited") # If we have launched or attached, then the first continue is done by @@ -681,13 +696,18 @@ def request_continue(self, threadId=None): args_dict = {} if threadId is None: threadId = self.get_thread_id() - args_dict["threadId"] = threadId + if threadId: + args_dict["threadId"] = threadId + if singleThread: + args_dict["singleThread"] = True command_dict = { "command": "continue", "type": "request", "arguments": args_dict, } response = self.send_recv(command_dict) + if response["success"]: + self._process_continued(response["body"]["allThreadsContinued"]) # Caller must still call wait_for_stopped. return response @@ -775,7 +795,7 @@ def request_exceptionInfo(self, threadId=None): } return self.send_recv(command_dict) - def request_initialize(self, sourceInitFile): + def request_initialize(self, sourceInitFile=False): command_dict = { "command": "initialize", "type": "request", @@ -802,11 +822,12 @@ def request_initialize(self, sourceInitFile): def request_launch( self, - program, - args=None, + program: Optional[str], + /, + args: Optional[list[str]] = None, cwd=None, env=None, - stopOnEntry=False, + stopOnEntry=True, disableASLR=True, disableSTDIO=False, shellExpandArguments=False, @@ -1190,7 +1211,8 @@ def request_testGetTargetBreakpoints(self): def terminate(self): self.send.close() - # self.recv.close() + if self.recv_thread.is_alive(): + self.recv_thread.join() def request_setInstructionBreakpoints(self, memory_reference=[]): breakpoints = [] @@ -1211,11 +1233,11 @@ def request_setInstructionBreakpoints(self, memory_reference=[]): class DebugAdapterServer(DebugCommunication): def __init__( self, - executable=None, - connection=None, - init_commands=[], - log_file=None, - env=None, + executable: Optional[str] = None, + connection: Optional[str] = None, + init_commands: list[str] = [], + log_file: Optional[TextIO] = None, + env: Optional[dict[str, str]] = None, ): self.process = None self.connection = None @@ -1247,7 +1269,14 @@ def __init__( ) @classmethod - def launch(cls, /, executable, env=None, log_file=None, connection=None): + def launch( + cls, + /, + executable: str, + env: Optional[dict[str, str]] = None, + log_file: Optional[TextIO] = None, + connection: Optional[str] = None, + ) -> tuple[subprocess.Popen, Optional[str]]: adapter_env = os.environ.copy() if env is not None: adapter_env.update(env) @@ -1289,26 +1318,29 @@ def launch(cls, /, executable, env=None, log_file=None, connection=None): return (process, connection) - def get_pid(self): + def get_pid(self) -> int: if self.process: return self.process.pid return -1 def terminate(self): - super(DebugAdapterServer, self).terminate() - if self.process is not None: - process = self.process - self.process = None - try: - # When we close stdin it should signal the lldb-dap that no - # new messages will arrive and it should shutdown on its own. - process.stdin.close() - process.wait(timeout=20) - except subprocess.TimeoutExpired: - process.kill() - process.wait() - if process.returncode != 0: - raise DebugAdapterProcessError(process.returncode) + try: + if self.process is not None: + process = self.process + self.process = None + try: + # When we close stdin it should signal the lldb-dap that no + # new messages will arrive and it should shutdown on its + # own. + process.stdin.close() + process.wait(timeout=20) + except subprocess.TimeoutExpired: + process.kill() + process.wait() + if process.returncode != 0: + raise DebugAdapterProcessError(process.returncode) + finally: + super(DebugAdapterServer, self).terminate() class DebugAdapterError(Exception): diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index c5a7eb76a58c7..f125c11160395 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -78,13 +78,13 @@ def waitUntil(self, condition_callback): time.sleep(0.5) return False - def verify_breakpoint_hit(self, breakpoint_ids): + def verify_breakpoint_hit(self, breakpoint_ids, timeout=timeoutval): """Wait for the process we are debugging to stop, and verify we hit any breakpoint location in the "breakpoint_ids" array. "breakpoint_ids" should be a list of breakpoint ID strings (["1", "2"]). The return value from self.set_source_breakpoints() or self.set_function_breakpoints() can be passed to this function""" - stopped_events = self.dap_server.wait_for_stopped() + stopped_events = self.dap_server.wait_for_stopped(timeout) for stopped_event in stopped_events: if "body" in stopped_event: body = stopped_event["body"] @@ -110,16 +110,15 @@ def verify_breakpoint_hit(self, breakpoint_ids): match_desc = "breakpoint %s." % (breakpoint_id) if match_desc in description: return - self.assertTrue(False, "breakpoint not hit") + self.assertTrue(False, f"breakpoint not hit, stopped_events={stopped_events}") def verify_stop_exception_info(self, expected_description, timeout=timeoutval): """Wait for the process we are debugging to stop, and verify the stop reason is 'exception' and that the description matches 'expected_description' """ - stopped_events = self.dap_server.wait_for_stopped(timeout=timeout) + stopped_events = self.dap_server.wait_for_stopped(timeout) for stopped_event in stopped_events: - print("stopped_event", stopped_event) if "body" in stopped_event: body = stopped_event["body"] if "reason" not in body: @@ -263,46 +262,61 @@ def set_global(self, name, value, id=None): return self.dap_server.request_setVariable(2, name, str(value), id=id) def stepIn( - self, threadId=None, targetId=None, waitForStop=True, granularity="statement" + self, + threadId=None, + targetId=None, + waitForStop=True, + granularity="statement", + timeout=timeoutval, ): response = self.dap_server.request_stepIn( threadId=threadId, targetId=targetId, granularity=granularity ) self.assertTrue(response["success"]) if waitForStop: - return self.dap_server.wait_for_stopped() + return self.dap_server.wait_for_stopped(timeout) return None - def stepOver(self, threadId=None, waitForStop=True, granularity="statement"): + def stepOver( + self, + threadId=None, + waitForStop=True, + granularity="statement", + timeout=timeoutval, + ): self.dap_server.request_next(threadId=threadId, granularity=granularity) if waitForStop: - return self.dap_server.wait_for_stopped() + return self.dap_server.wait_fo... [truncated] ``````````
https://github.com/llvm/llvm-project/pull/140107 From lldb-commits at lists.llvm.org Thu May 15 10:39:13 2025 From: lldb-commits at lists.llvm.org (Ilia Kuklin via lldb-commits) Date: Thu, 15 May 2025 10:39:13 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <682626c1.050a0220.1ccc17.1b8f@mx.google.com> https://github.com/kuilpd updated https://github.com/llvm/llvm-project/pull/138551 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Thu May 15 10:39:39 2025 From: lldb-commits at lists.llvm.org (Ilia Kuklin via lldb-commits) Date: Thu, 15 May 2025 10:39:39 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <682626db.a70a0220.1bb56c.1ef5@mx.google.com> ================ @@ -272,4 +272,67 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const ArraySubscriptNode *node) { + auto lhs_or_err = Evaluate(node->GetBase()); + if (!lhs_or_err) { + return lhs_or_err; + } + lldb::ValueObjectSP base = *lhs_or_err; + const llvm::APInt *index = node->GetIndex(); + + Status error; + if (base->GetCompilerType().IsReferenceType()) { + base = base->Dereference(error); + if (error.Fail()) + return error.ToError(); + } + + // Check to see if 'base' has a synthetic value; if so, try using that. + uint64_t child_idx = index->getZExtValue(); + if (base->HasSyntheticValue()) { + lldb::ValueObjectSP synthetic = base->GetSyntheticValue(); + if (synthetic && synthetic != base) { + uint32_t num_children = synthetic->GetNumChildrenIgnoringErrors(); ---------------- kuilpd wrote: I removed the other 2 of these calls, but this one specifically I couldn't: `GetChildAtIndex` for a synthetic value calls `ValueObjectSynthetic::GetChildAtIndex`. That one with `can_create = true` creates a value regardless of the index and always returns something, like a 0 value for a out of bounds subscript of a vector; and with `can_create = false` it doesn't create anything, even if index is within bounds and always returns an error. https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Thu May 15 10:39:50 2025 From: lldb-commits at lists.llvm.org (Ilia Kuklin via lldb-commits) Date: Thu, 15 May 2025 10:39:50 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <682626e6.050a0220.1284d.1f55@mx.google.com> ================ @@ -272,4 +272,67 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const ArraySubscriptNode *node) { + auto lhs_or_err = Evaluate(node->GetBase()); + if (!lhs_or_err) { + return lhs_or_err; + } + lldb::ValueObjectSP base = *lhs_or_err; + const llvm::APInt *index = node->GetIndex(); + + Status error; + if (base->GetCompilerType().IsReferenceType()) { + base = base->Dereference(error); + if (error.Fail()) + return error.ToError(); + } ---------------- kuilpd wrote: It was for type checks later, I forgot that there is a `GetNonReferenceType()`. https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Thu May 15 10:39:57 2025 From: lldb-commits at lists.llvm.org (Ilia Kuklin via lldb-commits) Date: Thu, 15 May 2025 10:39:57 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <682626ed.170a0220.15befc.4909@mx.google.com> ================ @@ -272,4 +272,67 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const ArraySubscriptNode *node) { + auto lhs_or_err = Evaluate(node->GetBase()); + if (!lhs_or_err) { + return lhs_or_err; + } + lldb::ValueObjectSP base = *lhs_or_err; + const llvm::APInt *index = node->GetIndex(); + + Status error; + if (base->GetCompilerType().IsReferenceType()) { + base = base->Dereference(error); + if (error.Fail()) + return error.ToError(); + } + + // Check to see if 'base' has a synthetic value; if so, try using that. + uint64_t child_idx = index->getZExtValue(); + if (base->HasSyntheticValue()) { + lldb::ValueObjectSP synthetic = base->GetSyntheticValue(); + if (synthetic && synthetic != base) { + uint32_t num_children = synthetic->GetNumChildrenIgnoringErrors(); + // Verify that the 'index' is not out-of-range for the declared type. + if (child_idx >= num_children) { + auto message = llvm::formatv( + "array index {0} is not valid for \"({1}) {2}\"", child_idx, + base->GetTypeName().AsCString(""), + base->GetName().AsCString()); + return llvm::make_error(m_expr, message, + node->GetLocation()); + } + + if (static_cast(child_idx) < + synthetic->GetNumChildrenIgnoringErrors()) { + lldb::ValueObjectSP child_valobj_sp = + synthetic->GetChildAtIndex(child_idx); + if (child_valobj_sp) { + return child_valobj_sp; + } + } + } + } + + auto base_type = base->GetCompilerType(); + if (!base_type.IsPointerType() && !base_type.IsArrayType()) ---------------- kuilpd wrote: I tried that, but because I need to return `base->GetSyntheticArrayMember` in any case other than array, it didn't end up looking better. https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Thu May 15 10:40:02 2025 From: lldb-commits at lists.llvm.org (Ilia Kuklin via lldb-commits) Date: Thu, 15 May 2025 10:40:02 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <682626f2.170a0220.3753ca.13ec@mx.google.com> ================ @@ -111,7 +111,42 @@ ASTNodeUP DILParser::ParseUnaryExpression() { llvm_unreachable("invalid token kind"); } } - return ParsePrimaryExpression(); + return ParsePostfixExpression(); +} + +// Parse a postfix_expression. +// +// postfix_expression: +// primary_expression +// postfix_expression "[" integer_literal "]" +// +ASTNodeUP DILParser::ParsePostfixExpression() { + ASTNodeUP lhs = ParsePrimaryExpression(); + while (CurToken().Is(Token::l_square)) { + uint32_t loc = CurToken().GetLocation(); + Token token = CurToken(); + switch (token.GetKind()) { + case Token::l_square: { + m_dil_lexer.Advance(); + auto rhs = ParseIntegerConstant(); ---------------- kuilpd wrote: Out of curiosity, why? https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Thu May 15 10:40:15 2025 From: lldb-commits at lists.llvm.org (Ilia Kuklin via lldb-commits) Date: Thu, 15 May 2025 10:40:15 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <682626ff.050a0220.24a10b.1b32@mx.google.com> kuilpd wrote: I think I addressed everything I could, please take a look again. https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Thu May 15 10:45:21 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 10:45:21 -0700 (PDT) Subject: [Lldb-commits] [lldb] 58b9b86 - [lldb-dap] Setup DAP for unit testing. (#139937) Message-ID: <68262831.170a0220.dc155.159e@mx.google.com> Author: John Harrison Date: 2025-05-15T10:45:16-07:00 New Revision: 58b9b865feffede59616cfc05cefa956d5352314 URL: https://github.com/llvm/llvm-project/commit/58b9b865feffede59616cfc05cefa956d5352314 DIFF: https://github.com/llvm/llvm-project/commit/58b9b865feffede59616cfc05cefa956d5352314.diff LOG: [lldb-dap] Setup DAP for unit testing. (#139937) This is a very simple case that currently only validates we can create a DAP instance and send a message over the transport layer. More in-depth tests will require additional helpers and possibly refactors of DAP to make it more testable, however this is some ground work to have basic support for unit tests. --------- Co-authored-by: Jonas Devlieghere Added: lldb/unittests/DAP/DAPTest.cpp lldb/unittests/DAP/Handler/DisconnectTest.cpp lldb/unittests/DAP/TestBase.cpp lldb/unittests/DAP/TestBase.h Modified: lldb/tools/lldb-dap/DAP.h lldb/unittests/DAP/CMakeLists.txt lldb/unittests/DAP/TransportTest.cpp Removed: ################################################################################ diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 9065995f5d722..c1a1130b1e59f 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -226,7 +226,8 @@ struct DAP { /// \param[in] default_repl_mode /// Default repl mode behavior, as configured by the binary. /// \param[in] pre_init_commands - /// LLDB commands to execute as soon as the debugger instance is allocaed. + /// LLDB commands to execute as soon as the debugger instance is + /// allocated. /// \param[in] transport /// Transport for this debug session. DAP(Log *log, const ReplMode default_repl_mode, diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index 110733e93b192..af7d11e2e95e2 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -1,8 +1,11 @@ add_lldb_unittest(DAPTests + DAPTest.cpp + Handler/DisconnectTest.cpp JSONUtilsTest.cpp LLDBUtilsTest.cpp - TransportTest.cpp ProtocolTypesTest.cpp + TestBase.cpp + TransportTest.cpp LINK_LIBS lldbDAP diff --git a/lldb/unittests/DAP/DAPTest.cpp b/lldb/unittests/DAP/DAPTest.cpp new file mode 100644 index 0000000000000..5fb6bf7e564ab --- /dev/null +++ b/lldb/unittests/DAP/DAPTest.cpp @@ -0,0 +1,38 @@ +//===-- DAPTest.cpp -------------------------------------------------------===// +// +// 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 "DAP.h" +#include "Protocol/ProtocolBase.h" +#include "TestBase.h" +#include "Transport.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include +#include + +using namespace llvm; +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap_tests; +using namespace lldb_dap::protocol; + +class DAPTest : public TransportBase {}; + +TEST_F(DAPTest, SendProtocolMessages) { + DAP dap{ + /*log=*/nullptr, + /*default_repl_mode=*/ReplMode::Auto, + /*pre_init_commands=*/{}, + /*transport=*/*to_dap, + }; + dap.Send(Event{/*event=*/"my-event", /*body=*/std::nullopt}); + ASSERT_THAT_EXPECTED(from_dap->Read(std::chrono::milliseconds(1)), + HasValue(testing::VariantWith(testing::FieldsAre( + /*event=*/"my-event", /*body=*/std::nullopt)))); +} diff --git a/lldb/unittests/DAP/Handler/DisconnectTest.cpp b/lldb/unittests/DAP/Handler/DisconnectTest.cpp new file mode 100644 index 0000000000000..6f3470239e974 --- /dev/null +++ b/lldb/unittests/DAP/Handler/DisconnectTest.cpp @@ -0,0 +1,35 @@ +//===-- DisconnectTest.cpp ------------------------------------------------===// +// +// 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 "DAP.h" +#include "Handler/RequestHandler.h" +#include "Protocol/ProtocolBase.h" +#include "TestBase.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include + +using namespace llvm; +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap_tests; +using namespace lldb_dap::protocol; + +class DisconnectRequestHandlerTest : public DAPTestBase {}; + +TEST_F(DisconnectRequestHandlerTest, DisconnectingTriggersTerminated) { + DisconnectRequestHandler handler(*dap); + EXPECT_FALSE(dap->disconnecting); + ASSERT_THAT_ERROR(handler.Run(std::nullopt), Succeeded()); + EXPECT_TRUE(dap->disconnecting); + std::vector messages = DrainOutput(); + EXPECT_THAT(messages, + testing::Contains(testing::VariantWith(testing::FieldsAre( + /*event=*/"terminated", /*body=*/std::nullopt)))); +} diff --git a/lldb/unittests/DAP/TestBase.cpp b/lldb/unittests/DAP/TestBase.cpp new file mode 100644 index 0000000000000..eb146cb2fa9f4 --- /dev/null +++ b/lldb/unittests/DAP/TestBase.cpp @@ -0,0 +1,70 @@ +//===-- TestBase.cpp ------------------------------------------------------===// +// +// 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 "TestBase.h" +#include "Protocol/ProtocolBase.h" +#include "lldb/Host/File.h" +#include "lldb/Host/Pipe.h" +#include "llvm/Testing/Support/Error.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_dap; +using namespace lldb_dap::protocol; +using namespace lldb_dap_tests; +using lldb_private::File; +using lldb_private::NativeFile; +using lldb_private::Pipe; + +void PipeBase::SetUp() { + ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); + ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); +} + +void TransportBase::SetUp() { + PipeBase::SetUp(); + to_dap = std::make_unique( + "to_dap", nullptr, + std::make_shared(input.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(output.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); + from_dap = std::make_unique( + "from_dap", nullptr, + std::make_shared(output.GetReadFileDescriptor(), + File::eOpenOptionReadOnly, + NativeFile::Unowned), + std::make_shared(input.GetWriteFileDescriptor(), + File::eOpenOptionWriteOnly, + NativeFile::Unowned)); +} + +void DAPTestBase::SetUp() { + TransportBase::SetUp(); + dap = std::make_unique( + /*log=*/nullptr, + /*default_repl_mode=*/ReplMode::Auto, + /*pre_init_commands=*/std::vector(), + /*transport=*/*to_dap); +} + +std::vector DAPTestBase::DrainOutput() { + std::vector msgs; + output.CloseWriteFileDescriptor(); + while (true) { + Expected next = from_dap->Read(std::chrono::milliseconds(1)); + if (!next) { + consumeError(next.takeError()); + break; + } + msgs.push_back(*next); + } + return msgs; +} diff --git a/lldb/unittests/DAP/TestBase.h b/lldb/unittests/DAP/TestBase.h new file mode 100644 index 0000000000000..c789adf53c225 --- /dev/null +++ b/lldb/unittests/DAP/TestBase.h @@ -0,0 +1,48 @@ +//===-- TestBase.cpp ------------------------------------------------------===// +// +// 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 "DAP.h" +#include "Protocol/ProtocolBase.h" +#include "Transport.h" +#include "lldb/Host/Pipe.h" +#include "gtest/gtest.h" + +namespace lldb_dap_tests { + +/// A base class for tests that need a pair of pipes for communication. +class PipeBase : public testing::Test { +protected: + lldb_private::Pipe input; + lldb_private::Pipe output; + + void SetUp() override; +}; + +/// A base class for tests that need transport configured for communicating DAP +/// messages. +class TransportBase : public PipeBase { +protected: + std::unique_ptr to_dap; + std::unique_ptr from_dap; + + void SetUp() override; +}; + +/// A base class for tests that interact with a `lldb_dap::DAP` instance. +class DAPTestBase : public TransportBase { +protected: + std::unique_ptr dap; + + void SetUp() override; + + /// Closes the DAP output pipe and returns the remaining protocol messages in + /// the buffer. + std::vector DrainOutput(); +}; + +} // namespace lldb_dap_tests diff --git a/lldb/unittests/DAP/TransportTest.cpp b/lldb/unittests/DAP/TransportTest.cpp index 5c77b4bb26343..e6dab42e30941 100644 --- a/lldb/unittests/DAP/TransportTest.cpp +++ b/lldb/unittests/DAP/TransportTest.cpp @@ -8,10 +8,10 @@ #include "Transport.h" #include "Protocol/ProtocolBase.h" +#include "TestBase.h" #include "lldb/Host/File.h" #include "lldb/Host/Pipe.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/FormatVariadic.h" #include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" #include @@ -21,20 +21,18 @@ using namespace llvm; using namespace lldb; using namespace lldb_dap; +using namespace lldb_dap_tests; using namespace lldb_dap::protocol; using lldb_private::File; using lldb_private::NativeFile; using lldb_private::Pipe; -class TransportTest : public testing::Test { +class TransportTest : public PipeBase { protected: - Pipe input; - Pipe output; std::unique_ptr transport; void SetUp() override { - ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded()); - ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded()); + PipeBase::SetUp(); transport = std::make_unique( "stdio", nullptr, std::make_shared(input.GetReadFileDescriptor(), @@ -44,13 +42,6 @@ class TransportTest : public testing::Test { File::eOpenOptionWriteOnly, NativeFile::Unowned)); } - - void Write(StringRef json) { - std::string message = - formatv("Content-Length: {0}\r\n\r\n{1}", json.size(), json).str(); - ASSERT_THAT_EXPECTED(input.Write(message.data(), message.size()), - Succeeded()); - } }; TEST_F(TransportTest, MalformedRequests) { @@ -65,7 +56,12 @@ TEST_F(TransportTest, MalformedRequests) { } TEST_F(TransportTest, Read) { - Write(R"json({"seq": 1, "type": "request", "command": "abc"})json"); + std::string json = + R"json({"seq": 1, "type": "request", "command": "abc"})json"; + std::string message = + formatv("Content-Length: {0}\r\n\r\n{1}", json.size(), json).str(); + ASSERT_THAT_EXPECTED(input.Write(message.data(), message.size()), + Succeeded()); ASSERT_THAT_EXPECTED( transport->Read(std::chrono::milliseconds(1)), HasValue(testing::VariantWith(testing::FieldsAre( From lldb-commits at lists.llvm.org Thu May 15 10:45:27 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Thu, 15 May 2025 10:45:27 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Setup DAP for unit testing. (PR #139937) In-Reply-To: Message-ID: <68262837.170a0220.fc482.1558@mx.google.com> https://github.com/ashgti closed https://github.com/llvm/llvm-project/pull/139937 From lldb-commits at lists.llvm.org Thu May 15 11:35:00 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Thu, 15 May 2025 11:35:00 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Refactor lldb-dap event handling. (PR #139669) In-Reply-To: Message-ID: <682633d4.170a0220.27f6eb.1f8f@mx.google.com> ashgti wrote: I'm working on splitting out the test changes, #140107 is the main set that I think are related. If so, this may become a more of a NFC from the test perspective. https://github.com/llvm/llvm-project/pull/139669 From lldb-commits at lists.llvm.org Thu May 15 13:15:32 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Thu, 15 May 2025 13:15:32 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding additional asserts to unit tests. (PR #140107) In-Reply-To: Message-ID: <68264b64.170a0220.11fd5.5775@mx.google.com> https://github.com/JDevlieghere commented: Overall looks good. Reviewing this, I think this could probably be broken down further into NFC-ish changes, but I'm not sure it's worth the overhead of doing that. No need to do it on my behalf at least. https://github.com/llvm/llvm-project/pull/140107 From lldb-commits at lists.llvm.org Thu May 15 13:15:32 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Thu, 15 May 2025 13:15:32 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding additional asserts to unit tests. (PR #140107) In-Reply-To: Message-ID: <68264b64.a70a0220.37ccaa.31dd@mx.google.com> https://github.com/JDevlieghere edited https://github.com/llvm/llvm-project/pull/140107 From lldb-commits at lists.llvm.org Thu May 15 13:15:32 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Thu, 15 May 2025 13:15:32 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding additional asserts to unit tests. (PR #140107) In-Reply-To: Message-ID: <68264b64.050a0220.20d53d.30a1@mx.google.com> ================ @@ -67,7 +67,7 @@ def test_core_file_source_mapping_array(self): self.create_debug_adapter() source_map = [["/home/labath/test", current_dir]] - self.attach(exe_file, coreFile=core_file, sourceMap=source_map) + self.attach(program=exe_file, coreFile=core_file, sourceMap=source_map) ---------------- JDevlieghere wrote: IIf you use `*args` you don't need this anymore. https://github.com/llvm/llvm-project/pull/140107 From lldb-commits at lists.llvm.org Thu May 15 13:15:33 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Thu, 15 May 2025 13:15:33 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding additional asserts to unit tests. (PR #140107) In-Reply-To: Message-ID: <68264b65.a70a0220.1fec6a.2e66@mx.google.com> ================ @@ -487,115 +453,36 @@ def cleanup(): response = self.dap_server.request_launch( program, - args=args, - cwd=cwd, - env=env, stopOnEntry=stopOnEntry, - disableASLR=disableASLR, - disableSTDIO=disableSTDIO, - shellExpandArguments=shellExpandArguments, - trace=trace, - initCommands=initCommands, - preRunCommands=preRunCommands, - stopCommands=stopCommands, - exitCommands=exitCommands, - terminateCommands=terminateCommands, - sourcePath=sourcePath, - debuggerRoot=debuggerRoot, - launchCommands=launchCommands, - sourceMap=sourceMap, - runInTerminal=runInTerminal, - postRunCommands=postRunCommands, - enableAutoVariableSummaries=enableAutoVariableSummaries, - displayExtendedBacktrace=displayExtendedBacktrace, - enableSyntheticChildDebugging=enableSyntheticChildDebugging, - commandEscapePrefix=commandEscapePrefix, - customFrameFormat=customFrameFormat, - customThreadFormat=customThreadFormat, + **kwargs, ---------------- JDevlieghere wrote: Nice :-) https://github.com/llvm/llvm-project/pull/140107 From lldb-commits at lists.llvm.org Thu May 15 13:15:33 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Thu, 15 May 2025 13:15:33 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding additional asserts to unit tests. (PR #140107) In-Reply-To: Message-ID: <68264b65.a70a0220.3be227.301d@mx.google.com> ================ @@ -78,13 +78,13 @@ def waitUntil(self, condition_callback): time.sleep(0.5) return False - def verify_breakpoint_hit(self, breakpoint_ids): + def verify_breakpoint_hit(self, breakpoint_ids, timeout=timeoutval): ---------------- JDevlieghere wrote: Any objections to changing `timeoutval` to `DEFAULT_TIMEOUT`? If that's too much churn for this PR, happy have that be a separate PR. https://github.com/llvm/llvm-project/pull/140107 From lldb-commits at lists.llvm.org Thu May 15 13:15:33 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Thu, 15 May 2025 13:15:33 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding additional asserts to unit tests. (PR #140107) In-Reply-To: Message-ID: <68264b65.a70a0220.33a4ea.2fa3@mx.google.com> ================ @@ -263,46 +262,61 @@ def set_global(self, name, value, id=None): return self.dap_server.request_setVariable(2, name, str(value), id=id) def stepIn( - self, threadId=None, targetId=None, waitForStop=True, granularity="statement" + self, + threadId=None, + targetId=None, + waitForStop=True, + granularity="statement", + timeout=timeoutval, ): response = self.dap_server.request_stepIn( threadId=threadId, targetId=targetId, granularity=granularity ) self.assertTrue(response["success"]) if waitForStop: - return self.dap_server.wait_for_stopped() + return self.dap_server.wait_for_stopped(timeout) return None - def stepOver(self, threadId=None, waitForStop=True, granularity="statement"): + def stepOver( + self, + threadId=None, + waitForStop=True, + granularity="statement", + timeout=timeoutval, + ): self.dap_server.request_next(threadId=threadId, granularity=granularity) if waitForStop: - return self.dap_server.wait_for_stopped() + return self.dap_server.wait_for_stopped(timeout) return None - def stepOut(self, threadId=None, waitForStop=True): + def stepOut(self, threadId=None, waitForStop=True, timeout=timeoutval): self.dap_server.request_stepOut(threadId=threadId) if waitForStop: - return self.dap_server.wait_for_stopped() + return self.dap_server.wait_for_stopped(timeout) return None - def continue_to_next_stop(self): - self.dap_server.request_continue() - return self.dap_server.wait_for_stopped() + def verify_continue(self): ---------------- JDevlieghere wrote: Maybe just: ```suggestion def continue(self): ``` The "verification" seems like it's an implementation detail and raw calls to this look rather weird (I originally thought the "verification" was the stop, which it isn't). https://github.com/llvm/llvm-project/pull/140107 From lldb-commits at lists.llvm.org Thu May 15 13:15:33 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Thu, 15 May 2025 13:15:33 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding additional asserts to unit tests. (PR #140107) In-Reply-To: Message-ID: <68264b65.170a0220.20cd39.2a0f@mx.google.com> ================ @@ -487,115 +453,36 @@ def cleanup(): response = self.dap_server.request_launch( program, - args=args, - cwd=cwd, - env=env, stopOnEntry=stopOnEntry, - disableASLR=disableASLR, - disableSTDIO=disableSTDIO, - shellExpandArguments=shellExpandArguments, - trace=trace, - initCommands=initCommands, - preRunCommands=preRunCommands, - stopCommands=stopCommands, - exitCommands=exitCommands, - terminateCommands=terminateCommands, - sourcePath=sourcePath, - debuggerRoot=debuggerRoot, - launchCommands=launchCommands, - sourceMap=sourceMap, - runInTerminal=runInTerminal, - postRunCommands=postRunCommands, - enableAutoVariableSummaries=enableAutoVariableSummaries, - displayExtendedBacktrace=displayExtendedBacktrace, - enableSyntheticChildDebugging=enableSyntheticChildDebugging, - commandEscapePrefix=commandEscapePrefix, - customFrameFormat=customFrameFormat, - customThreadFormat=customThreadFormat, + **kwargs, ) if expectFailure: return response - if not (response and response["success"]): self.assertTrue( response["success"], "launch failed (%s)" % (response["body"]["error"]["format"]), ) + if stopOnEntry: + self.dap_server.wait_for_stopped(timeout) + return response def build_and_launch( self, program, - args=None, - cwd=None, - env=None, - stopOnEntry=False, - disableASLR=False, - disableSTDIO=False, - shellExpandArguments=False, - trace=False, - initCommands=None, - preRunCommands=None, - stopCommands=None, - exitCommands=None, - terminateCommands=None, - sourcePath=None, - debuggerRoot=None, - sourceInitFile=False, - runInTerminal=False, - disconnectAutomatically=True, - postRunCommands=None, + /, ---------------- JDevlieghere wrote: What's this? Could this use `*args, **kwargs`? https://github.com/llvm/llvm-project/pull/140107 From lldb-commits at lists.llvm.org Thu May 15 13:18:02 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 13:18:02 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Retcon SBValue::GetChildAtIndex(synthetic=true) (PR #140065) In-Reply-To: Message-ID: <68264bfa.170a0220.29c071.365e@mx.google.com> ================ @@ -193,7 +188,7 @@ class LLDB_API SBValue { /// and also if the target can be run to figure out the dynamic /// type of the child value. /// - /// \param[in] can_create_synthetic + /// \param[in] use_synthetic ---------------- jimingham wrote: I think this change makes sense, but there must be a better term for this. use_synthetic doesn't actually tell you anything about what you are going to use synthetic FOR, and is confusing because it does NOT mean "use the children produced by the synthetic child provider for this type", which is almost always what we mean by "using synthetic". Seems to me this bool is forcing "treat_as_array" behavior for a pointer. Would that be an accurate name for what this parameter controls? https://github.com/llvm/llvm-project/pull/140065 From lldb-commits at lists.llvm.org Thu May 15 13:39:36 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Thu, 15 May 2025 13:39:36 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding additional asserts to unit tests. (PR #140107) In-Reply-To: Message-ID: <68265108.170a0220.320ec6.2dbd@mx.google.com> ================ @@ -263,46 +262,61 @@ def set_global(self, name, value, id=None): return self.dap_server.request_setVariable(2, name, str(value), id=id) def stepIn( - self, threadId=None, targetId=None, waitForStop=True, granularity="statement" + self, + threadId=None, + targetId=None, + waitForStop=True, + granularity="statement", + timeout=timeoutval, ): response = self.dap_server.request_stepIn( threadId=threadId, targetId=targetId, granularity=granularity ) self.assertTrue(response["success"]) if waitForStop: - return self.dap_server.wait_for_stopped() + return self.dap_server.wait_for_stopped(timeout) return None - def stepOver(self, threadId=None, waitForStop=True, granularity="statement"): + def stepOver( + self, + threadId=None, + waitForStop=True, + granularity="statement", + timeout=timeoutval, + ): self.dap_server.request_next(threadId=threadId, granularity=granularity) if waitForStop: - return self.dap_server.wait_for_stopped() + return self.dap_server.wait_for_stopped(timeout) return None - def stepOut(self, threadId=None, waitForStop=True): + def stepOut(self, threadId=None, waitForStop=True, timeout=timeoutval): self.dap_server.request_stepOut(threadId=threadId) if waitForStop: - return self.dap_server.wait_for_stopped() + return self.dap_server.wait_for_stopped(timeout) return None - def continue_to_next_stop(self): - self.dap_server.request_continue() - return self.dap_server.wait_for_stopped() + def verify_continue(self): ---------------- ashgti wrote: `continue` isn't a valid method name in python, I tried that at first, but its a keyword. I'm open to other suggestions. https://github.com/llvm/llvm-project/pull/140107 From lldb-commits at lists.llvm.org Thu May 15 14:02:04 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 14:02:04 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Limit formatter-section extractor range (PR #140139) Message-ID: https://github.com/Nerixyz created https://github.com/llvm/llvm-project/pull/140139 The formatter extraction would look at too much data for one type. This PR limits the size of the `DataExtractor` to the one specified in the record size before - previously, the whole section was looked at. Similarly, `ForEachFormatterInModule` skipped zero-bytes but didn't stop when reaching the end of the extractor. I hit both cases in an even smaller test than the one currently in the repo, but I tried this on Windows[^1]. In my executable, the formatter section started with my specified formatter and was padded to 512 bytes with zeroes. I'd guess this should've come up in the existing test case, so macOS might do something different here[?].
Test File ```c struct Point { int x; int y; }; __attribute__((used, section(".lldbformatters"))) const char my_string[] = { 0x01, // version 0x12, // record size 0x05, // type size 'P', 'o', 'i', 'n', 't', 0x00, // flags 0x00, // signature 0x09, // byte-code length 0x01, // drop 0x22, // push str 0x05, // str len 'A', 'A', 'A', 'A', 'A', 0x13, // return }; int main() { Point a{3, 4}; return a.x + a.y; // break here } ```
[^1]: I had to change the section name matching to use an 8 byte name in the [PE/COFF](https://github.com/llvm/llvm-project/blob/acdba28e148ac1e94d6c041f9911230e1e90e9cd/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp#L1003) reader, since executables on Windows [can't have section names longer than 8 bytes](https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#section-table-section-headers) (actually they can, and in MinGW they do, but I couldn't get `clang-cl` to generate such a binary). Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Thu May 15 14:02:36 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 14:02:36 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Limit formatter-section extractor range (PR #140139) In-Reply-To: Message-ID: <6826566c.050a0220.3b66fe.3a4c@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: nerix (Nerixyz)
Changes The formatter extraction would look at too much data for one type. This PR limits the size of the `DataExtractor` to the one specified in the record size before - previously, the whole section was looked at. Similarly, `ForEachFormatterInModule` skipped zero-bytes but didn't stop when reaching the end of the extractor. I hit both cases in an even smaller test than the one currently in the repo, but I tried this on Windows[^1]. In my executable, the formatter section started with my specified formatter and was padded to 512 bytes with zeroes. I'd guess this should've come up in the existing test case, so macOS might do something different here[?]. <details><summary>Test File</summary> ```c struct Point { int x; int y; }; __attribute__((used, section(".lldbformatters"))) const char my_string[] = { 0x01, // version 0x12, // record size 0x05, // type size 'P', 'o', 'i', 'n', 't', 0x00, // flags 0x00, // signature 0x09, // byte-code length 0x01, // drop 0x22, // push str 0x05, // str len 'A', 'A', 'A', 'A', 'A', 0x13, // return }; int main() { Point a{3, 4}; return a.x + a.y; // break here } ``` </details> [^1]: I had to change the section name matching to use an 8 byte name in the [PE/COFF](https://github.com/llvm/llvm-project/blob/acdba28e148ac1e94d6c041f9911230e1e90e9cd/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp#L1003) reader, since executables on Windows [can't have section names longer than 8 bytes](https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#section-table-section-headers) (actually they can, and in MinGW they do, but I couldn't get `clang-cl` to generate such a binary). --- Full diff: https://github.com/llvm/llvm-project/pull/140139.diff 1 Files Affected: - (modified) lldb/source/DataFormatters/FormatterSection.cpp (+6-2) ``````````diff diff --git a/lldb/source/DataFormatters/FormatterSection.cpp b/lldb/source/DataFormatters/FormatterSection.cpp index 1de633f4998e0..72979ac1923e8 100644 --- a/lldb/source/DataFormatters/FormatterSection.cpp +++ b/lldb/source/DataFormatters/FormatterSection.cpp @@ -57,11 +57,15 @@ static void ForEachFormatterInModule( cursor.seek(cursor.tell() - 1); break; } + if (!cursor || cursor.tell() >= section_size) + break; + uint64_t version = section.getULEB128(cursor); uint64_t record_size = section.getULEB128(cursor); if (version == 1) { - llvm::DataExtractor record(section.getData().drop_front(cursor.tell()), - le, addr_size); + llvm::DataExtractor record( + section.getData().drop_front(cursor.tell()).take_front(record_size), + le, addr_size); llvm::DataExtractor::Cursor cursor(0); uint64_t type_size = record.getULEB128(cursor); llvm::StringRef type_name = record.getBytes(cursor, type_size); ``````````
https://github.com/llvm/llvm-project/pull/140139 From lldb-commits at lists.llvm.org Thu May 15 14:04:43 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Thu, 15 May 2025 14:04:43 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding additional asserts to unit tests. (PR #140107) In-Reply-To: Message-ID: <682656eb.050a0220.407c7.33e3@mx.google.com> ================ @@ -263,46 +262,61 @@ def set_global(self, name, value, id=None): return self.dap_server.request_setVariable(2, name, str(value), id=id) def stepIn( - self, threadId=None, targetId=None, waitForStop=True, granularity="statement" + self, + threadId=None, + targetId=None, + waitForStop=True, + granularity="statement", + timeout=timeoutval, ): response = self.dap_server.request_stepIn( threadId=threadId, targetId=targetId, granularity=granularity ) self.assertTrue(response["success"]) if waitForStop: - return self.dap_server.wait_for_stopped() + return self.dap_server.wait_for_stopped(timeout) return None - def stepOver(self, threadId=None, waitForStop=True, granularity="statement"): + def stepOver( + self, + threadId=None, + waitForStop=True, + granularity="statement", + timeout=timeoutval, + ): self.dap_server.request_next(threadId=threadId, granularity=granularity) if waitForStop: - return self.dap_server.wait_for_stopped() + return self.dap_server.wait_for_stopped(timeout) return None - def stepOut(self, threadId=None, waitForStop=True): + def stepOut(self, threadId=None, waitForStop=True, timeout=timeoutval): self.dap_server.request_stepOut(threadId=threadId) if waitForStop: - return self.dap_server.wait_for_stopped() + return self.dap_server.wait_for_stopped(timeout) return None - def continue_to_next_stop(self): - self.dap_server.request_continue() - return self.dap_server.wait_for_stopped() + def verify_continue(self): ---------------- JDevlieghere wrote: Gotcha. Hmm, maybe `do_continue` or `send_continue`? They're only marginally better. https://github.com/llvm/llvm-project/pull/140107 From lldb-commits at lists.llvm.org Thu May 15 14:22:30 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Thu, 15 May 2025 14:22:30 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding additional asserts to unit tests. (PR #140107) In-Reply-To: Message-ID: <68265b16.050a0220.20ffdb.364e@mx.google.com> ================ @@ -16,8 +16,10 @@ def spawn_and_wait(program, delay): + print("spawn_and_wait started...", time.time()) ---------------- da-viper wrote: I don't think print statement works in tests. https://github.com/llvm/llvm-project/pull/140107 From lldb-commits at lists.llvm.org Thu May 15 14:26:40 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Thu, 15 May 2025 14:26:40 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Listen for broadcast classes. (PR #140142) Message-ID: https://github.com/ashgti created https://github.com/llvm/llvm-project/pull/140142 The recent change to the startup flow has highlighted a problem with breakpoint events being missed. Previously, we would handle `attach`/`launch` commands immediately, leaving the process in a suspended until the `configurationDone` command was sent. If a breakpoint was set between the `attach`/`launch` and the `configurationDone` request, it may have been resolved immediately, but there was a chance the module was not yet loaded. With the new startup flow, the breakpoint is always set before the target is loaded. For some targets, this is fine and the breakpoint event fires eventually and marks the breakpoint as verified. However, if a `attach`/`launch` request has `attachCommands`/`launchCommands` that create a new target then we will miss the breakpoint events associated with that target because we haven't configured the target broadcaster for the debugger. We only configure that in the `DAP::SetTarget` call, which happens after the events would have occurred. To address this, I adjusted the `DAP::EventThread` to listen for the broadcast class instead of an individual broadcaster. I think this may also fix the unstable `TestDAP_breakpointEvents` tests. We're not using the `Debugger::DefaultEventHandler` https://github.com/llvm/llvm-project/blob/090f46d8d246762401c41c5486dde299382d6c90/lldb/source/Core/Debugger.cpp#L2048 which is why these broadcast classes are not registered on our debugger instance in lldb-dap. >From ea5ee538a1ca384725f8166ec9289883683b52ce Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 15 May 2025 14:13:48 -0700 Subject: [PATCH] [lldb-dap] Listen for broadcast classes. The recent change to the startup flow has highlighted a problem with breakpoint events being missed. Previously, we would handle `attach`/`launch` commands immediately, leaving the process in a suspended until the `configurationDone` command was sent. If a breakpoint was set between the `attach`/`launch` and the `configurationDone` request, it may have been resolved immediately, but there was a chance the module was not yet loaded. With the new startup flow, the breakpoint is always set before the target is loaded. For some targets, this is fine and the breakpoint event fires eventually and marks the breakpoint as verified. However, if a `attach`/`launch` request has `attachCommands`/`launchCommands` that create a new target then we will miss the breakpoint events associated with that target because we haven't configured the target broadcaster for the debugger. We only configure that in the `DAP::SetTarget` call, which happens after the events would have occurred. To address this, I adjusted the `DAP::EventThread` to listen for the broadcast class instead of an individual broadcaster. I think this may also fix the unstable `TestDAP_breakpointEvents` tests. --- lldb/tools/lldb-dap/DAP.cpp | 53 +++++++++---------- lldb/tools/lldb-dap/DAP.h | 3 +- .../lldb-dap/Handler/AttachRequestHandler.cpp | 4 +- .../tools/lldb-dap/Handler/RequestHandler.cpp | 2 +- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 51f9da854f4b6..827ebb1465938 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -26,6 +26,7 @@ #include "lldb/API/SBListener.h" #include "lldb/API/SBProcess.h" #include "lldb/API/SBStream.h" +#include "lldb/API/SBTarget.h" #include "lldb/Utility/IOObject.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-defines.h" @@ -719,23 +720,7 @@ lldb::SBTarget DAP::CreateTarget(lldb::SBError &error) { return target; } -void DAP::SetTarget(const lldb::SBTarget target) { - this->target = target; - - if (target.IsValid()) { - // Configure breakpoint event listeners for the target. - lldb::SBListener listener = this->debugger.GetListener(); - listener.StartListeningForEvents( - this->target.GetBroadcaster(), - lldb::SBTarget::eBroadcastBitBreakpointChanged | - lldb::SBTarget::eBroadcastBitModulesLoaded | - lldb::SBTarget::eBroadcastBitModulesUnloaded | - lldb::SBTarget::eBroadcastBitSymbolsLoaded | - lldb::SBTarget::eBroadcastBitSymbolsChanged); - listener.StartListeningForEvents(this->broadcaster, - eBroadcastBitStopEventThread); - } -} +void DAP::SetTarget(const lldb::SBTarget target) { this->target = target; } bool DAP::HandleObject(const Message &M) { TelemetryDispatcher dispatcher(&debugger); @@ -1489,17 +1474,31 @@ void DAP::ProgressEventThread() { } // All events from the debugger, target, process, thread and frames are -// received in this function that runs in its own thread. We are using a -// "FILE *" to output packets back to VS Code and they have mutexes in them -// them prevent multiple threads from writing simultaneously so no locking -// is required. +// received in this function that runs in its own thread. void DAP::EventThread() { llvm::set_thread_name(transport.GetClientName() + ".event_handler"); - lldb::SBEvent event; + + // Configure the debugger listener for all events lldb-dap is interested in. lldb::SBListener listener = debugger.GetListener(); - broadcaster.AddListener(listener, eBroadcastBitStopEventThread); - debugger.GetBroadcaster().AddListener( - listener, lldb::eBroadcastBitError | lldb::eBroadcastBitWarning); + listener.StartListeningForEventClass( + debugger, lldb::SBTarget::GetBroadcasterClassName(), + lldb::SBTarget::eBroadcastBitBreakpointChanged | + lldb::SBTarget::eBroadcastBitModulesLoaded | + lldb::SBTarget::eBroadcastBitModulesUnloaded | + lldb::SBTarget::eBroadcastBitSymbolsLoaded | + lldb::SBTarget::eBroadcastBitSymbolsChanged); + listener.StartListeningForEventClass( + debugger, lldb::SBProcess::GetBroadcasterClassName(), + lldb::SBProcess::eBroadcastBitStateChanged | + lldb::SBProcess::eBroadcastBitSTDOUT | + lldb::SBProcess::eBroadcastBitSTDERR); + listener.StartListeningForEvents(debugger.GetBroadcaster(), + lldb::SBDebugger::eBroadcastBitError | + lldb::SBDebugger::eBroadcastBitWarning); + // Listen for the lldb-dap stop event. + listener.StartListeningForEvents(broadcaster, eBroadcastBitStopEventThread); + + lldb::SBEvent event; bool done = false; while (!done) { if (listener.WaitForEvent(1, event)) { @@ -1633,8 +1632,8 @@ void DAP::EventThread() { SendJSON(llvm::json::Value(std::move(bp_event))); } } - } else if (event_mask & lldb::eBroadcastBitError || - event_mask & lldb::eBroadcastBitWarning) { + } else if (event_mask & lldb::SBDebugger::eBroadcastBitError || + event_mask & lldb::SBDebugger::eBroadcastBitWarning) { lldb::SBStructuredData data = lldb::SBDebugger::GetDiagnosticFromEvent(event); if (!data.IsValid()) diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c2e4c2dea582e..c76f6d2ba1ffc 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -334,8 +334,7 @@ struct DAP { /// An SBTarget object. lldb::SBTarget CreateTarget(lldb::SBError &error); - /// Set given target object as a current target for lldb-dap and start - /// listeing for its breakpoint events. + /// Set given target object as a current target for lldb-dap. void SetTarget(const lldb::SBTarget target); bool HandleObject(const protocol::Message &M); diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp index 0293ffbd0c922..167ddb9eb73ed 100644 --- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp @@ -96,7 +96,9 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { if (llvm::Error err = dap.RunAttachCommands(args.attachCommands)) return err; - dap.target = dap.debugger.GetSelectedTarget(); + // The custom commands might have created a new target so we should use + // the selected target after these commands are run. + dap.SetTarget(dap.debugger.GetSelectedTarget()); // Validate the attachCommand results. if (!dap.target.GetProcess().IsValid()) diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp index 93bc80a38e29d..7de582ee94320 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp @@ -209,7 +209,7 @@ llvm::Error BaseRequestHandler::LaunchProcess( // The custom commands might have created a new target so we should use // the selected target after these commands are run. - dap.target = dap.debugger.GetSelectedTarget(); + dap.SetTarget(dap.debugger.GetSelectedTarget()); } } From lldb-commits at lists.llvm.org Thu May 15 14:27:15 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 14:27:15 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Listen for broadcast classes. (PR #140142) In-Reply-To: Message-ID: <68265c33.170a0220.243f9d.3e8d@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: John Harrison (ashgti)
Changes The recent change to the startup flow has highlighted a problem with breakpoint events being missed. Previously, we would handle `attach`/`launch` commands immediately, leaving the process in a suspended until the `configurationDone` command was sent. If a breakpoint was set between the `attach`/`launch` and the `configurationDone` request, it may have been resolved immediately, but there was a chance the module was not yet loaded. With the new startup flow, the breakpoint is always set before the target is loaded. For some targets, this is fine and the breakpoint event fires eventually and marks the breakpoint as verified. However, if a `attach`/`launch` request has `attachCommands`/`launchCommands` that create a new target then we will miss the breakpoint events associated with that target because we haven't configured the target broadcaster for the debugger. We only configure that in the `DAP::SetTarget` call, which happens after the events would have occurred. To address this, I adjusted the `DAP::EventThread` to listen for the broadcast class instead of an individual broadcaster. I think this may also fix the unstable `TestDAP_breakpointEvents` tests. We're not using the `Debugger::DefaultEventHandler` https://github.com/llvm/llvm-project/blob/090f46d8d246762401c41c5486dde299382d6c90/lldb/source/Core/Debugger.cpp#L2048 which is why these broadcast classes are not registered on our debugger instance in lldb-dap. --- Full diff: https://github.com/llvm/llvm-project/pull/140142.diff 4 Files Affected: - (modified) lldb/tools/lldb-dap/DAP.cpp (+26-27) - (modified) lldb/tools/lldb-dap/DAP.h (+1-2) - (modified) lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp (+3-1) - (modified) lldb/tools/lldb-dap/Handler/RequestHandler.cpp (+1-1) ``````````diff diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 51f9da854f4b6..827ebb1465938 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -26,6 +26,7 @@ #include "lldb/API/SBListener.h" #include "lldb/API/SBProcess.h" #include "lldb/API/SBStream.h" +#include "lldb/API/SBTarget.h" #include "lldb/Utility/IOObject.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-defines.h" @@ -719,23 +720,7 @@ lldb::SBTarget DAP::CreateTarget(lldb::SBError &error) { return target; } -void DAP::SetTarget(const lldb::SBTarget target) { - this->target = target; - - if (target.IsValid()) { - // Configure breakpoint event listeners for the target. - lldb::SBListener listener = this->debugger.GetListener(); - listener.StartListeningForEvents( - this->target.GetBroadcaster(), - lldb::SBTarget::eBroadcastBitBreakpointChanged | - lldb::SBTarget::eBroadcastBitModulesLoaded | - lldb::SBTarget::eBroadcastBitModulesUnloaded | - lldb::SBTarget::eBroadcastBitSymbolsLoaded | - lldb::SBTarget::eBroadcastBitSymbolsChanged); - listener.StartListeningForEvents(this->broadcaster, - eBroadcastBitStopEventThread); - } -} +void DAP::SetTarget(const lldb::SBTarget target) { this->target = target; } bool DAP::HandleObject(const Message &M) { TelemetryDispatcher dispatcher(&debugger); @@ -1489,17 +1474,31 @@ void DAP::ProgressEventThread() { } // All events from the debugger, target, process, thread and frames are -// received in this function that runs in its own thread. We are using a -// "FILE *" to output packets back to VS Code and they have mutexes in them -// them prevent multiple threads from writing simultaneously so no locking -// is required. +// received in this function that runs in its own thread. void DAP::EventThread() { llvm::set_thread_name(transport.GetClientName() + ".event_handler"); - lldb::SBEvent event; + + // Configure the debugger listener for all events lldb-dap is interested in. lldb::SBListener listener = debugger.GetListener(); - broadcaster.AddListener(listener, eBroadcastBitStopEventThread); - debugger.GetBroadcaster().AddListener( - listener, lldb::eBroadcastBitError | lldb::eBroadcastBitWarning); + listener.StartListeningForEventClass( + debugger, lldb::SBTarget::GetBroadcasterClassName(), + lldb::SBTarget::eBroadcastBitBreakpointChanged | + lldb::SBTarget::eBroadcastBitModulesLoaded | + lldb::SBTarget::eBroadcastBitModulesUnloaded | + lldb::SBTarget::eBroadcastBitSymbolsLoaded | + lldb::SBTarget::eBroadcastBitSymbolsChanged); + listener.StartListeningForEventClass( + debugger, lldb::SBProcess::GetBroadcasterClassName(), + lldb::SBProcess::eBroadcastBitStateChanged | + lldb::SBProcess::eBroadcastBitSTDOUT | + lldb::SBProcess::eBroadcastBitSTDERR); + listener.StartListeningForEvents(debugger.GetBroadcaster(), + lldb::SBDebugger::eBroadcastBitError | + lldb::SBDebugger::eBroadcastBitWarning); + // Listen for the lldb-dap stop event. + listener.StartListeningForEvents(broadcaster, eBroadcastBitStopEventThread); + + lldb::SBEvent event; bool done = false; while (!done) { if (listener.WaitForEvent(1, event)) { @@ -1633,8 +1632,8 @@ void DAP::EventThread() { SendJSON(llvm::json::Value(std::move(bp_event))); } } - } else if (event_mask & lldb::eBroadcastBitError || - event_mask & lldb::eBroadcastBitWarning) { + } else if (event_mask & lldb::SBDebugger::eBroadcastBitError || + event_mask & lldb::SBDebugger::eBroadcastBitWarning) { lldb::SBStructuredData data = lldb::SBDebugger::GetDiagnosticFromEvent(event); if (!data.IsValid()) diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c2e4c2dea582e..c76f6d2ba1ffc 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -334,8 +334,7 @@ struct DAP { /// An SBTarget object. lldb::SBTarget CreateTarget(lldb::SBError &error); - /// Set given target object as a current target for lldb-dap and start - /// listeing for its breakpoint events. + /// Set given target object as a current target for lldb-dap. void SetTarget(const lldb::SBTarget target); bool HandleObject(const protocol::Message &M); diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp index 0293ffbd0c922..167ddb9eb73ed 100644 --- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp @@ -96,7 +96,9 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { if (llvm::Error err = dap.RunAttachCommands(args.attachCommands)) return err; - dap.target = dap.debugger.GetSelectedTarget(); + // The custom commands might have created a new target so we should use + // the selected target after these commands are run. + dap.SetTarget(dap.debugger.GetSelectedTarget()); // Validate the attachCommand results. if (!dap.target.GetProcess().IsValid()) diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp index 93bc80a38e29d..7de582ee94320 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp @@ -209,7 +209,7 @@ llvm::Error BaseRequestHandler::LaunchProcess( // The custom commands might have created a new target so we should use // the selected target after these commands are run. - dap.target = dap.debugger.GetSelectedTarget(); + dap.SetTarget(dap.debugger.GetSelectedTarget()); } } ``````````
https://github.com/llvm/llvm-project/pull/140142 From lldb-commits at lists.llvm.org Thu May 15 14:58:46 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Thu, 15 May 2025 14:58:46 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68266396.170a0220.3a7a8b.2e91@mx.google.com> https://github.com/eronnen updated https://github.com/llvm/llvm-project/pull/139969 >From ae324862f516ebb5be3206485476b586b22488b7 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sat, 10 May 2025 20:45:17 +0200 Subject: [PATCH 1/4] support assembly in BreakpointLocationsRequestHandler --- .../breakpoint/TestDAP_setBreakpoints.py | 1 - .../TestDAP_setExceptionBreakpoints.py | 1 - .../TestDAP_setFunctionBreakpoints.py | 1 - lldb/tools/lldb-dap/DAP.h | 3 + .../Handler/BreakpointLocationsHandler.cpp | 77 +++++++++++++++---- lldb/tools/lldb-dap/Handler/RequestHandler.h | 11 +++ .../lldb-dap/Handler/SourceRequestHandler.cpp | 4 +- 7 files changed, 76 insertions(+), 22 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index aae1251b17c93..26df2573555df 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,7 +12,6 @@ import os - at skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py index 4dc8c5b3c7ded..92ac66cd44c5d 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setExceptionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_functionality(self): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index baaca4d974d5d..946595f639edc 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c1a1130b1e59f..587d15891530e 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -219,6 +219,9 @@ struct DAP { llvm::StringSet<> modules; /// @} + /// Number of lines of assembly code to show when no debug info is available. + uint32_t number_of_assembly_lines_for_nodebug = 32; + /// Creates a new DAP sessions. /// /// \param[in] log diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 2ac886c3a5d2c..9eea549d72b00 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "JSONUtils.h" +#include "LLDBUtils.h" #include "RequestHandler.h" #include @@ -19,19 +19,50 @@ namespace lldb_dap { llvm::Expected BreakpointLocationsRequestHandler::Run( const protocol::BreakpointLocationsArguments &args) const { - std::string path = args.source.path.value_or(""); uint32_t start_line = args.line; uint32_t start_column = args.column.value_or(LLDB_INVALID_COLUMN_NUMBER); uint32_t end_line = args.endLine.value_or(start_line); uint32_t end_column = args.endColumn.value_or(std::numeric_limits::max()); + // Find all relevant lines & columns + llvm::SmallVector, 8> locations; + if (args.source.sourceReference) { + AddAssemblyBreakpointLocations(locations, *args.source.sourceReference, + start_line, end_line); + } else { + std::string path = args.source.path.value_or(""); + AddSourceBreakpointLocations(locations, std::move(path), start_line, + start_column, end_line, end_column); + } + + // The line entries are sorted by addresses, but we must return the list + // ordered by line / column position. + std::sort(locations.begin(), locations.end()); + locations.erase(llvm::unique(locations), locations.end()); + + std::vector breakpoint_locations; + for (auto &l : locations) { + protocol::BreakpointLocation lc; + lc.line = l.first; + lc.column = l.second; + breakpoint_locations.push_back(std::move(lc)); + } + + return protocol::BreakpointLocationsResponseBody{ + /*breakpoints=*/std::move(breakpoint_locations)}; +} + +template +void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const { + lldb::SBFileSpec file_spec(path.c_str(), true); lldb::SBSymbolContextList compile_units = dap.target.FindCompileUnits(file_spec); - // Find all relevant lines & columns - llvm::SmallVector, 8> locations; for (uint32_t c_idx = 0, c_limit = compile_units.GetSize(); c_idx < c_limit; ++c_idx) { const lldb::SBCompileUnit &compile_unit = @@ -71,22 +102,34 @@ BreakpointLocationsRequestHandler::Run( locations.emplace_back(line, column); } } +} - // The line entries are sorted by addresses, but we must return the list - // ordered by line / column position. - std::sort(locations.begin(), locations.end()); - locations.erase(llvm::unique(locations), locations.end()); +template +void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { + lldb::SBProcess process = dap.target.GetProcess(); + lldb::SBThread thread = + process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); + lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - std::vector breakpoint_locations; - for (auto &l : locations) { - protocol::BreakpointLocation lc; - lc.line = l.first; - lc.column = l.second; - breakpoint_locations.push_back(std::move(lc)); - } + if (!frame.IsValid()) + return; - return protocol::BreakpointLocationsResponseBody{ - /*breakpoints=*/std::move(breakpoint_locations)}; + lldb::SBSymbol symbol = frame.GetSymbol(); + if (symbol.IsValid()) { + lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); + } + } else { + for (uint32_t i = start_line - 1; + i < dap.number_of_assembly_lines_for_nodebug && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); + } + } } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index eaebaf6619bbd..89faced78c847 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -16,6 +16,7 @@ #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/JSON.h" @@ -217,6 +218,16 @@ class BreakpointLocationsRequestHandler } llvm::Expected Run(const protocol::BreakpointLocationsArguments &args) const override; + + template + void AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const; + template + void AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const; }; class CompletionsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp index 0ddd87881a164..fb396a3dc8862 100644 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp @@ -52,8 +52,8 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { insts.GetDescription(stream, exe_ctx); } else { // No valid symbol, just return the disassembly. - lldb::SBInstructionList insts = - dap.target.ReadInstructions(frame.GetPCAddress(), 32); + lldb::SBInstructionList insts = dap.target.ReadInstructions( + frame.GetPCAddress(), dap.number_of_assembly_lines_for_nodebug); insts.GetDescription(stream, exe_ctx); } >From e57b4c00c1669c5fa25ce1ecb097e7d6b475f685 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 11 May 2025 19:49:03 +0200 Subject: [PATCH 2/4] support assembly in SetBreakpointsRequestHandler --- lldb/tools/lldb-dap/DAP.h | 1 + .../Handler/BreakpointLocationsHandler.cpp | 20 ++--- lldb/tools/lldb-dap/Handler/RequestHandler.h | 9 ++ .../Handler/SetBreakpointsRequestHandler.cpp | 90 ++++++++++++++++++- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 22 +++++ lldb/tools/lldb-dap/SourceBreakpoint.h | 1 + 6 files changed, 127 insertions(+), 16 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 587d15891530e..0bc9063e1266f 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -169,6 +169,7 @@ struct DAP { Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; + llvm::DenseMap assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 9eea549d72b00..be02c47056310 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -117,18 +117,14 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( return; lldb::SBSymbol symbol = frame.GetSymbol(); - if (symbol.IsValid()) { - lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); - ++i) { - locations.emplace_back(i, 0); - } - } else { - for (uint32_t i = start_line - 1; - i < dap.number_of_assembly_lines_for_nodebug && i < (end_line - 1); - ++i) { - locations.emplace_back(i, 0); - } + if (!symbol.IsValid()) + return; + + // start_line is relative to the symbol's start address + lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); } } diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 89faced78c847..cf12828aef8fc 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -372,6 +372,15 @@ class SetBreakpointsRequestHandler } llvm::Expected Run(const protocol::SetBreakpointsArguments &args) const override; + + std::vector SetSourceBreakpoints( + const std::string &path, + const std::optional> &breakpoints) + const; + std::vector SetAssemblyBreakpoints( + int64_t sourceReference, + const std::optional> &breakpoints) + const; }; class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 86e090b66afe9..71f9e5578ef08 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -9,8 +9,11 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" +#include +#include #include namespace lldb_dap { @@ -23,15 +26,30 @@ llvm::Expected SetBreakpointsRequestHandler::Run( const protocol::SetBreakpointsArguments &args) const { const auto &source = args.source; - const auto path = source.path.value_or(""); + std::vector response_breakpoints; + if (source.sourceReference) + response_breakpoints = SetAssemblyBreakpoints( + source.sourceReference.value(), args.breakpoints); + else if (source.path) + response_breakpoints = + SetSourceBreakpoints(source.path.value(), args.breakpoints); + + return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; +} + +std::vector +SetBreakpointsRequestHandler::SetSourceBreakpoints( + const std::string &path, + const std::optional> &breakpoints) + const { std::vector response_breakpoints; // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; // "breakpoints" may be unset, in which case we treat it the same as being set // to an empty array. - if (args.breakpoints) { - for (const auto &bp : *args.breakpoints) { + if (breakpoints) { + for (const auto &bp : *breakpoints) { SourceBreakpoint src_bp(dap, bp); std::pair bp_pos(src_bp.GetLine(), src_bp.GetColumn()); @@ -73,7 +91,71 @@ SetBreakpointsRequestHandler::Run( } } - return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; + return response_breakpoints; +} + +std::vector +SetBreakpointsRequestHandler::SetAssemblyBreakpoints( + int64_t sourceReference, + const std::optional> &breakpoints) + const { + std::vector response_breakpoints; + + lldb::SBProcess process = dap.target.GetProcess(); + lldb::SBThread thread = + process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); + lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); + + if (!frame.IsValid()) + return response_breakpoints; + + lldb::SBSymbol symbol = frame.GetSymbol(); + if (!symbol.IsValid()) + return response_breakpoints; // Not yet supporting breakpoints in assembly + // without a valid symbol + + SourceBreakpointMap request_bps; + if (breakpoints) { + for (const auto &bp : *breakpoints) { + SourceBreakpoint src_bp(dap, bp); + std::pair bp_pos(src_bp.GetLine(), 0); + request_bps.try_emplace(bp_pos, src_bp); + const auto [iv, inserted] = + dap.assembly_breakpoints[sourceReference].try_emplace(bp_pos, src_bp); + // We check if this breakpoint already exists to update it + if (inserted) + iv->getSecond().SetBreakpoint(symbol); + else + iv->getSecond().UpdateBreakpoint(src_bp); + + protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); + protocol::Source source; + source.sourceReference = sourceReference; + source.name = symbol.GetName(); + response_bp.source = std::move(source); + + if (!response_bp.line) + response_bp.line = src_bp.GetLine(); + if (!response_bp.column) + response_bp.column = src_bp.GetColumn(); + response_breakpoints.push_back(response_bp); + } + } + + // Delete existing breakpoints for this sourceReference that are not in the + // request_bps set. + auto old_src_bp_pos = dap.assembly_breakpoints.find(sourceReference); + if (old_src_bp_pos != dap.assembly_breakpoints.end()) { + for (auto &old_bp : old_src_bp_pos->second) { + auto request_pos = request_bps.find(old_bp.first); + if (request_pos == request_bps.end()) { + dap.target.BreakpointDelete(old_bp.second.GetID()); + old_src_bp_pos->second.erase(old_bp.first); + } + } + } + + return response_breakpoints; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 4581c995b4260..938b8fb8bcdda 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -13,7 +13,9 @@ #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBFileSpecList.h" #include "lldb/API/SBFrame.h" +#include "lldb/API/SBInstruction.h" #include "lldb/API/SBMutex.h" +#include "lldb/API/SBSymbol.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" #include "lldb/API/SBValue.h" @@ -45,6 +47,26 @@ void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) { Breakpoint::SetBreakpoint(); } +void SourceBreakpoint::SetBreakpoint(lldb::SBSymbol &symbol) { + lldb::SBMutex lock = m_dap.GetAPIMutex(); + std::lock_guard guard(lock); + + if (m_line == 0) + return; + + lldb::SBInstructionList inst_list = + m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); + if (inst_list.GetSize() < m_line) + return; + lldb::SBAddress address = + inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + + m_bp = m_dap.target.BreakpointCreateBySBAddress(address); + if (!m_log_message.empty()) + SetLogMessage(); + Breakpoint::SetBreakpoint(); +} + void SourceBreakpoint::UpdateBreakpoint(const SourceBreakpoint &request_bp) { if (m_log_message != request_bp.m_log_message) { m_log_message = request_bp.m_log_message; diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h index 5b15296f861c5..8589800e50983 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.h +++ b/lldb/tools/lldb-dap/SourceBreakpoint.h @@ -26,6 +26,7 @@ class SourceBreakpoint : public Breakpoint { // Set this breakpoint in LLDB as a new breakpoint void SetBreakpoint(const llvm::StringRef source_path); + void SetBreakpoint(lldb::SBSymbol &symbol); void UpdateBreakpoint(const SourceBreakpoint &request_bp); void SetLogMessage(); >From 53ac2b4eb7b1afaca28aca3ca5c26300586a55f4 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Wed, 14 May 2025 23:51:41 +0200 Subject: [PATCH 3/4] fix resolving of assembly source breakpoints --- lldb/tools/lldb-dap/Breakpoint.cpp | 45 ++++++++++++++++--- lldb/tools/lldb-dap/DAP.h | 3 +- .../Handler/BreakpointLocationsHandler.cpp | 4 +- lldb/tools/lldb-dap/Handler/RequestHandler.h | 4 +- .../Handler/SetBreakpointsRequestHandler.cpp | 30 ++++++------- lldb/tools/lldb-dap/package-lock.json | 4 +- lldb/tools/lldb-dap/package.json | 5 ++- 7 files changed, 63 insertions(+), 32 deletions(-) diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 26d633d1d172e..87fcd15b0a568 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -9,10 +9,12 @@ #include "Breakpoint.h" #include "DAP.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "lldb/API/SBAddress.h" #include "lldb/API/SBBreakpointLocation.h" #include "lldb/API/SBLineEntry.h" #include "lldb/API/SBMutex.h" +#include "lldb/lldb-enumerations.h" #include "llvm/ADT/StringExtras.h" #include #include @@ -63,14 +65,43 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { std::string formatted_addr = "0x" + llvm::utohexstr(bp_addr.GetLoadAddress(m_bp.GetTarget())); breakpoint.instructionReference = formatted_addr; + + lldb::StopDisassemblyType stop_disassembly_display = + GetStopDisassemblyDisplay(m_dap.debugger); auto line_entry = bp_addr.GetLineEntry(); - const auto line = line_entry.GetLine(); - if (line != UINT32_MAX) - breakpoint.line = line; - const auto column = line_entry.GetColumn(); - if (column != 0) - breakpoint.column = column; - breakpoint.source = CreateSource(line_entry); + if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) { + const auto line = line_entry.GetLine(); + if (line != UINT32_MAX) + breakpoint.line = line; + const auto column = line_entry.GetColumn(); + if (column != 0) + breakpoint.column = column; + breakpoint.source = CreateSource(line_entry); + } else { + // Breakpoint made by assembly + auto symbol_context = bp_addr.GetSymbolContext( + lldb::eSymbolContextSymbol | lldb::eSymbolContextModule); + if (symbol_context.IsValid()) { + auto symbol = symbol_context.GetSymbol(); + breakpoint.line = + m_bp.GetTarget() + .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) + .GetSize() + + 1; + protocol::Source source; + source.name = symbol.GetName(); + + auto module = symbol_context.GetModule(); + if (module.IsValid()) { + std::string path = module.GetFileSpec().GetDirectory(); + path += "/"; + path += module.GetFileSpec().GetFilename(); + source.path = std::move(path); + } + + breakpoint.source = std::move(source); + } + } } return breakpoint; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 0bc9063e1266f..54b233077f0c3 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -169,7 +169,8 @@ struct DAP { Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; - llvm::DenseMap assembly_breakpoints; + llvm::DenseMap> + assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index be02c47056310..06ada47a6f27f 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -122,9 +122,9 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( // start_line is relative to the symbol's start address lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i <= (end_line - 1); ++i) { - locations.emplace_back(i, 0); + locations.emplace_back(i, 1); } } diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index cf12828aef8fc..1ad6069c20b4b 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -374,11 +374,11 @@ class SetBreakpointsRequestHandler Run(const protocol::SetBreakpointsArguments &args) const override; std::vector SetSourceBreakpoints( - const std::string &path, + const protocol::Source &source, const std::optional> &breakpoints) const; std::vector SetAssemblyBreakpoints( - int64_t sourceReference, + const protocol::Source &source, const std::optional> &breakpoints) const; }; diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 71f9e5578ef08..4fefd8b440c7d 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -28,21 +28,20 @@ SetBreakpointsRequestHandler::Run( const auto &source = args.source; std::vector response_breakpoints; if (source.sourceReference) - response_breakpoints = SetAssemblyBreakpoints( - source.sourceReference.value(), args.breakpoints); + response_breakpoints = SetAssemblyBreakpoints(source, args.breakpoints); else if (source.path) - response_breakpoints = - SetSourceBreakpoints(source.path.value(), args.breakpoints); + response_breakpoints = SetSourceBreakpoints(source, args.breakpoints); return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; } std::vector SetBreakpointsRequestHandler::SetSourceBreakpoints( - const std::string &path, + const protocol::Source &source, const std::optional> &breakpoints) const { std::vector response_breakpoints; + std::string path = source.path.value_or(""); // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; @@ -96,10 +95,11 @@ SetBreakpointsRequestHandler::SetSourceBreakpoints( std::vector SetBreakpointsRequestHandler::SetAssemblyBreakpoints( - int64_t sourceReference, + const protocol::Source &source, const std::optional> &breakpoints) const { std::vector response_breakpoints; + int64_t sourceReference = source.sourceReference.value_or(0); lldb::SBProcess process = dap.target.GetProcess(); lldb::SBThread thread = @@ -114,14 +114,14 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( return response_breakpoints; // Not yet supporting breakpoints in assembly // without a valid symbol - SourceBreakpointMap request_bps; + llvm::DenseMap request_bps; if (breakpoints) { for (const auto &bp : *breakpoints) { SourceBreakpoint src_bp(dap, bp); - std::pair bp_pos(src_bp.GetLine(), 0); - request_bps.try_emplace(bp_pos, src_bp); + request_bps.try_emplace(src_bp.GetLine(), src_bp); const auto [iv, inserted] = - dap.assembly_breakpoints[sourceReference].try_emplace(bp_pos, src_bp); + dap.assembly_breakpoints[sourceReference].try_emplace( + src_bp.GetLine(), src_bp); // We check if this breakpoint already exists to update it if (inserted) iv->getSecond().SetBreakpoint(symbol); @@ -129,15 +129,11 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( iv->getSecond().UpdateBreakpoint(src_bp); protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - protocol::Source source; - source.sourceReference = sourceReference; - source.name = symbol.GetName(); - response_bp.source = std::move(source); - + response_bp.source = source; if (!response_bp.line) response_bp.line = src_bp.GetLine(); - if (!response_bp.column) - response_bp.column = src_bp.GetColumn(); + if (bp.column) + response_bp.column = *bp.column; response_breakpoints.push_back(response_bp); } } diff --git a/lldb/tools/lldb-dap/package-lock.json b/lldb/tools/lldb-dap/package-lock.json index 0a2b9e764067e..af90a9573aee6 100644 --- a/lldb/tools/lldb-dap/package-lock.json +++ b/lldb/tools/lldb-dap/package-lock.json @@ -1,12 +1,12 @@ { "name": "lldb-dap", - "version": "0.2.13", + "version": "0.2.14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lldb-dap", - "version": "0.2.13", + "version": "0.2.14", "license": "Apache 2.0 License with LLVM exceptions", "devDependencies": { "@types/node": "^18.19.41", diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index d5ca604798799..73e70cd961f4f 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -1,7 +1,7 @@ { "name": "lldb-dap", "displayName": "LLDB DAP", - "version": "0.2.13", + "version": "0.2.14", "publisher": "llvm-vs-code-extensions", "homepage": "https://lldb.llvm.org", "description": "Debugging with LLDB in Visual Studio Code", @@ -265,6 +265,9 @@ ] }, "breakpoints": [ + { + "language": "lldb.disassembly" + }, { "language": "ada" }, >From 226363193267986cee34c130baa125749ae0a2f9 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Thu, 15 May 2025 00:36:10 +0200 Subject: [PATCH 4/4] remove include --- lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 4fefd8b440c7d..d69da5bd02c1e 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -12,8 +12,6 @@ #include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" -#include -#include #include namespace lldb_dap { From lldb-commits at lists.llvm.org Thu May 15 15:04:28 2025 From: lldb-commits at lists.llvm.org (Jacob Lalonde via lldb-commits) Date: Thu, 15 May 2025 15:04:28 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Support all the Generic (Negative) SI Codes. (PR #140150) Message-ID: https://github.com/Jlalond created https://github.com/llvm/llvm-project/pull/140150 Recently, I was on an issue that generated a large number of Coredumps, and every time in both LLDB and GDB the signal was just `SIGSEGV`. This was frustrating because we would expect a `SIGSEGV` to have an address, or ideally even bounds. After some digging I found the `si_code` consistently was -6. With some help from [@cdown](https://github.com/cdown), we found neither LLDB or GDB supports the si_codes sent from [user space](https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/siginfo.h#L185). Excerpted from the sigaction man page. ``` For a regular signal, the following list shows the values which can be placed in si_code for any signal, along with the reason that the signal was generated. ``` For which I added all of the si_codes to every Linux signal. Now for the Coredump that triggered this whole investigation we get the accurate and now very informative summary. image Importantly, I didn't add an equivalent of `siginfo_t` to ELFSigInfo, and I think we should open an issue for this to make a (build) platform agnostic struct of siginfo_t. I'll defer to your expertise @labath and @DavidSpickett >From 86ec6c076b9cf8e7afeb7d6bb0e334434f6e0d9e Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Thu, 15 May 2025 13:57:11 -0700 Subject: [PATCH 1/4] Update ThreadElfCore --- lldb/include/lldb/Target/UnixSignals.h | 6 ++++-- .../Plugins/Process/Utility/LinuxSignals.cpp | 17 ++++++++++++++--- .../Plugins/Process/elf-core/ThreadElfCore.cpp | 10 +++++++--- .../Plugins/Process/elf-core/ThreadElfCore.h | 6 ++++++ lldb/source/Target/UnixSignals.cpp | 9 +++++++-- 5 files changed, 38 insertions(+), 10 deletions(-) diff --git a/lldb/include/lldb/Target/UnixSignals.h b/lldb/include/lldb/Target/UnixSignals.h index b3605ccefddbe..a1807d69f329b 100644 --- a/lldb/include/lldb/Target/UnixSignals.h +++ b/lldb/include/lldb/Target/UnixSignals.h @@ -36,7 +36,9 @@ class UnixSignals { std::optional code = std::nullopt, std::optional addr = std::nullopt, std::optional lower = std::nullopt, - std::optional upper = std::nullopt) const; + std::optional upper = std::nullopt, + std::optional pid = std::nullopt, + std::optional uid = std::nullopt) const; bool SignalIsValid(int32_t signo) const; @@ -105,7 +107,7 @@ class UnixSignals { llvm::StringRef description, llvm::StringRef alias = llvm::StringRef()); - enum SignalCodePrintOption { None, Address, Bounds }; + enum SignalCodePrintOption { None, Address, Bounds, Sender }; // Instead of calling this directly, use a ADD_SIGCODE macro to get compile // time checks when on the native platform. diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index 9c4fe55147a28..25d4e4609bbb8 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -38,6 +38,17 @@ #define ADD_SIGCODE(signal_name, signal_value, code_name, code_value, ...) \ AddSignalCode(signal_value, code_value, __VA_ARGS__) #endif /* if defined(__linux__) && !defined(__mips__) */ +// See siginfo.h in the Linux Kernel, these codes can be sent for any signal. +#define ADD_LINUX_SIGNAL(signo, name, ...) \ + AddSignal(signo, name, __VA_ARGS__); \ + ADD_SIGCODE(signo, signo, SI_QUEUE, -1, "sent by sigqueue"); \ + ADD_SIGCODE(signo, signo, SI_TIMER, -2, "sent by timer expiration"); \ + ADD_SIGCODE(signo, signo, SI_MESGQ, -3, "sent by real time mesq state change"); \ + ADD_SIGCODE(signo, signo, SI_ASYNCIO, -4, "sent by AIO completion"); \ + ADD_SIGCODE(signo, signo, SI_SIGIO, -5, "sent by queued SIGIO"); \ + ADD_SIGCODE(signo, signo, SI_TKILL, -6, "sent by tkill system call"); \ + ADD_SIGCODE(signo, signo, SI_DETHREAD, -7, "sent by execve() killing subsidiary threads"); \ + ADD_SIGCODE(signo, signo, SI_ASYNCNL, -60, "sent by glibc async name lookup completion"); using namespace lldb_private; @@ -46,9 +57,9 @@ LinuxSignals::LinuxSignals() : UnixSignals() { Reset(); } void LinuxSignals::Reset() { m_signals.clear(); // clang-format off - // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION - // ====== ============== ======== ====== ====== =================================================== - AddSignal(1, "SIGHUP", false, true, true, "hangup"); + // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION + // ====== ============== ======== ====== ====== =================================================== + ADD_LINUX_SIGNAL(1, "SIGHUP", false, true, true, "hangup"); AddSignal(2, "SIGINT", true, true, true, "interrupt"); AddSignal(3, "SIGQUIT", false, true, true, "quit"); diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index a0cd0ee5025bd..267879a473463 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -584,9 +584,13 @@ Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, // 64b ELF have a 4 byte pad. if (data.GetAddressByteSize() == 8) offset += 4; - // Not every stop signal has a valid address, but that will get resolved in - // the unix_signals.GetSignalDescription() call below. - if (unix_signals.GetShouldStop(si_signo)) { + + if (si_code < 0) { + sigfault.kill._pid = data.GetU32(&offset); + sigfault.kill._uid = data.GetU32(&offset); + } else if (unix_signals.GetShouldStop(si_signo)) { + // Not every stop signal has a valid address, but that will get resolved in + // the unix_signals.GetSignalDescription() call below. // Instead of memcpy we call all these individually as the extractor will // handle endianness for us. sigfault.si_addr = data.GetAddress(&offset); diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h index 6f8d41351a6bf..2cbf794c2b5b1 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -96,6 +96,12 @@ struct ELFLinuxSigInfo { /* used when si_code=SEGV_PKUERR */ uint32_t _pkey; } bounds; + + // We need this for all the generic signals. + struct { + uint32_t _pid; /* sender's pid */ + uint32_t _uid; /* sender's uid */ + } _kill; } sigfault; enum SigInfoNoteType : uint8_t { eUnspecified, eNT_SIGINFO }; diff --git a/lldb/source/Target/UnixSignals.cpp b/lldb/source/Target/UnixSignals.cpp index da661003925c7..a5dbfd029410a 100644 --- a/lldb/source/Target/UnixSignals.cpp +++ b/lldb/source/Target/UnixSignals.cpp @@ -141,7 +141,9 @@ std::string UnixSignals::GetSignalDescription(int32_t signo, std::optional code, std::optional addr, std::optional lower, - std::optional upper) const { + std::optional upper, + std::optional pid, + std::optional uid) const { std::string str; collection::const_iterator pos = m_signals.find(signo); @@ -180,6 +182,10 @@ UnixSignals::GetSignalDescription(int32_t signo, std::optional code, strm << sc.m_description.str(); break; + case SignalCodePrintOption::Sender: + if (pid && uid) + strm << " (sender pid=" << *pid << ", uid=" << *uid << ")"; + break; } str += strm.str(); } @@ -397,4 +403,3 @@ bool UnixSignals::ResetSignal(int32_t signo, bool reset_stop, (*elem).second.Reset(reset_stop, reset_notify, reset_suppress); return true; } - >From 6d8a30cc38816f661cd3126613987ccbde39ab05 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Thu, 15 May 2025 14:33:15 -0700 Subject: [PATCH 2/4] Add sender option to LinuxSignals.cpp --- .../Plugins/Process/Utility/LinuxSignals.cpp | 142 +++++++++--------- .../Process/elf-core/ThreadElfCore.cpp | 32 ++-- .../Plugins/Process/elf-core/ThreadElfCore.h | 44 +++--- 3 files changed, 111 insertions(+), 107 deletions(-) diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index 25d4e4609bbb8..da0abf5a1f471 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -41,14 +41,14 @@ // See siginfo.h in the Linux Kernel, these codes can be sent for any signal. #define ADD_LINUX_SIGNAL(signo, name, ...) \ AddSignal(signo, name, __VA_ARGS__); \ - ADD_SIGCODE(signo, signo, SI_QUEUE, -1, "sent by sigqueue"); \ - ADD_SIGCODE(signo, signo, SI_TIMER, -2, "sent by timer expiration"); \ - ADD_SIGCODE(signo, signo, SI_MESGQ, -3, "sent by real time mesq state change"); \ - ADD_SIGCODE(signo, signo, SI_ASYNCIO, -4, "sent by AIO completion"); \ - ADD_SIGCODE(signo, signo, SI_SIGIO, -5, "sent by queued SIGIO"); \ - ADD_SIGCODE(signo, signo, SI_TKILL, -6, "sent by tkill system call"); \ - ADD_SIGCODE(signo, signo, SI_DETHREAD, -7, "sent by execve() killing subsidiary threads"); \ - ADD_SIGCODE(signo, signo, SI_ASYNCNL, -60, "sent by glibc async name lookup completion"); + ADD_SIGCODE(signo, signo, SI_QUEUE, -1, "sent by sigqueue", SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_TIMER, -2, "sent by timer expiration", SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_MESGQ, -3, "sent by real time mesq state change", SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_ASYNCIO, -4, "sent by AIO completion", SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_SIGIO, -5, "sent by queued SIGIO", SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_TKILL, -6, "sent by tkill system call", SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_DETHREAD, -7, "sent by execve() killing subsidiary threads", SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_ASYNCNL, -60, "sent by glibc async name lookup completion", SignalCodePrintOption::Sender); using namespace lldb_private; @@ -60,10 +60,10 @@ void LinuxSignals::Reset() { // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION // ====== ============== ======== ====== ====== =================================================== ADD_LINUX_SIGNAL(1, "SIGHUP", false, true, true, "hangup"); - AddSignal(2, "SIGINT", true, true, true, "interrupt"); - AddSignal(3, "SIGQUIT", false, true, true, "quit"); + ADD_LINUX_SIGNAL(2, "SIGINT", true, true, true, "interrupt"); + ADD_LINUX_SIGNAL(3, "SIGQUIT", false, true, true, "quit"); - AddSignal(4, "SIGILL", false, true, true, "illegal instruction"); + ADD_LINUX_SIGNAL(4, "SIGILL", false, true, true, "illegal instruction"); ADD_SIGCODE(SIGILL, 4, ILL_ILLOPC, 1, "illegal opcode"); ADD_SIGCODE(SIGILL, 4, ILL_ILLOPN, 2, "illegal operand"); ADD_SIGCODE(SIGILL, 4, ILL_ILLADR, 3, "illegal addressing mode"); @@ -73,15 +73,15 @@ void LinuxSignals::Reset() { ADD_SIGCODE(SIGILL, 4, ILL_COPROC, 7, "coprocessor error"); ADD_SIGCODE(SIGILL, 4, ILL_BADSTK, 8, "internal stack error"); - AddSignal(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)"); - AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT"); + ADD_LINUX_SIGNAL(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)"); + ADD_LINUX_SIGNAL(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT"); - AddSignal(7, "SIGBUS", false, true, true, "bus error"); + ADD_LINUX_SIGNAL(7, "SIGBUS", false, true, true, "bus error"); ADD_SIGCODE(SIGBUS, 7, BUS_ADRALN, 1, "illegal alignment"); ADD_SIGCODE(SIGBUS, 7, BUS_ADRERR, 2, "illegal address"); ADD_SIGCODE(SIGBUS, 7, BUS_OBJERR, 3, "hardware error"); - AddSignal(8, "SIGFPE", false, true, true, "floating point exception"); + ADD_LINUX_SIGNAL(8, "SIGFPE", false, true, true, "floating point exception"); ADD_SIGCODE(SIGFPE, 8, FPE_INTDIV, 1, "integer divide by zero"); ADD_SIGCODE(SIGFPE, 8, FPE_INTOVF, 2, "integer overflow"); ADD_SIGCODE(SIGFPE, 8, FPE_FLTDIV, 3, "floating point divide by zero"); @@ -91,10 +91,10 @@ void LinuxSignals::Reset() { ADD_SIGCODE(SIGFPE, 8, FPE_FLTINV, 7, "floating point invalid operation"); ADD_SIGCODE(SIGFPE, 8, FPE_FLTSUB, 8, "subscript out of range"); - AddSignal(9, "SIGKILL", false, true, true, "kill"); - AddSignal(10, "SIGUSR1", false, true, true, "user defined signal 1"); + ADD_LINUX_SIGNAL(9, "SIGKILL", false, true, true, "kill"); + ADD_LINUX_SIGNAL(10, "SIGUSR1", false, true, true, "user defined signal 1"); - AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation"); + ADD_LINUX_SIGNAL(11, "SIGSEGV", false, true, true, "segmentation violation"); ADD_SIGCODE(SIGSEGV, 11, SEGV_MAPERR, 1, "address not mapped to object", SignalCodePrintOption::Address); ADD_SIGCODE(SIGSEGV, 11, SEGV_ACCERR, 2, "invalid permissions for mapped object", SignalCodePrintOption::Address); ADD_SIGCODE(SIGSEGV, 11, SEGV_BNDERR, 3, "failed address bounds checks", SignalCodePrintOption::Bounds); @@ -105,58 +105,58 @@ void LinuxSignals::Reset() { // codes. One way to get this is via unaligned SIMD loads. Treat it as invalid address. ADD_SIGCODE(SIGSEGV, 11, SI_KERNEL, 0x80, "invalid address", SignalCodePrintOption::Address); - AddSignal(12, "SIGUSR2", false, true, true, "user defined signal 2"); - AddSignal(13, "SIGPIPE", false, true, true, "write to pipe with reading end closed"); - AddSignal(14, "SIGALRM", false, false, false, "alarm"); - AddSignal(15, "SIGTERM", false, true, true, "termination requested"); - AddSignal(16, "SIGSTKFLT", false, true, true, "stack fault"); - AddSignal(17, "SIGCHLD", false, false, true, "child status has changed", "SIGCLD"); - AddSignal(18, "SIGCONT", false, false, true, "process continue"); - AddSignal(19, "SIGSTOP", true, true, true, "process stop"); - AddSignal(20, "SIGTSTP", false, true, true, "tty stop"); - AddSignal(21, "SIGTTIN", false, true, true, "background tty read"); - AddSignal(22, "SIGTTOU", false, true, true, "background tty write"); - AddSignal(23, "SIGURG", false, true, true, "urgent data on socket"); - AddSignal(24, "SIGXCPU", false, true, true, "CPU resource exceeded"); - AddSignal(25, "SIGXFSZ", false, true, true, "file size limit exceeded"); - AddSignal(26, "SIGVTALRM", false, true, true, "virtual time alarm"); - AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm"); - AddSignal(28, "SIGWINCH", false, true, true, "window size changes"); - AddSignal(29, "SIGIO", false, true, true, "input/output ready/Pollable event", "SIGPOLL"); - AddSignal(30, "SIGPWR", false, true, true, "power failure"); - AddSignal(31, "SIGSYS", false, true, true, "invalid system call"); - AddSignal(32, "SIG32", false, false, false, "threading library internal signal 1"); - AddSignal(33, "SIG33", false, false, false, "threading library internal signal 2"); - AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0"); - AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1"); - AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2"); - AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3"); - AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4"); - AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5"); - AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6"); - AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7"); - AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8"); - AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9"); - AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10"); - AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11"); - AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12"); - AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13"); - AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14"); - AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15"); - AddSignal(50, "SIGRTMAX-14", false, false, false, "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output - AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17"); - AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18"); - AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19"); - AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20"); - AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21"); - AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22"); - AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23"); - AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24"); - AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25"); - AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26"); - AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27"); - AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28"); - AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29"); - AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30"); + ADD_LINUX_SIGNAL(12, "SIGUSR2", false, true, true, "user defined signal 2"); + ADD_LINUX_SIGNAL(13, "SIGPIPE", false, true, true, "write to pipe with reading end closed"); + ADD_LINUX_SIGNAL(14, "SIGALRM", false, false, false, "alarm"); + ADD_LINUX_SIGNAL(15, "SIGTERM", false, true, true, "termination requested"); + ADD_LINUX_SIGNAL(16, "SIGSTKFLT", false, true, true, "stack fault"); + ADD_LINUX_SIGNAL(17, "SIGCHLD", false, false, true, "child status has changed", "SIGCLD"); + ADD_LINUX_SIGNAL(18, "SIGCONT", false, false, true, "process continue"); + ADD_LINUX_SIGNAL(19, "SIGSTOP", true, true, true, "process stop"); + ADD_LINUX_SIGNAL(20, "SIGTSTP", false, true, true, "tty stop"); + ADD_LINUX_SIGNAL(21, "SIGTTIN", false, true, true, "background tty read"); + ADD_LINUX_SIGNAL(22, "SIGTTOU", false, true, true, "background tty write"); + ADD_LINUX_SIGNAL(23, "SIGURG", false, true, true, "urgent data on socket"); + ADD_LINUX_SIGNAL(24, "SIGXCPU", false, true, true, "CPU resource exceeded"); + ADD_LINUX_SIGNAL(25, "SIGXFSZ", false, true, true, "file size limit exceeded"); + ADD_LINUX_SIGNAL(26, "SIGVTALRM", false, true, true, "virtual time alarm"); + ADD_LINUX_SIGNAL(27, "SIGPROF", false, false, false, "profiling time alarm"); + ADD_LINUX_SIGNAL(28, "SIGWINCH", false, true, true, "window size changes"); + ADD_LINUX_SIGNAL(29, "SIGIO", false, true, true, "input/output ready/Pollable event", "SIGPOLL"); + ADD_LINUX_SIGNAL(30, "SIGPWR", false, true, true, "power failure"); + ADD_LINUX_SIGNAL(31, "SIGSYS", false, true, true, "invalid system call"); + ADD_LINUX_SIGNAL(32, "SIG32", false, false, false, "threading library internal signal 1"); + ADD_LINUX_SIGNAL(33, "SIG33", false, false, false, "threading library internal signal 2"); + ADD_LINUX_SIGNAL(34, "SIGRTMIN", false, false, false, "real time signal 0"); + ADD_LINUX_SIGNAL(35, "SIGRTMIN+1", false, false, false, "real time signal 1"); + ADD_LINUX_SIGNAL(36, "SIGRTMIN+2", false, false, false, "real time signal 2"); + ADD_LINUX_SIGNAL(37, "SIGRTMIN+3", false, false, false, "real time signal 3"); + ADD_LINUX_SIGNAL(38, "SIGRTMIN+4", false, false, false, "real time signal 4"); + ADD_LINUX_SIGNAL(39, "SIGRTMIN+5", false, false, false, "real time signal 5"); + ADD_LINUX_SIGNAL(40, "SIGRTMIN+6", false, false, false, "real time signal 6"); + ADD_LINUX_SIGNAL(41, "SIGRTMIN+7", false, false, false, "real time signal 7"); + ADD_LINUX_SIGNAL(42, "SIGRTMIN+8", false, false, false, "real time signal 8"); + ADD_LINUX_SIGNAL(43, "SIGRTMIN+9", false, false, false, "real time signal 9"); + ADD_LINUX_SIGNAL(44, "SIGRTMIN+10", false, false, false, "real time signal 10"); + ADD_LINUX_SIGNAL(45, "SIGRTMIN+11", false, false, false, "real time signal 11"); + ADD_LINUX_SIGNAL(46, "SIGRTMIN+12", false, false, false, "real time signal 12"); + ADD_LINUX_SIGNAL(47, "SIGRTMIN+13", false, false, false, "real time signal 13"); + ADD_LINUX_SIGNAL(48, "SIGRTMIN+14", false, false, false, "real time signal 14"); + ADD_LINUX_SIGNAL(49, "SIGRTMIN+15", false, false, false, "real time signal 15"); + ADD_LINUX_SIGNAL(50, "SIGRTMAX-14", false, false, false, "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output + ADD_LINUX_SIGNAL(51, "SIGRTMAX-13", false, false, false, "real time signal 17"); + ADD_LINUX_SIGNAL(52, "SIGRTMAX-12", false, false, false, "real time signal 18"); + ADD_LINUX_SIGNAL(53, "SIGRTMAX-11", false, false, false, "real time signal 19"); + ADD_LINUX_SIGNAL(54, "SIGRTMAX-10", false, false, false, "real time signal 20"); + ADD_LINUX_SIGNAL(55, "SIGRTMAX-9", false, false, false, "real time signal 21"); + ADD_LINUX_SIGNAL(56, "SIGRTMAX-8", false, false, false, "real time signal 22"); + ADD_LINUX_SIGNAL(57, "SIGRTMAX-7", false, false, false, "real time signal 23"); + ADD_LINUX_SIGNAL(58, "SIGRTMAX-6", false, false, false, "real time signal 24"); + ADD_LINUX_SIGNAL(59, "SIGRTMAX-5", false, false, false, "real time signal 25"); + ADD_LINUX_SIGNAL(60, "SIGRTMAX-4", false, false, false, "real time signal 26"); + ADD_LINUX_SIGNAL(61, "SIGRTMAX-3", false, false, false, "real time signal 27"); + ADD_LINUX_SIGNAL(62, "SIGRTMAX-2", false, false, false, "real time signal 28"); + ADD_LINUX_SIGNAL(63, "SIGRTMAX-1", false, false, false, "real time signal 29"); + ADD_LINUX_SIGNAL(64, "SIGRTMAX", false, false, false, "real time signal 30"); // clang-format on } diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index 267879a473463..ce0f65cd9f14c 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -586,24 +586,24 @@ Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, offset += 4; if (si_code < 0) { - sigfault.kill._pid = data.GetU32(&offset); - sigfault.kill._uid = data.GetU32(&offset); + sifields.kill.pid = data.GetU32(&offset); + sifields.kill.uid = data.GetU32(&offset); } else if (unix_signals.GetShouldStop(si_signo)) { // Not every stop signal has a valid address, but that will get resolved in // the unix_signals.GetSignalDescription() call below. // Instead of memcpy we call all these individually as the extractor will // handle endianness for us. - sigfault.si_addr = data.GetAddress(&offset); - sigfault.si_addr_lsb = data.GetU16(&offset); - if (data.GetByteSize() - offset >= sizeof(sigfault.bounds)) { - sigfault.bounds._addr_bnd._lower = data.GetAddress(&offset); - sigfault.bounds._addr_bnd._upper = data.GetAddress(&offset); - sigfault.bounds._pkey = data.GetU32(&offset); + sifields.sigfault.si_addr = data.GetAddress(&offset); + sifields.sigfault.si_addr_lsb = data.GetU16(&offset); + if (data.GetByteSize() - offset >= sizeof(sifields.sigfault.bounds)) { + sifields.sigfault.bounds._addr_bnd._lower = data.GetAddress(&offset); + sifields.sigfault.bounds._addr_bnd._upper = data.GetAddress(&offset); + sifields.sigfault.bounds._pkey = data.GetU32(&offset); } else { // Set these to 0 so we don't use bogus data for the description. - sigfault.bounds._addr_bnd._lower = 0; - sigfault.bounds._addr_bnd._upper = 0; - sigfault.bounds._pkey = 0; + sifields.sigfault.bounds._addr_bnd._lower = 0; + sifields.sigfault.bounds._addr_bnd._upper = 0; + sifields.sigfault.bounds._pkey = 0; } } @@ -613,13 +613,15 @@ Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, std::string ELFLinuxSigInfo::GetDescription( const lldb_private::UnixSignals &unix_signals) const { if (unix_signals.GetShouldStop(si_signo) && note_type == eNT_SIGINFO) { - if (sigfault.bounds._addr_bnd._upper != 0) + if (si_code < 0) + return unix_signals.GetSignalDescription(si_signo, si_code, std::nullopt, std::nullopt, std::nullopt, sifields.kill.pid, sifields.kill.uid); + else if (sifields.sigfault.bounds._addr_bnd._upper != 0) return unix_signals.GetSignalDescription( - si_signo, si_code, sigfault.si_addr, sigfault.bounds._addr_bnd._lower, - sigfault.bounds._addr_bnd._upper); + si_signo, si_code, sifields.sigfault.si_addr, sifields.sigfault.bounds._addr_bnd._lower, + sifields.sigfault.bounds._addr_bnd._upper); else return unix_signals.GetSignalDescription(si_signo, si_code, - sigfault.si_addr); + sifields.sigfault.si_addr); } // This looks weird, but there is an existing pattern where we don't pass a diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h index 2cbf794c2b5b1..2c254b4b522e9 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -82,27 +82,29 @@ struct ELFLinuxSigInfo { int32_t si_signo; // Order matters for the first 3. int32_t si_errno; int32_t si_code; - // Copied from siginfo_t so we don't have to include signal.h on non 'Nix - // builds. Slight modifications to ensure no 32b vs 64b differences. - struct alignas(8) { - lldb::addr_t si_addr; /* faulting insn/memory ref. */ - int16_t si_addr_lsb; /* Valid LSB of the reported address. */ - union { - /* used when si_code=SEGV_BNDERR */ - struct { - lldb::addr_t _lower; - lldb::addr_t _upper; - } _addr_bnd; - /* used when si_code=SEGV_PKUERR */ - uint32_t _pkey; - } bounds; - - // We need this for all the generic signals. - struct { - uint32_t _pid; /* sender's pid */ - uint32_t _uid; /* sender's uid */ - } _kill; - } sigfault; + union alignas(8) { + struct alignas(8) { + uint32_t pid; /* sender's pid */ + uint32_t uid; /* sender's uid */ + } kill; + // Copied from siginfo_t so we don't have to include signal.h on non 'Nix + // builds. Slight modifications to ensure no 32b vs 64b differences. + struct alignas(8) { + lldb::addr_t si_addr; /* faulting insn/memory ref. */ + int16_t si_addr_lsb; /* Valid LSB of the reported address. */ + union { + /* used when si_code=SEGV_BNDERR */ + struct { + lldb::addr_t _lower; + lldb::addr_t _upper; + } _addr_bnd; + /* used when si_code=SEGV_PKUERR */ + uint32_t _pkey; + } bounds; + + // We need this for all the generic signals. + } sigfault; + } sifields; enum SigInfoNoteType : uint8_t { eUnspecified, eNT_SIGINFO }; SigInfoNoteType note_type; >From 9e352e71666628c7e81f520e8619779cc7a6e150 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Thu, 15 May 2025 14:46:40 -0700 Subject: [PATCH 3/4] Add test for sender case --- lldb/unittests/Signals/UnixSignalsTest.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lldb/unittests/Signals/UnixSignalsTest.cpp b/lldb/unittests/Signals/UnixSignalsTest.cpp index 9a7d9afc2b185..825cc5ea6a782 100644 --- a/lldb/unittests/Signals/UnixSignalsTest.cpp +++ b/lldb/unittests/Signals/UnixSignalsTest.cpp @@ -27,6 +27,7 @@ class TestSignals : public UnixSignals { AddSignalCode(16, 2, "SIG16 with a fault address", SignalCodePrintOption::Address); AddSignalCode(16, 3, "bounds violation", SignalCodePrintOption::Bounds); + AddSignalCode(16, -6, "sent by tkill system call", SignalCodePrintOption::Sender); } }; @@ -124,6 +125,10 @@ TEST(UnixSignalsTest, GetAsString) { // No address given just print the code description. ASSERT_EQ("SIG16: SIG16 with a fault address", signals.GetSignalDescription(16, 2)); + // TKill, but with no sender + ASSERT_EQ("SIG16: sent by tkill system call", signals.GetSignalDescription(16, -6, 0xCAFEF00D)); + // TKill, but with no sender + ASSERT_EQ("SIG16: sent by tkill system call (sender pid=912, uid=99)", signals.GetSignalDescription(16, -6, 0xCAFEF00D, std::nullopt, std::nullopt, 912, 99)); const char *expected = "SIG16: bounds violation"; // Must pass all needed info to get full output. >From 1a1b9fa48bead59a15291a58814e363cd4412f55 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Thu, 15 May 2025 15:03:32 -0700 Subject: [PATCH 4/4] run GCF --- .../Plugins/Process/Utility/LinuxSignals.cpp | 31 +++++++++++++------ .../Process/elf-core/ThreadElfCore.cpp | 17 +++++----- .../Plugins/Process/elf-core/ThreadElfCore.h | 4 +-- lldb/source/Target/UnixSignals.cpp | 12 +++---- lldb/unittests/Signals/UnixSignalsTest.cpp | 10 ++++-- 5 files changed, 45 insertions(+), 29 deletions(-) diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index da0abf5a1f471..76c32e376eb4b 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -39,16 +39,27 @@ AddSignalCode(signal_value, code_value, __VA_ARGS__) #endif /* if defined(__linux__) && !defined(__mips__) */ // See siginfo.h in the Linux Kernel, these codes can be sent for any signal. -#define ADD_LINUX_SIGNAL(signo, name, ...) \ - AddSignal(signo, name, __VA_ARGS__); \ - ADD_SIGCODE(signo, signo, SI_QUEUE, -1, "sent by sigqueue", SignalCodePrintOption::Sender); \ - ADD_SIGCODE(signo, signo, SI_TIMER, -2, "sent by timer expiration", SignalCodePrintOption::Sender); \ - ADD_SIGCODE(signo, signo, SI_MESGQ, -3, "sent by real time mesq state change", SignalCodePrintOption::Sender); \ - ADD_SIGCODE(signo, signo, SI_ASYNCIO, -4, "sent by AIO completion", SignalCodePrintOption::Sender); \ - ADD_SIGCODE(signo, signo, SI_SIGIO, -5, "sent by queued SIGIO", SignalCodePrintOption::Sender); \ - ADD_SIGCODE(signo, signo, SI_TKILL, -6, "sent by tkill system call", SignalCodePrintOption::Sender); \ - ADD_SIGCODE(signo, signo, SI_DETHREAD, -7, "sent by execve() killing subsidiary threads", SignalCodePrintOption::Sender); \ - ADD_SIGCODE(signo, signo, SI_ASYNCNL, -60, "sent by glibc async name lookup completion", SignalCodePrintOption::Sender); +#define ADD_LINUX_SIGNAL(signo, name, ...) \ + AddSignal(signo, name, __VA_ARGS__); \ + ADD_SIGCODE(signo, signo, SI_QUEUE, -1, "sent by sigqueue", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_TIMER, -2, "sent by timer expiration", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_MESGQ, -3, \ + "sent by real time mesq state change", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_ASYNCIO, -4, "sent by AIO completion", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_SIGIO, -5, "sent by queued SIGIO", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_TKILL, -6, "sent by tkill system call", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_DETHREAD, -7, \ + "sent by execve() killing subsidiary threads", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_ASYNCNL, -60, \ + "sent by glibc async name lookup completion", \ + SignalCodePrintOption::Sender); using namespace lldb_private; diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index ce0f65cd9f14c..907e009bc7b80 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -585,10 +585,10 @@ Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, if (data.GetAddressByteSize() == 8) offset += 4; - if (si_code < 0) { - sifields.kill.pid = data.GetU32(&offset); - sifields.kill.uid = data.GetU32(&offset); - } else if (unix_signals.GetShouldStop(si_signo)) { + if (si_code < 0) { + sifields.kill.pid = data.GetU32(&offset); + sifields.kill.uid = data.GetU32(&offset); + } else if (unix_signals.GetShouldStop(si_signo)) { // Not every stop signal has a valid address, but that will get resolved in // the unix_signals.GetSignalDescription() call below. // Instead of memcpy we call all these individually as the extractor will @@ -614,14 +614,17 @@ std::string ELFLinuxSigInfo::GetDescription( const lldb_private::UnixSignals &unix_signals) const { if (unix_signals.GetShouldStop(si_signo) && note_type == eNT_SIGINFO) { if (si_code < 0) - return unix_signals.GetSignalDescription(si_signo, si_code, std::nullopt, std::nullopt, std::nullopt, sifields.kill.pid, sifields.kill.uid); + return unix_signals.GetSignalDescription( + si_signo, si_code, std::nullopt, std::nullopt, std::nullopt, + sifields.kill.pid, sifields.kill.uid); else if (sifields.sigfault.bounds._addr_bnd._upper != 0) return unix_signals.GetSignalDescription( - si_signo, si_code, sifields.sigfault.si_addr, sifields.sigfault.bounds._addr_bnd._lower, + si_signo, si_code, sifields.sigfault.si_addr, + sifields.sigfault.bounds._addr_bnd._lower, sifields.sigfault.bounds._addr_bnd._upper); else return unix_signals.GetSignalDescription(si_signo, si_code, - sifields.sigfault.si_addr); + sifields.sigfault.si_addr); } // This looks weird, but there is an existing pattern where we don't pass a diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h index 2c254b4b522e9..40434543b7bb2 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -84,8 +84,8 @@ struct ELFLinuxSigInfo { int32_t si_code; union alignas(8) { struct alignas(8) { - uint32_t pid; /* sender's pid */ - uint32_t uid; /* sender's uid */ + uint32_t pid; /* sender's pid */ + uint32_t uid; /* sender's uid */ } kill; // Copied from siginfo_t so we don't have to include signal.h on non 'Nix // builds. Slight modifications to ensure no 32b vs 64b differences. diff --git a/lldb/source/Target/UnixSignals.cpp b/lldb/source/Target/UnixSignals.cpp index a5dbfd029410a..6113c6648817c 100644 --- a/lldb/source/Target/UnixSignals.cpp +++ b/lldb/source/Target/UnixSignals.cpp @@ -137,13 +137,11 @@ llvm::StringRef UnixSignals::GetSignalAsStringRef(int32_t signo) const { return pos->second.m_name; } -std::string -UnixSignals::GetSignalDescription(int32_t signo, std::optional code, - std::optional addr, - std::optional lower, - std::optional upper, - std::optional pid, - std::optional uid) const { +std::string UnixSignals::GetSignalDescription( + int32_t signo, std::optional code, + std::optional addr, std::optional lower, + std::optional upper, std::optional pid, + std::optional uid) const { std::string str; collection::const_iterator pos = m_signals.find(signo); diff --git a/lldb/unittests/Signals/UnixSignalsTest.cpp b/lldb/unittests/Signals/UnixSignalsTest.cpp index 825cc5ea6a782..582e441556067 100644 --- a/lldb/unittests/Signals/UnixSignalsTest.cpp +++ b/lldb/unittests/Signals/UnixSignalsTest.cpp @@ -27,7 +27,8 @@ class TestSignals : public UnixSignals { AddSignalCode(16, 2, "SIG16 with a fault address", SignalCodePrintOption::Address); AddSignalCode(16, 3, "bounds violation", SignalCodePrintOption::Bounds); - AddSignalCode(16, -6, "sent by tkill system call", SignalCodePrintOption::Sender); + AddSignalCode(16, -6, "sent by tkill system call", + SignalCodePrintOption::Sender); } }; @@ -126,9 +127,12 @@ TEST(UnixSignalsTest, GetAsString) { ASSERT_EQ("SIG16: SIG16 with a fault address", signals.GetSignalDescription(16, 2)); // TKill, but with no sender - ASSERT_EQ("SIG16: sent by tkill system call", signals.GetSignalDescription(16, -6, 0xCAFEF00D)); + ASSERT_EQ("SIG16: sent by tkill system call", + signals.GetSignalDescription(16, -6, 0xCAFEF00D)); // TKill, but with no sender - ASSERT_EQ("SIG16: sent by tkill system call (sender pid=912, uid=99)", signals.GetSignalDescription(16, -6, 0xCAFEF00D, std::nullopt, std::nullopt, 912, 99)); + ASSERT_EQ("SIG16: sent by tkill system call (sender pid=912, uid=99)", + signals.GetSignalDescription(16, -6, 0xCAFEF00D, std::nullopt, + std::nullopt, 912, 99)); const char *expected = "SIG16: bounds violation"; // Must pass all needed info to get full output. From lldb-commits at lists.llvm.org Thu May 15 15:05:04 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 15:05:04 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Support all the Generic (Negative) SI Codes. (PR #140150) In-Reply-To: Message-ID: <68266510.170a0220.bf65a.2e51@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Jacob Lalonde (Jlalond)
Changes Recently, I was on an issue that generated a large number of Coredumps, and every time in both LLDB and GDB the signal was just `SIGSEGV`. This was frustrating because we would expect a `SIGSEGV` to have an address, or ideally even bounds. After some digging I found the `si_code` consistently was -6. With some help from [@cdown](https://github.com/cdown), we found neither LLDB or GDB supports the si_codes sent from [user space](https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/siginfo.h#L185). Excerpted from the sigaction man page. ``` For a regular signal, the following list shows the values which can be placed in si_code for any signal, along with the reason that the signal was generated. ``` For which I added all of the si_codes to every Linux signal. Now for the Coredump that triggered this whole investigation we get the accurate and now very informative summary. <img width="524" alt="image" src="https://github.com/user-attachments/assets/5149f781-ef21-4491-a077-8fac862fbc20" /> Importantly, I didn't add an equivalent of `siginfo_t` to ELFSigInfo, and I think we should open an issue for this to make a (build) platform agnostic struct of siginfo_t. I'll defer to your expertise @labath and @DavidSpickett --- Patch is 24.96 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/140150.diff 6 Files Affected: - (modified) lldb/include/lldb/Target/UnixSignals.h (+4-2) - (modified) lldb/source/Plugins/Process/Utility/LinuxSignals.cpp (+88-66) - (modified) lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp (+25-16) - (modified) lldb/source/Plugins/Process/elf-core/ThreadElfCore.h (+23-15) - (modified) lldb/source/Target/UnixSignals.cpp (+9-6) - (modified) lldb/unittests/Signals/UnixSignalsTest.cpp (+9) ``````````diff diff --git a/lldb/include/lldb/Target/UnixSignals.h b/lldb/include/lldb/Target/UnixSignals.h index b3605ccefddbe..a1807d69f329b 100644 --- a/lldb/include/lldb/Target/UnixSignals.h +++ b/lldb/include/lldb/Target/UnixSignals.h @@ -36,7 +36,9 @@ class UnixSignals { std::optional code = std::nullopt, std::optional addr = std::nullopt, std::optional lower = std::nullopt, - std::optional upper = std::nullopt) const; + std::optional upper = std::nullopt, + std::optional pid = std::nullopt, + std::optional uid = std::nullopt) const; bool SignalIsValid(int32_t signo) const; @@ -105,7 +107,7 @@ class UnixSignals { llvm::StringRef description, llvm::StringRef alias = llvm::StringRef()); - enum SignalCodePrintOption { None, Address, Bounds }; + enum SignalCodePrintOption { None, Address, Bounds, Sender }; // Instead of calling this directly, use a ADD_SIGCODE macro to get compile // time checks when on the native platform. diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index 9c4fe55147a28..76c32e376eb4b 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -38,6 +38,28 @@ #define ADD_SIGCODE(signal_name, signal_value, code_name, code_value, ...) \ AddSignalCode(signal_value, code_value, __VA_ARGS__) #endif /* if defined(__linux__) && !defined(__mips__) */ +// See siginfo.h in the Linux Kernel, these codes can be sent for any signal. +#define ADD_LINUX_SIGNAL(signo, name, ...) \ + AddSignal(signo, name, __VA_ARGS__); \ + ADD_SIGCODE(signo, signo, SI_QUEUE, -1, "sent by sigqueue", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_TIMER, -2, "sent by timer expiration", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_MESGQ, -3, \ + "sent by real time mesq state change", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_ASYNCIO, -4, "sent by AIO completion", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_SIGIO, -5, "sent by queued SIGIO", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_TKILL, -6, "sent by tkill system call", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_DETHREAD, -7, \ + "sent by execve() killing subsidiary threads", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_ASYNCNL, -60, \ + "sent by glibc async name lookup completion", \ + SignalCodePrintOption::Sender); using namespace lldb_private; @@ -46,13 +68,13 @@ LinuxSignals::LinuxSignals() : UnixSignals() { Reset(); } void LinuxSignals::Reset() { m_signals.clear(); // clang-format off - // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION - // ====== ============== ======== ====== ====== =================================================== - AddSignal(1, "SIGHUP", false, true, true, "hangup"); - AddSignal(2, "SIGINT", true, true, true, "interrupt"); - AddSignal(3, "SIGQUIT", false, true, true, "quit"); + // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION + // ====== ============== ======== ====== ====== =================================================== + ADD_LINUX_SIGNAL(1, "SIGHUP", false, true, true, "hangup"); + ADD_LINUX_SIGNAL(2, "SIGINT", true, true, true, "interrupt"); + ADD_LINUX_SIGNAL(3, "SIGQUIT", false, true, true, "quit"); - AddSignal(4, "SIGILL", false, true, true, "illegal instruction"); + ADD_LINUX_SIGNAL(4, "SIGILL", false, true, true, "illegal instruction"); ADD_SIGCODE(SIGILL, 4, ILL_ILLOPC, 1, "illegal opcode"); ADD_SIGCODE(SIGILL, 4, ILL_ILLOPN, 2, "illegal operand"); ADD_SIGCODE(SIGILL, 4, ILL_ILLADR, 3, "illegal addressing mode"); @@ -62,15 +84,15 @@ void LinuxSignals::Reset() { ADD_SIGCODE(SIGILL, 4, ILL_COPROC, 7, "coprocessor error"); ADD_SIGCODE(SIGILL, 4, ILL_BADSTK, 8, "internal stack error"); - AddSignal(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)"); - AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT"); + ADD_LINUX_SIGNAL(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)"); + ADD_LINUX_SIGNAL(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT"); - AddSignal(7, "SIGBUS", false, true, true, "bus error"); + ADD_LINUX_SIGNAL(7, "SIGBUS", false, true, true, "bus error"); ADD_SIGCODE(SIGBUS, 7, BUS_ADRALN, 1, "illegal alignment"); ADD_SIGCODE(SIGBUS, 7, BUS_ADRERR, 2, "illegal address"); ADD_SIGCODE(SIGBUS, 7, BUS_OBJERR, 3, "hardware error"); - AddSignal(8, "SIGFPE", false, true, true, "floating point exception"); + ADD_LINUX_SIGNAL(8, "SIGFPE", false, true, true, "floating point exception"); ADD_SIGCODE(SIGFPE, 8, FPE_INTDIV, 1, "integer divide by zero"); ADD_SIGCODE(SIGFPE, 8, FPE_INTOVF, 2, "integer overflow"); ADD_SIGCODE(SIGFPE, 8, FPE_FLTDIV, 3, "floating point divide by zero"); @@ -80,10 +102,10 @@ void LinuxSignals::Reset() { ADD_SIGCODE(SIGFPE, 8, FPE_FLTINV, 7, "floating point invalid operation"); ADD_SIGCODE(SIGFPE, 8, FPE_FLTSUB, 8, "subscript out of range"); - AddSignal(9, "SIGKILL", false, true, true, "kill"); - AddSignal(10, "SIGUSR1", false, true, true, "user defined signal 1"); + ADD_LINUX_SIGNAL(9, "SIGKILL", false, true, true, "kill"); + ADD_LINUX_SIGNAL(10, "SIGUSR1", false, true, true, "user defined signal 1"); - AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation"); + ADD_LINUX_SIGNAL(11, "SIGSEGV", false, true, true, "segmentation violation"); ADD_SIGCODE(SIGSEGV, 11, SEGV_MAPERR, 1, "address not mapped to object", SignalCodePrintOption::Address); ADD_SIGCODE(SIGSEGV, 11, SEGV_ACCERR, 2, "invalid permissions for mapped object", SignalCodePrintOption::Address); ADD_SIGCODE(SIGSEGV, 11, SEGV_BNDERR, 3, "failed address bounds checks", SignalCodePrintOption::Bounds); @@ -94,58 +116,58 @@ void LinuxSignals::Reset() { // codes. One way to get this is via unaligned SIMD loads. Treat it as invalid address. ADD_SIGCODE(SIGSEGV, 11, SI_KERNEL, 0x80, "invalid address", SignalCodePrintOption::Address); - AddSignal(12, "SIGUSR2", false, true, true, "user defined signal 2"); - AddSignal(13, "SIGPIPE", false, true, true, "write to pipe with reading end closed"); - AddSignal(14, "SIGALRM", false, false, false, "alarm"); - AddSignal(15, "SIGTERM", false, true, true, "termination requested"); - AddSignal(16, "SIGSTKFLT", false, true, true, "stack fault"); - AddSignal(17, "SIGCHLD", false, false, true, "child status has changed", "SIGCLD"); - AddSignal(18, "SIGCONT", false, false, true, "process continue"); - AddSignal(19, "SIGSTOP", true, true, true, "process stop"); - AddSignal(20, "SIGTSTP", false, true, true, "tty stop"); - AddSignal(21, "SIGTTIN", false, true, true, "background tty read"); - AddSignal(22, "SIGTTOU", false, true, true, "background tty write"); - AddSignal(23, "SIGURG", false, true, true, "urgent data on socket"); - AddSignal(24, "SIGXCPU", false, true, true, "CPU resource exceeded"); - AddSignal(25, "SIGXFSZ", false, true, true, "file size limit exceeded"); - AddSignal(26, "SIGVTALRM", false, true, true, "virtual time alarm"); - AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm"); - AddSignal(28, "SIGWINCH", false, true, true, "window size changes"); - AddSignal(29, "SIGIO", false, true, true, "input/output ready/Pollable event", "SIGPOLL"); - AddSignal(30, "SIGPWR", false, true, true, "power failure"); - AddSignal(31, "SIGSYS", false, true, true, "invalid system call"); - AddSignal(32, "SIG32", false, false, false, "threading library internal signal 1"); - AddSignal(33, "SIG33", false, false, false, "threading library internal signal 2"); - AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0"); - AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1"); - AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2"); - AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3"); - AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4"); - AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5"); - AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6"); - AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7"); - AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8"); - AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9"); - AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10"); - AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11"); - AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12"); - AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13"); - AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14"); - AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15"); - AddSignal(50, "SIGRTMAX-14", false, false, false, "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output - AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17"); - AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18"); - AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19"); - AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20"); - AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21"); - AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22"); - AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23"); - AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24"); - AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25"); - AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26"); - AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27"); - AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28"); - AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29"); - AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30"); + ADD_LINUX_SIGNAL(12, "SIGUSR2", false, true, true, "user defined signal 2"); + ADD_LINUX_SIGNAL(13, "SIGPIPE", false, true, true, "write to pipe with reading end closed"); + ADD_LINUX_SIGNAL(14, "SIGALRM", false, false, false, "alarm"); + ADD_LINUX_SIGNAL(15, "SIGTERM", false, true, true, "termination requested"); + ADD_LINUX_SIGNAL(16, "SIGSTKFLT", false, true, true, "stack fault"); + ADD_LINUX_SIGNAL(17, "SIGCHLD", false, false, true, "child status has changed", "SIGCLD"); + ADD_LINUX_SIGNAL(18, "SIGCONT", false, false, true, "process continue"); + ADD_LINUX_SIGNAL(19, "SIGSTOP", true, true, true, "process stop"); + ADD_LINUX_SIGNAL(20, "SIGTSTP", false, true, true, "tty stop"); + ADD_LINUX_SIGNAL(21, "SIGTTIN", false, true, true, "background tty read"); + ADD_LINUX_SIGNAL(22, "SIGTTOU", false, true, true, "background tty write"); + ADD_LINUX_SIGNAL(23, "SIGURG", false, true, true, "urgent data on socket"); + ADD_LINUX_SIGNAL(24, "SIGXCPU", false, true, true, "CPU resource exceeded"); + ADD_LINUX_SIGNAL(25, "SIGXFSZ", false, true, true, "file size limit exceeded"); + ADD_LINUX_SIGNAL(26, "SIGVTALRM", false, true, true, "virtual time alarm"); + ADD_LINUX_SIGNAL(27, "SIGPROF", false, false, false, "profiling time alarm"); + ADD_LINUX_SIGNAL(28, "SIGWINCH", false, true, true, "window size changes"); + ADD_LINUX_SIGNAL(29, "SIGIO", false, true, true, "input/output ready/Pollable event", "SIGPOLL"); + ADD_LINUX_SIGNAL(30, "SIGPWR", false, true, true, "power failure"); + ADD_LINUX_SIGNAL(31, "SIGSYS", false, true, true, "invalid system call"); + ADD_LINUX_SIGNAL(32, "SIG32", false, false, false, "threading library internal signal 1"); + ADD_LINUX_SIGNAL(33, "SIG33", false, false, false, "threading library internal signal 2"); + ADD_LINUX_SIGNAL(34, "SIGRTMIN", false, false, false, "real time signal 0"); + ADD_LINUX_SIGNAL(35, "SIGRTMIN+1", false, false, false, "real time signal 1"); + ADD_LINUX_SIGNAL(36, "SIGRTMIN+2", false, false, false, "real time signal 2"); + ADD_LINUX_SIGNAL(37, "SIGRTMIN+3", false, false, false, "real time signal 3"); + ADD_LINUX_SIGNAL(38, "SIGRTMIN+4", false, false, false, "real time signal 4"); + ADD_LINUX_SIGNAL(39, "SIGRTMIN+5", false, false, false, "real time signal 5"); + ADD_LINUX_SIGNAL(40, "SIGRTMIN+6", false, false, false, "real time signal 6"); + ADD_LINUX_SIGNAL(41, "SIGRTMIN+7", false, false, false, "real time signal 7"); + ADD_LINUX_SIGNAL(42, "SIGRTMIN+8", false, false, false, "real time signal 8"); + ADD_LINUX_SIGNAL(43, "SIGRTMIN+9", false, false, false, "real time signal 9"); + ADD_LINUX_SIGNAL(44, "SIGRTMIN+10", false, false, false, "real time signal 10"); + ADD_LINUX_SIGNAL(45, "SIGRTMIN+11", false, false, false, "real time signal 11"); + ADD_LINUX_SIGNAL(46, "SIGRTMIN+12", false, false, false, "real time signal 12"); + ADD_LINUX_SIGNAL(47, "SIGRTMIN+13", false, false, false, "real time signal 13"); + ADD_LINUX_SIGNAL(48, "SIGRTMIN+14", false, false, false, "real time signal 14"); + ADD_LINUX_SIGNAL(49, "SIGRTMIN+15", false, false, false, "real time signal 15"); + ADD_LINUX_SIGNAL(50, "SIGRTMAX-14", false, false, false, "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output + ADD_LINUX_SIGNAL(51, "SIGRTMAX-13", false, false, false, "real time signal 17"); + ADD_LINUX_SIGNAL(52, "SIGRTMAX-12", false, false, false, "real time signal 18"); + ADD_LINUX_SIGNAL(53, "SIGRTMAX-11", false, false, false, "real time signal 19"); + ADD_LINUX_SIGNAL(54, "SIGRTMAX-10", false, false, false, "real time signal 20"); + ADD_LINUX_SIGNAL(55, "SIGRTMAX-9", false, false, false, "real time signal 21"); + ADD_LINUX_SIGNAL(56, "SIGRTMAX-8", false, false, false, "real time signal 22"); + ADD_LINUX_SIGNAL(57, "SIGRTMAX-7", false, false, false, "real time signal 23"); + ADD_LINUX_SIGNAL(58, "SIGRTMAX-6", false, false, false, "real time signal 24"); + ADD_LINUX_SIGNAL(59, "SIGRTMAX-5", false, false, false, "real time signal 25"); + ADD_LINUX_SIGNAL(60, "SIGRTMAX-4", false, false, false, "real time signal 26"); + ADD_LINUX_SIGNAL(61, "SIGRTMAX-3", false, false, false, "real time signal 27"); + ADD_LINUX_SIGNAL(62, "SIGRTMAX-2", false, false, false, "real time signal 28"); + ADD_LINUX_SIGNAL(63, "SIGRTMAX-1", false, false, false, "real time signal 29"); + ADD_LINUX_SIGNAL(64, "SIGRTMAX", false, false, false, "real time signal 30"); // clang-format on } diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index a0cd0ee5025bd..907e009bc7b80 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -584,22 +584,26 @@ Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, // 64b ELF have a 4 byte pad. if (data.GetAddressByteSize() == 8) offset += 4; - // Not every stop signal has a valid address, but that will get resolved in - // the unix_signals.GetSignalDescription() call below. - if (unix_signals.GetShouldStop(si_signo)) { + + if (si_code < 0) { + sifields.kill.pid = data.GetU32(&offset); + sifields.kill.uid = data.GetU32(&offset); + } else if (unix_signals.GetShouldStop(si_signo)) { + // Not every stop signal has a valid address, but that will get resolved in + // the unix_signals.GetSignalDescription() call below. // Instead of memcpy we call all these individually as the extractor will // handle endianness for us. - sigfault.si_addr = data.GetAddress(&offset); - sigfault.si_addr_lsb = data.GetU16(&offset); - if (data.GetByteSize() - offset >= sizeof(sigfault.bounds)) { - sigfault.bounds._addr_bnd._lower = data.GetAddress(&offset); - sigfault.bounds._addr_bnd._upper = data.GetAddress(&offset); - sigfault.bounds._pkey = data.GetU32(&offset); + sifields.sigfault.si_addr = data.GetAddress(&offset); + sifields.sigfault.si_addr_lsb = data.GetU16(&offset); + if (data.GetByteSize() - offset >= sizeof(sifields.sigfault.bounds)) { + sifields.sigfault.bounds._addr_bnd._lower = data.GetAddress(&offset); + sifields.sigfault.bounds._addr_bnd._upper = data.GetAddress(&offset); + sifields.sigfault.bounds._pkey = data.GetU32(&offset); } else { // Set these to 0 so we don't use bogus data for the description. - sigfault.bounds._addr_bnd._lower = 0; - sigfault.bounds._addr_bnd._upper = 0; - sigfault.bounds._pkey = 0; + sifields.sigfault.bounds._addr_bnd._lower = 0; + sifields.sigfault.bounds._addr_bnd._upper = 0; + sifields.sigfault.bounds._pkey = 0; } } @@ -609,13 +613,18 @@ Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, std::string ELFLinuxSigInfo::GetDescription( const lldb_private::UnixSignals &unix_signals) const { if (unix_signals.GetShouldStop(si_signo) && note_type == eNT_SIGINFO) { - if (sigfault.bounds._addr_bnd._upper != 0) + if (si_code < 0) + return unix_signals.GetSignalDescription( + si_signo, si_code, std::nullopt, std::nullopt, std::nullopt, + sifields.kill.pid, sifields.kill.uid); + else if (sifields.sigfault.bounds._addr_bnd._upper != 0) return unix_signals.GetSignalDescription( - si_signo, si_code, sigfault.si_addr, sigfault.bounds._addr_bnd._lower, - sigfault.bounds._addr_bnd._upper); + si_signo, si_code, sifields.sigfault.si_addr, + sifields.sigfault.bounds._addr_bnd._lower, + sifie... [truncated] ``````````
https://github.com/llvm/llvm-project/pull/140150 From lldb-commits at lists.llvm.org Thu May 15 15:10:08 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 15:10:08 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Support all the Generic (Negative) SI Codes. (PR #140150) In-Reply-To: Message-ID: <68266640.170a0220.34373.30a4@mx.google.com> ================ @@ -584,22 +584,26 @@ Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, // 64b ELF have a 4 byte pad. if (data.GetAddressByteSize() == 8) offset += 4; - // Not every stop signal has a valid address, but that will get resolved in - // the unix_signals.GetSignalDescription() call below. - if (unix_signals.GetShouldStop(si_signo)) { + + if (si_code < 0) { + sifields.kill.pid = data.GetU32(&offset); + sifields.kill.uid = data.GetU32(&offset); ---------------- youngd007 wrote: Are these populating to the same ints if the offset is the same into the data object/struct? https://github.com/llvm/llvm-project/pull/140150 From lldb-commits at lists.llvm.org Thu May 15 15:10:16 2025 From: lldb-commits at lists.llvm.org (Jacob Lalonde via lldb-commits) Date: Thu, 15 May 2025 15:10:16 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Support all the Generic (Negative) SI Codes. (PR #140150) In-Reply-To: Message-ID: <68266648.170a0220.4d423.655c@mx.google.com> https://github.com/Jlalond edited https://github.com/llvm/llvm-project/pull/140150 From lldb-commits at lists.llvm.org Thu May 15 15:11:07 2025 From: lldb-commits at lists.llvm.org (Jacob Lalonde via lldb-commits) Date: Thu, 15 May 2025 15:11:07 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Support all the Generic (Negative) SI Codes. (PR #140150) In-Reply-To: Message-ID: <6826667b.050a0220.16c125.3d33@mx.google.com> ================ @@ -584,22 +584,26 @@ Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, // 64b ELF have a 4 byte pad. if (data.GetAddressByteSize() == 8) offset += 4; - // Not every stop signal has a valid address, but that will get resolved in - // the unix_signals.GetSignalDescription() call below. - if (unix_signals.GetShouldStop(si_signo)) { + + if (si_code < 0) { + sifields.kill.pid = data.GetU32(&offset); + sifields.kill.uid = data.GetU32(&offset); ---------------- Jlalond wrote: No, the data extractor will increment the offset for each call, so the first call will take the first 0-4 bytes, and the second call the next 4-8 bytes. https://github.com/llvm/llvm-project/pull/140150 From lldb-commits at lists.llvm.org Thu May 15 15:34:32 2025 From: lldb-commits at lists.llvm.org (Adrian Prantl via lldb-commits) Date: Thu, 15 May 2025 15:34:32 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Reduce max-children-count default to readable size (PR #139826) In-Reply-To: Message-ID: <68266bf8.a70a0220.1f8fca.36c6@mx.google.com> https://github.com/adrian-prantl approved this pull request. As an 80x24 terminal user, I approve of this change :-) https://github.com/llvm/llvm-project/pull/139826 From lldb-commits at lists.llvm.org Thu May 15 15:39:50 2025 From: lldb-commits at lists.llvm.org (Jacob Lalonde via lldb-commits) Date: Thu, 15 May 2025 15:39:50 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB][ELF Core] Support all the Generic (Negative) SI Codes. (PR #140150) In-Reply-To: Message-ID: <68266d36.170a0220.43513.3e1b@mx.google.com> https://github.com/Jlalond edited https://github.com/llvm/llvm-project/pull/140150 From lldb-commits at lists.llvm.org Thu May 15 15:50:56 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Thu, 15 May 2025 15:50:56 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding additional asserts to unit tests. (PR #140107) In-Reply-To: Message-ID: <68266fd0.630a0220.3dc0e1.7cdf@mx.google.com> https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/140107 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Thu May 15 15:51:22 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Thu, 15 May 2025 15:51:22 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding additional asserts to unit tests. (PR #140107) In-Reply-To: Message-ID: <68266fea.170a0220.169c64.416d@mx.google.com> ================ @@ -263,46 +262,61 @@ def set_global(self, name, value, id=None): return self.dap_server.request_setVariable(2, name, str(value), id=id) def stepIn( - self, threadId=None, targetId=None, waitForStop=True, granularity="statement" + self, + threadId=None, + targetId=None, + waitForStop=True, + granularity="statement", + timeout=timeoutval, ): response = self.dap_server.request_stepIn( threadId=threadId, targetId=targetId, granularity=granularity ) self.assertTrue(response["success"]) if waitForStop: - return self.dap_server.wait_for_stopped() + return self.dap_server.wait_for_stopped(timeout) return None - def stepOver(self, threadId=None, waitForStop=True, granularity="statement"): + def stepOver( + self, + threadId=None, + waitForStop=True, + granularity="statement", + timeout=timeoutval, + ): self.dap_server.request_next(threadId=threadId, granularity=granularity) if waitForStop: - return self.dap_server.wait_for_stopped() + return self.dap_server.wait_for_stopped(timeout) return None - def stepOut(self, threadId=None, waitForStop=True): + def stepOut(self, threadId=None, waitForStop=True, timeout=timeoutval): self.dap_server.request_stepOut(threadId=threadId) if waitForStop: - return self.dap_server.wait_for_stopped() + return self.dap_server.wait_for_stopped(timeout) return None - def continue_to_next_stop(self): - self.dap_server.request_continue() - return self.dap_server.wait_for_stopped() + def verify_continue(self): ---------------- ashgti wrote: I went with `do_continue`. https://github.com/llvm/llvm-project/pull/140107 From lldb-commits at lists.llvm.org Thu May 15 15:51:29 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Thu, 15 May 2025 15:51:29 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding additional asserts to unit tests. (PR #140107) In-Reply-To: Message-ID: <68266ff1.170a0220.93c33.053d@mx.google.com> ================ @@ -16,8 +16,10 @@ def spawn_and_wait(program, delay): + print("spawn_and_wait started...", time.time()) ---------------- ashgti wrote: Removed the extra prints. https://github.com/llvm/llvm-project/pull/140107 From lldb-commits at lists.llvm.org Thu May 15 15:53:19 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Thu, 15 May 2025 15:53:19 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding additional asserts to unit tests. (PR #140107) In-Reply-To: Message-ID: <6826705f.050a0220.1e4e74.3a70@mx.google.com> ================ @@ -67,7 +67,7 @@ def test_core_file_source_mapping_array(self): self.create_debug_adapter() source_map = [["/home/labath/test", current_dir]] - self.attach(exe_file, coreFile=core_file, sourceMap=source_map) + self.attach(program=exe_file, coreFile=core_file, sourceMap=source_map) ---------------- ashgti wrote: For `attach` and `launch`, I wanted them to require kwargs because they have so many arguments and almost all of them are optional. `launch` I only left `program` as a positional arg for the simplicity of `self.launch(program)` but the rest, I was using the syntax that requires kwargs. https://github.com/llvm/llvm-project/pull/140107 From lldb-commits at lists.llvm.org Thu May 15 15:55:37 2025 From: lldb-commits at lists.llvm.org (Jacob Lalonde via lldb-commits) Date: Thu, 15 May 2025 15:55:37 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB][ELF Core] Support all the Generic (Negative) SI Codes. (PR #140150) In-Reply-To: Message-ID: <682670e9.170a0220.f2b5d.311b@mx.google.com> ================ @@ -584,22 +584,26 @@ Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, // 64b ELF have a 4 byte pad. if (data.GetAddressByteSize() == 8) offset += 4; - // Not every stop signal has a valid address, but that will get resolved in - // the unix_signals.GetSignalDescription() call below. - if (unix_signals.GetShouldStop(si_signo)) { + + if (si_code < 0) { ---------------- Jlalond wrote: So this check is my primary concern with my own code. In the Linux source I linked they define user space as `<0`, and I followed suite here. I would ideally like to make this a static function on LinuxSignals, but wanted to get feedback on how we want to implement this. https://github.com/llvm/llvm-project/pull/140150 From lldb-commits at lists.llvm.org Thu May 15 15:56:22 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Thu, 15 May 2025 15:56:22 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding additional asserts to unit tests. (PR #140107) In-Reply-To: Message-ID: <68267116.170a0220.73329.2e64@mx.google.com> ================ @@ -487,115 +453,36 @@ def cleanup(): response = self.dap_server.request_launch( program, - args=args, - cwd=cwd, - env=env, stopOnEntry=stopOnEntry, - disableASLR=disableASLR, - disableSTDIO=disableSTDIO, - shellExpandArguments=shellExpandArguments, - trace=trace, - initCommands=initCommands, - preRunCommands=preRunCommands, - stopCommands=stopCommands, - exitCommands=exitCommands, - terminateCommands=terminateCommands, - sourcePath=sourcePath, - debuggerRoot=debuggerRoot, - launchCommands=launchCommands, - sourceMap=sourceMap, - runInTerminal=runInTerminal, - postRunCommands=postRunCommands, - enableAutoVariableSummaries=enableAutoVariableSummaries, - displayExtendedBacktrace=displayExtendedBacktrace, - enableSyntheticChildDebugging=enableSyntheticChildDebugging, - commandEscapePrefix=commandEscapePrefix, - customFrameFormat=customFrameFormat, - customThreadFormat=customThreadFormat, + **kwargs, ) if expectFailure: return response - if not (response and response["success"]): self.assertTrue( response["success"], "launch failed (%s)" % (response["body"]["error"]["format"]), ) + if stopOnEntry: + self.dap_server.wait_for_stopped(timeout) + return response def build_and_launch( self, program, - args=None, - cwd=None, - env=None, - stopOnEntry=False, - disableASLR=False, - disableSTDIO=False, - shellExpandArguments=False, - trace=False, - initCommands=None, - preRunCommands=None, - stopCommands=None, - exitCommands=None, - terminateCommands=None, - sourcePath=None, - debuggerRoot=None, - sourceInitFile=False, - runInTerminal=False, - disconnectAutomatically=True, - postRunCommands=None, + /, ---------------- ashgti wrote: `/` is a separator to mark the end of the positional args. I switched it to `*` which means the remainder of the args are required to be kwargs. At a high level its: ``` def name(positional_only_parameters, /, positional_or_keyword_parameters, *, keyword_only_parameters): ``` I was trying to DRY up the definitions by using kwargs to forward to the dap_server.py method. https://github.com/llvm/llvm-project/pull/140107 From lldb-commits at lists.llvm.org Thu May 15 15:56:41 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Thu, 15 May 2025 15:56:41 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding additional asserts to unit tests. (PR #140107) In-Reply-To: Message-ID: <68267129.050a0220.179076.0110@mx.google.com> https://github.com/ashgti edited https://github.com/llvm/llvm-project/pull/140107 From lldb-commits at lists.llvm.org Thu May 15 15:57:09 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Thu, 15 May 2025 15:57:09 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding additional asserts to unit tests. (PR #140107) In-Reply-To: Message-ID: <68267145.170a0220.106673.2f94@mx.google.com> ================ @@ -78,13 +78,13 @@ def waitUntil(self, condition_callback): time.sleep(0.5) return False - def verify_breakpoint_hit(self, breakpoint_ids): + def verify_breakpoint_hit(self, breakpoint_ids, timeout=timeoutval): ---------------- ashgti wrote: Done. https://github.com/llvm/llvm-project/pull/140107 From lldb-commits at lists.llvm.org Thu May 15 16:46:05 2025 From: lldb-commits at lists.llvm.org (Jacob Lalonde via lldb-commits) Date: Thu, 15 May 2025 16:46:05 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB][Progress-On-Dap] Have indeterminate progress actually send events. (PR #140162) In-Reply-To: Message-ID: <68267cbd.170a0220.f2b5d.326b@mx.google.com> https://github.com/Jlalond updated https://github.com/llvm/llvm-project/pull/140162 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Thu May 15 16:46:48 2025 From: lldb-commits at lists.llvm.org (Jacob Lalonde via lldb-commits) Date: Thu, 15 May 2025 16:46:48 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB][Progress-On-Dap] Have indeterminate progress actually send events. (PR #140162) In-Reply-To: Message-ID: <68267ce8.170a0220.229eae.7066@mx.google.com> https://github.com/Jlalond updated https://github.com/llvm/llvm-project/pull/140162 >From 0673dc530a91cb2dd1bdd60dd5136d64e4ed48e8 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Thu, 15 May 2025 16:37:06 -0700 Subject: [PATCH 1/2] Have interderminate events actually broadcast to dap --- .../API/tools/lldb-dap/progress/TestDAP_Progress.py | 2 +- lldb/tools/lldb-dap/ProgressEvent.cpp | 11 +++++++---- lldb/tools/lldb-dap/ProgressEvent.h | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py b/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py index fee63655de0da..c87d2afe36821 100755 --- a/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py +++ b/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py @@ -81,7 +81,7 @@ def test(self): self.verify_progress_events( expected_title="Progress tester: Initial Indeterminate Detail", - expected_message="Step 1", + expected_message="Step 2", only_verify_first_update=True, ) diff --git a/lldb/tools/lldb-dap/ProgressEvent.cpp b/lldb/tools/lldb-dap/ProgressEvent.cpp index 6a4978c055e51..b6b62efb5f33c 100644 --- a/lldb/tools/lldb-dap/ProgressEvent.cpp +++ b/lldb/tools/lldb-dap/ProgressEvent.cpp @@ -77,16 +77,19 @@ ProgressEvent::Create(uint64_t progress_id, std::optional message, if (event.GetEventType() == progressStart && event.GetEventName().empty()) return std::nullopt; - if (prev_event && prev_event->EqualsForIDE(event)) + if (prev_event && prev_event->EqualsForIDE(event, total)) return std::nullopt; return event; } -bool ProgressEvent::EqualsForIDE(const ProgressEvent &other) const { +bool ProgressEvent::EqualsForIDE(const ProgressEvent &other, uint64_t total) const { return m_progress_id == other.m_progress_id && - m_event_type == other.m_event_type && - m_percentage == other.m_percentage; + m_event_type == other.m_event_type && + // If we check the percentage of a non-deterministic event + // we will basically never send the event, because N+1/Uint64_max + // will always be an infinitesimally small change. + (total != UINT64_MAX && m_percentage == other.m_percentage); } ProgressEventType ProgressEvent::GetEventType() const { return m_event_type; } diff --git a/lldb/tools/lldb-dap/ProgressEvent.h b/lldb/tools/lldb-dap/ProgressEvent.h index d1b9b9dd887cd..ab3487c1dbc3d 100644 --- a/lldb/tools/lldb-dap/ProgressEvent.h +++ b/lldb/tools/lldb-dap/ProgressEvent.h @@ -54,7 +54,7 @@ class ProgressEvent { /// \return /// \b true if two event messages would result in the same event for the /// IDE, e.g. same rounded percentage. - bool EqualsForIDE(const ProgressEvent &other) const; + bool EqualsForIDE(const ProgressEvent &other, uint64_t total) const; llvm::StringRef GetEventName() const; >From ad616dcb2f492f0c56389d629adb8f17a750563d Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Thu, 15 May 2025 16:44:56 -0700 Subject: [PATCH 2/2] GCF --- lldb/tools/lldb-dap/ProgressEvent.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lldb/tools/lldb-dap/ProgressEvent.cpp b/lldb/tools/lldb-dap/ProgressEvent.cpp index b6b62efb5f33c..36ecb3a8cc095 100644 --- a/lldb/tools/lldb-dap/ProgressEvent.cpp +++ b/lldb/tools/lldb-dap/ProgressEvent.cpp @@ -83,9 +83,10 @@ ProgressEvent::Create(uint64_t progress_id, std::optional message, return event; } -bool ProgressEvent::EqualsForIDE(const ProgressEvent &other, uint64_t total) const { +bool ProgressEvent::EqualsForIDE(const ProgressEvent &other, + uint64_t total) const { return m_progress_id == other.m_progress_id && - m_event_type == other.m_event_type && + m_event_type == other.m_event_type && // If we check the percentage of a non-deterministic event // we will basically never send the event, because N+1/Uint64_max // will always be an infinitesimally small change. From lldb-commits at lists.llvm.org Thu May 15 17:12:06 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Thu, 15 May 2025 17:12:06 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB][Progress-On-Dap] Have indeterminate progress actually send events. (PR #140162) In-Reply-To: Message-ID: <682682d6.170a0220.3a3b51.6907@mx.google.com> ================ @@ -77,16 +77,19 @@ ProgressEvent::Create(uint64_t progress_id, std::optional message, if (event.GetEventType() == progressStart && event.GetEventName().empty()) return std::nullopt; - if (prev_event && prev_event->EqualsForIDE(event)) + if (prev_event && prev_event->EqualsForIDE(event, total)) return std::nullopt; return event; } -bool ProgressEvent::EqualsForIDE(const ProgressEvent &other) const { +bool ProgressEvent::EqualsForIDE(const ProgressEvent &other, uint64_t total) const { return m_progress_id == other.m_progress_id && - m_event_type == other.m_event_type && - m_percentage == other.m_percentage; + m_event_type == other.m_event_type && + // If we check the percentage of a non-deterministic event ---------------- ashgti wrote: Isn't `m_percentage` a nullopt when the `total` is UINT64_MAX? Or is there a logic issue in lines 35-65? https://github.com/llvm/llvm-project/pull/140162 From lldb-commits at lists.llvm.org Thu May 15 19:58:10 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Thu, 15 May 2025 19:58:10 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Listen for broadcast classes. (PR #140142) In-Reply-To: Message-ID: <6826a9c2.170a0220.12fdb2.3a58@mx.google.com> JDevlieghere wrote: Summarizing the problem to make sure I understand: with the new launch/attach flow, we set the breakpoints in the dummy target before the actual target is created. If the target is created through launch commands, we're calling SetTarget with the currently selected target. By that time, we've already missed events belong to the new target. With this PR, we mimic what the default event handler does, which is listen to all target events. I think the problem with this approach is that now we're going to be broadcasting events for targets that are not the focus of the current debug session (i.e. the selected target). It should be easy to verify this by running a script that creates a second target and seeing if we now broadcast the events. If my theory is correct, then we would have to filter events not belonging to the selected target. Interestingly, I was thinking about multi-target/multi-process support in DAP earlier this week. I had someone reach out to ask questions about this. I'll file an issue to track this, but we should keep that use case in mind as we design this. https://github.com/llvm/llvm-project/pull/140142 From lldb-commits at lists.llvm.org Thu May 15 21:46:46 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 21:46:46 -0700 (PDT) Subject: [Lldb-commits] [lldb] Extending LLDB to work on AIX (PR #102601) In-Reply-To: Message-ID: <6826c336.170a0220.262a3.5034@mx.google.com> https://github.com/ravindra-shinde2 updated https://github.com/llvm/llvm-project/pull/102601 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Thu May 15 21:49:55 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Thu, 15 May 2025 21:49:55 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Listen for broadcast classes. (PR #140142) In-Reply-To: Message-ID: <6826c3f3.630a0220.338d7.8088@mx.google.com> ashgti wrote: > Summarizing the problem to make sure I understand: with the new launch/attach flow, we set the breakpoints in the dummy target before the actual target is created. If the target is created through launch commands, we're calling SetTarget with the currently selected target after we're done running the launch commands. By that time, we may have already missed events belong to the new target. > > With this PR, we mimic what the default event handler does, which is listen to all target events. I think the problem with this approach is that now we're going to be broadcasting events for targets that are not the focus of the current debug session (i.e. the selected target). It should be easy to verify this by running a script that creates a second target and seeing if we now broadcast the events. If my theory is correct, then we would have to filter events not belonging to the selected target. I had thought about also including a check on the target to see if it was the `DAP.target`, but again during launch or attach commands we may not know which target we need to focus on yet. > Interestingly, I was thinking about multi-target/multi-process support in DAP earlier this week. I had someone reach out to ask questions about this. I'll file an issue to track this, but we should keep that use case in mind as we design this. We do support the `startDebugging` reverse request https://microsoft.github.io/debug-adapter-protocol/specification#Reverse_Requests_StartDebugging. I use this to attach to multiple processes when tests are running from some scripts that involve multiple processes. I use the script hook we have https://github.com/llvm/llvm-project/blob/680b3b742da02972bc0b5298b6f472d2b95ca90a/lldb/tools/lldb-dap/DAP.h#L135 to call this from a python script. With the lldb-dap server mode we can handle multiple DAP sessions from the same binary, or you can have lldb-dap launch one instance per debug session. The DAP doesn't really have a way to have multiple processes per debug session, but it does allow for multiple debug sessions in general. Compound launch configurations are one way to get this setup https://code.visualstudio.com/docs/debugtest/debugging-configuration#_compound-launch-configurations for example, you could have a server and a client in a compound launch configuration. https://github.com/llvm/llvm-project/pull/140142 From lldb-commits at lists.llvm.org Thu May 15 22:34:32 2025 From: lldb-commits at lists.llvm.org (Jason Molenda via lldb-commits) Date: Thu, 15 May 2025 22:34:32 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][NFC] Split RegisterContextUnwind::SavedLocationForRegister (PR #139817) In-Reply-To: Message-ID: <6826ce68.170a0220.34692e.3d4a@mx.google.com> https://github.com/jasonmolenda updated https://github.com/llvm/llvm-project/pull/139817 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Thu May 15 23:00:11 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Thu, 15 May 2025 23:00:11 -0700 (PDT) Subject: [Lldb-commits] [lldb] bcb1227 - [lldb][AIX] Adding NativeThreadAIX (#139537) Message-ID: <6826d46b.050a0220.21025e.4d47@mx.google.com> Author: Dhruv Srivastava Date: 2025-05-16T11:30:07+05:30 New Revision: bcb1227c3c1cc904fe6bc724b78c8c737234c709 URL: https://github.com/llvm/llvm-project/commit/bcb1227c3c1cc904fe6bc724b78c8c737234c709 DIFF: https://github.com/llvm/llvm-project/commit/bcb1227c3c1cc904fe6bc724b78c8c737234c709.diff LOG: [lldb][AIX] Adding NativeThreadAIX (#139537) This PR is in reference to porting LLDB on AIX. Link to discussions on llvm discourse and github: 1. https://discourse.llvm.org/t/port-lldb-to-ibm-aix/80640 2. https://github.com/llvm/llvm-project/issues/101657 The complete changes for porting are present in this draft PR: https://github.com/llvm/llvm-project/pull/102601 **Description:** Adding NativeThreadAIX base files, to be integrated with already merged NativeProcessAIX. Added: lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp lldb/source/Plugins/Process/AIX/NativeThreadAIX.h Modified: lldb/source/Plugins/Process/AIX/CMakeLists.txt Removed: ################################################################################ diff --git a/lldb/source/Plugins/Process/AIX/CMakeLists.txt b/lldb/source/Plugins/Process/AIX/CMakeLists.txt index 9a3c77bd2ffeb..911f30349ef52 100644 --- a/lldb/source/Plugins/Process/AIX/CMakeLists.txt +++ b/lldb/source/Plugins/Process/AIX/CMakeLists.txt @@ -1,5 +1,6 @@ add_lldb_library(lldbPluginProcessAIX NativeProcessAIX.cpp + NativeThreadAIX.cpp LINK_LIBS lldbCore diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp new file mode 100644 index 0000000000000..3bb608168ce30 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp @@ -0,0 +1,58 @@ +//===-- NativeThreadAIX.cpp ---------------------------------------------===// +// +// 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 "NativeThreadAIX.h" +#include "NativeProcessAIX.h" +#include "lldb/Utility/State.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; + +NativeThreadAIX::NativeThreadAIX(NativeProcessAIX &process, lldb::tid_t tid) + : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid) {} + +std::string NativeThreadAIX::GetName() { return ""; } + +lldb::StateType NativeThreadAIX::GetState() { return m_state; } + +bool NativeThreadAIX::GetStopReason(ThreadStopInfo &stop_info, + std::string &description) { + return false; +} + +Status NativeThreadAIX::SetWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags, bool hardware) { + return Status("Unable to Set hardware watchpoint."); +} + +Status NativeThreadAIX::RemoveWatchpoint(lldb::addr_t addr) { + return Status("Clearing hardware watchpoint failed."); +} + +Status NativeThreadAIX::SetHardwareBreakpoint(lldb::addr_t addr, size_t size) { + return Status("Unable to set hardware breakpoint."); +} + +Status NativeThreadAIX::RemoveHardwareBreakpoint(lldb::addr_t addr) { + return Status("Clearing hardware breakpoint failed."); +} + +NativeProcessAIX &NativeThreadAIX::GetProcess() { + return static_cast(m_process); +} + +const NativeProcessAIX &NativeThreadAIX::GetProcess() const { + return static_cast(m_process); +} + +llvm::Expected> +NativeThreadAIX::GetSiginfo() const { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Not implemented"); +} diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h new file mode 100644 index 0000000000000..e32d3db2c5fa2 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h @@ -0,0 +1,53 @@ +//===-- NativeThreadAIX.h ----------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_NATIVETHREADAIX_H_ +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_NATIVETHREADAIX_H_ + +#include "lldb/Host/common/NativeThreadProtocol.h" + +namespace lldb_private::process_aix { + +class NativeProcessAIX; + +class NativeThreadAIX : public NativeThreadProtocol { + friend class NativeProcessAIX; + +public: + NativeThreadAIX(NativeProcessAIX &process, lldb::tid_t tid); + + // NativeThreadProtocol Interface + std::string GetName() override; + + lldb::StateType GetState() override; + + bool GetStopReason(ThreadStopInfo &stop_info, + std::string &description) override; + + Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, + bool hardware) override; + + Status RemoveWatchpoint(lldb::addr_t addr) override; + + Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override; + + Status RemoveHardwareBreakpoint(lldb::addr_t addr) override; + + NativeProcessAIX &GetProcess(); + + const NativeProcessAIX &GetProcess() const; + + llvm::Expected> + GetSiginfo() const override; + +private: + lldb::StateType m_state; +}; +} // namespace lldb_private::process_aix + +#endif // #ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_NATIVETHREADAIX_H_ From lldb-commits at lists.llvm.org Thu May 15 23:00:15 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Thu, 15 May 2025 23:00:15 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Adding NativeThreadAIX (PR #139537) In-Reply-To: Message-ID: <6826d46f.170a0220.12518c.40d0@mx.google.com> https://github.com/DhruvSrivastavaX closed https://github.com/llvm/llvm-project/pull/139537 From lldb-commits at lists.llvm.org Thu May 15 23:08:36 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Thu, 15 May 2025 23:08:36 -0700 (PDT) Subject: [Lldb-commits] [lldb] Extending LLDB to work on AIX (PR #102601) In-Reply-To: Message-ID: <6826d664.170a0220.beb3.4705@mx.google.com> https://github.com/DhruvSrivastavaX updated https://github.com/llvm/llvm-project/pull/102601 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Thu May 15 23:12:29 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Thu, 15 May 2025 23:12:29 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Listen for broadcast classes. (PR #140142) In-Reply-To: Message-ID: <6826d74d.170a0220.72c48.3fdd@mx.google.com> JDevlieghere wrote: > I had thought about also including a check on the target to see if it was the `DAP.target`, but again during launch or attach commands we may not know which target we need to focus on yet. Can we use the selected target until we've decided on the dap target? I guess that still leaves the possibility that the launch commands create multiple targets and that you temporarily see events belonging to the wrong target before another target was selected, but I'm not sure how to avoid that. Unless there's a way to queue up events? I'd need to look at the code in more detail to figure out how that works exactly (or ask @jimingham). https://github.com/llvm/llvm-project/pull/140142 From lldb-commits at lists.llvm.org Thu May 15 23:18:30 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Thu, 15 May 2025 23:18:30 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Listen for broadcast classes. (PR #140142) In-Reply-To: Message-ID: <6826d8b6.170a0220.1828c8.3eb4@mx.google.com> JDevlieghere wrote: > We do support the `startDebugging` reverse request https://microsoft.github.io/debug-adapter-protocol/specification#Reverse_Requests_StartDebugging. I use this to attach to multiple processes when tests are running from some scripts that involve multiple processes. I use the script hook we have > > https://github.com/llvm/llvm-project/blob/680b3b742da02972bc0b5298b6f472d2b95ca90a/lldb/tools/lldb-dap/DAP.h#L135 > > to call this from a python script. With the lldb-dap server mode we can handle multiple DAP sessions from the same binary, or you can have lldb-dap launch one instance per debug session. The DAP doesn't really have a way to have multiple processes per debug session, but it does allow for multiple debug sessions in general. Compound launch configurations are one way to get this setup https://code.visualstudio.com/docs/debugtest/debugging-configuration#_compound-launch-configurations for example, you could have a server and a client in a compound launch configuration. Cool, I knew we supported the request but I didn't know how that was hooked up. So it seems like this may be better supported than I thought. In that case we should definitely make sure we test that configuration and make sure it keeps working. https://github.com/llvm/llvm-project/pull/140142 From lldb-commits at lists.llvm.org Thu May 15 23:22:06 2025 From: lldb-commits at lists.llvm.org (Hemang Gadhavi via lldb-commits) Date: Thu, 15 May 2025 23:22:06 -0700 (PDT) Subject: [Lldb-commits] [lldb] Extending LLDB to work on AIX (PR #102601) In-Reply-To: Message-ID: <6826d98e.630a0220.37cc5.9459@mx.google.com> https://github.com/HemangGadhavi updated https://github.com/llvm/llvm-project/pull/102601 >From 39d395f75c306a0d932a783eef039fd93d66e246 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 7 Aug 2024 12:10:43 -0500 Subject: [PATCH 01/49] LLDB Support for AIX --- clang/lib/CodeGen/CGObjCMac.cpp | 6 +- lldb/CMakeLists.txt | 4 + lldb/cmake/modules/LLDBConfig.cmake | 2 +- lldb/include/lldb/Core/Module.h | 3 + lldb/include/lldb/Core/ModuleSpec.h | 23 +- lldb/include/lldb/Host/HostGetOpt.h | 2 +- lldb/include/lldb/Host/HostInfo.h | 3 + lldb/include/lldb/Host/HostInfoBase.h | 2 +- lldb/include/lldb/Host/XML.h | 5 + lldb/include/lldb/Host/aix/AbstractSocket.h | 25 + lldb/include/lldb/Host/aix/Host.h | 22 + lldb/include/lldb/Host/aix/HostInfoAIX.h | 42 + lldb/include/lldb/Host/aix/Ptrace.h | 62 + lldb/include/lldb/Host/aix/Support.h | 29 + lldb/include/lldb/Host/aix/Uio.h | 23 + lldb/include/lldb/Host/common/GetOptInc.h | 6 +- lldb/include/lldb/Symbol/ObjectFile.h | 5 + lldb/include/lldb/Target/ABI.h | 6 + lldb/include/lldb/Target/DynamicLoader.h | 6 + lldb/include/lldb/Target/Process.h | 14 + .../lldb/Target/RegisterContextUnwind.h | 4 + .../lldb/Target/ThreadPlanCallFunction.h | 6 + .../lldb/Utility/StringExtractorGDBRemote.h | 1 + lldb/include/lldb/lldb-private-enumerations.h | 1 + lldb/source/API/CMakeLists.txt | 108 + lldb/source/API/SBBreakpoint.cpp | 6 +- lldb/source/API/SBBreakpointLocation.cpp | 6 +- lldb/source/API/SBBreakpointName.cpp | 4 +- lldb/source/Core/DynamicLoader.cpp | 10 + lldb/source/Core/Mangled.cpp | 2 + lldb/source/Core/Module.cpp | 12 + lldb/source/Core/Section.cpp | 4 + lldb/source/Expression/DWARFExpression.cpp | 10 +- lldb/source/Host/CMakeLists.txt | 13 + lldb/source/Host/aix/AbstractSocket.cpp | 21 + lldb/source/Host/aix/Host.cpp | 304 +++ lldb/source/Host/aix/HostInfoAIX.cpp | 215 ++ lldb/source/Host/aix/Support.cpp | 44 + lldb/source/Host/common/GetOptInc.cpp | 2 +- lldb/source/Host/common/Host.cpp | 180 +- .../source/Host/common/LICENSE.aix-netbsd.txt | 125 + lldb/source/Host/common/XML.cpp | 3 + .../posix/ConnectionFileDescriptorPosix.cpp | 2 + lldb/source/Host/posix/FileSystemPosix.cpp | 2 + lldb/source/Host/posix/MainLoopPosix.cpp | 17 + .../Host/posix/ProcessLauncherPosixFork.cpp | 5 + lldb/source/Initialization/CMakeLists.txt | 2 +- .../SystemInitializerCommon.cpp | 4 +- .../Plugins/ABI/PowerPC/ABISysV_ppc64.cpp | 131 +- .../Plugins/ABI/PowerPC/ABISysV_ppc64.h | 6 + .../DynamicLoader/AIX-DYLD/CMakeLists.txt | 11 + .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 272 +++ .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 55 + .../Plugins/DynamicLoader/CMakeLists.txt | 1 + .../DynamicLoaderDarwinKernel.cpp | 4 +- .../MacOSX-DYLD/DynamicLoaderDarwin.cpp | 2 +- .../PPC64/EmulateInstructionPPC64.cpp | 196 +- .../PPC64/EmulateInstructionPPC64.h | 14 + ...nstrumentationRuntimeMainThreadChecker.cpp | 2 +- .../TSan/InstrumentationRuntimeTSan.cpp | 14 +- .../UBSan/InstrumentationRuntimeUBSan.cpp | 2 +- .../Plugins/JITLoader/GDB/JITLoaderGDB.cpp | 4 + lldb/source/Plugins/Language/ObjC/Cocoa.cpp | 2 + .../MemoryHistory/asan/MemoryHistoryASan.cpp | 2 +- .../BSD-Archive/ObjectContainerBSDArchive.cpp | 2 +- .../Big-Archive/CMakeLists.txt | 10 + .../Big-Archive/ObjectContainerBigArchive.cpp | 522 +++++ .../Big-Archive/ObjectContainerBigArchive.h | 177 ++ .../Plugins/ObjectContainer/CMakeLists.txt | 1 + lldb/source/Plugins/ObjectFile/CMakeLists.txt | 1 + .../ObjectFile/Mach-O/ObjectFileMachO.cpp | 6 +- .../Minidump/ObjectFileMinidump.cpp | 2 + .../Plugins/ObjectFile/PDB/ObjectFilePDB.cpp | 15 +- .../ObjectFile/PECOFF/ObjectFilePECOFF.cpp | 18 +- .../Plugins/ObjectFile/XCOFF/CMakeLists.txt | 13 + .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 780 +++++++ .../ObjectFile/XCOFF/ObjectFileXCOFF.h | 243 ++ .../Python/OperatingSystemPython.cpp | 2 +- .../Plugins/Platform/AIX/CMakeLists.txt | 13 + .../Plugins/Platform/AIX/PlatformAIX.cpp | 471 ++++ .../source/Plugins/Platform/AIX/PlatformAIX.h | 74 + lldb/source/Plugins/Platform/CMakeLists.txt | 1 + .../source/Plugins/Process/AIX/CMakeLists.txt | 19 + .../Plugins/Process/AIX/NativeProcessAIX.cpp | 2048 +++++++++++++++++ .../Plugins/Process/AIX/NativeProcessAIX.h | 283 +++ .../Process/AIX/NativeRegisterContextAIX.cpp | 157 ++ .../Process/AIX/NativeRegisterContextAIX.h | 133 ++ .../AIX/NativeRegisterContextAIX_ppc64.cpp | 744 ++++++ .../AIX/NativeRegisterContextAIX_ppc64.h | 138 ++ .../Plugins/Process/AIX/NativeThreadAIX.cpp | 526 +++++ .../Plugins/Process/AIX/NativeThreadAIX.h | 126 + lldb/source/Plugins/Process/CMakeLists.txt | 3 + .../Process/Utility/InferiorCallPOSIX.cpp | 33 + .../Utility/RegisterInfoPOSIX_ppc64le.cpp | 4 + .../Plugins/Process/Utility/ThreadMemory.cpp | 2 +- .../Plugins/Process/gdb-remote/CMakeLists.txt | 5 + .../GDBRemoteCommunicationClient.cpp | 30 + .../gdb-remote/GDBRemoteCommunicationClient.h | 7 + .../GDBRemoteCommunicationServerLLGS.cpp | 28 + .../GDBRemoteCommunicationServerLLGS.h | 2 + .../Process/gdb-remote/ProcessGDBRemote.cpp | 13 +- .../Process/gdb-remote/ProcessGDBRemote.h | 8 + .../Process/mach-core/ProcessMachCore.cpp | 8 +- .../ScriptInterpreter/Python/CMakeLists.txt | 5 + .../SymbolFile/DWARF/DWARFFormValue.cpp | 4 + .../Plugins/SymbolFile/DWARF/DWARFUnit.cpp | 12 +- .../MacOSX/AppleGetThreadItemInfoHandler.cpp | 2 +- lldb/source/Symbol/DWARFCallFrameInfo.cpp | 4 +- lldb/source/Target/ABI.cpp | 9 + lldb/source/Target/CMakeLists.txt | 5 + lldb/source/Target/Process.cpp | 10 + lldb/source/Target/RegisterContextUnwind.cpp | 46 + lldb/source/Target/ThreadPlanCallFunction.cpp | 34 + lldb/source/Target/UnwindLLDB.cpp | 15 + lldb/source/Utility/ArchSpec.cpp | 18 +- .../Utility/StringExtractorGDBRemote.cpp | 2 + lldb/test/CMakeLists.txt | 2 +- lldb/test/Shell/Expr/TestIRMemoryMap.test | 2 +- lldb/test/Shell/Process/TestEnvironment.test | 2 +- lldb/tools/driver/CMakeLists.txt | 5 + lldb/tools/driver/Driver.cpp | 5 +- lldb/tools/lldb-dap/CMakeLists.txt | 4 + lldb/tools/lldb-server/CMakeLists.txt | 7 + .../lldb-server/SystemInitializerLLGS.cpp | 15 + lldb/tools/lldb-server/lldb-gdbserver.cpp | 4 + lldb/unittests/Host/FileSystemTest.cpp | 2 +- lldb/unittests/Host/posix/TerminalTest.cpp | 4 + llvm/include/llvm/Object/XCOFFObjectFile.h | 4 +- llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 15 +- 129 files changed, 8950 insertions(+), 76 deletions(-) create mode 100644 lldb/include/lldb/Host/aix/AbstractSocket.h create mode 100644 lldb/include/lldb/Host/aix/Host.h create mode 100644 lldb/include/lldb/Host/aix/HostInfoAIX.h create mode 100644 lldb/include/lldb/Host/aix/Ptrace.h create mode 100644 lldb/include/lldb/Host/aix/Support.h create mode 100644 lldb/include/lldb/Host/aix/Uio.h create mode 100644 lldb/source/Host/aix/AbstractSocket.cpp create mode 100644 lldb/source/Host/aix/Host.cpp create mode 100644 lldb/source/Host/aix/HostInfoAIX.cpp create mode 100644 lldb/source/Host/aix/Support.cpp create mode 100644 lldb/source/Host/common/LICENSE.aix-netbsd.txt create mode 100644 lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt create mode 100644 lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp create mode 100644 lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h create mode 100644 lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt create mode 100644 lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp create mode 100644 lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h create mode 100644 lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt create mode 100644 lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp create mode 100644 lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h create mode 100644 lldb/source/Plugins/Platform/AIX/CMakeLists.txt create mode 100644 lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp create mode 100644 lldb/source/Plugins/Platform/AIX/PlatformAIX.h create mode 100644 lldb/source/Plugins/Process/AIX/CMakeLists.txt create mode 100644 lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeProcessAIX.h create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h create mode 100644 lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeThreadAIX.h diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index 30f3911a8b03c..fc91981db68c1 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -5052,10 +5052,14 @@ std::string CGObjCCommonMac::GetSectionName(StringRef Section, case llvm::Triple::COFF: assert(Section.starts_with("__") && "expected the name to begin with __"); return ("." + Section.substr(2) + "$B").str(); + case llvm::Triple::XCOFF: + // Hack to allow "p 10+1" on AIX for lldb + assert(Section.substr(0, 2) == "__" && + "expected the name to begin with __"); + return Section.substr(2).str(); case llvm::Triple::Wasm: case llvm::Triple::GOFF: case llvm::Triple::SPIRV: - case llvm::Triple::XCOFF: case llvm::Triple::DXContainer: llvm::report_fatal_error( "Objective-C support is unimplemented for object file format"); diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt index 59cdc4593463c..2e9ae0d0b3221 100644 --- a/lldb/CMakeLists.txt +++ b/lldb/CMakeLists.txt @@ -38,6 +38,10 @@ endif() include(LLDBConfig) include(AddLLDB) +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + add_definitions("-D__AIX__") +endif() + # Define the LLDB_CONFIGURATION_xxx matching the build type. if(uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" ) add_definitions(-DLLDB_CONFIGURATION_DEBUG) diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake index a60921990cf77..a0f118a11984c 100644 --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -299,7 +299,7 @@ endif() # Figure out if lldb could use lldb-server. If so, then we'll # ensure we build lldb-server when an lldb target is being built. -if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD|Windows") +if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD|Windows|AIX") set(LLDB_CAN_USE_LLDB_SERVER ON) else() set(LLDB_CAN_USE_LLDB_SERVER OFF) diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 5589c1c9a350d..3829386562795 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -196,6 +196,9 @@ class Module : public std::enable_shared_from_this, bool SetLoadAddress(Target &target, lldb::addr_t value, bool value_is_offset, bool &changed); + bool SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, bool &changed, int type_id); + /// \copydoc SymbolContextScope::CalculateSymbolContext(SymbolContext*) /// /// \see SymbolContextScope diff --git a/lldb/include/lldb/Core/ModuleSpec.h b/lldb/include/lldb/Core/ModuleSpec.h index 4cbbbfa8a26e1..4fe06412b6b0b 100644 --- a/lldb/include/lldb/Core/ModuleSpec.h +++ b/lldb/include/lldb/Core/ModuleSpec.h @@ -21,6 +21,7 @@ #include #include +#include namespace lldb_private { @@ -41,8 +42,26 @@ class ModuleSpec { } ModuleSpec(const FileSpec &file_spec, const ArchSpec &arch) - : m_file(file_spec), m_arch(arch), m_object_offset(0), - m_object_size(FileSystem::Instance().GetByteSize(file_spec)) {} + : m_arch(arch), m_object_offset(0) { + // parse object inside module format for example: /usr/ccs/lib/libc.a(shr_64.o) + llvm::SmallString<256> path_with_object; + file_spec.GetPath(path_with_object); + if (strstr(path_with_object.c_str(), "(") != nullptr) { + char *part; + char *str = (char *)path_with_object.c_str(); + part = strtok(str, "()"); + assert(part); + llvm::StringRef file_name(part); + part = strtok(nullptr, "()"); + assert(part); + m_object_name = ConstString(part); + m_file = FileSpec(file_name); + m_object_size = FileSystem::Instance().GetByteSize(m_file); + } else { + m_file = file_spec; + m_object_size = FileSystem::Instance().GetByteSize(file_spec); + } + } FileSpec *GetFileSpecPtr() { return (m_file ? &m_file : nullptr); } diff --git a/lldb/include/lldb/Host/HostGetOpt.h b/lldb/include/lldb/Host/HostGetOpt.h index 52cfdf4dbb89c..f450e561d6afb 100644 --- a/lldb/include/lldb/Host/HostGetOpt.h +++ b/lldb/include/lldb/Host/HostGetOpt.h @@ -9,7 +9,7 @@ #ifndef LLDB_HOST_HOSTGETOPT_H #define LLDB_HOST_HOSTGETOPT_H -#if !defined(_MSC_VER) && !defined(__NetBSD__) +#if !defined(_MSC_VER) && !defined(__NetBSD__) && !defined(__AIX__) #include #include diff --git a/lldb/include/lldb/Host/HostInfo.h b/lldb/include/lldb/Host/HostInfo.h index b7010d69d88e7..156df8cf6901d 100644 --- a/lldb/include/lldb/Host/HostInfo.h +++ b/lldb/include/lldb/Host/HostInfo.h @@ -55,6 +55,9 @@ #elif defined(__APPLE__) #include "lldb/Host/macosx/HostInfoMacOSX.h" #define HOST_INFO_TYPE HostInfoMacOSX +#elif defined(__AIX__) +#include "lldb/Host/aix/HostInfoAIX.h" +#define HOST_INFO_TYPE HostInfoAIX #else #include "lldb/Host/posix/HostInfoPosix.h" #define HOST_INFO_TYPE HostInfoPosix diff --git a/lldb/include/lldb/Host/HostInfoBase.h b/lldb/include/lldb/Host/HostInfoBase.h index 705aad559f3b7..29e6acf39bfb2 100644 --- a/lldb/include/lldb/Host/HostInfoBase.h +++ b/lldb/include/lldb/Host/HostInfoBase.h @@ -149,6 +149,7 @@ class HostInfoBase { return {}; } + static bool ComputeSharedLibraryDirectory(FileSpec &file_spec); /// Returns the distribution id of the host /// /// This will be something like "ubuntu", "fedora", etc. on Linux. @@ -158,7 +159,6 @@ class HostInfoBase { static llvm::StringRef GetDistributionId() { return llvm::StringRef(); } protected: - static bool ComputeSharedLibraryDirectory(FileSpec &file_spec); static bool ComputeSupportExeDirectory(FileSpec &file_spec); static bool ComputeProcessTempFileDirectory(FileSpec &file_spec); static bool ComputeGlobalTempFileDirectory(FileSpec &file_spec); diff --git a/lldb/include/lldb/Host/XML.h b/lldb/include/lldb/Host/XML.h index da0f9cd7aa8c0..cf359f7726d5d 100644 --- a/lldb/include/lldb/Host/XML.h +++ b/lldb/include/lldb/Host/XML.h @@ -11,6 +11,11 @@ #include "lldb/Host/Config.h" +#if defined(__AIX__) +//FIXME for AIX +#undef LLDB_ENABLE_LIBXML2 +#endif + #if LLDB_ENABLE_LIBXML2 #include #endif diff --git a/lldb/include/lldb/Host/aix/AbstractSocket.h b/lldb/include/lldb/Host/aix/AbstractSocket.h new file mode 100644 index 0000000000000..78a567a6b9095 --- /dev/null +++ b/lldb/include/lldb/Host/aix/AbstractSocket.h @@ -0,0 +1,25 @@ +//===-- AbstractSocket.h ----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_AbstractSocket_h_ +#define liblldb_AbstractSocket_h_ + +#include "lldb/Host/posix/DomainSocket.h" + +namespace lldb_private { +class AbstractSocket : public DomainSocket { +public: + AbstractSocket(bool child_processes_inherit); + +protected: + size_t GetNameOffset() const override; + void DeleteSocketFile(llvm::StringRef name) override; +}; +} + +#endif // ifndef liblldb_AbstractSocket_h_ diff --git a/lldb/include/lldb/Host/aix/Host.h b/lldb/include/lldb/Host/aix/Host.h new file mode 100644 index 0000000000000..1e3487752995f --- /dev/null +++ b/lldb/include/lldb/Host/aix/Host.h @@ -0,0 +1,22 @@ +//===-- Host.h --------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_HOST_AIX_HOST_H +#define LLDB_HOST_AIX_HOST_H + +#include "lldb/lldb-types.h" +#include + +namespace lldb_private { + +// Get PID (i.e. the primary thread ID) corresponding to the specified TID. +std::optional getPIDForTID(lldb::pid_t tid); + +} // namespace lldb_private + +#endif // #ifndef LLDB_HOST_AIX_HOST_H diff --git a/lldb/include/lldb/Host/aix/HostInfoAIX.h b/lldb/include/lldb/Host/aix/HostInfoAIX.h new file mode 100644 index 0000000000000..ced4cf34d38a8 --- /dev/null +++ b/lldb/include/lldb/Host/aix/HostInfoAIX.h @@ -0,0 +1,42 @@ +//===-- HostInfoAIX.h -----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_Host_aix_HostInfoAIX_h_ +#define lldb_Host_aix_HostInfoAIX_h_ + +#include "lldb/Host/posix/HostInfoPosix.h" +#include "lldb/Utility/FileSpec.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VersionTuple.h" + +#include + +namespace lldb_private { + +class HostInfoAIX : public HostInfoPosix { + friend class HostInfoBase; + +public: + static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr); + static void Terminate(); + + static llvm::VersionTuple GetOSVersion(); + static std::optional GetOSBuildString(); + static llvm::StringRef GetDistributionId(); + static FileSpec GetProgramFileSpec(); + +protected: + static bool ComputeSupportExeDirectory(FileSpec &file_spec); + static bool ComputeSystemPluginsDirectory(FileSpec &file_spec); + static bool ComputeUserPluginsDirectory(FileSpec &file_spec); + static void ComputeHostArchitectureSupport(ArchSpec &arch_32, + ArchSpec &arch_64); +}; +} + +#endif diff --git a/lldb/include/lldb/Host/aix/Ptrace.h b/lldb/include/lldb/Host/aix/Ptrace.h new file mode 100644 index 0000000000000..88928f18102d7 --- /dev/null +++ b/lldb/include/lldb/Host/aix/Ptrace.h @@ -0,0 +1,62 @@ +//===-- Ptrace.h ------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +// This file defines ptrace functions & structures + +#ifndef liblldb_Host_aix_Ptrace_h_ +#define liblldb_Host_aix_Ptrace_h_ + +#include + +#define DEBUG_PTRACE_MAXBYTES 20 + +// Support ptrace extensions even when compiled without required kernel support +#ifndef PTRACE_GETREGS +#define PTRACE_GETREGS (PT_COMMAND_MAX+1) +#endif +#ifndef PTRACE_SETREGS +#define PTRACE_SETREGS (PT_COMMAND_MAX+2) +#endif +#ifndef PTRACE_GETFPREGS +#define PTRACE_GETFPREGS (PT_COMMAND_MAX+3) +#endif +#ifndef PTRACE_SETFPREGS +#define PTRACE_SETFPREGS (PT_COMMAND_MAX+4) +#endif +#ifndef PTRACE_GETREGSET +#define PTRACE_GETREGSET 0x4204 +#endif +#ifndef PTRACE_SETREGSET +#define PTRACE_SETREGSET 0x4205 +#endif +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA (PT_COMMAND_MAX+5) +#endif +#ifndef PTRACE_ARCH_PRCTL +#define PTRACE_ARCH_PRCTL (PT_COMMAND_MAX+6) +#endif +#ifndef ARCH_GET_FS +#define ARCH_SET_GS 0x1001 +#define ARCH_SET_FS 0x1002 +#define ARCH_GET_FS 0x1003 +#define ARCH_GET_GS 0x1004 +#endif +#ifndef PTRACE_PEEKMTETAGS +#define PTRACE_PEEKMTETAGS (PT_COMMAND_MAX+7) +#endif +#ifndef PTRACE_POKEMTETAGS +#define PTRACE_POKEMTETAGS (PT_COMMAND_MAX+8) +#endif +#ifndef PTRACE_GETVRREGS +#define PTRACE_GETVRREGS (PT_COMMAND_MAX+9) +#endif +#ifndef PTRACE_GETVSRREGS +#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+10) +#endif + +#endif // liblldb_Host_aix_Ptrace_h_ diff --git a/lldb/include/lldb/Host/aix/Support.h b/lldb/include/lldb/Host/aix/Support.h new file mode 100644 index 0000000000000..27d6c2b50a35b --- /dev/null +++ b/lldb/include/lldb/Host/aix/Support.h @@ -0,0 +1,29 @@ +//===-- Support.h -----------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_HOST_AIX_SUPPORT_H +#define LLDB_HOST_AIX_SUPPORT_H + +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MemoryBuffer.h" +#include + +namespace lldb_private { + +llvm::ErrorOr> +getProcFile(::pid_t pid, ::pid_t tid, const llvm::Twine &file); + +llvm::ErrorOr> +getProcFile(::pid_t pid, const llvm::Twine &file); + +llvm::ErrorOr> +getProcFile(const llvm::Twine &file); + +} // namespace lldb_private + +#endif // #ifndef LLDB_HOST_AIX_SUPPORT_H diff --git a/lldb/include/lldb/Host/aix/Uio.h b/lldb/include/lldb/Host/aix/Uio.h new file mode 100644 index 0000000000000..acf79ecc6a1d0 --- /dev/null +++ b/lldb/include/lldb/Host/aix/Uio.h @@ -0,0 +1,23 @@ +//===-- Uio.h ---------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Host_aix_Uio_h_ +#define liblldb_Host_aix_Uio_h_ + +#include "lldb/Host/Config.h" +#include + +// We shall provide our own implementation of process_vm_readv if it is not +// present +#if !HAVE_PROCESS_VM_READV +ssize_t process_vm_readv(::pid_t pid, const struct iovec *local_iov, + unsigned long liovcnt, const struct iovec *remote_iov, + unsigned long riovcnt, unsigned long flags); +#endif + +#endif // liblldb_Host_aix_Uio_h_ diff --git a/lldb/include/lldb/Host/common/GetOptInc.h b/lldb/include/lldb/Host/common/GetOptInc.h index 3fb9add479541..ebb475bfaf6b8 100644 --- a/lldb/include/lldb/Host/common/GetOptInc.h +++ b/lldb/include/lldb/Host/common/GetOptInc.h @@ -11,11 +11,11 @@ #include "lldb/lldb-defines.h" -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__AIX__) #define REPLACE_GETOPT #define REPLACE_GETOPT_LONG #endif -#if defined(_MSC_VER) || defined(__NetBSD__) +#if defined(_MSC_VER) || defined(__NetBSD__) || defined(__AIX__) #define REPLACE_GETOPT_LONG_ONLY #endif @@ -35,7 +35,7 @@ struct option { int val; }; -int getopt(int argc, char *const argv[], const char *optstring); +int getopt(int argc, char *const argv[], const char *optstring) throw(); // from getopt.h extern char *optarg; diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h index 8592323322e38..bf66ccec263d2 100644 --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/lldb/include/lldb/Symbol/ObjectFile.h @@ -401,6 +401,11 @@ class ObjectFile : public std::enable_shared_from_this, return false; } + virtual bool SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) { + return false; + } + /// Gets whether endian swapping should occur when extracting data from this /// object file. /// diff --git a/lldb/include/lldb/Target/ABI.h b/lldb/include/lldb/Target/ABI.h index 7b646d743346b..281a89951ef88 100644 --- a/lldb/include/lldb/Target/ABI.h +++ b/lldb/include/lldb/Target/ABI.h @@ -47,6 +47,12 @@ class ABI : public PluginInterface { lldb::addr_t returnAddress, llvm::ArrayRef args) const = 0; + virtual bool PrepareTrivialCall(lldb_private::Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t tocAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef args) const; + // Prepare trivial call used from ThreadPlanFunctionCallUsingABI // AD: // . Because i don't want to change other ABI's this is not declared pure diff --git a/lldb/include/lldb/Target/DynamicLoader.h b/lldb/include/lldb/Target/DynamicLoader.h index 0629e2faae7e9..7dccd317c2dca 100644 --- a/lldb/include/lldb/Target/DynamicLoader.h +++ b/lldb/include/lldb/Target/DynamicLoader.h @@ -359,6 +359,12 @@ class DynamicLoader : public PluginInterface { lldb::addr_t base_addr, bool base_addr_is_offset); + virtual void UpdateLoadedSectionsByType(lldb::ModuleSP module, + lldb::addr_t link_map_addr, + lldb::addr_t base_addr, + bool base_addr_is_offset, + int type_id); + // Utility method so base classes can share implementation of // UpdateLoadedSections void UpdateLoadedSectionsCommon(lldb::ModuleSP module, lldb::addr_t base_addr, diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index cf16fbc812aa4..886ca766112c8 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -63,6 +63,10 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/VersionTuple.h" +#if defined(__AIX__) +struct ld_xinfo; +#endif + namespace lldb_private { template struct Range; @@ -1915,6 +1919,10 @@ class Process : public std::enable_shared_from_this, Status GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &range_info); +#if defined(__AIX__) + Status GetLDXINFO(struct ld_xinfo *info_ptr); +#endif + /// Obtain all the mapped memory regions within this process. /// /// \param[out] region_list @@ -2855,6 +2863,12 @@ void PruneThreadPlans(); return Status("Process::DoGetMemoryRegionInfo() not supported"); } +#if defined(__AIX__) + virtual Status DoGetLDXINFO(struct ld_xinfo *info_ptr) { + return Status("Process::DoGetLDXINFO() not supported"); + } +#endif + /// Provide an override value in the subclass for lldb's /// CPU-based logic for whether watchpoint exceptions are /// received before or after an instruction executes. diff --git a/lldb/include/lldb/Target/RegisterContextUnwind.h b/lldb/include/lldb/Target/RegisterContextUnwind.h index ef8ae88403866..00a95853800ed 100644 --- a/lldb/include/lldb/Target/RegisterContextUnwind.h +++ b/lldb/include/lldb/Target/RegisterContextUnwind.h @@ -67,6 +67,10 @@ class RegisterContextUnwind : public lldb_private::RegisterContext { bool ReadPC(lldb::addr_t &start_pc); +#ifdef __AIX__ + bool ReadLR(lldb::addr_t &lr); +#endif + // Indicates whether this frame *behaves* like frame zero -- the currently // executing frame -- or not. This can be true in the middle of the stack // above asynchronous trap handlers (sigtramp) for instance. diff --git a/lldb/include/lldb/Target/ThreadPlanCallFunction.h b/lldb/include/lldb/Target/ThreadPlanCallFunction.h index cb6e7caebb4ad..7880db1592e04 100644 --- a/lldb/include/lldb/Target/ThreadPlanCallFunction.h +++ b/lldb/include/lldb/Target/ThreadPlanCallFunction.h @@ -27,6 +27,12 @@ class ThreadPlanCallFunction : public ThreadPlan { llvm::ArrayRef args, const EvaluateExpressionOptions &options); + ThreadPlanCallFunction(Thread &thread, const Address &function, + const Address &toc, + const CompilerType &return_type, + llvm::ArrayRef args, + const EvaluateExpressionOptions &options); + ThreadPlanCallFunction(Thread &thread, const Address &function, const EvaluateExpressionOptions &options); diff --git a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h index dd468ef5bddef..9953bd6c24588 100644 --- a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h +++ b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h @@ -61,6 +61,7 @@ class StringExtractorGDBRemote : public StringExtractor { eServerPacketType_qQueryGDBServer, eServerPacketType_qKillSpawnedProcess, eServerPacketType_qLaunchSuccess, + eServerPacketType_qLDXINFO, eServerPacketType_qModuleInfo, eServerPacketType_qProcessInfoPID, eServerPacketType_qSpeedTest, diff --git a/lldb/include/lldb/lldb-private-enumerations.h b/lldb/include/lldb/lldb-private-enumerations.h index c24a3538f58da..98c1e956bf8f7 100644 --- a/lldb/include/lldb/lldb-private-enumerations.h +++ b/lldb/include/lldb/lldb-private-enumerations.h @@ -65,6 +65,7 @@ enum ArchitectureType { eArchTypeMachO, eArchTypeELF, eArchTypeCOFF, + eArchTypeXCOFF, kNumArchTypes }; diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index a32bc58507d8e..3ecdb11daef7d 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -40,6 +40,113 @@ add_custom_target(lldb-sbapi-dwarf-enums DEPENDS ${sb_languages_file}) set_target_properties(lldb-sbapi-dwarf-enums PROPERTIES FOLDER "LLDB/Tablegenning") +if(CMAKE_SYSTEM_NAME MATCHES "AIX") +add_lldb_library(liblldb STATIC ${option_framework} + SBAddress.cpp + SBAddressRange.cpp + SBAddressRangeList.cpp + SBAttachInfo.cpp + SBBlock.cpp + SBBreakpoint.cpp + SBBreakpointLocation.cpp + SBBreakpointName.cpp + SBBreakpointOptionCommon.cpp + SBBroadcaster.cpp + SBCommandInterpreter.cpp + SBCommandInterpreterRunOptions.cpp + SBCommandReturnObject.cpp + SBCommunication.cpp + SBCompileUnit.cpp + SBSaveCoreOptions.cpp + SBData.cpp + SBDebugger.cpp + SBDeclaration.cpp + SBEnvironment.cpp + SBError.cpp + SBEvent.cpp + SBExecutionContext.cpp + SBExpressionOptions.cpp + SBFileSpec.cpp + SBFile.cpp + SBFileSpecList.cpp + SBFormat.cpp + SBFrame.cpp + SBFunction.cpp + SBHostOS.cpp + SBInstruction.cpp + SBInstructionList.cpp + SBLanguageRuntime.cpp + SBLaunchInfo.cpp + SBLineEntry.cpp + SBListener.cpp + SBMemoryRegionInfo.cpp + SBMemoryRegionInfoList.cpp + SBModule.cpp + SBModuleSpec.cpp + SBPlatform.cpp + SBProcess.cpp + SBProcessInfo.cpp + SBProcessInfoList.cpp + SBQueue.cpp + SBQueueItem.cpp + SBReproducer.cpp + SBScriptObject.cpp + SBSection.cpp + SBSourceManager.cpp + SBStatisticsOptions.cpp + SBStream.cpp + SBStringList.cpp + SBStructuredData.cpp + SBSymbol.cpp + SBSymbolContext.cpp + SBSymbolContextList.cpp + SBTarget.cpp + SBThread.cpp + SBThreadCollection.cpp + SBThreadPlan.cpp + SBTrace.cpp + SBTraceCursor.cpp + SBType.cpp + SBTypeCategory.cpp + SBTypeEnumMember.cpp + SBTypeFilter.cpp + SBTypeFormat.cpp + SBTypeNameSpecifier.cpp + SBTypeSummary.cpp + SBTypeSynthetic.cpp + SBValue.cpp + SBValueList.cpp + SBVariablesOptions.cpp + SBWatchpoint.cpp + SBWatchpointOptions.cpp + SBUnixSignals.cpp + SystemInitializerFull.cpp + ${lldb_python_wrapper} + ${lldb_lua_wrapper} + + DEPENDS + lldb-sbapi-dwarf-enums + + LINK_LIBS + lldbBreakpoint + lldbCore + lldbDataFormatters + lldbExpression + lldbHost + lldbInitialization + lldbInterpreter + lldbSymbol + lldbTarget + lldbUtility + lldbVersion + ${LLDB_ALL_PLUGINS} + LINK_COMPONENTS + Support + + ${option_install_prefix} +) + +else() add_lldb_library(liblldb SHARED ${option_framework} SBAddress.cpp SBAddressRange.cpp @@ -144,6 +251,7 @@ add_lldb_library(liblldb SHARED ${option_framework} ${option_install_prefix} ) +endif() # lib/pythonX.Y/dist-packages/lldb/_lldb.so is a symlink to lib/liblldb.so, # which depends on lib/libLLVM*.so (BUILD_SHARED_LIBS) or lib/libLLVM-10git.so diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp index 3d908047f9455..728fe04d14d92 100644 --- a/lldb/source/API/SBBreakpoint.cpp +++ b/lldb/source/API/SBBreakpoint.cpp @@ -342,7 +342,7 @@ uint32_t SBBreakpoint::GetIgnoreCount() const { return count; } -void SBBreakpoint::SetThreadID(tid_t tid) { +void SBBreakpoint::SetThreadID(lldb::tid_t tid) { LLDB_INSTRUMENT_VA(this, tid); BreakpointSP bkpt_sp = GetSP(); @@ -353,10 +353,10 @@ void SBBreakpoint::SetThreadID(tid_t tid) { } } -tid_t SBBreakpoint::GetThreadID() { +lldb::tid_t SBBreakpoint::GetThreadID() { LLDB_INSTRUMENT_VA(this); - tid_t tid = LLDB_INVALID_THREAD_ID; + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; BreakpointSP bkpt_sp = GetSP(); if (bkpt_sp) { std::lock_guard guard( diff --git a/lldb/source/API/SBBreakpointLocation.cpp b/lldb/source/API/SBBreakpointLocation.cpp index 75b66364d4f1a..fad9a4076a54f 100644 --- a/lldb/source/API/SBBreakpointLocation.cpp +++ b/lldb/source/API/SBBreakpointLocation.cpp @@ -302,7 +302,7 @@ bool SBBreakpointLocation::GetCommandLineCommands(SBStringList &commands) { return has_commands; } -void SBBreakpointLocation::SetThreadID(tid_t thread_id) { +void SBBreakpointLocation::SetThreadID(lldb::tid_t thread_id) { LLDB_INSTRUMENT_VA(this, thread_id); BreakpointLocationSP loc_sp = GetSP(); @@ -313,10 +313,10 @@ void SBBreakpointLocation::SetThreadID(tid_t thread_id) { } } -tid_t SBBreakpointLocation::GetThreadID() { +lldb::tid_t SBBreakpointLocation::GetThreadID() { LLDB_INSTRUMENT_VA(this); - tid_t tid = LLDB_INVALID_THREAD_ID; + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; BreakpointLocationSP loc_sp = GetSP(); if (loc_sp) { std::lock_guard guard( diff --git a/lldb/source/API/SBBreakpointName.cpp b/lldb/source/API/SBBreakpointName.cpp index 7f63aaf6fa7d5..5c7c0a8f6504b 100644 --- a/lldb/source/API/SBBreakpointName.cpp +++ b/lldb/source/API/SBBreakpointName.cpp @@ -347,7 +347,7 @@ bool SBBreakpointName::GetAutoContinue() { return bp_name->GetOptions().IsAutoContinue(); } -void SBBreakpointName::SetThreadID(tid_t tid) { +void SBBreakpointName::SetThreadID(lldb::tid_t tid) { LLDB_INSTRUMENT_VA(this, tid); BreakpointName *bp_name = GetBreakpointName(); @@ -361,7 +361,7 @@ void SBBreakpointName::SetThreadID(tid_t tid) { UpdateName(*bp_name); } -tid_t SBBreakpointName::GetThreadID() { +lldb::tid_t SBBreakpointName::GetThreadID() { LLDB_INSTRUMENT_VA(this); BreakpointName *bp_name = GetBreakpointName(); diff --git a/lldb/source/Core/DynamicLoader.cpp b/lldb/source/Core/DynamicLoader.cpp index 7758a87403b5a..ea43a7f98b69f 100644 --- a/lldb/source/Core/DynamicLoader.cpp +++ b/lldb/source/Core/DynamicLoader.cpp @@ -113,6 +113,16 @@ void DynamicLoader::UpdateLoadedSections(ModuleSP module, addr_t link_map_addr, UpdateLoadedSectionsCommon(module, base_addr, base_addr_is_offset); } +void DynamicLoader::UpdateLoadedSectionsByType(lldb::ModuleSP module, + lldb::addr_t link_map_addr, + lldb::addr_t base_addr, + bool base_addr_is_offset, + int type_id) { + bool changed; + module->SetLoadAddressByType(m_process->GetTarget(), base_addr, base_addr_is_offset, + changed, type_id); +} + void DynamicLoader::UpdateLoadedSectionsCommon(ModuleSP module, addr_t base_addr, bool base_addr_is_offset) { diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp index 387c4fac6b0f8..43c5b043ef7a2 100644 --- a/lldb/source/Core/Mangled.cpp +++ b/lldb/source/Core/Mangled.cpp @@ -167,12 +167,14 @@ static char *GetItaniumDemangledStr(const char *M) { "Expected demangled_size to return length including trailing null"); } +#if !defined(__AIX__) if (Log *log = GetLog(LLDBLog::Demangle)) { if (demangled_cstr) LLDB_LOGF(log, "demangled itanium: %s -> \"%s\"", M, demangled_cstr); else LLDB_LOGF(log, "demangled itanium: %s -> error: failed to demangle", M); } +#endif return demangled_cstr; } diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index f9d7832254f46..044a5d29978e8 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -1510,6 +1510,18 @@ bool Module::SetLoadAddress(Target &target, lldb::addr_t value, return false; } +bool Module::SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, bool &changed, int type_id) { + ObjectFile *object_file = GetObjectFile(); + if (object_file != nullptr) { + changed = object_file->SetLoadAddressByType(target, value, value_is_offset, type_id); + return true; + } else { + changed = false; + } + return false; +} + bool Module::MatchesModuleSpec(const ModuleSpec &module_ref) { const UUID &uuid = module_ref.GetUUID(); diff --git a/lldb/source/Core/Section.cpp b/lldb/source/Core/Section.cpp index 0763e88d4608f..9ed55853930a6 100644 --- a/lldb/source/Core/Section.cpp +++ b/lldb/source/Core/Section.cpp @@ -263,6 +263,10 @@ bool Section::ResolveContainedAddress(addr_t offset, Address &so_addr, bool Section::ContainsFileAddress(addr_t vm_addr) const { const addr_t file_addr = GetFileAddress(); +#ifdef __AIX__ + if (file_addr == 0) + return false; +#endif if (file_addr != LLDB_INVALID_ADDRESS && !IsThreadSpecific()) { if (file_addr <= vm_addr) { const addr_t offset = (vm_addr - file_addr) * m_target_byte_size; diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index 444e44b392891..c1feec990f989 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -130,7 +130,7 @@ static llvm::Error ReadRegisterValueAsScalar(RegisterContext *reg_ctx, /// Return the length in bytes of the set of operands for \p op. No guarantees /// are made on the state of \p data after this call. -static offset_t GetOpcodeDataSize(const DataExtractor &data, +static lldb::offset_t GetOpcodeDataSize(const DataExtractor &data, const lldb::offset_t data_offset, const uint8_t op, const DWARFUnit *dwarf_cu) { lldb::offset_t offset = data_offset; @@ -358,7 +358,7 @@ lldb::addr_t DWARFExpression::GetLocation_DW_OP_addr(const DWARFUnit *dwarf_cu, error = true; break; } - const offset_t op_arg_size = + const lldb::offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op, dwarf_cu); if (op_arg_size == LLDB_INVALID_OFFSET) { error = true; @@ -418,7 +418,7 @@ bool DWARFExpression::Update_DW_OP_addr(const DWARFUnit *dwarf_cu, m_data.SetData(encoder.GetDataBuffer()); return true; } - const offset_t op_arg_size = + const lldb::offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op, dwarf_cu); if (op_arg_size == LLDB_INVALID_OFFSET) break; @@ -435,7 +435,7 @@ bool DWARFExpression::ContainsThreadLocalStorage( if (op == DW_OP_form_tls_address || op == DW_OP_GNU_push_tls_address) return true; - const offset_t op_arg_size = + const lldb::offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op, dwarf_cu); if (op_arg_size == LLDB_INVALID_OFFSET) return false; @@ -515,7 +515,7 @@ bool DWARFExpression::LinkThreadLocalStorage( } if (!decoded_data) { - const offset_t op_arg_size = + const lldb::offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op, dwarf_cu); if (op_arg_size == LLDB_INVALID_OFFSET) return false; diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index c2e091ee8555b..5374b16881950 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -7,6 +7,11 @@ if (APPLE AND LLVM_ENABLE_LOCAL_SUBMODULE_VISIBILITY) endif() endif() +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + macro(add_host_subdirectory group) list(APPEND HOST_SOURCES ${ARGN}) source_group(${group} FILES ${ARGN}) @@ -133,6 +138,14 @@ else() openbsd/Host.cpp openbsd/HostInfoOpenBSD.cpp ) + + elseif (CMAKE_SYSTEM_NAME MATCHES "AIX") + add_host_subdirectory(aix + aix/AbstractSocket.cpp + aix/Host.cpp + aix/HostInfoAIX.cpp + aix/Support.cpp + ) endif() endif() diff --git a/lldb/source/Host/aix/AbstractSocket.cpp b/lldb/source/Host/aix/AbstractSocket.cpp new file mode 100644 index 0000000000000..bfb67d452f7ec --- /dev/null +++ b/lldb/source/Host/aix/AbstractSocket.cpp @@ -0,0 +1,21 @@ +//===-- AbstractSocket.cpp ------------------------------------------------===// +// +// 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 "lldb/Host/aix/AbstractSocket.h" + +#include "llvm/ADT/StringRef.h" + +using namespace lldb; +using namespace lldb_private; + +AbstractSocket::AbstractSocket(bool child_processes_inherit) + : DomainSocket(ProtocolUnixAbstract, child_processes_inherit) {} + +size_t AbstractSocket::GetNameOffset() const { return 1; } + +void AbstractSocket::DeleteSocketFile(llvm::StringRef name) {} diff --git a/lldb/source/Host/aix/Host.cpp b/lldb/source/Host/aix/Host.cpp new file mode 100644 index 0000000000000..d82cb9049d389 --- /dev/null +++ b/lldb/source/Host/aix/Host.cpp @@ -0,0 +1,304 @@ +//===-- source/Host/aix/Host.cpp ----------------------------------------===// +// +// 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/ScopedPrinter.h" + +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/ProcessInfo.h" +#include "lldb/Utility/Status.h" + +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Host/aix/Host.h" +#include "lldb/Host/aix/Support.h" +#include "lldb/Utility/DataExtractor.h" +#include "llvm/BinaryFormat/XCOFF.h" + +#include +#include + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; + +namespace { +enum class ProcessState { + Unknown, + Dead, + DiskSleep, + Idle, + Paging, + Parked, + Running, + Sleeping, + TracedOrStopped, + Zombie, +}; +} + +namespace lldb_private { +class ProcessLaunchInfo; +} + +static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo, + ProcessState &State, ::pid_t &TracerPid, + ::pid_t &Tgid) { + Log *log = GetLog(LLDBLog::Host); + + auto BufferOrError = getProcFile(Pid, "status"); + if (!BufferOrError) + return false; + + llvm::StringRef Rest = BufferOrError.get()->getBuffer(); + while (!Rest.empty()) { + llvm::StringRef Line; + std::tie(Line, Rest) = Rest.split('\n'); + + if (Line.consume_front("Gid:")) { + // Real, effective, saved set, and file system GIDs. Read the first two. + Line = Line.ltrim(); + uint32_t RGid, EGid; + Line.consumeInteger(10, RGid); + Line = Line.ltrim(); + Line.consumeInteger(10, EGid); + + ProcessInfo.SetGroupID(RGid); + ProcessInfo.SetEffectiveGroupID(EGid); + } else if (Line.consume_front("Uid:")) { + // Real, effective, saved set, and file system UIDs. Read the first two. + Line = Line.ltrim(); + uint32_t RUid, EUid; + Line.consumeInteger(10, RUid); + Line = Line.ltrim(); + Line.consumeInteger(10, EUid); + + ProcessInfo.SetUserID(RUid); + ProcessInfo.SetEffectiveUserID(EUid); + } else if (Line.consume_front("PPid:")) { + ::pid_t PPid; + Line.ltrim().consumeInteger(10, PPid); + ProcessInfo.SetParentProcessID(PPid); + } else if (Line.consume_front("State:")) { + State = llvm::StringSwitch(Line.ltrim().take_front(1)) + .Case("D", ProcessState::DiskSleep) + .Case("I", ProcessState::Idle) + .Case("R", ProcessState::Running) + .Case("S", ProcessState::Sleeping) + .CaseLower("T", ProcessState::TracedOrStopped) + .Case("W", ProcessState::Paging) + .Case("P", ProcessState::Parked) + .Case("X", ProcessState::Dead) + .Case("Z", ProcessState::Zombie) + .Default(ProcessState::Unknown); + if (State == ProcessState::Unknown) { + LLDB_LOG(log, "Unknown process state {0}", Line); + } + } else if (Line.consume_front("TracerPid:")) { + Line = Line.ltrim(); + Line.consumeInteger(10, TracerPid); + } else if (Line.consume_front("Tgid:")) { + Line = Line.ltrim(); + Line.consumeInteger(10, Tgid); + } + } + return true; +} + +static bool IsDirNumeric(const char *dname) { + for (; *dname; dname++) { + if (!isdigit(*dname)) + return false; + } + return true; +} + +static void GetProcessArgs(::pid_t pid, ProcessInstanceInfo &process_info) { + auto BufferOrError = getProcFile(pid, "cmdline"); + if (!BufferOrError) + return; + std::unique_ptr Cmdline = std::move(*BufferOrError); + + llvm::StringRef Arg0, Rest; + std::tie(Arg0, Rest) = Cmdline->getBuffer().split('\0'); + process_info.SetArg0(Arg0); + while (!Rest.empty()) { + llvm::StringRef Arg; + std::tie(Arg, Rest) = Rest.split('\0'); + process_info.GetArguments().AppendArgument(Arg); + } +} + +static void GetExePathAndArch(::pid_t pid, ProcessInstanceInfo &process_info) { + Log *log = GetLog(LLDBLog::Process); + std::string ExePath(PATH_MAX, '\0'); + std::string Basename(PATH_MAX, '\0'); + struct psinfo psinfoData; + + // We can't use getProcFile here because proc/[pid]/exe is a symbolic link. + llvm::SmallString<64> ProcExe; + (llvm::Twine("/proc/") + llvm::Twine(pid) + "/cwd").toVector(ProcExe); + + ssize_t len = readlink(ProcExe.c_str(), &ExePath[0], PATH_MAX); + if (len > 0) { + ExePath.resize(len); + + //FIXME: hack to get basename + struct stat statData; + + std::ostringstream oss; + + oss << "/proc/" << std::dec << pid << "/psinfo"; + assert(stat(oss.str().c_str(), &statData) == 0); + + const int fd = open(oss.str().c_str(), O_RDONLY); + assert (fd >= 0); + + ssize_t readNum = read(fd, &psinfoData, sizeof(psinfoData)); + assert (readNum >= 0); + + close (fd); + } else { + LLDB_LOG(log, "failed to read link exe link for {0}: {1}", pid, + Status(errno, eErrorTypePOSIX)); + ExePath.resize(0); + } + + llvm::StringRef PathRef = std::string(&(psinfoData.pr_psargs[0])); + + if (!PathRef.empty()) { + process_info.GetExecutableFile().SetFile(PathRef, FileSpec::Style::native); + ArchSpec arch_spec = ArchSpec(); + arch_spec.SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX); + process_info.SetArchitecture(arch_spec); + } +} + +static void GetProcessEnviron(::pid_t pid, ProcessInstanceInfo &process_info) { + // Get the process environment. + auto BufferOrError = getProcFile(pid, "environ"); + if (!BufferOrError) + return; + + std::unique_ptr Environ = std::move(*BufferOrError); + llvm::StringRef Rest = Environ->getBuffer(); + while (!Rest.empty()) { + llvm::StringRef Var; + std::tie(Var, Rest) = Rest.split('\0'); + process_info.GetEnvironment().insert(Var); + } +} + +static bool GetProcessAndStatInfo(::pid_t pid, + ProcessInstanceInfo &process_info, + ProcessState &State, ::pid_t &tracerpid) { + ::pid_t tgid; + tracerpid = 0; + process_info.Clear(); + + process_info.SetProcessID(pid); + + GetExePathAndArch(pid, process_info); + GetProcessArgs(pid, process_info); + GetProcessEnviron(pid, process_info); + + // Get User and Group IDs and get tracer pid. + if (!GetStatusInfo(pid, process_info, State, tracerpid, tgid)) + return false; + + return true; +} + +uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { + static const char procdir[] = "/proc/"; + + DIR *dirproc = opendir(procdir); + if (dirproc) { + struct dirent *direntry = nullptr; + const uid_t our_uid = getuid(); + const lldb::pid_t our_pid = getpid(); + bool all_users = match_info.GetMatchAllUsers(); + + while ((direntry = readdir(dirproc)) != nullptr) { + /* + if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name)) + continue; + */ + + lldb::pid_t pid = atoi(direntry->d_name); + + // Skip this process. + if (pid == our_pid) + continue; + + ::pid_t tracerpid; + ProcessState State; + ProcessInstanceInfo process_info; + + if (!GetProcessAndStatInfo(pid, process_info, State, tracerpid)) + continue; + + // Skip if process is being debugged. + if (tracerpid != 0) + continue; + + if (State == ProcessState::Zombie) + continue; + + // Check for user match if we're not matching all users and not running + // as root. + if (!all_users && (our_uid != 0) && (process_info.GetUserID() != our_uid)) + continue; + + if (match_info.Matches(process_info)) { + process_infos.push_back(process_info); + } + } + + closedir(dirproc); + } + + return process_infos.size(); +} + +bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { + ::pid_t tracerpid; + ProcessState State; + return GetProcessAndStatInfo(pid, process_info, State, tracerpid); +} + +Environment Host::GetEnvironment() { return Environment(environ); } + +Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) { + return Status("unimplemented"); +} + +std::optional lldb_private::getPIDForTID(lldb::pid_t tid) { + ::pid_t tracerpid, tgid = LLDB_INVALID_PROCESS_ID; + ProcessInstanceInfo process_info; + ProcessState state; + + if (!GetStatusInfo(tid, process_info, state, tracerpid, tgid) || + tgid == LLDB_INVALID_PROCESS_ID) + return std::nullopt; + return tgid; +} diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp new file mode 100644 index 0000000000000..8bda09e01741b --- /dev/null +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -0,0 +1,215 @@ +//===-- HostInfoAIX.cpp -------------------------------------------------===// +// +// 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 "lldb/Host/aix/HostInfoAIX.h" +#include "lldb/Host/Config.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" + +#include "llvm/Support/Threading.h" + +#include +#include +#include +#include +#include + +#include +#include + +using namespace lldb_private; + +namespace { +struct HostInfoAIXFields { + llvm::once_flag m_distribution_once_flag; + std::string m_distribution_id; + llvm::once_flag m_os_version_once_flag; + llvm::VersionTuple m_os_version; +}; +} // namespace + +static HostInfoAIXFields *g_fields = nullptr; + +void HostInfoAIX::Initialize(SharedLibraryDirectoryHelper *helper) { + HostInfoPosix::Initialize(helper); + + g_fields = new HostInfoAIXFields(); +} + +void HostInfoAIX::Terminate() { + assert(g_fields && "Missing call to Initialize?"); + delete g_fields; + g_fields = nullptr; + HostInfoBase::Terminate(); +} + +llvm::VersionTuple HostInfoAIX::GetOSVersion() { + assert(g_fields && "Missing call to Initialize?"); + llvm::call_once(g_fields->m_os_version_once_flag, []() { + struct utsname un; + if (uname(&un) != 0) + return; + + llvm::StringRef release = un.release; + // The kernel release string can include a lot of stuff (e.g. + // 4.9.0-6-amd64). We're only interested in the numbered prefix. + release = release.substr(0, release.find_first_not_of("0123456789.")); + g_fields->m_os_version.tryParse(release); + }); + + return g_fields->m_os_version; +} + +std::optional HostInfoAIX::GetOSBuildString() { + struct utsname un; + ::memset(&un, 0, sizeof(utsname)); + + if (uname(&un) < 0) + return std::nullopt; + + return std::string(un.release); +} + +llvm::StringRef HostInfoAIX::GetDistributionId() { + assert(g_fields && "Missing call to Initialize?"); + // Try to run 'lbs_release -i', and use that response for the distribution + // id. + llvm::call_once(g_fields->m_distribution_once_flag, []() { + Log *log = GetLog(LLDBLog::Host); + LLDB_LOGF(log, "attempting to determine AIX distribution..."); + + // check if the lsb_release command exists at one of the following paths + const char *const exe_paths[] = {"/bin/lsb_release", + "/usr/bin/lsb_release"}; + + for (size_t exe_index = 0; + exe_index < sizeof(exe_paths) / sizeof(exe_paths[0]); ++exe_index) { + const char *const get_distribution_info_exe = exe_paths[exe_index]; + if (access(get_distribution_info_exe, F_OK)) { + // this exe doesn't exist, move on to next exe + LLDB_LOGF(log, "executable doesn't exist: %s", + get_distribution_info_exe); + continue; + } + + // execute the distribution-retrieval command, read output + std::string get_distribution_id_command(get_distribution_info_exe); + get_distribution_id_command += " -i"; + + FILE *file = popen(get_distribution_id_command.c_str(), "r"); + if (!file) { + LLDB_LOGF(log, + "failed to run command: \"%s\", cannot retrieve " + "platform information", + get_distribution_id_command.c_str()); + break; + } + + // retrieve the distribution id string. + char distribution_id[256] = {'\0'}; + if (fgets(distribution_id, sizeof(distribution_id) - 1, file) != + nullptr) { + LLDB_LOGF(log, "distribution id command returned \"%s\"", + distribution_id); + + const char *const distributor_id_key = "Distributor ID:\t"; + if (strstr(distribution_id, distributor_id_key)) { + // strip newlines + std::string id_string(distribution_id + strlen(distributor_id_key)); + id_string.erase(std::remove(id_string.begin(), id_string.end(), '\n'), + id_string.end()); + + // lower case it and convert whitespace to underscores + std::transform( + id_string.begin(), id_string.end(), id_string.begin(), + [](char ch) { return tolower(isspace(ch) ? '_' : ch); }); + + g_fields->m_distribution_id = id_string; + LLDB_LOGF(log, "distribution id set to \"%s\"", + g_fields->m_distribution_id.c_str()); + } else { + LLDB_LOGF(log, "failed to find \"%s\" field in \"%s\"", + distributor_id_key, distribution_id); + } + } else { + LLDB_LOGF(log, + "failed to retrieve distribution id, \"%s\" returned no" + " lines", + get_distribution_id_command.c_str()); + } + + // clean up the file + pclose(file); + } + }); + + return g_fields->m_distribution_id; +} + +FileSpec HostInfoAIX::GetProgramFileSpec() { + static FileSpec g_program_filespec; + + if (!g_program_filespec) { + char exe_path[PATH_MAX]; + ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); + if (len > 0) { + exe_path[len] = 0; + g_program_filespec.SetFile(exe_path, FileSpec::Style::native); + } + } + + return g_program_filespec; +} + +bool HostInfoAIX::ComputeSupportExeDirectory(FileSpec &file_spec) { + if (HostInfoPosix::ComputeSupportExeDirectory(file_spec) && + file_spec.IsAbsolute() && FileSystem::Instance().Exists(file_spec)) + return true; + file_spec.SetDirectory(GetProgramFileSpec().GetDirectory()); + return !file_spec.GetDirectory().IsEmpty(); +} + +bool HostInfoAIX::ComputeSystemPluginsDirectory(FileSpec &file_spec) { + FileSpec temp_file("/usr/" LLDB_INSTALL_LIBDIR_BASENAME "/lldb/plugins"); + FileSystem::Instance().Resolve(temp_file); + file_spec.SetDirectory(temp_file.GetPath()); + return true; +} + +bool HostInfoAIX::ComputeUserPluginsDirectory(FileSpec &file_spec) { + // XDG Base Directory Specification + // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html If + // XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb. + const char *xdg_data_home = getenv("XDG_DATA_HOME"); + if (xdg_data_home && xdg_data_home[0]) { + std::string user_plugin_dir(xdg_data_home); + user_plugin_dir += "/lldb"; + file_spec.SetDirectory(user_plugin_dir.c_str()); + } else + file_spec.SetDirectory("~/.local/share/lldb"); + return true; +} + +void HostInfoAIX::ComputeHostArchitectureSupport(ArchSpec &arch_32, + ArchSpec &arch_64) { + HostInfoPosix::ComputeHostArchitectureSupport(arch_32, arch_64); + + const char *distribution_id = GetDistributionId().data(); + + // On Linux, "unknown" in the vendor slot isn't what we want for the default + // triple. It's probably an artifact of config.guess. + if (arch_32.IsValid()) { + if (arch_32.GetTriple().getVendor() == llvm::Triple::UnknownVendor) + arch_32.GetTriple().setVendorName(llvm::StringRef()); + } + if (arch_64.IsValid()) { + if (arch_64.GetTriple().getVendor() == llvm::Triple::UnknownVendor) + arch_64.GetTriple().setVendorName(llvm::StringRef()); + } +} diff --git a/lldb/source/Host/aix/Support.cpp b/lldb/source/Host/aix/Support.cpp new file mode 100644 index 0000000000000..1bf2662190127 --- /dev/null +++ b/lldb/source/Host/aix/Support.cpp @@ -0,0 +1,44 @@ +//===-- Support.cpp -------------------------------------------------------===// +// +// 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 "lldb/Host/aix/Support.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "llvm/Support/MemoryBuffer.h" + +llvm::ErrorOr> +lldb_private::getProcFile(::pid_t pid, ::pid_t tid, const llvm::Twine &file) { + Log *log = GetLog(LLDBLog::Host); + std::string File = + ("/proc/" + llvm::Twine(pid) + "/task/" + llvm::Twine(tid) + "/" + file) + .str(); + auto Ret = llvm::MemoryBuffer::getFileAsStream(File); + if (!Ret) + LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message()); + return Ret; +} + +llvm::ErrorOr> +lldb_private::getProcFile(::pid_t pid, const llvm::Twine &file) { + Log *log = GetLog(LLDBLog::Host); + std::string File = ("/proc/" + llvm::Twine(pid) + "/" + file).str(); + auto Ret = llvm::MemoryBuffer::getFileAsStream(File); + if (!Ret) + LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message()); + return Ret; +} + +llvm::ErrorOr> +lldb_private::getProcFile(const llvm::Twine &file) { + Log *log = GetLog(LLDBLog::Host); + std::string File = ("/proc/" + file).str(); + auto Ret = llvm::MemoryBuffer::getFileAsStream(File); + if (!Ret) + LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message()); + return Ret; +} diff --git a/lldb/source/Host/common/GetOptInc.cpp b/lldb/source/Host/common/GetOptInc.cpp index c2044b6873221..e0ae2aa1774b3 100644 --- a/lldb/source/Host/common/GetOptInc.cpp +++ b/lldb/source/Host/common/GetOptInc.cpp @@ -409,7 +409,7 @@ static int getopt_internal(int nargc, char *const *nargv, const char *options, * [eventually this will replace the BSD getopt] */ #if defined(REPLACE_GETOPT) -int getopt(int nargc, char *const *nargv, const char *options) { +int getopt(int nargc, char *const *nargv, const char *options) throw() { /* * We don't pass FLAG_PERMUTE to getopt_internal() since diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index e03d36e9cad4a..2fd7111a94fb2 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -357,9 +357,183 @@ bool Host::ResolveExecutableInBundle(FileSpec &file) { return false; } #ifndef _WIN32 +#if defined(__AIX__) + +#include +extern char **p_xargv; + +/* Fix missing Dl_info & dladdr in AIX + * The code is taken from netbsd.org (src/crypto/external/bsd/openssl/dist/crypto/dso/dso_dlfcn.c) + * except strlcpy & strlcat (those are taken from openbsd.org (src/lib/libc/string)) + */ +/*- + * See IBM's AIX Version 7.2, Technical Reference: + * Base Operating System and Extensions, Volume 1 and 2 + * https://www.ibm.com/support/knowledgecenter/ssw_aix_72/com.ibm.aix.base/technicalreferences.htm + */ +#include +#include + +/* strlcpy: + * Copy string src to buffer dst of size dsize. At most dsize-1 + * chars will be copied. Always NUL terminates (unless dsize == 0). + * Returns strlen(src); if retval >= dsize, truncation occurred. + */ +size_t strlcpy(char *dst, const char *src, size_t dsize) +{ + const char *osrc = src; + size_t nleft = dsize; + + /* Copy as many bytes as will fit. */ + if (nleft != 0) { + while (--nleft != 0) { + if ((*dst++ = *src++) == '\0') { + break; + } + } + } + + /* Not enough room in dst, add NUL and traverse rest of src. */ + if (nleft == 0) { + if (dsize != 0) { + *dst = '\0'; /* NUL-terminate dst */ + } + while (*src++) { + ; + } + } + + return src - osrc - 1; /* count does not include NUL */ +} + +/* strlcat: + * Appends src to string dst of size dsize (unlike strncat, dsize is the + * full size of dst, not space left). At most dsize-1 characters + * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). + * Returns strlen(src) + MIN(dsize, strlen(initial dst)). + * If retval >= dsize, truncation occurred. + */ +size_t strlcat(char *dst, const char *src, size_t dsize) +{ + const char *odst = dst; + const char *osrc = src; + size_t n = dsize; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end. */ + while (n-- != 0 && *dst != '\0') { + dst++; + } + dlen = dst - odst; + n = dsize - dlen; + + if (n-- == 0) { + return dlen + strlen(src); + } + while (*src != '\0') { + if (n != 0) { + *dst++ = *src; + n--; + } + src++; + } + *dst = '\0'; + + return dlen + src - osrc; /* count does not include NUL */ +} + +/* ~ 64 * (sizeof(struct ld_info) + _XOPEN_PATH_MAX + _XOPEN_NAME_MAX) */ +# define DLFCN_LDINFO_SIZE 86976 +typedef struct Dl_info { + const char *dli_fname; +} Dl_info; +/* + * This dladdr()-implementation will also find the ptrgl (Pointer Glue) virtual + * address of a function, which is just located in the DATA segment instead of + * the TEXT segment. + */ +static int dladdr(const void *ptr, Dl_info *dl) +{ + uintptr_t addr = (uintptr_t)ptr; + struct ld_info *ldinfos; + struct ld_info *next_ldi; + struct ld_info *this_ldi; + + if ((ldinfos = (struct ld_info *)malloc(DLFCN_LDINFO_SIZE)) == NULL) { + dl->dli_fname = NULL; + return 0; + } + + if ((loadquery(L_GETINFO, (void *)ldinfos, DLFCN_LDINFO_SIZE)) < 0) { + /*- + * Error handling is done through errno and dlerror() reading errno: + * ENOMEM (ldinfos buffer is too small), + * EINVAL (invalid flags), + * EFAULT (invalid ldinfos ptr) + */ + free((void *)ldinfos); + dl->dli_fname = NULL; + return 0; + } + next_ldi = ldinfos; + + do { + this_ldi = next_ldi; + if (((addr >= (uintptr_t)this_ldi->ldinfo_textorg) + && (addr < ((uintptr_t)this_ldi->ldinfo_textorg + + this_ldi->ldinfo_textsize))) + || ((addr >= (uintptr_t)this_ldi->ldinfo_dataorg) + && (addr < ((uintptr_t)this_ldi->ldinfo_dataorg + + this_ldi->ldinfo_datasize)))) { + char *buffer = NULL; + char *member = NULL; + size_t buffer_sz; + size_t member_len; + + buffer_sz = strlen(this_ldi->ldinfo_filename) + 1; + member = this_ldi->ldinfo_filename + buffer_sz; + if ((member_len = strlen(member)) > 0) { + buffer_sz += 1 + member_len + 1; + } + if ((buffer = (char *)malloc(buffer_sz)) != NULL) { + strlcpy(buffer, this_ldi->ldinfo_filename, buffer_sz); + if (member_len > 0) { + /* + * Need to respect a possible member name and not just + * returning the path name in this case. See docs: + * sys/ldr.h, loadquery() and dlopen()/RTLD_MEMBER. + */ + strlcat(buffer, "(", buffer_sz); + strlcat(buffer, member, buffer_sz); + strlcat(buffer, ")", buffer_sz); + } + dl->dli_fname = buffer; + } + break; + } else { + next_ldi = (struct ld_info *)((uintptr_t)this_ldi + + this_ldi->ldinfo_next); + } + } while (this_ldi->ldinfo_next); + free((void *)ldinfos); + return dl->dli_fname != NULL; +} + +#endif + FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSpec module_filespec; #if !defined(__ANDROID__) +#ifdef __AIX__ + if (host_addr == reinterpret_cast(HostInfoBase::ComputeSharedLibraryDirectory)) { + // FIXME: AIX dladdr return "lldb" for this case + if (p_xargv[0]) { + module_filespec.SetFile(p_xargv[0], FileSpec::Style::native); + FileSystem::Instance().Resolve(module_filespec); + return module_filespec; + } + } +#endif Dl_info info; if (::dladdr(host_addr, &info)) { if (info.dli_fname) { @@ -373,12 +547,6 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { #endif -#if !defined(__linux__) -bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) { - return false; -} -#endif - struct ShellInfo { ShellInfo() : process_reaped(false) {} diff --git a/lldb/source/Host/common/LICENSE.aix-netbsd.txt b/lldb/source/Host/common/LICENSE.aix-netbsd.txt new file mode 100644 index 0000000000000..9601ab43575f9 --- /dev/null +++ b/lldb/source/Host/common/LICENSE.aix-netbsd.txt @@ -0,0 +1,125 @@ + + LICENSE ISSUES + ============== + + The OpenSSL toolkit stays under a double license, i.e. both the conditions of + the OpenSSL License and the original SSLeay license apply to the toolkit. + See below for the actual license texts. + + OpenSSL License + --------------- + +/* ==================================================================== + * Copyright (c) 1998-2019 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core at openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay at cryptsoft.com). This product includes software written by Tim + * Hudson (tjh at cryptsoft.com). + * + */ + + Original SSLeay License + ----------------------- + +/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay at cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh at cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay at cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh at cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + diff --git a/lldb/source/Host/common/XML.cpp b/lldb/source/Host/common/XML.cpp index f480ef3166a44..62cac78aaac23 100644 --- a/lldb/source/Host/common/XML.cpp +++ b/lldb/source/Host/common/XML.cpp @@ -10,6 +10,9 @@ #include "lldb/Host/XML.h" #include "llvm/ADT/StringExtras.h" +#if defined(__AIX__) +#undef LLDB_ENABLE_LIBXML2 +#endif using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index fceeff08ed9d3..143254bb12901 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -721,6 +721,7 @@ ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, ConnectionStatus ConnectionFileDescriptor::ConnectFile( llvm::StringRef s, socket_id_callback_type socket_id_callback, Status *error_ptr) { +#if !defined(__AIX__) #if LLDB_ENABLE_POSIX std::string addr_str = s.str(); // file:///PATH @@ -753,6 +754,7 @@ ConnectionStatus ConnectionFileDescriptor::ConnectFile( m_io_sp = std::make_shared(fd, File::eOpenOptionReadWrite, true); return eConnectionStatusSuccess; #endif // LLDB_ENABLE_POSIX +#endif llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX"); } diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index cdb76da626bc9..a7c50f6a3c835 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,7 +11,9 @@ // C includes #include #include +#if !defined(__AIX__) #include +#endif #include #include #include diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp index 5fe4d015251c8..e5be0db4cf19b 100644 --- a/lldb/source/Host/posix/MainLoopPosix.cpp +++ b/lldb/source/Host/posix/MainLoopPosix.cpp @@ -179,9 +179,21 @@ Status MainLoopPosix::RunImpl::Poll() { read_fds.push_back(pfd); } +#if defined(__AIX__) + sigset_t origmask; + int timeout; + + timeout = -1; + pthread_sigmask(SIG_SETMASK, &sigmask, &origmask); + int ready = poll(read_fds.data(), read_fds.size(), timeout); + pthread_sigmask(SIG_SETMASK, &origmask, nullptr); + if (ready == -1 && errno != EINTR) + return Status(errno, eErrorTypePOSIX); +#else if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 && errno != EINTR) return Status(errno, eErrorTypePOSIX); +#endif return Status(); } @@ -312,8 +324,13 @@ MainLoopPosix::RegisterSignal(int signo, const Callback &callback, // If we're using kqueue, the signal needs to be unblocked in order to // receive it. If using pselect/ppoll, we need to block it, and later unblock // it as a part of the system call. +#if defined(__AIX__) + //FIXME: where is signal unblocked? + ret = pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, &old_set); +#else ret = pthread_sigmask(HAVE_SYS_EVENT_H ? SIG_UNBLOCK : SIG_BLOCK, &new_action.sa_mask, &old_set); +#endif assert(ret == 0 && "pthread_sigmask failed"); info.was_blocked = sigismember(&old_set, signo); auto insert_ret = m_signals.insert({signo, info}); diff --git a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp index 0a832ebad13a7..cd106f605b1f4 100644 --- a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp +++ b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp @@ -193,8 +193,13 @@ struct ForkLaunchInfo { } // Start tracing this child that is about to exec. +#if !defined(__AIX__) if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1) ExitWithError(error_fd, "ptrace"); +#else + if (ptrace64(PT_TRACE_ME, 0, 0, 0, nullptr) == -1) + ExitWithError(error_fd, "ptrace"); +#endif } // Execute. We should never return... diff --git a/lldb/source/Initialization/CMakeLists.txt b/lldb/source/Initialization/CMakeLists.txt index c1a167826f76f..9f94830c8509f 100644 --- a/lldb/source/Initialization/CMakeLists.txt +++ b/lldb/source/Initialization/CMakeLists.txt @@ -1,4 +1,4 @@ -if ( CMAKE_SYSTEM_NAME MATCHES "Linux|Android|FreeBSD|NetBSD" ) +if ( CMAKE_SYSTEM_NAME MATCHES "Linux|Android|FreeBSD|NetBSD|AIX" ) list(APPEND EXTRA_PLUGINS lldbPluginProcessPOSIX) endif() diff --git a/lldb/source/Initialization/SystemInitializerCommon.cpp b/lldb/source/Initialization/SystemInitializerCommon.cpp index 1a172a95aa147..4b01442a94bac 100644 --- a/lldb/source/Initialization/SystemInitializerCommon.cpp +++ b/lldb/source/Initialization/SystemInitializerCommon.cpp @@ -19,7 +19,7 @@ #include "lldb/Version/Version.h" #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__OpenBSD__) + defined(__OpenBSD__) || defined(__AIX__) #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" #endif @@ -79,7 +79,7 @@ llvm::Error SystemInitializerCommon::Initialize() { process_gdb_remote::ProcessGDBRemoteLog::Initialize(); #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__OpenBSD__) + defined(__OpenBSD__) || defined(__AIX__) ProcessPOSIXLog::Initialize(); #endif #if defined(_WIN32) diff --git a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp index eac058701313b..feb0d7c0e09be 100644 --- a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp +++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp @@ -156,6 +156,9 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) return false; +#if defined(__AIX__) + assert(0); +#else // Read TOC pointer value. reg_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0); @@ -171,6 +174,132 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, (uint64_t)reg_value); if (!process_sp->WritePointerToMemory(sp + stack_offset, reg_value, error)) return false; +#endif + + // Read the current SP value. + reg_value = reg_ctx->ReadRegisterAsUnsigned(sp_reg_info, 0); + + // Save current SP onto the stack. + LLDB_LOGF(log, "Writing SP at SP(0x%" PRIx64 ")+0: 0x%" PRIx64, (uint64_t)sp, + (uint64_t)reg_value); + if (!process_sp->WritePointerToMemory(sp, reg_value, error)) + return false; + + // %r1 is set to the actual stack value. + LLDB_LOGF(log, "Writing SP: 0x%" PRIx64, (uint64_t)sp); + + if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_info, sp)) + return false; + + // %pc is set to the address of the called function. + + LLDB_LOGF(log, "Writing IP: 0x%" PRIx64, (uint64_t)func_addr); + + if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_info, func_addr)) + return false; + + return true; +} + +bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, + addr_t func_addr, addr_t toc_addr, + addr_t return_addr, + llvm::ArrayRef args) const { + Log *log = GetLog(LLDBLog::Expressions); + + if (log) { + StreamString s; + s.Printf("ABISysV_ppc64::PrepareTrivialCall (tid = 0x%" PRIx64 + ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 + ", return_addr = 0x%" PRIx64, + thread.GetID(), (uint64_t)sp, (uint64_t)func_addr, + (uint64_t)return_addr); + + for (size_t i = 0; i < args.size(); ++i) + s.Printf(", arg%" PRIu64 " = 0x%" PRIx64, static_cast(i + 1), + args[i]); + s.PutCString(")"); + log->PutString(s.GetString()); + } + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return false; + + const RegisterInfo *reg_info = nullptr; + + if (args.size() > 8) // TODO handle more than 8 arguments + return false; + + for (size_t i = 0; i < args.size(); ++i) { + reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_ARG1 + i); + LLDB_LOGF(log, "About to write arg%" PRIu64 " (0x%" PRIx64 ") into %s", + static_cast(i + 1), args[i], reg_info->name); + if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) + return false; + } + + // First, align the SP + + LLDB_LOGF(log, "16-byte aligning SP: 0x%" PRIx64 " to 0x%" PRIx64, + (uint64_t)sp, (uint64_t)(sp & ~0xfull)); + + sp &= ~(0xfull); // 16-byte alignment + + sp -= 544; // allocate frame to save TOC, RA and SP. + + Status error; + uint64_t reg_value; + const RegisterInfo *pc_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + const RegisterInfo *sp_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); + ProcessSP process_sp(thread.GetProcess()); + const RegisterInfo *lr_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); + const RegisterInfo *r2_reg_info = reg_ctx->GetRegisterInfoAtIndex(2); + const RegisterInfo *r12_reg_info = reg_ctx->GetRegisterInfoAtIndex(12); + + // Save return address onto the stack. + LLDB_LOGF(log, + "Pushing the return address onto the stack: 0x%" PRIx64 + "(+16): 0x%" PRIx64, + (uint64_t)sp, (uint64_t)return_addr); + if (!process_sp->WritePointerToMemory(sp + 16, return_addr, error)) + return false; + + // Write the return address to link register. + LLDB_LOGF(log, "Writing LR: 0x%" PRIx64, (uint64_t)return_addr); + if (!reg_ctx->WriteRegisterFromUnsigned(lr_reg_info, return_addr)) + return false; + + // Write target address to %r12 register. + LLDB_LOGF(log, "Writing R12: 0x%" PRIx64, (uint64_t)func_addr); + if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) + return false; + +#if defined(__AIX__) + LLDB_LOGF(log, "Writing R2: 0x%" PRIx64, (uint64_t)toc_addr); + if (!reg_ctx->WriteRegisterFromUnsigned(r2_reg_info, toc_addr)) + return false; +#else + // Read TOC pointer value. + reg_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0); + + // Write TOC pointer onto the stack. + uint64_t stack_offset; + if (GetByteOrder() == lldb::eByteOrderLittle) + stack_offset = 24; + else + stack_offset = 40; + + LLDB_LOGF(log, "Writing R2 (TOC) at SP(0x%" PRIx64 ")+%d: 0x%" PRIx64, + (uint64_t)(sp + stack_offset), (int)stack_offset, + (uint64_t)reg_value); + if (!process_sp->WritePointerToMemory(sp + stack_offset, reg_value, error)) + return false; +#endif // Read the current SP value. reg_value = reg_ctx->ReadRegisterAsUnsigned(sp_reg_info, 0); @@ -641,7 +770,7 @@ class ReturnValueExtractor { DataExtractor de(&raw_data, sizeof(raw_data), m_byte_order, m_addr_size); - offset_t offset = 0; + lldb::offset_t offset = 0; std::optional byte_size = type.GetByteSize(m_process_sp.get()); if (!byte_size) return {}; diff --git a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h index bfa96cc0df703..d752a8ded9748 100644 --- a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h +++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h @@ -23,6 +23,12 @@ class ABISysV_ppc64 : public lldb_private::RegInfoBasedABI { lldb::addr_t returnAddress, llvm::ArrayRef args) const override; + bool PrepareTrivialCall(lldb_private::Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t tocAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef args) const override; + bool GetArgumentValues(lldb_private::Thread &thread, lldb_private::ValueList &values) const override; diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt new file mode 100644 index 0000000000000..02fe0d617955a --- /dev/null +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt @@ -0,0 +1,11 @@ +add_definitions("-D_ALL_SOURCE") + +add_lldb_library(lldbPluginDynamicLoaderAIXDYLD PLUGIN + DynamicLoaderAIXDYLD.cpp + + LINK_LIBS + lldbCore + lldbTarget + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp new file mode 100644 index 0000000000000..62663974134b0 --- /dev/null +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -0,0 +1,272 @@ +//===-- DynamicLoaderAIXDYLD.cpp --------------------------------------===// +// +// 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 "DynamicLoaderAIXDYLD.h" + +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Platform.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/ThreadPlanStepInstruction.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#if defined(__AIX__) +#include +#endif + +/*#include "llvm/ADT/Triple.h" +*/ + +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(DynamicLoaderAIXDYLD) + +DynamicLoaderAIXDYLD::DynamicLoaderAIXDYLD(Process *process) + : DynamicLoader(process) {} + +DynamicLoaderAIXDYLD::~DynamicLoaderAIXDYLD() = default; + +void DynamicLoaderAIXDYLD::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); +} + +void DynamicLoaderAIXDYLD::Terminate() {} + +llvm::StringRef DynamicLoaderAIXDYLD::GetPluginDescriptionStatic() { + return "Dynamic loader plug-in that watches for shared library " + "loads/unloads in AIX processes."; +} + +DynamicLoader *DynamicLoaderAIXDYLD::CreateInstance(Process *process, + bool force) { + bool should_create = force; + if (!should_create) { + const llvm::Triple &triple_ref = + process->GetTarget().GetArchitecture().GetTriple(); + if (triple_ref.getOS() == llvm::Triple::AIX) + should_create = true; + } + + if (should_create) + return new DynamicLoaderAIXDYLD(process); + + return nullptr; +} + +void DynamicLoaderAIXDYLD::OnLoadModule(lldb::ModuleSP module_sp, + const ModuleSpec module_spec, + lldb::addr_t module_addr) { + + // Resolve the module unless we already have one. + if (!module_sp) { + Status error; + module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, + true /* notify */, &error); + if (error.Fail()) + return; + } + + m_loaded_modules[module_sp] = module_addr; + UpdateLoadedSectionsCommon(module_sp, module_addr, false); + ModuleList module_list; + module_list.Append(module_sp); + m_process->GetTarget().ModulesDidLoad(module_list); +} + +void DynamicLoaderAIXDYLD::OnUnloadModule(lldb::addr_t module_addr) { + Address resolved_addr; + if (!m_process->GetTarget().ResolveLoadAddress(module_addr, resolved_addr)) + return; + + ModuleSP module_sp = resolved_addr.GetModule(); + if (module_sp) { + m_loaded_modules.erase(module_sp); + UnloadSectionsCommon(module_sp); + ModuleList module_list; + module_list.Append(module_sp); + m_process->GetTarget().ModulesDidUnload(module_list, false); + } +} + +lldb::addr_t DynamicLoaderAIXDYLD::GetLoadAddress(ModuleSP executable) { + // First, see if the load address is already cached. + auto it = m_loaded_modules.find(executable); + if (it != m_loaded_modules.end() && it->second != LLDB_INVALID_ADDRESS) + return it->second; + + lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; + + // Second, try to get it through the process plugins. For a remote process, + // the remote platform will be responsible for providing it. + FileSpec file_spec(executable->GetPlatformFileSpec()); + bool is_loaded = false; + Status status = + m_process->GetFileLoadAddress(file_spec, is_loaded, load_addr); + // Servers other than lldb server could respond with a bogus address. + if (status.Success() && is_loaded && load_addr != LLDB_INVALID_ADDRESS) { + m_loaded_modules[executable] = load_addr; + return load_addr; + } + + //// Hack to try set breakpoint + //Breakpoint *dyld_break = m_process->GetTarget().CreateBreakpoint(0x100000638, true, false).get(); + //dyld_break->SetCallback(DynamicLoaderAIXDYLD::NotifyBreakpointHit, this, true); + //dyld_break->SetBreakpointKind("hack-debug"); + + return LLDB_INVALID_ADDRESS; +} + +bool DynamicLoaderAIXDYLD::NotifyBreakpointHit( + void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, + lldb::user_id_t break_loc_id) { +} + +void DynamicLoaderAIXDYLD::DidAttach() { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); + + ModuleSP executable = GetTargetExecutable(); + + if (!executable.get()) + return; + + // Try to fetch the load address of the file from the process, since there + // could be randomization of the load address. + lldb::addr_t load_addr = GetLoadAddress(executable); + if (load_addr == LLDB_INVALID_ADDRESS) + return; + + // Request the process base address. + lldb::addr_t image_base = m_process->GetImageInfoAddress(); + if (image_base == load_addr) + return; + + // Rebase the process's modules if there is a mismatch. + UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_addr, false); + + ModuleList module_list; + module_list.Append(executable); + m_process->GetTarget().ModulesDidLoad(module_list); + auto error = m_process->LoadModules(); + LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}"); + +#if defined(__AIX__) + // Get struct ld_xinfo (FIXME) + struct ld_xinfo ldinfo[64]; + Status status = m_process->GetLDXINFO(&(ldinfo[0])); + if (status.Fail()) { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOG(log, "LDXINFO failed: {0}", status); + return; + } + struct ld_xinfo *ptr = &(ldinfo[0]); + bool skip_current = true; + while (ptr != nullptr) { + char *pathName = (char *)ptr + ptr->ldinfo_filename; + char *memberName = pathName + (strlen(pathName) + 1); + if (!skip_current) { + // FIXME: buffer size + char pathWithMember[128] = {0}; + if (strlen(memberName) > 0) { + sprintf(pathWithMember, "%s(%s)", pathName, memberName); + } else { + sprintf(pathWithMember, "%s", pathName); + } + FileSpec file(pathWithMember); + ModuleSpec module_spec(file, m_process->GetTarget().GetArchitecture()); + if (ModuleSP module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, true /* notify */)) { + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_textorg, false, 1); + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_dataorg, false, 2); + // FIXME: .tdata, .bss + } + } else { + skip_current = false; + } + if (ptr->ldinfo_next == 0) { + ptr = nullptr; + } else { + ptr = (struct ld_xinfo *)((char *)ptr + ptr->ldinfo_next); + } + } +#endif +} + +void DynamicLoaderAIXDYLD::DidLaunch() { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); + + ModuleSP executable = GetTargetExecutable(); + if (!executable.get()) + return; + + lldb::addr_t load_addr = GetLoadAddress(executable); + if (load_addr != LLDB_INVALID_ADDRESS) { + // Update the loaded sections so that the breakpoints can be resolved. + UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_addr, false); + + ModuleList module_list; + module_list.Append(executable); + m_process->GetTarget().ModulesDidLoad(module_list); + auto error = m_process->LoadModules(); + LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}"); + } + +#if defined(__AIX__) + // Get struct ld_xinfo (FIXME) + struct ld_xinfo ldinfo[64]; + Status status = m_process->GetLDXINFO(&(ldinfo[0])); + if (status.Fail()) { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOG(log, "LDXINFO failed: {0}", status); + return; + } + struct ld_xinfo *ptr = &(ldinfo[0]); + bool skip_current = true; + while (ptr != nullptr) { + char *pathName = (char *)ptr + ptr->ldinfo_filename; + char *memberName = pathName + (strlen(pathName) + 1); + if (!skip_current) { + // FIXME: buffer size + char pathWithMember[128] = {0}; + if (strlen(memberName) > 0) { + sprintf(pathWithMember, "%s(%s)", pathName, memberName); + } else { + sprintf(pathWithMember, "%s", pathName); + } + FileSpec file(pathWithMember); + ModuleSpec module_spec(file, m_process->GetTarget().GetArchitecture()); + if (ModuleSP module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, true /* notify */)) { + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_textorg, false, 1); + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_dataorg, false, 2); + // FIXME: .tdata, .bss + } + } else { + skip_current = false; + } + if (ptr->ldinfo_next == 0) { + ptr = nullptr; + } else { + ptr = (struct ld_xinfo *)((char *)ptr + ptr->ldinfo_next); + } + } +#endif +} + +Status DynamicLoaderAIXDYLD::CanLoadImage() { return Status(); } + +ThreadPlanSP +DynamicLoaderAIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, + bool stop) { + //FIXME + return ThreadPlanSP(); +} diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h new file mode 100644 index 0000000000000..ae4b7aca66dcc --- /dev/null +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -0,0 +1,55 @@ +//===-- DynamicLoaderAIXDYLD.h ------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_DYNAMICLOADER_AIX_DYLD_DYNAMICLOADERAIXDYLD_H +#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_AIX_DYLD_DYNAMICLOADERAIXDYLD_H + +#include "lldb/Target/DynamicLoader.h" +#include "lldb/lldb-forward.h" + +#include + +namespace lldb_private { + +class DynamicLoaderAIXDYLD : public DynamicLoader { +public: + DynamicLoaderAIXDYLD(Process *process); + + ~DynamicLoaderAIXDYLD() override; + + static void Initialize(); + static void Terminate(); + static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; } + static llvm::StringRef GetPluginDescriptionStatic(); + + static DynamicLoader *CreateInstance(Process *process, bool force); + + void OnLoadModule(lldb::ModuleSP module_sp, const ModuleSpec module_spec, + lldb::addr_t module_addr); + void OnUnloadModule(lldb::addr_t module_addr); + + void DidAttach() override; + void DidLaunch() override; + Status CanLoadImage() override; + lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread, + bool stop) override; + + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + static bool NotifyBreakpointHit(void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id); + +protected: + lldb::addr_t GetLoadAddress(lldb::ModuleSP executable); + +private: + std::map m_loaded_modules; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_AIX_DYLD_DYNAMICLOADERWAIXDYLD_H diff --git a/lldb/source/Plugins/DynamicLoader/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/CMakeLists.txt index 30607159acdc0..4f3fb693faae1 100644 --- a/lldb/source/Plugins/DynamicLoader/CMakeLists.txt +++ b/lldb/source/Plugins/DynamicLoader/CMakeLists.txt @@ -5,4 +5,5 @@ add_subdirectory(POSIX-DYLD) add_subdirectory(Static) add_subdirectory(Hexagon-DYLD) add_subdirectory(Windows-DYLD) +add_subdirectory(AIX-DYLD) add_subdirectory(wasm-DYLD) diff --git a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp index 20e5652c65bf8..26abea0fdd24d 100644 --- a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp +++ b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp @@ -256,7 +256,7 @@ DynamicLoaderDarwinKernel::SearchForKernelWithDebugHints(Process *process) { if (process->ReadMemoryFromInferior (kernel_addresses_64[i], uval, 8, read_err) == 8) { DataExtractor data (&uval, 8, process->GetByteOrder(), process->GetAddressByteSize()); - offset_t offset = 0; + lldb::offset_t offset = 0; uint64_t addr = data.GetU64 (&offset); if (CheckForKernelImageAtAddress(addr, process).IsValid()) { return addr; @@ -270,7 +270,7 @@ DynamicLoaderDarwinKernel::SearchForKernelWithDebugHints(Process *process) { if (process->ReadMemoryFromInferior (kernel_addresses_32[i], uval, 4, read_err) == 4) { DataExtractor data (&uval, 4, process->GetByteOrder(), process->GetAddressByteSize()); - offset_t offset = 0; + lldb::offset_t offset = 0; uint32_t addr = data.GetU32 (&offset); if (CheckForKernelImageAtAddress(addr, process).IsValid()) { return addr; diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp index 3863b6b3520db..624848dee6ec3 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp @@ -1151,7 +1151,7 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp, // TLS data for the pthread_key on a specific thread yet. If we have we // can re-use it since its location will not change unless the process // execs. - const tid_t tid = thread_sp->GetID(); + const lldb::tid_t tid = thread_sp->GetID(); auto tid_pos = m_tid_to_tls_map.find(tid); if (tid_pos != m_tid_to_tls_map.end()) { auto tls_pos = tid_pos->second.find(key); diff --git a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp index 3035c51341778..d14ae2daeb47d 100644 --- a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp +++ b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp @@ -146,7 +146,25 @@ EmulateInstructionPPC64::GetOpcodeForInstruction(uint32_t opcode) { {0xfc000000, 0x38000000, &EmulateInstructionPPC64::EmulateADDI, "addi RT, RA, SI"}, {0xfc000003, 0xe8000000, &EmulateInstructionPPC64::EmulateLD, - "ld RT, DS(RA)"}}; + "ld RT, DS(RA)"}, +// {0xffff0003, 0x40820000, &EmulateInstructionPPC64::EmulateBNE, +// "bne TARGET"}, + {0xfc000002, 0x48000000, &EmulateInstructionPPC64::EmulateB, + "b TARGET"}, + {0xfc000003, 0x48000002, &EmulateInstructionPPC64::EmulateBA, + "ba TARGET"}, + {0xfc000003, 0x48000003, &EmulateInstructionPPC64::EmulateBLA, + "bla TARGET"}, + {0xfc000002, 0x40000000, &EmulateInstructionPPC64::EmulateBC, + "bc BO,BI,TARGET"}, + {0xfc000002, 0x40000002, &EmulateInstructionPPC64::EmulateBCA, + "bca BO,BI,TARGET"}, + {0xfc0007fe, 0x4c000020, &EmulateInstructionPPC64::EmulateBCLR, + "bclr BO,BI,BH"}, + {0xfc0007fe, 0x4c000420, &EmulateInstructionPPC64::EmulateBCCTR, + "bcctr BO,BI,BH"}, + {0xfc0007fe, 0x4c000460, &EmulateInstructionPPC64::EmulateBCTAR, + "bctar BO,BI,BH"}}; static const size_t k_num_ppc_opcodes = std::size(g_opcodes); for (size_t i = 0; i < k_num_ppc_opcodes; ++i) { @@ -169,12 +187,13 @@ bool EmulateInstructionPPC64::EvaluateInstruction(uint32_t evaluate_options) { bool success = false; - uint32_t orig_pc_value = 0; + uint64_t orig_pc_value = 0; if (auto_advance_pc) { orig_pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); if (!success) return false; + LLDB_LOG(GetLog(LLDBLog::Unwind), "orig_pc_value:{0}", orig_pc_value); } // Call the Emulate... function. @@ -183,11 +202,13 @@ bool EmulateInstructionPPC64::EvaluateInstruction(uint32_t evaluate_options) { return false; if (auto_advance_pc) { - uint32_t new_pc_value = + uint64_t new_pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); if (!success) return false; + LLDB_LOG(GetLog(LLDBLog::Unwind), "new_pc_value:{0}", new_pc_value); + if (new_pc_value == orig_pc_value) { EmulateInstruction::Context context; context.type = eContextAdvancePC; @@ -389,5 +410,174 @@ bool EmulateInstructionPPC64::EmulateADDI(uint32_t opcode) { return false; WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_r1_ppc64le, r1 + si_val); LLDB_LOG(log, "EmulateADDI: success!"); + + // FIX the next-pc + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + + return true; +} + +bool EmulateInstructionPPC64::EmulateBC(uint32_t opcode) { + // FIXME:32bit M + uint32_t M = 0; + uint32_t target32 = Bits32(opcode, 15, 2) << 2; + uint64_t target = (uint64_t)target32 + ((target32 & 0x8000) ? 0xffffffffffff0000UL : 0); + uint32_t BO = Bits32(opcode, 25, 21); + bool success; + uint64_t ctr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success); + if ((~BO) & (1U << 2)) + ctr_value = ctr_value - 1; + bool ctr_ok = (bool)(BO & (1U << 2)) | ((bool)(ctr_value != 0) ^ (bool)(BO & (1U << 1))); + uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success); + uint32_t BI = Bits32(opcode, 20, 16); + bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U)); + + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + if (ctr_ok & cond_ok) + next_pc = pc_value + target; + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + Log *log = GetLog(LLDBLog::Unwind); + LLDB_LOG(log, "EmulateBC: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBCA(uint32_t opcode) { + // FIXME:32bit M + uint32_t M = 0; + uint32_t target32 = Bits32(opcode, 15, 2) << 2; + uint64_t target = (uint64_t)target32 + ((target32 & 0x8000) ? 0xffffffffffff0000UL : 0); + uint32_t BO = Bits32(opcode, 25, 21); + bool success; + uint64_t ctr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success); + if ((~BO) & (1U << 2)) + ctr_value = ctr_value - 1; + bool ctr_ok = (bool)(BO & (1U << 2)) | ((bool)(ctr_value != 0) ^ (bool)(BO & (1U << 1))); + uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success); + uint32_t BI = Bits32(opcode, 20, 16); + bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U)); + + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + if (ctr_ok & cond_ok) + next_pc = target; + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + Log *log = GetLog(LLDBLog::Unwind); + LLDB_LOG(log, "EmulateBCA: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBCLR(uint32_t opcode) { + // FIXME:32bit M + uint32_t M = 0; + uint32_t BO = Bits32(opcode, 25, 21); + bool success; + uint64_t ctr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success); + if ((~BO) & (1U << 2)) + ctr_value = ctr_value - 1; + bool ctr_ok = (bool)(BO & (1U << 2)) | ((bool)(ctr_value != 0) ^ (bool)(BO & (1U << 1))); + uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success); + uint32_t BI = Bits32(opcode, 20, 16); + bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U)); + + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + if (ctr_ok & cond_ok) { + next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success); + next_pc &= ~((1UL << 2) - 1); + } + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + Log *log = GetLog(LLDBLog::Unwind); + LLDB_LOG(log, "EmulateBCLR: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBCCTR(uint32_t opcode) { + // FIXME:32bit M + uint32_t M = 0; + uint32_t BO = Bits32(opcode, 25, 21); + bool success; + uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success); + uint32_t BI = Bits32(opcode, 20, 16); + bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U)); + + Log *log = GetLog(LLDBLog::Unwind); + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + if (cond_ok) { + next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success); + next_pc &= ~((1UL << 2) - 1); + if (next_pc < 0x4000000) { + LLDB_LOGF(log, "EmulateBCCTR: next address %lx out of range, emulate by goto LR!"); + next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success); + } + } + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + LLDB_LOG(log, "EmulateBCCTR: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBCTAR(uint32_t opcode) { + // Not supported yet. + LLDB_LOG(GetLog(LLDBLog::Unwind), "EmulateBCTAR: not supported!"); + assert(0); + return false; +} + +bool EmulateInstructionPPC64::EmulateB(uint32_t opcode) { + uint32_t target32 = Bits32(opcode, 25, 2) << 2; + uint64_t target = (uint64_t)target32 + ((target32 & 0x2000000) ? 0xfffffffffc000000UL : 0); + + bool success; + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + target; + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + Log *log = GetLog(LLDBLog::Unwind); + LLDB_LOG(log, "EmulateB: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBA(uint32_t opcode) { + Log *log = GetLog(LLDBLog::Unwind); + + bool success; + uint64_t next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success); + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + LLDB_LOG(log, "EmulateBA: emulate by branch to lr!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBLA(uint32_t opcode) { + Log *log = GetLog(LLDBLog::Unwind); + + bool success; + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + LLDB_LOG(log, "EmulateBLA: emulate by branch to lr!"); return true; } diff --git a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h index a9424f16b0ad0..1576c9700e557 100644 --- a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h +++ b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h @@ -39,6 +39,12 @@ class EmulateInstructionPPC64 : public EmulateInstruction { return true; case eInstructionTypePCModifying: +#if defined(__AIX__) + return true; +#else + return false; +#endif + case eInstructionTypeAll: return false; } @@ -84,6 +90,14 @@ class EmulateInstructionPPC64 : public EmulateInstruction { bool EmulateSTD(uint32_t opcode); bool EmulateOR(uint32_t opcode); bool EmulateADDI(uint32_t opcode); + bool EmulateB(uint32_t opcode); + bool EmulateBA(uint32_t opcode); + bool EmulateBLA(uint32_t opcode); + bool EmulateBC(uint32_t opcode); + bool EmulateBCA(uint32_t opcode); + bool EmulateBCLR(uint32_t opcode); + bool EmulateBCCTR(uint32_t opcode); + bool EmulateBCTAR(uint32_t opcode); }; } // namespace lldb_private diff --git a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp index b7cd2b1ac6bf6..876e74056face 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp @@ -261,7 +261,7 @@ InstrumentationRuntimeMainThreadChecker::GetBacktracesFromExtendedStopInfo( StructuredData::ObjectSP thread_id_obj = info->GetObjectForDotSeparatedPath("tid"); - tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; + lldb::tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; // We gather symbolication addresses above, so no need for HistoryThread to // try to infer the call addresses. diff --git a/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp b/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp index b2781aa5e7db1..7a827a3ea76f9 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp @@ -770,13 +770,13 @@ std::string InstrumentationRuntimeTSan::GetLocationDescription( Sprintf("Location is a %ld-byte heap object at 0x%llx", size, addr); } } else if (type == "stack") { - tid_t tid = loc->GetAsDictionary() + lldb::tid_t tid = loc->GetAsDictionary() ->GetValueForKey("thread_id") ->GetUnsignedIntegerValue(); result = Sprintf("Location is stack of thread %d", tid); } else if (type == "tls") { - tid_t tid = loc->GetAsDictionary() + lldb::tid_t tid = loc->GetAsDictionary() ->GetValueForKey("thread_id") ->GetUnsignedIntegerValue(); @@ -948,7 +948,7 @@ static std::string GenerateThreadName(const std::string &path, if (path == "mops") { size_t size = o->GetObjectForDotSeparatedPath("size")->GetUnsignedIntegerValue(); - tid_t thread_id = + lldb::tid_t thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); bool is_write = o->GetObjectForDotSeparatedPath("is_write")->GetBooleanValue(); @@ -979,7 +979,7 @@ static std::string GenerateThreadName(const std::string &path, } if (path == "threads") { - tid_t thread_id = + lldb::tid_t thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); result = Sprintf("Thread %zu created", thread_id); } @@ -987,7 +987,7 @@ static std::string GenerateThreadName(const std::string &path, if (path == "locs") { std::string type = std::string( o->GetAsDictionary()->GetValueForKey("type")->GetStringValue()); - tid_t thread_id = + lldb::tid_t thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); int fd = o->GetObjectForDotSeparatedPath("file_descriptor") ->GetSignedIntegerValue(); @@ -1007,7 +1007,7 @@ static std::string GenerateThreadName(const std::string &path, } if (path == "stacks") { - tid_t thread_id = + lldb::tid_t thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); result = Sprintf("Thread %" PRIu64, thread_id); } @@ -1034,7 +1034,7 @@ static void AddThreadsForPath(const std::string &path, StructuredData::ObjectSP thread_id_obj = o->GetObjectForDotSeparatedPath("thread_os_id"); - tid_t tid = + lldb::tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; ThreadSP new_thread_sp = diff --git a/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp index 1c58922e8d36c..de9719ad4a89e 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp @@ -321,7 +321,7 @@ InstrumentationRuntimeUBSan::GetBacktracesFromExtendedStopInfo( StructuredData::ObjectSP thread_id_obj = info->GetObjectForDotSeparatedPath("tid"); - tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; + lldb::tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; // We gather symbolication addresses above, so no need for HistoryThread to // try to infer the call addresses. diff --git a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp index 1688fb27430a7..690fb0d60a09a 100644 --- a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp +++ b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp @@ -194,6 +194,10 @@ void JITLoaderGDB::SetJITBreakpoint(lldb_private::ModuleList &module_list) { if (jit_addr == LLDB_INVALID_ADDRESS) return; +#if defined(__AIX__) + return; +#endif + m_jit_descriptor_addr = GetSymbolAddress( module_list, ConstString("__jit_debug_descriptor"), eSymbolTypeData); if (m_jit_descriptor_addr == LLDB_INVALID_ADDRESS) { diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index 341923108e321..fb5bc2c58e6fb 100644 --- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -1227,6 +1227,7 @@ bool lldb_private::formatters::ObjCSELSummaryProvider( time_t lldb_private::formatters::GetOSXEpoch() { static time_t epoch = 0; if (!epoch) { +#if !defined(__AIX__) #ifndef _WIN32 tzset(); tm tm_epoch; @@ -1240,6 +1241,7 @@ time_t lldb_private::formatters::GetOSXEpoch() { tm_epoch.tm_gmtoff = 0; tm_epoch.tm_zone = nullptr; epoch = timegm(&tm_epoch); +#endif #endif } return epoch; diff --git a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp index 6efd2516578ff..fe6c5a0544be3 100644 --- a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp +++ b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp @@ -107,7 +107,7 @@ static void CreateHistoryThreadFromValueObject(ProcessSP process_sp, return; int count = count_sp->GetValueAsUnsigned(0); - tid_t tid = tid_sp->GetValueAsUnsigned(0) + 1; + lldb::tid_t tid = tid_sp->GetValueAsUnsigned(0) + 1; if (count <= 0) return; diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 7aa5b8d81890a..5ea55772c3aba 100644 --- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -8,7 +8,7 @@ #include "ObjectContainerBSDArchive.h" -#if defined(_WIN32) || defined(__ANDROID__) +#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__) // Defines from ar, missing on Windows #define SARMAG 8 #define ARFMAG "`\n" diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt b/lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt new file mode 100644 index 0000000000000..612a36265b536 --- /dev/null +++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt @@ -0,0 +1,10 @@ +add_lldb_library(lldbPluginObjectContainerBigArchive PLUGIN + ObjectContainerBigArchive.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp new file mode 100644 index 0000000000000..050ad73f1d19a --- /dev/null +++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp @@ -0,0 +1,522 @@ +//===-- ObjectContainerBigArchive.cpp -------------------------------------===// +// +// 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 "ObjectContainerBigArchive.h" + +#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__) +// Defines from ar, missing on Windows +#define ARMAG "!\n" +#define SARMAG 8 +#define ARFMAG "`\n" + +typedef struct ar_hdr { + char ar_name[16]; + char ar_date[12]; + char ar_uid[6], ar_gid[6]; + char ar_mode[8]; + char ar_size[10]; + char ar_fmag[2]; +} ar_hdr; +#else +#include +#endif + +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/Timer.h" + +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Object/Archive.h" +#include "llvm/Support/Chrono.h" + +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ObjectContainerBigArchive) + +ObjectContainerBigArchive::Object::Object() : ar_name() {} + +void ObjectContainerBigArchive::Object::Clear() { + ar_name.Clear(); + modification_time = 0; + uid = 0; + gid = 0; + mode = 0; + size = 0; + file_offset = 0; + file_size = 0; +} + +lldb::offset_t +ObjectContainerBigArchive::Object::Extract(const DataExtractor &data, + lldb::offset_t offset) { + size_t ar_name_len = 0; + std::string str; + char *err; + + // File header + // + // The common format is as follows. + // + // Offset Length Name Format + // 0 16 File name ASCII right padded with spaces (no spaces + // allowed in file name) + // 16 12 File mod Decimal as cstring right padded with + // spaces + // 28 6 Owner ID Decimal as cstring right padded with + // spaces + // 34 6 Group ID Decimal as cstring right padded with + // spaces + // 40 8 File mode Octal as cstring right padded with + // spaces + // 48 10 File byte size Decimal as cstring right padded with + // spaces + // 58 2 File magic 0x60 0x0A + + // Make sure there is enough data for the file header and bail if not + if (!data.ValidOffsetForDataOfSize(offset, 60)) + return LLDB_INVALID_OFFSET; + + str.assign((const char *)data.GetData(&offset, 16), 16); + if (llvm::StringRef(str).starts_with("#1/")) { + // If the name is longer than 16 bytes, or contains an embedded space then + // it will use this format where the length of the name is here and the + // name characters are after this header. + ar_name_len = strtoul(str.c_str() + 3, &err, 10); + } else { + // Strip off any trailing spaces. + const size_t last_pos = str.find_last_not_of(' '); + if (last_pos != std::string::npos) { + if (last_pos + 1 < 16) + str.erase(last_pos + 1); + } + ar_name.SetCString(str.c_str()); + } + + str.assign((const char *)data.GetData(&offset, 12), 12); + modification_time = strtoul(str.c_str(), &err, 10); + + str.assign((const char *)data.GetData(&offset, 6), 6); + uid = strtoul(str.c_str(), &err, 10); + + str.assign((const char *)data.GetData(&offset, 6), 6); + gid = strtoul(str.c_str(), &err, 10); + + str.assign((const char *)data.GetData(&offset, 8), 8); + mode = strtoul(str.c_str(), &err, 8); + + str.assign((const char *)data.GetData(&offset, 10), 10); + size = strtoul(str.c_str(), &err, 10); + + str.assign((const char *)data.GetData(&offset, 2), 2); + if (str == ARFMAG) { + if (ar_name_len > 0) { + const void *ar_name_ptr = data.GetData(&offset, ar_name_len); + // Make sure there was enough data for the string value and bail if not + if (ar_name_ptr == nullptr) + return LLDB_INVALID_OFFSET; + str.assign((const char *)ar_name_ptr, ar_name_len); + ar_name.SetCString(str.c_str()); + } + file_offset = offset; + file_size = size - ar_name_len; + return offset; + } + return LLDB_INVALID_OFFSET; +} + +ObjectContainerBigArchive::Archive::Archive(const lldb_private::ArchSpec &arch, + const llvm::sys::TimePoint<> &time, + lldb::offset_t file_offset, + lldb_private::DataExtractor &data) + : m_arch(arch), m_modification_time(time), m_file_offset(file_offset), + m_objects(), m_data(data) {} + +ObjectContainerBigArchive::Archive::~Archive() = default; + +size_t ObjectContainerBigArchive::Archive::ParseObjects() { + DataExtractor &data = m_data; + std::string str; + lldb::offset_t offset = 0; + str.assign((const char *)data.GetData(&offset, (sizeof(llvm::object::BigArchiveMagic) - 1)), + (sizeof(llvm::object::BigArchiveMagic) - 1)); + if (str == llvm::object::BigArchiveMagic) { + llvm::Error err = llvm::Error::success(); + llvm::object::BigArchive bigAr(llvm::MemoryBufferRef(toStringRef(m_data.GetData()), llvm::StringRef("")), err); + if (err) + return 0; + + for (const llvm::object::Archive::Child &child : bigAr.children(err)) { + if (err) + continue; + if (!child.getParent()) + continue; + Object obj; + obj.Clear(); + // FIXME: check errors + llvm::Expected childNameOrErr = child.getName(); + if (!childNameOrErr) + continue; + obj.ar_name.SetCString(childNameOrErr->str().c_str()); + llvm::Expected> lastModifiedOrErr = child.getLastModified(); + if (!lastModifiedOrErr) + continue; + obj.modification_time = (uint32_t)llvm::sys::toTimeT(*(lastModifiedOrErr)); + llvm::Expected getUIDOrErr = child.getUID(); + if (!getUIDOrErr) + continue; + obj.uid = (uint16_t)*getUIDOrErr; + llvm::Expected getGIDOrErr = child.getGID(); + if (!getGIDOrErr) + continue; + obj.gid = (uint16_t)*getGIDOrErr; + llvm::Expected getAccessModeOrErr = child.getAccessMode(); + if (!getAccessModeOrErr) + continue; + obj.mode = (uint16_t)*getAccessModeOrErr; + llvm::Expected getRawSizeOrErr = child.getRawSize(); + if (!getRawSizeOrErr) + continue; + obj.size = (uint32_t)*getRawSizeOrErr; + + obj.file_offset = (lldb::offset_t)child.getDataOffset(); + + llvm::Expected getSizeOrErr = child.getSize(); + if (!getSizeOrErr) + continue; + obj.file_size = (lldb::offset_t)*getSizeOrErr; + + size_t obj_idx = m_objects.size(); + m_objects.push_back(obj); + // Insert all of the C strings out of order for now... + m_object_name_to_index_map.Append(obj.ar_name, obj_idx); + } + if (err) + return 0; + + // Now sort all of the object name pointers + m_object_name_to_index_map.Sort(); + } + return m_objects.size(); +} + +ObjectContainerBigArchive::Object * +ObjectContainerBigArchive::Archive::FindObject( + ConstString object_name, const llvm::sys::TimePoint<> &object_mod_time) { + const ObjectNameToIndexMap::Entry *match = + m_object_name_to_index_map.FindFirstValueForName(object_name); + if (!match) + return nullptr; + if (object_mod_time == llvm::sys::TimePoint<>()) + return &m_objects[match->value]; + + const uint64_t object_modification_date = llvm::sys::toTimeT(object_mod_time); + if (m_objects[match->value].modification_time == object_modification_date) + return &m_objects[match->value]; + + const ObjectNameToIndexMap::Entry *next_match = + m_object_name_to_index_map.FindNextValueForName(match); + while (next_match) { + if (m_objects[next_match->value].modification_time == + object_modification_date) + return &m_objects[next_match->value]; + next_match = m_object_name_to_index_map.FindNextValueForName(next_match); + } + + return nullptr; +} + +ObjectContainerBigArchive::Archive::shared_ptr +ObjectContainerBigArchive::Archive::FindCachedArchive( + const FileSpec &file, const ArchSpec &arch, + const llvm::sys::TimePoint<> &time, lldb::offset_t file_offset) { + std::lock_guard guard(Archive::GetArchiveCacheMutex()); + shared_ptr archive_sp; + Archive::Map &archive_map = Archive::GetArchiveCache(); + Archive::Map::iterator pos = archive_map.find(file); + // Don't cache a value for "archive_map.end()" below since we might delete an + // archive entry... + while (pos != archive_map.end() && pos->first == file) { + bool match = true; + if (arch.IsValid() && + !pos->second->GetArchitecture().IsCompatibleMatch(arch)) + match = false; + else if (file_offset != LLDB_INVALID_OFFSET && + pos->second->GetFileOffset() != file_offset) + match = false; + if (match) { + if (pos->second->GetModificationTime() == time) { + return pos->second; + } else { + // We have a file at the same path with the same architecture whose + // modification time doesn't match. It doesn't make sense for us to + // continue to use this Big archive since we cache only the object info + // which consists of file time info and also the file offset and file + // size of any contained objects. Since this information is now out of + // date, we won't get the correct information if we go and extract the + // file data, so we should remove the old and outdated entry. + archive_map.erase(pos); + pos = archive_map.find(file); + continue; // Continue to next iteration so we don't increment pos + // below... + } + } + ++pos; + } + return archive_sp; +} + +ObjectContainerBigArchive::Archive::shared_ptr +ObjectContainerBigArchive::Archive::ParseAndCacheArchiveForFile( + const FileSpec &file, const ArchSpec &arch, + const llvm::sys::TimePoint<> &time, lldb::offset_t file_offset, + DataExtractor &data) { + shared_ptr archive_sp(new Archive(arch, time, file_offset, data)); + if (archive_sp) { + const size_t num_objects = archive_sp->ParseObjects(); + if (num_objects > 0) { + std::lock_guard guard( + Archive::GetArchiveCacheMutex()); + Archive::GetArchiveCache().insert(std::make_pair(file, archive_sp)); + } else { + archive_sp.reset(); + } + } + return archive_sp; +} + +ObjectContainerBigArchive::Archive::Map & +ObjectContainerBigArchive::Archive::GetArchiveCache() { + static Archive::Map g_archive_map; + return g_archive_map; +} + +std::recursive_mutex & +ObjectContainerBigArchive::Archive::GetArchiveCacheMutex() { + static std::recursive_mutex g_archive_map_mutex; + return g_archive_map_mutex; +} + +void ObjectContainerBigArchive::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + GetModuleSpecifications); +} + +void ObjectContainerBigArchive::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ObjectContainer *ObjectContainerBigArchive::CreateInstance( + const lldb::ModuleSP &module_sp, DataBufferSP &data_sp, + lldb::offset_t data_offset, const FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length) { + ConstString object_name(module_sp->GetObjectName()); + if (!object_name) + return nullptr; + + if (data_sp) { + // We have data, which means this is the first 512 bytes of the file Check + // to see if the magic bytes match and if they do, read the entire table of + // contents for the archive and cache it + DataExtractor data; + data.SetData(data_sp, data_offset, length); + if (file && data_sp && ObjectContainerBigArchive::MagicBytesMatch(data)) { + LLDB_SCOPED_TIMERF( + "ObjectContainerBigArchive::CreateInstance (module = %s, file = " + "%p, file_offset = 0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")", + module_sp->GetFileSpec().GetPath().c_str(), + static_cast(file), static_cast(file_offset), + static_cast(length)); + + // Map the entire .a file to be sure that we don't lose any data if the + // file gets updated by a new build while this .a file is being used for + // debugging + DataBufferSP archive_data_sp = + FileSystem::Instance().CreateDataBuffer(*file, length, file_offset); + if (!archive_data_sp) + return nullptr; + + lldb::offset_t archive_data_offset = 0; + + Archive::shared_ptr archive_sp(Archive::FindCachedArchive( + *file, module_sp->GetArchitecture(), module_sp->GetModificationTime(), + file_offset)); + std::unique_ptr container_up( + new ObjectContainerBigArchive(module_sp, archive_data_sp, + archive_data_offset, file, file_offset, + length)); + + if (container_up) { + if (archive_sp) { + // We already have this archive in our cache, use it + container_up->SetArchive(archive_sp); + return container_up.release(); + } else if (container_up->ParseHeader()) + return container_up.release(); + } + } + } else { + // No data, just check for a cached archive + Archive::shared_ptr archive_sp(Archive::FindCachedArchive( + *file, module_sp->GetArchitecture(), module_sp->GetModificationTime(), + file_offset)); + if (archive_sp) { + std::unique_ptr container_up( + new ObjectContainerBigArchive(module_sp, data_sp, data_offset, file, + file_offset, length)); + + if (container_up) { + // We already have this archive in our cache, use it + container_up->SetArchive(archive_sp); + return container_up.release(); + } + } + } + return nullptr; +} + +bool ObjectContainerBigArchive::MagicBytesMatch(const DataExtractor &data) { + uint32_t offset = 0; + const char *armag = (const char *)data.PeekData(offset, (sizeof(llvm::object::BigArchiveMagic) - 1)); + if (armag && ::strncmp(armag, llvm::object::BigArchiveMagic, (sizeof(llvm::object::BigArchiveMagic) - 1)) == 0) + return true; + return false; +} + +ObjectContainerBigArchive::ObjectContainerBigArchive( + const lldb::ModuleSP &module_sp, DataBufferSP &data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t size) + : ObjectContainer(module_sp, file, file_offset, size, data_sp, data_offset), + m_archive_sp() {} +void ObjectContainerBigArchive::SetArchive(Archive::shared_ptr &archive_sp) { + m_archive_sp = archive_sp; +} + +ObjectContainerBigArchive::~ObjectContainerBigArchive() = default; + +bool ObjectContainerBigArchive::ParseHeader() { + if (m_archive_sp.get() == nullptr) { + if (m_data.GetByteSize() > 0) { + ModuleSP module_sp(GetModule()); + if (module_sp) { + m_archive_sp = Archive::ParseAndCacheArchiveForFile( + m_file, module_sp->GetArchitecture(), + module_sp->GetModificationTime(), m_offset, m_data); + } + // Clear the m_data that contains the entire archive data and let our + // m_archive_sp hold onto the data. + m_data.Clear(); + } + } + return m_archive_sp.get() != nullptr; +} + +void ObjectContainerBigArchive::Object::Dump(Stream *s) const { + printf("name = \"%s\"\n", ar_name.GetCString()); + printf("mtime = 0x%8.8" PRIx32 "\n", modification_time); + printf("size = 0x%8.8" PRIx32 " (%" PRIu32 ")\n", size, size); + printf("file_offset = 0x%16.16" PRIx64 " (%" PRIu64 ")\n", file_offset, + file_offset); + printf("file_size = 0x%16.16" PRIx64 " (%" PRIu64 ")\n\n", file_size, + file_size); +} + +ObjectFileSP ObjectContainerBigArchive::GetObjectFile(const FileSpec *file) { + ModuleSP module_sp(GetModule()); + if (module_sp) { + if (module_sp->GetObjectName() && m_archive_sp) { + Object *object = m_archive_sp->FindObject( + module_sp->GetObjectName(), module_sp->GetObjectModificationTime()); + if (object) { + lldb::offset_t data_offset = object->file_offset; + return ObjectFile::FindPlugin( + module_sp, file, m_offset + object->file_offset, object->file_size, + m_archive_sp->GetData().GetSharedDataBuffer(), data_offset); + } + } + } + return ObjectFileSP(); +} + +size_t ObjectContainerBigArchive::GetModuleSpecifications( + const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, lldb::offset_t file_offset, + lldb::offset_t file_size, lldb_private::ModuleSpecList &specs) { + + // We have data, which means this is the first 512 bytes of the file Check to + // see if the magic bytes match and if they do, read the entire table of + // contents for the archive and cache it + DataExtractor data; + data.SetData(data_sp, data_offset, data_sp->GetByteSize()); + if (!file || !data_sp || !ObjectContainerBigArchive::MagicBytesMatch(data)) + return 0; + + const size_t initial_count = specs.GetSize(); + llvm::sys::TimePoint<> file_mod_time = FileSystem::Instance().GetModificationTime(file); + Archive::shared_ptr archive_sp( + Archive::FindCachedArchive(file, ArchSpec(), file_mod_time, file_offset)); + bool set_archive_arch = false; + if (!archive_sp) { + set_archive_arch = true; + data_sp = + FileSystem::Instance().CreateDataBuffer(file, file_size, file_offset); + if (data_sp) { + data.SetData(data_sp, 0, data_sp->GetByteSize()); + archive_sp = Archive::ParseAndCacheArchiveForFile( + file, ArchSpec(), file_mod_time, file_offset, data); + } + } + + if (archive_sp) { + const size_t num_objects = archive_sp->GetNumObjects(); + for (size_t idx = 0; idx < num_objects; ++idx) { + const Object *object = archive_sp->GetObjectAtIndex(idx); + if (object) { + 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( + file, object_file_offset, file_size - object_file_offset, + specs)) { + ModuleSpec &spec = + specs.GetModuleSpecRefAtIndex(specs.GetSize() - 1); + llvm::sys::TimePoint<> object_mod_time( + std::chrono::seconds(object->modification_time)); + spec.GetObjectName() = object->ar_name; + spec.SetObjectOffset(object_file_offset); + spec.SetObjectSize(file_size - object_file_offset); + spec.GetObjectModificationTime() = object_mod_time; + } + } + } + } + } + const size_t end_count = specs.GetSize(); + size_t num_specs_added = end_count - initial_count; + if (set_archive_arch && num_specs_added > 0) { + // The archive was created but we didn't have an architecture so we need to + // set it + for (size_t i = initial_count; i < end_count; ++i) { + ModuleSpec module_spec; + if (specs.GetModuleSpecAtIndex(i, module_spec)) { + if (module_spec.GetArchitecture().IsValid()) { + archive_sp->SetArchitecture(module_spec.GetArchitecture()); + break; + } + } + } + } + return num_specs_added; +} diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h new file mode 100644 index 0000000000000..ad9b814048a87 --- /dev/null +++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h @@ -0,0 +1,177 @@ +//===-- ObjectContainerBigArchive.h -----------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BIG_ARCHIVE_OBJECTCONTAINERBIGARCHIVE_H +#define LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BIG_ARCHIVE_OBJECTCONTAINERBIGARCHIVE_H + +#include "lldb/Core/UniqueCStringMap.h" +#include "lldb/Symbol/ObjectContainer.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/FileSpec.h" + +#include "llvm/Support/Chrono.h" + +#include +#include +#include + +class ObjectContainerBigArchive : public lldb_private::ObjectContainer { +public: + ObjectContainerBigArchive(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + ~ObjectContainerBigArchive() override; + + // Static Functions + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "big-archive"; } + + static llvm::StringRef GetPluginDescriptionStatic() { + return "Big Archive object container reader."; + } + + static lldb_private::ObjectContainer * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + static size_t GetModuleSpecifications(const lldb_private::FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + lldb_private::ModuleSpecList &specs); + + static bool MagicBytesMatch(const lldb_private::DataExtractor &data); + + // Member Functions + bool ParseHeader() override; + + size_t GetNumObjects() const override { + if (m_archive_sp) + return m_archive_sp->GetNumObjects(); + return 0; + } + + lldb::ObjectFileSP GetObjectFile(const lldb_private::FileSpec *file) override; + + // PluginInterface protocol + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + +protected: + struct Object { + Object(); + + void Clear(); + + lldb::offset_t Extract(const lldb_private::DataExtractor &data, + lldb::offset_t offset); + /// Object name in the archive. + lldb_private::ConstString ar_name; + + /// Object modification time in the archive. + uint32_t modification_time = 0; + + /// Object user id in the archive. + uint16_t uid = 0; + + /// Object group id in the archive. + uint16_t gid = 0; + + /// Object octal file permissions in the archive. + uint16_t mode = 0; + + /// Object size in bytes in the archive. + uint32_t size = 0; + + /// File offset in bytes from the beginning of the file of the object data. + lldb::offset_t file_offset = 0; + + /// Length of the object data. + lldb::offset_t file_size = 0; + + void Dump(lldb_private::Stream *s) const; + }; + + class Archive { + public: + typedef std::shared_ptr shared_ptr; + typedef std::multimap Map; + + Archive(const lldb_private::ArchSpec &arch, + const llvm::sys::TimePoint<> &mod_time, lldb::offset_t file_offset, + lldb_private::DataExtractor &data); + + ~Archive(); + + static Map &GetArchiveCache(); + + static std::recursive_mutex &GetArchiveCacheMutex(); + + static Archive::shared_ptr FindCachedArchive( + const lldb_private::FileSpec &file, const lldb_private::ArchSpec &arch, + const llvm::sys::TimePoint<> &mod_time, lldb::offset_t file_offset); + + static Archive::shared_ptr ParseAndCacheArchiveForFile( + const lldb_private::FileSpec &file, const lldb_private::ArchSpec &arch, + const llvm::sys::TimePoint<> &mod_time, lldb::offset_t file_offset, + lldb_private::DataExtractor &data); + + size_t GetNumObjects() const { return m_objects.size(); } + + const Object *GetObjectAtIndex(size_t idx) { + if (idx < m_objects.size()) + return &m_objects[idx]; + return nullptr; + } + + size_t ParseObjects(); + + Object *FindObject(lldb_private::ConstString object_name, + const llvm::sys::TimePoint<> &object_mod_time); + + lldb::offset_t GetFileOffset() const { return m_file_offset; } + + const llvm::sys::TimePoint<> &GetModificationTime() { + return m_modification_time; + } + + const lldb_private::ArchSpec &GetArchitecture() const { return m_arch; } + + void SetArchitecture(const lldb_private::ArchSpec &arch) { m_arch = arch; } + + bool HasNoExternalReferences() const; + + lldb_private::DataExtractor &GetData() { return m_data; } + + protected: + typedef lldb_private::UniqueCStringMap ObjectNameToIndexMap; + // Member Variables + lldb_private::ArchSpec m_arch; + llvm::sys::TimePoint<> m_modification_time; + lldb::offset_t m_file_offset; + std::vector m_objects; + ObjectNameToIndexMap m_object_name_to_index_map; + lldb_private::DataExtractor m_data; ///< The data for this object container + ///so we don't lose data if the .a files + ///gets modified + }; + + void SetArchive(Archive::shared_ptr &archive_sp); + + Archive::shared_ptr m_archive_sp; +}; + +#endif // LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BIG_ARCHIVE_OBJECTCONTAINERBIGARCHIVE_H diff --git a/lldb/source/Plugins/ObjectContainer/CMakeLists.txt b/lldb/source/Plugins/ObjectContainer/CMakeLists.txt index cda0c8151dd8a..2492798bb13ef 100644 --- a/lldb/source/Plugins/ObjectContainer/CMakeLists.txt +++ b/lldb/source/Plugins/ObjectContainer/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(BSD-Archive) +add_subdirectory(Big-Archive) add_subdirectory(Universal-Mach-O) add_subdirectory(Mach-O-Fileset) diff --git a/lldb/source/Plugins/ObjectFile/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/CMakeLists.txt index 773241c8944c8..7abd0c96f4fd7 100644 --- a/lldb/source/Plugins/ObjectFile/CMakeLists.txt +++ b/lldb/source/Plugins/ObjectFile/CMakeLists.txt @@ -6,5 +6,6 @@ add_subdirectory(Mach-O) add_subdirectory(Minidump) add_subdirectory(PDB) add_subdirectory(PECOFF) +add_subdirectory(XCOFF) add_subdirectory(Placeholder) add_subdirectory(wasm) diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index ce095bcc48374..bcb6330cbb1f9 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -5673,7 +5673,7 @@ bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &value, return false; } -bool ObjectFileMachO::GetCorefileThreadExtraInfos(std::vector &tids) { +bool ObjectFileMachO::GetCorefileThreadExtraInfos(std::vector &tids) { tids.clear(); ModuleSP module_sp(GetModule()); if (module_sp) { @@ -5724,8 +5724,8 @@ bool ObjectFileMachO::GetCorefileThreadExtraInfos(std::vector &tids) { return false; } StructuredData::Dictionary *thread = *maybe_thread; - tid_t tid = LLDB_INVALID_THREAD_ID; - if (thread->GetValueForKeyAsInteger("thread_id", tid)) + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; + if (thread->GetValueForKeyAsInteger("thread_id", tid)) if (tid == 0) tid = LLDB_INVALID_THREAD_ID; tids.push_back(tid); diff --git a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp index faa144bfb5f6a..d27cdfc60de85 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp +++ b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp @@ -51,7 +51,9 @@ size_t ObjectFileMinidump::GetModuleSpecifications( const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, lldb_private::ModuleSpecList &specs) { +#if !defined(__AIX__) specs.Clear(); +#endif return 0; } diff --git a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp index f0832dbf07347..75cc54e4f0d48 100644 --- a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp +++ b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp @@ -116,18 +116,31 @@ size_t ObjectFilePDB::GetModuleSpecifications( ModuleSpec module_spec(file); llvm::BumpPtrAllocator allocator; std::unique_ptr pdb_file = loadPDBFile(file.GetPath(), allocator); - if (!pdb_file) + if (!pdb_file){ +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif + } auto info_stream = pdb_file->getPDBInfoStream(); if (!info_stream) { llvm::consumeError(info_stream.takeError()); +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif } auto dbi_stream = pdb_file->getPDBDbiStream(); if (!dbi_stream) { llvm::consumeError(dbi_stream.takeError()); +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif } lldb_private::UUID &uuid = module_spec.GetUUID(); diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index bda691ade8af0..db8fa78043fdc 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -252,8 +252,13 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, lldb_private::ModuleSpecList &specs) { const size_t initial_count = specs.GetSize(); - if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp)) + if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp)){ +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif + } Log *log = GetLog(LLDBLog::Object); @@ -266,12 +271,21 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( if (!binary) { LLDB_LOG_ERROR(log, binary.takeError(), "Failed to create binary for file ({1}): {0}", file); +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif } auto *COFFObj = llvm::dyn_cast(binary->get()); - if (!COFFObj) + if (!COFFObj){ +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif + } ModuleSpec module_spec(file); ArchSpec &spec = module_spec.GetArchitecture(); diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt new file mode 100644 index 0000000000000..8840248574c88 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt @@ -0,0 +1,13 @@ +add_lldb_library(lldbPluginObjectFileXCOFF PLUGIN + ObjectFileXCOFF.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + lldbTarget + LINK_COMPONENTS + BinaryFormat + Object + Support + ) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp new file mode 100644 index 0000000000000..a4d9ea295b4c3 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -0,0 +1,780 @@ +//===-- ObjectFileXCOFF.cpp -------------------------------------------------===// +// +// 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 "ObjectFileXCOFF.h" + +#include +#include +#include +#include + +#include "lldb/Utility/FileSpecList.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Progress.h" +#include "lldb/Core/Section.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/LZMA.h" +#include "lldb/Symbol/DWARFCallFrameInfo.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RangeMap.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/Timer.h" +#include "llvm/ADT/IntervalMap.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/Object/Decompressor.h" +#include "llvm/Support/CRC.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Object/XCOFFObjectFile.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ObjectFileXCOFF) + +char ObjectFileXCOFF::ID; + +// FIXME: target 64bit at this moment. + +// Static methods. +void ObjectFileXCOFF::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + CreateMemoryInstance, GetModuleSpecifications); +} + +void ObjectFileXCOFF::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; + +ObjectFile *ObjectFileXCOFF::CreateInstance(const lldb::ModuleSP &module_sp, + DataBufferSP data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t file_offset, + lldb::offset_t length) { + if (!data_sp) { + data_sp = MapFileData(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + } + + if (!ObjectFileXCOFF::MagicBytesMatch(data_sp, data_offset, length)) + return nullptr; + + // Update the data to contain the entire file if it doesn't already + if (data_sp->GetByteSize() < length) { + data_sp = MapFileData(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + } + auto objfile_up = std::make_unique( + module_sp, data_sp, data_offset, file, file_offset, length); + if (!objfile_up) + return nullptr; + + // Cache xcoff binary. + if (!objfile_up->CreateBinary()) + return nullptr; + + if (!objfile_up->ParseHeader()) + //FIXME objfile leak + return nullptr; + + UGLY_FLAG_FOR_AIX = true; + return objfile_up.release(); +} + +bool ObjectFileXCOFF::CreateBinary() { + if (m_binary) + return true; + + Log *log = GetLog(LLDBLog::Object); + + auto binary = llvm::object::XCOFFObjectFile::createObjectFile(llvm::MemoryBufferRef( + toStringRef(m_data.GetData()), m_file.GetFilename().GetStringRef()), + file_magic::xcoff_object_64); + if (!binary) { + LLDB_LOG_ERROR(log, binary.takeError(), + "Failed to create binary for file ({1}): {0}", m_file); + return false; + } + + // Make sure we only handle COFF format. + m_binary = + llvm::unique_dyn_cast(std::move(*binary)); + if (!m_binary) + return false; + + LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}", + this, GetModule().get(), GetModule()->GetSpecificationDescription(), + m_file.GetPath(), m_binary.get()); + return true; +} + +ObjectFile *ObjectFileXCOFF::CreateMemoryInstance( + const lldb::ModuleSP &module_sp, WritableDataBufferSP data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) { + return nullptr; +} + +size_t ObjectFileXCOFF::GetModuleSpecifications( + const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, lldb::offset_t file_offset, + lldb::offset_t length, lldb_private::ModuleSpecList &specs) { + const size_t initial_count = specs.GetSize(); + + if (ObjectFileXCOFF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) { + ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + ModuleSpec spec(file, arch_spec); + spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX); + specs.Append(spec); + } + return specs.GetSize() - initial_count; +} + +static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) { + switch (magic) { + /* TODO: 32bit not supported yet + case XCOFF::XCOFF32: + return sizeof(struct llvm::object::XCOFFFileHeader32); + */ + + case XCOFF::XCOFF64: + return sizeof(struct llvm::object::XCOFFFileHeader64); + break; + + default: + break; + } + return 0; +} + +bool ObjectFileXCOFF::MagicBytesMatch(DataBufferSP &data_sp, + lldb::addr_t data_offset, + lldb::addr_t data_length) { + lldb_private::DataExtractor data; + data.SetData(data_sp, data_offset, data_length); + lldb::offset_t offset = 0; + uint16_t magic = data.GetU16(&offset); + return XCOFFHeaderSizeFromMagic(magic) != 0; +} + +bool ObjectFileXCOFF::ParseHeader() { + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard guard(module_sp->GetMutex()); + m_sect_headers.clear(); + lldb::offset_t offset = 0; + + if (ParseXCOFFHeader(m_data, &offset, m_xcoff_header)) { + m_data.SetAddressByteSize(GetAddressByteSize()); + if (m_xcoff_header.auxhdrsize > 0) + ParseXCOFFOptionalHeader(m_data, &offset); + ParseSectionHeaders(offset); + } + return true; + } + + return false; +} + +bool ObjectFileXCOFF::ParseXCOFFHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + xcoff_header_t &xcoff_header) { + //FIXME: data.ValidOffsetForDataOfSize + xcoff_header.magic = data.GetU16(offset_ptr); + xcoff_header.nsects = data.GetU16(offset_ptr); + xcoff_header.modtime = data.GetU32(offset_ptr); + xcoff_header.symoff = data.GetU64(offset_ptr); + xcoff_header.auxhdrsize = data.GetU16(offset_ptr); + xcoff_header.flags = data.GetU16(offset_ptr); + xcoff_header.nsyms = data.GetU32(offset_ptr); + return true; +} + +bool ObjectFileXCOFF::ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr) { + lldb::offset_t init_offset = *offset_ptr; + //FIXME: data.ValidOffsetForDataOfSize + m_xcoff_aux_header.AuxMagic = data.GetU16(offset_ptr); + m_xcoff_aux_header.Version = data.GetU16(offset_ptr); + m_xcoff_aux_header.ReservedForDebugger = data.GetU32(offset_ptr); + m_xcoff_aux_header.TextStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.DataStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.TOCAnchorAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfEntryPoint = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTOC = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfLoader = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.ModuleType = data.GetU16(offset_ptr); + m_xcoff_aux_header.CpuFlag = data.GetU8(offset_ptr); + m_xcoff_aux_header.CpuType = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.DataPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.StackPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.FlagAndTDataAlignment = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.InitDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.BssDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.EntryPointAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxStackSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfTData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.XCOFF64Flag = data.GetU16(offset_ptr); + lldb::offset_t last_offset = *offset_ptr; + if ((last_offset - init_offset) < m_xcoff_header.auxhdrsize) + *offset_ptr += (m_xcoff_header.auxhdrsize - (last_offset - init_offset)); + return true; +} + +bool ObjectFileXCOFF::ParseSectionHeaders( + uint32_t section_header_data_offset) { + const uint32_t nsects = m_xcoff_header.nsects; + m_sect_headers.clear(); + + if (nsects > 0) { + const size_t section_header_byte_size = nsects * m_binary->getSectionHeaderSize(); + lldb_private::DataExtractor section_header_data = + ReadImageData(section_header_data_offset, section_header_byte_size); + + lldb::offset_t offset = 0; + //FIXME: section_header_data.ValidOffsetForDataOfSize + m_sect_headers.resize(nsects); + + for (uint32_t idx = 0; idx < nsects; ++idx) { + const void *name_data = section_header_data.GetData(&offset, 8); + if (name_data) { + memcpy(m_sect_headers[idx].name, name_data, 8); + m_sect_headers[idx].phyaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].vmaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].size = section_header_data.GetU64(&offset); + m_sect_headers[idx].offset = section_header_data.GetU64(&offset); + m_sect_headers[idx].reloff = section_header_data.GetU64(&offset); + m_sect_headers[idx].lineoff = section_header_data.GetU64(&offset); + m_sect_headers[idx].nreloc = section_header_data.GetU32(&offset); + m_sect_headers[idx].nline = section_header_data.GetU32(&offset); + m_sect_headers[idx].flags = section_header_data.GetU32(&offset); + offset += 4; + } else { + offset += (m_binary->getSectionHeaderSize() - 8); + } + } + } + + return !m_sect_headers.empty(); +} + +lldb_private::DataExtractor ObjectFileXCOFF::ReadImageData(uint32_t offset, size_t size) { + if (!size) + return {}; + + if (m_data.ValidOffsetForDataOfSize(offset, size)) + return lldb_private::DataExtractor(m_data, offset, size); + + assert(0); + ProcessSP process_sp(m_process_wp.lock()); + lldb_private::DataExtractor data; + if (process_sp) { + auto data_up = std::make_unique(size, 0); + Status readmem_error; + size_t bytes_read = + process_sp->ReadMemory(offset, data_up->GetBytes(), + data_up->GetByteSize(), readmem_error); + if (bytes_read == size) { + DataBufferSP buffer_sp(data_up.release()); + data.SetData(buffer_sp, 0, buffer_sp->GetByteSize()); + } + } + return data; +} + +bool ObjectFileXCOFF::SetLoadAddress(Target &target, lldb::addr_t value, + bool value_is_offset) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (section_sp && !section_sp->IsThreadSpecific()) { + bool use_offset = false; + if (strcmp(section_sp->GetName().AsCString(), ".text") == 0 || + strcmp(section_sp->GetName().AsCString(), ".data") == 0 || + strcmp(section_sp->GetName().AsCString(), ".bss") == 0) + use_offset = true; + + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, (use_offset ? + (section_sp->GetFileOffset() + value) : (section_sp->GetFileAddress() + value)))) + ++num_loaded_sections; + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (type_id == 1 && section_sp && strcmp(section_sp->GetName().AsCString(), ".text") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileOffset() + value)) + ++num_loaded_sections; + } + } else if (type_id == 2 && section_sp && strcmp(section_sp->GetName().AsCString(), ".data") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileAddress() + value)) + ++num_loaded_sections; + } + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +ByteOrder ObjectFileXCOFF::GetByteOrder() const { + return eByteOrderBig; +} + +bool ObjectFileXCOFF::IsExecutable() const { + return true; +} + +uint32_t ObjectFileXCOFF::GetAddressByteSize() const { + if (m_xcoff_header.magic == XCOFF::XCOFF64) + return 8; + else if (m_xcoff_header.magic == XCOFF::XCOFF32) + return 4; + return 4; +} + +AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) { + return AddressClass::eUnknown; +} + +lldb::SymbolType ObjectFileXCOFF::MapSymbolType(llvm::object::SymbolRef::Type sym_type) { + if (sym_type == llvm::object::SymbolRef::ST_Function) + return lldb::eSymbolTypeCode; + else if (sym_type == llvm::object::SymbolRef::ST_Data) + return lldb::eSymbolTypeData; + return lldb::eSymbolTypeInvalid; +} + +void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) { + SectionList *sect_list = GetSectionList(); + const uint32_t num_syms = m_xcoff_header.nsyms; + uint32_t sidx = 0; + if (num_syms > 0 && m_xcoff_header.symoff > 0) { + const uint32_t symbol_size = XCOFF::SymbolTableEntrySize; + const size_t symbol_data_size = num_syms * symbol_size; + lldb_private::DataExtractor symtab_data = + ReadImageData(m_xcoff_header.symoff, symbol_data_size); + + lldb::offset_t offset = 0; + std::string symbol_name; + Symbol *symbols = lldb_symtab.Resize(num_syms); + llvm::object::symbol_iterator SI = m_binary->symbol_begin(); + for (uint32_t i = 0; i < num_syms; ++i, ++SI) { + xcoff_symbol_t symbol; + const uint32_t symbol_offset = offset; + symbol.value = symtab_data.GetU64(&offset); + symbol.offset = symtab_data.GetU32(&offset); + Expected symbol_name_or_err = m_binary->getStringTableEntry(symbol.offset); + if (!symbol_name_or_err) { + consumeError(symbol_name_or_err.takeError()); + return; + } + StringRef symbol_name_str = symbol_name_or_err.get(); + symbol_name.assign(symbol_name_str.data()); + symbol.sect = symtab_data.GetU16(&offset); + symbol.type = symtab_data.GetU16(&offset); + symbol.storage = symtab_data.GetU8(&offset); + symbol.naux = symtab_data.GetU8(&offset); + // Allow C_HIDEXT TOC symbol, and check others. + if (symbol.storage == XCOFF::C_HIDEXT && strcmp(symbol_name.c_str(), "TOC") != 0) { + if (symbol.naux == 0) + continue; + if (symbol.naux > 1) { + i += symbol.naux; + offset += symbol.naux * symbol_size; + continue; + } + /* Allow XCOFF::C_HIDEXT with following SMC and AT: + StorageMappingClass: XMC_PR (0x0) + Auxiliary Type: AUX_CSECT (0xFB) + */ + xcoff_sym_csect_aux_entry_t symbol_aux; + symbol_aux.section_or_len_low_byte = symtab_data.GetU32(&offset); + symbol_aux.parameter_hash_index = symtab_data.GetU32(&offset); + symbol_aux.type_check_sect_num = symtab_data.GetU16(&offset); + symbol_aux.symbol_alignment_and_type = symtab_data.GetU8(&offset); + symbol_aux.storage_mapping_class = symtab_data.GetU8(&offset); + symbol_aux.section_or_len_high_byte = symtab_data.GetU32(&offset); + symbol_aux.pad = symtab_data.GetU8(&offset); + symbol_aux.aux_type = symtab_data.GetU8(&offset); + offset -= symbol.naux * symbol_size; + if (symbol_aux.storage_mapping_class != XCOFF::XMC_PR || symbol_aux.aux_type != XCOFF::AUX_CSECT) { + i += symbol.naux; + offset += symbol.naux * symbol_size; + continue; + } + } + // Remove the dot prefix for demangle + if (symbol_name_str.size() > 1 && symbol_name_str.data()[0] == '.') { + symbols[sidx].GetMangled().SetValue(ConstString(symbol_name.c_str() + 1)); + } else { + symbols[sidx].GetMangled().SetValue(ConstString(symbol_name.c_str())); + } + if ((int16_t)symbol.sect >= 1) { + Address symbol_addr(sect_list->GetSectionAtIndex((size_t)(symbol.sect - 1)), + (symbol.value - sect_list->GetSectionAtIndex((size_t)(symbol.sect - 1))->GetFileAddress())); + symbols[sidx].GetAddressRef() = symbol_addr; + + Expected sym_type_or_err = SI->getType(); + if (!sym_type_or_err) { + consumeError(sym_type_or_err.takeError()); + return; + } + symbols[sidx].SetType(MapSymbolType(sym_type_or_err.get())); + } + ++sidx; + + if (symbol.naux > 0) { + i += symbol.naux; + offset += symbol.naux * symbol_size; + } + } + lldb_symtab.Resize(sidx); + } +} + +bool ObjectFileXCOFF::IsStripped() { + return false; +} + +void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) { + if (m_sections_up) + return; + m_sections_up = std::make_unique(); + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard guard(module_sp->GetMutex()); + + const uint32_t nsects = m_sect_headers.size(); + ModuleSP module_sp(GetModule()); + for (uint32_t idx = 0; idx < nsects; ++idx) { + llvm::StringRef sect_name = GetSectionName(m_sect_headers[idx]); + ConstString const_sect_name(sect_name); + SectionType section_type = GetSectionType(sect_name, m_sect_headers[idx]); + + SectionSP section_sp(new Section( + module_sp, // Module to which this section belongs + this, // Object file to which this section belongs + idx + 1, // Section ID is the 1 based section index. + const_sect_name, // Name of this section + section_type, + m_sect_headers[idx].vmaddr, // File VM address == addresses as + // they are found in the object file + m_sect_headers[idx].size, // VM size in bytes of this section + m_sect_headers[idx].offset, // Offset to the data for this section in the file + m_sect_headers[idx].size, // Size in bytes of this section as found in the file + 0, // FIXME: alignment + m_sect_headers[idx].flags)); // Flags for this section + + // FIXME + uint32_t permissions = 0; + permissions |= ePermissionsReadable; + if (m_sect_headers[idx].flags & (XCOFF::STYP_DATA | XCOFF::STYP_BSS)) + permissions |= ePermissionsWritable; + if (m_sect_headers[idx].flags & XCOFF::STYP_TEXT) + permissions |= ePermissionsExecutable; + section_sp->SetPermissions(permissions); + + m_sections_up->AddSection(section_sp); + unified_section_list.AddSection(section_sp); + } + } +} + +llvm::StringRef ObjectFileXCOFF::GetSectionName(const section_header_t §) { + llvm::StringRef hdr_name(sect.name, std::size(sect.name)); + hdr_name = hdr_name.split('\0').first; + if (hdr_name.consume_front("/")) { + lldb::offset_t stroff; + if (!to_integer(hdr_name, stroff, 10)) + return ""; + lldb::offset_t string_file_offset = + m_xcoff_header.symoff + (m_xcoff_header.nsyms * static_cast(XCOFF::SymbolTableEntrySize)) + stroff; + if (const char *name = m_data.GetCStr(&string_file_offset)) + return name; + return ""; + } + return hdr_name; +} + +SectionType ObjectFileXCOFF::GetSectionType(llvm::StringRef sect_name, + const section_header_t §) { + if (sect.flags & XCOFF::STYP_TEXT) + return eSectionTypeCode; + if (sect.flags & XCOFF::STYP_DATA) + return eSectionTypeData; + if (sect.flags & XCOFF::STYP_BSS) + return eSectionTypeZeroFill; + if (sect.flags & XCOFF::STYP_DWARF) { + SectionType section_type = + llvm::StringSwitch(sect_name) + .Case(".dwinfo", eSectionTypeDWARFDebugInfo) + .Case(".dwline", eSectionTypeDWARFDebugLine) + .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev) + .Default(eSectionTypeInvalid); + + if (section_type != eSectionTypeInvalid) + return section_type; + } + return eSectionTypeOther; +} + +void ObjectFileXCOFF::Dump(Stream *s) { +} + +ArchSpec ObjectFileXCOFF::GetArchitecture() { + ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + return arch_spec; +} + +UUID ObjectFileXCOFF::GetUUID() { + return UUID(); +} + +std::optional ObjectFileXCOFF::GetDebugLink() { + return std::nullopt; +} + +uint32_t ObjectFileXCOFF::ParseDependentModules() { + ModuleSP module_sp(GetModule()); + if (!module_sp) + return 0; + + std::lock_guard guard(module_sp->GetMutex()); + if (m_deps_filespec) + return m_deps_filespec->GetSize(); + + // Cache coff binary if it is not done yet. + if (!CreateBinary()) + return 0; + + Log *log = GetLog(LLDBLog::Object); + LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}", + this, GetModule().get(), GetModule()->GetSpecificationDescription(), + m_file.GetPath(), m_binary.get()); + + m_deps_filespec = FileSpecList(); + + auto ImportFilesOrError = m_binary->getImportFileTable(); + if (!ImportFilesOrError) { + consumeError(ImportFilesOrError.takeError()); + return 0; + } + +#if 0 + StringRef ImportFileTable = ImportFilesOrError.get(); + const char *CurrentStr = ImportFileTable.data(); + const char *TableEnd = ImportFileTable.end(); + const char *Basename = nullptr; + + for (size_t StrIndex = 0; CurrentStr < TableEnd; + ++StrIndex, CurrentStr += strlen(CurrentStr) + 1) { + if (StrIndex >= 3 && StrIndex % 3 == 1) { + // base_name + llvm::StringRef dll_name(CurrentStr); + Basename = CurrentStr; + + // At this moment we only have the base name of the DLL. The full path can + // only be seen after the dynamic loading. Our best guess is Try to get it + // with the help of the object file's directory. + llvm::SmallString<128> dll_fullpath; + FileSpec dll_specs(dll_name); + // FIXME: hack to get libc.a loaded + if (strcmp(CurrentStr, "libc.a") == 0) { + dll_specs.GetDirectory().SetString("/usr/lib"); + } else { + dll_specs.GetDirectory().SetString(m_file.GetDirectory().GetCString()); + } + + if (!llvm::sys::fs::real_path(dll_specs.GetPath(), dll_fullpath)) + //m_deps_filespec->EmplaceBack(dll_fullpath); + m_deps_filespec->EmplaceBack("/usr/lib/libc.a(shr_64.o)"); + else { + // Known DLLs or DLL not found in the object file directory. + m_deps_filespec->EmplaceBack(dll_name); + } + } else if (StrIndex >= 3 && StrIndex % 3 == 2) { + // archive_member_name + if (strcmp(CurrentStr, "") == 0) { + continue; + } + assert(strcmp(Basename, "") != 0); + std::map>::iterator iter = m_deps_base_members.find(std::string(Basename)); + if (iter == m_deps_base_members.end()) { + m_deps_base_members[std::string(Basename)] = std::vector(); + iter = m_deps_base_members.find(std::string(Basename)); + } + iter->second.push_back(std::string(CurrentStr)); + } + } +#endif + return m_deps_filespec->GetSize(); +} + +uint32_t ObjectFileXCOFF::GetDependentModules(FileSpecList &files) { + auto num_modules = ParseDependentModules(); + auto original_size = files.GetSize(); + + for (unsigned i = 0; i < num_modules; ++i) + files.AppendIfUnique(m_deps_filespec->GetFileSpecAtIndex(i)); + + return files.GetSize() - original_size; +} + +Address ObjectFileXCOFF::GetImageInfoAddress(Target *target) { + return Address(); +} + +lldb_private::Address ObjectFileXCOFF::GetEntryPointAddress() { + if (m_entry_point_address.IsValid()) + return m_entry_point_address; + + if (!ParseHeader() || !IsExecutable()) + return m_entry_point_address; + + SectionList *section_list = GetSectionList(); + addr_t vm_addr = m_xcoff_aux_header.EntryPointAddr; + SectionSP section_sp( + section_list->FindSectionContainingFileAddress(vm_addr)); + if (section_sp) { + lldb::offset_t offset_ptr = section_sp->GetFileOffset() + (vm_addr - section_sp->GetFileAddress()); + vm_addr = m_data.GetU64(&offset_ptr); + } + + if (!section_list) + m_entry_point_address.SetOffset(vm_addr); + else + m_entry_point_address.ResolveAddressUsingFileSections(vm_addr, + section_list); + + return m_entry_point_address; +} + +lldb_private::Address ObjectFileXCOFF::GetBaseAddress() { + return lldb_private::Address(); +} + +ObjectFile::Type ObjectFileXCOFF::CalculateType() { + if (m_xcoff_header.flags & XCOFF::F_EXEC) + return eTypeExecutable; + else if (m_xcoff_header.flags & XCOFF::F_SHROBJ) + return eTypeSharedLibrary; + return eTypeUnknown; +} + +ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { + return eStrataUnknown; +} + +llvm::StringRef +ObjectFileXCOFF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const { + return llvm::StringRef(); +} + +void ObjectFileXCOFF::RelocateSection(lldb_private::Section *section) +{ +} + +std::vector +ObjectFileXCOFF::GetLoadableData(Target &target) { + std::vector loadables; + return loadables; +} + +lldb::WritableDataBufferSP +ObjectFileXCOFF::MapFileDataWritable(const FileSpec &file, uint64_t Size, + uint64_t Offset) { + return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size, + Offset); +} + +ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp, + DataBufferSP data_sp, lldb::offset_t data_offset, + const FileSpec *file, lldb::offset_t file_offset, + lldb::offset_t length) + : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset), + m_xcoff_header(), m_sect_headers(), m_deps_filespec(), m_deps_base_members(), + m_entry_point_address() { + ::memset(&m_xcoff_header, 0, sizeof(m_xcoff_header)); + if (file) + m_file = *file; +} + +ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp, + DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, + addr_t header_addr) + : ObjectFile(module_sp, process_sp, header_addr, header_data_sp), + m_xcoff_header(), m_sect_headers(), m_deps_filespec(), m_deps_base_members(), + m_entry_point_address() { + ::memset(&m_xcoff_header, 0, sizeof(m_xcoff_header)); +} diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h new file mode 100644 index 0000000000000..5a12d16886489 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h @@ -0,0 +1,243 @@ +//===-- ObjectFileXCOFF.h --------------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H + +#include + +#include + +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/UUID.h" +#include "lldb/lldb-private.h" +#include "llvm/Object/XCOFFObjectFile.h" + +/// \class ObjectFileXCOFF +/// Generic XCOFF object file reader. +/// +/// This class provides a generic XCOFF (32/64 bit) reader plugin implementing +/// the ObjectFile protocol. +class ObjectFileXCOFF : public lldb_private::ObjectFile { +public: + // Static Functions + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "xcoff"; } + + static llvm::StringRef GetPluginDescriptionStatic() { + return "XCOFF object file reader."; + } + + static lldb_private::ObjectFile * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length); + + static lldb_private::ObjectFile *CreateMemoryInstance( + const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + + static size_t GetModuleSpecifications(const lldb_private::FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + lldb_private::ModuleSpecList &specs); + + static bool MagicBytesMatch(lldb::DataBufferSP &data_sp, lldb::addr_t offset, + lldb::addr_t length); + + static lldb::SymbolType MapSymbolType(llvm::object::SymbolRef::Type sym_type); + + // PluginInterface protocol + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + // LLVM RTTI support + static char ID; + bool isA(const void *ClassID) const override { + return ClassID == &ID || ObjectFile::isA(ClassID); + } + static bool classof(const ObjectFile *obj) { return obj->isA(&ID); } + + // ObjectFile Protocol. + bool ParseHeader() override; + + bool SetLoadAddress(lldb_private::Target &target, lldb::addr_t value, + bool value_is_offset) override; + + bool SetLoadAddressByType(lldb_private::Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) override; + + lldb::ByteOrder GetByteOrder() const override; + + bool IsExecutable() const override; + + uint32_t GetAddressByteSize() const override; + + lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override; + + void ParseSymtab(lldb_private::Symtab &symtab) override; + + bool IsStripped() override; + + void CreateSections(lldb_private::SectionList &unified_section_list) override; + + void Dump(lldb_private::Stream *s) override; + + lldb_private::ArchSpec GetArchitecture() override; + + lldb_private::UUID GetUUID() override; + + /// Return the contents of the .gnu_debuglink section, if the object file + /// contains it. + std::optional GetDebugLink(); + + uint32_t GetDependentModules(lldb_private::FileSpecList &files) override; + + lldb_private::Address + GetImageInfoAddress(lldb_private::Target *target) override; + + lldb_private::Address GetEntryPointAddress() override; + + lldb_private::Address GetBaseAddress() override; + + ObjectFile::Type CalculateType() override; + + ObjectFile::Strata CalculateStrata() override; + + llvm::StringRef + StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const override; + + void RelocateSection(lldb_private::Section *section) override; + + lldb_private::DataExtractor ReadImageData(uint32_t offset, size_t size); + + ObjectFileXCOFF(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + ObjectFileXCOFF(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + +protected: + + typedef struct xcoff_header { + uint16_t magic; + uint16_t nsects; + uint32_t modtime; + uint64_t symoff; + uint32_t nsyms; + uint16_t auxhdrsize; + uint16_t flags; + } xcoff_header_t; + + typedef struct xcoff_aux_header { + uint16_t AuxMagic; + uint16_t Version; + uint32_t ReservedForDebugger; + uint64_t TextStartAddr; + uint64_t DataStartAddr; + uint64_t TOCAnchorAddr; + uint16_t SecNumOfEntryPoint; + uint16_t SecNumOfText; + uint16_t SecNumOfData; + uint16_t SecNumOfTOC; + uint16_t SecNumOfLoader; + uint16_t SecNumOfBSS; + uint16_t MaxAlignOfText; + uint16_t MaxAlignOfData; + uint16_t ModuleType; + uint8_t CpuFlag; + uint8_t CpuType; + uint8_t TextPageSize; + uint8_t DataPageSize; + uint8_t StackPageSize; + uint8_t FlagAndTDataAlignment; + uint64_t TextSize; + uint64_t InitDataSize; + uint64_t BssDataSize; + uint64_t EntryPointAddr; + uint64_t MaxStackSize; + uint64_t MaxDataSize; + uint16_t SecNumOfTData; + uint16_t SecNumOfTBSS; + uint16_t XCOFF64Flag; + } xcoff_aux_header_t; + + typedef struct section_header { + char name[8]; + uint64_t phyaddr; // Physical Addr + uint64_t vmaddr; // Virtual Addr + uint64_t size; // Section size + uint64_t offset; // File offset to raw data + uint64_t reloff; // Offset to relocations + uint64_t lineoff; // Offset to line table entries + uint32_t nreloc; // Number of relocation entries + uint32_t nline; // Number of line table entries + uint32_t flags; + } section_header_t; + + typedef struct xcoff_symbol { + uint64_t value; + uint32_t offset; + uint16_t sect; + uint16_t type; + uint8_t storage; + uint8_t naux; + } xcoff_symbol_t; + + typedef struct xcoff_sym_csect_aux_entry { + uint32_t section_or_len_low_byte; + uint32_t parameter_hash_index; + uint16_t type_check_sect_num; + uint8_t symbol_alignment_and_type; + uint8_t storage_mapping_class; + uint32_t section_or_len_high_byte; + uint8_t pad; + uint8_t aux_type; + } xcoff_sym_csect_aux_entry_t; + + static bool ParseXCOFFHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + xcoff_header_t &xcoff_header); + bool ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr); + bool ParseSectionHeaders(uint32_t offset); + + std::vector + GetLoadableData(lldb_private::Target &target) override; + + static lldb::WritableDataBufferSP + MapFileDataWritable(const lldb_private::FileSpec &file, uint64_t Size, + uint64_t Offset); + llvm::StringRef GetSectionName(const section_header_t §); + static lldb::SectionType GetSectionType(llvm::StringRef sect_name, + const section_header_t §); + + uint32_t ParseDependentModules(); + typedef std::vector SectionHeaderColl; + +private: + bool CreateBinary(); + + xcoff_header_t m_xcoff_header; + xcoff_aux_header_t m_xcoff_aux_header; + SectionHeaderColl m_sect_headers; + std::unique_ptr m_binary; + lldb_private::Address m_entry_point_address; + std::optional m_deps_filespec; + std::map> m_deps_base_members; +}; + +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H diff --git a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp index e026ffefd645e..106e38b6e25ae 100644 --- a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp +++ b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp @@ -227,7 +227,7 @@ ThreadSP OperatingSystemPython::CreateThreadFromThreadInfo( ThreadList &old_thread_list, std::vector &core_used_map, bool *did_create_ptr) { ThreadSP thread_sp; - tid_t tid = LLDB_INVALID_THREAD_ID; + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; if (!thread_dict.GetValueForKeyAsInteger("tid", tid)) return ThreadSP(); diff --git a/lldb/source/Plugins/Platform/AIX/CMakeLists.txt b/lldb/source/Plugins/Platform/AIX/CMakeLists.txt new file mode 100644 index 0000000000000..85ff0a315eabd --- /dev/null +++ b/lldb/source/Plugins/Platform/AIX/CMakeLists.txt @@ -0,0 +1,13 @@ +add_definitions("-D_ALL_SOURCE") + +add_lldb_library(lldbPluginPlatformAIX PLUGIN + PlatformAIX.cpp + + LINK_LIBS + lldbBreakpoint + lldbCore + lldbHost + lldbInterpreter + lldbTarget + lldbPluginPlatformPOSIX + ) diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp new file mode 100644 index 0000000000000..b6b08b73bec41 --- /dev/null +++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp @@ -0,0 +1,471 @@ +//===-- PlatformAIX.cpp -------------------------------------------------===// +// +// 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 "PlatformAIX.h" +#include "lldb/Host/Config.h" + +#include +#if LLDB_ENABLE_POSIX +#include +#endif + +#include "Utility/ARM64_DWARF_Registers.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/StreamString.h" + +// Define these constants from AIX mman.h for use when targeting remote aix +// systems even when host has different values. + +#if defined(__AIX__) +#include +#endif + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::platform_aix; + +LLDB_PLUGIN_DEFINE(PlatformAIX) + +static uint32_t g_initialize_count = 0; + + +PlatformSP PlatformAIX::CreateInstance(bool force, const ArchSpec *arch) { + Log *log = GetLog(LLDBLog::Platform); + LLDB_LOG(log, "force = {0}, arch=({1}, {2})", force, + arch ? arch->GetArchitectureName() : "", + arch ? arch->GetTriple().getTriple() : ""); + + bool create = force; + if (!create && arch && arch->IsValid()) { + const llvm::Triple &triple = arch->GetTriple(); + switch (triple.getOS()) { + case llvm::Triple::AIX: + create = true; + break; + + default: + break; + } + } + + LLDB_LOG(log, "create = {0}", create); + if (create) { + return PlatformSP(new PlatformAIX(false)); + } + return PlatformSP(); +} + +llvm::StringRef PlatformAIX::GetPluginDescriptionStatic(bool is_host) { + if (is_host) + return "Local AIX user platform plug-in."; + return "Remote AIX user platform plug-in."; +} + +void PlatformAIX::Initialize() { + PlatformPOSIX::Initialize(); + + if (g_initialize_count++ == 0) { +#if defined(__AIX__) + PlatformSP default_platform_sp(new PlatformAIX(true)); + default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); + Platform::SetHostPlatform(default_platform_sp); +#endif + PluginManager::RegisterPlugin( + PlatformAIX::GetPluginNameStatic(false), + PlatformAIX::GetPluginDescriptionStatic(false), + PlatformAIX::CreateInstance, nullptr); + } +} + +void PlatformAIX::Terminate() { + if (g_initialize_count > 0) { + if (--g_initialize_count == 0) { + PluginManager::UnregisterPlugin(PlatformAIX::CreateInstance); + } + } + + PlatformPOSIX::Terminate(); +} + +/// Default Constructor +PlatformAIX::PlatformAIX(bool is_host) + : PlatformPOSIX(is_host) // This is the local host platform +{ + if (is_host) { + ArchSpec hostArch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault); + m_supported_architectures.push_back(hostArch); + if (hostArch.GetTriple().isArch64Bit()) { + m_supported_architectures.push_back( + HostInfo::GetArchitecture(HostInfo::eArchKind32)); + } + } else { + m_supported_architectures = CreateArchList( + {llvm::Triple::x86_64, llvm::Triple::x86, llvm::Triple::arm, + llvm::Triple::aarch64, llvm::Triple::mips64, llvm::Triple::mips64, + llvm::Triple::hexagon, llvm::Triple::mips, llvm::Triple::mips64el, + llvm::Triple::mipsel, llvm::Triple::systemz}, + llvm::Triple::AIX); + } +} + +std::vector +PlatformAIX::GetSupportedArchitectures(const ArchSpec &process_host_arch) { + if (m_remote_platform_sp) + return m_remote_platform_sp->GetSupportedArchitectures(process_host_arch); + return m_supported_architectures; +} + +void PlatformAIX::GetStatus(Stream &strm) { + Platform::GetStatus(strm); + +#if LLDB_ENABLE_POSIX + // Display local kernel information only when we are running in host mode. + // Otherwise, we would end up printing non-AIX information (when running on + // Mac OS for example). + if (IsHost()) { + struct utsname un; + + if (uname(&un)) + return; + + strm.Printf(" Kernel: %s\n", un.sysname); + strm.Printf(" Release: %s\n", un.release); + strm.Printf(" Version: %s\n", un.version); + } +#endif +} + +uint32_t +PlatformAIX::GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) { + uint32_t resume_count = 0; + + // Always resume past the initial stop when we use eLaunchFlagDebug + if (launch_info.GetFlags().Test(eLaunchFlagDebug)) { + // Resume past the stop for the final exec into the true inferior. + ++resume_count; + } + + // If we're not launching a shell, we're done. + const FileSpec &shell = launch_info.GetShell(); + if (!shell) + return resume_count; + + std::string shell_string = shell.GetPath(); + // We're in a shell, so for sure we have to resume past the shell exec. + ++resume_count; + + // Figure out what shell we're planning on using. + const char *shell_name = strrchr(shell_string.c_str(), '/'); + if (shell_name == nullptr) + shell_name = shell_string.c_str(); + else + shell_name++; + + if (strcmp(shell_name, "csh") == 0 || strcmp(shell_name, "tcsh") == 0 || + strcmp(shell_name, "zsh") == 0 || strcmp(shell_name, "sh") == 0) { + // These shells seem to re-exec themselves. Add another resume. + ++resume_count; + } + + return resume_count; +} + +bool PlatformAIX::CanDebugProcess() { + if (IsHost()) { + return true; + } else { + // If we're connected, we can debug. + return IsConnected(); + } +} + +void PlatformAIX::CalculateTrapHandlerSymbolNames() { + m_trap_handlers.push_back(ConstString("_sigtramp")); + m_trap_handlers.push_back(ConstString("__kernel_rt_sigreturn")); + m_trap_handlers.push_back(ConstString("__restore_rt")); +} + +static lldb::UnwindPlanSP GetAArch64TrapHanlderUnwindPlan(ConstString name) { + UnwindPlanSP unwind_plan_sp; + if (name != "__kernel_rt_sigreturn") + return unwind_plan_sp; + + UnwindPlan::RowSP row = std::make_shared(); + row->SetOffset(0); + + // In the signal trampoline frame, sp points to an rt_sigframe[1], which is: + // - 128-byte siginfo struct + // - ucontext struct: + // - 8-byte long (uc_flags) + // - 8-byte pointer (uc_link) + // - 24-byte stack_t + // - 128-byte signal set + // - 8 bytes of padding because sigcontext has 16-byte alignment + // - sigcontext/mcontext_t + // [1] + // https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/signal.c + int32_t offset = 128 + 8 + 8 + 24 + 128 + 8; + // Then sigcontext[2] is: + // - 8 byte fault address + // - 31 8 byte registers + // - 8 byte sp + // - 8 byte pc + // [2] + // https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/sigcontext.h + + // Skip fault address + offset += 8; + row->GetCFAValue().SetIsRegisterPlusOffset(arm64_dwarf::sp, offset); + + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x0, 0 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x1, 1 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x2, 2 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x3, 3 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x4, 4 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x5, 5 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x6, 6 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x7, 7 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x8, 8 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x9, 9 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x10, 10 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x11, 11 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x12, 12 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x13, 13 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x14, 14 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x15, 15 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x16, 16 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x17, 17 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x18, 18 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x19, 19 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x20, 20 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x21, 21 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x22, 22 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x23, 23 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x24, 24 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x25, 25 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x26, 26 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x27, 27 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x28, 28 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::fp, 29 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x30, 30 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::sp, 31 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::pc, 32 * 8, false); + + // The sigcontext may also contain floating point and SVE registers. + // However this would require a dynamic unwind plan so they are not included + // here. + + unwind_plan_sp = std::make_shared(eRegisterKindDWARF); + unwind_plan_sp->AppendRow(row); + unwind_plan_sp->SetSourceName("AArch64 AIX sigcontext"); + unwind_plan_sp->SetSourcedFromCompiler(eLazyBoolYes); + // Because sp is the same throughout the function + unwind_plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolYes); + unwind_plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolYes); + + return unwind_plan_sp; +} + +lldb::UnwindPlanSP +PlatformAIX::GetTrapHandlerUnwindPlan(const llvm::Triple &triple, + ConstString name) { + if (triple.isAArch64()) + return GetAArch64TrapHanlderUnwindPlan(name); + + return {}; +} + +MmapArgList PlatformAIX::GetMmapArgumentList(const ArchSpec &arch, + addr_t addr, addr_t length, + unsigned prot, unsigned flags, + addr_t fd, addr_t offset) { +#if defined(__AIX__) + unsigned flags_platform = MAP_VARIABLE | MAP_PRIVATE | MAP_ANONYMOUS; +#else + unsigned flags_platform = 0; +#endif + MmapArgList args({addr, length, prot, flags_platform, fd, offset}); + return args; +} + +CompilerType PlatformAIX::GetSiginfoType(const llvm::Triple &triple) { + if (!m_type_system_up) + m_type_system_up.reset(new TypeSystemClang("siginfo", triple)); + TypeSystemClang *ast = m_type_system_up.get(); + + bool si_errno_then_code = true; + + switch (triple.getArch()) { + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + // mips has si_code and si_errno swapped + si_errno_then_code = false; + break; + default: + break; + } + + // generic types + CompilerType int_type = ast->GetBasicType(eBasicTypeInt); + CompilerType uint_type = ast->GetBasicType(eBasicTypeUnsignedInt); + CompilerType short_type = ast->GetBasicType(eBasicTypeShort); + CompilerType long_type = ast->GetBasicType(eBasicTypeLong); + CompilerType voidp_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); + + // platform-specific types + CompilerType &pid_type = int_type; + CompilerType &uid_type = uint_type; + CompilerType &clock_type = long_type; + CompilerType &band_type = long_type; + + CompilerType sigval_type = ast->CreateRecordType( + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_sigval_t", + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); + ast->StartTagDeclarationDefinition(sigval_type); + ast->AddFieldToRecordType(sigval_type, "sival_int", int_type, + lldb::eAccessPublic, 0); + ast->AddFieldToRecordType(sigval_type, "sival_ptr", voidp_type, + lldb::eAccessPublic, 0); + ast->CompleteTagDeclarationDefinition(sigval_type); + + CompilerType sigfault_bounds_type = ast->CreateRecordType( + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); + ast->StartTagDeclarationDefinition(sigfault_bounds_type); + ast->AddFieldToRecordType(sigfault_bounds_type, "_addr_bnd", + ast->CreateStructForIdentifier(ConstString(), + { + {"_lower", voidp_type}, + {"_upper", voidp_type}, + }), + lldb::eAccessPublic, 0); + ast->AddFieldToRecordType(sigfault_bounds_type, "_pkey", uint_type, + lldb::eAccessPublic, 0); + ast->CompleteTagDeclarationDefinition(sigfault_bounds_type); + + // siginfo_t + CompilerType siginfo_type = ast->CreateRecordType( + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_siginfo_t", + llvm::to_underlying(clang::TagTypeKind::Struct), lldb::eLanguageTypeC); + ast->StartTagDeclarationDefinition(siginfo_type); + ast->AddFieldToRecordType(siginfo_type, "si_signo", int_type, + lldb::eAccessPublic, 0); + + if (si_errno_then_code) { + ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type, + lldb::eAccessPublic, 0); + ast->AddFieldToRecordType(siginfo_type, "si_code", int_type, + lldb::eAccessPublic, 0); + } else { + ast->AddFieldToRecordType(siginfo_type, "si_code", int_type, + lldb::eAccessPublic, 0); + ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type, + lldb::eAccessPublic, 0); + } + + // the structure is padded on 64-bit arches to fix alignment + if (triple.isArch64Bit()) + ast->AddFieldToRecordType(siginfo_type, "__pad0", int_type, + lldb::eAccessPublic, 0); + + // union used to hold the signal data + CompilerType union_type = ast->CreateRecordType( + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); + ast->StartTagDeclarationDefinition(union_type); + + ast->AddFieldToRecordType( + union_type, "_kill", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_pid", pid_type}, + {"si_uid", uid_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_timer", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_tid", int_type}, + {"si_overrun", int_type}, + {"si_sigval", sigval_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_rt", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_pid", pid_type}, + {"si_uid", uid_type}, + {"si_sigval", sigval_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_sigchld", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_pid", pid_type}, + {"si_uid", uid_type}, + {"si_status", int_type}, + {"si_utime", clock_type}, + {"si_stime", clock_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_sigfault", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_addr", voidp_type}, + {"si_addr_lsb", short_type}, + {"_bounds", sigfault_bounds_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_sigpoll", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_band", band_type}, + {"si_fd", int_type}, + }), + lldb::eAccessPublic, 0); + + // NB: SIGSYS is not present on ia64 but we don't seem to support that + ast->AddFieldToRecordType( + union_type, "_sigsys", + ast->CreateStructForIdentifier(ConstString(), + { + {"_call_addr", voidp_type}, + {"_syscall", int_type}, + {"_arch", uint_type}, + }), + lldb::eAccessPublic, 0); + + ast->CompleteTagDeclarationDefinition(union_type); + ast->AddFieldToRecordType(siginfo_type, "_sifields", union_type, + lldb::eAccessPublic, 0); + + ast->CompleteTagDeclarationDefinition(siginfo_type); + return siginfo_type; +} diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.h b/lldb/source/Plugins/Platform/AIX/PlatformAIX.h new file mode 100644 index 0000000000000..3ae8089a48d71 --- /dev/null +++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.h @@ -0,0 +1,74 @@ +//===-- PlatformAIX.h -----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PLATFORM_AIX_PLATFORMAIX_H +#define LLDB_SOURCE_PLUGINS_PLATFORM_AIX_PLATFORMAIX_H + +#include "Plugins/Platform/POSIX/PlatformPOSIX.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" + +namespace lldb_private { +namespace platform_aix { + +class PlatformAIX : public PlatformPOSIX { +public: + PlatformAIX(bool is_host); + + static void Initialize(); + + static void Terminate(); + + // lldb_private::PluginInterface functions + static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch); + + static llvm::StringRef GetPluginNameStatic(bool is_host) { + return is_host ? Platform::GetHostPlatformName() : "remote-AIX"; + } + + static llvm::StringRef GetPluginDescriptionStatic(bool is_host); + + llvm::StringRef GetPluginName() override { + return GetPluginNameStatic(IsHost()); + } + + // lldb_private::Platform functions + llvm::StringRef GetDescription() override { + return GetPluginDescriptionStatic(IsHost()); + } + + void GetStatus(Stream &strm) override; + + std::vector + GetSupportedArchitectures(const ArchSpec &process_host_arch) override; + + uint32_t GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) override; + + bool CanDebugProcess() override; + + void CalculateTrapHandlerSymbolNames() override; + + lldb::UnwindPlanSP GetTrapHandlerUnwindPlan(const llvm::Triple &triple, + ConstString name) override; + + MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr, + lldb::addr_t length, unsigned prot, + unsigned flags, lldb::addr_t fd, + lldb::addr_t offset) override; + + CompilerType GetSiginfoType(const llvm::Triple &triple) override; + + std::vector m_supported_architectures; + +private: + std::unique_ptr m_type_system_up; +}; + +} // namespace platform_AIX +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_PLATFORM_AIX_PLATFORMAIX_H diff --git a/lldb/source/Plugins/Platform/CMakeLists.txt b/lldb/source/Plugins/Platform/CMakeLists.txt index 6869587f917eb..9d0afd97cff85 100644 --- a/lldb/source/Plugins/Platform/CMakeLists.txt +++ b/lldb/source/Plugins/Platform/CMakeLists.txt @@ -8,3 +8,4 @@ add_subdirectory(OpenBSD) add_subdirectory(POSIX) add_subdirectory(QemuUser) add_subdirectory(Windows) +add_subdirectory(AIX) diff --git a/lldb/source/Plugins/Process/AIX/CMakeLists.txt b/lldb/source/Plugins/Process/AIX/CMakeLists.txt new file mode 100644 index 0000000000000..e9d83266f5857 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/CMakeLists.txt @@ -0,0 +1,19 @@ +add_definitions("-D_ALL_SOURCE") + +add_lldb_library(lldbPluginProcessAIX + NativeProcessAIX.cpp + NativeRegisterContextAIX.cpp + NativeRegisterContextAIX_ppc64.cpp + NativeThreadAIX.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + lldbTarget + lldbUtility + lldbPluginProcessPOSIX + lldbPluginProcessUtility + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp new file mode 100644 index 0000000000000..882f20d30a3bf --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -0,0 +1,2048 @@ +//===-- NativeProcessAIX.cpp --------------------------------------------===// +// +// 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 "NativeProcessAIX.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "NativeThreadAIX.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +//#include "Plugins/Process/Utility/LinuxProcMaps.h" +//#include "Procfs.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/HostProcess.h" +#include "lldb/Host/ProcessLaunchInfo.h" +#include "lldb/Host/PseudoTerminal.h" +#include "lldb/Host/ThreadLauncher.h" +#include "lldb/Host/common/NativeRegisterContext.h" +#include "lldb/Host/aix/Ptrace.h" +//#include "lldb/Host/linux/Host.h" +//#include "lldb/Host/linux/Uio.h" +#include "lldb/Host/posix/ProcessLauncherPosixFork.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/State.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/StringExtractor.h" +#include "llvm/ADT/ScopeExit.h" +#include "llvm/Support/Errno.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Threading.h" + +#include +#include +#include +#include +//#include +#include +#include +#include +#include + +#ifdef __aarch64__ +#include +#include +#endif + +// Support hardware breakpoints in case it has not been defined +#ifndef TRAP_HWBKPT +#define TRAP_HWBKPT 4 +#endif + +#ifndef HWCAP2_MTE +#define HWCAP2_MTE (1 << 18) +#endif + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; +using namespace llvm; + +// Private bits we only need internally. + +static bool ProcessVmReadvSupported() { + static bool is_supported; + static llvm::once_flag flag; + + llvm::call_once(flag, [] { + Log *log = GetLog(POSIXLog::Process); + + uint32_t source = 0x47424742; + uint32_t dest = 0; + + struct iovec local, remote; + remote.iov_base = &source; + local.iov_base = &dest; + remote.iov_len = local.iov_len = sizeof source; + +#if 0 + // We shall try if cross-process-memory reads work by attempting to read a + // value from our own process. + ssize_t res = process_vm_readv(getpid(), &local, 1, &remote, 1, 0); + is_supported = (res == sizeof(source) && source == dest); + if (is_supported) + LLDB_LOG(log, + "Detected kernel support for process_vm_readv syscall. " + "Fast memory reads enabled."); + else + LLDB_LOG(log, + "syscall process_vm_readv failed (error: {0}). Fast memory " + "reads disabled.", + llvm::sys::StrError()); +#endif + }); + + return is_supported; +} + +static void MaybeLogLaunchInfo(const ProcessLaunchInfo &info) { + Log *log = GetLog(POSIXLog::Process); + if (!log) + return; + + if (const FileAction *action = info.GetFileActionForFD(STDIN_FILENO)) + LLDB_LOG(log, "setting STDIN to '{0}'", action->GetFileSpec()); + else + LLDB_LOG(log, "leaving STDIN as is"); + + if (const FileAction *action = info.GetFileActionForFD(STDOUT_FILENO)) + LLDB_LOG(log, "setting STDOUT to '{0}'", action->GetFileSpec()); + else + LLDB_LOG(log, "leaving STDOUT as is"); + + if (const FileAction *action = info.GetFileActionForFD(STDERR_FILENO)) + LLDB_LOG(log, "setting STDERR to '{0}'", action->GetFileSpec()); + else + LLDB_LOG(log, "leaving STDERR as is"); + + int i = 0; + for (const char **args = info.GetArguments().GetConstArgumentVector(); *args; + ++args, ++i) + LLDB_LOG(log, "arg {0}: '{1}'", i, *args); +} + +static void DisplayBytes(StreamString &s, void *bytes, uint32_t count) { + uint8_t *ptr = (uint8_t *)bytes; + const uint32_t loop_count = std::min(DEBUG_PTRACE_MAXBYTES, count); + for (uint32_t i = 0; i < loop_count; i++) { + s.Printf("[%x]", *ptr); + ptr++; + } +} + +static void PtraceDisplayBytes(int &req, void *data, size_t data_size) { + Log *log = GetLog(POSIXLog::Ptrace); + if (!log) + return; + StreamString buf; + + switch (req) { + case PTRACE_POKETEXT: { + DisplayBytes(buf, &data, 8); + LLDB_LOGV(log, "PTRACE_POKETEXT {0}", buf.GetData()); + break; + } + case PTRACE_POKEDATA: { + DisplayBytes(buf, &data, 8); + LLDB_LOGV(log, "PTRACE_POKEDATA {0}", buf.GetData()); + break; + } + case PTRACE_POKEUSER: { + DisplayBytes(buf, &data, 8); + LLDB_LOGV(log, "PTRACE_POKEUSER {0}", buf.GetData()); + break; + } + case PTRACE_SETREGS: { + DisplayBytes(buf, data, data_size); + LLDB_LOGV(log, "PTRACE_SETREGS {0}", buf.GetData()); + break; + } + case PTRACE_SETFPREGS: { + DisplayBytes(buf, data, data_size); + LLDB_LOGV(log, "PTRACE_SETFPREGS {0}", buf.GetData()); + break; + } +#if 0 + case PTRACE_SETSIGINFO: { + DisplayBytes(buf, data, sizeof(siginfo_t)); + LLDB_LOGV(log, "PTRACE_SETSIGINFO {0}", buf.GetData()); + break; + } +#endif + case PTRACE_SETREGSET: { + // Extract iov_base from data, which is a pointer to the struct iovec + DisplayBytes(buf, *(void **)data, data_size); + LLDB_LOGV(log, "PTRACE_SETREGSET {0}", buf.GetData()); + break; + } + default: {} + } +} + +static constexpr unsigned k_ptrace_word_size = sizeof(void *); +static_assert(sizeof(long) >= k_ptrace_word_size, + "Size of long must be larger than ptrace word size"); + +// Simple helper function to ensure flags are enabled on the given file +// descriptor. +static Status EnsureFDFlags(int fd, int flags) { + Status error; + + int status = fcntl(fd, F_GETFL); + if (status == -1) { + error.SetErrorToErrno(); + return error; + } + + if (fcntl(fd, F_SETFL, status | flags) == -1) { + error.SetErrorToErrno(); + return error; + } + + return error; +} + +#if 0 +static llvm::Error AddPtraceScopeNote(llvm::Error original_error) { + Expected ptrace_scope = GetPtraceScope(); + if (auto E = ptrace_scope.takeError()) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "error reading value of ptrace_scope: {0}", E); + + // The original error is probably more interesting than not being able to + // read or interpret ptrace_scope. + return original_error; + } + + // We only have suggestions to provide for 1-3. + switch (*ptrace_scope) { + case 1: + case 2: + return llvm::createStringError( + std::error_code(errno, std::generic_category()), + "The current value of ptrace_scope is %d, which can cause ptrace to " + "fail to attach to a running process. To fix this, run:\n" + "\tsudo sysctl -w kernel.yama.ptrace_scope=0\n" + "For more information, see: " + "https://www.kernel.org/doc/Documentation/security/Yama.txt.", + *ptrace_scope); + case 3: + return llvm::createStringError( + std::error_code(errno, std::generic_category()), + "The current value of ptrace_scope is 3, which will cause ptrace to " + "fail to attach to a running process. This value cannot be changed " + "without rebooting.\n" + "For more information, see: " + "https://www.kernel.org/doc/Documentation/security/Yama.txt."); + case 0: + default: + return original_error; + } +} +#endif + +NativeProcessAIX::Manager::Manager(MainLoop &mainloop) + : NativeProcessProtocol::Manager(mainloop) { + Status status; + m_sigchld_handle = mainloop.RegisterSignal( + SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status); + assert(m_sigchld_handle && status.Success()); +} + +// Public Static Methods + +llvm::Expected> +NativeProcessAIX::Manager::Launch(ProcessLaunchInfo &launch_info, + NativeDelegate &native_delegate) { + Log *log = GetLog(POSIXLog::Process); + + MaybeLogLaunchInfo(launch_info); + + Status status; + ::pid_t pid = ProcessLauncherPosixFork() + .LaunchProcess(launch_info, status) + .GetProcessId(); + LLDB_LOG(log, "pid = {0:x}", pid); + if (status.Fail()) { + LLDB_LOG(log, "failed to launch process: {0}", status); + return status.ToError(); + } + + // Wait for the child process to trap on its call to execve. + int wstatus = 0; + ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0); + assert(wpid == pid); + UNUSED_IF_ASSERT_DISABLED(wpid); + if (!WIFSTOPPED(wstatus)) { + LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}", + WaitStatus::Decode(wstatus)); + return llvm::make_error("Could not sync with inferior process", + llvm::inconvertibleErrorCode()); + } + LLDB_LOG(log, "inferior started, now in stopped state"); + + ProcessInstanceInfo Info; + if (!Host::GetProcessInfo(pid, Info)) { + return llvm::make_error("Cannot get process architectrue", + llvm::inconvertibleErrorCode()); + } + /*llvm::Expected arch_or = + NativeRegisterContextAIX::DetermineArchitecture(pid); + if (!arch_or) + return arch_or.takeError();*/ + + // Set the architecture to the exe architecture. + LLDB_LOG(log, "pid = {0}, detected architecture {1}", pid, + Info.GetArchitecture().GetArchitectureName()); + + return std::unique_ptr(new NativeProcessAIX( + pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate, + Info.GetArchitecture(), *this, {pid})); +} + +llvm::Expected> +NativeProcessAIX::Manager::Attach( + lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "pid = {0:x}", pid); + + ProcessInstanceInfo Info; + if (!Host::GetProcessInfo(pid, Info)) { + return llvm::make_error("Cannot get process architectrue", + llvm::inconvertibleErrorCode()); + } + auto tids_or = NativeProcessAIX::Attach(pid); + if (!tids_or) + return tids_or.takeError(); +#if 0 + ArrayRef<::pid_t> tids = *tids_or; + llvm::Expected arch_or = + NativeRegisterContextAIX::DetermineArchitecture(tids[0]); + if (!arch_or) + return arch_or.takeError(); +#endif + + return std::unique_ptr( + new NativeProcessAIX(pid, -1, native_delegate, Info.GetArchitecture(), *this, *tids_or)); +} + +lldb::addr_t NativeProcessAIX::GetSharedLibraryInfoAddress() { + // punt on this for now + return LLDB_INVALID_ADDRESS; +} + +NativeProcessAIX::Extension +NativeProcessAIX::Manager::GetSupportedExtensions() const { + NativeProcessAIX::Extension supported = + Extension::multiprocess | Extension::fork | Extension::vfork | + Extension::pass_signals | Extension::auxv | Extension::libraries_svr4 | + Extension::siginfo_read; + +#ifdef __aarch64__ + // At this point we do not have a process so read auxv directly. + if ((getauxval(AT_HWCAP2) & HWCAP2_MTE)) + supported |= Extension::memory_tagging; +#endif + + return supported; +} + +static std::optional> WaitPid() { + Log *log = GetLog(POSIXLog::Process); + + int status; + ::pid_t wait_pid = llvm::sys::RetryAfterSignal( + -1, ::waitpid, -1, &status, /*__WALL | __WNOTHREAD |*/ WNOHANG); + + if (wait_pid == 0) + return std::nullopt; + + if (wait_pid == -1) { + Status error(errno, eErrorTypePOSIX); + LLDB_LOG(log, "waitpid(-1, &status, _) failed: {1}", error); + return std::nullopt; + } + + WaitStatus wait_status = WaitStatus::Decode(status); + + LLDB_LOG(log, "waitpid(-1, &status, _) = {0}, status = {1}", wait_pid, + wait_status); + return std::make_pair(wait_pid, wait_status); +} + +void NativeProcessAIX::Manager::SigchldHandler() { + Log *log = GetLog(POSIXLog::Process); + while (true) { + auto wait_result = WaitPid(); + if (!wait_result) + return; + lldb::pid_t pid = wait_result->first; + WaitStatus status = wait_result->second; + + // Ask each process whether it wants to handle the event. Each event should + // be handled by exactly one process, but thread creation events require + // special handling. + // Thread creation consists of two events (one on the parent and one on the + // child thread) and they can arrive in any order nondeterministically. The + // parent event carries the information about the child thread, but not + // vice-versa. This means that if the child event arrives first, it may not + // be handled by any process (because it doesn't know the thread belongs to + // it). + bool handled = llvm::any_of(m_processes, [&](NativeProcessAIX *process) { + return process->TryHandleWaitStatus(pid, status); + }); + if (!handled) { + if (status.type == WaitStatus::Stop && status.status == SIGSTOP) { + // Store the thread creation event for later collection. + m_unowned_threads.insert(pid); + } else { + LLDB_LOG(log, "Ignoring waitpid event {0} for pid {1}", status, pid); + } + } + } +} + +void NativeProcessAIX::Manager::CollectThread(::pid_t tid) { + Log *log = GetLog(POSIXLog::Process); + + if (m_unowned_threads.erase(tid)) + return; // We've encountered this thread already. + + // The TID is not tracked yet, let's wait for it to appear. + int status = -1; + LLDB_LOG(log, + "received clone event for tid {0}. tid not tracked yet, " + "waiting for it to appear...", + tid); + ::pid_t wait_pid = + llvm::sys::RetryAfterSignal(-1, ::waitpid, tid, &status, P_ALL/*__WALL*/); + + // It's theoretically possible to get other events if the entire process was + // SIGKILLed before we got a chance to check this. In that case, we'll just + // clean everything up when we get the process exit event. + + LLDB_LOG(log, + "waitpid({0}, &status, __WALL) => {1} (errno: {2}, status = {3})", + tid, wait_pid, errno, WaitStatus::Decode(status)); +} + +// Public Instance Methods + +NativeProcessAIX::NativeProcessAIX(::pid_t pid, int terminal_fd, + NativeDelegate &delegate, + const ArchSpec &arch, Manager &manager, + llvm::ArrayRef<::pid_t> tids) + : NativeProcessProtocol(pid, terminal_fd, delegate), m_manager(manager), + m_arch(arch) { + manager.AddProcess(*this); + if (m_terminal_fd != -1) { + Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK); + assert(status.Success()); + } + + for (const auto &tid : tids) { + NativeThreadAIX &thread = AddThread(tid, /*resume*/ false); + ThreadWasCreated(thread); + } + + // Let our process instance know the thread has stopped. + SetCurrentThreadID(tids[0]); + SetState(StateType::eStateStopped, false); +} + +llvm::Expected> NativeProcessAIX::Attach(::pid_t pid) { + Log *log = GetLog(POSIXLog::Process); + + Status status; + if ((status = PtraceWrapper(PT_ATTACH, pid)).Fail()) { + return status.ToError(); + } + + int wpid = + llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, nullptr, WNOHANG); + if (wpid <= 0) { + return llvm::errorCodeToError( + std::error_code(errno, std::generic_category())); + } + + LLDB_LOG(log, "adding pid = {0}", pid); + + std::vector<::pid_t> tids; + tids.push_back(pid); + return std::move(tids); +} + +bool NativeProcessAIX::TryHandleWaitStatus(lldb::pid_t pid, + WaitStatus status) { + if (pid == GetID() && + (status.type == WaitStatus::Exit || status.type == WaitStatus::Signal)) { + // The process exited. We're done monitoring. Report to delegate. + SetExitStatus(status, true); + return true; + } + if (NativeThreadAIX *thread = GetThreadByID(pid)) { + MonitorCallback(*thread, status); + return true; + } + return false; +} + +// Handles all waitpid events from the inferior process. +void NativeProcessAIX::MonitorCallback(NativeThreadAIX &thread, + WaitStatus status) { + Log *log = GetLog(LLDBLog::Process); + + // Certain activities differ based on whether the pid is the tid of the main + // thread. + const bool is_main_thread = (thread.GetID() == GetID()); + + // Handle when the thread exits. + if (status.type == WaitStatus::Exit || status.type == WaitStatus::Signal) { + LLDB_LOG(log, + "got exit status({0}) , tid = {1} ({2} main thread), process " + "state = {3}", + status, thread.GetID(), is_main_thread ? "is" : "is not", + GetState()); + + // This is a thread that exited. Ensure we're not tracking it anymore. + StopTrackingThread(thread); + + assert(!is_main_thread && "Main thread exits handled elsewhere"); + return; + } + + int8_t signo = GetSignalInfo(status); + + // Get details on the signal raised. + if (signo) { + // We have retrieved the signal info. Dispatch appropriately. + if (signo == SIGTRAP) + MonitorSIGTRAP(status, thread); + else + MonitorSignal(status, thread); + } else { + assert(0); + } +} + + +void NativeProcessAIX::MonitorSIGTRAP(const WaitStatus status, + NativeThreadAIX &thread) { + Log *log = GetLog(POSIXLog::Process); + const bool is_main_thread = (thread.GetID() == GetID()); + + NativeRegisterContextAIX ®_ctx = thread.GetRegisterContext(); + const RegisterInfo *pc_info = reg_ctx.GetRegisterInfoByName("pc", 0); + RegisterValue pc_value; + + switch (status.status) { + case SIGTRAP: + // Determine the source of SIGTRAP by checking current instruction: + // if that is trap instruction, then this is breakpoint, otherwise + // this is watchpoint. + reg_ctx.ReadRegister(pc_info, pc_value); + + MonitorBreakpoint(thread); + break; + default: + LLDB_LOG(log, "received unknown SIGTRAP stop event ({0}, pid {1} tid {2}", + status.status, GetID(), thread.GetID()); + MonitorSignal(status, thread); + break; + } +} + +void NativeProcessAIX::MonitorTrace(NativeThreadAIX &thread) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "received trace event, pid = {0}", thread.GetID()); + + // This thread is currently stopped. + thread.SetStoppedByTrace(); + + StopRunningThreads(thread.GetID()); +} + +void NativeProcessAIX::MonitorBreakpoint(NativeThreadAIX &thread) { + Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints); + LLDB_LOG(log, "received breakpoint event, pid = {0}", thread.GetID()); + + // Mark the thread as stopped at breakpoint. + thread.SetStoppedByBreakpoint(); + FixupBreakpointPCAsNeeded(thread); + + if (m_threads_stepping_with_breakpoint.find(thread.GetID()) != + m_threads_stepping_with_breakpoint.end()) + thread.SetStoppedByTrace(); + + StopRunningThreads(thread.GetID()); +} + +void NativeProcessAIX::MonitorWatchpoint(NativeThreadAIX &thread, + uint32_t wp_index) { + Log *log = GetLog(LLDBLog::Process | LLDBLog::Watchpoints); + LLDB_LOG(log, "received watchpoint event, pid = {0}, wp_index = {1}", + thread.GetID(), wp_index); + + // Mark the thread as stopped at watchpoint. The address is at + // (lldb::addr_t)info->si_addr if we need it. + thread.SetStoppedByWatchpoint(wp_index); + + // We need to tell all other running threads before we notify the delegate + // about this stop. + StopRunningThreads(thread.GetID()); +} + +void NativeProcessAIX::MonitorSignal(const WaitStatus status, + NativeThreadAIX &thread) { + int8_t signo = GetSignalInfo(status); +#if 0 + const bool is_from_llgs = info.si_pid == getpid(); +#endif + + Log *log = GetLog(POSIXLog::Process); + + // POSIX says that process behaviour is undefined after it ignores a SIGFPE, + // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a kill(2) + // or raise(3). Similarly for tgkill(2) on AIX. + // + // IOW, user generated signals never generate what we consider to be a + // "crash". + // + // Similarly, ACK signals generated by this monitor. + + // Handle the signal. + LLDB_LOG(log, + "received signal {0} ({1}) with code NA, (siginfo pid = {2}, " + "waitpid pid = {3})", + Host::GetSignalAsCString(signo), signo, thread.GetID(), GetID()); + +#if 0 + // Check for thread stop notification. + // FIXME + if (is_from_llgs /*&& (info.si_code == SI_TKILL)*/ && (signo == SIGSTOP)) { + // This is a tgkill()-based stop. + LLDB_LOG(log, "pid {0} tid {1}, thread stopped", GetID(), thread.GetID()); + + // Check that we're not already marked with a stop reason. Note this thread + // really shouldn't already be marked as stopped - if we were, that would + // imply that the kernel signaled us with the thread stopping which we + // handled and marked as stopped, and that, without an intervening resume, + // we received another stop. It is more likely that we are missing the + // marking of a run state somewhere if we find that the thread was marked + // as stopped. + const StateType thread_state = thread.GetState(); + if (!StateIsStoppedState(thread_state, false)) { + // An inferior thread has stopped because of a SIGSTOP we have sent it. + // Generally, these are not important stops and we don't want to report + // them as they are just used to stop other threads when one thread (the + // one with the *real* stop reason) hits a breakpoint (watchpoint, + // etc...). However, in the case of an asynchronous Interrupt(), this + // *is* the real stop reason, so we leave the signal intact if this is + // the thread that was chosen as the triggering thread. + if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID) { + if (m_pending_notification_tid == thread.GetID()) + thread.SetStoppedBySignal(SIGSTOP, &info); + else + thread.SetStoppedWithNoReason(); + + SetCurrentThreadID(thread.GetID()); + SignalIfAllThreadsStopped(); + } else { + // We can end up here if stop was initiated by LLGS but by this time a + // thread stop has occurred - maybe initiated by another event. + Status error = ResumeThread(thread, thread.GetState(), 0); + if (error.Fail()) + LLDB_LOG(log, "failed to resume thread {0}: {1}", thread.GetID(), + error); + } + } else { + LLDB_LOG(log, + "pid {0} tid {1}, thread was already marked as a stopped " + "state (state={2}), leaving stop signal as is", + GetID(), thread.GetID(), thread_state); + SignalIfAllThreadsStopped(); + } + + // Done handling. + return; + } +#endif + + // Check if debugger should stop at this signal or just ignore it and resume + // the inferior. + if (m_signals_to_ignore.contains(signo) || signo == SIGCHLD) { + ResumeThread(thread, thread.GetState(), signo); + return; + } + + // This thread is stopped. + LLDB_LOG(log, "received signal {0}", Host::GetSignalAsCString(signo)); + thread.SetStoppedBySignal(signo); + + // Send a stop to the debugger after we get all other threads to stop. + StopRunningThreads(thread.GetID()); +} + +bool NativeProcessAIX::MonitorClone(NativeThreadAIX &parent, + lldb::pid_t child_pid, int event) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "parent_tid={0}, child_pid={1}, event={2}", parent.GetID(), + child_pid, event); + + // WaitForCloneNotification(child_pid); + + switch (event) { +#if 0 + case PTRACE_EVENT_CLONE: { + // PTRACE_EVENT_CLONE can either mean a new thread or a new process. + // Try to grab the new process' PGID to figure out which one it is. + // If PGID is the same as the PID, then it's a new process. Otherwise, + // it's a thread. + auto tgid_ret = getPIDForTID(child_pid); + if (tgid_ret != child_pid) { + // A new thread should have PGID matching our process' PID. + assert(!tgid_ret || tgid_ret.getValue() == GetID()); + + NativeThreadAIX &child_thread = AddThread(child_pid, /*resume*/ true); + ThreadWasCreated(child_thread); + + // Resume the parent. + ResumeThread(parent, parent.GetState(), LLDB_INVALID_SIGNAL_NUMBER); + break; + } + } + LLVM_FALLTHROUGH; + case PTRACE_EVENT_FORK: + case PTRACE_EVENT_VFORK: { + bool is_vfork = event == PTRACE_EVENT_VFORK; + std::unique_ptr child_process{new NativeProcessAIX( + static_cast<::pid_t>(child_pid), m_terminal_fd, m_delegate, m_arch, + m_main_loop, {static_cast<::pid_t>(child_pid)})}; + if (!is_vfork) + child_process->m_software_breakpoints = m_software_breakpoints; + + Extension expected_ext = is_vfork ? Extension::vfork : Extension::fork; + if (bool(m_enabled_extensions & expected_ext)) { + m_delegate.NewSubprocess(this, std::move(child_process)); + // NB: non-vfork clone() is reported as fork + parent.SetStoppedByFork(is_vfork, child_pid); + StopRunningThreads(parent.GetID()); + } else { + child_process->Detach(); + ResumeThread(parent, parent.GetState(), LLDB_INVALID_SIGNAL_NUMBER); + } + break; + } +#endif + default: + llvm_unreachable("unknown clone_info.event"); + } + + return true; +} + +bool NativeProcessAIX::SupportHardwareSingleStepping() const { + return false; +} + +Status NativeProcessAIX::Resume(const ResumeActionList &resume_actions) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "pid {0}", GetID()); + + bool software_single_step = !SupportHardwareSingleStepping(); + + if (software_single_step) { + for (const auto &thread : m_threads) { + assert(thread && "thread list should not contain NULL threads"); + + const ResumeAction *const action = + resume_actions.GetActionForThread(thread->GetID(), true); + if (action == nullptr) + continue; + + if (action->state == eStateStepping) { + Status error = SetupSoftwareSingleStepping( + static_cast(*thread)); + if (error.Fail()) + return error; + } + } + } + + for (const auto &thread : m_threads) { + assert(thread && "thread list should not contain NULL threads"); + + const ResumeAction *const action = + resume_actions.GetActionForThread(thread->GetID(), true); + + if (action == nullptr) { + LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(), + thread->GetID()); + continue; + } + + LLDB_LOG(log, "processing resume action state {0} for pid {1} tid {2}", + action->state, GetID(), thread->GetID()); + + switch (action->state) { + case eStateRunning: + case eStateStepping: { + // Run the thread, possibly feeding it the signal. + const int signo = action->signal; + Status error = ResumeThread(static_cast(*thread), + action->state, signo); + if (error.Fail()) + return Status("NativeProcessAIX::%s: failed to resume thread " + "for pid %" PRIu64 ", tid %" PRIu64 ", error = %s", + __FUNCTION__, GetID(), thread->GetID(), + error.AsCString()); + + break; + } + + case eStateSuspended: + case eStateStopped: + break; + + default: + return Status("NativeProcessAIX::%s (): unexpected state %s specified " + "for pid %" PRIu64 ", tid %" PRIu64, + __FUNCTION__, StateAsCString(action->state), GetID(), + thread->GetID()); + } + } + + return Status(); +} + +Status NativeProcessAIX::Halt() { + Status error; + + if (kill(GetID(), SIGSTOP) != 0) + error.SetErrorToErrno(); + + return error; +} + +Status NativeProcessAIX::Detach() { + Status error; + + // Tell ptrace to detach from the process. + if (GetID() == LLDB_INVALID_PROCESS_ID) + return error; + + // Cancel out any SIGSTOPs we may have sent while stopping the process. + // Otherwise, the process may stop as soon as we detach from it. + kill(GetID(), SIGCONT); + + for (const auto &thread : m_threads) { + Status e = Detach(thread->GetID()); + if (e.Fail()) + error = + e; // Save the error, but still attempt to detach from other threads. + } + + return error; +} + +Status NativeProcessAIX::Signal(int signo) { + Status error; + + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "sending signal {0} ({1}) to pid {1}", signo, + Host::GetSignalAsCString(signo), GetID()); + + if (kill(GetID(), signo)) + error.SetErrorToErrno(); + + return error; +} + +Status NativeProcessAIX::Interrupt() { + // Pick a running thread (or if none, a not-dead stopped thread) as the + // chosen thread that will be the stop-reason thread. + Log *log = GetLog(POSIXLog::Process); + + NativeThreadProtocol *running_thread = nullptr; + NativeThreadProtocol *stopped_thread = nullptr; + + LLDB_LOG(log, "selecting running thread for interrupt target"); + for (const auto &thread : m_threads) { + // If we have a running or stepping thread, we'll call that the target of + // the interrupt. + const auto thread_state = thread->GetState(); + if (thread_state == eStateRunning || thread_state == eStateStepping) { + running_thread = thread.get(); + break; + } else if (!stopped_thread && StateIsStoppedState(thread_state, true)) { + // Remember the first non-dead stopped thread. We'll use that as a + // backup if there are no running threads. + stopped_thread = thread.get(); + } + } + + if (!running_thread && !stopped_thread) { + Status error("found no running/stepping or live stopped threads as target " + "for interrupt"); + LLDB_LOG(log, "skipping due to error: {0}", error); + + return error; + } + + NativeThreadProtocol *deferred_signal_thread = + running_thread ? running_thread : stopped_thread; + + LLDB_LOG(log, "pid {0} {1} tid {2} chosen for interrupt target", GetID(), + running_thread ? "running" : "stopped", + deferred_signal_thread->GetID()); + + StopRunningThreads(deferred_signal_thread->GetID()); + + return Status(); +} + +Status NativeProcessAIX::Kill() { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "pid {0}", GetID()); + + Status error; + + switch (m_state) { + case StateType::eStateInvalid: + case StateType::eStateExited: + case StateType::eStateCrashed: + case StateType::eStateDetached: + case StateType::eStateUnloaded: + // Nothing to do - the process is already dead. + LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(), + m_state); + return error; + + case StateType::eStateConnected: + case StateType::eStateAttaching: + case StateType::eStateLaunching: + case StateType::eStateStopped: + case StateType::eStateRunning: + case StateType::eStateStepping: + case StateType::eStateSuspended: + // We can try to kill a process in these states. + break; + } + + if (kill(GetID(), SIGKILL) != 0) { + error.SetErrorToErrno(); + return error; + } + + return error; +} + +Status NativeProcessAIX::GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info) { + // FIXME review that the final memory region returned extends to the end of + // the virtual address space, + // with no perms if it is not mapped. + + // Use an approach that reads memory regions from /proc/{pid}/maps. Assume + // proc maps entries are in ascending order. + // FIXME assert if we find differently. + + if (m_supports_mem_region == LazyBool::eLazyBoolNo) { + // We're done. + return Status("unsupported"); + } + + Status error = PopulateMemoryRegionCache(); + if (error.Fail()) { + return error; + } + + lldb::addr_t prev_base_address = 0; + + // FIXME start by finding the last region that is <= target address using + // binary search. Data is sorted. + // There can be a ton of regions on pthreads apps with lots of threads. + for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end(); + ++it) { + MemoryRegionInfo &proc_entry_info = it->first; + + // Sanity check assumption that /proc/{pid}/maps entries are ascending. + assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) && + "descending /proc/pid/maps entries detected, unexpected"); + prev_base_address = proc_entry_info.GetRange().GetRangeBase(); + UNUSED_IF_ASSERT_DISABLED(prev_base_address); + + // If the target address comes before this entry, indicate distance to next + // region. + if (load_addr < proc_entry_info.GetRange().GetRangeBase()) { + range_info.GetRange().SetRangeBase(load_addr); + range_info.GetRange().SetByteSize( + proc_entry_info.GetRange().GetRangeBase() - load_addr); + range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); + + return error; + } else if (proc_entry_info.GetRange().Contains(load_addr)) { + // The target address is within the memory region we're processing here. + range_info = proc_entry_info; + return error; + } + + // The target memory address comes somewhere after the region we just + // parsed. + } + + // If we made it here, we didn't find an entry that contained the given + // address. Return the load_addr as start and the amount of bytes betwwen + // load address and the end of the memory as size. + range_info.GetRange().SetRangeBase(load_addr); + range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS); + range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); + return error; +} + +Status NativeProcessAIX::PopulateMemoryRegionCache() { + Log *log = GetLog(POSIXLog::Process); + + // If our cache is empty, pull the latest. There should always be at least + // one memory region if memory region handling is supported. + if (!m_mem_region_cache.empty()) { + LLDB_LOG(log, "reusing {0} cached memory region entries", + m_mem_region_cache.size()); + return Status(); + } + + Status Result; +#if 0 + AIXMapCallback callback = [&](llvm::Expected Info) { + if (Info) { + FileSpec file_spec(Info->GetName().GetCString()); + FileSystem::Instance().Resolve(file_spec); + m_mem_region_cache.emplace_back(*Info, file_spec); + return true; + } + + Result = Info.takeError(); + m_supports_mem_region = LazyBool::eLazyBoolNo; + LLDB_LOG(log, "failed to parse proc maps: {0}", Result); + return false; + }; + + // AIX kernel since 2.6.14 has /proc/{pid}/smaps + // if CONFIG_PROC_PAGE_MONITOR is enabled + auto BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "smaps"); + if (BufferOrError) + ParseAIXSMapRegions(BufferOrError.get()->getBuffer(), callback); + else { + BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "maps"); + if (!BufferOrError) { + m_supports_mem_region = LazyBool::eLazyBoolNo; + return BufferOrError.getError(); + } + + ParseAIXMapRegions(BufferOrError.get()->getBuffer(), callback); + } + + if (Result.Fail()) + return Result; + + if (m_mem_region_cache.empty()) { + // No entries after attempting to read them. This shouldn't happen if + // /proc/{pid}/maps is supported. Assume we don't support map entries via + // procfs. + m_supports_mem_region = LazyBool::eLazyBoolNo; + LLDB_LOG(log, + "failed to find any procfs maps entries, assuming no support " + "for memory region metadata retrieval"); + return Status("not supported"); + } + + LLDB_LOG(log, "read {0} memory region entries from /proc/{1}/maps", + m_mem_region_cache.size(), GetID()); + + // We support memory retrieval, remember that. + m_supports_mem_region = LazyBool::eLazyBoolYes; +#endif + return Status(); +} + +void NativeProcessAIX::DoStopIDBumped(uint32_t newBumpId) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "newBumpId={0}", newBumpId); + LLDB_LOG(log, "clearing {0} entries from memory region cache", + m_mem_region_cache.size()); + m_mem_region_cache.clear(); +} + +llvm::Expected +NativeProcessAIX::Syscall(llvm::ArrayRef args) { + PopulateMemoryRegionCache(); + auto region_it = llvm::find_if(m_mem_region_cache, [](const auto &pair) { + return pair.first.GetExecutable() == MemoryRegionInfo::eYes && + pair.first.GetShared() != MemoryRegionInfo::eYes; + }); + if (region_it == m_mem_region_cache.end()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "No executable memory region found!"); + + addr_t exe_addr = region_it->first.GetRange().GetRangeBase(); + + NativeThreadAIX &thread = *GetCurrentThread(); + assert(thread.GetState() == eStateStopped); + NativeRegisterContextAIX ®_ctx = thread.GetRegisterContext(); + + NativeRegisterContextAIX::SyscallData syscall_data = + *reg_ctx.GetSyscallData(); + + WritableDataBufferSP registers_sp; + if (llvm::Error Err = reg_ctx.ReadAllRegisterValues(registers_sp).ToError()) + return std::move(Err); + auto restore_regs = llvm::make_scope_exit( + [&] { reg_ctx.WriteAllRegisterValues(registers_sp); }); + + llvm::SmallVector memory(syscall_data.Insn.size()); + size_t bytes_read; + if (llvm::Error Err = + ReadMemory(exe_addr, memory.data(), memory.size(), bytes_read) + .ToError()) { + return std::move(Err); + } + + auto restore_mem = llvm::make_scope_exit( + [&] { WriteMemory(exe_addr, memory.data(), memory.size(), bytes_read); }); + + if (llvm::Error Err = reg_ctx.SetPC(exe_addr).ToError()) + return std::move(Err); + + for (const auto &zip : llvm::zip_first(args, syscall_data.Args)) { + if (llvm::Error Err = + reg_ctx + .WriteRegisterFromUnsigned(std::get<1>(zip), std::get<0>(zip)) + .ToError()) { + return std::move(Err); + } + } + if (llvm::Error Err = WriteMemory(exe_addr, syscall_data.Insn.data(), + syscall_data.Insn.size(), bytes_read) + .ToError()) + return std::move(Err); + + m_mem_region_cache.clear(); + + // With software single stepping the syscall insn buffer must also include a + // trap instruction to stop the process. + int req = SupportHardwareSingleStepping() ? PTRACE_SINGLESTEP : PTRACE_CONT; + if (llvm::Error Err = + PtraceWrapper(req, thread.GetID(), nullptr, nullptr).ToError()) + return std::move(Err); + + //FIXME + int status; + ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, ::waitpid, thread.GetID(), + &status, P_ALL/*__WALL*/); + if (wait_pid == -1) { + return llvm::errorCodeToError( + std::error_code(errno, std::generic_category())); + } + assert((unsigned)wait_pid == thread.GetID()); + + uint64_t result = reg_ctx.ReadRegisterAsUnsigned(syscall_data.Result, -ESRCH); + + // Values larger than this are actually negative errno numbers. + uint64_t errno_threshold = + (uint64_t(-1) >> (64 - 8 * m_arch.GetAddressByteSize())) - 0x1000; + if (result > errno_threshold) { + return llvm::errorCodeToError( + std::error_code(-result & 0xfff, std::generic_category())); + } + + return result; +} + +llvm::Expected +NativeProcessAIX::AllocateMemory(size_t size, uint32_t permissions) { + + std::optional mmap_data = + GetCurrentThread()->GetRegisterContext().GetMmapData(); + if (!mmap_data) + return llvm::make_error(); + + unsigned prot = PROT_NONE; + assert((permissions & (ePermissionsReadable | ePermissionsWritable | + ePermissionsExecutable)) == permissions && + "Unknown permission!"); + if (permissions & ePermissionsReadable) + prot |= PROT_READ; + if (permissions & ePermissionsWritable) + prot |= PROT_WRITE; + if (permissions & ePermissionsExecutable) + prot |= PROT_EXEC; + + llvm::Expected Result = + Syscall({mmap_data->SysMmap, 0, size, prot, MAP_ANONYMOUS | MAP_PRIVATE, + uint64_t(-1), 0}); + if (Result) + m_allocated_memory.try_emplace(*Result, size); + return Result; +} + +llvm::Error NativeProcessAIX::DeallocateMemory(lldb::addr_t addr) { + std::optional mmap_data = + GetCurrentThread()->GetRegisterContext().GetMmapData(); + if (!mmap_data) + return llvm::make_error(); + + auto it = m_allocated_memory.find(addr); + if (it == m_allocated_memory.end()) + return llvm::createStringError(llvm::errc::invalid_argument, + "Memory not allocated by the debugger."); + + llvm::Expected Result = + Syscall({mmap_data->SysMunmap, addr, it->second}); + if (!Result) + return Result.takeError(); + + m_allocated_memory.erase(it); + return llvm::Error::success(); +} + +Status NativeProcessAIX::ReadMemoryTags(int32_t type, lldb::addr_t addr, + size_t len, + std::vector &tags) { + llvm::Expected details = + GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); + if (!details) + return Status(details.takeError()); + + // Ignore 0 length read + if (!len) + return Status(); + + // lldb will align the range it requests but it is not required to by + // the protocol so we'll do it again just in case. + // Remove tag bits too. Ptrace calls may work regardless but that + // is not a guarantee. + MemoryTagManager::TagRange range(details->manager->RemoveTagBits(addr), len); + range = details->manager->ExpandToGranule(range); + + // Allocate enough space for all tags to be read + size_t num_tags = range.GetByteSize() / details->manager->GetGranuleSize(); + tags.resize(num_tags * details->manager->GetTagSizeInBytes()); + + struct iovec tags_iovec; + uint8_t *dest = tags.data(); + lldb::addr_t read_addr = range.GetRangeBase(); + + // This call can return partial data so loop until we error or + // get all tags back. + while (num_tags) { + tags_iovec.iov_base = dest; + tags_iovec.iov_len = num_tags; + + Status error = NativeProcessAIX::PtraceWrapper( + details->ptrace_read_req, GetCurrentThreadID(), + reinterpret_cast(read_addr), static_cast(&tags_iovec), + 0, nullptr); + + if (error.Fail()) { + // Discard partial reads + tags.resize(0); + return error; + } + + size_t tags_read = tags_iovec.iov_len; + assert(tags_read && (tags_read <= num_tags)); + + dest += tags_read * details->manager->GetTagSizeInBytes(); + read_addr += details->manager->GetGranuleSize() * tags_read; + num_tags -= tags_read; + } + + return Status(); +} + +Status NativeProcessAIX::WriteMemoryTags(int32_t type, lldb::addr_t addr, + size_t len, + const std::vector &tags) { + llvm::Expected details = + GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); + if (!details) + return Status(details.takeError()); + + // Ignore 0 length write + if (!len) + return Status(); + + // lldb will align the range it requests but it is not required to by + // the protocol so we'll do it again just in case. + // Remove tag bits too. Ptrace calls may work regardless but that + // is not a guarantee. + MemoryTagManager::TagRange range(details->manager->RemoveTagBits(addr), len); + range = details->manager->ExpandToGranule(range); + + // Not checking number of tags here, we may repeat them below + llvm::Expected> unpacked_tags_or_err = + details->manager->UnpackTagsData(tags); + if (!unpacked_tags_or_err) + return Status(unpacked_tags_or_err.takeError()); + + llvm::Expected> repeated_tags_or_err = + details->manager->RepeatTagsForRange(*unpacked_tags_or_err, range); + if (!repeated_tags_or_err) + return Status(repeated_tags_or_err.takeError()); + + // Repack them for ptrace to use + llvm::Expected> final_tag_data = + details->manager->PackTags(*repeated_tags_or_err); + if (!final_tag_data) + return Status(final_tag_data.takeError()); + + struct iovec tags_vec; + uint8_t *src = final_tag_data->data(); + lldb::addr_t write_addr = range.GetRangeBase(); + // unpacked tags size because the number of bytes per tag might not be 1 + size_t num_tags = repeated_tags_or_err->size(); + + // This call can partially write tags, so we loop until we + // error or all tags have been written. + while (num_tags > 0) { + tags_vec.iov_base = src; + tags_vec.iov_len = num_tags; + + Status error = NativeProcessAIX::PtraceWrapper( + details->ptrace_write_req, GetCurrentThreadID(), + reinterpret_cast(write_addr), static_cast(&tags_vec), 0, + nullptr); + + if (error.Fail()) { + // Don't attempt to restore the original values in the case of a partial + // write + return error; + } + + size_t tags_written = tags_vec.iov_len; + assert(tags_written && (tags_written <= num_tags)); + + src += tags_written * details->manager->GetTagSizeInBytes(); + write_addr += details->manager->GetGranuleSize() * tags_written; + num_tags -= tags_written; + } + + return Status(); +} + +size_t NativeProcessAIX::UpdateThreads() { + // The NativeProcessAIX monitoring threads are always up to date with + // respect to thread state and they keep the thread list populated properly. + // All this method needs to do is return the thread count. + return m_threads.size(); +} + +Status NativeProcessAIX::SetBreakpoint(lldb::addr_t addr, uint32_t size, + bool hardware) { + if (hardware) + return SetHardwareBreakpoint(addr, size); + else + return SetSoftwareBreakpoint(addr, size); +} + +Status NativeProcessAIX::RemoveBreakpoint(lldb::addr_t addr, bool hardware) { + if (hardware) + return RemoveHardwareBreakpoint(addr); + else + return NativeProcessProtocol::RemoveBreakpoint(addr); +} + +llvm::Expected> +NativeProcessAIX::GetSoftwareBreakpointTrapOpcode(size_t size_hint) { + // The ARM reference recommends the use of 0xe7fddefe and 0xdefe but the + // linux kernel does otherwise. + static const uint8_t g_arm_opcode[] = {0xf0, 0x01, 0xf0, 0xe7}; + static const uint8_t g_thumb_opcode[] = {0x01, 0xde}; + + switch (GetArchitecture().GetMachine()) { + case llvm::Triple::arm: + switch (size_hint) { + case 2: + return llvm::ArrayRef(g_thumb_opcode); + case 4: + return llvm::ArrayRef(g_arm_opcode); + default: + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Unrecognised trap opcode size hint!"); + } + default: + return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint); + } +} + +Status NativeProcessAIX::ReadMemory(lldb::addr_t addr, void *buf, size_t size, + size_t &bytes_read) { + unsigned char *dst = static_cast(buf); + size_t remainder; + long data; + + Log *log = GetLog(POSIXLog::Memory); + LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); + + for (bytes_read = 0; bytes_read < size; bytes_read += remainder) { + Status error = NativeProcessAIX::PtraceWrapper( + PT_READ_BLOCK, GetCurrentThreadID(), (void *)addr, nullptr, sizeof(data), &data); + if (error.Fail()) + return error; + + remainder = size - bytes_read; + remainder = remainder > k_ptrace_word_size ? k_ptrace_word_size : remainder; + + // Copy the data into our buffer + memcpy(dst, &data, remainder); + + LLDB_LOG(log, "[{0:x}]:{1:x}", addr, data); + addr += k_ptrace_word_size; + dst += k_ptrace_word_size; + } + return Status(); +} + +Status NativeProcessAIX::WriteMemory(lldb::addr_t addr, const void *buf, + size_t size, size_t &bytes_written) { + const unsigned char *src = static_cast(buf); + size_t remainder; + Status error; + + Log *log = GetLog(POSIXLog::Memory); + LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); + + error = NativeProcessAIX::PtraceWrapper( + PT_WRITE_BLOCK, GetCurrentThreadID(), (void *)addr, nullptr, (int)size, (long *)buf); + if (error.Fail()) + return error; + + bytes_written = size; + return error; +} + +int8_t NativeProcessAIX::GetSignalInfo(WaitStatus wstatus) const { + return wstatus.status; +} + +Status NativeProcessAIX::GetEventMessage(lldb::tid_t tid, + unsigned long *message) { + //FIXME + return PtraceWrapper(PT_CLEAR/*PTRACE_GETEVENTMSG*/, tid, nullptr, message); +} + +Status NativeProcessAIX::Detach(lldb::tid_t tid) { + if (tid == LLDB_INVALID_THREAD_ID) + return Status(); + + return PtraceWrapper(PT_DETACH, tid); +} + +bool NativeProcessAIX::HasThreadNoLock(lldb::tid_t thread_id) { + for (const auto &thread : m_threads) { + assert(thread && "thread list should not contain NULL threads"); + if (thread->GetID() == thread_id) { + // We have this thread. + return true; + } + } + + // We don't have this thread. + return false; +} + +void NativeProcessAIX::StopTrackingThread(NativeThreadAIX &thread) { + Log *const log = GetLog(POSIXLog::Thread); + lldb::tid_t thread_id = thread.GetID(); + LLDB_LOG(log, "tid: {0}", thread_id); + + auto it = llvm::find_if(m_threads, [&](const auto &thread_up) { + return thread_up.get() == &thread; + }); + assert(it != m_threads.end()); + m_threads.erase(it); + + NotifyTracersOfThreadDestroyed(thread_id); + SignalIfAllThreadsStopped(); +} + +void NativeProcessAIX::NotifyTracersProcessDidStop() { +} + +void NativeProcessAIX::NotifyTracersProcessWillResume() { +} + +Status NativeProcessAIX::NotifyTracersOfNewThread(lldb::tid_t tid) { + Log *log = GetLog(POSIXLog::Thread); + Status error; + return error; +} + +Status NativeProcessAIX::NotifyTracersOfThreadDestroyed(lldb::tid_t tid) { + Log *log = GetLog(POSIXLog::Thread); + Status error; + return error; +} + +NativeThreadAIX &NativeProcessAIX::AddThread(lldb::tid_t thread_id, + bool resume) { + Log *log = GetLog(POSIXLog::Thread); + LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id); + + assert(!HasThreadNoLock(thread_id) && + "attempted to add a thread by id that already exists"); + + // If this is the first thread, save it as the current thread + if (m_threads.empty()) + SetCurrentThreadID(thread_id); + + m_threads.push_back(std::make_unique(*this, thread_id)); + NativeThreadAIX &thread = + static_cast(*m_threads.back()); + + Status tracing_error = NotifyTracersOfNewThread(thread.GetID()); + if (tracing_error.Fail()) { + thread.SetStoppedByProcessorTrace(tracing_error.AsCString()); + StopRunningThreads(thread.GetID()); + } else if (resume) + ResumeThread(thread, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); + else + thread.SetStoppedBySignal(SIGSTOP); + + return thread; +} + +Status NativeProcessAIX::GetLoadedModuleFileSpec(const char *module_path, + FileSpec &file_spec) { + Status error = PopulateMemoryRegionCache(); + if (error.Fail()) + return error; + + FileSpec module_file_spec(module_path); + FileSystem::Instance().Resolve(module_file_spec); + + file_spec.Clear(); + for (const auto &it : m_mem_region_cache) { + if (it.second.GetFilename() == module_file_spec.GetFilename()) { + file_spec = it.second; + return Status(); + } + } + return Status("Module file (%s) not found in /proc/%" PRIu64 "/maps file!", + module_file_spec.GetFilename().AsCString(), GetID()); +} + +Status NativeProcessAIX::GetFileLoadAddress(const llvm::StringRef &file_name, + lldb::addr_t &load_addr) { + load_addr = LLDB_INVALID_ADDRESS; + + NativeThreadAIX &thread = *GetCurrentThread(); + NativeRegisterContextAIX ®_ctx = thread.GetRegisterContext(); + + // FIXME: buffer size + struct ld_xinfo info[64]; + if (ptrace64(PT_LDXINFO, reg_ctx.GetThread().GetID(), (long long)&(info[0]), sizeof(info), nullptr) == 0) { + load_addr = (unsigned long)info[0].ldinfo_textorg; + return Status(); + } + return Status("No load address found for specified file."); +} + +NativeThreadAIX *NativeProcessAIX::GetThreadByID(lldb::tid_t tid) { + return static_cast( + NativeProcessProtocol::GetThreadByID(tid)); +} + +NativeThreadAIX *NativeProcessAIX::GetCurrentThread() { + return static_cast( + NativeProcessProtocol::GetCurrentThread()); +} + +Status NativeProcessAIX::ResumeThread(NativeThreadAIX &thread, + lldb::StateType state, int signo) { + Log *const log = GetLog(POSIXLog::Thread); + LLDB_LOG(log, "tid: {0}", thread.GetID()); + + // Before we do the resume below, first check if we have a pending stop + // notification that is currently waiting for all threads to stop. This is + // potentially a buggy situation since we're ostensibly waiting for threads + // to stop before we send out the pending notification, and here we are + // resuming one before we send out the pending stop notification. + if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID) { + LLDB_LOG(log, + "about to resume tid {0} per explicit request but we have a " + "pending stop notification (tid {1}) that is actively " + "waiting for this thread to stop. Valid sequence of events?", + thread.GetID(), m_pending_notification_tid); + } + + // Request a resume. We expect this to be synchronous and the system to + // reflect it is running after this completes. + switch (state) { + case eStateRunning: { + const auto resume_result = thread.Resume(signo); + if (resume_result.Success()) + SetState(eStateRunning, true); + return resume_result; + } + case eStateStepping: { + const auto step_result = thread.SingleStep(signo); + if (step_result.Success()) + SetState(eStateRunning, true); + return step_result; + } + default: + LLDB_LOG(log, "Unhandled state {0}.", state); + llvm_unreachable("Unhandled state for resume"); + } +} + +//===----------------------------------------------------------------------===// + +void NativeProcessAIX::StopRunningThreads(const lldb::tid_t triggering_tid) { + Log *const log = GetLog(POSIXLog::Thread); + LLDB_LOG(log, "about to process event: (triggering_tid: {0})", + triggering_tid); + + m_pending_notification_tid = triggering_tid; + + // Request a stop for all the thread stops that need to be stopped and are + // not already known to be stopped. + for (const auto &thread : m_threads) { + if (StateIsRunningState(thread->GetState())) + static_cast(thread.get())->RequestStop(); + } + + SignalIfAllThreadsStopped(); + LLDB_LOG(log, "event processing done"); +} + +void NativeProcessAIX::SignalIfAllThreadsStopped() { + if (m_pending_notification_tid == LLDB_INVALID_THREAD_ID) + return; // No pending notification. Nothing to do. + + for (const auto &thread_sp : m_threads) { + if (StateIsRunningState(thread_sp->GetState())) + return; // Some threads are still running. Don't signal yet. + } + + // We have a pending notification and all threads have stopped. + Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints); + + // Clear any temporary breakpoints we used to implement software single + // stepping. + for (const auto &thread_info : m_threads_stepping_with_breakpoint) { + Status error = RemoveBreakpoint(thread_info.second); + if (error.Fail()) + LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}", + thread_info.first, error); + } + m_threads_stepping_with_breakpoint.clear(); + + // Notify the delegate about the stop + SetCurrentThreadID(m_pending_notification_tid); + SetState(StateType::eStateStopped, true); + m_pending_notification_tid = LLDB_INVALID_THREAD_ID; +} + +void NativeProcessAIX::ThreadWasCreated(NativeThreadAIX &thread) { + Log *const log = GetLog(POSIXLog::Thread); + LLDB_LOG(log, "tid: {0}", thread.GetID()); + + if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID && + StateIsRunningState(thread.GetState())) { + // We will need to wait for this new thread to stop as well before firing + // the notification. + thread.RequestStop(); + } +} + +#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT +#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h" +#undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT + +static void GetRegister(lldb::pid_t pid, long long addr, void *buf) { + uint64_t val = 0; + ptrace64(PT_READ_GPR, pid, addr, 0, (int *)&val); + *(uint64_t *)buf = llvm::byteswap(val); +} + +static void SetRegister(lldb::pid_t pid, long long addr, void *buf) { + uint64_t val = llvm::byteswap(*(uint64_t *)buf); + ptrace64(PT_WRITE_GPR, pid, addr, 0, (int *)&val); +} + +static void GetFPRegister(lldb::pid_t pid, long long addr, void *buf) { + uint64_t val = 0; + ptrace64(PT_READ_FPR, pid, addr, 0, (int *)&val); + *(uint64_t *)buf = llvm::byteswap(val); +} + +static void GetVMRegister(lldb::tid_t tid, long long addr, void *buf) { + uint64_t val = 0; + ptrace64(PTT_READ_VEC, tid, addr, 0, (int *)&val); + //*(uint64_t *)buf = llvm::byteswap(val); +} + +static void GetVSRegister(lldb::tid_t tid, long long addr, void *buf) { + uint64_t val = 0; + ptrace64(PTT_READ_VSX, tid, addr, 0, (int *)&val); + //*(uint64_t *)buf = llvm::byteswap(val); +} + +// Wrapper for ptrace to catch errors and log calls. Note that ptrace sets +// errno on error because -1 can be a valid result (i.e. for PTRACE_PEEK*) +Status NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid, void *addr, + void *data, size_t data_size, + long *result) { + Status error; + long int ret; + + Log *log = GetLog(POSIXLog::Ptrace); + + PtraceDisplayBytes(req, data, data_size); + + errno = 0; + + // for PTT_* + const char procdir[] = "/proc/"; + const char lwpdir[] = "/lwp/"; + std::string process_task_dir = procdir + std::to_string(pid) + lwpdir; + DIR *dirproc = opendir(process_task_dir.c_str()); + + lldb::tid_t tid = 0; + if (dirproc) { + struct dirent *direntry = nullptr; + while ((direntry = readdir(dirproc)) != nullptr) { + if (strcmp(direntry->d_name, ".") == 0 || strcmp(direntry->d_name, "..") == 0) { + continue; + } + tid = atoi(direntry->d_name); + break; + } + closedir(dirproc); + } + + if (req == PTRACE_GETREGS) { + GetRegister(pid, GPR0, &(((GPR *)data)->r0)); + GetRegister(pid, GPR1, &(((GPR *)data)->r1)); + GetRegister(pid, GPR2, &(((GPR *)data)->r2)); + GetRegister(pid, GPR3, &(((GPR *)data)->r3)); + GetRegister(pid, GPR4, &(((GPR *)data)->r4)); + GetRegister(pid, GPR5, &(((GPR *)data)->r5)); + GetRegister(pid, GPR6, &(((GPR *)data)->r6)); + GetRegister(pid, GPR7, &(((GPR *)data)->r7)); + GetRegister(pid, GPR8, &(((GPR *)data)->r8)); + GetRegister(pid, GPR9, &(((GPR *)data)->r9)); + GetRegister(pid, GPR10, &(((GPR *)data)->r10)); + GetRegister(pid, GPR11, &(((GPR *)data)->r11)); + GetRegister(pid, GPR12, &(((GPR *)data)->r12)); + GetRegister(pid, GPR13, &(((GPR *)data)->r13)); + GetRegister(pid, GPR14, &(((GPR *)data)->r14)); + GetRegister(pid, GPR15, &(((GPR *)data)->r15)); + GetRegister(pid, GPR16, &(((GPR *)data)->r16)); + GetRegister(pid, GPR17, &(((GPR *)data)->r17)); + GetRegister(pid, GPR18, &(((GPR *)data)->r18)); + GetRegister(pid, GPR19, &(((GPR *)data)->r19)); + GetRegister(pid, GPR20, &(((GPR *)data)->r20)); + GetRegister(pid, GPR21, &(((GPR *)data)->r21)); + GetRegister(pid, GPR22, &(((GPR *)data)->r22)); + GetRegister(pid, GPR23, &(((GPR *)data)->r23)); + GetRegister(pid, GPR24, &(((GPR *)data)->r24)); + GetRegister(pid, GPR25, &(((GPR *)data)->r25)); + GetRegister(pid, GPR26, &(((GPR *)data)->r26)); + GetRegister(pid, GPR27, &(((GPR *)data)->r27)); + GetRegister(pid, GPR28, &(((GPR *)data)->r28)); + GetRegister(pid, GPR29, &(((GPR *)data)->r29)); + GetRegister(pid, GPR30, &(((GPR *)data)->r30)); + GetRegister(pid, GPR31, &(((GPR *)data)->r31)); + GetRegister(pid, IAR, &(((GPR *)data)->pc)); + GetRegister(pid, MSR, &(((GPR *)data)->msr)); + //FIXME: origr3/softe/trap on AIX? + GetRegister(pid, CTR, &(((GPR *)data)->ctr)); + GetRegister(pid, LR, &(((GPR *)data)->lr)); + GetRegister(pid, XER, &(((GPR *)data)->xer)); + GetRegister(pid, CR, &(((GPR *)data)->cr)); + } else if (req == PTRACE_SETREGS) { + SetRegister(pid, GPR0, &(((GPR *)data)->r0)); + SetRegister(pid, GPR1, &(((GPR *)data)->r1)); + SetRegister(pid, GPR2, &(((GPR *)data)->r2)); + SetRegister(pid, GPR3, &(((GPR *)data)->r3)); + SetRegister(pid, GPR4, &(((GPR *)data)->r4)); + SetRegister(pid, GPR5, &(((GPR *)data)->r5)); + SetRegister(pid, GPR6, &(((GPR *)data)->r6)); + SetRegister(pid, GPR7, &(((GPR *)data)->r7)); + SetRegister(pid, GPR8, &(((GPR *)data)->r8)); + SetRegister(pid, GPR9, &(((GPR *)data)->r9)); + SetRegister(pid, GPR10, &(((GPR *)data)->r10)); + SetRegister(pid, GPR11, &(((GPR *)data)->r11)); + SetRegister(pid, GPR12, &(((GPR *)data)->r12)); + SetRegister(pid, GPR13, &(((GPR *)data)->r13)); + SetRegister(pid, GPR14, &(((GPR *)data)->r14)); + SetRegister(pid, GPR15, &(((GPR *)data)->r15)); + SetRegister(pid, GPR16, &(((GPR *)data)->r16)); + SetRegister(pid, GPR17, &(((GPR *)data)->r17)); + SetRegister(pid, GPR18, &(((GPR *)data)->r18)); + SetRegister(pid, GPR19, &(((GPR *)data)->r19)); + SetRegister(pid, GPR20, &(((GPR *)data)->r20)); + SetRegister(pid, GPR21, &(((GPR *)data)->r21)); + SetRegister(pid, GPR22, &(((GPR *)data)->r22)); + SetRegister(pid, GPR23, &(((GPR *)data)->r23)); + SetRegister(pid, GPR24, &(((GPR *)data)->r24)); + SetRegister(pid, GPR25, &(((GPR *)data)->r25)); + SetRegister(pid, GPR26, &(((GPR *)data)->r26)); + SetRegister(pid, GPR27, &(((GPR *)data)->r27)); + SetRegister(pid, GPR28, &(((GPR *)data)->r28)); + SetRegister(pid, GPR29, &(((GPR *)data)->r29)); + SetRegister(pid, GPR30, &(((GPR *)data)->r30)); + SetRegister(pid, GPR31, &(((GPR *)data)->r31)); + SetRegister(pid, IAR, &(((GPR *)data)->pc)); + SetRegister(pid, MSR, &(((GPR *)data)->msr)); + //FIXME: origr3/softe/trap on AIX? + SetRegister(pid, CTR, &(((GPR *)data)->ctr)); + SetRegister(pid, LR, &(((GPR *)data)->lr)); + SetRegister(pid, XER, &(((GPR *)data)->xer)); + SetRegister(pid, CR, &(((GPR *)data)->cr)); + } else if (req == PTRACE_GETFPREGS) { + GetFPRegister(pid, FPR0, &(((FPR *)data)->f0)); + GetFPRegister(pid, FPR1, &(((FPR *)data)->f1)); + GetFPRegister(pid, FPR2, &(((FPR *)data)->f2)); + GetFPRegister(pid, FPR3, &(((FPR *)data)->f3)); + GetFPRegister(pid, FPR4, &(((FPR *)data)->f4)); + GetFPRegister(pid, FPR5, &(((FPR *)data)->f5)); + GetFPRegister(pid, FPR6, &(((FPR *)data)->f6)); + GetFPRegister(pid, FPR7, &(((FPR *)data)->f7)); + GetFPRegister(pid, FPR8, &(((FPR *)data)->f8)); + GetFPRegister(pid, FPR9, &(((FPR *)data)->f9)); + GetFPRegister(pid, FPR10, &(((FPR *)data)->f10)); + GetFPRegister(pid, FPR11, &(((FPR *)data)->f11)); + GetFPRegister(pid, FPR12, &(((FPR *)data)->f12)); + GetFPRegister(pid, FPR13, &(((FPR *)data)->f13)); + GetFPRegister(pid, FPR14, &(((FPR *)data)->f14)); + GetFPRegister(pid, FPR15, &(((FPR *)data)->f15)); + GetFPRegister(pid, FPR16, &(((FPR *)data)->f16)); + GetFPRegister(pid, FPR17, &(((FPR *)data)->f17)); + GetFPRegister(pid, FPR18, &(((FPR *)data)->f18)); + GetFPRegister(pid, FPR19, &(((FPR *)data)->f19)); + GetFPRegister(pid, FPR20, &(((FPR *)data)->f20)); + GetFPRegister(pid, FPR21, &(((FPR *)data)->f21)); + GetFPRegister(pid, FPR22, &(((FPR *)data)->f22)); + GetFPRegister(pid, FPR23, &(((FPR *)data)->f23)); + GetFPRegister(pid, FPR24, &(((FPR *)data)->f24)); + GetFPRegister(pid, FPR25, &(((FPR *)data)->f25)); + GetFPRegister(pid, FPR26, &(((FPR *)data)->f26)); + GetFPRegister(pid, FPR27, &(((FPR *)data)->f27)); + GetFPRegister(pid, FPR28, &(((FPR *)data)->f28)); + GetFPRegister(pid, FPR29, &(((FPR *)data)->f29)); + GetFPRegister(pid, FPR30, &(((FPR *)data)->f30)); + GetFPRegister(pid, FPR31, &(((FPR *)data)->f31)); + GetFPRegister(pid, FPSCR, &(((FPR *)data)->fpscr)); + } else if (req == PTRACE_GETVRREGS && tid) { + GetVMRegister(tid, VR0, &(((VMX *)data)->vr0[0])); + GetVMRegister(tid, VR1, &(((VMX *)data)->vr1[0])); + GetVMRegister(tid, VR2, &(((VMX *)data)->vr2[0])); + GetVMRegister(tid, VR3, &(((VMX *)data)->vr3[0])); + GetVMRegister(tid, VR4, &(((VMX *)data)->vr4[0])); + GetVMRegister(tid, VR5, &(((VMX *)data)->vr5[0])); + GetVMRegister(tid, VR6, &(((VMX *)data)->vr6[0])); + GetVMRegister(tid, VR7, &(((VMX *)data)->vr7[0])); + GetVMRegister(tid, VR8, &(((VMX *)data)->vr8[0])); + GetVMRegister(tid, VR9, &(((VMX *)data)->vr9[0])); + GetVMRegister(tid, VR10, &(((VMX *)data)->vr10[0])); + GetVMRegister(tid, VR11, &(((VMX *)data)->vr11[0])); + GetVMRegister(tid, VR12, &(((VMX *)data)->vr12[0])); + GetVMRegister(tid, VR13, &(((VMX *)data)->vr13[0])); + GetVMRegister(tid, VR14, &(((VMX *)data)->vr14[0])); + GetVMRegister(tid, VR15, &(((VMX *)data)->vr15[0])); + GetVMRegister(tid, VR16, &(((VMX *)data)->vr16[0])); + GetVMRegister(tid, VR17, &(((VMX *)data)->vr17[0])); + GetVMRegister(tid, VR18, &(((VMX *)data)->vr18[0])); + GetVMRegister(tid, VR19, &(((VMX *)data)->vr19[0])); + GetVMRegister(tid, VR20, &(((VMX *)data)->vr20[0])); + GetVMRegister(tid, VR21, &(((VMX *)data)->vr21[0])); + GetVMRegister(tid, VR22, &(((VMX *)data)->vr22[0])); + GetVMRegister(tid, VR23, &(((VMX *)data)->vr23[0])); + GetVMRegister(tid, VR24, &(((VMX *)data)->vr24[0])); + GetVMRegister(tid, VR25, &(((VMX *)data)->vr25[0])); + GetVMRegister(tid, VR26, &(((VMX *)data)->vr26[0])); + GetVMRegister(tid, VR27, &(((VMX *)data)->vr27[0])); + GetVMRegister(tid, VR28, &(((VMX *)data)->vr28[0])); + GetVMRegister(tid, VR29, &(((VMX *)data)->vr29[0])); + GetVMRegister(tid, VR30, &(((VMX *)data)->vr30[0])); + GetVMRegister(tid, VR31, &(((VMX *)data)->vr31[0])); + GetVMRegister(tid, VSCR, &(((VMX *)data)->vscr[0])); + GetVMRegister(tid, VRSAVE, &(((VMX *)data)->vrsave)); + } else if (req == PTRACE_GETVSRREGS && tid) { + GetVSRegister(tid, VSR0, &(((VSX *)data)->vs0[0])); + GetVSRegister(tid, VSR1, &(((VSX *)data)->vs1[0])); + GetVSRegister(tid, VSR2, &(((VSX *)data)->vs2[0])); + GetVSRegister(tid, VSR3, &(((VSX *)data)->vs3[0])); + GetVSRegister(tid, VSR4, &(((VSX *)data)->vs4[0])); + GetVSRegister(tid, VSR5, &(((VSX *)data)->vs5[0])); + GetVSRegister(tid, VSR6, &(((VSX *)data)->vs6[0])); + GetVSRegister(tid, VSR7, &(((VSX *)data)->vs7[0])); + GetVSRegister(tid, VSR8, &(((VSX *)data)->vs8[0])); + GetVSRegister(tid, VSR9, &(((VSX *)data)->vs9[0])); + GetVSRegister(tid, VSR10, &(((VSX *)data)->vs10[0])); + GetVSRegister(tid, VSR11, &(((VSX *)data)->vs11[0])); + GetVSRegister(tid, VSR12, &(((VSX *)data)->vs12[0])); + GetVSRegister(tid, VSR13, &(((VSX *)data)->vs13[0])); + GetVSRegister(tid, VSR14, &(((VSX *)data)->vs14[0])); + GetVSRegister(tid, VSR15, &(((VSX *)data)->vs15[0])); + GetVSRegister(tid, VSR16, &(((VSX *)data)->vs16[0])); + GetVSRegister(tid, VSR17, &(((VSX *)data)->vs17[0])); + GetVSRegister(tid, VSR18, &(((VSX *)data)->vs18[0])); + GetVSRegister(tid, VSR19, &(((VSX *)data)->vs19[0])); + GetVSRegister(tid, VSR20, &(((VSX *)data)->vs20[0])); + GetVSRegister(tid, VSR21, &(((VSX *)data)->vs21[0])); + GetVSRegister(tid, VSR22, &(((VSX *)data)->vs22[0])); + GetVSRegister(tid, VSR23, &(((VSX *)data)->vs23[0])); + GetVSRegister(tid, VSR24, &(((VSX *)data)->vs24[0])); + GetVSRegister(tid, VSR25, &(((VSX *)data)->vs25[0])); + GetVSRegister(tid, VSR26, &(((VSX *)data)->vs26[0])); + GetVSRegister(tid, VSR27, &(((VSX *)data)->vs27[0])); + GetVSRegister(tid, VSR28, &(((VSX *)data)->vs28[0])); + GetVSRegister(tid, VSR29, &(((VSX *)data)->vs29[0])); + GetVSRegister(tid, VSR30, &(((VSX *)data)->vs30[0])); + GetVSRegister(tid, VSR31, &(((VSX *)data)->vs31[0])); + GetVSRegister(tid, VSR32, &(((VSX *)data)->vs32[0])); + GetVSRegister(tid, VSR33, &(((VSX *)data)->vs33[0])); + GetVSRegister(tid, VSR34, &(((VSX *)data)->vs34[0])); + GetVSRegister(tid, VSR35, &(((VSX *)data)->vs35[0])); + GetVSRegister(tid, VSR36, &(((VSX *)data)->vs36[0])); + GetVSRegister(tid, VSR37, &(((VSX *)data)->vs37[0])); + GetVSRegister(tid, VSR38, &(((VSX *)data)->vs38[0])); + GetVSRegister(tid, VSR39, &(((VSX *)data)->vs39[0])); + GetVSRegister(tid, VSR40, &(((VSX *)data)->vs40[0])); + GetVSRegister(tid, VSR41, &(((VSX *)data)->vs41[0])); + GetVSRegister(tid, VSR42, &(((VSX *)data)->vs42[0])); + GetVSRegister(tid, VSR43, &(((VSX *)data)->vs43[0])); + GetVSRegister(tid, VSR44, &(((VSX *)data)->vs44[0])); + GetVSRegister(tid, VSR45, &(((VSX *)data)->vs45[0])); + GetVSRegister(tid, VSR46, &(((VSX *)data)->vs46[0])); + GetVSRegister(tid, VSR47, &(((VSX *)data)->vs47[0])); + GetVSRegister(tid, VSR48, &(((VSX *)data)->vs48[0])); + GetVSRegister(tid, VSR49, &(((VSX *)data)->vs49[0])); + GetVSRegister(tid, VSR50, &(((VSX *)data)->vs50[0])); + GetVSRegister(tid, VSR51, &(((VSX *)data)->vs51[0])); + GetVSRegister(tid, VSR52, &(((VSX *)data)->vs52[0])); + GetVSRegister(tid, VSR53, &(((VSX *)data)->vs53[0])); + GetVSRegister(tid, VSR54, &(((VSX *)data)->vs54[0])); + GetVSRegister(tid, VSR55, &(((VSX *)data)->vs55[0])); + GetVSRegister(tid, VSR56, &(((VSX *)data)->vs56[0])); + GetVSRegister(tid, VSR57, &(((VSX *)data)->vs57[0])); + GetVSRegister(tid, VSR58, &(((VSX *)data)->vs58[0])); + GetVSRegister(tid, VSR59, &(((VSX *)data)->vs59[0])); + GetVSRegister(tid, VSR60, &(((VSX *)data)->vs60[0])); + GetVSRegister(tid, VSR61, &(((VSX *)data)->vs61[0])); + GetVSRegister(tid, VSR62, &(((VSX *)data)->vs62[0])); + GetVSRegister(tid, VSR63, &(((VSX *)data)->vs63[0])); + } else if (req < PT_COMMAND_MAX) { + if (req == PT_CONTINUE) { +#if 0 + // Use PTT_CONTINUE + const char procdir[] = "/proc/"; + const char lwpdir[] = "/lwp/"; + std::string process_task_dir = procdir + std::to_string(pid) + lwpdir; + DIR *dirproc = opendir(process_task_dir.c_str()); + + struct ptthreads64 pts; + int idx = 0; + lldb::tid_t tid = 0; + if (dirproc) { + struct dirent *direntry = nullptr; + while ((direntry = readdir(dirproc)) != nullptr) { + if (strcmp(direntry->d_name, ".") == 0 || strcmp(direntry->d_name, "..") == 0) { + continue; + } + tid = atoi(direntry->d_name); + pts.th[idx++] = tid; + } + closedir(dirproc); + } + pts.th[idx] = 0; + ret = ptrace64(PTT_CONTINUE, tid, (long long)1, (int)(size_t)data, (int *)&pts); +#else + int buf; + ptrace64(req, pid, 1, (int)(size_t)data, &buf); +#endif + } else if (req == PT_READ_BLOCK) { + ptrace64(req, pid, (long long)addr, (int)data_size, (int *)result); + } else if (req == PT_WRITE_BLOCK) { + ptrace64(req, pid, (long long)addr, (int)data_size, (int *)result); + } else if (req == PT_ATTACH) { + ptrace64(req, pid, 0, 0, nullptr); + } else if (req == PT_WATCH) { + ptrace64(req, pid, (long long)addr, (int)data_size, nullptr); + } else if (req == PT_DETACH) { + ptrace64(req, pid, 0, 0, nullptr); + } else { + assert(0 && "Not supported yet."); + } + } else { + assert(0 && "Not supported yet."); + } + + if (errno) { + error.SetErrorToErrno(); + ret = -1; + } + + LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3}, {4})={5:x}", req, pid, addr, data, + data_size, ret); + + PtraceDisplayBytes(req, data, data_size); + + if (error.Fail()) + LLDB_LOG(log, "ptrace() failed: {0}", error); + + return error; +} + +llvm::Expected NativeProcessAIX::TraceSupported() { + return NativeProcessProtocol::TraceSupported(); +} + +Error NativeProcessAIX::TraceStart(StringRef json_request, StringRef type) { + return NativeProcessProtocol::TraceStart(json_request, type); +} + +Error NativeProcessAIX::TraceStop(const TraceStopRequest &request) { + return NativeProcessProtocol::TraceStop(request); +} + +Expected NativeProcessAIX::TraceGetState(StringRef type) { + return NativeProcessProtocol::TraceGetState(type); +} + +Expected> NativeProcessAIX::TraceGetBinaryData( + const TraceGetBinaryDataRequest &request) { + return NativeProcessProtocol::TraceGetBinaryData(request); +} diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h new file mode 100644 index 0000000000000..bdb6f7c500885 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h @@ -0,0 +1,283 @@ +//===-- NativeProcessAIX.h ---------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeProcessAIX_H_ +#define liblldb_NativeProcessAIX_H_ + +#include +#include + +#include "lldb/Host/Debug.h" +#include "lldb/Host/HostThread.h" +#include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/lldb-types.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "lldb/Host/aix/Support.h" + +#include "NativeThreadAIX.h" +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h" + +namespace lldb_private { +class Status; +class Scalar; + +namespace process_aix { +/// \class NativeProcessAIX +/// Manages communication with the inferior (debugee) process. +/// +/// Upon construction, this class prepares and launches an inferior process +/// for debugging. +/// +/// Changes in the inferior process state are broadcasted. +class NativeProcessAIX : public NativeProcessProtocol, + private NativeProcessSoftwareSingleStep { +public: + class Manager : public NativeProcessProtocol::Manager { + public: + Manager(MainLoop &mainloop); + + llvm::Expected> + Launch(ProcessLaunchInfo &launch_info, + NativeDelegate &native_delegate) override; + + llvm::Expected> + Attach(lldb::pid_t pid, NativeDelegate &native_delegate) override; + + Extension GetSupportedExtensions() const override; + + void AddProcess(NativeProcessAIX &process) { + m_processes.insert(&process); + } + + void RemoveProcess(NativeProcessAIX &process) { + m_processes.erase(&process); + } + + // Collect an event for the given tid, waiting for it if necessary. + void CollectThread(::pid_t tid); + + private: + MainLoop::SignalHandleUP m_sigchld_handle; + + llvm::SmallPtrSet m_processes; + + // Threads (events) which haven't been claimed by any process. + llvm::DenseSet<::pid_t> m_unowned_threads; + + void SigchldHandler(); + }; + + // NativeProcessProtocol Interface + + ~NativeProcessAIX() override { m_manager.RemoveProcess(*this); } + + Status Resume(const ResumeActionList &resume_actions) override; + + Status Halt() override; + + Status Detach() override; + + Status Signal(int signo) override; + + Status Interrupt() override; + + Status Kill() override; + + lldb::addr_t GetSharedLibraryInfoAddress() override; + + Status GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info) override; + + Status ReadMemory(lldb::addr_t addr, void *buf, size_t size, + size_t &bytes_read) override; + + Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, + size_t &bytes_written) override; + + llvm::Expected AllocateMemory(size_t size, + uint32_t permissions) override; + + llvm::Error DeallocateMemory(lldb::addr_t addr) override; + + Status ReadMemoryTags(int32_t type, lldb::addr_t addr, size_t len, + std::vector &tags) override; + + Status WriteMemoryTags(int32_t type, lldb::addr_t addr, size_t len, + const std::vector &tags) override; + + size_t UpdateThreads() override; + + const ArchSpec &GetArchitecture() const override { return m_arch; } + + Status SetBreakpoint(lldb::addr_t addr, uint32_t size, + bool hardware) override; + + Status RemoveBreakpoint(lldb::addr_t addr, bool hardware = false) override; + + void DoStopIDBumped(uint32_t newBumpId) override; + + Status GetLoadedModuleFileSpec(const char *module_path, + FileSpec &file_spec) override; + + Status GetFileLoadAddress(const llvm::StringRef &file_name, + lldb::addr_t &load_addr) override; + + NativeThreadAIX *GetThreadByID(lldb::tid_t id); + NativeThreadAIX *GetCurrentThread(); + + llvm::ErrorOr> + GetAuxvData() const override { + // Not available on this target. + return llvm::errc::not_supported; + } + + /// Tracing + /// These methods implement the jLLDBTrace packets + /// \{ + llvm::Error TraceStart(llvm::StringRef json_request, + llvm::StringRef type) override; + + llvm::Error TraceStop(const TraceStopRequest &request) override; + + llvm::Expected + TraceGetState(llvm::StringRef type) override; + + llvm::Expected> + TraceGetBinaryData(const TraceGetBinaryDataRequest &request) override; + + llvm::Expected TraceSupported() override; + /// } + + // Interface used by NativeRegisterContext-derived classes. + static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr, + void *data = nullptr, size_t data_size = 0, + long *result = nullptr); + + bool SupportHardwareSingleStepping() const; + + /// Writes a siginfo_t structure corresponding to the given thread ID to the + /// memory region pointed to by \p siginfo. + int8_t GetSignalInfo(WaitStatus wstatus) const; + +protected: + llvm::Expected> + GetSoftwareBreakpointTrapOpcode(size_t size_hint) override; + + llvm::Expected Syscall(llvm::ArrayRef args); + +private: + Manager &m_manager; + /*MainLoop::SignalHandleUP m_sigchld_handle;*/ + ArchSpec m_arch; + /*MainLoop& m_main_loop;*/ + + LazyBool m_supports_mem_region = eLazyBoolCalculate; + std::vector> m_mem_region_cache; + + lldb::tid_t m_pending_notification_tid = LLDB_INVALID_THREAD_ID; + + /// Inferior memory (allocated by us) and its size. + llvm::DenseMap m_allocated_memory; + + // Private Instance Methods + NativeProcessAIX(::pid_t pid, int terminal_fd, NativeDelegate &delegate, + const ArchSpec &arch, Manager &manager, + llvm::ArrayRef<::pid_t> tids); + + // Returns a list of process threads that we have attached to. + static llvm::Expected> Attach(::pid_t pid); + + static Status SetDefaultPtraceOpts(const lldb::pid_t); + + bool TryHandleWaitStatus(lldb::pid_t pid, WaitStatus status); + + void MonitorCallback(NativeThreadAIX &thread, WaitStatus status); + + void MonitorSIGTRAP(const WaitStatus status, NativeThreadAIX &thread); + + void MonitorTrace(NativeThreadAIX &thread); + + void MonitorBreakpoint(NativeThreadAIX &thread); + + void MonitorWatchpoint(NativeThreadAIX &thread, uint32_t wp_index); + + void MonitorSignal(const WaitStatus status, NativeThreadAIX &thread); + + bool HasThreadNoLock(lldb::tid_t thread_id); + + void StopTrackingThread(NativeThreadAIX &thread); + + /// Create a new thread. + /// + /// If process tracing is enabled and the thread can't be traced, then the + /// thread is left stopped with a \a eStopReasonProcessorTrace status, and + /// then the process is stopped. + /// + /// \param[in] resume + /// If a tracing error didn't happen, then resume the thread after + /// creation if \b true, or leave it stopped with SIGSTOP if \b false. + NativeThreadAIX &AddThread(lldb::tid_t thread_id, bool resume); + + /// Start tracing a new thread if process tracing is enabled. + /// + /// Trace mechanisms should modify this method to provide automatic tracing + /// for new threads. + Status NotifyTracersOfNewThread(lldb::tid_t tid); + + /// Stop tracing threads upon a destroy event. + /// + /// Trace mechanisms should modify this method to provide automatic trace + /// stopping for threads being destroyed. + Status NotifyTracersOfThreadDestroyed(lldb::tid_t tid); + + void NotifyTracersProcessWillResume() override; + + void NotifyTracersProcessDidStop() override; + /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG) + /// corresponding to the given thread ID to the memory pointed to by @p + /// message. + Status GetEventMessage(lldb::tid_t tid, unsigned long *message); + + void NotifyThreadDeath(lldb::tid_t tid); + + Status Detach(lldb::tid_t tid); + + // This method is requests a stop on all threads which are still running. It + // sets up a + // deferred delegate notification, which will fire once threads report as + // stopped. The + // triggerring_tid will be set as the current thread (main stop reason). + void StopRunningThreads(lldb::tid_t triggering_tid); + + // Notify the delegate if all threads have stopped. + void SignalIfAllThreadsStopped(); + + // Resume the given thread, optionally passing it the given signal. The type + // of resume + // operation (continue, single-step) depends on the state parameter. + Status ResumeThread(NativeThreadAIX &thread, lldb::StateType state, + int signo); + + void ThreadWasCreated(NativeThreadAIX &thread); + + void SigchldHandler(); + + Status PopulateMemoryRegionCache(); + + // Handle a clone()-like event. + bool MonitorClone(NativeThreadAIX &parent, lldb::pid_t child_pid, + int event); +}; + +} // namespace process_aix +} // namespace lldb_private + +#endif // #ifndef liblldb_NativeProcessAIX_H_ diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp new file mode 100644 index 0000000000000..0859f9501c1b6 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp @@ -0,0 +1,157 @@ +//===-- NativeRegisterContextAIX.cpp ------------------------------------===// +// +// 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 "NativeRegisterContextAIX.h" + +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/Utility/RegisterValue.h" + +#include "Plugins/Process/AIX/NativeProcessAIX.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "lldb/Host/aix/Ptrace.h" + +using namespace lldb_private; +using namespace lldb_private::process_aix; + +lldb::ByteOrder NativeRegisterContextAIX::GetByteOrder() const { + return m_thread.GetProcess().GetByteOrder(); +} + +Status NativeRegisterContextAIX::ReadRegisterRaw(uint32_t reg_index, + RegisterValue ®_value) { + const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); + if (!reg_info) + return Status("register %" PRIu32 " not found", reg_index); + + return DoReadRegisterValue(GetPtraceOffset(reg_index), reg_info->name, + reg_info->byte_size, reg_value); +} + +Status +NativeRegisterContextAIX::WriteRegisterRaw(uint32_t reg_index, + const RegisterValue ®_value) { + uint32_t reg_to_write = reg_index; + RegisterValue value_to_write = reg_value; + + // Check if this is a subregister of a full register. + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index); + if (reg_info->invalidate_regs && + (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) { + Status error; + + RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + error = ReadRegister(full_reg_info, full_value); + if (error.Fail()) + return error; + + lldb::ByteOrder byte_order = GetByteOrder(); + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData( + *full_reg_info, dst, sizeof(dst), byte_order, error); + if (error.Success() && dest_size) { + uint8_t src[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = reg_value.GetAsMemoryData( + *reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) { + // Copy the src bytes to the destination. + memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(*full_reg_info); + reg_to_write = full_reg; + } + } + } + + const RegisterInfo *const register_to_write_info_p = + GetRegisterInfoAtIndex(reg_to_write); + assert(register_to_write_info_p && + "register to write does not have valid RegisterInfo"); + if (!register_to_write_info_p) + return Status("NativeRegisterContextAIX::%s failed to get RegisterInfo " + "for write register index %" PRIu32, + __FUNCTION__, reg_to_write); + + return DoWriteRegisterValue(GetPtraceOffset(reg_index), reg_info->name, + reg_value); +} + +Status NativeRegisterContextAIX::ReadGPR() { + return NativeProcessAIX::PtraceWrapper( + PTRACE_GETREGS, m_thread.GetID(), nullptr, GetGPRBuffer(), GetGPRSize()); +} + +Status NativeRegisterContextAIX::WriteGPR() { + return NativeProcessAIX::PtraceWrapper( + PTRACE_SETREGS, m_thread.GetID(), nullptr, GetGPRBuffer(), GetGPRSize()); +} + +Status NativeRegisterContextAIX::ReadFPR() { + return NativeProcessAIX::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(), + nullptr, GetFPRBuffer(), + GetFPRSize()); +} + +Status NativeRegisterContextAIX::WriteFPR() { + return NativeProcessAIX::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(), + nullptr, GetFPRBuffer(), + GetFPRSize()); +} + +Status NativeRegisterContextAIX::ReadRegisterSet(void *buf, size_t buf_size, + unsigned int regset) { + return NativeProcessAIX::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), + static_cast(®set), buf, + buf_size); +} + +Status NativeRegisterContextAIX::WriteRegisterSet(void *buf, size_t buf_size, + unsigned int regset) { + return NativeProcessAIX::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), + static_cast(®set), buf, + buf_size); +} + +Status NativeRegisterContextAIX::DoReadRegisterValue(uint32_t offset, + const char *reg_name, + uint32_t size, + RegisterValue &value) { + Log *log = GetLog(POSIXLog::Registers); + + long data; + Status error = NativeProcessAIX::PtraceWrapper( + PTRACE_PEEKUSER, m_thread.GetID(), reinterpret_cast(offset), + nullptr, 0, &data); + + if (error.Success()) + // First cast to an unsigned of the same size to avoid sign extension. + value.SetUInt(static_cast(data), size); + + LLDB_LOG(log, "{0}: {1:x}", reg_name, data); + return error; +} + +Status NativeRegisterContextAIX::DoWriteRegisterValue( + uint32_t offset, const char *reg_name, const RegisterValue &value) { + Log *log = GetLog(POSIXLog::Registers); + + void *buf = reinterpret_cast(value.GetAsUInt64()); + LLDB_LOG(log, "{0}: {1}", reg_name, buf); + + return NativeProcessAIX::PtraceWrapper( + PTRACE_POKEUSER, m_thread.GetID(), reinterpret_cast(offset), buf); +} diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h new file mode 100644 index 0000000000000..9c2a326856c0b --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h @@ -0,0 +1,133 @@ +//===-- NativeRegisterContextAIX.h ----------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_NativeRegisterContextAIX_h +#define lldb_NativeRegisterContextAIX_h + +#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h" +#include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/Target/MemoryTagManager.h" +#include "llvm/Support/Error.h" + +namespace lldb_private { +namespace process_aix { + +class NativeThreadAIX; + +class NativeRegisterContextAIX + : public virtual NativeRegisterContextRegisterInfo { +public: + // This function is implemented in the NativeRegisterContextAIX_* subclasses + // to create a new instance of the host specific NativeRegisterContextAIX. + // The implementations can't collide as only one NativeRegisterContextAIX_* + // variant should be compiled into the final executable. + static std::unique_ptr + CreateHostNativeRegisterContextAIX(const ArchSpec &target_arch, + NativeThreadAIX &native_thread); + + // Invalidates cached values in register context data structures + virtual void InvalidateAllRegisters(){} + + struct SyscallData { + /// The syscall instruction. If the architecture uses software + /// single-stepping, the instruction should also be followed by a trap to + /// ensure the process is stopped after the syscall. + llvm::ArrayRef Insn; + + /// Registers used for syscall arguments. The first register is used to + /// store the syscall number. + llvm::ArrayRef Args; + + uint32_t Result; ///< Register containing the syscall result. + }; + /// Return architecture-specific data needed to make inferior syscalls, if + /// they are supported. + virtual std::optional GetSyscallData() { return std::nullopt; } + + struct MmapData { + // Syscall numbers can be found (e.g.) in /usr/include/asm/unistd.h for the + // relevant architecture. + unsigned SysMmap; ///< mmap syscall number. + unsigned SysMunmap; ///< munmap syscall number + }; + /// Return the architecture-specific data needed to make mmap syscalls, if + /// they are supported. + virtual std::optional GetMmapData() { return std::nullopt; } + + struct MemoryTaggingDetails { + /// Object with tag handling utilities. If the function below returns + /// a valid structure, you can assume that this pointer is valid. + std::unique_ptr manager; + int ptrace_read_req; /// ptrace operation number for memory tag read + int ptrace_write_req; /// ptrace operation number for memory tag write + }; + /// Return architecture specific data needed to use memory tags, + /// if they are supported. + virtual llvm::Expected + GetMemoryTaggingDetails(int32_t type) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Architecture does not support memory tagging"); + } + +protected: + // NB: This constructor is here only because gcc<=6.5 requires a virtual base + // class initializer on abstract class (even though it is never used). It can + // be deleted once we move to gcc>=7.0. + NativeRegisterContextAIX(NativeThreadProtocol &thread) + : NativeRegisterContextRegisterInfo(thread, nullptr) {} + + lldb::ByteOrder GetByteOrder() const; + + virtual Status ReadRegisterRaw(uint32_t reg_index, RegisterValue ®_value); + + virtual Status WriteRegisterRaw(uint32_t reg_index, + const RegisterValue ®_value); + + virtual Status ReadRegisterSet(void *buf, size_t buf_size, + unsigned int regset); + + virtual Status WriteRegisterSet(void *buf, size_t buf_size, + unsigned int regset); + + virtual Status ReadGPR(); + + virtual Status WriteGPR(); + + virtual Status ReadFPR(); + + virtual Status WriteFPR(); + + virtual void *GetGPRBuffer() = 0; + + virtual size_t GetGPRSize() const { + return GetRegisterInfoInterface().GetGPRSize(); + } + + virtual void *GetFPRBuffer() = 0; + + virtual size_t GetFPRSize() = 0; + + virtual uint32_t GetPtraceOffset(uint32_t reg_index) { + return GetRegisterInfoAtIndex(reg_index)->byte_offset; + } + + // The Do*** functions are executed on the privileged thread and can perform + // ptrace + // operations directly. + virtual Status DoReadRegisterValue(uint32_t offset, const char *reg_name, + uint32_t size, RegisterValue &value); + + virtual Status DoWriteRegisterValue(uint32_t offset, const char *reg_name, + const RegisterValue &value); +}; + +} // namespace process_aix +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextAIX_h diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp new file mode 100644 index 0000000000000..1996373791748 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp @@ -0,0 +1,744 @@ +//===-- NativeRegisterContextAIX_ppc64.cpp ----------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// This implementation is related to the OpenPOWER ABI for Power Architecture +// 64-bit ELF V2 ABI + +#if defined(__powerpc64__) + +#include "NativeRegisterContextAIX_ppc64.h" + +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Status.h" +#include "lldb/Host/aix/Ptrace.h" + +#include "Plugins/Process/AIX/NativeProcessAIX.h" +#include "Plugins/Process/Linux/Procfs.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h" + +// System includes - They have to be included after framework includes because +// they define some macros which collide with variable names in other modules +#include +#include +#include +#include + +#define REG_CONTEXT_SIZE \ + (GetGPRSize() + GetFPRSize() + sizeof(m_vmx_ppc64le) + sizeof(m_vsx_ppc64le)) +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; + +static const uint32_t g_gpr_regnums_ppc64le[] = { + gpr_r0_ppc64le, gpr_r1_ppc64le, gpr_r2_ppc64le, gpr_r3_ppc64le, + gpr_r4_ppc64le, gpr_r5_ppc64le, gpr_r6_ppc64le, gpr_r7_ppc64le, + gpr_r8_ppc64le, gpr_r9_ppc64le, gpr_r10_ppc64le, gpr_r11_ppc64le, + gpr_r12_ppc64le, gpr_r13_ppc64le, gpr_r14_ppc64le, gpr_r15_ppc64le, + gpr_r16_ppc64le, gpr_r17_ppc64le, gpr_r18_ppc64le, gpr_r19_ppc64le, + gpr_r20_ppc64le, gpr_r21_ppc64le, gpr_r22_ppc64le, gpr_r23_ppc64le, + gpr_r24_ppc64le, gpr_r25_ppc64le, gpr_r26_ppc64le, gpr_r27_ppc64le, + gpr_r28_ppc64le, gpr_r29_ppc64le, gpr_r30_ppc64le, gpr_r31_ppc64le, + gpr_pc_ppc64le, gpr_msr_ppc64le, gpr_origr3_ppc64le, gpr_ctr_ppc64le, + gpr_lr_ppc64le, gpr_xer_ppc64le, gpr_cr_ppc64le, gpr_softe_ppc64le, + gpr_trap_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +static const uint32_t g_fpr_regnums_ppc64le[] = { + fpr_f0_ppc64le, fpr_f1_ppc64le, fpr_f2_ppc64le, fpr_f3_ppc64le, + fpr_f4_ppc64le, fpr_f5_ppc64le, fpr_f6_ppc64le, fpr_f7_ppc64le, + fpr_f8_ppc64le, fpr_f9_ppc64le, fpr_f10_ppc64le, fpr_f11_ppc64le, + fpr_f12_ppc64le, fpr_f13_ppc64le, fpr_f14_ppc64le, fpr_f15_ppc64le, + fpr_f16_ppc64le, fpr_f17_ppc64le, fpr_f18_ppc64le, fpr_f19_ppc64le, + fpr_f20_ppc64le, fpr_f21_ppc64le, fpr_f22_ppc64le, fpr_f23_ppc64le, + fpr_f24_ppc64le, fpr_f25_ppc64le, fpr_f26_ppc64le, fpr_f27_ppc64le, + fpr_f28_ppc64le, fpr_f29_ppc64le, fpr_f30_ppc64le, fpr_f31_ppc64le, + fpr_fpscr_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +static const uint32_t g_vmx_regnums_ppc64le[] = { + vmx_vr0_ppc64le, vmx_vr1_ppc64le, vmx_vr2_ppc64le, vmx_vr3_ppc64le, + vmx_vr4_ppc64le, vmx_vr5_ppc64le, vmx_vr6_ppc64le, vmx_vr7_ppc64le, + vmx_vr8_ppc64le, vmx_vr9_ppc64le, vmx_vr10_ppc64le, vmx_vr11_ppc64le, + vmx_vr12_ppc64le, vmx_vr13_ppc64le, vmx_vr14_ppc64le, vmx_vr15_ppc64le, + vmx_vr16_ppc64le, vmx_vr17_ppc64le, vmx_vr18_ppc64le, vmx_vr19_ppc64le, + vmx_vr20_ppc64le, vmx_vr21_ppc64le, vmx_vr22_ppc64le, vmx_vr23_ppc64le, + vmx_vr24_ppc64le, vmx_vr25_ppc64le, vmx_vr26_ppc64le, vmx_vr27_ppc64le, + vmx_vr28_ppc64le, vmx_vr29_ppc64le, vmx_vr30_ppc64le, vmx_vr31_ppc64le, + vmx_vscr_ppc64le, vmx_vrsave_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +static const uint32_t g_vsx_regnums_ppc64le[] = { + vsx_vs0_ppc64le, vsx_vs1_ppc64le, vsx_vs2_ppc64le, vsx_vs3_ppc64le, + vsx_vs4_ppc64le, vsx_vs5_ppc64le, vsx_vs6_ppc64le, vsx_vs7_ppc64le, + vsx_vs8_ppc64le, vsx_vs9_ppc64le, vsx_vs10_ppc64le, vsx_vs11_ppc64le, + vsx_vs12_ppc64le, vsx_vs13_ppc64le, vsx_vs14_ppc64le, vsx_vs15_ppc64le, + vsx_vs16_ppc64le, vsx_vs17_ppc64le, vsx_vs18_ppc64le, vsx_vs19_ppc64le, + vsx_vs20_ppc64le, vsx_vs21_ppc64le, vsx_vs22_ppc64le, vsx_vs23_ppc64le, + vsx_vs24_ppc64le, vsx_vs25_ppc64le, vsx_vs26_ppc64le, vsx_vs27_ppc64le, + vsx_vs28_ppc64le, vsx_vs29_ppc64le, vsx_vs30_ppc64le, vsx_vs31_ppc64le, + vsx_vs32_ppc64le, vsx_vs33_ppc64le, vsx_vs34_ppc64le, vsx_vs35_ppc64le, + vsx_vs36_ppc64le, vsx_vs37_ppc64le, vsx_vs38_ppc64le, vsx_vs39_ppc64le, + vsx_vs40_ppc64le, vsx_vs41_ppc64le, vsx_vs42_ppc64le, vsx_vs43_ppc64le, + vsx_vs44_ppc64le, vsx_vs45_ppc64le, vsx_vs46_ppc64le, vsx_vs47_ppc64le, + vsx_vs48_ppc64le, vsx_vs49_ppc64le, vsx_vs50_ppc64le, vsx_vs51_ppc64le, + vsx_vs52_ppc64le, vsx_vs53_ppc64le, vsx_vs54_ppc64le, vsx_vs55_ppc64le, + vsx_vs56_ppc64le, vsx_vs57_ppc64le, vsx_vs58_ppc64le, vsx_vs59_ppc64le, + vsx_vs60_ppc64le, vsx_vs61_ppc64le, vsx_vs62_ppc64le, vsx_vs63_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +// Number of register sets provided by this context. +static constexpr int k_num_register_sets = 4; + +static const RegisterSet g_reg_sets_ppc64le[k_num_register_sets] = { + {"General Purpose Registers", "gpr", k_num_gpr_registers_ppc64le, + g_gpr_regnums_ppc64le}, + {"Floating Point Registers", "fpr", k_num_fpr_registers_ppc64le, + g_fpr_regnums_ppc64le}, + {"AltiVec/VMX Registers", "vmx", k_num_vmx_registers_ppc64le, + g_vmx_regnums_ppc64le}, + {"VSX Registers", "vsx", k_num_vsx_registers_ppc64le, + g_vsx_regnums_ppc64le}, +}; + +std::unique_ptr +NativeRegisterContextAIX::CreateHostNativeRegisterContextAIX( + const ArchSpec &target_arch, NativeThreadAIX &native_thread) { + switch (target_arch.GetMachine()) { + case llvm::Triple::ppc64: + return std::make_unique(target_arch, + native_thread); + default: + llvm_unreachable("have no register context for architecture"); + } +} + +NativeRegisterContextAIX_ppc64::NativeRegisterContextAIX_ppc64( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + : NativeRegisterContextRegisterInfo( + native_thread, new RegisterInfoPOSIX_ppc64le(target_arch)), + NativeRegisterContextAIX(native_thread) { + if (target_arch.GetMachine() != llvm::Triple::ppc64) { + llvm_unreachable("Unhandled target architecture."); + } + + ::memset(&m_gpr_ppc64le, 0, sizeof(m_gpr_ppc64le)); + ::memset(&m_fpr_ppc64le, 0, sizeof(m_fpr_ppc64le)); + ::memset(&m_vmx_ppc64le, 0, sizeof(m_vmx_ppc64le)); + ::memset(&m_vsx_ppc64le, 0, sizeof(m_vsx_ppc64le)); + ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); +} + +uint32_t NativeRegisterContextAIX_ppc64::GetRegisterSetCount() const { + return k_num_register_sets; +} + +const RegisterSet * +NativeRegisterContextAIX_ppc64::GetRegisterSet(uint32_t set_index) const { + if (set_index < k_num_register_sets) + return &g_reg_sets_ppc64le[set_index]; + + return nullptr; +} + +uint32_t NativeRegisterContextAIX_ppc64::GetUserRegisterCount() const { + uint32_t count = 0; + for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) + count += g_reg_sets_ppc64le[set_index].num_registers; + return count; +} + +Status NativeRegisterContextAIX_ppc64::ReadRegister( + const RegisterInfo *reg_info, RegisterValue ®_value) { + Status error; + + if (!reg_info) { + error.SetErrorString("reg_info NULL"); + return error; + } + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (IsFPR(reg)) { + error = ReadFPR(); + if (error.Fail()) + return error; + + // Get pointer to m_fpr_ppc64le variable and set the data from it. + uint32_t fpr_offset = CalculateFprOffset(reg_info); + assert(fpr_offset < sizeof m_fpr_ppc64le); + uint8_t *src = (uint8_t *)&m_fpr_ppc64le + fpr_offset; + reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } else if (IsVSX(reg)) { + uint32_t vsx_offset = CalculateVsxOffset(reg_info); + assert(vsx_offset < sizeof(m_vsx_ppc64le)); + + if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) { + error = ReadVSX(); + if (error.Fail()) + return error; + + error = ReadFPR(); + if (error.Fail()) + return error; + + uint64_t value[2]; + uint8_t *dst, *src; + dst = (uint8_t *)&value; + src = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + dst += 8; + src = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + reg_value.SetFromMemoryData(*reg_info, &value, reg_info->byte_size, + eByteOrderLittle, error); + } else { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data from it. + uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2; + uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } + } else if (IsVMX(reg)) { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data from it. + uint32_t vmx_offset = CalculateVmxOffset(reg_info); + assert(vmx_offset < sizeof m_vmx_ppc64le); + uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } else if (IsGPR(reg)) { + error = ReadGPR(); + if (error.Fail()) + return error; + + uint8_t *src = (uint8_t *) &m_gpr_ppc64le + reg_info->byte_offset; + reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } else { + return Status("failed - register wasn't recognized to be a GPR, FPR, VSX " + "or VMX, read strategy unknown"); + } + + return error; +} + +Status NativeRegisterContextAIX_ppc64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue ®_value) { + Status error; + if (!reg_info) + return Status("reg_info NULL"); + + const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; + if (reg_index == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : ""); + + if (IsGPR(reg_index)) { + error = ReadGPR(); + if (error.Fail()) + return error; + + uint8_t *dst = (uint8_t *)&m_gpr_ppc64le + reg_info->byte_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + *(uint64_t *)dst = llvm::byteswap(*(uint64_t *)dst); + + error = WriteGPR(); + if (error.Fail()) + return error; + + return Status(); + } + + if (IsFPR(reg_index)) { + error = ReadFPR(); + if (error.Fail()) + return error; + + // Get pointer to m_fpr_ppc64le variable and set the data to it. + uint32_t fpr_offset = CalculateFprOffset(reg_info); + assert(fpr_offset < GetFPRSize()); + uint8_t *dst = (uint8_t *)&m_fpr_ppc64le + fpr_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + + error = WriteFPR(); + if (error.Fail()) + return error; + + return Status(); + } + + if (IsVMX(reg_index)) { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data to it. + uint32_t vmx_offset = CalculateVmxOffset(reg_info); + assert(vmx_offset < sizeof(m_vmx_ppc64le)); + uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + + error = WriteVMX(); + if (error.Fail()) + return error; + + return Status(); + } + + if (IsVSX(reg_index)) { + uint32_t vsx_offset = CalculateVsxOffset(reg_info); + assert(vsx_offset < sizeof(m_vsx_ppc64le)); + + if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) { + error = ReadVSX(); + if (error.Fail()) + return error; + + error = ReadFPR(); + if (error.Fail()) + return error; + + uint64_t value[2]; + ::memcpy(value, reg_value.GetBytes(), 16); + uint8_t *dst, *src; + src = (uint8_t *)value; + dst = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + src += 8; + dst = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + + WriteVSX(); + WriteFPR(); + } else { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data from it. + uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2; + uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + WriteVMX(); + } + + return Status(); + } + + return Status("failed - register wasn't recognized to be a GPR, FPR, VSX " + "or VMX, write strategy unknown"); +} + +Status NativeRegisterContextAIX_ppc64::ReadAllRegisterValues( + lldb::WritableDataBufferSP &data_sp) { + Status error; + + data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); + error = ReadGPR(); + if (error.Fail()) + return error; + + error = ReadFPR(); + if (error.Fail()) + return error; + + error = ReadVMX(); + if (error.Fail()) + return error; + + error = ReadVSX(); + if (error.Fail()) + return error; + + uint8_t *dst = data_sp->GetBytes(); + ::memcpy(dst, &m_gpr_ppc64le, GetGPRSize()); + dst += GetGPRSize(); + ::memcpy(dst, &m_fpr_ppc64le, GetFPRSize()); + dst += GetFPRSize(); + ::memcpy(dst, &m_vmx_ppc64le, sizeof(m_vmx_ppc64le)); + dst += sizeof(m_vmx_ppc64le); + ::memcpy(dst, &m_vsx_ppc64le, sizeof(m_vsx_ppc64le)); + + return error; +} + +Status NativeRegisterContextAIX_ppc64::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + Status error; + + if (!data_sp) { + error.SetErrorStringWithFormat( + "NativeRegisterContextAIX_ppc64::%s invalid data_sp provided", + __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { + error.SetErrorStringWithFormat( + "NativeRegisterContextAIX_ppc64::%s data_sp contained mismatched " + "data size, expected %" PRIu64 ", actual %" PRIu64, + __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); + return error; + } + + const uint8_t *src = data_sp->GetBytes(); + if (src == nullptr) { + error.SetErrorStringWithFormat("NativeRegisterContextAIX_ppc64::%s " + "DataBuffer::GetBytes() returned a null " + "pointer", + __FUNCTION__); + return error; + } + + ::memcpy(&m_gpr_ppc64le, src, GetGPRSize()); + error = WriteGPR(); + + if (error.Fail()) + return error; + + src += GetGPRSize(); + ::memcpy(&m_fpr_ppc64le, src, GetFPRSize()); + + error = WriteFPR(); + if (error.Fail()) + return error; + + src += GetFPRSize(); + ::memcpy(&m_vmx_ppc64le, src, sizeof(m_vmx_ppc64le)); + + error = WriteVMX(); + if (error.Fail()) + return error; + + src += sizeof(m_vmx_ppc64le); + ::memcpy(&m_vsx_ppc64le, src, sizeof(m_vsx_ppc64le)); + error = WriteVSX(); + + return error; +} + +bool NativeRegisterContextAIX_ppc64::IsGPR(unsigned reg) const { + return reg <= k_last_gpr_ppc64le; // GPR's come first. +} + +bool NativeRegisterContextAIX_ppc64::IsFPR(unsigned reg) const { + return (k_first_fpr_ppc64le <= reg && reg <= k_last_fpr_ppc64le); +} + +uint32_t NativeRegisterContextAIX_ppc64::CalculateFprOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - + GetRegisterInfoAtIndex(k_first_fpr_ppc64le)->byte_offset; +} + +uint32_t NativeRegisterContextAIX_ppc64::CalculateVmxOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - + GetRegisterInfoAtIndex(k_first_vmx_ppc64le)->byte_offset; +} + +uint32_t NativeRegisterContextAIX_ppc64::CalculateVsxOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - + GetRegisterInfoAtIndex(k_first_vsx_ppc64le)->byte_offset; +} + +Status NativeRegisterContextAIX_ppc64::ReadVMX() { + return NativeProcessAIX::PtraceWrapper(PTRACE_GETVRREGS, m_thread.GetID(), + nullptr, &m_vmx_ppc64le, + sizeof(m_vmx_ppc64le)); +} + +Status NativeRegisterContextAIX_ppc64::WriteVMX() { + //FIXME + int regset = 0/*NT_PPC_VMX*/; + return NativeProcessAIX::PtraceWrapper(PT_CLEAR/*PTRACE_SETVRREGS*/, m_thread.GetID(), + ®set, &m_vmx_ppc64le, + sizeof(m_vmx_ppc64le)); +} + +Status NativeRegisterContextAIX_ppc64::ReadVSX() { + return NativeProcessAIX::PtraceWrapper(PTRACE_GETVSRREGS, m_thread.GetID(), + nullptr, &m_vsx_ppc64le, + sizeof(m_vsx_ppc64le)); +} + +Status NativeRegisterContextAIX_ppc64::WriteVSX() { + //FIXME + int regset = 0/*NT_PPC_VSX*/; + return NativeProcessAIX::PtraceWrapper(PT_CLEAR/*PTRACE_SETVSRREGS*/, m_thread.GetID(), + ®set, &m_vsx_ppc64le, + sizeof(m_vsx_ppc64le)); +} + +bool NativeRegisterContextAIX_ppc64::IsVMX(unsigned reg) { + return (reg >= k_first_vmx_ppc64le) && (reg <= k_last_vmx_ppc64le); +} + +bool NativeRegisterContextAIX_ppc64::IsVSX(unsigned reg) { + return (reg >= k_first_vsx_ppc64le) && (reg <= k_last_vsx_ppc64le); +} + +uint32_t NativeRegisterContextAIX_ppc64::NumSupportedHardwareWatchpoints() { + Log *log = GetLog(POSIXLog::Watchpoints); + + // Read hardware breakpoint and watchpoint information. + Status error = ReadHardwareDebugInfo(); + + if (error.Fail()) + return 0; + + LLDB_LOG(log, "{0}", m_max_hwp_supported); + return m_max_hwp_supported; +} + +uint32_t NativeRegisterContextAIX_ppc64::SetHardwareWatchpoint( + lldb::addr_t addr, size_t size, uint32_t watch_flags) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size, + watch_flags); + + // Read hardware breakpoint and watchpoint information. + Status error = ReadHardwareDebugInfo(); + + if (error.Fail()) + return LLDB_INVALID_INDEX32; + + uint32_t control_value = 0, wp_index = 0; + lldb::addr_t real_addr = addr; + uint32_t rw_mode = 0; + + // Check if we are setting watchpoint other than read/write/access Update + // watchpoint flag to match ppc64le write-read bit configuration. + switch (watch_flags) { + case eWatchpointKindWrite: + //FIXME + //rw_mode = 0/*PPC_BREAKPOINT_TRIGGER_WRITE*/; + watch_flags = 2; + break; + // Watchpoint read not supported + case eWatchpointKindRead: + case (eWatchpointKindRead | eWatchpointKindWrite): + default: + return LLDB_INVALID_INDEX32; + } + + // Check if size has a valid hardware watchpoint length. + if (size != 8) + return LLDB_INVALID_INDEX32; + + // Check 8-byte alignment for hardware watchpoint target address. Below is a + // hack to recalculate address and size in order to make sure we can watch + // non 8-byte aligned addresses as well. + if (addr & 0x07) { + + addr_t begin = llvm::alignDown(addr, 8); + addr_t end = llvm::alignTo(addr + size, 8); + size = llvm::PowerOf2Ceil(end - begin); + + addr = addr & (~0x07); + } + + // Setup control value + control_value = watch_flags << 3; + control_value |= ((1 << size) - 1) << 5; + control_value |= (2 << 1) | 1; + + // Iterate over stored watchpoints and find a free wp_index + wp_index = LLDB_INVALID_INDEX32; + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + if ((m_hwp_regs[i].control & 1) == 0) { + wp_index = i; // Mark last free slot + } else if (m_hwp_regs[i].address == addr) { + return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints. + } + } + + if (wp_index == LLDB_INVALID_INDEX32) + return LLDB_INVALID_INDEX32; + + // Update watchpoint in local cache + m_hwp_regs[wp_index].real_addr = real_addr; + m_hwp_regs[wp_index].address = addr; + m_hwp_regs[wp_index].control = control_value; + //m_hwp_regs[wp_index].mode = rw_mode; + + // PTRACE call to set corresponding watchpoint register. + error = WriteHardwareDebugRegs(); + + if (error.Fail()) { + m_hwp_regs[wp_index].address = 0; + m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros(1); + + return LLDB_INVALID_INDEX32; + } + + return wp_index; +} + +bool NativeRegisterContextAIX_ppc64::ClearHardwareWatchpoint( + uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + // Read hardware breakpoint and watchpoint information. + Status error = ReadHardwareDebugInfo(); + + if (error.Fail()) + return false; + + if (wp_index >= m_max_hwp_supported) + return false; + + // Create a backup we can revert to in case of failure. + lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; + uint32_t tempControl = m_hwp_regs[wp_index].control; + long *tempSlot = reinterpret_cast(m_hwp_regs[wp_index].slot); + + // Update watchpoint in local cache + m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros(1); + m_hwp_regs[wp_index].address = 0; + m_hwp_regs[wp_index].slot = 0; + m_hwp_regs[wp_index].mode = 0; + + // Ptrace call to update hardware debug registers + //FIXME + error = NativeProcessAIX::PtraceWrapper(PT_CLEAR/*PPC_PTRACE_DELHWDEBUG*/, + m_thread.GetID(), 0, tempSlot); + + if (error.Fail()) { + m_hwp_regs[wp_index].control = tempControl; + m_hwp_regs[wp_index].address = tempAddr; + m_hwp_regs[wp_index].slot = reinterpret_cast(tempSlot); + + return false; + } + + return true; +} + +uint32_t +NativeRegisterContextAIX_ppc64::GetWatchpointSize(uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + unsigned control = (m_hwp_regs[wp_index].control >> 5) & 0xff; + if (llvm::isPowerOf2_32(control + 1)) { + return llvm::popcount(control); + } + + return 0; +} + +bool NativeRegisterContextAIX_ppc64::WatchpointIsEnabled( + uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + return !!((m_hwp_regs[wp_index].control & 0x1) == 0x1); +} + +Status NativeRegisterContextAIX_ppc64::GetWatchpointHitIndex( + uint32_t &wp_index, lldb::addr_t trap_addr) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr); + + uint32_t watch_size; + lldb::addr_t watch_addr; + + for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) { + watch_size = GetWatchpointSize(wp_index); + watch_addr = m_hwp_regs[wp_index].address; + + if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr && + trap_addr <= watch_addr + watch_size) { + m_hwp_regs[wp_index].hit_addr = trap_addr; + return Status(); + } + } + + wp_index = LLDB_INVALID_INDEX32; + return Status(); +} + +lldb::addr_t +NativeRegisterContextAIX_ppc64::GetWatchpointAddress(uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + if (wp_index >= m_max_hwp_supported) + return LLDB_INVALID_ADDRESS; + + if (WatchpointIsEnabled(wp_index)) + return m_hwp_regs[wp_index].real_addr; + else + return LLDB_INVALID_ADDRESS; +} + +lldb::addr_t +NativeRegisterContextAIX_ppc64::GetWatchpointHitAddress(uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + if (wp_index >= m_max_hwp_supported) + return LLDB_INVALID_ADDRESS; + + if (WatchpointIsEnabled(wp_index)) + return m_hwp_regs[wp_index].hit_addr; + + return LLDB_INVALID_ADDRESS; +} + +Status NativeRegisterContextAIX_ppc64::ReadHardwareDebugInfo() { + if (!m_refresh_hwdebug_info) { + return Status(); + } + + m_max_hwp_supported = 1; + m_max_hbp_supported = 0; + m_refresh_hwdebug_info = false; + + return Status(); +} + +Status NativeRegisterContextAIX_ppc64::WriteHardwareDebugRegs() { + Status error; + long ret; + + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + if ((m_hwp_regs[i].control & 1) == 0) + continue; + + error = NativeProcessAIX::PtraceWrapper(PT_WATCH, m_thread.GetID(), (void *)m_hwp_regs[i].address, nullptr, 8, &ret); + + if (error.Fail()) + return error; + + m_hwp_regs[i].slot = ret; + } + return error; +} + +#endif // defined(__powerpc64__) diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h new file mode 100644 index 0000000000000..a29f786f2313a --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h @@ -0,0 +1,138 @@ +//===-- NativeRegisterContextAIX_ppc64.h --------------------*- 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 +// +//===----------------------------------------------------------------------===// + +// This implementation is related to the OpenPOWER ABI for Power Architecture +// 64-bit ELF V2 ABI + +#if defined(__powerpc64__) + +#ifndef lldb_NativeRegisterContextAIX_ppc64_h +#define lldb_NativeRegisterContextAIX_ppc64_h + +#include "Plugins/Process/AIX/NativeRegisterContextAIX.h" +#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" + +#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT +#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h" +#undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT + +namespace lldb_private { +namespace process_aix { + +class NativeProcessAIX; + +class NativeRegisterContextAIX_ppc64 : public NativeRegisterContextAIX { +public: + NativeRegisterContextAIX_ppc64(const ArchSpec &target_arch, + NativeThreadProtocol &native_thread); + + uint32_t GetRegisterSetCount() const override; + + uint32_t GetUserRegisterCount() const override; + + const RegisterSet *GetRegisterSet(uint32_t set_index) const override; + + Status ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + + Status WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + + Status ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override; + + Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + // Hardware watchpoint management functions + + uint32_t NumSupportedHardwareWatchpoints() override; + + uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags) override; + + bool ClearHardwareWatchpoint(uint32_t hw_index) override; + + Status GetWatchpointHitIndex(uint32_t &wp_index, + lldb::addr_t trap_addr) override; + + lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override; + + lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; + + uint32_t GetWatchpointSize(uint32_t wp_index); + + bool WatchpointIsEnabled(uint32_t wp_index); + +protected: + bool IsVMX(unsigned reg); + + bool IsVSX(unsigned reg); + + Status ReadVMX(); + + Status WriteVMX(); + + Status ReadVSX(); + + Status WriteVSX(); + + void *GetGPRBuffer() override { return &m_gpr_ppc64le; } + + void *GetFPRBuffer() override { return &m_fpr_ppc64le; } + + size_t GetFPRSize() override { return sizeof(m_fpr_ppc64le); } + +private: + GPR m_gpr_ppc64le; // 64-bit general purpose registers. + FPR m_fpr_ppc64le; // floating-point registers including extended register. + VMX m_vmx_ppc64le; // VMX registers. + VSX m_vsx_ppc64le; // Last lower bytes from first VSX registers. + + bool IsGPR(unsigned reg) const; + + bool IsFPR(unsigned reg) const; + + bool IsVMX(unsigned reg) const; + + bool IsVSX(unsigned reg) const; + + uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const; + + uint32_t CalculateVmxOffset(const RegisterInfo *reg_info) const; + + uint32_t CalculateVsxOffset(const RegisterInfo *reg_info) const; + + Status ReadHardwareDebugInfo(); + + Status WriteHardwareDebugRegs(); + + // Debug register info for hardware watchpoints management. + struct DREG { + lldb::addr_t address; // Breakpoint/watchpoint address value. + lldb::addr_t hit_addr; // Address at which last watchpoint trigger + // exception occurred. + lldb::addr_t real_addr; // Address value that should cause target to stop. + uint32_t control; // Breakpoint/watchpoint control value. + uint32_t refcount; // Serves as enable/disable and reference counter. + long slot; // Saves the value returned from PTRACE_SETHWDEBUG. + int mode; // Defines if watchpoint is read/write/access. + }; + + std::array m_hwp_regs; + + // 16 is just a maximum value, query hardware for actual watchpoint count + uint32_t m_max_hwp_supported = 16; + uint32_t m_max_hbp_supported = 16; + bool m_refresh_hwdebug_info = true; +}; + +} // namespace process_aix +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextAIX_ppc64_h + +#endif // defined(__powerpc64__) diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp new file mode 100644 index 0000000000000..e07daccdff550 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp @@ -0,0 +1,526 @@ +//===-- NativeThreadAIX.cpp ---------------------------------------------===// +// +// 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 "NativeThreadAIX.h" + +#include +#include + +#include "NativeProcessAIX.h" +#include "NativeRegisterContextAIX.h" + +#include "lldb/Host/HostNativeThread.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" +#include "lldb/lldb-enumerations.h" + +#include "llvm/ADT/SmallString.h" + +#include "Plugins/Process/POSIX/CrashReason.h" + +#include +#include +#include + +#if 0 +#include +// Try to define a macro to encapsulate the tgkill syscall +#define tgkill(pid, tid, sig) \ + syscall(__NR_tgkill, static_cast<::pid_t>(pid), static_cast<::pid_t>(tid), \ + sig) +#endif + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; + +namespace { +void LogThreadStopInfo(Log &log, const ThreadStopInfo &stop_info, + const char *const header) { + switch (stop_info.reason) { + case eStopReasonNone: + log.Printf("%s: %s no stop reason", __FUNCTION__, header); + return; + case eStopReasonTrace: + log.Printf("%s: %s trace, stopping signal 0x%" PRIx32, __FUNCTION__, header, + stop_info.signo); + return; + case eStopReasonBreakpoint: + log.Printf("%s: %s breakpoint, stopping signal 0x%" PRIx32, __FUNCTION__, + header, stop_info.signo); + return; + case eStopReasonWatchpoint: + log.Printf("%s: %s watchpoint, stopping signal 0x%" PRIx32, __FUNCTION__, + header, stop_info.signo); + return; + case eStopReasonSignal: + log.Printf("%s: %s signal 0x%02" PRIx32, __FUNCTION__, header, + stop_info.signo); + return; + case eStopReasonException: + log.Printf("%s: %s exception type 0x%02" PRIx64, __FUNCTION__, header, + stop_info.details.exception.type); + return; + case eStopReasonExec: + log.Printf("%s: %s exec, stopping signal 0x%" PRIx32, __FUNCTION__, header, + stop_info.signo); + return; + case eStopReasonPlanComplete: + log.Printf("%s: %s plan complete", __FUNCTION__, header); + return; + case eStopReasonThreadExiting: + log.Printf("%s: %s thread exiting", __FUNCTION__, header); + return; + case eStopReasonInstrumentation: + log.Printf("%s: %s instrumentation", __FUNCTION__, header); + return; + case eStopReasonProcessorTrace: + log.Printf("%s: %s processor trace", __FUNCTION__, header); + return; + default: + log.Printf("%s: %s invalid stop reason %" PRIu32, __FUNCTION__, header, + static_cast(stop_info.reason)); + } +} +} + +NativeThreadAIX::NativeThreadAIX(NativeProcessAIX &process, + lldb::tid_t tid) + : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid), + m_stop_info(), + m_reg_context_up( + NativeRegisterContextAIX::CreateHostNativeRegisterContextAIX( + process.GetArchitecture(), *this)), + m_stop_description() {} + +std::string NativeThreadAIX::GetName() { + NativeProcessAIX &process = GetProcess(); + + auto BufferOrError = getProcFile(process.GetID(), GetID(), "comm"); + if (!BufferOrError) + return ""; + return std::string(BufferOrError.get()->getBuffer().rtrim('\n')); +} + +lldb::StateType NativeThreadAIX::GetState() { return m_state; } + +bool NativeThreadAIX::GetStopReason(ThreadStopInfo &stop_info, + std::string &description) { + Log *log = GetLog(LLDBLog::Thread); + + description.clear(); + + switch (m_state) { + case eStateStopped: + case eStateCrashed: + case eStateExited: + case eStateSuspended: + case eStateUnloaded: + if (log) + LogThreadStopInfo(*log, m_stop_info, "m_stop_info in thread:"); + stop_info = m_stop_info; + description = m_stop_description; + if (log) + LogThreadStopInfo(*log, stop_info, "returned stop_info:"); + + return true; + + case eStateInvalid: + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + case eStateRunning: + case eStateStepping: + case eStateDetached: + if (log) { + LLDB_LOGF(log, + "NativeThreadAIX::%s tid %" PRIu64 + " in state %s cannot answer stop reason", + __FUNCTION__, GetID(), StateAsCString(m_state)); + } + return false; + } + llvm_unreachable("unhandled StateType!"); +} + +Status NativeThreadAIX::SetWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags, bool hardware) { + if (!hardware) + return Status("not implemented"); + if (m_state == eStateLaunching) + return Status(); + Status error = RemoveWatchpoint(addr); + if (error.Fail()) + return error; + uint32_t wp_index = + m_reg_context_up->SetHardwareWatchpoint(addr, size, watch_flags); + if (wp_index == LLDB_INVALID_INDEX32) + return Status("Setting hardware watchpoint failed."); + m_watchpoint_index_map.insert({addr, wp_index}); + return Status(); +} + +Status NativeThreadAIX::RemoveWatchpoint(lldb::addr_t addr) { + auto wp = m_watchpoint_index_map.find(addr); + if (wp == m_watchpoint_index_map.end()) + return Status(); + uint32_t wp_index = wp->second; + m_watchpoint_index_map.erase(wp); + if (m_reg_context_up->ClearHardwareWatchpoint(wp_index)) + return Status(); + return Status("Clearing hardware watchpoint failed."); +} + +Status NativeThreadAIX::SetHardwareBreakpoint(lldb::addr_t addr, + size_t size) { + if (m_state == eStateLaunching) + return Status(); + + Status error = RemoveHardwareBreakpoint(addr); + if (error.Fail()) + return error; + + uint32_t bp_index = m_reg_context_up->SetHardwareBreakpoint(addr, size); + + if (bp_index == LLDB_INVALID_INDEX32) + return Status("Setting hardware breakpoint failed."); + + m_hw_break_index_map.insert({addr, bp_index}); + return Status(); +} + +Status NativeThreadAIX::RemoveHardwareBreakpoint(lldb::addr_t addr) { + auto bp = m_hw_break_index_map.find(addr); + if (bp == m_hw_break_index_map.end()) + return Status(); + + uint32_t bp_index = bp->second; + if (m_reg_context_up->ClearHardwareBreakpoint(bp_index)) { + m_hw_break_index_map.erase(bp); + return Status(); + } + + return Status("Clearing hardware breakpoint failed."); +} + +Status NativeThreadAIX::Resume(uint32_t signo) { + const StateType new_state = StateType::eStateRunning; + MaybeLogStateChange(new_state); + m_state = new_state; + + m_stop_info.reason = StopReason::eStopReasonNone; + m_stop_description.clear(); + + // If watchpoints have been set, but none on this thread, then this is a new + // thread. So set all existing watchpoints. + if (m_watchpoint_index_map.empty()) { + NativeProcessAIX &process = GetProcess(); + + const auto &watchpoint_map = process.GetWatchpointMap(); + m_reg_context_up->ClearAllHardwareWatchpoints(); + for (const auto &pair : watchpoint_map) { + const auto &wp = pair.second; + SetWatchpoint(wp.m_addr, wp.m_size, wp.m_watch_flags, wp.m_hardware); + } + } + + // Set all active hardware breakpoint on all threads. + if (m_hw_break_index_map.empty()) { + NativeProcessAIX &process = GetProcess(); + + const auto &hw_breakpoint_map = process.GetHardwareBreakpointMap(); + m_reg_context_up->ClearAllHardwareBreakpoints(); + for (const auto &pair : hw_breakpoint_map) { + const auto &bp = pair.second; + SetHardwareBreakpoint(bp.m_addr, bp.m_size); + } + } + + intptr_t data = 0; + + if (signo != LLDB_INVALID_SIGNAL_NUMBER) + data = signo; + + return NativeProcessAIX::PtraceWrapper(PT_CONTINUE, GetID(), nullptr, + reinterpret_cast(data)); +} + +Status NativeThreadAIX::SingleStep(uint32_t signo) { + const StateType new_state = StateType::eStateStepping; + MaybeLogStateChange(new_state); + m_state = new_state; + m_stop_info.reason = StopReason::eStopReasonNone; + + intptr_t data = 0; + if (signo != LLDB_INVALID_SIGNAL_NUMBER) + data = signo; + + // If hardware single-stepping is not supported, we just do a continue. The + // breakpoint on the next instruction has been setup in + // NativeProcessAIX::Resume. + return NativeProcessAIX::PtraceWrapper( + GetProcess().SupportHardwareSingleStepping() ? PT_STEP : PT_CONTINUE, + m_tid, nullptr, reinterpret_cast(data)); +} + +void NativeThreadAIX::SetStoppedBySignal(uint32_t signo, + const siginfo_t *info) { + Log *log = GetLog(LLDBLog::Thread); + LLDB_LOGF(log, "NativeThreadAIX::%s called with signal 0x%02" PRIx32, + __FUNCTION__, signo); + + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonSignal; + m_stop_info.signo = signo; + + m_stop_description.clear(); + switch (signo) { + case SIGSEGV: + case SIGBUS: + case SIGFPE: + case SIGILL: + break; + } +} + +void NativeThreadAIX::AnnotateSyncTagCheckFault(const siginfo_t *info) { + int32_t allocation_tag_type = 0; + switch (GetProcess().GetArchitecture().GetMachine()) { + default: + return; + } + + auto details = + GetRegisterContext().GetMemoryTaggingDetails(allocation_tag_type); + if (!details) { + llvm::consumeError(details.takeError()); + return; + } + + // We assume that the stop description is currently: + // signal SIGSEGV: sync tag check fault (fault address: ) + // Remove the closing ) + m_stop_description.pop_back(); + + std::stringstream ss; + lldb::addr_t fault_addr = reinterpret_cast(info->si_addr); + std::unique_ptr manager(std::move(details->manager)); + + ss << " logical tag: 0x" << std::hex << manager->GetLogicalTag(fault_addr); + + std::vector allocation_tag_data; + // The fault address may not be granule aligned. ReadMemoryTags will granule + // align any range you give it, potentially making it larger. + // To prevent this set len to 1. This always results in a range that is at + // most 1 granule in size and includes fault_addr. + Status status = GetProcess().ReadMemoryTags(allocation_tag_type, fault_addr, + 1, allocation_tag_data); + + if (status.Success()) { + llvm::Expected> allocation_tag = + manager->UnpackTagsData(allocation_tag_data, 1); + if (allocation_tag) { + ss << " allocation tag: 0x" << std::hex << allocation_tag->front() << ")"; + } else { + llvm::consumeError(allocation_tag.takeError()); + ss << ")"; + } + } else + ss << ")"; + + m_stop_description += ss.str(); +} + +bool NativeThreadAIX::IsStopped(int *signo) { + if (!StateIsStoppedState(m_state, false)) + return false; + + // If we are stopped by a signal, return the signo. + if (signo && m_state == StateType::eStateStopped && + m_stop_info.reason == StopReason::eStopReasonSignal) { + *signo = m_stop_info.signo; + } + + // Regardless, we are stopped. + return true; +} + +void NativeThreadAIX::SetStopped() { + // On every stop, clear any cached register data structures + GetRegisterContext().InvalidateAllRegisters(); + + const StateType new_state = StateType::eStateStopped; + MaybeLogStateChange(new_state); + m_state = new_state; + m_stop_description.clear(); +} + +void NativeThreadAIX::SetStoppedByExec() { + Log *log = GetLog(LLDBLog::Thread); + LLDB_LOGF(log, "NativeThreadAIX::%s()", __FUNCTION__); + + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonExec; + m_stop_info.signo = SIGSTOP; +} + +void NativeThreadAIX::SetStoppedByBreakpoint() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonBreakpoint; + m_stop_info.signo = SIGTRAP; + m_stop_description.clear(); +} + +void NativeThreadAIX::SetStoppedByWatchpoint(uint32_t wp_index) { + SetStopped(); + + lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); + + std::ostringstream ostr; + ostr << m_reg_context_up->GetWatchpointAddress(wp_index) << " "; + ostr << wp_index; + + /* + * MIPS: Last 3bits of the watchpoint address are masked by the kernel. For + * example: + * 'n' is at 0x120010d00 and 'm' is 0x120010d04. When a watchpoint is set at + * 'm', then + * watch exception is generated even when 'n' is read/written. To handle this + * case, + * find the base address of the load/store instruction and append it in the + * stop-info + * packet. + */ + ostr << " " << m_reg_context_up->GetWatchpointHitAddress(wp_index); + + m_stop_description = ostr.str(); + + m_stop_info.reason = StopReason::eStopReasonWatchpoint; + m_stop_info.signo = SIGTRAP; +} + +bool NativeThreadAIX::IsStoppedAtBreakpoint() { + return GetState() == StateType::eStateStopped && + m_stop_info.reason == StopReason::eStopReasonBreakpoint; +} + +bool NativeThreadAIX::IsStoppedAtWatchpoint() { + return GetState() == StateType::eStateStopped && + m_stop_info.reason == StopReason::eStopReasonWatchpoint; +} + +void NativeThreadAIX::SetStoppedByTrace() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonTrace; + m_stop_info.signo = SIGTRAP; +} + +void NativeThreadAIX::SetStoppedByFork(bool is_vfork, lldb::pid_t child_pid) { + SetStopped(); + + m_stop_info.reason = + is_vfork ? StopReason::eStopReasonVFork : StopReason::eStopReasonFork; + m_stop_info.details.fork.child_pid = child_pid; + m_stop_info.details.fork.child_tid = child_pid; +} + +void NativeThreadAIX::SetStoppedByVForkDone() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonVForkDone; +} + +void NativeThreadAIX::SetStoppedWithNoReason() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonNone; + m_stop_info.signo = 0; +} + +void NativeThreadAIX::SetStoppedByProcessorTrace( + llvm::StringRef description) { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonProcessorTrace; + m_stop_info.signo = 0; + m_stop_description = description.str(); +} + +void NativeThreadAIX::SetExited() { + const StateType new_state = StateType::eStateExited; + MaybeLogStateChange(new_state); + m_state = new_state; + + m_stop_info.reason = StopReason::eStopReasonThreadExiting; +} + +Status NativeThreadAIX::RequestStop() { + Log *log = GetLog(LLDBLog::Thread); + + NativeProcessAIX &process = GetProcess(); + + lldb::pid_t pid = process.GetID(); + lldb::tid_t tid = GetID(); + + LLDB_LOGF(log, + "NativeThreadAIX::%s requesting thread stop(pid: %" PRIu64 + ", tid: %" PRIu64 ")", + __FUNCTION__, pid, tid); + + Status err; + errno = 0; + if (::kill(pid, SIGSTOP) != 0) { + err.SetErrorToErrno(); + LLDB_LOGF(log, + "NativeThreadAIX::%s kill(%" PRIu64 ", SIGSTOP) failed: %s", + __FUNCTION__, pid, err.AsCString()); + } + return err; +} + +void NativeThreadAIX::MaybeLogStateChange(lldb::StateType new_state) { + Log *log = GetLog(LLDBLog::Thread); + // If we're not logging, we're done. + if (!log) + return; + + // If this is a state change to the same state, we're done. + lldb::StateType old_state = m_state; + if (new_state == old_state) + return; + + LLDB_LOG(log, "pid={0}, tid={1}: changing from state {2} to {3}", + m_process.GetID(), GetID(), old_state, new_state); +} + +NativeProcessAIX &NativeThreadAIX::GetProcess() { + return static_cast(m_process); +} + +const NativeProcessAIX &NativeThreadAIX::GetProcess() const { + return static_cast(m_process); +} + +llvm::Expected> +NativeThreadAIX::GetSiginfo() const { + auto siginfo_buf = + llvm::WritableMemoryBuffer::getNewUninitMemBuffer(sizeof(siginfo_t)); +#if 0 + Status error = + GetProcess().GetSignalInfo(GetID(), siginfo_buf->getBufferStart()); + if (!error.Success()) + return error.ToError(); +#endif + return std::move(siginfo_buf); +} diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h new file mode 100644 index 0000000000000..706a7ce69da8e --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h @@ -0,0 +1,126 @@ +//===-- NativeThreadAIX.h ----------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeThreadAIX_H_ +#define liblldb_NativeThreadAIX_H_ + +#include "Plugins/Process/AIX/NativeRegisterContextAIX.h" +#include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/lldb-private-forward.h" + +#include "llvm/ADT/StringRef.h" + +#include +#include +#include +#include + +namespace lldb_private { +namespace process_aix { + +class NativeProcessAIX; + +class NativeThreadAIX : public NativeThreadProtocol { + friend class NativeProcessAIX; + +public: + NativeThreadAIX(NativeProcessAIX &process, lldb::tid_t tid); + + // NativeThreadProtocol Interface + std::string GetName() override; + + lldb::StateType GetState() override; + + bool GetStopReason(ThreadStopInfo &stop_info, + std::string &description) override; + + NativeRegisterContextAIX &GetRegisterContext() override { + return *m_reg_context_up; + } + + Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, + bool hardware) override; + + Status RemoveWatchpoint(lldb::addr_t addr) override; + + Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override; + + Status RemoveHardwareBreakpoint(lldb::addr_t addr) override; + + NativeProcessAIX &GetProcess(); + + const NativeProcessAIX &GetProcess() const; + + llvm::Expected> + GetSiginfo() const override; + +private: + // Interface for friend classes + + /// Resumes the thread. If \p signo is anything but + /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. + Status Resume(uint32_t signo); + + /// Single steps the thread. If \p signo is anything but + /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. + Status SingleStep(uint32_t signo); + + void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr); + + /// Return true if the thread is stopped. + /// If stopped by a signal, indicate the signo in the signo argument. + /// Otherwise, return LLDB_INVALID_SIGNAL_NUMBER. + bool IsStopped(int *signo); + + void SetStoppedByExec(); + + void SetStoppedByBreakpoint(); + + void SetStoppedByWatchpoint(uint32_t wp_index); + + bool IsStoppedAtBreakpoint(); + + bool IsStoppedAtWatchpoint(); + + void SetStoppedByTrace(); + + void SetStoppedByFork(bool is_vfork, lldb::pid_t child_pid); + + void SetStoppedByVForkDone(); + + void SetStoppedWithNoReason(); + + void SetStoppedByProcessorTrace(llvm::StringRef description); + + void SetExited(); + + Status RequestStop(); + + // Private interface + void MaybeLogStateChange(lldb::StateType new_state); + + void SetStopped(); + + /// Extend m_stop_description with logical and allocation tag values. + /// If there is an error along the way just add the information we were able + /// to get. + void AnnotateSyncTagCheckFault(const siginfo_t *info); + + // Member Variables + lldb::StateType m_state; + ThreadStopInfo m_stop_info; + std::unique_ptr m_reg_context_up; + std::string m_stop_description; + using WatchpointIndexMap = std::map; + WatchpointIndexMap m_watchpoint_index_map; + WatchpointIndexMap m_hw_break_index_map; +}; +} // namespace process_aix +} // namespace lldb_private + +#endif // #ifndef liblldb_NativeThreadAIX_H_ diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt index a51d0f7afd175..01bb5f462eba4 100644 --- a/lldb/source/Plugins/Process/CMakeLists.txt +++ b/lldb/source/Plugins/Process/CMakeLists.txt @@ -7,6 +7,9 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD") add_subdirectory(NetBSD) add_subdirectory(POSIX) +elseif (CMAKE_SYSTEM_NAME MATCHES "AIX") + add_subdirectory(AIX) + add_subdirectory(POSIX) elseif (CMAKE_SYSTEM_NAME MATCHES "Windows") add_subdirectory(Windows/Common) elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin") diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 32c71d87c7f58..db271357d792a 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -46,8 +46,34 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, function_options.include_inlines = false; SymbolContextList sc_list; +#if !defined(__AIX__) process->GetTarget().GetImages().FindFunctions( ConstString("mmap"), eFunctionNameTypeFull, function_options, sc_list); +#else + process->GetTarget().GetImages().FindFunctions( + ConstString("mmap64"), eFunctionNameTypeFull, function_options, sc_list); + SymbolContextList toc_list; + process->GetTarget().GetImages().FindSymbolsWithNameAndType( + ConstString("TOC"), lldb::eSymbolTypeAny, toc_list); + + AddressRange toc_range; + if (sc_list.GetSize() > 0) { + SymbolContext sc; + if (sc_list.GetContextAtIndex(0, sc)) { + for (int i = 0; i < toc_list.GetSize(); ++i) { + SymbolContext tocSC; + if (toc_list.GetContextAtIndex(i, tocSC)) { + if (tocSC.module_sp == sc.module_sp) { + if (tocSC.GetAddressRange(eSymbolContextSymbol, 0, false, + toc_range)) { + break; + } + } + } + } + } + } +#endif const uint32_t count = sc_list.GetSize(); if (count > 0) { SymbolContext sc; @@ -96,9 +122,16 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, MmapArgList args = process->GetTarget().GetPlatform()->GetMmapArgumentList( arch, addr, length, prot_arg, flags, fd, offset); +#if defined(__AIX__) + lldb::ThreadPlanSP call_plan_sp( + new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(), + toc_range.GetBaseAddress(), + void_ptr_type, args, options)); +#else lldb::ThreadPlanSP call_plan_sp( new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(), void_ptr_type, args, options)); +#endif if (call_plan_sp) { DiagnosticManager diagnostics; diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp index 159fd2856443c..d9b41d595147f 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp @@ -23,6 +23,8 @@ static const lldb_private::RegisterInfo * GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { + //HH + case llvm::Triple::ppc64: case llvm::Triple::ppc64le: return g_register_infos_ppc64le; default: @@ -34,6 +36,8 @@ GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) { static uint32_t GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { + //HitchHike + case llvm::Triple::ppc64: case llvm::Triple::ppc64le: return static_cast(sizeof(g_register_infos_ppc64le) / sizeof(g_register_infos_ppc64le[0])); diff --git a/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp b/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp index 89ecc757a68f5..550b53688fd39 100644 --- a/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp +++ b/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp @@ -20,7 +20,7 @@ using namespace lldb; using namespace lldb_private; -ThreadMemory::ThreadMemory(Process &process, tid_t tid, +ThreadMemory::ThreadMemory(Process &process, lldb::tid_t tid, const ValueObjectSP &thread_info_valobj_sp) : Thread(process, tid), m_backing_thread_sp(), m_thread_info_valobj_sp(thread_info_valobj_sp), m_name(), m_queue(), diff --git a/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt b/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt index 6755999b18185..4eddbb5ec4cfd 100644 --- a/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt +++ b/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt @@ -6,6 +6,11 @@ lldb_tablegen(ProcessGDBRemotePropertiesEnum.inc -gen-lldb-property-enum-defs SOURCE ProcessGDBRemoteProperties.td TARGET LLDBPluginProcessGDBRemotePropertiesEnumGen) +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + set(LLDB_PLUGINS lldbPluginProcessUtility ) diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 74e392249a94e..b7ecf7a5dc328 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -40,6 +40,10 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/JSON.h" +#if defined(__AIX__) +#include +#endif + #if defined(HAVE_LIBCOMPRESSION) #include #endif @@ -1710,6 +1714,32 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( return error; } +#if defined(__AIX__) +Status GDBRemoteCommunicationClient::GetLDXINFO(struct ld_xinfo *info_ptr) +{ + Status error; + + char packet[64]; + const int packet_len = ::snprintf(packet, sizeof(packet), "qLDXINFO"); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response) == + PacketResult::Success && + response.GetResponseType() == StringExtractorGDBRemote::eResponse) { + llvm::MutableArrayRef infoData((uint8_t *)info_ptr, sizeof(struct ld_xinfo)*64); + size_t got_bytes = response.GetHexBytesAvail(infoData); + if (got_bytes != sizeof(struct ld_xinfo)*64) { + error.SetErrorString("qLDXINFO ret bad size"); + return error; + } + } else { + error.SetErrorString("qLDXINFO is not supported"); + } + return error; +} +#endif + Status GDBRemoteCommunicationClient::GetQXferMemoryMapRegionInfo( lldb::addr_t addr, MemoryRegionInfo ®ion) { Status error = LoadQXferMemoryMap(); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 898d176abc346..520f37ac56716 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -32,6 +32,10 @@ #include "llvm/Support/VersionTuple.h" +#if defined(__AIX__) +struct ld_xinfo; +#endif + namespace lldb_private { namespace process_gdb_remote { @@ -196,6 +200,9 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase { Status GetMemoryRegionInfo(lldb::addr_t addr, MemoryRegionInfo &range_info); std::optional GetWatchpointSlotCount(); +#if defined(__AIX__) + Status GetLDXINFO(struct ld_xinfo *info_ptr); +#endif std::optional GetWatchpointReportedAfter(); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index a0b08a219ae14..f019062986925 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -48,6 +48,9 @@ #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "lldb/Utility/StringExtractorGDBRemote.h" +#if defined(__AIX__) +#include +#endif using namespace lldb; using namespace lldb_private; @@ -193,6 +196,8 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { &GDBRemoteCommunicationServerLLGS::Handle_Z); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_z, &GDBRemoteCommunicationServerLLGS::Handle_z); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLDXINFO, + &GDBRemoteCommunicationServerLLGS::Handle_qLDXINFO); RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_QPassSignals, &GDBRemoteCommunicationServerLLGS::Handle_QPassSignals); @@ -3006,6 +3011,29 @@ GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) { } } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_qLDXINFO(StringExtractorGDBRemote &packet) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { + Log *log = GetLog(LLDBLog::Process); + LLDB_LOG(log, "qLDXINFO failed, no process available"); + return SendErrorResponse(0xff); + } + +#if defined(__AIX__) + // FIXME: buffer size + struct ld_xinfo info[64]; + if (ptrace64(PT_LDXINFO, m_current_process->GetID(), (long long)&(info[0]), sizeof(info), nullptr) != 0) { + return SendErrorResponse(0xff); + } + StreamGDBRemote response; + response.PutBytesAsRawHex8(&(info[0]), sizeof(info)); + return SendPacketNoLock(response.GetString()); +#else + return SendErrorResponse(0xff); +#endif +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index 646b6a102abf6..a464479e178de 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -211,6 +211,8 @@ class GDBRemoteCommunicationServerLLGS PacketResult Handle_z(StringExtractorGDBRemote &packet); + PacketResult Handle_qLDXINFO(StringExtractorGDBRemote &packet); + PacketResult Handle_s(StringExtractorGDBRemote &packet); PacketResult Handle_qXfer(StringExtractorGDBRemote &packet); diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 6f9c2cc1e4b4e..10fbaa2b3c837 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -92,6 +92,10 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/raw_ostream.h" +#if defined(__AIX__) +#include +#endif + #define DEBUGSERVER_BASENAME "debugserver" using namespace lldb; using namespace lldb_private; @@ -1513,7 +1517,7 @@ bool ProcessGDBRemote::DoUpdateThreadList(ThreadList &old_thread_list, ThreadList old_thread_list_copy(old_thread_list); if (num_thread_ids > 0) { for (size_t i = 0; i < num_thread_ids; ++i) { - tid_t tid = m_thread_ids[i]; + lldb::tid_t tid = m_thread_ids[i]; ThreadSP thread_sp( old_thread_list_copy.RemoveThreadByProtocolID(tid, false)); if (!thread_sp) { @@ -2945,6 +2949,13 @@ Status ProcessGDBRemote::DoGetMemoryRegionInfo(addr_t load_addr, return error; } +#if defined(__AIX__) +Status ProcessGDBRemote::DoGetLDXINFO(struct ld_xinfo *info_ptr) { + Status error(m_gdb_comm.GetLDXINFO(info_ptr)); + return error; +} +#endif + std::optional ProcessGDBRemote::GetWatchpointSlotCount() { return m_gdb_comm.GetWatchpointSlotCount(); } diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 2492795851388..82200fbea21cd 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -37,6 +37,10 @@ #include "GDBRemoteCommunicationClient.h" #include "GDBRemoteRegisterContext.h" +#if defined(__AIX__) +struct ld_xinfo; +#endif + #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" @@ -423,6 +427,10 @@ class ProcessGDBRemote : public Process, Status DoGetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo ®ion_info) override; +#if defined(__AIX__) + Status DoGetLDXINFO(struct ld_xinfo *info_ptr) override; +#endif + private: // For ProcessGDBRemote only std::string m_partial_profile_data; diff --git a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp index 1da7696c9a352..930c707604bb3 100644 --- a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp +++ b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp @@ -593,19 +593,19 @@ bool ProcessMachCore::DoUpdateThreadList(ThreadList &old_thread_list, ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); if (core_objfile) { - std::set used_tids; + std::set used_tids; const uint32_t num_threads = core_objfile->GetNumThreadContexts(); - std::vector tids; + std::vector tids; if (core_objfile->GetCorefileThreadExtraInfos(tids)) { assert(tids.size() == num_threads); // Find highest tid value. - tid_t highest_tid = 0; + lldb::tid_t highest_tid = 0; for (uint32_t i = 0; i < num_threads; i++) { if (tids[i] != LLDB_INVALID_THREAD_ID && tids[i] > highest_tid) highest_tid = tids[i]; } - tid_t current_unused_tid = highest_tid + 1; + lldb::tid_t current_unused_tid = highest_tid + 1; for (uint32_t i = 0; i < num_threads; i++) { if (tids[i] == LLDB_INVALID_THREAD_ID) { tids[i] = current_unused_tid++; diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt index 7523d65abf0f8..1ce60a0b66154 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt +++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt @@ -20,6 +20,11 @@ if (LLDB_ENABLE_LIBEDIT) endif() add_subdirectory(Interfaces) +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + add_lldb_library(lldbPluginScriptInterpreterPython PLUGIN PythonDataObjects.cpp diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp index e1f73f1997e36..92882cfc3da31 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -500,6 +500,8 @@ dw_addr_t DWARFFormValue::Address() const { &offset, index_size); } +bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; + std::pair DWARFFormValue::ReferencedUnitAndOffset() const { uint64_t value = m_value.value.uval; @@ -512,6 +514,8 @@ DWARFFormValue::ReferencedUnitAndOffset() const { assert(m_unit); // Unit must be valid for DW_FORM_ref forms that are compile // unit relative or we will get this wrong value += m_unit->GetOffset(); + if (UGLY_FLAG_FOR_AIX) + value -= 8; if (!m_unit->ContainsDIEOffset(value)) { m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( "DW_FORM_ref* DIE reference {0:x16} is outside of its CU", value); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index 66a762bf9b685..6721c1895a576 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -924,6 +924,12 @@ const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() { return *m_func_aranges_up; } +/* AIX-NOTE - TODO: Removed conflicting code due to merge conflicts + * Refer Patches: 27,28,29,30,35 and 76 + * and modify the code accordingly. */ + +bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; + llvm::Expected DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid, const DWARFDataExtractor &debug_info, @@ -1002,6 +1008,10 @@ const lldb_private::DWARFDataExtractor &DWARFUnit::GetData() const { uint32_t DWARFUnit::GetHeaderByteSize() const { switch (m_header.getUnitType()) { case llvm::dwarf::DW_UT_compile: + if (UGLY_FLAG_FOR_AIX) + return 11 + 4/*GetDWARFSizeOfOffset*/; + else + return GetVersion() < 5 ? 11 : 12; case llvm::dwarf::DW_UT_partial: return GetVersion() < 5 ? 11 : 12; case llvm::dwarf::DW_UT_skeleton: @@ -1016,7 +1026,7 @@ uint32_t DWARFUnit::GetHeaderByteSize() const { std::optional DWARFUnit::GetStringOffsetSectionItem(uint32_t index) const { - offset_t offset = GetStrOffsetsBase() + index * 4; + lldb::offset_t offset = GetStrOffsetsBase() + index * 4; return m_dwarf.GetDWARFContext().getOrLoadStrOffsetsData().GetU32(&offset); } diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp index 2064b73dc3ea5..824528fc3acfa 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp @@ -216,7 +216,7 @@ lldb::addr_t AppleGetThreadItemInfoHandler::SetupGetThreadItemInfoFunction( AppleGetThreadItemInfoHandler::GetThreadItemInfoReturnInfo AppleGetThreadItemInfoHandler::GetThreadItemInfo(Thread &thread, - tid_t thread_id, + lldb::tid_t thread_id, addr_t page_to_free, uint64_t page_to_free_size, Status &error) { diff --git a/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/lldb/source/Symbol/DWARFCallFrameInfo.cpp index f3df8a2c27f5a..de244e372579d 100644 --- a/lldb/source/Symbol/DWARFCallFrameInfo.cpp +++ b/lldb/source/Symbol/DWARFCallFrameInfo.cpp @@ -33,7 +33,7 @@ using namespace lldb_private::dwarf; // Used for calls when the value type is specified by a DWARF EH Frame pointer // encoding. static uint64_t -GetGNUEHPointer(const DataExtractor &DE, offset_t *offset_ptr, +GetGNUEHPointer(const DataExtractor &DE, lldb::offset_t *offset_ptr, uint32_t eh_ptr_enc, addr_t pc_rel_addr, addr_t text_addr, addr_t data_addr) //, BSDRelocs *data_relocs) const { @@ -588,7 +588,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset, if (cie->augmentation[0] == 'z') { uint32_t aug_data_len = (uint32_t)m_cfi_data.GetULEB128(&offset); if (aug_data_len != 0 && cie->lsda_addr_encoding != DW_EH_PE_omit) { - offset_t saved_offset = offset; + lldb::offset_t saved_offset = offset; lsda_data_file_address = GetGNUEHPointer(m_cfi_data, &offset, cie->lsda_addr_encoding, pc_rel_addr, text_addr, data_addr); diff --git a/lldb/source/Target/ABI.cpp b/lldb/source/Target/ABI.cpp index 110b5c86fc425..6df03533cda29 100644 --- a/lldb/source/Target/ABI.cpp +++ b/lldb/source/Target/ABI.cpp @@ -208,6 +208,15 @@ bool ABI::PrepareTrivialCall(Thread &thread, lldb::addr_t sp, llvm_unreachable("Should never get here!"); } +bool ABI::PrepareTrivialCall(Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t tocAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef args) const { + // dummy prepare trivial call + llvm_unreachable("Should never get here!"); +} + bool ABI::GetFallbackRegisterLocation( const RegisterInfo *reg_info, UnwindPlan::Row::RegisterLocation &unwind_regloc) { diff --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt index a42c44b761dc5..833489b16dfd7 100644 --- a/lldb/source/Target/CMakeLists.txt +++ b/lldb/source/Target/CMakeLists.txt @@ -1,3 +1,8 @@ +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + lldb_tablegen(TargetProperties.inc -gen-lldb-property-defs SOURCE TargetProperties.td TARGET LLDBTargetPropertiesGen) diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index e3c4f2ee398cc..e31245178b2f2 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -75,6 +75,10 @@ #include "lldb/Utility/State.h" #include "lldb/Utility/Timer.h" +#if defined(__AIX__) +#include +#endif + using namespace lldb; using namespace lldb_private; using namespace std::chrono; @@ -6206,6 +6210,12 @@ Status Process::GetMemoryRegionInfo(lldb::addr_t load_addr, return DoGetMemoryRegionInfo(load_addr, range_info); } +#if defined(__AIX__) +Status Process::GetLDXINFO(struct ld_xinfo *info_ptr) { + return DoGetLDXINFO(info_ptr); +} +#endif + Status Process::GetMemoryRegions(lldb_private::MemoryRegionInfos ®ion_list) { Status error; diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index a61228d092d89..57f42ea56cb18 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -40,6 +40,9 @@ #include #include +#ifdef __AIX__ +#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" +#endif using namespace lldb; using namespace lldb_private; @@ -1257,6 +1260,10 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( // Answer the question: Where did THIS frame save the CALLER frame ("previous" // frame)'s register value? +#ifdef __AIX__ +extern bool UGLY_HACK_NULL_TOPFRAME; +#endif + enum UnwindLLDB::RegisterSearchResult RegisterContextUnwind::SavedLocationForRegister( uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc) { @@ -1517,6 +1524,11 @@ RegisterContextUnwind::SavedLocationForRegister( new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext; new_regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); +#ifdef __AIX__ + if (UGLY_HACK_NULL_TOPFRAME && new_regloc.location.register_number == 0x20) { + new_regloc.location.register_number = 0x24; + } +#endif m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; regloc = new_regloc; UnwindLogMsg("supplying caller's register %s (%d) from the live " @@ -2368,6 +2380,40 @@ bool RegisterContextUnwind::ReadPC(addr_t &pc) { } } +#ifdef __AIX__ +bool RegisterContextUnwind::ReadLR(addr_t &lr) { + if (!IsValid()) + return false; + + bool above_trap_handler = false; + if (GetNextFrame().get() && GetNextFrame()->IsValid() && + GetNextFrame()->IsTrapHandlerFrame()) + above_trap_handler = true; + + if (ReadGPRValue(eRegisterKindLLDB, gpr_lr_ppc64le, lr)) { + // A lr value of 0 or 1 is impossible in the middle of the stack -- it + // indicates the end of a stack walk. + // On the currently executing frame (or such a frame interrupted + // asynchronously by sigtramp et al) this may occur if code has jumped + // through a NULL pointer -- we want to be able to unwind past that frame + // to help find the bug. + + ProcessSP process_sp (m_thread.GetProcess()); + if (process_sp) + { + ABI *abi = process_sp->GetABI().get(); + if (abi) + lr = abi->FixCodeAddress(lr); + } + + return !(m_all_registers_available == false && + above_trap_handler == false && (lr == 0 || lr == 1)); + } else { + return false; + } +} +#endif + void RegisterContextUnwind::UnwindLogMsg(const char *fmt, ...) { Log *log = GetLog(LLDBLog::Unwind); if (!log) diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp index 50dcb66b9719f..0926579ea2930 100644 --- a/lldb/source/Target/ThreadPlanCallFunction.cpp +++ b/lldb/source/Target/ThreadPlanCallFunction.cpp @@ -127,6 +127,40 @@ ThreadPlanCallFunction::ThreadPlanCallFunction( m_valid = true; } +ThreadPlanCallFunction::ThreadPlanCallFunction( + Thread &thread, const Address &function, const Address &toc, + const CompilerType &return_type, + llvm::ArrayRef args, const EvaluateExpressionOptions &options) + : ThreadPlan(ThreadPlan::eKindCallFunction, "Call function plan", thread, + eVoteNoOpinion, eVoteNoOpinion), + m_valid(false), m_stop_other_threads(options.GetStopOthers()), + m_unwind_on_error(options.DoesUnwindOnError()), + m_ignore_breakpoints(options.DoesIgnoreBreakpoints()), + m_debug_execution(options.GetDebug()), + m_trap_exceptions(options.GetTrapExceptions()), m_function_addr(function), + m_function_sp(0), m_takedown_done(false), + m_should_clear_objc_exception_bp(false), + m_should_clear_cxx_exception_bp(false), + m_stop_address(LLDB_INVALID_ADDRESS), m_return_type(return_type) { + lldb::addr_t start_load_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t function_load_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t toc_addr = LLDB_INVALID_ADDRESS; + ABI *abi = nullptr; + + if (!ConstructorSetup(thread, abi, start_load_addr, function_load_addr)) + return; + + toc_addr = toc.GetLoadAddress(&GetTarget()); + + if (!abi->PrepareTrivialCall(thread, m_function_sp, function_load_addr, + toc_addr, start_load_addr, args)) + return; + + ReportRegisterState("Function call was set up. Register state was:"); + + m_valid = true; +} + ThreadPlanCallFunction::ThreadPlanCallFunction( Thread &thread, const Address &function, const EvaluateExpressionOptions &options) diff --git a/lldb/source/Target/UnwindLLDB.cpp b/lldb/source/Target/UnwindLLDB.cpp index f43e940492b09..255b829738ba2 100644 --- a/lldb/source/Target/UnwindLLDB.cpp +++ b/lldb/source/Target/UnwindLLDB.cpp @@ -68,6 +68,10 @@ uint32_t UnwindLLDB::DoGetFrameCount() { return m_frames.size(); } +#ifdef __AIX__ +bool UGLY_HACK_NULL_TOPFRAME = false; +#endif + bool UnwindLLDB::AddFirstFrame() { if (m_frames.size() > 0) return true; @@ -91,6 +95,17 @@ bool UnwindLLDB::AddFirstFrame() { if (!reg_ctx_sp->ReadPC(first_cursor_sp->start_pc)) goto unwind_done; +#ifdef __AIX__ + lldb::addr_t lr; + if (!reg_ctx_sp->ReadLR(lr)) + goto unwind_done; + + if (first_cursor_sp->start_pc == 0) { + first_cursor_sp->start_pc = lr; + UGLY_HACK_NULL_TOPFRAME = true; + } +#endif + // Everything checks out, so release the auto pointer value and let the // cursor own it in its shared pointer first_cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp; diff --git a/lldb/source/Utility/ArchSpec.cpp b/lldb/source/Utility/ArchSpec.cpp index 07ef435ef451d..3868f77169cc6 100644 --- a/lldb/source/Utility/ArchSpec.cpp +++ b/lldb/source/Utility/ArchSpec.cpp @@ -14,6 +14,7 @@ #include "lldb/lldb-defines.h" #include "llvm/ADT/STLExtras.h" #include "llvm/BinaryFormat/COFF.h" +#include "llvm/BinaryFormat/XCOFF.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Compiler.h" @@ -459,10 +460,22 @@ static const ArchDefinition g_coff_arch_def = { "pe-coff", }; +static const ArchDefinitionEntry g_xcoff_arch_entries[] = { + {ArchSpec::eCore_ppc_generic, llvm::XCOFF::TCPU_COM, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, + {ArchSpec::eCore_ppc64_generic, llvm::XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu} +}; + +static const ArchDefinition g_xcoff_arch_def = { + eArchTypeXCOFF, + std::size(g_xcoff_arch_entries), + g_xcoff_arch_entries, + "xcoff", +}; + //===----------------------------------------------------------------------===// // Table of all ArchDefinitions static const ArchDefinition *g_arch_definitions[] = { - &g_macho_arch_def, &g_elf_arch_def, &g_coff_arch_def}; + &g_macho_arch_def, &g_elf_arch_def, &g_coff_arch_def, &g_xcoff_arch_def}; //===----------------------------------------------------------------------===// // Static helper functions. @@ -903,6 +916,9 @@ bool ArchSpec::SetArchitecture(ArchitectureType arch_type, uint32_t cpu, } else if (arch_type == eArchTypeCOFF && os == llvm::Triple::Win32) { m_triple.setVendor(llvm::Triple::PC); m_triple.setOS(llvm::Triple::Win32); + } else if (arch_type == eArchTypeXCOFF && os == llvm::Triple::AIX) { + m_triple.setVendor(llvm::Triple::IBM); + m_triple.setOS(llvm::Triple::AIX); } else { m_triple.setVendor(llvm::Triple::UnknownVendor); m_triple.setOS(llvm::Triple::UnknownOS); diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp index 9f79d2271b1e6..dbd3236536f8c 100644 --- a/lldb/source/Utility/StringExtractorGDBRemote.cpp +++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -227,6 +227,8 @@ StringExtractorGDBRemote::GetServerPacketType() const { return eServerPacketType_qLaunchGDBServer; if (PACKET_MATCHES("qLaunchSuccess")) return eServerPacketType_qLaunchSuccess; + if (PACKET_MATCHES("qLDXINFO")) + return eServerPacketType_qLDXINFO; break; case 'M': diff --git a/lldb/test/CMakeLists.txt b/lldb/test/CMakeLists.txt index 5ac474736eb63..413a1e5120288 100644 --- a/lldb/test/CMakeLists.txt +++ b/lldb/test/CMakeLists.txt @@ -155,7 +155,7 @@ if(TARGET clang) add_lldb_test_dependency(clang) # TestFullLtoStepping depends on LTO, and only runs when the compiler is clang. - add_lldb_test_dependency(LTO) + #add_lldb_test_dependency(LTO) if (TARGET libcxx OR ("libcxx" IN_LIST LLVM_ENABLE_RUNTIMES)) set(LLDB_HAS_LIBCXX ON) diff --git a/lldb/test/Shell/Expr/TestIRMemoryMap.test b/lldb/test/Shell/Expr/TestIRMemoryMap.test index 9dd0413be14cf..5ed61ad33ffc4 100644 --- a/lldb/test/Shell/Expr/TestIRMemoryMap.test +++ b/lldb/test/Shell/Expr/TestIRMemoryMap.test @@ -1,6 +1,6 @@ # UNSUPPORTED: system-windows -# RUN: %clangxx_host %p/Inputs/call-function.cpp -g -o %t +# RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t # RUN: lldb-test ir-memory-map %t %S/Inputs/ir-memory-map-basic # RUN: lldb-test ir-memory-map -host-only %t %S/Inputs/ir-memory-map-basic diff --git a/lldb/test/Shell/Process/TestEnvironment.test b/lldb/test/Shell/Process/TestEnvironment.test index e6d6e56fc9203..2ead258719f32 100644 --- a/lldb/test/Shell/Process/TestEnvironment.test +++ b/lldb/test/Shell/Process/TestEnvironment.test @@ -3,7 +3,7 @@ UNSUPPORTED: lldb-repro The double quotes around "BAR" ensure we don't match the command. -RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t +RUN: %clangxx_host -std=c++11 -I/compgpfs/build/xlcit/rings/openxlC/aix/wyvern_dev/ring0/latest/opt/IBM/openxlC/17.1.2/include/c++/v1/ %p/Inputs/env.cpp -o %t RUN: %lldb %t -o 'process launch --environment FOO="BAR"' | FileCheck %s RUN: %lldb %t -o 'env FOO="BAR"' -o 'process launch' | FileCheck %s diff --git a/lldb/tools/driver/CMakeLists.txt b/lldb/tools/driver/CMakeLists.txt index cd304a047dea6..78617be24f780 100644 --- a/lldb/tools/driver/CMakeLists.txt +++ b/lldb/tools/driver/CMakeLists.txt @@ -11,6 +11,11 @@ if(APPLE) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_BINARY_DIR}/lldb-Info.plist") endif() +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + add_lldb_tool(lldb Driver.cpp Platform.cpp diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp index 14371da64f2f2..f7eaf56738d7d 100644 --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -639,7 +639,7 @@ void sigwinch_handler(int signo) { } void sigint_handler(int signo) { -#ifdef _WIN32 // Restore handler as it is not persistent on Windows +#if defined(_WIN32) || defined(__AIX__) // Restore handler as it is not persistent on Windows signal(SIGINT, sigint_handler); #endif static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT; @@ -727,8 +727,11 @@ static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) { int main(int argc, char const *argv[]) { // Editline uses for example iswprint which is dependent on LC_CTYPE. + // FIXME: this caused unexpected SIGTRAP on AIX +#ifndef __AIX__ std::setlocale(LC_ALL, ""); std::setlocale(LC_CTYPE, ""); +#endif // Setup LLVM signal handlers and make sure we call llvm_shutdown() on // destruction. diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index f8f0d86453f58..2fa6f6c9a5369 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -6,6 +6,10 @@ if (HAVE_LIBPTHREAD) list(APPEND extra_libs pthread) endif () +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + add_definitions("-D_AIX") + add_definitions("-D_ALL_SOURCE") +endif() if(APPLE) configure_file( diff --git a/lldb/tools/lldb-server/CMakeLists.txt b/lldb/tools/lldb-server/CMakeLists.txt index 9030ed709a647..0d69ae32a008f 100644 --- a/lldb/tools/lldb-server/CMakeLists.txt +++ b/lldb/tools/lldb-server/CMakeLists.txt @@ -8,6 +8,10 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux|Android") list(APPEND LLDB_PLUGINS lldbPluginProcessLinux) endif() +if(CMAKE_SYSTEM_NAME MATCHES "AIX") + list(APPEND LLDB_PLUGINS lldbPluginProcessAIX) +endif() + if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") list(APPEND LLDB_PLUGINS lldbPluginProcessFreeBSD) endif() @@ -20,6 +24,8 @@ if(CMAKE_SYSTEM_NAME MATCHES "Darwin") list(APPEND LLDB_PLUGINS lldbPluginObjectFileMachO) elseif(CMAKE_SYSTEM_NAME MATCHES "Windows") list(APPEND LLDB_PLUGINS lldbPluginObjectFilePECOFF) +elseif(CMAKE_SYSTEM_NAME MATCHES "AIX") + list(APPEND LLDB_PLUGINS lldbPluginObjectFileXCOFF) else() list(APPEND LLDB_PLUGINS lldbPluginObjectFileELF) endif() @@ -54,6 +60,7 @@ add_lldb_tool(lldb-server lldbPluginInstructionMIPS lldbPluginInstructionMIPS64 lldbPluginInstructionRISCV + lldbPluginInstructionPPC64 ${LLDB_SYSTEM_LIBS} LINK_COMPONENTS diff --git a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp index 4233252a84dfc..91bb2083a88b5 100644 --- a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp +++ b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp @@ -14,6 +14,9 @@ using HostObjectFile = ObjectFileMachO; #elif defined(_WIN32) #include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" using HostObjectFile = ObjectFilePECOFF; +#elif defined(__AIX__) +#include "Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h" +using HostObjectFile = ObjectFileXCOFF; #else #include "Plugins/ObjectFile/ELF/ObjectFileELF.h" using HostObjectFile = ObjectFileELF; @@ -46,6 +49,10 @@ using HostObjectFile = ObjectFileELF; #include "Plugins/Instruction/MIPS/EmulateInstructionMIPS.h" #endif +#if defined(__AIX__) +#include "Plugins/Instruction/PPC64/EmulateInstructionPPC64.h" +#endif + #if defined(__riscv) #define LLDB_TARGET_RISCV #include "Plugins/Instruction/RISCV/EmulateInstructionRISCV.h" @@ -75,6 +82,10 @@ llvm::Error SystemInitializerLLGS::Initialize() { EmulateInstructionRISCV::Initialize(); #endif +#if defined(__AIX__) + EmulateInstructionPPC64::Initialize(); +#endif + return llvm::Error::success(); } @@ -97,5 +108,9 @@ void SystemInitializerLLGS::Terminate() { EmulateInstructionRISCV::Terminate(); #endif +#if defined(__AIX__) + EmulateInstructionPPC64::Terminate(); +#endif + SystemInitializerCommon::Terminate(); } diff --git a/lldb/tools/lldb-server/lldb-gdbserver.cpp b/lldb/tools/lldb-server/lldb-gdbserver.cpp index 563284730bc70..2a14f4f9c82aa 100644 --- a/lldb/tools/lldb-server/lldb-gdbserver.cpp +++ b/lldb/tools/lldb-server/lldb-gdbserver.cpp @@ -45,6 +45,8 @@ #include "Plugins/Process/NetBSD/NativeProcessNetBSD.h" #elif defined(_WIN32) #include "Plugins/Process/Windows/Common/NativeProcessWindows.h" +#elif defined(__AIX__) +#include "Plugins/Process/AIX/NativeProcessAIX.h" #endif #ifndef LLGS_PROGRAM_NAME @@ -70,6 +72,8 @@ typedef process_freebsd::NativeProcessFreeBSD::Manager NativeProcessManager; typedef process_netbsd::NativeProcessNetBSD::Manager NativeProcessManager; #elif defined(_WIN32) typedef NativeProcessWindows::Manager NativeProcessManager; +#elif defined(__AIX__) +typedef process_aix::NativeProcessAIX::Manager NativeProcessManager; #else // Dummy implementation to make sure the code compiles class NativeProcessManager : public NativeProcessProtocol::Manager { diff --git a/lldb/unittests/Host/FileSystemTest.cpp b/lldb/unittests/Host/FileSystemTest.cpp index 58887f6b2467e..89d0f5b87171a 100644 --- a/lldb/unittests/Host/FileSystemTest.cpp +++ b/lldb/unittests/Host/FileSystemTest.cpp @@ -59,7 +59,7 @@ class DummyFileSystem : public vfs::FileSystem { return I->second; } ErrorOr> - openFileForRead(const Twine &Path) override { + openFileForRead(const Twine &Path, bool IsText) override { auto S = status(Path); if (S) return std::unique_ptr(new DummyFile{*S}); diff --git a/lldb/unittests/Host/posix/TerminalTest.cpp b/lldb/unittests/Host/posix/TerminalTest.cpp index 5187a0c20a68b..f3de92c0852b1 100644 --- a/lldb/unittests/Host/posix/TerminalTest.cpp +++ b/lldb/unittests/Host/posix/TerminalTest.cpp @@ -94,15 +94,19 @@ TEST_F(TerminalTest, SetRaw) { TEST_F(TerminalTest, SetBaudRate) { struct termios terminfo; +#if (defined(__AIX__) && defined(B38400)) || !defined(__AIX__) ASSERT_THAT_ERROR(m_term.SetBaudRate(38400), llvm::Succeeded()); ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0); EXPECT_EQ(cfgetispeed(&terminfo), static_cast(B38400)); EXPECT_EQ(cfgetospeed(&terminfo), static_cast(B38400)); +#endif +#if (defined(__AIX__) && defined(B115200)) || !defined(__AIX__) ASSERT_THAT_ERROR(m_term.SetBaudRate(115200), llvm::Succeeded()); ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0); EXPECT_EQ(cfgetispeed(&terminfo), static_cast(B115200)); EXPECT_EQ(cfgetospeed(&terminfo), static_cast(B115200)); +#endif // uncommon value #if defined(B153600) diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h index 5a7cd8e38f2b7..fa9c6781e24f5 100644 --- a/llvm/include/llvm/Object/XCOFFObjectFile.h +++ b/llvm/include/llvm/Object/XCOFFObjectFile.h @@ -542,7 +542,6 @@ class XCOFFObjectFile : public ObjectFile { template const T *sectionHeaderTable() const; size_t getFileHeaderSize() const; - size_t getSectionHeaderSize() const; const XCOFFSectionHeader32 *toSection32(DataRefImpl Ref) const; const XCOFFSectionHeader64 *toSection64(DataRefImpl Ref) const; @@ -578,6 +577,9 @@ class XCOFFObjectFile : public ObjectFile { void checkSectionAddress(uintptr_t Addr, uintptr_t TableAddr) const; public: + size_t getSectionHeaderSize() const; + Expected getLoaderSectionAddress() const; + static constexpr uint64_t InvalidRelocOffset = std::numeric_limits::max(); diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp index bdd04b00f557b..9c96df1bbdc54 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -251,10 +251,16 @@ Expected DWARFUnit::getStringOffsetSectionItem(uint32_t Index) const { return DA.getRelocatedValue(ItemSize, &Offset); } +bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; + Error DWARFUnitHeader::extract(DWARFContext &Context, const DWARFDataExtractor &debug_info, uint64_t *offset_ptr, DWARFSectionKind SectionKind) { + if (UGLY_FLAG_FOR_AIX) { + // FIXME: hack to get version + *offset_ptr += 8; + } Offset = *offset_ptr; Error Err = Error::success(); IndexEntry = nullptr; @@ -267,8 +273,13 @@ Error DWARFUnitHeader::extract(DWARFContext &Context, AbbrOffset = debug_info.getRelocatedValue( FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err); } else { - AbbrOffset = debug_info.getRelocatedValue( - FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err); + if (UGLY_FLAG_FOR_AIX) { + AbbrOffset = debug_info.getRelocatedValue( + 8, offset_ptr, nullptr, &Err); + } else { + AbbrOffset = debug_info.getRelocatedValue( + FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err); + } FormParams.AddrSize = debug_info.getU8(offset_ptr, &Err); // Fake a unit type based on the section type. This isn't perfect, // but distinguishing compile and type units is generally enough. >From b1da5b1cf35829fcbf4ad6564c6005c755012e47 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 7 Aug 2024 12:18:45 -0500 Subject: [PATCH 02/49] Code license notice --- lldb/NOTICE.TXT | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 lldb/NOTICE.TXT diff --git a/lldb/NOTICE.TXT b/lldb/NOTICE.TXT new file mode 100644 index 0000000000000..d814272967476 --- /dev/null +++ b/lldb/NOTICE.TXT @@ -0,0 +1,7 @@ + +This product contains small piece of code to support AIX, taken from netbsd. + + * LICENSE: + * lldb/source/Host/common/LICENSE.aix-netbsd.txt (OpenSSL License) + * HOMEPAGE: + * https://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/crypto/external/bsd/openssl/dist >From 50ad673a78029fd6c47d90317e2c61ca2b59d5c5 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 7 Aug 2024 13:27:20 -0500 Subject: [PATCH 03/49] Reverting .tests --- lldb/test/Shell/Expr/TestIRMemoryMap.test | 2 +- lldb/test/Shell/Process/TestEnvironment.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/test/Shell/Expr/TestIRMemoryMap.test b/lldb/test/Shell/Expr/TestIRMemoryMap.test index 5ed61ad33ffc4..9dd0413be14cf 100644 --- a/lldb/test/Shell/Expr/TestIRMemoryMap.test +++ b/lldb/test/Shell/Expr/TestIRMemoryMap.test @@ -1,6 +1,6 @@ # UNSUPPORTED: system-windows -# RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t +# RUN: %clangxx_host %p/Inputs/call-function.cpp -g -o %t # RUN: lldb-test ir-memory-map %t %S/Inputs/ir-memory-map-basic # RUN: lldb-test ir-memory-map -host-only %t %S/Inputs/ir-memory-map-basic diff --git a/lldb/test/Shell/Process/TestEnvironment.test b/lldb/test/Shell/Process/TestEnvironment.test index 2ead258719f32..e6d6e56fc9203 100644 --- a/lldb/test/Shell/Process/TestEnvironment.test +++ b/lldb/test/Shell/Process/TestEnvironment.test @@ -3,7 +3,7 @@ UNSUPPORTED: lldb-repro The double quotes around "BAR" ensure we don't match the command. -RUN: %clangxx_host -std=c++11 -I/compgpfs/build/xlcit/rings/openxlC/aix/wyvern_dev/ring0/latest/opt/IBM/openxlC/17.1.2/include/c++/v1/ %p/Inputs/env.cpp -o %t +RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t RUN: %lldb %t -o 'process launch --environment FOO="BAR"' | FileCheck %s RUN: %lldb %t -o 'env FOO="BAR"' -o 'process launch' | FileCheck %s >From c1967be8fe14d469cb5ae9d41d115a7003ff39b6 Mon Sep 17 00:00:00 2001 From: Lakshmi Surekha Kovvuri Date: Thu, 22 Aug 2024 08:49:50 -0500 Subject: [PATCH 04/49] For TestSuite Run --- lldb/unittests/Host/FileSystemTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/unittests/Host/FileSystemTest.cpp b/lldb/unittests/Host/FileSystemTest.cpp index 89d0f5b87171a..58887f6b2467e 100644 --- a/lldb/unittests/Host/FileSystemTest.cpp +++ b/lldb/unittests/Host/FileSystemTest.cpp @@ -59,7 +59,7 @@ class DummyFileSystem : public vfs::FileSystem { return I->second; } ErrorOr> - openFileForRead(const Twine &Path, bool IsText) override { + openFileForRead(const Twine &Path) override { auto S = status(Path); if (S) return std::unique_ptr(new DummyFile{*S}); >From 758ab642d0974e799ac902d8ad240a3a90aeb24d Mon Sep 17 00:00:00 2001 From: Lakshmi Surekha Kovvuri Date: Fri, 30 Aug 2024 08:33:32 -0500 Subject: [PATCH 05/49] Changes made to AIX-specific files to eliminate errors encountered during CI when updating LLDB. --- .../Plugins/Process/AIX/NativeProcessAIX.cpp | 20 ++++++++++--------- .../Process/AIX/NativeRegisterContextAIX.cpp | 4 ++-- .../AIX/NativeRegisterContextAIX_ppc64.cpp | 10 +++++----- .../Plugins/Process/AIX/NativeThreadAIX.cpp | 2 +- .../GDBRemoteCommunicationClient.cpp | 4 ++-- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp index 882f20d30a3bf..5b01a66b0453f 100644 --- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -211,12 +211,14 @@ static Status EnsureFDFlags(int fd, int flags) { int status = fcntl(fd, F_GETFL); if (status == -1) { - error.SetErrorToErrno(); + error = Status::FromErrno(); + // error.SetErrorToErrno(); return error; } if (fcntl(fd, F_SETFL, status | flags) == -1) { - error.SetErrorToErrno(); + error = Status::FromErrno(); + // error.SetErrorToErrno(); return error; } @@ -813,7 +815,7 @@ Status NativeProcessAIX::Resume(const ResumeActionList &resume_actions) { Status error = ResumeThread(static_cast(*thread), action->state, signo); if (error.Fail()) - return Status("NativeProcessAIX::%s: failed to resume thread " + return Status::FromErrorStringWithFormat("NativeProcessAIX::%s: failed to resume thread " "for pid %" PRIu64 ", tid %" PRIu64 ", error = %s", __FUNCTION__, GetID(), thread->GetID(), error.AsCString()); @@ -826,7 +828,7 @@ Status NativeProcessAIX::Resume(const ResumeActionList &resume_actions) { break; default: - return Status("NativeProcessAIX::%s (): unexpected state %s specified " + return Status::FromErrorStringWithFormat("NativeProcessAIX::%s (): unexpected state %s specified " "for pid %" PRIu64 ", tid %" PRIu64, __FUNCTION__, StateAsCString(action->state), GetID(), thread->GetID()); @@ -840,7 +842,7 @@ Status NativeProcessAIX::Halt() { Status error; if (kill(GetID(), SIGSTOP) != 0) - error.SetErrorToErrno(); + error = Status::FromErrno(); return error; } @@ -874,7 +876,7 @@ Status NativeProcessAIX::Signal(int signo) { Host::GetSignalAsCString(signo), GetID()); if (kill(GetID(), signo)) - error.SetErrorToErrno(); + error = Status::FromErrno(); return error; } @@ -951,7 +953,7 @@ Status NativeProcessAIX::Kill() { } if (kill(GetID(), SIGKILL) != 0) { - error.SetErrorToErrno(); + error = Status::FromErrno(); return error; } @@ -1555,7 +1557,7 @@ Status NativeProcessAIX::GetLoadedModuleFileSpec(const char *module_path, return Status(); } } - return Status("Module file (%s) not found in /proc/%" PRIu64 "/maps file!", + return Status::FromErrorStringWithFormat("Module file (%s) not found in /proc/%" PRIu64 "/maps file!", module_file_spec.GetFilename().AsCString(), GetID()); } @@ -2011,7 +2013,7 @@ Status NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid, void *addr, } if (errno) { - error.SetErrorToErrno(); + error = Status::FromErrno(); ret = -1; } diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp index 0859f9501c1b6..071e55543cc3c 100644 --- a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp @@ -27,7 +27,7 @@ Status NativeRegisterContextAIX::ReadRegisterRaw(uint32_t reg_index, RegisterValue ®_value) { const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); if (!reg_info) - return Status("register %" PRIu32 " not found", reg_index); + return Status::FromErrorStringWithFormat("register %" PRIu32 " not found", reg_index); return DoReadRegisterValue(GetPtraceOffset(reg_index), reg_info->name, reg_info->byte_size, reg_value); @@ -82,7 +82,7 @@ NativeRegisterContextAIX::WriteRegisterRaw(uint32_t reg_index, assert(register_to_write_info_p && "register to write does not have valid RegisterInfo"); if (!register_to_write_info_p) - return Status("NativeRegisterContextAIX::%s failed to get RegisterInfo " + return Status::FromErrorStringWithFormat("NativeRegisterContextAIX::%s failed to get RegisterInfo " "for write register index %" PRIu32, __FUNCTION__, reg_to_write); diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp index 1996373791748..0132b52dec6f2 100644 --- a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp @@ -165,7 +165,7 @@ Status NativeRegisterContextAIX_ppc64::ReadRegister( Status error; if (!reg_info) { - error.SetErrorString("reg_info NULL"); + error.FromErrorString("reg_info NULL"); return error; } @@ -251,7 +251,7 @@ Status NativeRegisterContextAIX_ppc64::WriteRegister( const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; if (reg_index == LLDB_INVALID_REGNUM) - return Status("no lldb regnum for %s", reg_info && reg_info->name + return Status::FromErrorStringWithFormat("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : ""); @@ -389,14 +389,14 @@ Status NativeRegisterContextAIX_ppc64::WriteAllRegisterValues( Status error; if (!data_sp) { - error.SetErrorStringWithFormat( + error = Status::FromErrorStringWithFormat( "NativeRegisterContextAIX_ppc64::%s invalid data_sp provided", __FUNCTION__); return error; } if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { - error.SetErrorStringWithFormat( + error = Status::FromErrorStringWithFormat( "NativeRegisterContextAIX_ppc64::%s data_sp contained mismatched " "data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); @@ -405,7 +405,7 @@ Status NativeRegisterContextAIX_ppc64::WriteAllRegisterValues( const uint8_t *src = data_sp->GetBytes(); if (src == nullptr) { - error.SetErrorStringWithFormat("NativeRegisterContextAIX_ppc64::%s " + error = Status::FromErrorStringWithFormat("NativeRegisterContextAIX_ppc64::%s " "DataBuffer::GetBytes() returned a null " "pointer", __FUNCTION__); diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp index e07daccdff550..bb14b6ab4a05e 100644 --- a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp @@ -481,7 +481,7 @@ Status NativeThreadAIX::RequestStop() { Status err; errno = 0; if (::kill(pid, SIGSTOP) != 0) { - err.SetErrorToErrno(); + err = Status::FromErrno(); LLDB_LOGF(log, "NativeThreadAIX::%s kill(%" PRIu64 ", SIGSTOP) failed: %s", __FUNCTION__, pid, err.AsCString()); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 17926f8e4ab53..0aa68a4a09cbe 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -1728,11 +1728,11 @@ Status GDBRemoteCommunicationClient::GetLDXINFO(struct ld_xinfo *info_ptr) llvm::MutableArrayRef infoData((uint8_t *)info_ptr, sizeof(struct ld_xinfo)*64); size_t got_bytes = response.GetHexBytesAvail(infoData); if (got_bytes != sizeof(struct ld_xinfo)*64) { - error.SetErrorString("qLDXINFO ret bad size"); + error.FromErrorString("qLDXINFO ret bad size"); return error; } } else { - error.SetErrorString("qLDXINFO is not supported"); + error.FromErrorString("qLDXINFO is not supported"); } return error; } >From 33d561f4bb74a2efd0da163ebde416c9ad1c2925 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Tue, 10 Sep 2024 02:00:09 -0500 Subject: [PATCH 06/49] Removed non-required PTRACE defs --- lldb/include/lldb/Host/aix/Ptrace.h | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/lldb/include/lldb/Host/aix/Ptrace.h b/lldb/include/lldb/Host/aix/Ptrace.h index 88928f18102d7..393928a89add3 100644 --- a/lldb/include/lldb/Host/aix/Ptrace.h +++ b/lldb/include/lldb/Host/aix/Ptrace.h @@ -34,29 +34,11 @@ #ifndef PTRACE_SETREGSET #define PTRACE_SETREGSET 0x4205 #endif -#ifndef PTRACE_GET_THREAD_AREA -#define PTRACE_GET_THREAD_AREA (PT_COMMAND_MAX+5) -#endif -#ifndef PTRACE_ARCH_PRCTL -#define PTRACE_ARCH_PRCTL (PT_COMMAND_MAX+6) -#endif -#ifndef ARCH_GET_FS -#define ARCH_SET_GS 0x1001 -#define ARCH_SET_FS 0x1002 -#define ARCH_GET_FS 0x1003 -#define ARCH_GET_GS 0x1004 -#endif -#ifndef PTRACE_PEEKMTETAGS -#define PTRACE_PEEKMTETAGS (PT_COMMAND_MAX+7) -#endif -#ifndef PTRACE_POKEMTETAGS -#define PTRACE_POKEMTETAGS (PT_COMMAND_MAX+8) -#endif #ifndef PTRACE_GETVRREGS -#define PTRACE_GETVRREGS (PT_COMMAND_MAX+9) +#define PTRACE_GETVRREGS (PT_COMMAND_MAX+5) #endif #ifndef PTRACE_GETVSRREGS -#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+10) +#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+6) #endif #endif // liblldb_Host_aix_Ptrace_h_ >From 450793d7270999ecdd6714c4222663517dab3928 Mon Sep 17 00:00:00 2001 From: Lakshmi Surekha Kovvuri Date: Wed, 11 Sep 2024 02:52:41 -0500 Subject: [PATCH 07/49] Patch for running of unit testcases without hang --- lldb/unittests/Host/MainLoopTest.cpp | 4 +++- lldb/unittests/Host/PipeTest.cpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lldb/unittests/Host/MainLoopTest.cpp b/lldb/unittests/Host/MainLoopTest.cpp index 4084e90782fd5..9e92ec1470d4d 100644 --- a/lldb/unittests/Host/MainLoopTest.cpp +++ b/lldb/unittests/Host/MainLoopTest.cpp @@ -183,7 +183,7 @@ TEST_F(MainLoopTest, PendingCallbackAfterLoopExited) { loop.AddPendingCallback([&](MainLoopBase &loop) {}); } -#ifdef LLVM_ON_UNIX +#if defined(LLVM_ON_UNIX) && !defined(__AIX__) TEST_F(MainLoopTest, DetectsEOF) { PseudoTerminal term; @@ -202,7 +202,9 @@ TEST_F(MainLoopTest, DetectsEOF) { ASSERT_TRUE(loop.Run().Success()); ASSERT_EQ(1u, callback_count); } +// #endif +// #ifdef LLVM_ON_UNIX TEST_F(MainLoopTest, Signal) { MainLoop loop; Status error; diff --git a/lldb/unittests/Host/PipeTest.cpp b/lldb/unittests/Host/PipeTest.cpp index 506f3d225a21e..c1013aa7a7e4e 100644 --- a/lldb/unittests/Host/PipeTest.cpp +++ b/lldb/unittests/Host/PipeTest.cpp @@ -55,6 +55,7 @@ TEST_F(PipeTest, OpenAsReader) { } #endif +#if !defined(__AIX__) TEST_F(PipeTest, WriteWithTimeout) { Pipe pipe; ASSERT_THAT_ERROR(pipe.CreateNew(false).ToError(), llvm::Succeeded()); @@ -150,3 +151,4 @@ TEST_F(PipeTest, WriteWithTimeout) { .ToError(), llvm::Succeeded()); } +#endif >From 61e7843b431ff3657e3c4b39d1559401ff3de891 Mon Sep 17 00:00:00 2001 From: Lakshmi Surekha Kovvuri Date: Thu, 12 Sep 2024 13:22:03 -0500 Subject: [PATCH 08/49] changes applied to NativeProcessAIX.cpp file to solve build errors while making LLDB up to date --- .../Plugins/Process/AIX/NativeProcessAIX.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp index 5b01a66b0453f..fc84763857453 100644 --- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -862,7 +862,7 @@ Status NativeProcessAIX::Detach() { Status e = Detach(thread->GetID()); if (e.Fail()) error = - e; // Save the error, but still attempt to detach from other threads. + e.Clone(); // Save the error, but still attempt to detach from other threads. } return error; @@ -1240,7 +1240,7 @@ Status NativeProcessAIX::ReadMemoryTags(int32_t type, lldb::addr_t addr, llvm::Expected details = GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); if (!details) - return Status(details.takeError()); + return Status::FromError(details.takeError()); // Ignore 0 length read if (!len) @@ -1295,7 +1295,7 @@ Status NativeProcessAIX::WriteMemoryTags(int32_t type, lldb::addr_t addr, llvm::Expected details = GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); if (!details) - return Status(details.takeError()); + return Status::FromError(details.takeError()); // Ignore 0 length write if (!len) @@ -1312,18 +1312,18 @@ Status NativeProcessAIX::WriteMemoryTags(int32_t type, lldb::addr_t addr, llvm::Expected> unpacked_tags_or_err = details->manager->UnpackTagsData(tags); if (!unpacked_tags_or_err) - return Status(unpacked_tags_or_err.takeError()); + return Status::FromError(unpacked_tags_or_err.takeError()); llvm::Expected> repeated_tags_or_err = details->manager->RepeatTagsForRange(*unpacked_tags_or_err, range); if (!repeated_tags_or_err) - return Status(repeated_tags_or_err.takeError()); + return Status::FromError(repeated_tags_or_err.takeError()); // Repack them for ptrace to use llvm::Expected> final_tag_data = details->manager->PackTags(*repeated_tags_or_err); if (!final_tag_data) - return Status(final_tag_data.takeError()); + return Status::FromError(final_tag_data.takeError()); struct iovec tags_vec; uint8_t *src = final_tag_data->data(); @@ -1609,13 +1609,13 @@ Status NativeProcessAIX::ResumeThread(NativeThreadAIX &thread, // reflect it is running after this completes. switch (state) { case eStateRunning: { - const auto resume_result = thread.Resume(signo); + Status resume_result = thread.Resume(signo); if (resume_result.Success()) SetState(eStateRunning, true); return resume_result; } case eStateStepping: { - const auto step_result = thread.SingleStep(signo); + Status step_result = thread.SingleStep(signo); if (step_result.Success()) SetState(eStateRunning, true); return step_result; >From 627a5427daba3fc5ea03ae481874f4aa1b4d2ed0 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Fri, 13 Sep 2024 16:25:47 +0530 Subject: [PATCH 09/49] Revert "Removed non-required PTRACE defs" --- lldb/include/lldb/Host/aix/Ptrace.h | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/lldb/include/lldb/Host/aix/Ptrace.h b/lldb/include/lldb/Host/aix/Ptrace.h index 393928a89add3..88928f18102d7 100644 --- a/lldb/include/lldb/Host/aix/Ptrace.h +++ b/lldb/include/lldb/Host/aix/Ptrace.h @@ -34,11 +34,29 @@ #ifndef PTRACE_SETREGSET #define PTRACE_SETREGSET 0x4205 #endif +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA (PT_COMMAND_MAX+5) +#endif +#ifndef PTRACE_ARCH_PRCTL +#define PTRACE_ARCH_PRCTL (PT_COMMAND_MAX+6) +#endif +#ifndef ARCH_GET_FS +#define ARCH_SET_GS 0x1001 +#define ARCH_SET_FS 0x1002 +#define ARCH_GET_FS 0x1003 +#define ARCH_GET_GS 0x1004 +#endif +#ifndef PTRACE_PEEKMTETAGS +#define PTRACE_PEEKMTETAGS (PT_COMMAND_MAX+7) +#endif +#ifndef PTRACE_POKEMTETAGS +#define PTRACE_POKEMTETAGS (PT_COMMAND_MAX+8) +#endif #ifndef PTRACE_GETVRREGS -#define PTRACE_GETVRREGS (PT_COMMAND_MAX+5) +#define PTRACE_GETVRREGS (PT_COMMAND_MAX+9) #endif #ifndef PTRACE_GETVSRREGS -#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+6) +#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+10) #endif #endif // liblldb_Host_aix_Ptrace_h_ >From ea34b15d8568b4639b4e850ef032e684d82dd971 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Thu, 10 Oct 2024 00:38:18 -0500 Subject: [PATCH 10/49] Replaced __AIX__ with _AIX --- clang/test/SemaCXX/class-layout.cpp | 2 +- lldb/CMakeLists.txt | 2 +- lldb/include/lldb/Host/HostGetOpt.h | 2 +- lldb/include/lldb/Host/HostInfo.h | 2 +- lldb/include/lldb/Host/XML.h | 2 +- lldb/include/lldb/Host/common/GetOptInc.h | 4 ++-- lldb/include/lldb/Target/Process.h | 6 +++--- lldb/include/lldb/Target/RegisterContextUnwind.h | 2 +- lldb/source/Core/Mangled.cpp | 2 +- lldb/source/Core/Section.cpp | 2 +- lldb/source/Host/common/Host.cpp | 4 ++-- lldb/source/Host/common/XML.cpp | 2 +- lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp | 2 +- lldb/source/Host/posix/FileSystemPosix.cpp | 2 +- lldb/source/Host/posix/MainLoopPosix.cpp | 4 ++-- lldb/source/Host/posix/ProcessLauncherPosixFork.cpp | 2 +- lldb/source/Initialization/SystemInitializerCommon.cpp | 4 ++-- lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp | 4 ++-- .../DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 6 +++--- .../Plugins/Instruction/PPC64/EmulateInstructionPPC64.h | 2 +- lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp | 2 +- lldb/source/Plugins/Language/ObjC/Cocoa.cpp | 2 +- .../BSD-Archive/ObjectContainerBSDArchive.cpp | 2 +- .../Big-Archive/ObjectContainerBigArchive.cpp | 2 +- .../Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp | 2 +- lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp | 6 +++--- .../source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp | 6 +++--- lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp | 6 +++--- lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp | 4 ++-- .../Process/gdb-remote/GDBRemoteCommunicationClient.cpp | 4 ++-- .../Process/gdb-remote/GDBRemoteCommunicationClient.h | 4 ++-- .../gdb-remote/GDBRemoteCommunicationServerLLGS.cpp | 4 ++-- .../Plugins/Process/gdb-remote/ProcessGDBRemote.cpp | 4 ++-- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h | 4 ++-- lldb/source/Target/Process.cpp | 4 ++-- lldb/source/Target/RegisterContextUnwind.cpp | 8 ++++---- lldb/source/Target/UnwindLLDB.cpp | 4 ++-- lldb/tools/driver/Driver.cpp | 4 ++-- lldb/tools/lldb-server/SystemInitializerLLGS.cpp | 8 ++++---- lldb/tools/lldb-server/lldb-gdbserver.cpp | 4 ++-- lldb/unittests/Host/MainLoopTest.cpp | 2 +- lldb/unittests/Host/PipeTest.cpp | 2 +- lldb/unittests/Host/posix/TerminalTest.cpp | 4 ++-- 43 files changed, 75 insertions(+), 75 deletions(-) diff --git a/clang/test/SemaCXX/class-layout.cpp b/clang/test/SemaCXX/class-layout.cpp index 22fb34b8419c5..0931d905a9749 100644 --- a/clang/test/SemaCXX/class-layout.cpp +++ b/clang/test/SemaCXX/class-layout.cpp @@ -639,7 +639,7 @@ namespace PR37275 { #pragma pack(pop) } -#endif // !defined(__MVS__) && !defined(__AIX__) +#endif // !defined(__MVS__) && !defined(_AIX) namespace non_pod { struct t1 { diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt index 2e9ae0d0b3221..a4fd8bccf056d 100644 --- a/lldb/CMakeLists.txt +++ b/lldb/CMakeLists.txt @@ -39,7 +39,7 @@ include(LLDBConfig) include(AddLLDB) if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") - add_definitions("-D__AIX__") + add_definitions("-D_AIX") endif() # Define the LLDB_CONFIGURATION_xxx matching the build type. diff --git a/lldb/include/lldb/Host/HostGetOpt.h b/lldb/include/lldb/Host/HostGetOpt.h index f450e561d6afb..b2b436e64a692 100644 --- a/lldb/include/lldb/Host/HostGetOpt.h +++ b/lldb/include/lldb/Host/HostGetOpt.h @@ -9,7 +9,7 @@ #ifndef LLDB_HOST_HOSTGETOPT_H #define LLDB_HOST_HOSTGETOPT_H -#if !defined(_MSC_VER) && !defined(__NetBSD__) && !defined(__AIX__) +#if !defined(_MSC_VER) && !defined(__NetBSD__) && !defined(_AIX) #include #include diff --git a/lldb/include/lldb/Host/HostInfo.h b/lldb/include/lldb/Host/HostInfo.h index 156df8cf6901d..0f7ec0e0aa0d2 100644 --- a/lldb/include/lldb/Host/HostInfo.h +++ b/lldb/include/lldb/Host/HostInfo.h @@ -55,7 +55,7 @@ #elif defined(__APPLE__) #include "lldb/Host/macosx/HostInfoMacOSX.h" #define HOST_INFO_TYPE HostInfoMacOSX -#elif defined(__AIX__) +#elif defined(_AIX) #include "lldb/Host/aix/HostInfoAIX.h" #define HOST_INFO_TYPE HostInfoAIX #else diff --git a/lldb/include/lldb/Host/XML.h b/lldb/include/lldb/Host/XML.h index cf359f7726d5d..483589f1abc75 100644 --- a/lldb/include/lldb/Host/XML.h +++ b/lldb/include/lldb/Host/XML.h @@ -11,7 +11,7 @@ #include "lldb/Host/Config.h" -#if defined(__AIX__) +#if defined(_AIX) //FIXME for AIX #undef LLDB_ENABLE_LIBXML2 #endif diff --git a/lldb/include/lldb/Host/common/GetOptInc.h b/lldb/include/lldb/Host/common/GetOptInc.h index ebb475bfaf6b8..652e6174ff8b6 100644 --- a/lldb/include/lldb/Host/common/GetOptInc.h +++ b/lldb/include/lldb/Host/common/GetOptInc.h @@ -11,11 +11,11 @@ #include "lldb/lldb-defines.h" -#if defined(_MSC_VER) || defined(__AIX__) +#if defined(_MSC_VER) || defined(_AIX) #define REPLACE_GETOPT #define REPLACE_GETOPT_LONG #endif -#if defined(_MSC_VER) || defined(__NetBSD__) || defined(__AIX__) +#if defined(_MSC_VER) || defined(__NetBSD__) || defined(_AIX) #define REPLACE_GETOPT_LONG_ONLY #endif diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index 4a47ffd8d779d..d1527d316d678 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -65,7 +65,7 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/VersionTuple.h" -#if defined(__AIX__) +#if defined(_AIX) struct ld_xinfo; #endif @@ -1884,7 +1884,7 @@ class Process : public std::enable_shared_from_this, Status GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &range_info); -#if defined(__AIX__) +#if defined(_AIX) Status GetLDXINFO(struct ld_xinfo *info_ptr); #endif @@ -2823,7 +2823,7 @@ void PruneThreadPlans(); "Process::DoGetMemoryRegionInfo() not supported"); } -#if defined(__AIX__) +#if defined(_AIX) virtual Status DoGetLDXINFO(struct ld_xinfo *info_ptr) { return Status("Process::DoGetLDXINFO() not supported"); } diff --git a/lldb/include/lldb/Target/RegisterContextUnwind.h b/lldb/include/lldb/Target/RegisterContextUnwind.h index 46c06cb422caf..b6176f8e5727f 100644 --- a/lldb/include/lldb/Target/RegisterContextUnwind.h +++ b/lldb/include/lldb/Target/RegisterContextUnwind.h @@ -67,7 +67,7 @@ class RegisterContextUnwind : public lldb_private::RegisterContext { bool ReadPC(lldb::addr_t &start_pc); -#ifdef __AIX__ +#ifdef _AIX bool ReadLR(lldb::addr_t &lr); #endif diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp index 43c5b043ef7a2..8f2e3562f6577 100644 --- a/lldb/source/Core/Mangled.cpp +++ b/lldb/source/Core/Mangled.cpp @@ -167,7 +167,7 @@ static char *GetItaniumDemangledStr(const char *M) { "Expected demangled_size to return length including trailing null"); } -#if !defined(__AIX__) +#if !defined(_AIX) if (Log *log = GetLog(LLDBLog::Demangle)) { if (demangled_cstr) LLDB_LOGF(log, "demangled itanium: %s -> \"%s\"", M, demangled_cstr); diff --git a/lldb/source/Core/Section.cpp b/lldb/source/Core/Section.cpp index 9ed55853930a6..e0a9f7fcc7135 100644 --- a/lldb/source/Core/Section.cpp +++ b/lldb/source/Core/Section.cpp @@ -263,7 +263,7 @@ bool Section::ResolveContainedAddress(addr_t offset, Address &so_addr, bool Section::ContainsFileAddress(addr_t vm_addr) const { const addr_t file_addr = GetFileAddress(); -#ifdef __AIX__ +#ifdef _AIX if (file_addr == 0) return false; #endif diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 94b1d0fd57d07..dc48cb87b5ce6 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -358,7 +358,7 @@ bool Host::ResolveExecutableInBundle(FileSpec &file) { return false; } #ifndef _WIN32 -#if defined(__AIX__) +#if defined(_AIX) #include extern char **p_xargv; @@ -525,7 +525,7 @@ static int dladdr(const void *ptr, Dl_info *dl) FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSpec module_filespec; #if !defined(__ANDROID__) -#ifdef __AIX__ +#ifdef _AIX if (host_addr == reinterpret_cast(HostInfoBase::ComputeSharedLibraryDirectory)) { // FIXME: AIX dladdr return "lldb" for this case if (p_xargv[0]) { diff --git a/lldb/source/Host/common/XML.cpp b/lldb/source/Host/common/XML.cpp index 62cac78aaac23..fbc409105fe60 100644 --- a/lldb/source/Host/common/XML.cpp +++ b/lldb/source/Host/common/XML.cpp @@ -10,7 +10,7 @@ #include "lldb/Host/XML.h" #include "llvm/ADT/StringExtras.h" -#if defined(__AIX__) +#if defined(_AIX) #undef LLDB_ENABLE_LIBXML2 #endif diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index bd204c812b7e3..09c3fd2af6d3e 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -722,7 +722,7 @@ ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, ConnectionStatus ConnectionFileDescriptor::ConnectFile( llvm::StringRef s, socket_id_callback_type socket_id_callback, Status *error_ptr) { -#if !defined(__AIX__) +#if !defined(_AIX) #if LLDB_ENABLE_POSIX std::string addr_str = s.str(); // file:///PATH diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index 866fd8ac96c7b..21da5612ff6b8 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,7 +11,7 @@ // C includes #include #include -#if !defined(__AIX__) +#if !defined(_AIX) #include #endif #include diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp index d1eba52791a78..015570236b9d3 100644 --- a/lldb/source/Host/posix/MainLoopPosix.cpp +++ b/lldb/source/Host/posix/MainLoopPosix.cpp @@ -179,7 +179,7 @@ Status MainLoopPosix::RunImpl::Poll() { read_fds.push_back(pfd); } -#if defined(__AIX__) +#if defined(_AIX) sigset_t origmask; int timeout; @@ -325,7 +325,7 @@ MainLoopPosix::RegisterSignal(int signo, const Callback &callback, // If we're using kqueue, the signal needs to be unblocked in order to // receive it. If using pselect/ppoll, we need to block it, and later unblock // it as a part of the system call. -#if defined(__AIX__) +#if defined(_AIX) //FIXME: where is signal unblocked? ret = pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, &old_set); #else diff --git a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp index b8a96fbd19f02..f9f99decd39c2 100644 --- a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp +++ b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp @@ -193,7 +193,7 @@ struct ForkLaunchInfo { } // Start tracing this child that is about to exec. -#if !defined(__AIX__) +#if !defined(_AIX) if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1) ExitWithError(error_fd, "ptrace"); #else diff --git a/lldb/source/Initialization/SystemInitializerCommon.cpp b/lldb/source/Initialization/SystemInitializerCommon.cpp index 4b01442a94bac..2e2d622d9981c 100644 --- a/lldb/source/Initialization/SystemInitializerCommon.cpp +++ b/lldb/source/Initialization/SystemInitializerCommon.cpp @@ -19,7 +19,7 @@ #include "lldb/Version/Version.h" #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__OpenBSD__) || defined(__AIX__) + defined(__OpenBSD__) || defined(_AIX) #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" #endif @@ -79,7 +79,7 @@ llvm::Error SystemInitializerCommon::Initialize() { process_gdb_remote::ProcessGDBRemoteLog::Initialize(); #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__OpenBSD__) || defined(__AIX__) + defined(__OpenBSD__) || defined(_AIX) ProcessPOSIXLog::Initialize(); #endif #if defined(_WIN32) diff --git a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp index 88a82f4a0d20c..a3abb15ee625b 100644 --- a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp +++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp @@ -156,7 +156,7 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) return false; -#if defined(__AIX__) +#if defined(_AIX) assert(0); #else // Read TOC pointer value. @@ -279,7 +279,7 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) return false; -#if defined(__AIX__) +#if defined(_AIX) LLDB_LOGF(log, "Writing R2: 0x%" PRIx64, (uint64_t)toc_addr); if (!reg_ctx->WriteRegisterFromUnsigned(r2_reg_info, toc_addr)) return false; diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 62663974134b0..7f3a638d5b028 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -18,7 +18,7 @@ #include "lldb/Target/ThreadPlanStepInstruction.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -160,7 +160,7 @@ void DynamicLoaderAIXDYLD::DidAttach() { auto error = m_process->LoadModules(); LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}"); -#if defined(__AIX__) +#if defined(_AIX) // Get struct ld_xinfo (FIXME) struct ld_xinfo ldinfo[64]; Status status = m_process->GetLDXINFO(&(ldinfo[0])); @@ -221,7 +221,7 @@ void DynamicLoaderAIXDYLD::DidLaunch() { LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}"); } -#if defined(__AIX__) +#if defined(_AIX) // Get struct ld_xinfo (FIXME) struct ld_xinfo ldinfo[64]; Status status = m_process->GetLDXINFO(&(ldinfo[0])); diff --git a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h index 1576c9700e557..d98b2880ca3b4 100644 --- a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h +++ b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h @@ -39,7 +39,7 @@ class EmulateInstructionPPC64 : public EmulateInstruction { return true; case eInstructionTypePCModifying: -#if defined(__AIX__) +#if defined(_AIX) return true; #else return false; diff --git a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp index 690fb0d60a09a..9a52fb2f2adc5 100644 --- a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp +++ b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp @@ -194,7 +194,7 @@ void JITLoaderGDB::SetJITBreakpoint(lldb_private::ModuleList &module_list) { if (jit_addr == LLDB_INVALID_ADDRESS) return; -#if defined(__AIX__) +#if defined(_AIX) return; #endif diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index fb5bc2c58e6fb..71f2b127afb12 100644 --- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -1227,7 +1227,7 @@ bool lldb_private::formatters::ObjCSELSummaryProvider( time_t lldb_private::formatters::GetOSXEpoch() { static time_t epoch = 0; if (!epoch) { -#if !defined(__AIX__) +#if !defined(_AIX) #ifndef _WIN32 tzset(); tm tm_epoch; diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 5ea55772c3aba..4f747ab20c9ef 100644 --- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -8,7 +8,7 @@ #include "ObjectContainerBSDArchive.h" -#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__) +#if defined(_WIN32) || defined(__ANDROID__) || defined(_AIX) // Defines from ar, missing on Windows #define SARMAG 8 #define ARFMAG "`\n" diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp index 050ad73f1d19a..38756a0dd2969 100644 --- a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp @@ -8,7 +8,7 @@ #include "ObjectContainerBigArchive.h" -#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__) +#if defined(_WIN32) || defined(__ANDROID__) || defined(_AIX) // Defines from ar, missing on Windows #define ARMAG "!\n" #define SARMAG 8 diff --git a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp index d8834af2c33ef..9aab76c6c48ba 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp +++ b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp @@ -51,7 +51,7 @@ size_t ObjectFileMinidump::GetModuleSpecifications( const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, lldb_private::ModuleSpecList &specs) { -#if !defined(__AIX__) +#if !defined(_AIX) specs.Clear(); #endif return 0; diff --git a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp index 75cc54e4f0d48..d76d6adb1be2c 100644 --- a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp +++ b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp @@ -117,7 +117,7 @@ size_t ObjectFilePDB::GetModuleSpecifications( llvm::BumpPtrAllocator allocator; std::unique_ptr pdb_file = loadPDBFile(file.GetPath(), allocator); if (!pdb_file){ -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; @@ -127,7 +127,7 @@ size_t ObjectFilePDB::GetModuleSpecifications( auto info_stream = pdb_file->getPDBInfoStream(); if (!info_stream) { llvm::consumeError(info_stream.takeError()); -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; @@ -136,7 +136,7 @@ size_t ObjectFilePDB::GetModuleSpecifications( auto dbi_stream = pdb_file->getPDBDbiStream(); if (!dbi_stream) { llvm::consumeError(dbi_stream.takeError()); -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index 519ce2ca4a0b2..02a86234bd363 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -254,7 +254,7 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( lldb::offset_t length, lldb_private::ModuleSpecList &specs) { const size_t initial_count = specs.GetSize(); if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp)){ -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; @@ -272,7 +272,7 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( if (!binary) { LLDB_LOG_ERROR(log, binary.takeError(), "Failed to create binary for file ({1}): {0}", file); -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; @@ -281,7 +281,7 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( auto *COFFObj = llvm::dyn_cast(binary->get()); if (!COFFObj){ -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp index b6b08b73bec41..5c94477002978 100644 --- a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp +++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp @@ -31,7 +31,7 @@ // Define these constants from AIX mman.h for use when targeting remote aix // systems even when host has different values. -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -80,7 +80,7 @@ void PlatformAIX::Initialize() { PlatformPOSIX::Initialize(); if (g_initialize_count++ == 0) { -#if defined(__AIX__) +#if defined(_AIX) PlatformSP default_platform_sp(new PlatformAIX(true)); default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); Platform::SetHostPlatform(default_platform_sp); @@ -294,7 +294,7 @@ MmapArgList PlatformAIX::GetMmapArgumentList(const ArchSpec &arch, addr_t addr, addr_t length, unsigned prot, unsigned flags, addr_t fd, addr_t offset) { -#if defined(__AIX__) +#if defined(_AIX) unsigned flags_platform = MAP_VARIABLE | MAP_PRIVATE | MAP_ANONYMOUS; #else unsigned flags_platform = 0; diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index db271357d792a..ea758caa653a1 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -46,7 +46,7 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, function_options.include_inlines = false; SymbolContextList sc_list; -#if !defined(__AIX__) +#if !defined(_AIX) process->GetTarget().GetImages().FindFunctions( ConstString("mmap"), eFunctionNameTypeFull, function_options, sc_list); #else @@ -122,7 +122,7 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, MmapArgList args = process->GetTarget().GetPlatform()->GetMmapArgumentList( arch, addr, length, prot_arg, flags, fd, offset); -#if defined(__AIX__) +#if defined(_AIX) lldb::ThreadPlanSP call_plan_sp( new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(), toc_range.GetBaseAddress(), diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 443b7c7b2c7fb..fa0a3b5d4dc38 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -41,7 +41,7 @@ #include "llvm/Config/llvm-config.h" // for LLVM_ENABLE_ZLIB #include "llvm/Support/JSON.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -1715,7 +1715,7 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( return error; } -#if defined(__AIX__) +#if defined(_AIX) Status GDBRemoteCommunicationClient::GetLDXINFO(struct ld_xinfo *info_ptr) { Status error; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 520f37ac56716..1812fc9b7ca65 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -32,7 +32,7 @@ #include "llvm/Support/VersionTuple.h" -#if defined(__AIX__) +#if defined(_AIX) struct ld_xinfo; #endif @@ -200,7 +200,7 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase { Status GetMemoryRegionInfo(lldb::addr_t addr, MemoryRegionInfo &range_info); std::optional GetWatchpointSlotCount(); -#if defined(__AIX__) +#if defined(_AIX) Status GetLDXINFO(struct ld_xinfo *info_ptr); #endif diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 4f1ef0898ba08..27be61a474238 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -48,7 +48,7 @@ #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "lldb/Utility/StringExtractorGDBRemote.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -3011,7 +3011,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qLDXINFO(StringExtractorGDBRemote &pack return SendErrorResponse(0xff); } -#if defined(__AIX__) +#if defined(_AIX) // FIXME: buffer size struct ld_xinfo info[64]; if (ptrace64(PT_LDXINFO, m_current_process->GetID(), (long long)&(info[0]), sizeof(info), nullptr) != 0) { diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index ca381290d0e9f..5b7ce5f1424d9 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -92,7 +92,7 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/raw_ostream.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -2963,7 +2963,7 @@ Status ProcessGDBRemote::DoGetMemoryRegionInfo(addr_t load_addr, return error; } -#if defined(__AIX__) +#if defined(_AIX) Status ProcessGDBRemote::DoGetLDXINFO(struct ld_xinfo *info_ptr) { Status error(m_gdb_comm.GetLDXINFO(info_ptr)); return error; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 82200fbea21cd..2bf3a04d213d4 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -37,7 +37,7 @@ #include "GDBRemoteCommunicationClient.h" #include "GDBRemoteRegisterContext.h" -#if defined(__AIX__) +#if defined(_AIX) struct ld_xinfo; #endif @@ -427,7 +427,7 @@ class ProcessGDBRemote : public Process, Status DoGetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo ®ion_info) override; -#if defined(__AIX__) +#if defined(_AIX) Status DoGetLDXINFO(struct ld_xinfo *info_ptr) override; #endif diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index a9aef7ef21855..e6ae7fc559ef4 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -75,7 +75,7 @@ #include "lldb/Utility/State.h" #include "lldb/Utility/Timer.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -6188,7 +6188,7 @@ Status Process::GetMemoryRegionInfo(lldb::addr_t load_addr, return DoGetMemoryRegionInfo(load_addr, range_info); } -#if defined(__AIX__) +#if defined(_AIX) Status Process::GetLDXINFO(struct ld_xinfo *info_ptr) { return DoGetLDXINFO(info_ptr); } diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index fbdbc8c63a5d0..fdf269a3d3653 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -40,7 +40,7 @@ #include #include -#ifdef __AIX__ +#ifdef _AIX #include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" #endif @@ -1260,7 +1260,7 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( // Answer the question: Where did THIS frame save the CALLER frame ("previous" // frame)'s register value? -#ifdef __AIX__ +#ifdef _AIX extern bool UGLY_HACK_NULL_TOPFRAME; #endif @@ -1525,7 +1525,7 @@ RegisterContextUnwind::SavedLocationForRegister( new_regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterInLiveRegisterContext; new_regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); -#ifdef __AIX__ +#ifdef _AIX if (UGLY_HACK_NULL_TOPFRAME && new_regloc.location.register_number == 0x20) { new_regloc.location.register_number = 0x24; } @@ -2390,7 +2390,7 @@ bool RegisterContextUnwind::ReadPC(addr_t &pc) { } } -#ifdef __AIX__ +#ifdef _AIX bool RegisterContextUnwind::ReadLR(addr_t &lr) { if (!IsValid()) return false; diff --git a/lldb/source/Target/UnwindLLDB.cpp b/lldb/source/Target/UnwindLLDB.cpp index 8edf359cac497..764bea5bf86c6 100644 --- a/lldb/source/Target/UnwindLLDB.cpp +++ b/lldb/source/Target/UnwindLLDB.cpp @@ -68,7 +68,7 @@ uint32_t UnwindLLDB::DoGetFrameCount() { return m_frames.size(); } -#ifdef __AIX__ +#ifdef _AIX bool UGLY_HACK_NULL_TOPFRAME = false; #endif @@ -95,7 +95,7 @@ bool UnwindLLDB::AddFirstFrame() { if (!reg_ctx_sp->ReadPC(first_cursor_sp->start_pc)) goto unwind_done; -#ifdef __AIX__ +#ifdef _AIX lldb::addr_t lr; if (!reg_ctx_sp->ReadLR(lr)) goto unwind_done; diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp index 45837503e8b73..d17ed77485d31 100644 --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -640,7 +640,7 @@ void sigwinch_handler(int signo) { } void sigint_handler(int signo) { -#if defined(_WIN32) || defined(__AIX__) // Restore handler as it is not persistent on Windows +#if defined(_WIN32) || defined(_AIX) // Restore handler as it is not persistent on Windows signal(SIGINT, sigint_handler); #endif static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT; @@ -729,7 +729,7 @@ static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) { int main(int argc, char const *argv[]) { // Editline uses for example iswprint which is dependent on LC_CTYPE. // FIXME: this caused unexpected SIGTRAP on AIX -#ifndef __AIX__ +#ifndef _AIX std::setlocale(LC_ALL, ""); std::setlocale(LC_CTYPE, ""); #endif diff --git a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp index 91bb2083a88b5..52c2eae0c9033 100644 --- a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp +++ b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp @@ -14,7 +14,7 @@ using HostObjectFile = ObjectFileMachO; #elif defined(_WIN32) #include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" using HostObjectFile = ObjectFilePECOFF; -#elif defined(__AIX__) +#elif defined(_AIX) #include "Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h" using HostObjectFile = ObjectFileXCOFF; #else @@ -49,7 +49,7 @@ using HostObjectFile = ObjectFileELF; #include "Plugins/Instruction/MIPS/EmulateInstructionMIPS.h" #endif -#if defined(__AIX__) +#if defined(_AIX) #include "Plugins/Instruction/PPC64/EmulateInstructionPPC64.h" #endif @@ -82,7 +82,7 @@ llvm::Error SystemInitializerLLGS::Initialize() { EmulateInstructionRISCV::Initialize(); #endif -#if defined(__AIX__) +#if defined(_AIX) EmulateInstructionPPC64::Initialize(); #endif @@ -108,7 +108,7 @@ void SystemInitializerLLGS::Terminate() { EmulateInstructionRISCV::Terminate(); #endif -#if defined(__AIX__) +#if defined(_AIX) EmulateInstructionPPC64::Terminate(); #endif diff --git a/lldb/tools/lldb-server/lldb-gdbserver.cpp b/lldb/tools/lldb-server/lldb-gdbserver.cpp index 844a6370bdb2e..dcbb421a73e25 100644 --- a/lldb/tools/lldb-server/lldb-gdbserver.cpp +++ b/lldb/tools/lldb-server/lldb-gdbserver.cpp @@ -45,7 +45,7 @@ #include "Plugins/Process/NetBSD/NativeProcessNetBSD.h" #elif defined(_WIN32) #include "Plugins/Process/Windows/Common/NativeProcessWindows.h" -#elif defined(__AIX__) +#elif defined(_AIX) #include "Plugins/Process/AIX/NativeProcessAIX.h" #endif @@ -72,7 +72,7 @@ typedef process_freebsd::NativeProcessFreeBSD::Manager NativeProcessManager; typedef process_netbsd::NativeProcessNetBSD::Manager NativeProcessManager; #elif defined(_WIN32) typedef NativeProcessWindows::Manager NativeProcessManager; -#elif defined(__AIX__) +#elif defined(_AIX) typedef process_aix::NativeProcessAIX::Manager NativeProcessManager; #else // Dummy implementation to make sure the code compiles diff --git a/lldb/unittests/Host/MainLoopTest.cpp b/lldb/unittests/Host/MainLoopTest.cpp index c76476c947054..5c042261b9ef2 100644 --- a/lldb/unittests/Host/MainLoopTest.cpp +++ b/lldb/unittests/Host/MainLoopTest.cpp @@ -223,7 +223,7 @@ TEST_F(MainLoopTest, PendingCallbackAfterLoopExited) { loop.AddPendingCallback([&](MainLoopBase &loop) {}); } -#if defined(LLVM_ON_UNIX) && !defined(__AIX__) +#if defined(LLVM_ON_UNIX) && !defined(_AIX) TEST_F(MainLoopTest, DetectsEOF) { PseudoTerminal term; diff --git a/lldb/unittests/Host/PipeTest.cpp b/lldb/unittests/Host/PipeTest.cpp index c1013aa7a7e4e..00ffd33d68f7a 100644 --- a/lldb/unittests/Host/PipeTest.cpp +++ b/lldb/unittests/Host/PipeTest.cpp @@ -55,7 +55,7 @@ TEST_F(PipeTest, OpenAsReader) { } #endif -#if !defined(__AIX__) +#if !defined(_AIX) TEST_F(PipeTest, WriteWithTimeout) { Pipe pipe; ASSERT_THAT_ERROR(pipe.CreateNew(false).ToError(), llvm::Succeeded()); diff --git a/lldb/unittests/Host/posix/TerminalTest.cpp b/lldb/unittests/Host/posix/TerminalTest.cpp index f3de92c0852b1..64e6be64db80c 100644 --- a/lldb/unittests/Host/posix/TerminalTest.cpp +++ b/lldb/unittests/Host/posix/TerminalTest.cpp @@ -94,14 +94,14 @@ TEST_F(TerminalTest, SetRaw) { TEST_F(TerminalTest, SetBaudRate) { struct termios terminfo; -#if (defined(__AIX__) && defined(B38400)) || !defined(__AIX__) +#if (defined(_AIX) && defined(B38400)) || !defined(_AIX) ASSERT_THAT_ERROR(m_term.SetBaudRate(38400), llvm::Succeeded()); ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0); EXPECT_EQ(cfgetispeed(&terminfo), static_cast(B38400)); EXPECT_EQ(cfgetospeed(&terminfo), static_cast(B38400)); #endif -#if (defined(__AIX__) && defined(B115200)) || !defined(__AIX__) +#if (defined(_AIX) && defined(B115200)) || !defined(_AIX) ASSERT_THAT_ERROR(m_term.SetBaudRate(115200), llvm::Succeeded()); ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0); EXPECT_EQ(cfgetispeed(&terminfo), static_cast(B115200)); >From a8020a6a8692f059679195ae1a0ef5e0eeee94c8 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Thu, 10 Oct 2024 04:52:08 -0500 Subject: [PATCH 11/49] Removed from lldb/CMakeLists --- lldb/CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt index a4fd8bccf056d..59cdc4593463c 100644 --- a/lldb/CMakeLists.txt +++ b/lldb/CMakeLists.txt @@ -38,10 +38,6 @@ endif() include(LLDBConfig) include(AddLLDB) -if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") - add_definitions("-D_AIX") -endif() - # Define the LLDB_CONFIGURATION_xxx matching the build type. if(uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" ) add_definitions(-DLLDB_CONFIGURATION_DEBUG) >From 7609ad339bfab48412221be54edc2d2d146279c3 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Thu, 14 Nov 2024 13:23:59 -0600 Subject: [PATCH 12/49] Patch for the Merge conflict of xcoff first merge with llvm --- .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 253 +++++++++++++++++- 1 file changed, 252 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index 395a126a01fce..a4d9ea295b4c3 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -188,7 +188,258 @@ bool ObjectFileXCOFF::ParseHeader() { if (module_sp) { std::lock_guard guard(module_sp->GetMutex()); m_sect_headers.clear(); - lldb::offs + lldb::offset_t offset = 0; + + if (ParseXCOFFHeader(m_data, &offset, m_xcoff_header)) { + m_data.SetAddressByteSize(GetAddressByteSize()); + if (m_xcoff_header.auxhdrsize > 0) + ParseXCOFFOptionalHeader(m_data, &offset); + ParseSectionHeaders(offset); + } + return true; + } + + return false; +} + +bool ObjectFileXCOFF::ParseXCOFFHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + xcoff_header_t &xcoff_header) { + //FIXME: data.ValidOffsetForDataOfSize + xcoff_header.magic = data.GetU16(offset_ptr); + xcoff_header.nsects = data.GetU16(offset_ptr); + xcoff_header.modtime = data.GetU32(offset_ptr); + xcoff_header.symoff = data.GetU64(offset_ptr); + xcoff_header.auxhdrsize = data.GetU16(offset_ptr); + xcoff_header.flags = data.GetU16(offset_ptr); + xcoff_header.nsyms = data.GetU32(offset_ptr); + return true; +} + +bool ObjectFileXCOFF::ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr) { + lldb::offset_t init_offset = *offset_ptr; + //FIXME: data.ValidOffsetForDataOfSize + m_xcoff_aux_header.AuxMagic = data.GetU16(offset_ptr); + m_xcoff_aux_header.Version = data.GetU16(offset_ptr); + m_xcoff_aux_header.ReservedForDebugger = data.GetU32(offset_ptr); + m_xcoff_aux_header.TextStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.DataStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.TOCAnchorAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfEntryPoint = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTOC = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfLoader = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.ModuleType = data.GetU16(offset_ptr); + m_xcoff_aux_header.CpuFlag = data.GetU8(offset_ptr); + m_xcoff_aux_header.CpuType = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.DataPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.StackPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.FlagAndTDataAlignment = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.InitDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.BssDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.EntryPointAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxStackSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfTData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.XCOFF64Flag = data.GetU16(offset_ptr); + lldb::offset_t last_offset = *offset_ptr; + if ((last_offset - init_offset) < m_xcoff_header.auxhdrsize) + *offset_ptr += (m_xcoff_header.auxhdrsize - (last_offset - init_offset)); + return true; +} + +bool ObjectFileXCOFF::ParseSectionHeaders( + uint32_t section_header_data_offset) { + const uint32_t nsects = m_xcoff_header.nsects; + m_sect_headers.clear(); + + if (nsects > 0) { + const size_t section_header_byte_size = nsects * m_binary->getSectionHeaderSize(); + lldb_private::DataExtractor section_header_data = + ReadImageData(section_header_data_offset, section_header_byte_size); + + lldb::offset_t offset = 0; + //FIXME: section_header_data.ValidOffsetForDataOfSize + m_sect_headers.resize(nsects); + + for (uint32_t idx = 0; idx < nsects; ++idx) { + const void *name_data = section_header_data.GetData(&offset, 8); + if (name_data) { + memcpy(m_sect_headers[idx].name, name_data, 8); + m_sect_headers[idx].phyaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].vmaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].size = section_header_data.GetU64(&offset); + m_sect_headers[idx].offset = section_header_data.GetU64(&offset); + m_sect_headers[idx].reloff = section_header_data.GetU64(&offset); + m_sect_headers[idx].lineoff = section_header_data.GetU64(&offset); + m_sect_headers[idx].nreloc = section_header_data.GetU32(&offset); + m_sect_headers[idx].nline = section_header_data.GetU32(&offset); + m_sect_headers[idx].flags = section_header_data.GetU32(&offset); + offset += 4; + } else { + offset += (m_binary->getSectionHeaderSize() - 8); + } + } + } + + return !m_sect_headers.empty(); +} + +lldb_private::DataExtractor ObjectFileXCOFF::ReadImageData(uint32_t offset, size_t size) { + if (!size) + return {}; + + if (m_data.ValidOffsetForDataOfSize(offset, size)) + return lldb_private::DataExtractor(m_data, offset, size); + + assert(0); + ProcessSP process_sp(m_process_wp.lock()); + lldb_private::DataExtractor data; + if (process_sp) { + auto data_up = std::make_unique(size, 0); + Status readmem_error; + size_t bytes_read = + process_sp->ReadMemory(offset, data_up->GetBytes(), + data_up->GetByteSize(), readmem_error); + if (bytes_read == size) { + DataBufferSP buffer_sp(data_up.release()); + data.SetData(buffer_sp, 0, buffer_sp->GetByteSize()); + } + } + return data; +} + +bool ObjectFileXCOFF::SetLoadAddress(Target &target, lldb::addr_t value, + bool value_is_offset) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (section_sp && !section_sp->IsThreadSpecific()) { + bool use_offset = false; + if (strcmp(section_sp->GetName().AsCString(), ".text") == 0 || + strcmp(section_sp->GetName().AsCString(), ".data") == 0 || + strcmp(section_sp->GetName().AsCString(), ".bss") == 0) + use_offset = true; + + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, (use_offset ? + (section_sp->GetFileOffset() + value) : (section_sp->GetFileAddress() + value)))) + ++num_loaded_sections; + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (type_id == 1 && section_sp && strcmp(section_sp->GetName().AsCString(), ".text") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileOffset() + value)) + ++num_loaded_sections; + } + } else if (type_id == 2 && section_sp && strcmp(section_sp->GetName().AsCString(), ".data") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileAddress() + value)) + ++num_loaded_sections; + } + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +ByteOrder ObjectFileXCOFF::GetByteOrder() const { + return eByteOrderBig; +} + +bool ObjectFileXCOFF::IsExecutable() const { + return true; +} + +uint32_t ObjectFileXCOFF::GetAddressByteSize() const { + if (m_xcoff_header.magic == XCOFF::XCOFF64) + return 8; + else if (m_xcoff_header.magic == XCOFF::XCOFF32) + return 4; + return 4; +} + +AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) { + return AddressClass::eUnknown; +} + +lldb::SymbolType ObjectFileXCOFF::MapSymbolType(llvm::object::SymbolRef::Type sym_type) { + if (sym_type == llvm::object::SymbolRef::ST_Function) + return lldb::eSymbolTypeCode; + else if (sym_type == llvm::object::SymbolRef::ST_Data) + return lldb::eSymbolTypeData; + return lldb::eSymbolTypeInvalid; +} + +void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) { + SectionList *sect_list = GetSectionList(); + const uint32_t num_syms = m_xcoff_header.nsyms; + uint32_t sidx = 0; + if (num_syms > 0 && m_xcoff_header.symoff > 0) { + const uint32_t symbol_size = XCOFF::SymbolTableEntrySize; + const size_t symbol_data_size = num_syms * symbol_size; + lldb_private::DataExtractor symtab_data = + ReadImageData(m_xcoff_header.symoff, symbol_data_size); + + lldb::offset_t offset = 0; + std::string symbol_name; + Symbol *symbols = lldb_symtab.Resize(num_syms); + llvm::object::symbol_iterator SI = m_binary->symbol_begin(); + for (uint32_t i = 0; i < num_syms; ++i, ++SI) { + xcoff_symbol_t symbol; + const uint32_t symbol_offset = offset; + symbol.value = symtab_data.GetU64(&offset); + symbol.offset = symtab_data.GetU32(&offset); + Expected symbol_name_or_err = m_binary->getStringTableEntry(symbol.offset); + if (!symbol_name_or_err) { + consumeError(symbol_name_or_err.takeError()); + return; + } + StringRef symbol_name_str = symbol_name_or_err.get(); + symbol_name.assign(symbol_name_str.data()); symbol.sect = symtab_data.GetU16(&offset); symbol.type = symtab_data.GetU16(&offset); symbol.storage = symtab_data.GetU8(&offset); >From dd56fce276b60b40e1997292b3f554a20157661a Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 17 Nov 2024 00:15:01 -0600 Subject: [PATCH 13/49] Attach fix for AIX --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 130 ++++++++++++++++++ .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 5 +- 2 files changed, 134 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 7f3a638d5b028..acaa6a72edded 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -18,8 +18,13 @@ #include "lldb/Target/ThreadPlanStepInstruction.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" +#include "llvm/Support/FileSystem.h" #if defined(_AIX) #include +#include +#include +#include +#include #endif /*#include "llvm/ADT/Triple.h" @@ -131,14 +136,139 @@ bool DynamicLoaderAIXDYLD::NotifyBreakpointHit( lldb::user_id_t break_loc_id) { } + +void DynamicLoaderAIXDYLD::ResolveExecutableModule( + lldb::ModuleSP &module_sp) { + Log *log = GetLog(LLDBLog::DynamicLoader); + + if (m_process == nullptr) + return; + + auto &target = m_process->GetTarget(); + const auto platform_sp = target.GetPlatform(); + + ProcessInstanceInfo process_info; + if (!m_process->GetProcessInfo(process_info)) { + LLDB_LOGF(log, + "DynamicLoaderPOSIXDYLD::%s - failed to get process info for " + "pid %" PRIu64, + __FUNCTION__, m_process->GetID()); + return; + } + + char procinfo_path[64], exe_path[PATH_MAX], arg_buffer[8192]; + struct procsinfo64 procs_info; + int32long64_t pid = m_process->GetID(); + std::string proc_file = "/proc/" + std::to_string(pid) + "/psinfo"; + std::string cwd_link = "/proc/" + std::to_string(pid) + "/cwd"; + psinfo_t psinfo; + std::ifstream file(proc_file, std::ios::binary); + if(!file.is_open()) + { + LLDB_LOGF(log, "Error psinfo "); + } + file.read(reinterpret_cast(&psinfo), sizeof(psinfo_t)); + if(!file) + LLDB_LOGF(log, "Error psinfo: Failed to read "); + + std::string relative_path(psinfo.pr_fname); + LLDB_LOGF(log, "relative path %s",relative_path.c_str()); + + char cwd[PATH_MAX]; + char resolved_path[PATH_MAX]; + std::string executable_name; + bool found = 0; + if(readlink(cwd_link.c_str(), cwd, sizeof(cwd)) != -1){ + std::filesystem::path full_path = std::filesystem::path(cwd)/relative_path; + if(realpath(full_path.c_str(), resolved_path)) { + LLDB_LOGF(log, " RESOLVED PATH: %s", resolved_path); + found = 1; + } + else + perror("realpath error");} + + executable_name = resolved_path; + if(found == 0) { + std::string command_line(psinfo.pr_psargs); + LLDB_LOGF(log, "command line %s",command_line.c_str()); + if (!command_line.empty()) { + size_t space1 = command_line.find(' '); + executable_name = command_line.substr(0, space1); + LLDB_LOGF(log, "executable name %s",executable_name.c_str()); + } + } + + LLDB_LOGF(log, "executable name %s",executable_name.c_str()); + /*target.SetExecutableModule(target.GetOrCreateModule(lldb_private::FileSpec(resolved_path), + true),true);*/ + process_info.SetExecutableFile(lldb_private::FileSpec(executable_name), + true); + +/* snprintf(procinfo_path, sizeof(procinfo_path), "/proc/%d/object/a.out", pid); + ssize_t len = readlink(procinfo_path, exe_path, sizeof(exe_path) - 1); + exe_path[len] = '\0'; + int num_procs = getprocs64(&procs_info, sizeof(struct procsinfo64), NULL, 0, + &pid, + 1); + int result = getargs(pid, arg_buffer, sizeof(arg_buffer)); + std::vector args; + char *arg_start = arg_buffer; + while(*arg_start != '\0') { + args.emplace_back(arg_start); + arg_start += strlen(arg_start) + 1; + } + + LLDB_LOGF( + log, "1. DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s" + ", pid: %d, current_path: %s", + __FUNCTION__, m_process->GetID(), + args[0], pid, current_path.c_str()); + LLDB_LOGF( + log, "1. DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s" + "num_procs: %d, pid: %d", + __FUNCTION__, m_process->GetID(), + std::string(procs_info.pi_comm).c_str(), num_procs, pid); + if(num_procs <= 0) + perror("getprocs64 failed"); */ + + LLDB_LOGF( + log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s", + __FUNCTION__, m_process->GetID(), + process_info.GetExecutableFile().GetPath().c_str()); + + ModuleSpec module_spec(process_info.GetExecutableFile(), + process_info.GetArchitecture()); + if (module_sp && module_sp->MatchesModuleSpec(module_spec)) + return; + + const auto executable_search_paths(Target::GetDefaultExecutableSearchPaths()); + auto error = platform_sp->ResolveExecutable( + module_spec, module_sp, + !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr); + if (error.Fail()) { + StreamString stream; + module_spec.Dump(stream); + + LLDB_LOGF(log, + "DynamicLoaderPOSIXDYLD::%s - failed to resolve executable " + "with module spec \"%s\": %s", + __FUNCTION__, stream.GetData(), error.AsCString()); + return; + } + + target.SetExecutableModule(module_sp, eLoadDependentsNo); +} + void DynamicLoaderAIXDYLD::DidAttach() { Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); ModuleSP executable = GetTargetExecutable(); + ResolveExecutableModule(executable); if (!executable.get()) return; + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); // Try to fetch the load address of the file from the process, since there // could be randomization of the load address. diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h index ae4b7aca66dcc..0ffbe688e0069 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -24,7 +24,7 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { static void Initialize(); static void Terminate(); - static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; } + static llvm::StringRef GetPluginNameStatic() { return "aix-dyld"; } static llvm::StringRef GetPluginDescriptionStatic(); static DynamicLoader *CreateInstance(Process *process, bool force); @@ -46,6 +46,9 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { protected: lldb::addr_t GetLoadAddress(lldb::ModuleSP executable); + /// Loads Module from inferior process. + void ResolveExecutableModule(lldb::ModuleSP &module_sp); + private: std::map m_loaded_modules; }; >From 48b8b1b6532181acab0ee1710d5f4ab92903ae78 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 18 Nov 2024 02:56:31 -0600 Subject: [PATCH 14/49] Cleanup --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 65 +++++-------------- 1 file changed, 17 insertions(+), 48 deletions(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index acaa6a72edded..1a98bb9334043 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -156,81 +156,50 @@ void DynamicLoaderAIXDYLD::ResolveExecutableModule( return; } - char procinfo_path[64], exe_path[PATH_MAX], arg_buffer[8192]; - struct procsinfo64 procs_info; int32long64_t pid = m_process->GetID(); + char cwd[PATH_MAX], resolved_path[PATH_MAX]; + std::string executable_name; + bool path_resolved = false; + psinfo_t psinfo; + std::string proc_file = "/proc/" + std::to_string(pid) + "/psinfo"; std::string cwd_link = "/proc/" + std::to_string(pid) + "/cwd"; - psinfo_t psinfo; std::ifstream file(proc_file, std::ios::binary); if(!file.is_open()) - { - LLDB_LOGF(log, "Error psinfo "); - } + LLDB_LOGF(log, "Error: Unable to access process info "); + file.read(reinterpret_cast(&psinfo), sizeof(psinfo_t)); if(!file) - LLDB_LOGF(log, "Error psinfo: Failed to read "); + LLDB_LOGF(log, "Process info error: Failed to read "); std::string relative_path(psinfo.pr_fname); - LLDB_LOGF(log, "relative path %s",relative_path.c_str()); + LLDB_LOGF(log, "Relative path %s",relative_path.c_str()); - char cwd[PATH_MAX]; - char resolved_path[PATH_MAX]; - std::string executable_name; - bool found = 0; if(readlink(cwd_link.c_str(), cwd, sizeof(cwd)) != -1){ std::filesystem::path full_path = std::filesystem::path(cwd)/relative_path; if(realpath(full_path.c_str(), resolved_path)) { - LLDB_LOGF(log, " RESOLVED PATH: %s", resolved_path); - found = 1; + LLDB_LOGF(log, "Resolved Path using process info : %s", resolved_path); + path_resolved = true; } else - perror("realpath error");} + LLDB_LOGF(log, "Realpath error: Unable to resolve. "); + } executable_name = resolved_path; - if(found == 0) { + if(path_resolved == false) { std::string command_line(psinfo.pr_psargs); - LLDB_LOGF(log, "command line %s",command_line.c_str()); + LLDB_LOGF(log, "Command line: %s",command_line.c_str()); if (!command_line.empty()) { size_t space1 = command_line.find(' '); executable_name = command_line.substr(0, space1); - LLDB_LOGF(log, "executable name %s",executable_name.c_str()); + LLDB_LOGF(log, "Resolved path using command line arg %s",executable_name.c_str()); } } - LLDB_LOGF(log, "executable name %s",executable_name.c_str()); - /*target.SetExecutableModule(target.GetOrCreateModule(lldb_private::FileSpec(resolved_path), - true),true);*/ + LLDB_LOGF(log, "Executable Name %s",executable_name.c_str()); process_info.SetExecutableFile(lldb_private::FileSpec(executable_name), true); -/* snprintf(procinfo_path, sizeof(procinfo_path), "/proc/%d/object/a.out", pid); - ssize_t len = readlink(procinfo_path, exe_path, sizeof(exe_path) - 1); - exe_path[len] = '\0'; - int num_procs = getprocs64(&procs_info, sizeof(struct procsinfo64), NULL, 0, - &pid, - 1); - int result = getargs(pid, arg_buffer, sizeof(arg_buffer)); - std::vector args; - char *arg_start = arg_buffer; - while(*arg_start != '\0') { - args.emplace_back(arg_start); - arg_start += strlen(arg_start) + 1; - } - - LLDB_LOGF( - log, "1. DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s" - ", pid: %d, current_path: %s", - __FUNCTION__, m_process->GetID(), - args[0], pid, current_path.c_str()); - LLDB_LOGF( - log, "1. DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s" - "num_procs: %d, pid: %d", - __FUNCTION__, m_process->GetID(), - std::string(procs_info.pi_comm).c_str(), num_procs, pid); - if(num_procs <= 0) - perror("getprocs64 failed"); */ - LLDB_LOGF( log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s", __FUNCTION__, m_process->GetID(), >From d410734184a681b3e95949d3953142995682d7f6 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Tue, 19 Nov 2024 09:44:42 -0600 Subject: [PATCH 15/49] Patch in MainLoopPosix.cpp for runtime issue --- lldb/source/Host/posix/MainLoopPosix.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp index f68268f114075..4c617cdde67ba 100644 --- a/lldb/source/Host/posix/MainLoopPosix.cpp +++ b/lldb/source/Host/posix/MainLoopPosix.cpp @@ -149,7 +149,7 @@ Status MainLoopPosix::RunImpl::Poll() { int timeout; timeout = -1; - pthread_sigmask(SIG_SETMASK, &sigmask, &origmask); + pthread_sigmask(SIG_SETMASK, nullptr, &origmask); int ready = poll(read_fds.data(), read_fds.size(), timeout); pthread_sigmask(SIG_SETMASK, &origmask, nullptr); if (ready == -1 && errno != EINTR) >From 48f39dadbbdb4874fbd9b6350933dc67e8823339 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Thu, 5 Dec 2024 05:13:14 -0600 Subject: [PATCH 16/49] Patch for compilation failure in DomainSocket.cpp, AbstractSocket.cpp and AbstractSocket.h --- lldb/include/lldb/Host/aix/AbstractSocket.h | 2 +- lldb/source/Host/aix/AbstractSocket.cpp | 3 +-- lldb/source/Host/posix/DomainSocket.cpp | 4 ++++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lldb/include/lldb/Host/aix/AbstractSocket.h b/lldb/include/lldb/Host/aix/AbstractSocket.h index 78a567a6b9095..accfd01457a5e 100644 --- a/lldb/include/lldb/Host/aix/AbstractSocket.h +++ b/lldb/include/lldb/Host/aix/AbstractSocket.h @@ -14,7 +14,7 @@ namespace lldb_private { class AbstractSocket : public DomainSocket { public: - AbstractSocket(bool child_processes_inherit); + AbstractSocket(); protected: size_t GetNameOffset() const override; diff --git a/lldb/source/Host/aix/AbstractSocket.cpp b/lldb/source/Host/aix/AbstractSocket.cpp index bfb67d452f7ec..fddf78f54f46d 100644 --- a/lldb/source/Host/aix/AbstractSocket.cpp +++ b/lldb/source/Host/aix/AbstractSocket.cpp @@ -13,8 +13,7 @@ using namespace lldb; using namespace lldb_private; -AbstractSocket::AbstractSocket(bool child_processes_inherit) - : DomainSocket(ProtocolUnixAbstract, child_processes_inherit) {} +AbstractSocket::AbstractSocket() : DomainSocket(ProtocolUnixAbstract) {} size_t AbstractSocket::GetNameOffset() const { return 1; } diff --git a/lldb/source/Host/posix/DomainSocket.cpp b/lldb/source/Host/posix/DomainSocket.cpp index 9a0b385d998bf..6cbffb2d9c4bd 100644 --- a/lldb/source/Host/posix/DomainSocket.cpp +++ b/lldb/source/Host/posix/DomainSocket.cpp @@ -17,6 +17,10 @@ #include #include +#if defined(_AIX) +#include +#endif + using namespace lldb; using namespace lldb_private; >From 97531f7bf6e385f0f51d860c6eea17aeb32f6594 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Thu, 19 Dec 2024 06:38:36 -0600 Subject: [PATCH 17/49] Patch for merge conflict in ObjectFileXCOFF.cpp & ObjectFileXCOFF.h --- .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 253 +++++++++++++++++- 1 file changed, 252 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index 395a126a01fce..a4d9ea295b4c3 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -188,7 +188,258 @@ bool ObjectFileXCOFF::ParseHeader() { if (module_sp) { std::lock_guard guard(module_sp->GetMutex()); m_sect_headers.clear(); - lldb::offs + lldb::offset_t offset = 0; + + if (ParseXCOFFHeader(m_data, &offset, m_xcoff_header)) { + m_data.SetAddressByteSize(GetAddressByteSize()); + if (m_xcoff_header.auxhdrsize > 0) + ParseXCOFFOptionalHeader(m_data, &offset); + ParseSectionHeaders(offset); + } + return true; + } + + return false; +} + +bool ObjectFileXCOFF::ParseXCOFFHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + xcoff_header_t &xcoff_header) { + //FIXME: data.ValidOffsetForDataOfSize + xcoff_header.magic = data.GetU16(offset_ptr); + xcoff_header.nsects = data.GetU16(offset_ptr); + xcoff_header.modtime = data.GetU32(offset_ptr); + xcoff_header.symoff = data.GetU64(offset_ptr); + xcoff_header.auxhdrsize = data.GetU16(offset_ptr); + xcoff_header.flags = data.GetU16(offset_ptr); + xcoff_header.nsyms = data.GetU32(offset_ptr); + return true; +} + +bool ObjectFileXCOFF::ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr) { + lldb::offset_t init_offset = *offset_ptr; + //FIXME: data.ValidOffsetForDataOfSize + m_xcoff_aux_header.AuxMagic = data.GetU16(offset_ptr); + m_xcoff_aux_header.Version = data.GetU16(offset_ptr); + m_xcoff_aux_header.ReservedForDebugger = data.GetU32(offset_ptr); + m_xcoff_aux_header.TextStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.DataStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.TOCAnchorAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfEntryPoint = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTOC = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfLoader = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.ModuleType = data.GetU16(offset_ptr); + m_xcoff_aux_header.CpuFlag = data.GetU8(offset_ptr); + m_xcoff_aux_header.CpuType = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.DataPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.StackPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.FlagAndTDataAlignment = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.InitDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.BssDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.EntryPointAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxStackSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfTData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.XCOFF64Flag = data.GetU16(offset_ptr); + lldb::offset_t last_offset = *offset_ptr; + if ((last_offset - init_offset) < m_xcoff_header.auxhdrsize) + *offset_ptr += (m_xcoff_header.auxhdrsize - (last_offset - init_offset)); + return true; +} + +bool ObjectFileXCOFF::ParseSectionHeaders( + uint32_t section_header_data_offset) { + const uint32_t nsects = m_xcoff_header.nsects; + m_sect_headers.clear(); + + if (nsects > 0) { + const size_t section_header_byte_size = nsects * m_binary->getSectionHeaderSize(); + lldb_private::DataExtractor section_header_data = + ReadImageData(section_header_data_offset, section_header_byte_size); + + lldb::offset_t offset = 0; + //FIXME: section_header_data.ValidOffsetForDataOfSize + m_sect_headers.resize(nsects); + + for (uint32_t idx = 0; idx < nsects; ++idx) { + const void *name_data = section_header_data.GetData(&offset, 8); + if (name_data) { + memcpy(m_sect_headers[idx].name, name_data, 8); + m_sect_headers[idx].phyaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].vmaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].size = section_header_data.GetU64(&offset); + m_sect_headers[idx].offset = section_header_data.GetU64(&offset); + m_sect_headers[idx].reloff = section_header_data.GetU64(&offset); + m_sect_headers[idx].lineoff = section_header_data.GetU64(&offset); + m_sect_headers[idx].nreloc = section_header_data.GetU32(&offset); + m_sect_headers[idx].nline = section_header_data.GetU32(&offset); + m_sect_headers[idx].flags = section_header_data.GetU32(&offset); + offset += 4; + } else { + offset += (m_binary->getSectionHeaderSize() - 8); + } + } + } + + return !m_sect_headers.empty(); +} + +lldb_private::DataExtractor ObjectFileXCOFF::ReadImageData(uint32_t offset, size_t size) { + if (!size) + return {}; + + if (m_data.ValidOffsetForDataOfSize(offset, size)) + return lldb_private::DataExtractor(m_data, offset, size); + + assert(0); + ProcessSP process_sp(m_process_wp.lock()); + lldb_private::DataExtractor data; + if (process_sp) { + auto data_up = std::make_unique(size, 0); + Status readmem_error; + size_t bytes_read = + process_sp->ReadMemory(offset, data_up->GetBytes(), + data_up->GetByteSize(), readmem_error); + if (bytes_read == size) { + DataBufferSP buffer_sp(data_up.release()); + data.SetData(buffer_sp, 0, buffer_sp->GetByteSize()); + } + } + return data; +} + +bool ObjectFileXCOFF::SetLoadAddress(Target &target, lldb::addr_t value, + bool value_is_offset) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (section_sp && !section_sp->IsThreadSpecific()) { + bool use_offset = false; + if (strcmp(section_sp->GetName().AsCString(), ".text") == 0 || + strcmp(section_sp->GetName().AsCString(), ".data") == 0 || + strcmp(section_sp->GetName().AsCString(), ".bss") == 0) + use_offset = true; + + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, (use_offset ? + (section_sp->GetFileOffset() + value) : (section_sp->GetFileAddress() + value)))) + ++num_loaded_sections; + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (type_id == 1 && section_sp && strcmp(section_sp->GetName().AsCString(), ".text") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileOffset() + value)) + ++num_loaded_sections; + } + } else if (type_id == 2 && section_sp && strcmp(section_sp->GetName().AsCString(), ".data") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileAddress() + value)) + ++num_loaded_sections; + } + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +ByteOrder ObjectFileXCOFF::GetByteOrder() const { + return eByteOrderBig; +} + +bool ObjectFileXCOFF::IsExecutable() const { + return true; +} + +uint32_t ObjectFileXCOFF::GetAddressByteSize() const { + if (m_xcoff_header.magic == XCOFF::XCOFF64) + return 8; + else if (m_xcoff_header.magic == XCOFF::XCOFF32) + return 4; + return 4; +} + +AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) { + return AddressClass::eUnknown; +} + +lldb::SymbolType ObjectFileXCOFF::MapSymbolType(llvm::object::SymbolRef::Type sym_type) { + if (sym_type == llvm::object::SymbolRef::ST_Function) + return lldb::eSymbolTypeCode; + else if (sym_type == llvm::object::SymbolRef::ST_Data) + return lldb::eSymbolTypeData; + return lldb::eSymbolTypeInvalid; +} + +void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) { + SectionList *sect_list = GetSectionList(); + const uint32_t num_syms = m_xcoff_header.nsyms; + uint32_t sidx = 0; + if (num_syms > 0 && m_xcoff_header.symoff > 0) { + const uint32_t symbol_size = XCOFF::SymbolTableEntrySize; + const size_t symbol_data_size = num_syms * symbol_size; + lldb_private::DataExtractor symtab_data = + ReadImageData(m_xcoff_header.symoff, symbol_data_size); + + lldb::offset_t offset = 0; + std::string symbol_name; + Symbol *symbols = lldb_symtab.Resize(num_syms); + llvm::object::symbol_iterator SI = m_binary->symbol_begin(); + for (uint32_t i = 0; i < num_syms; ++i, ++SI) { + xcoff_symbol_t symbol; + const uint32_t symbol_offset = offset; + symbol.value = symtab_data.GetU64(&offset); + symbol.offset = symtab_data.GetU32(&offset); + Expected symbol_name_or_err = m_binary->getStringTableEntry(symbol.offset); + if (!symbol_name_or_err) { + consumeError(symbol_name_or_err.takeError()); + return; + } + StringRef symbol_name_str = symbol_name_or_err.get(); + symbol_name.assign(symbol_name_str.data()); symbol.sect = symtab_data.GetU16(&offset); symbol.type = symtab_data.GetU16(&offset); symbol.storage = symtab_data.GetU8(&offset); >From 71d2fcff8975831e7f0a657481220749b0a473dc Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Tue, 24 Dec 2024 02:05:35 -0600 Subject: [PATCH 18/49] Added upcoming clang-format and other merge changes --- .../posix/ConnectionFileDescriptorPosix.cpp | 9 ++-- lldb/source/Host/posix/DomainSocket.cpp | 5 ++- lldb/source/Host/posix/FileSystemPosix.cpp | 2 +- lldb/source/Host/posix/MainLoopPosix.cpp | 43 ++++++++----------- .../Host/posix/ProcessLauncherPosixFork.cpp | 2 +- lldb/source/Plugins/Language/ObjC/Cocoa.cpp | 17 +++----- .../BSD-Archive/ObjectContainerBSDArchive.cpp | 29 +++++++------ lldb/source/Utility/ArchSpec.cpp | 1 - 8 files changed, 49 insertions(+), 59 deletions(-) diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index 32d034e60d26c..e3d1300cf76ed 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -119,8 +119,7 @@ bool ConnectionFileDescriptor::IsConnected() const { ConnectionStatus ConnectionFileDescriptor::Connect(llvm::StringRef path, Status *error_ptr) { - return Connect( - path, [](llvm::StringRef) {}, error_ptr); + return Connect(path, [](llvm::StringRef) {}, error_ptr); } ConnectionStatus @@ -716,8 +715,7 @@ ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, ConnectionStatus ConnectionFileDescriptor::ConnectFile( llvm::StringRef s, socket_id_callback_type socket_id_callback, Status *error_ptr) { -#if !defined(_AIX) -#if LLDB_ENABLE_POSIX +#if LLDB_ENABLE_POSIX && !defined(_AIX) std::string addr_str = s.str(); // file:///PATH int fd = FileSystem::Instance().Open(addr_str.c_str(), O_RDWR); @@ -748,8 +746,7 @@ ConnectionStatus ConnectionFileDescriptor::ConnectFile( m_io_sp = std::make_shared(fd, File::eOpenOptionReadWrite, true); return eConnectionStatusSuccess; -#endif // LLDB_ENABLE_POSIX -#endif +#endif // LLDB_ENABLE_POSIX && !defined(_AIX) llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX"); } diff --git a/lldb/source/Host/posix/DomainSocket.cpp b/lldb/source/Host/posix/DomainSocket.cpp index 6cbffb2d9c4bd..28db5964a5a8a 100644 --- a/lldb/source/Host/posix/DomainSocket.cpp +++ b/lldb/source/Host/posix/DomainSocket.cpp @@ -89,8 +89,9 @@ Status DomainSocket::Connect(llvm::StringRef name) { m_socket = CreateSocket(kDomain, kType, 0, error); if (error.Fail()) return error; - if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(), - (struct sockaddr *)&saddr_un, saddr_un_len) < 0) + if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(), + (struct sockaddr *)&saddr_un, + saddr_un_len) < 0) SetLastError(error); return error; diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index 21da5612ff6b8..1a84f550662d7 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,7 +11,7 @@ // C includes #include #include -#if !defined(_AIX) +#ifndef _AIX #include #endif #include diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp index 125b954023dc0..e4ff928a58962 100644 --- a/lldb/source/Host/posix/MainLoopPosix.cpp +++ b/lldb/source/Host/posix/MainLoopPosix.cpp @@ -99,6 +99,7 @@ class MainLoopPosix::RunImpl { ~RunImpl() = default; Status Poll(); + int StartPoll(std::optional point); void ProcessReadEvents(); private: @@ -159,6 +160,22 @@ MainLoopPosix::RunImpl::RunImpl(MainLoopPosix &loop) : loop(loop) { read_fds.reserve(loop.m_read_fds.size()); } +int MainLoopPosix::RunImpl::StartPoll( + std::optional point) { +#if HAVE_PPOLL + return ppoll(read_fds.data(), read_fds.size(), ToTimeSpec(point), + /*sigmask=*/nullptr); +#else + using namespace std::chrono; + int timeout = -1; + if (point) { + nanoseconds dur = std::max(*point - steady_clock::now(), nanoseconds(0)); + timeout = ceil(dur).count(); + } + return poll(read_fds.data(), read_fds.size(), timeout); +#endif +} + Status MainLoopPosix::RunImpl::Poll() { read_fds.clear(); @@ -169,24 +186,10 @@ Status MainLoopPosix::RunImpl::Poll() { pfd.revents = 0; read_fds.push_back(pfd); } + int ready = StartPoll(loop.GetNextWakeupTime()); -#if defined(_AIX) - sigset_t origmask; - int timeout; - - timeout = -1; - pthread_sigmask(SIG_SETMASK, nullptr, &origmask); - int ready = poll(read_fds.data(), read_fds.size(), timeout); - pthread_sigmask(SIG_SETMASK, &origmask, nullptr); if (ready == -1 && errno != EINTR) return Status(errno, eErrorTypePOSIX); -#else - if (ppoll(read_fds.data(), read_fds.size(), - ToTimeSpec(loop.GetNextWakeupTime()), - /*sigmask=*/nullptr) == -1 && - errno != EINTR) - return Status(errno, eErrorTypePOSIX); -#endif return Status(); } @@ -291,16 +294,6 @@ MainLoopPosix::RegisterSignal(int signo, const Callback &callback, UNUSED_IF_ASSERT_DISABLED(ret); assert(ret == 0 && "sigaction failed"); -#if HAVE_SYS_EVENT_H - struct kevent ev; - EV_SET(&ev, signo, EVFILT_SIGNAL, EV_ADD, 0, 0, 0); - ret = kevent(m_kqueue, &ev, 1, nullptr, 0, nullptr); - assert(ret == 0); -#endif - - // If we're using kqueue, the signal needs to be unblocked in order to - // receive it. If using pselect/ppoll, we need to block it, and later unblock - // it as a part of the system call. ret = pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, &old_set); assert(ret == 0 && "pthread_sigmask failed"); info.was_blocked = sigismember(&old_set, signo); diff --git a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp index 52fc58aa21bf4..7b8b42a4b7fe0 100644 --- a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp +++ b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp @@ -197,7 +197,7 @@ struct ForkLaunchInfo { #else if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1) #endif - ExitWithError(error_fd, "ptrace"); + ExitWithError(error_fd, "ptrace"); } // Execute. We should never return... diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index 1d841a032aa6e..1d79edbede5d6 100644 --- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -31,7 +31,6 @@ #include "llvm/ADT/APInt.h" #include "llvm/ADT/bit.h" - using namespace lldb; using namespace lldb_private; using namespace lldb_private::formatters; @@ -267,21 +266,21 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider( if (class_name == "NSIndexSet" || class_name == "NSMutableIndexSet") { // Foundation version 2000 added a bitmask if the index set fit in 64 bits // and a Tagged Pointer version if the bitmask is small enough to fit in - // the tagged pointer payload. + // the tagged pointer payload. // It also changed the layout (but not the size) of the set descriptor. // First check whether this is a tagged pointer. The bitmask will be in // the payload of the tagged pointer. uint64_t payload; - if (runtime->GetFoundationVersion() >= 2000 - && descriptor->GetTaggedPointerInfo(nullptr, nullptr, &payload)) { + if (runtime->GetFoundationVersion() >= 2000 && + descriptor->GetTaggedPointerInfo(nullptr, nullptr, &payload)) { count = llvm::popcount(payload); break; } // The first 32 bits describe the index set in all cases: Status error; uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory( - valobj_addr + ptr_size, 4, 0, error); + valobj_addr + ptr_size, 4, 0, error); if (error.Fail()) return false; // Now check if the index is held in a bitmask in the object: @@ -292,7 +291,7 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider( if ((mode & 2) == 2) { // The bitfield is a 64 bit uint at the beginning of the data var. uint64_t bitfield = process_sp->ReadUnsignedIntegerFromMemory( - valobj_addr + 2 * ptr_size, 8, 0, error); + valobj_addr + 2 * ptr_size, 8, 0, error); if (error.Fail()) return false; count = llvm::popcount(bitfield); @@ -309,7 +308,7 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider( count = 0; break; } - + if ((mode & 2) == 2) mode = 1; // this means the set only has one range else @@ -1227,8 +1226,7 @@ bool lldb_private::formatters::ObjCSELSummaryProvider( time_t lldb_private::formatters::GetOSXEpoch() { static time_t epoch = 0; if (!epoch) { -#if !defined(_AIX) -#ifndef _WIN32 +#if !defined(_WIN32) && !defined(_AIX) tzset(); tm tm_epoch; tm_epoch.tm_sec = 0; @@ -1241,7 +1239,6 @@ time_t lldb_private::formatters::GetOSXEpoch() { tm_epoch.tm_gmtoff = 0; tm_epoch.tm_zone = nullptr; epoch = timegm(&tm_epoch); -#endif #endif } return epoch; diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 4f747ab20c9ef..b202898ff438a 100644 --- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -81,10 +81,10 @@ size_t ObjectContainerBSDArchive::Archive::ParseObjects() { std::unique_ptr mem_buffer = llvm::MemoryBuffer::getMemBuffer( - llvm::StringRef((const char *)data.GetDataStart(), - data.GetByteSize()), - llvm::StringRef(), - /*RequiresNullTerminator=*/false); + llvm::StringRef((const char *)data.GetDataStart(), + data.GetByteSize()), + llvm::StringRef(), + /*RequiresNullTerminator=*/false); auto exp_ar = llvm::object::Archive::create(mem_buffer->getMemBufferRef()); if (!exp_ar) { @@ -95,7 +95,7 @@ size_t ObjectContainerBSDArchive::Archive::ParseObjects() { llvm::Error iter_err = llvm::Error::success(); Object obj; - for (const auto &child: llvm_archive->children(iter_err)) { + for (const auto &child : llvm_archive->children(iter_err)) { obj.Clear(); auto exp_name = child.getName(); if (exp_name) { @@ -111,7 +111,9 @@ size_t ObjectContainerBSDArchive::Archive::ParseObjects() { obj.modification_time = std::chrono::duration_cast( std::chrono::time_point_cast( - exp_mtime.get()).time_since_epoch()).count(); + exp_mtime.get()) + .time_since_epoch()) + .count(); } else { LLDB_LOG_ERROR(l, exp_mtime.takeError(), "failed to get archive object time: {0}"); @@ -331,21 +333,21 @@ ObjectContainer *ObjectContainerBSDArchive::CreateInstance( ArchiveType ObjectContainerBSDArchive::MagicBytesMatch(const DataExtractor &data) { uint32_t offset = 0; - const char *armag = (const char *)data.PeekData(offset, - sizeof(ar_hdr) + SARMAG); + const char *armag = + (const char *)data.PeekData(offset, sizeof(ar_hdr) + SARMAG); if (armag == nullptr) return ArchiveType::Invalid; ArchiveType result = ArchiveType::Invalid; if (strncmp(armag, ArchiveMagic, SARMAG) == 0) - result = ArchiveType::Archive; + result = ArchiveType::Archive; else if (strncmp(armag, ThinArchiveMagic, SARMAG) == 0) - result = ArchiveType::ThinArchive; + result = ArchiveType::ThinArchive; else - return ArchiveType::Invalid; + return ArchiveType::Invalid; armag += offsetof(struct ar_hdr, ar_fmag) + SARMAG; if (strncmp(armag, ARFMAG, 2) == 0) - return result; + return result; return ArchiveType::Invalid; } @@ -443,7 +445,8 @@ size_t ObjectContainerBSDArchive::GetModuleSpecifications( return 0; const size_t initial_count = specs.GetSize(); - llvm::sys::TimePoint<> file_mod_time = FileSystem::Instance().GetModificationTime(file); + llvm::sys::TimePoint<> file_mod_time = + FileSystem::Instance().GetModificationTime(file); Archive::shared_ptr archive_sp( Archive::FindCachedArchive(file, ArchSpec(), file_mod_time, file_offset)); bool set_archive_arch = false; diff --git a/lldb/source/Utility/ArchSpec.cpp b/lldb/source/Utility/ArchSpec.cpp index ac91183a271cc..85bb85044ec15 100644 --- a/lldb/source/Utility/ArchSpec.cpp +++ b/lldb/source/Utility/ArchSpec.cpp @@ -14,7 +14,6 @@ #include "lldb/lldb-defines.h" #include "llvm/ADT/STLExtras.h" #include "llvm/BinaryFormat/COFF.h" -#include "llvm/BinaryFormat/XCOFF.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/BinaryFormat/XCOFF.h" >From 8fcf69ed77148f8b339b87f75ed97e5ce719b4ba Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Fri, 27 Dec 2024 06:50:27 -0600 Subject: [PATCH 19/49] Some Updates --- lldb/include/lldb/Host/aix/HostInfoAIX.h | 11 +-- lldb/source/Host/aix/HostInfoAIX.cpp | 65 +------------- .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 87 +++++++++---------- .../ObjectFile/XCOFF/ObjectFileXCOFF.h | 11 ++- 4 files changed, 50 insertions(+), 124 deletions(-) diff --git a/lldb/include/lldb/Host/aix/HostInfoAIX.h b/lldb/include/lldb/Host/aix/HostInfoAIX.h index ced4cf34d38a8..ba727e1d5f171 100644 --- a/lldb/include/lldb/Host/aix/HostInfoAIX.h +++ b/lldb/include/lldb/Host/aix/HostInfoAIX.h @@ -6,16 +6,14 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_Host_aix_HostInfoAIX_h_ -#define lldb_Host_aix_HostInfoAIX_h_ +#ifndef LLDB_HOST_AIX_HOSTINFOAIX_H_ +#define LLDB_HOST_AIX_HOSTINFOAIX_H_ #include "lldb/Host/posix/HostInfoPosix.h" #include "lldb/Utility/FileSpec.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/VersionTuple.h" -#include - namespace lldb_private { class HostInfoAIX : public HostInfoPosix { @@ -25,15 +23,10 @@ class HostInfoAIX : public HostInfoPosix { static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr); static void Terminate(); - static llvm::VersionTuple GetOSVersion(); - static std::optional GetOSBuildString(); static llvm::StringRef GetDistributionId(); static FileSpec GetProgramFileSpec(); protected: - static bool ComputeSupportExeDirectory(FileSpec &file_spec); - static bool ComputeSystemPluginsDirectory(FileSpec &file_spec); - static bool ComputeUserPluginsDirectory(FileSpec &file_spec); static void ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64); }; diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp index 8bda09e01741b..ef07b07c8cab2 100644 --- a/lldb/source/Host/aix/HostInfoAIX.cpp +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -29,8 +29,6 @@ namespace { struct HostInfoAIXFields { llvm::once_flag m_distribution_once_flag; std::string m_distribution_id; - llvm::once_flag m_os_version_once_flag; - llvm::VersionTuple m_os_version; }; } // namespace @@ -49,33 +47,6 @@ void HostInfoAIX::Terminate() { HostInfoBase::Terminate(); } -llvm::VersionTuple HostInfoAIX::GetOSVersion() { - assert(g_fields && "Missing call to Initialize?"); - llvm::call_once(g_fields->m_os_version_once_flag, []() { - struct utsname un; - if (uname(&un) != 0) - return; - - llvm::StringRef release = un.release; - // The kernel release string can include a lot of stuff (e.g. - // 4.9.0-6-amd64). We're only interested in the numbered prefix. - release = release.substr(0, release.find_first_not_of("0123456789.")); - g_fields->m_os_version.tryParse(release); - }); - - return g_fields->m_os_version; -} - -std::optional HostInfoAIX::GetOSBuildString() { - struct utsname un; - ::memset(&un, 0, sizeof(utsname)); - - if (uname(&un) < 0) - return std::nullopt; - - return std::string(un.release); -} - llvm::StringRef HostInfoAIX::GetDistributionId() { assert(g_fields && "Missing call to Initialize?"); // Try to run 'lbs_release -i', and use that response for the distribution @@ -122,8 +93,7 @@ llvm::StringRef HostInfoAIX::GetDistributionId() { if (strstr(distribution_id, distributor_id_key)) { // strip newlines std::string id_string(distribution_id + strlen(distributor_id_key)); - id_string.erase(std::remove(id_string.begin(), id_string.end(), '\n'), - id_string.end()); + llvm::erase(id_string, '\n'); // lower case it and convert whitespace to underscores std::transform( @@ -167,42 +137,11 @@ FileSpec HostInfoAIX::GetProgramFileSpec() { return g_program_filespec; } -bool HostInfoAIX::ComputeSupportExeDirectory(FileSpec &file_spec) { - if (HostInfoPosix::ComputeSupportExeDirectory(file_spec) && - file_spec.IsAbsolute() && FileSystem::Instance().Exists(file_spec)) - return true; - file_spec.SetDirectory(GetProgramFileSpec().GetDirectory()); - return !file_spec.GetDirectory().IsEmpty(); -} - -bool HostInfoAIX::ComputeSystemPluginsDirectory(FileSpec &file_spec) { - FileSpec temp_file("/usr/" LLDB_INSTALL_LIBDIR_BASENAME "/lldb/plugins"); - FileSystem::Instance().Resolve(temp_file); - file_spec.SetDirectory(temp_file.GetPath()); - return true; -} - -bool HostInfoAIX::ComputeUserPluginsDirectory(FileSpec &file_spec) { - // XDG Base Directory Specification - // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html If - // XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb. - const char *xdg_data_home = getenv("XDG_DATA_HOME"); - if (xdg_data_home && xdg_data_home[0]) { - std::string user_plugin_dir(xdg_data_home); - user_plugin_dir += "/lldb"; - file_spec.SetDirectory(user_plugin_dir.c_str()); - } else - file_spec.SetDirectory("~/.local/share/lldb"); - return true; -} - void HostInfoAIX::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64) { HostInfoPosix::ComputeHostArchitectureSupport(arch_32, arch_64); - const char *distribution_id = GetDistributionId().data(); - - // On Linux, "unknown" in the vendor slot isn't what we want for the default + // "unknown" in the vendor slot isn't what we want for the default // triple. It's probably an artifact of config.guess. if (arch_32.IsValid()) { if (arch_32.GetTriple().getVendor() == llvm::Triple::UnknownVendor) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index a4d9ea295b4c3..afd8027bab06c 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -1,4 +1,5 @@ -//===-- ObjectFileXCOFF.cpp -------------------------------------------------===// +//===-- ObjectFileXCOFF.cpp +//-------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,13 +8,6 @@ //===----------------------------------------------------------------------===// #include "ObjectFileXCOFF.h" - -#include -#include -#include -#include - -#include "lldb/Utility/FileSpecList.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" @@ -28,6 +22,7 @@ #include "lldb/Target/Target.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/FileSpecList.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RangeMap.h" @@ -38,12 +33,16 @@ #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/Object/XCOFFObjectFile.h" #include "llvm/Object/Decompressor.h" #include "llvm/Support/CRC.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Object/XCOFFObjectFile.h" +#include +#include +#include +#include using namespace llvm; using namespace lldb; @@ -69,21 +68,19 @@ void ObjectFileXCOFF::Terminate() { bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; ObjectFile *ObjectFileXCOFF::CreateInstance(const lldb::ModuleSP &module_sp, - DataBufferSP data_sp, - lldb::offset_t data_offset, - const lldb_private::FileSpec *file, - lldb::offset_t file_offset, - lldb::offset_t length) { + DataBufferSP data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t file_offset, + lldb::offset_t length) { if (!data_sp) { data_sp = MapFileData(*file, length, file_offset); if (!data_sp) return nullptr; data_offset = 0; } - if (!ObjectFileXCOFF::MagicBytesMatch(data_sp, data_offset, length)) return nullptr; - // Update the data to contain the entire file if it doesn't already if (data_sp->GetByteSize() < length) { data_sp = MapFileData(*file, length, file_offset); @@ -114,15 +111,15 @@ bool ObjectFileXCOFF::CreateBinary() { Log *log = GetLog(LLDBLog::Object); - auto binary = llvm::object::XCOFFObjectFile::createObjectFile(llvm::MemoryBufferRef( - toStringRef(m_data.GetData()), m_file.GetFilename().GetStringRef()), - file_magic::xcoff_object_64); + auto binary = llvm::object::ObjectFile::createObjectFile( + llvm::MemoryBufferRef(toStringRef(m_data.GetData()), + m_file.GetFilename().GetStringRef()), + file_magic::xcoff_object_64); if (!binary) { LLDB_LOG_ERROR(log, binary.takeError(), "Failed to create binary for file ({1}): {0}", m_file); return false; } - // Make sure we only handle COFF format. m_binary = llvm::unique_dyn_cast(std::move(*binary)); @@ -132,6 +129,7 @@ bool ObjectFileXCOFF::CreateBinary() { LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}", this, GetModule().get(), GetModule()->GetSpecificationDescription(), m_file.GetPath(), m_binary.get()); + return true; } @@ -148,9 +146,12 @@ size_t ObjectFileXCOFF::GetModuleSpecifications( const size_t initial_count = specs.GetSize(); if (ObjectFileXCOFF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) { - ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + ArchSpec arch_spec = + ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); ModuleSpec spec(file, arch_spec); - spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX); + spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, + LLDB_INVALID_CPUTYPE, + llvm::Triple::AIX); specs.Append(spec); } return specs.GetSize() - initial_count; @@ -158,11 +159,9 @@ size_t ObjectFileXCOFF::GetModuleSpecifications( static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) { switch (magic) { - /* TODO: 32bit not supported yet - case XCOFF::XCOFF32: - return sizeof(struct llvm::object::XCOFFFileHeader32); - */ - + // TODO: 32bit not supported. + // case XCOFF::XCOFF32: + // return sizeof(struct llvm::object::XCOFFFileHeader32); case XCOFF::XCOFF64: return sizeof(struct llvm::object::XCOFFFileHeader64); break; @@ -174,10 +173,12 @@ static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) { } bool ObjectFileXCOFF::MagicBytesMatch(DataBufferSP &data_sp, - lldb::addr_t data_offset, - lldb::addr_t data_length) { - lldb_private::DataExtractor data; + lldb::addr_t data_offset, + lldb::addr_t data_length) { + lldb_private::DataExtractor data; data.SetData(data_sp, data_offset, data_length); + // Need to set this as XCOFF is only compatible with Big Endian + data.SetByteOrder(eByteOrderBig); lldb::offset_t offset = 0; uint16_t magic = data.GetU16(&offset); return XCOFFHeaderSizeFromMagic(magic) != 0; @@ -386,13 +387,10 @@ bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, return changed; } -ByteOrder ObjectFileXCOFF::GetByteOrder() const { - return eByteOrderBig; -} -bool ObjectFileXCOFF::IsExecutable() const { - return true; -} +ByteOrder ObjectFileXCOFF::GetByteOrder() const { return eByteOrderBig; } + +bool ObjectFileXCOFF::IsExecutable() const { return true; } uint32_t ObjectFileXCOFF::GetAddressByteSize() const { if (m_xcoff_header.magic == XCOFF::XCOFF64) @@ -592,13 +590,12 @@ void ObjectFileXCOFF::Dump(Stream *s) { } ArchSpec ObjectFileXCOFF::GetArchitecture() { - ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + ArchSpec arch_spec = + ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); return arch_spec; } -UUID ObjectFileXCOFF::GetUUID() { - return UUID(); -} +UUID ObjectFileXCOFF::GetUUID() { return UUID(); } std::optional ObjectFileXCOFF::GetDebugLink() { return std::nullopt; @@ -724,16 +721,14 @@ lldb_private::Address ObjectFileXCOFF::GetBaseAddress() { } ObjectFile::Type ObjectFileXCOFF::CalculateType() { - if (m_xcoff_header.flags & XCOFF::F_EXEC) + if (m_binary->fileHeader64()->Flags & XCOFF::F_EXEC) return eTypeExecutable; - else if (m_xcoff_header.flags & XCOFF::F_SHROBJ) + else if (m_binary->fileHeader64()->Flags & XCOFF::F_SHROBJ) return eTypeSharedLibrary; return eTypeUnknown; } -ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { - return eStrataUnknown; -} +ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { return eStrataUnknown; } llvm::StringRef ObjectFileXCOFF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const { @@ -752,7 +747,7 @@ ObjectFileXCOFF::GetLoadableData(Target &target) { lldb::WritableDataBufferSP ObjectFileXCOFF::MapFileDataWritable(const FileSpec &file, uint64_t Size, - uint64_t Offset) { + uint64_t Offset) { return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size, Offset); } diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h index 5a12d16886489..f827fca3932f4 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h @@ -1,4 +1,5 @@ -//===-- ObjectFileXCOFF.h --------------------------------------- -*- C++ -*-===// +//===-- ObjectFileXCOFF.h --------------------------------------- -*- C++ +//-*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -9,16 +10,14 @@ #ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H #define LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H -#include - -#include - #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/UUID.h" #include "lldb/lldb-private.h" #include "llvm/Object/XCOFFObjectFile.h" +#include +#include /// \class ObjectFileXCOFF /// Generic XCOFF object file reader. @@ -240,4 +239,4 @@ class ObjectFileXCOFF : public lldb_private::ObjectFile { std::map> m_deps_base_members; }; -#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILE_H >From f8b05dfc9fc75177a63dfa2d6df4a9af143b09b8 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 5 Jan 2025 05:01:47 -0600 Subject: [PATCH 20/49] HostInfoAIX Cleanup --- lldb/include/lldb/Host/aix/HostInfoAIX.h | 4 - lldb/source/Host/aix/HostInfoAIX.cpp | 108 ----------------------- 2 files changed, 112 deletions(-) diff --git a/lldb/include/lldb/Host/aix/HostInfoAIX.h b/lldb/include/lldb/Host/aix/HostInfoAIX.h index ba727e1d5f171..5a52c42fa6199 100644 --- a/lldb/include/lldb/Host/aix/HostInfoAIX.h +++ b/lldb/include/lldb/Host/aix/HostInfoAIX.h @@ -23,12 +23,8 @@ class HostInfoAIX : public HostInfoPosix { static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr); static void Terminate(); - static llvm::StringRef GetDistributionId(); static FileSpec GetProgramFileSpec(); -protected: - static void ComputeHostArchitectureSupport(ArchSpec &arch_32, - ArchSpec &arch_64); }; } diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp index ef07b07c8cab2..2996fcb55f811 100644 --- a/lldb/source/Host/aix/HostInfoAIX.cpp +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -11,117 +11,25 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" - #include "llvm/Support/Threading.h" - #include #include #include #include #include - #include #include using namespace lldb_private; -namespace { -struct HostInfoAIXFields { - llvm::once_flag m_distribution_once_flag; - std::string m_distribution_id; -}; -} // namespace - -static HostInfoAIXFields *g_fields = nullptr; - void HostInfoAIX::Initialize(SharedLibraryDirectoryHelper *helper) { HostInfoPosix::Initialize(helper); - - g_fields = new HostInfoAIXFields(); } void HostInfoAIX::Terminate() { - assert(g_fields && "Missing call to Initialize?"); - delete g_fields; - g_fields = nullptr; HostInfoBase::Terminate(); } -llvm::StringRef HostInfoAIX::GetDistributionId() { - assert(g_fields && "Missing call to Initialize?"); - // Try to run 'lbs_release -i', and use that response for the distribution - // id. - llvm::call_once(g_fields->m_distribution_once_flag, []() { - Log *log = GetLog(LLDBLog::Host); - LLDB_LOGF(log, "attempting to determine AIX distribution..."); - - // check if the lsb_release command exists at one of the following paths - const char *const exe_paths[] = {"/bin/lsb_release", - "/usr/bin/lsb_release"}; - - for (size_t exe_index = 0; - exe_index < sizeof(exe_paths) / sizeof(exe_paths[0]); ++exe_index) { - const char *const get_distribution_info_exe = exe_paths[exe_index]; - if (access(get_distribution_info_exe, F_OK)) { - // this exe doesn't exist, move on to next exe - LLDB_LOGF(log, "executable doesn't exist: %s", - get_distribution_info_exe); - continue; - } - - // execute the distribution-retrieval command, read output - std::string get_distribution_id_command(get_distribution_info_exe); - get_distribution_id_command += " -i"; - - FILE *file = popen(get_distribution_id_command.c_str(), "r"); - if (!file) { - LLDB_LOGF(log, - "failed to run command: \"%s\", cannot retrieve " - "platform information", - get_distribution_id_command.c_str()); - break; - } - - // retrieve the distribution id string. - char distribution_id[256] = {'\0'}; - if (fgets(distribution_id, sizeof(distribution_id) - 1, file) != - nullptr) { - LLDB_LOGF(log, "distribution id command returned \"%s\"", - distribution_id); - - const char *const distributor_id_key = "Distributor ID:\t"; - if (strstr(distribution_id, distributor_id_key)) { - // strip newlines - std::string id_string(distribution_id + strlen(distributor_id_key)); - llvm::erase(id_string, '\n'); - - // lower case it and convert whitespace to underscores - std::transform( - id_string.begin(), id_string.end(), id_string.begin(), - [](char ch) { return tolower(isspace(ch) ? '_' : ch); }); - - g_fields->m_distribution_id = id_string; - LLDB_LOGF(log, "distribution id set to \"%s\"", - g_fields->m_distribution_id.c_str()); - } else { - LLDB_LOGF(log, "failed to find \"%s\" field in \"%s\"", - distributor_id_key, distribution_id); - } - } else { - LLDB_LOGF(log, - "failed to retrieve distribution id, \"%s\" returned no" - " lines", - get_distribution_id_command.c_str()); - } - - // clean up the file - pclose(file); - } - }); - - return g_fields->m_distribution_id; -} - FileSpec HostInfoAIX::GetProgramFileSpec() { static FileSpec g_program_filespec; @@ -136,19 +44,3 @@ FileSpec HostInfoAIX::GetProgramFileSpec() { return g_program_filespec; } - -void HostInfoAIX::ComputeHostArchitectureSupport(ArchSpec &arch_32, - ArchSpec &arch_64) { - HostInfoPosix::ComputeHostArchitectureSupport(arch_32, arch_64); - - // "unknown" in the vendor slot isn't what we want for the default - // triple. It's probably an artifact of config.guess. - if (arch_32.IsValid()) { - if (arch_32.GetTriple().getVendor() == llvm::Triple::UnknownVendor) - arch_32.GetTriple().setVendorName(llvm::StringRef()); - } - if (arch_64.IsValid()) { - if (arch_64.GetTriple().getVendor() == llvm::Triple::UnknownVendor) - arch_64.GetTriple().setVendorName(llvm::StringRef()); - } -} >From 57d080e44e80203a6ab848c362469954a7c9f067 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 5 Jan 2025 05:49:40 -0600 Subject: [PATCH 21/49] Cleanup HostInfoAIX Including the previous commit, Removed: GetDistributionID, ComputeHostArchitectureSupport and Reduced GetProgramFileSpec as it was not needed --- lldb/source/Host/aix/HostInfoAIX.cpp | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp index 2996fcb55f811..d09b9052668af 100644 --- a/lldb/source/Host/aix/HostInfoAIX.cpp +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -26,21 +26,9 @@ void HostInfoAIX::Initialize(SharedLibraryDirectoryHelper *helper) { HostInfoPosix::Initialize(helper); } -void HostInfoAIX::Terminate() { - HostInfoBase::Terminate(); -} +void HostInfoAIX::Terminate() { HostInfoBase::Terminate(); } FileSpec HostInfoAIX::GetProgramFileSpec() { static FileSpec g_program_filespec; - - if (!g_program_filespec) { - char exe_path[PATH_MAX]; - ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); - if (len > 0) { - exe_path[len] = 0; - g_program_filespec.SetFile(exe_path, FileSpec::Style::native); - } - } - return g_program_filespec; } >From 673713a9339de4e4ea395ee2e7f65dc1db43bcf9 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 5 Jan 2025 15:35:23 -0600 Subject: [PATCH 22/49] Removing headers --- lldb/include/lldb/Host/aix/HostInfoAIX.h | 2 -- lldb/source/Host/aix/HostInfoAIX.cpp | 12 ------------ 2 files changed, 14 deletions(-) diff --git a/lldb/include/lldb/Host/aix/HostInfoAIX.h b/lldb/include/lldb/Host/aix/HostInfoAIX.h index 5a52c42fa6199..331a274630850 100644 --- a/lldb/include/lldb/Host/aix/HostInfoAIX.h +++ b/lldb/include/lldb/Host/aix/HostInfoAIX.h @@ -11,8 +11,6 @@ #include "lldb/Host/posix/HostInfoPosix.h" #include "lldb/Utility/FileSpec.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/VersionTuple.h" namespace lldb_private { diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp index d09b9052668af..61b47462dd647 100644 --- a/lldb/source/Host/aix/HostInfoAIX.cpp +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -7,18 +7,6 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/aix/HostInfoAIX.h" -#include "lldb/Host/Config.h" -#include "lldb/Host/FileSystem.h" -#include "lldb/Utility/LLDBLog.h" -#include "lldb/Utility/Log.h" -#include "llvm/Support/Threading.h" -#include -#include -#include -#include -#include -#include -#include using namespace lldb_private; >From cdc31f3963365e4595247ff5a7155662df1ce1af Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 6 Jan 2025 09:28:56 -0600 Subject: [PATCH 23/49] Reverted merge blunder CMakeLists --- lldb/source/Host/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index f326bc07dc1f6..f4fca8acc4d83 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -141,7 +141,10 @@ else() elseif (CMAKE_SYSTEM_NAME MATCHES "AIX") add_host_subdirectory(aix + aix/AbstractSocket.cpp + aix/Host.cpp aix/HostInfoAIX.cpp + aix/Support.cpp ) endif() endif() >From 713a6cbbb97b9bc56b039ab050a1690eccc017e3 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 6 Jan 2025 09:39:36 -0600 Subject: [PATCH 24/49] Removed DomainSocket.cpp FileSystemPosix.cpp includes --- lldb/source/Host/posix/DomainSocket.cpp | 4 ---- lldb/source/Host/posix/FileSystemPosix.cpp | 3 --- 2 files changed, 7 deletions(-) diff --git a/lldb/source/Host/posix/DomainSocket.cpp b/lldb/source/Host/posix/DomainSocket.cpp index f30e84d83efca..be8fcdf2c8f2c 100644 --- a/lldb/source/Host/posix/DomainSocket.cpp +++ b/lldb/source/Host/posix/DomainSocket.cpp @@ -17,10 +17,6 @@ #include #include -#if defined(_AIX) -#include -#endif - using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index 1a84f550662d7..a631bb01209ec 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,9 +11,6 @@ // C includes #include #include -#ifndef _AIX -#include -#endif #include #include #include >From 0a706d29dabeefa62e354fc9358d650f89032048 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 6 Jan 2025 09:44:10 -0600 Subject: [PATCH 25/49] sys/mount.h --- lldb/source/Host/posix/FileSystemPosix.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index a631bb01209ec..945e2affc8371 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,6 +11,7 @@ // C includes #include #include +#include #include #include #include >From 84ebb4ec9b542c38fe1b60261a3253383e9fbf5d Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 6 Jan 2025 09:54:58 -0600 Subject: [PATCH 26/49] sys/mount.h --- lldb/source/Host/posix/FileSystemPosix.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index 945e2affc8371..1a84f550662d7 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,7 +11,9 @@ // C includes #include #include +#ifndef _AIX #include +#endif #include #include #include >From 844f7980040de9e13620e9d65a3fcaef56b6c8d6 Mon Sep 17 00:00:00 2001 From: Dhruv Srivastava Date: Thu, 9 Jan 2025 09:47:43 +0530 Subject: [PATCH 27/49] Removed _AIX from ConnectionFileDescriptorPosix.cpp --- lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index 2530c8fa353ba..0ed2016667162 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -715,7 +715,7 @@ ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, ConnectionStatus ConnectionFileDescriptor::ConnectFile( llvm::StringRef s, socket_id_callback_type socket_id_callback, Status *error_ptr) { -#if LLDB_ENABLE_POSIX && !defined(_AIX) +#if LLDB_ENABLE_POSIX std::string addr_str = s.str(); // file:///PATH int fd = FileSystem::Instance().Open(addr_str.c_str(), O_RDWR); @@ -756,7 +756,7 @@ ConnectionStatus ConnectionFileDescriptor::ConnectFile( m_io_sp = std::make_shared(fd, File::eOpenOptionReadWrite, true); return eConnectionStatusSuccess; -#endif // LLDB_ENABLE_POSIX && !defined(_AIX) +#endif // LLDB_ENABLE_POSIX llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX"); } >From 4fe42cda7c2f4990b18a39c1d6563094fb88775f Mon Sep 17 00:00:00 2001 From: ravindra shinde Date: Fri, 17 Jan 2025 13:58:13 +0530 Subject: [PATCH 28/49] [ObjectFileXCOFF] Fix access to protected member 'GetSectionLoadList' in Target - Added a public method to Target for accessing 'GetSectionLoadList' safely. - Updated ObjectFileXCOFF to use the new public method, ensuring compliance with encapsulation rules. This resolves the build error caused by direct access to the protected member. Signed-off-by: ravindra shinde --- lldb/include/lldb/Target/Target.h | 5 +++++ lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index f31ac381391b4..75f9c9c2e999c 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -522,6 +522,7 @@ class Target : public std::enable_shared_from_this, eBroadcastBitSymbolsChanged = (1 << 5), }; + // These two functions fill out the Broadcaster interface: static llvm::StringRef GetStaticBroadcasterClass(); @@ -1644,6 +1645,10 @@ class Target : public std::enable_shared_from_this, TargetStats &GetStatistics() { return m_stats; } +public: + SectionLoadList &GetSectionLoadListPublic() { + return GetSectionLoadList(); + } protected: /// Construct with optional file and arch. /// diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index afd8027bab06c..cf11e5fb8f5a3 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -340,7 +340,7 @@ bool ObjectFileXCOFF::SetLoadAddress(Target &target, lldb::addr_t value, strcmp(section_sp->GetName().AsCString(), ".bss") == 0) use_offset = true; - if (target.GetSectionLoadList().SetSectionLoadAddress( + if (target.GetSectionLoadListPublic().SetSectionLoadAddress( section_sp, (use_offset ? (section_sp->GetFileOffset() + value) : (section_sp->GetFileAddress() + value)))) ++num_loaded_sections; @@ -369,13 +369,13 @@ bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); if (type_id == 1 && section_sp && strcmp(section_sp->GetName().AsCString(), ".text") == 0) { if (!section_sp->IsThreadSpecific()) { - if (target.GetSectionLoadList().SetSectionLoadAddress( + if (target.GetSectionLoadListPublic().SetSectionLoadAddress( section_sp, section_sp->GetFileOffset() + value)) ++num_loaded_sections; } } else if (type_id == 2 && section_sp && strcmp(section_sp->GetName().AsCString(), ".data") == 0) { if (!section_sp->IsThreadSpecific()) { - if (target.GetSectionLoadList().SetSectionLoadAddress( + if (target.GetSectionLoadListPublic().SetSectionLoadAddress( section_sp, section_sp->GetFileAddress() + value)) ++num_loaded_sections; } >From e5ed4f21c5bbc709e5e2eff0f83995cc6d89de48 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 19 Jan 2025 03:43:11 -0600 Subject: [PATCH 29/49] Resolved cmake failure for SBProgress.cpp --- lldb/source/API/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index eb348e2b97232..0a03e000c0cae 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -85,6 +85,7 @@ add_lldb_library(liblldb STATIC ${option_framework} SBModuleSpec.cpp SBPlatform.cpp SBProcess.cpp + SBProgress.cpp SBProcessInfo.cpp SBProcessInfoList.cpp SBQueue.cpp >From 82dbcb0e776c438e5f40c9f8d8c8e8eb81b7febd Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 27 Jan 2025 06:35:19 -0600 Subject: [PATCH 30/49] Host.cpp ANDROID --- lldb/source/Host/common/Host.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 758e9f49ade2c..adf74df8aa90b 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -1,4 +1,4 @@ -//===-- Host.cpp ----------------------------------------------------------===// + // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -516,7 +516,6 @@ static int dladdr(const void *ptr, Dl_info *dl) FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSpec module_filespec; -#if !defined(__ANDROID__) #ifdef _AIX if (host_addr == reinterpret_cast(HostInfoBase::ComputeSharedLibraryDirectory)) { // FIXME: AIX dladdr return "lldb" for this case @@ -527,6 +526,7 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { } } #endif +#if !defined(__ANDROID__) Dl_info info; if (::dladdr(host_addr, &info)) { if (info.dli_fname) { @@ -534,6 +534,7 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSystem::Instance().Resolve(module_filespec); } } +#endif return module_filespec; } >From 60294eaa1611632afc94b9da503752e34ad2703d Mon Sep 17 00:00:00 2001 From: Ravindra Shinde Date: Tue, 4 Feb 2025 03:23:56 -0600 Subject: [PATCH 31/49] Resolving the fatal error while build Build is failing due to the fatal error: 'sys/syscall.h' file not found Signed-off-by: Ravindra Shinde --- lldb/source/Host/common/Host.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 40ce76d70d6e8..b5bd68b8539bd 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -18,8 +18,12 @@ #include #include #include + +#ifndef _AIX #include #include +#endif + #include #include #endif >From 2644be59b13a61c69cc635875c94b0b4645fe76c Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 10 Feb 2025 01:49:12 -0600 Subject: [PATCH 32/49] InferiorCallPOSIX.cpp --- lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index d1f9fe851119e..8e74cce097894 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -120,12 +120,13 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, arch, addr, length, prot_arg, flags, fd, offset); #if defined(_AIX) lldb::ThreadPlanSP call_plan_sp( - new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(), + new ThreadPlanCallFunction(*thread, mmap_addr, toc_range.GetBaseAddress(), void_ptr_type, args, options)); #else lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallFunction( *thread, mmap_addr, void_ptr_type, args, options)); +#endif if (call_plan_sp) { DiagnosticManager diagnostics; >From 4805b13cba964b58def39a66ad4c4309a9b2c501 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 12 Feb 2025 07:33:04 -0600 Subject: [PATCH 33/49] Merge branch gh-101657 --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 97 ------------------- .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 5 +- 2 files changed, 1 insertion(+), 101 deletions(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 1a98bb9334043..375d879c7a995 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -21,10 +21,6 @@ #include "llvm/Support/FileSystem.h" #if defined(_AIX) #include -#include -#include -#include -#include #endif /*#include "llvm/ADT/Triple.h" @@ -137,107 +133,14 @@ bool DynamicLoaderAIXDYLD::NotifyBreakpointHit( } -void DynamicLoaderAIXDYLD::ResolveExecutableModule( - lldb::ModuleSP &module_sp) { - Log *log = GetLog(LLDBLog::DynamicLoader); - - if (m_process == nullptr) - return; - - auto &target = m_process->GetTarget(); - const auto platform_sp = target.GetPlatform(); - - ProcessInstanceInfo process_info; - if (!m_process->GetProcessInfo(process_info)) { - LLDB_LOGF(log, - "DynamicLoaderPOSIXDYLD::%s - failed to get process info for " - "pid %" PRIu64, - __FUNCTION__, m_process->GetID()); - return; - } - - int32long64_t pid = m_process->GetID(); - char cwd[PATH_MAX], resolved_path[PATH_MAX]; - std::string executable_name; - bool path_resolved = false; - psinfo_t psinfo; - - std::string proc_file = "/proc/" + std::to_string(pid) + "/psinfo"; - std::string cwd_link = "/proc/" + std::to_string(pid) + "/cwd"; - std::ifstream file(proc_file, std::ios::binary); - if(!file.is_open()) - LLDB_LOGF(log, "Error: Unable to access process info "); - - file.read(reinterpret_cast(&psinfo), sizeof(psinfo_t)); - if(!file) - LLDB_LOGF(log, "Process info error: Failed to read "); - - std::string relative_path(psinfo.pr_fname); - LLDB_LOGF(log, "Relative path %s",relative_path.c_str()); - - if(readlink(cwd_link.c_str(), cwd, sizeof(cwd)) != -1){ - std::filesystem::path full_path = std::filesystem::path(cwd)/relative_path; - if(realpath(full_path.c_str(), resolved_path)) { - LLDB_LOGF(log, "Resolved Path using process info : %s", resolved_path); - path_resolved = true; - } - else - LLDB_LOGF(log, "Realpath error: Unable to resolve. "); - } - - executable_name = resolved_path; - if(path_resolved == false) { - std::string command_line(psinfo.pr_psargs); - LLDB_LOGF(log, "Command line: %s",command_line.c_str()); - if (!command_line.empty()) { - size_t space1 = command_line.find(' '); - executable_name = command_line.substr(0, space1); - LLDB_LOGF(log, "Resolved path using command line arg %s",executable_name.c_str()); - } - } - - LLDB_LOGF(log, "Executable Name %s",executable_name.c_str()); - process_info.SetExecutableFile(lldb_private::FileSpec(executable_name), - true); - - LLDB_LOGF( - log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s", - __FUNCTION__, m_process->GetID(), - process_info.GetExecutableFile().GetPath().c_str()); - - ModuleSpec module_spec(process_info.GetExecutableFile(), - process_info.GetArchitecture()); - if (module_sp && module_sp->MatchesModuleSpec(module_spec)) - return; - - const auto executable_search_paths(Target::GetDefaultExecutableSearchPaths()); - auto error = platform_sp->ResolveExecutable( - module_spec, module_sp, - !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr); - if (error.Fail()) { - StreamString stream; - module_spec.Dump(stream); - - LLDB_LOGF(log, - "DynamicLoaderPOSIXDYLD::%s - failed to resolve executable " - "with module spec \"%s\": %s", - __FUNCTION__, stream.GetData(), error.AsCString()); - return; - } - - target.SetExecutableModule(module_sp, eLoadDependentsNo); -} - void DynamicLoaderAIXDYLD::DidAttach() { Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); ModuleSP executable = GetTargetExecutable(); - ResolveExecutableModule(executable); if (!executable.get()) return; - LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); // Try to fetch the load address of the file from the process, since there // could be randomization of the load address. diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h index 0ffbe688e0069..ae4b7aca66dcc 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -24,7 +24,7 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { static void Initialize(); static void Terminate(); - static llvm::StringRef GetPluginNameStatic() { return "aix-dyld"; } + static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; } static llvm::StringRef GetPluginDescriptionStatic(); static DynamicLoader *CreateInstance(Process *process, bool force); @@ -46,9 +46,6 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { protected: lldb::addr_t GetLoadAddress(lldb::ModuleSP executable); - /// Loads Module from inferior process. - void ResolveExecutableModule(lldb::ModuleSP &module_sp); - private: std::map m_loaded_modules; }; >From cff574b36903e12385e5d6cddf4532ba279f47de Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 12 Feb 2025 07:52:04 -0600 Subject: [PATCH 34/49] Fix for Debugging Attach to AIX Process --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 97 +++++++++++++++++++ .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 5 +- 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 375d879c7a995..1a98bb9334043 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -21,6 +21,10 @@ #include "llvm/Support/FileSystem.h" #if defined(_AIX) #include +#include +#include +#include +#include #endif /*#include "llvm/ADT/Triple.h" @@ -133,14 +137,107 @@ bool DynamicLoaderAIXDYLD::NotifyBreakpointHit( } +void DynamicLoaderAIXDYLD::ResolveExecutableModule( + lldb::ModuleSP &module_sp) { + Log *log = GetLog(LLDBLog::DynamicLoader); + + if (m_process == nullptr) + return; + + auto &target = m_process->GetTarget(); + const auto platform_sp = target.GetPlatform(); + + ProcessInstanceInfo process_info; + if (!m_process->GetProcessInfo(process_info)) { + LLDB_LOGF(log, + "DynamicLoaderPOSIXDYLD::%s - failed to get process info for " + "pid %" PRIu64, + __FUNCTION__, m_process->GetID()); + return; + } + + int32long64_t pid = m_process->GetID(); + char cwd[PATH_MAX], resolved_path[PATH_MAX]; + std::string executable_name; + bool path_resolved = false; + psinfo_t psinfo; + + std::string proc_file = "/proc/" + std::to_string(pid) + "/psinfo"; + std::string cwd_link = "/proc/" + std::to_string(pid) + "/cwd"; + std::ifstream file(proc_file, std::ios::binary); + if(!file.is_open()) + LLDB_LOGF(log, "Error: Unable to access process info "); + + file.read(reinterpret_cast(&psinfo), sizeof(psinfo_t)); + if(!file) + LLDB_LOGF(log, "Process info error: Failed to read "); + + std::string relative_path(psinfo.pr_fname); + LLDB_LOGF(log, "Relative path %s",relative_path.c_str()); + + if(readlink(cwd_link.c_str(), cwd, sizeof(cwd)) != -1){ + std::filesystem::path full_path = std::filesystem::path(cwd)/relative_path; + if(realpath(full_path.c_str(), resolved_path)) { + LLDB_LOGF(log, "Resolved Path using process info : %s", resolved_path); + path_resolved = true; + } + else + LLDB_LOGF(log, "Realpath error: Unable to resolve. "); + } + + executable_name = resolved_path; + if(path_resolved == false) { + std::string command_line(psinfo.pr_psargs); + LLDB_LOGF(log, "Command line: %s",command_line.c_str()); + if (!command_line.empty()) { + size_t space1 = command_line.find(' '); + executable_name = command_line.substr(0, space1); + LLDB_LOGF(log, "Resolved path using command line arg %s",executable_name.c_str()); + } + } + + LLDB_LOGF(log, "Executable Name %s",executable_name.c_str()); + process_info.SetExecutableFile(lldb_private::FileSpec(executable_name), + true); + + LLDB_LOGF( + log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s", + __FUNCTION__, m_process->GetID(), + process_info.GetExecutableFile().GetPath().c_str()); + + ModuleSpec module_spec(process_info.GetExecutableFile(), + process_info.GetArchitecture()); + if (module_sp && module_sp->MatchesModuleSpec(module_spec)) + return; + + const auto executable_search_paths(Target::GetDefaultExecutableSearchPaths()); + auto error = platform_sp->ResolveExecutable( + module_spec, module_sp, + !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr); + if (error.Fail()) { + StreamString stream; + module_spec.Dump(stream); + + LLDB_LOGF(log, + "DynamicLoaderPOSIXDYLD::%s - failed to resolve executable " + "with module spec \"%s\": %s", + __FUNCTION__, stream.GetData(), error.AsCString()); + return; + } + + target.SetExecutableModule(module_sp, eLoadDependentsNo); +} + void DynamicLoaderAIXDYLD::DidAttach() { Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); ModuleSP executable = GetTargetExecutable(); + ResolveExecutableModule(executable); if (!executable.get()) return; + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); // Try to fetch the load address of the file from the process, since there // could be randomization of the load address. diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h index ae4b7aca66dcc..0ffbe688e0069 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -24,7 +24,7 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { static void Initialize(); static void Terminate(); - static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; } + static llvm::StringRef GetPluginNameStatic() { return "aix-dyld"; } static llvm::StringRef GetPluginDescriptionStatic(); static DynamicLoader *CreateInstance(Process *process, bool force); @@ -46,6 +46,9 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { protected: lldb::addr_t GetLoadAddress(lldb::ModuleSP executable); + /// Loads Module from inferior process. + void ResolveExecutableModule(lldb::ModuleSP &module_sp); + private: std::map m_loaded_modules; }; >From 303fa3bc078d7572702fb302726d4dd1bd13ddb2 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Fri, 21 Feb 2025 06:18:33 -0600 Subject: [PATCH 35/49] Merge branch 'llvm:main' into gh-101657 --- lldb/source/Plugins/Platform/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/lldb/source/Plugins/Platform/CMakeLists.txt b/lldb/source/Plugins/Platform/CMakeLists.txt index f5b0dbdd5e0a9..0220e734b36d1 100644 --- a/lldb/source/Plugins/Platform/CMakeLists.txt +++ b/lldb/source/Plugins/Platform/CMakeLists.txt @@ -9,4 +9,3 @@ add_subdirectory(OpenBSD) add_subdirectory(POSIX) add_subdirectory(QemuUser) add_subdirectory(Windows) -add_subdirectory(AIX) >From 6947dec02bb527f710c1bea3827b2c16d89f308a Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Fri, 21 Feb 2025 07:02:53 -0600 Subject: [PATCH 36/49] Merge branch 'llvm:main' into gh-101657 --- .../Plugins/Platform/AIX/PlatformAIX.cpp | 171 +----------------- 1 file changed, 1 insertion(+), 170 deletions(-) diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp index 0d66325d16267..21724d83133e9 100644 --- a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp +++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp @@ -130,12 +130,6 @@ void PlatformAIX::GetStatus(Stream &strm) { #endif } -void PlatformAIX::CalculateTrapHandlerSymbolNames() { - m_trap_handlers.push_back(ConstString("_sigtramp")); - m_trap_handlers.push_back(ConstString("__kernel_rt_sigreturn")); - m_trap_handlers.push_back(ConstString("__restore_rt")); -} - void PlatformAIX::CalculateTrapHandlerSymbolNames() {} lldb::UnwindPlanSP @@ -160,168 +154,5 @@ MmapArgList PlatformAIX::GetMmapArgumentList(const ArchSpec &arch, addr_t addr, } CompilerType PlatformAIX::GetSiginfoType(const llvm::Triple &triple) { - if (!m_type_system_up) - m_type_system_up.reset(new TypeSystemClang("siginfo", triple)); - TypeSystemClang *ast = m_type_system_up.get(); - - bool si_errno_then_code = true; - - switch (triple.getArch()) { - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - // mips has si_code and si_errno swapped - si_errno_then_code = false; - break; - default: - break; - } - - // generic types - CompilerType int_type = ast->GetBasicType(eBasicTypeInt); - CompilerType uint_type = ast->GetBasicType(eBasicTypeUnsignedInt); - CompilerType short_type = ast->GetBasicType(eBasicTypeShort); - CompilerType long_type = ast->GetBasicType(eBasicTypeLong); - CompilerType voidp_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); - - // platform-specific types - CompilerType &pid_type = int_type; - CompilerType &uid_type = uint_type; - CompilerType &clock_type = long_type; - CompilerType &band_type = long_type; - - CompilerType sigval_type = ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_sigval_t", - llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); - ast->StartTagDeclarationDefinition(sigval_type); - ast->AddFieldToRecordType(sigval_type, "sival_int", int_type, - lldb::eAccessPublic, 0); - ast->AddFieldToRecordType(sigval_type, "sival_ptr", voidp_type, - lldb::eAccessPublic, 0); - ast->CompleteTagDeclarationDefinition(sigval_type); - - CompilerType sigfault_bounds_type = ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", - llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); - ast->StartTagDeclarationDefinition(sigfault_bounds_type); - ast->AddFieldToRecordType(sigfault_bounds_type, "_addr_bnd", - ast->CreateStructForIdentifier(ConstString(), - { - {"_lower", voidp_type}, - {"_upper", voidp_type}, - }), - lldb::eAccessPublic, 0); - ast->AddFieldToRecordType(sigfault_bounds_type, "_pkey", uint_type, - lldb::eAccessPublic, 0); - ast->CompleteTagDeclarationDefinition(sigfault_bounds_type); - - // siginfo_t - CompilerType siginfo_type = ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_siginfo_t", - llvm::to_underlying(clang::TagTypeKind::Struct), lldb::eLanguageTypeC); - ast->StartTagDeclarationDefinition(siginfo_type); - ast->AddFieldToRecordType(siginfo_type, "si_signo", int_type, - lldb::eAccessPublic, 0); - - if (si_errno_then_code) { - ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type, - lldb::eAccessPublic, 0); - ast->AddFieldToRecordType(siginfo_type, "si_code", int_type, - lldb::eAccessPublic, 0); - } else { - ast->AddFieldToRecordType(siginfo_type, "si_code", int_type, - lldb::eAccessPublic, 0); - ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type, - lldb::eAccessPublic, 0); - } - - // the structure is padded on 64-bit arches to fix alignment - if (triple.isArch64Bit()) - ast->AddFieldToRecordType(siginfo_type, "__pad0", int_type, - lldb::eAccessPublic, 0); - - // union used to hold the signal data - CompilerType union_type = ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", - llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); - ast->StartTagDeclarationDefinition(union_type); - - ast->AddFieldToRecordType( - union_type, "_kill", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_pid", pid_type}, - {"si_uid", uid_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_timer", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_tid", int_type}, - {"si_overrun", int_type}, - {"si_sigval", sigval_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_rt", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_pid", pid_type}, - {"si_uid", uid_type}, - {"si_sigval", sigval_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_sigchld", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_pid", pid_type}, - {"si_uid", uid_type}, - {"si_status", int_type}, - {"si_utime", clock_type}, - {"si_stime", clock_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_sigfault", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_addr", voidp_type}, - {"si_addr_lsb", short_type}, - {"_bounds", sigfault_bounds_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_sigpoll", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_band", band_type}, - {"si_fd", int_type}, - }), - lldb::eAccessPublic, 0); - - // NB: SIGSYS is not present on ia64 but we don't seem to support that - ast->AddFieldToRecordType( - union_type, "_sigsys", - ast->CreateStructForIdentifier(ConstString(), - { - {"_call_addr", voidp_type}, - {"_syscall", int_type}, - {"_arch", uint_type}, - }), - lldb::eAccessPublic, 0); - - ast->CompleteTagDeclarationDefinition(union_type); - ast->AddFieldToRecordType(siginfo_type, "_sifields", union_type, - lldb::eAccessPublic, 0); - - ast->CompleteTagDeclarationDefinition(siginfo_type); - return siginfo_type; + return CompilerType(); } >From 24615119addcdf9fe5a8c5b2ebd0c15d75651279 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sat, 22 Feb 2025 03:42:26 -0600 Subject: [PATCH 37/49] Removed un-needed changes --- lldb/include/lldb/Host/aix/AbstractSocket.h | 25 --------------------- lldb/include/lldb/Host/aix/Uio.h | 23 ------------------- lldb/source/Host/CMakeLists.txt | 1 - lldb/source/Host/aix/AbstractSocket.cpp | 20 ----------------- 4 files changed, 69 deletions(-) delete mode 100644 lldb/include/lldb/Host/aix/AbstractSocket.h delete mode 100644 lldb/include/lldb/Host/aix/Uio.h delete mode 100644 lldb/source/Host/aix/AbstractSocket.cpp diff --git a/lldb/include/lldb/Host/aix/AbstractSocket.h b/lldb/include/lldb/Host/aix/AbstractSocket.h deleted file mode 100644 index accfd01457a5e..0000000000000 --- a/lldb/include/lldb/Host/aix/AbstractSocket.h +++ /dev/null @@ -1,25 +0,0 @@ -//===-- AbstractSocket.h ----------------------------------------*- 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 -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_AbstractSocket_h_ -#define liblldb_AbstractSocket_h_ - -#include "lldb/Host/posix/DomainSocket.h" - -namespace lldb_private { -class AbstractSocket : public DomainSocket { -public: - AbstractSocket(); - -protected: - size_t GetNameOffset() const override; - void DeleteSocketFile(llvm::StringRef name) override; -}; -} - -#endif // ifndef liblldb_AbstractSocket_h_ diff --git a/lldb/include/lldb/Host/aix/Uio.h b/lldb/include/lldb/Host/aix/Uio.h deleted file mode 100644 index acf79ecc6a1d0..0000000000000 --- a/lldb/include/lldb/Host/aix/Uio.h +++ /dev/null @@ -1,23 +0,0 @@ -//===-- Uio.h ---------------------------------------------------*- 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 -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_Host_aix_Uio_h_ -#define liblldb_Host_aix_Uio_h_ - -#include "lldb/Host/Config.h" -#include - -// We shall provide our own implementation of process_vm_readv if it is not -// present -#if !HAVE_PROCESS_VM_READV -ssize_t process_vm_readv(::pid_t pid, const struct iovec *local_iov, - unsigned long liovcnt, const struct iovec *remote_iov, - unsigned long riovcnt, unsigned long flags); -#endif - -#endif // liblldb_Host_aix_Uio_h_ diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index bb6b5befa16e4..5a14b4c629825 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -140,7 +140,6 @@ else() elseif (CMAKE_SYSTEM_NAME MATCHES "AIX") add_host_subdirectory(aix - aix/AbstractSocket.cpp aix/Host.cpp aix/HostInfoAIX.cpp aix/Support.cpp diff --git a/lldb/source/Host/aix/AbstractSocket.cpp b/lldb/source/Host/aix/AbstractSocket.cpp deleted file mode 100644 index fddf78f54f46d..0000000000000 --- a/lldb/source/Host/aix/AbstractSocket.cpp +++ /dev/null @@ -1,20 +0,0 @@ -//===-- AbstractSocket.cpp ------------------------------------------------===// -// -// 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 "lldb/Host/aix/AbstractSocket.h" - -#include "llvm/ADT/StringRef.h" - -using namespace lldb; -using namespace lldb_private; - -AbstractSocket::AbstractSocket() : DomainSocket(ProtocolUnixAbstract) {} - -size_t AbstractSocket::GetNameOffset() const { return 1; } - -void AbstractSocket::DeleteSocketFile(llvm::StringRef name) {} >From 25bea9ca48dc458c1dddd72f10a483e76926a04e Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Wed, 26 Feb 2025 01:10:15 -0600 Subject: [PATCH 38/49] Resolving coredump issue while attach with library calls --- lldb/include/lldb/Core/ModuleSpec.h | 2 ++ lldb/source/Core/ModuleList.cpp | 12 +++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lldb/include/lldb/Core/ModuleSpec.h b/lldb/include/lldb/Core/ModuleSpec.h index 4fe06412b6b0b..9d79992b48c7e 100644 --- a/lldb/include/lldb/Core/ModuleSpec.h +++ b/lldb/include/lldb/Core/ModuleSpec.h @@ -122,6 +122,8 @@ class ModuleSpec { ConstString &GetObjectName() { return m_object_name; } ConstString GetObjectName() const { return m_object_name; } + + void SetObjectName(ConstString objName) { m_object_name = objName; } uint64_t GetObjectOffset() const { return m_object_offset; } diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index 2b8ccab2406c6..862a2729c1afb 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -260,7 +260,17 @@ void ModuleList::ReplaceEquivalent( module_sp->GetArchitecture()); equivalent_module_spec.GetPlatformFileSpec() = module_sp->GetPlatformFileSpec(); - +#ifdef _AIX + // To remove the exact equivalent module, the object name must be + // specified. When the equivalent_module_spec object is created, its + // object name is initially set to NULL. This is because the module_sp's + // GetPath() returns a path in the format (/usr/ccs/libc.a), which does + // not include the object name. As a result, MatchesModuleSpec may return + // true even though the object name is NULL and doesn't match any loaded + // module. To fix this, set the object name of the equivalent_module_spec + // to be the same as the object name of the module_sp. */ + equivalent_module_spec.SetObjectName(module_sp->GetObjectName()); +#endif size_t idx = 0; while (idx < m_modules.size()) { ModuleSP test_module_sp(m_modules[idx]); >From 349ec0064668a0ee1d3af7c2f38fa7427b4b2d36 Mon Sep 17 00:00:00 2001 From: Dhruv Srivastava Date: Fri, 28 Feb 2025 23:44:40 +0530 Subject: [PATCH 39/49] [AIX][Coredump] AIX Coredump debugging Implementation (#25) Creates a general framework to be able to debug an AIX generated coredump file. At this point, we are only supporting 64-bit core files using this general framework. With this implementation, LLDB can recognise and debug any 64-bit AIX coredump file. Most of the generic debugging commands work after this: # bin/lldb --core /home/dhruv/LLDB/tests/core (lldb) target create --core "/home/dhruv/LLDB/tests/core" Core file '/home/dhruv/LLDB/tests/core' (powerpc64) was loaded. (lldb) bt * thread #1, stop reason = SIGSEGV * frame #0: 0x0000000100000940 coretest64`main at core.c:5 frame #1: 0x00000001000004ac coretest64`__start + 116 (lldb) process status Process 18446744071562067991 stopped * thread #1, stop reason = SIGSEGV frame #0: 0x0000000100000940 coretest64`main at core.c:5 2 char *str; 3 int a = 10; 4 str = "GfG"; -> 5 *(str+1) = 'n'; 6 return a; 7 } And others like memory read, image list, image dump sections, disassembly etc --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 62 ++++- .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 6 + .../Plugins/ObjectFile/AIXCore/CMakeLists.txt | 13 + .../ObjectFile/AIXCore/ObjectFileAIXCore.cpp | 254 ++++++++++++++++++ .../ObjectFile/AIXCore/ObjectFileAIXCore.h | 121 +++++++++ lldb/source/Plugins/ObjectFile/CMakeLists.txt | 1 + lldb/source/Plugins/Process/CMakeLists.txt | 1 + .../Plugins/Process/aix-core/AIXCore.cpp | 116 ++++++++ .../source/Plugins/Process/aix-core/AIXCore.h | 125 +++++++++ .../Plugins/Process/aix-core/CMakeLists.txt | 16 ++ .../Process/aix-core/ProcessAIXCore.cpp | 251 +++++++++++++++++ .../Plugins/Process/aix-core/ProcessAIXCore.h | 100 +++++++ .../aix-core/RegisterContextCoreAIX_ppc64.cpp | 136 ++++++++++ .../aix-core/RegisterContextCoreAIX_ppc64.h | 46 ++++ .../Process/aix-core/ThreadAIXCore.cpp | 127 +++++++++ .../Plugins/Process/aix-core/ThreadAIXCore.h | 110 ++++++++ 16 files changed, 1484 insertions(+), 1 deletion(-) create mode 100644 lldb/source/Plugins/ObjectFile/AIXCore/CMakeLists.txt create mode 100644 lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp create mode 100644 lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.h create mode 100644 lldb/source/Plugins/Process/aix-core/AIXCore.cpp create mode 100644 lldb/source/Plugins/Process/aix-core/AIXCore.h create mode 100644 lldb/source/Plugins/Process/aix-core/CMakeLists.txt create mode 100644 lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp create mode 100644 lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h create mode 100644 lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.cpp create mode 100644 lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.h create mode 100644 lldb/source/Plugins/Process/aix-core/ThreadAIXCore.cpp create mode 100644 lldb/source/Plugins/Process/aix-core/ThreadAIXCore.h diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 1a98bb9334043..7e44ffbb1c051 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -228,6 +228,65 @@ void DynamicLoaderAIXDYLD::ResolveExecutableModule( target.SetExecutableModule(module_sp, eLoadDependentsNo); } +bool DynamicLoaderAIXDYLD::IsCoreFile() const { + return !m_process->IsLiveDebugSession(); +} + +void DynamicLoaderAIXDYLD::FillCoreLoaderData(lldb_private::DataExtractor &data, + uint64_t loader_offset, uint64_t loader_size ) { + + static char *buffer = (char *)malloc(loader_size); + struct ld_info ldinfo[64]; + char *buffer_complete; + struct ld_info *ptr; + int i = 0; + + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); + ByteOrder byteorder = data.GetByteOrder(); + data.ExtractBytes(loader_offset, loader_size, eByteOrderBig, buffer); + buffer_complete = buffer + loader_size; + ldinfo[0].ldinfo_next = 1; + + while (ldinfo[i++].ldinfo_next != 0) { + + ptr = (struct ld_info *)buffer; + ldinfo[i].ldinfo_next = ptr->ldinfo_next; + ldinfo[i].ldinfo_flags = ptr->ldinfo_flags; + ldinfo[i].ldinfo_core = ptr->ldinfo_core; + ldinfo[i].ldinfo_textorg = ptr->ldinfo_textorg; + ldinfo[i].ldinfo_textsize = ptr->ldinfo_textsize; + ldinfo[i].ldinfo_dataorg = ptr->ldinfo_dataorg; + ldinfo[i].ldinfo_datasize = ptr->ldinfo_datasize; + + char *filename = &ptr->ldinfo_filename[0]; + char *membername = filename + (strlen(filename) + 1); + strcpy(ldinfo[i].ldinfo_filename, filename); + + buffer += ptr->ldinfo_next; + struct ld_info *ptr2 = &(ldinfo[i]); + char *pathName = ptr2->ldinfo_filename; + char pathWithMember[PATH_MAX] = {0}; + if (strlen(membername) > 0) { + sprintf(pathWithMember, "%s(%s)", pathName, membername); + } else { + sprintf(pathWithMember, "%s", pathName); + } + + FileSpec file(pathWithMember); + ModuleSpec module_spec(file, m_process->GetTarget().GetArchitecture()); + LLDB_LOGF(log, "Module :%s", pathWithMember); + if (ModuleSP module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, true /* notify */)) { + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr2->ldinfo_textorg, false, 1); + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr2->ldinfo_dataorg, false, 2); + // FIXME: .tdata, .bss + } + if (ptr2->ldinfo_next == 0) { + ptr2 = nullptr; + } + } +} + void DynamicLoaderAIXDYLD::DidAttach() { Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); @@ -361,7 +420,8 @@ void DynamicLoaderAIXDYLD::DidLaunch() { #endif } -Status DynamicLoaderAIXDYLD::CanLoadImage() { return Status(); } +Status DynamicLoaderAIXDYLD::CanLoadImage() { + return Status(); } ThreadPlanSP DynamicLoaderAIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h index 0ffbe688e0069..097f8d048b77f 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -33,6 +33,9 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { lldb::addr_t module_addr); void OnUnloadModule(lldb::addr_t module_addr); + void FillCoreLoaderData(lldb_private::DataExtractor &data, + uint64_t loader_offset, uint64_t loader_size); + void DidAttach() override; void DidLaunch() override; Status CanLoadImage() override; @@ -49,6 +52,9 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { /// Loads Module from inferior process. void ResolveExecutableModule(lldb::ModuleSP &module_sp); + /// Returns true if the process is for a core file. + bool IsCoreFile() const; + private: std::map m_loaded_modules; }; diff --git a/lldb/source/Plugins/ObjectFile/AIXCore/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/AIXCore/CMakeLists.txt new file mode 100644 index 0000000000000..5656b33a61726 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/AIXCore/CMakeLists.txt @@ -0,0 +1,13 @@ +add_lldb_library(lldbPluginObjectFileAIXCore PLUGIN + ObjectFileAIXCore.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + lldbTarget + lldbUtility + lldbPluginProcessUtility + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp new file mode 100644 index 0000000000000..5158fa4e25077 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp @@ -0,0 +1,254 @@ +//===-- ObjectFileAIXCore.cpp -------------------------------------------------===// +// +// 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 "ObjectFileAIXCore.h" + +#include +#include +#include +#include + +#include "lldb/Utility/FileSpecList.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Stream.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Object/XCOFFObjectFile.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ObjectFileAIXCore) + +enum CoreVersion : uint64_t {AIXCORE32 = 0xFEEDDB1, AIXCORE64 = 0xFEEDDB2}; + +bool m_is_core = false; + +// Static methods. +void ObjectFileAIXCore::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + CreateMemoryInstance, GetModuleSpecifications); +} + +void ObjectFileAIXCore::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ObjectFile *ObjectFileAIXCore::CreateInstance(const lldb::ModuleSP &module_sp, + DataBufferSP data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t file_offset, + lldb::offset_t length) { + + if(m_is_core) + { + + bool mapped_writable = false; + if (!data_sp) { + data_sp = MapFileDataWritable(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + mapped_writable = true; + } + + assert(data_sp); + + const uint8_t *magic = data_sp->GetBytes() + data_offset; + + // Update the data to contain the entire file if it doesn't already + if (data_sp->GetByteSize() < length) { + data_sp = MapFileDataWritable(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + mapped_writable = true; + magic = data_sp->GetBytes(); + } + + // If we didn't map the data as writable take ownership of the buffer. + if (!mapped_writable) { + data_sp = std::make_shared(data_sp->GetBytes(), + data_sp->GetByteSize()); + data_offset = 0; + magic = data_sp->GetBytes(); + } + + std::unique_ptr objfile_up(new ObjectFileAIXCore( + module_sp, data_sp, data_offset, file, file_offset, length)); + ArchSpec spec = objfile_up->GetArchitecture(); + objfile_up->SetModulesArchitecture(spec); + return objfile_up.release(); + + } +} + +ObjectFile *ObjectFileAIXCore::CreateMemoryInstance( + const lldb::ModuleSP &module_sp, WritableDataBufferSP data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) { + return nullptr; +} + +size_t ObjectFileAIXCore::GetModuleSpecifications( + const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, lldb::offset_t file_offset, + lldb::offset_t length, lldb_private::ModuleSpecList &specs) { + const size_t initial_count = specs.GetSize(); + + if (ObjectFileAIXCore::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) { + // Need new ArchType??? + ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + ModuleSpec spec(file, arch_spec); + spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX); + specs.Append(spec); + } + return specs.GetSize() - initial_count; +} + +static uint32_t AIXCoreHeaderCheckFromMagic(uint32_t magic) { + + Log *log = GetLog(LLDBLog::Modules); + switch (magic) { + case AIXCORE32: + LLDB_LOGF(log, "ObjectFileAIXCore: 32-bit not supported"); + break; + case AIXCORE64: + m_is_core = true; + return 1; + break; + } + return 0; +} + +bool ObjectFileAIXCore::MagicBytesMatch(DataBufferSP &data_sp, + lldb::addr_t data_offset, + lldb::addr_t data_length) { + lldb_private::DataExtractor data; + data.SetData(data_sp, data_offset, data_length); + lldb::offset_t offset = 0; + offset += 4; // Skipping to the coredump version + uint32_t magic = data.GetU32(&offset); + return AIXCoreHeaderCheckFromMagic(magic) != 0; +} + +bool ObjectFileAIXCore::ParseHeader() { + + return false; +} + +ByteOrder ObjectFileAIXCore::GetByteOrder() const { + return eByteOrderBig; +} + +bool ObjectFileAIXCore::IsExecutable() const { + return false; +} + +uint32_t ObjectFileAIXCore::GetAddressByteSize() const { + return 8; +} + +AddressClass ObjectFileAIXCore::GetAddressClass(addr_t file_addr) { + return AddressClass::eUnknown; +} + +lldb::SymbolType ObjectFileAIXCore::MapSymbolType(llvm::object::SymbolRef::Type sym_type) { + if (sym_type == llvm::object::SymbolRef::ST_Function) + return lldb::eSymbolTypeCode; + else if (sym_type == llvm::object::SymbolRef::ST_Data) + return lldb::eSymbolTypeData; + return lldb::eSymbolTypeInvalid; +} + +void ObjectFileAIXCore::ParseSymtab(Symtab &lldb_symtab) { +} + +bool ObjectFileAIXCore::IsStripped() { + return false; +} + +void ObjectFileAIXCore::CreateSections(SectionList &unified_section_list) { +} + +void ObjectFileAIXCore::Dump(Stream *s) { +} + +ArchSpec ObjectFileAIXCore::GetArchitecture() { + ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + return arch_spec; +} + +UUID ObjectFileAIXCore::GetUUID() { + return UUID(); +} + +uint32_t ObjectFileAIXCore::GetDependentModules(FileSpecList &files) { + + auto original_size = files.GetSize(); + return files.GetSize() - original_size; +} + +Address ObjectFileAIXCore::GetImageInfoAddress(Target *target) { + return Address(); +} + +lldb_private::Address ObjectFileAIXCore::GetBaseAddress() { + return lldb_private::Address(); +} +ObjectFile::Type ObjectFileAIXCore::CalculateType() { + return eTypeCoreFile; +} + +ObjectFile::Strata ObjectFileAIXCore::CalculateStrata() { + return eStrataUnknown; +} + +std::vector +ObjectFileAIXCore::GetLoadableData(Target &target) { + std::vector loadables; + return loadables; +} + +lldb::WritableDataBufferSP +ObjectFileAIXCore::MapFileDataWritable(const FileSpec &file, uint64_t Size, + uint64_t Offset) { + return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size, + Offset); +} + +ObjectFileAIXCore::ObjectFileAIXCore(const lldb::ModuleSP &module_sp, + DataBufferSP data_sp, lldb::offset_t data_offset, + const FileSpec *file, lldb::offset_t file_offset, + lldb::offset_t length) + : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset) + { + if (file) + m_file = *file; +} + +ObjectFileAIXCore::ObjectFileAIXCore(const lldb::ModuleSP &module_sp, + DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, + addr_t header_addr) + : ObjectFile(module_sp, process_sp, header_addr, header_data_sp) + { +} diff --git a/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.h b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.h new file mode 100644 index 0000000000000..5dbd78d919bb6 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.h @@ -0,0 +1,121 @@ +//===-- ObjectFileAIXCore.h --------------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_AIXCORE_OBJECTFILEAIXCORE_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_AIXCORE_OBJECTFILEAIXCORE_H + +#include + +#include + +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/UUID.h" +#include "lldb/lldb-private.h" +#include "llvm/Object/XCOFFObjectFile.h" + +/// \class ObjectFileAIXCore +/// Generic AIX CORE object file reader. +/// +/// This class provides a generic AIX Core (32/64 bit) reader plugin implementing +/// the ObjectFile protocol. +class ObjectFileAIXCore : public lldb_private::ObjectFile { +public: + // Static Functions + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "aix-core-obj"; } + + static llvm::StringRef GetPluginDescriptionStatic() { + return "AIX core object file reader."; + } + + static lldb_private::ObjectFile * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length); + + static lldb_private::ObjectFile *CreateMemoryInstance( + const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + + static size_t GetModuleSpecifications(const lldb_private::FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + lldb_private::ModuleSpecList &specs); + + static bool MagicBytesMatch(lldb::DataBufferSP &data_sp, lldb::addr_t offset, + lldb::addr_t length); + + static lldb::SymbolType MapSymbolType(llvm::object::SymbolRef::Type sym_type); + + // PluginInterface protocol + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + // ObjectFile Protocol. + bool ParseHeader() override; + + lldb::ByteOrder GetByteOrder() const override; + + bool IsExecutable() const override; + + uint32_t GetAddressByteSize() const override; + + lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override; + + void ParseSymtab(lldb_private::Symtab &symtab) override; + + bool IsStripped() override; + + void CreateSections(lldb_private::SectionList &unified_section_list) override; + + void Dump(lldb_private::Stream *s) override; + + lldb_private::ArchSpec GetArchitecture() override; + + lldb_private::UUID GetUUID() override; + + uint32_t GetDependentModules(lldb_private::FileSpecList &files) override; + + lldb_private::Address + GetImageInfoAddress(lldb_private::Target *target) override; + lldb_private::Address GetBaseAddress() override; + + ObjectFile::Type CalculateType() override; + + ObjectFile::Strata CalculateStrata() override; + + ObjectFileAIXCore(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + ObjectFileAIXCore(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + +protected: + + static bool ParseAIXCoreHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr + ); + + std::vector + GetLoadableData(lldb_private::Target &target) override; + + static lldb::WritableDataBufferSP + MapFileDataWritable(const lldb_private::FileSpec &file, uint64_t Size, + uint64_t Offset); + +}; + +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_AIXCORE_OBJECTFILEAIXCORE_H diff --git a/lldb/source/Plugins/ObjectFile/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/CMakeLists.txt index 7abd0c96f4fd7..1605356fdb7f1 100644 --- a/lldb/source/Plugins/ObjectFile/CMakeLists.txt +++ b/lldb/source/Plugins/ObjectFile/CMakeLists.txt @@ -9,3 +9,4 @@ add_subdirectory(PECOFF) add_subdirectory(XCOFF) add_subdirectory(Placeholder) add_subdirectory(wasm) +add_subdirectory(AIXCore) diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt index 058b4b9ad2157..0b66ea18c82ce 100644 --- a/lldb/source/Plugins/Process/CMakeLists.txt +++ b/lldb/source/Plugins/Process/CMakeLists.txt @@ -24,3 +24,4 @@ add_subdirectory(elf-core) add_subdirectory(mach-core) add_subdirectory(minidump) add_subdirectory(FreeBSDKernel) +add_subdirectory(aix-core) diff --git a/lldb/source/Plugins/Process/aix-core/AIXCore.cpp b/lldb/source/Plugins/Process/aix-core/AIXCore.cpp new file mode 100644 index 0000000000000..95e47b4d8be53 --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/AIXCore.cpp @@ -0,0 +1,116 @@ +//===-- AIXCore.cpp ------------------------------------------------===// +// +// 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 + +#include "lldb/Core/Section.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" + +#include "AIXCore.h" + +using namespace AIXCORE; +using namespace lldb; +using namespace lldb_private; + +AIXCore64Header::AIXCore64Header() { memset(this, 0, sizeof(AIXCore64Header)); } + + +bool AIXCore64Header::ParseRegisterContext(lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + // The data is arranged in this order in this coredump file + // so we have to fetch in this exact order. But need to change + // the context structure order according to Infos_ppc64 + for(int i = 0; i < 32; i++) + Fault.context.gpr[i] = data.GetU64(offset); + Fault.context.msr = data.GetU64(offset); + Fault.context.pc = data.GetU64(offset); + Fault.context.lr = data.GetU64(offset); + Fault.context.ctr = data.GetU64(offset); + Fault.context.cr = data.GetU32(offset); + Fault.context.xer = data.GetU32(offset); + Fault.context.fpscr = data.GetU32(offset); + Fault.context.fpscrx = data.GetU32(offset); + Fault.context.except[0] = data.GetU64(offset); + for(int i = 0; i < 32; i++) + Fault.context.fpr[i] = data.GetU64(offset); + Fault.context.fpeu = data.GetU8(offset); + Fault.context.fpinfo = data.GetU8(offset); + Fault.context.fpscr24_31 = data.GetU8(offset); + Fault.context.pad[0] = data.GetU8(offset); + Fault.context.excp_type = data.GetU32(offset); + + return true; +} +bool AIXCore64Header::ParseThreadContext(lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + + lldb::offset_t offset_to_regctx = *offset; + offset_to_regctx += sizeof(thrdentry64); + Fault.thread.ti_tid = data.GetU64(offset); + Fault.thread.ti_pid = data.GetU32(offset); + int ret = ParseRegisterContext(data, &offset_to_regctx); + return true; +} + +bool AIXCore64Header::ParseUserData(lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + User.process.pi_pid = data.GetU32(offset); + User.process.pi_ppid = data.GetU32(offset); + User.process.pi_sid = data.GetU32(offset); + User.process.pi_pgrp = data.GetU32(offset); + User.process.pi_uid = data.GetU32(offset); + User.process.pi_suid = data.GetU32(offset); + + *offset += 76; + + ByteOrder byteorder = data.GetByteOrder(); + size_t size = 33; + data.ExtractBytes(*offset, size, byteorder, User.process.pi_comm); + offset += size; + + return true; +} + +bool AIXCore64Header::ParseCoreHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + + SignalNum = data.GetU8(offset); + Flag = data.GetU8(offset); + Entries = data.GetU16(offset); + Version = data.GetU32(offset); + FDInfo = data.GetU64(offset); + + LoaderOffset = data.GetU64(offset); + LoaderSize = data.GetU64(offset); + NumberOfThreads = data.GetU32(offset); + Reserved0 = data.GetU32(offset); + ThreadContextOffset = data.GetU64(offset); + NumSegRegion = data.GetU64(offset); + SegRegionOffset = data.GetU64(offset); + StackOffset = data.GetU64(offset); + StackBaseAddr = data.GetU64(offset); + StackSize = data.GetU64(offset); + DataRegionOffset = data.GetU64(offset); + DataBaseAddr = data.GetU64(offset); + DataSize = data.GetU64(offset); + + *offset += 104; + lldb::offset_t offset_to_user = (*offset + sizeof(ThreadContext64)); + int ret = 0; + ret = ParseThreadContext(data, offset); + ret = ParseUserData(data, &offset_to_user); + + return true; + +} + diff --git a/lldb/source/Plugins/Process/aix-core/AIXCore.h b/lldb/source/Plugins/Process/aix-core/AIXCore.h new file mode 100644 index 0000000000000..3d78d5e92c7ab --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/AIXCore.h @@ -0,0 +1,125 @@ +//===-- AIXCore.h ----------------------------------------*- 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 +// +// Notes about AIX Process core dumps: +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_AIXCORE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_AIXCORE_H + +#include "llvm/ADT/StringRef.h" +#include +#include +#include + +#include +#include + +namespace AIXCORE { + +struct RegContext { + // The data is arranged in order as filled by AIXCore.cpp in this coredump file + // so we have to fetch in that exact order, refer there. + // But need to change + // the context structure in order according to Infos_ppc64 + uint64_t gpr[32]; /* 64-bit gprs */ + unsigned long pc; /* msr */ + unsigned long msr; /* iar */ + unsigned long origr3; /* iar */ + unsigned long ctr; /* CTR */ + unsigned long lr; /* LR */ + unsigned long xer; /* XER */ + unsigned long cr; /* CR */ + unsigned long softe; /* CR */ + unsigned long trap; /* CR */ + unsigned int fpscr; /* floating pt status reg */ + unsigned int fpscrx; /* software ext to fpscr */ + unsigned long except[1]; /* exception address */ + double fpr[32]; /* floating pt regs */ + char fpeu; /* floating pt ever used */ + char fpinfo; /* floating pt info */ + char fpscr24_31; /* bits 24-31 of 64-bit FPSCR */ + char pad[1]; + int excp_type; /* exception type */ +}; + + struct ThreadContext64 { + struct thrdentry64 thread; + struct RegContext context; + }; + + struct UserData { + + struct procentry64 process; + unsigned long long reserved[16]; + }; + + struct AIXCore64Header { + + int8_t SignalNum; /* signal number (cause of error) */ + int8_t Flag; /* flag to describe core dump type */ + uint16_t Entries; /* number of core dump modules */ + uint32_t Version; /* core file format number */ + uint64_t FDInfo; /* offset to fd region in file */ + + uint64_t LoaderOffset; /* offset to loader region in file */ + uint64_t LoaderSize; /* size of loader region */ + + uint32_t NumberOfThreads ; /* number of elements in thread table */ + uint32_t Reserved0; /* Padding */ + uint64_t ThreadContextOffset; /* offset to thread context table */ + + uint64_t NumSegRegion; /* n of elements in segregion */ + uint64_t SegRegionOffset; /* offset to start of segregion table */ + + uint64_t StackOffset; /* offset of user stack in file */ + uint64_t StackBaseAddr; /* base address of user stack region */ + uint64_t StackSize; /* size of user stack region */ + + uint64_t DataRegionOffset; /* offset to user data region */ + uint64_t DataBaseAddr; /* base address of user data region */ + uint64_t DataSize; /* size of user data region */ + uint64_t SDataBase; /* base address of sdata region */ + uint64_t SDataSize; /* size of sdata region */ + + uint64_t NumVMRegions; /* number of anonymously mapped areas */ + uint64_t VMOffset; /* offset to start of vm_infox table */ + + int32_t ProcessorImplementation; /* processor implementation */ + uint32_t NumElementsCTX; /* n of elements in extended ctx table*/ + uint64_t CPRSOffset; /* Checkpoint/Restart offset */ + uint64_t ExtendedContextOffset; /* extended context offset */ + uint64_t OffsetUserKey; /* Offset to user-key exception data */ + uint64_t OffsetLoaderTLS; /* offset to the loader region in file + when a process uses TLS data */ + uint64_t TLSLoaderSize; /* size of the above loader region */ + uint64_t ExtendedProcEntry; /* Extended procentry64 information */ + uint64_t Reserved[2]; + + struct ThreadContext64 Fault; + + struct UserData User; + + AIXCore64Header(); + + bool ParseCoreHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + bool ParseThreadContext(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + bool ParseUserData(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + bool ParseRegisterContext(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + bool ParseLoaderData(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + + }; + + +} + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_AIXCORE_H diff --git a/lldb/source/Plugins/Process/aix-core/CMakeLists.txt b/lldb/source/Plugins/Process/aix-core/CMakeLists.txt new file mode 100644 index 0000000000000..347717a362491 --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/CMakeLists.txt @@ -0,0 +1,16 @@ +add_definitions("-D_ALL_SOURCE") + +add_lldb_library(lldbPluginProcessAIXCore PLUGIN + ProcessAIXCore.cpp + AIXCore.cpp + ThreadAIXCore.cpp + RegisterContextCoreAIX_ppc64.cpp + + LINK_LIBS + lldbCore + lldbTarget + lldbPluginProcessUtility + LINK_COMPONENTS + BinaryFormat + Support + ) diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp new file mode 100644 index 0000000000000..9300aa14ac4db --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp @@ -0,0 +1,251 @@ +//===-- ProcessAIXCore.cpp ------------------------------------------------===// +// +// 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 + +#include +#include + +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Section.h" +#include "lldb/Target/ABI.h" +#include "lldb/Target/DynamicLoader.h" +#include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/UnixSignals.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" + +#include "llvm/Support/Threading.h" +#include "Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h" + +#include "ProcessAIXCore.h" +#include "AIXCore.h" +#include "ThreadAIXCore.h" + +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ProcessAIXCore) + +llvm::StringRef ProcessAIXCore::GetPluginDescriptionStatic() { + return "AIX core dump plug-in."; +} + +void ProcessAIXCore::Initialize() { + static llvm::once_flag g_once_flag; + + llvm::call_once(g_once_flag, []() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); + }); +} + +void ProcessAIXCore::Terminate() { + PluginManager::UnregisterPlugin(ProcessAIXCore::CreateInstance); +} + +lldb::ProcessSP ProcessAIXCore::CreateInstance(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const FileSpec *crash_file, + bool can_connect) { + lldb::ProcessSP process_sp; + if (crash_file && !can_connect) { + const size_t header_size = sizeof(AIXCORE::AIXCore64Header); + + auto data_sp = FileSystem::Instance().CreateDataBuffer( + crash_file->GetPath(), header_size, 0); + + if (data_sp && data_sp->GetByteSize() == header_size) { + AIXCORE::AIXCore64Header aixcore_header; + DataExtractor data(data_sp, lldb::eByteOrderBig, 4); + lldb::offset_t data_offset = 0; + if(aixcore_header.ParseCoreHeader(data, &data_offset)) { + process_sp = std::make_shared(target_sp, listener_sp, + *crash_file); + } + } + + } + return process_sp; +} + +// ProcessAIXCore constructor +ProcessAIXCore::ProcessAIXCore(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const FileSpec &core_file) + : PostMortemProcess(target_sp, listener_sp, core_file) {} + +// Destructor +ProcessAIXCore::~ProcessAIXCore() { + Clear(); + // We need to call finalize on the process before destroying ourselves to + // make sure all of the broadcaster cleanup goes as planned. If we destruct + // this class, then Process::~Process() might have problems trying to fully + // destroy the broadcaster. + Finalize(true /* destructing */); +} + +bool ProcessAIXCore::CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) { + + if (!m_core_module_sp && FileSystem::Instance().Exists(m_core_file)) { + ModuleSpec core_module_spec(m_core_file, target_sp->GetArchitecture()); + Status error(ModuleList::GetSharedModule(core_module_spec, m_core_module_sp, + nullptr, nullptr, nullptr)); + if (m_core_module_sp) { + ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); + if (core_objfile && core_objfile->GetType() == ObjectFile::eTypeCoreFile){ + return true; + } + } + } + return false; + +} + +ArchSpec ProcessAIXCore::GetArchitecture() { + + ArchSpec arch = m_core_module_sp->GetObjectFile()->GetArchitecture(); + + ArchSpec target_arch = GetTarget().GetArchitecture(); + arch.MergeFrom(target_arch); + + return arch; +} + +lldb_private::DynamicLoader *ProcessAIXCore::GetDynamicLoader() { + if (m_dyld_up.get() == nullptr) { + m_dyld_up.reset(DynamicLoader::FindPlugin( + this, DynamicLoaderAIXDYLD::GetPluginNameStatic())); + } + return m_dyld_up.get(); +} + +void ProcessAIXCore::ParseAIXCoreFile() { + + Log *log = GetLog(LLDBLog::Process); + AIXSigInfo siginfo; + ThreadData thread_data; + + const lldb_private::UnixSignals &unix_signals = *GetUnixSignals(); + const ArchSpec &arch = GetArchitecture(); + + siginfo.Parse(m_aixcore_header, arch, unix_signals); + thread_data.siginfo = siginfo; + SetID(m_aixcore_header.User.process.pi_pid); + + thread_data.name.assign (m_aixcore_header.User.process.pi_comm, + strnlen (m_aixcore_header.User.process.pi_comm, + sizeof (m_aixcore_header.User.process.pi_comm))); + + lldb::DataBufferSP data_buffer_sp(new lldb_private::DataBufferHeap(sizeof(m_aixcore_header.Fault.context), 0)); + + memcpy(static_cast(const_cast(data_buffer_sp->GetBytes())), + &m_aixcore_header.Fault.context, sizeof(m_aixcore_header.Fault.context)); + + lldb_private::DataExtractor data(data_buffer_sp, lldb::eByteOrderBig, 8); + + thread_data.gpregset = DataExtractor(data, 0, sizeof(m_aixcore_header.Fault.context)); + m_thread_data.push_back(thread_data); + LLDB_LOGF(log, "ProcessAIXCore: Parsing Complete!"); + +} + +// Process Control +Status ProcessAIXCore::DoLoadCore() { + + Status error; + if (!m_core_module_sp) { + error = Status::FromErrorString("invalid core module"); + return error; + } + + FileSpec file = m_core_module_sp->GetObjectFile()->GetFileSpec(); + + if (file) { + const size_t header_size = sizeof(AIXCORE::AIXCore64Header); + auto data_sp = FileSystem::Instance().CreateDataBuffer( + file.GetPath(), -1, 0); + if (data_sp && data_sp->GetByteSize() != 0) { + + DataExtractor data(data_sp, lldb::eByteOrderBig, 4); + lldb::offset_t data_offset = 0; + m_aixcore_header.ParseCoreHeader(data, &data_offset); + auto dyld = static_cast(GetDynamicLoader()); + dyld->FillCoreLoaderData(data, m_aixcore_header.LoaderOffset, + m_aixcore_header.LoaderSize); + + } else { + error = Status::FromErrorString("invalid data"); + return error; + } + } else { + error = Status::FromErrorString("invalid file"); + return error; + } + + m_thread_data_valid = true; + ParseAIXCoreFile(); + ArchSpec arch(m_core_module_sp->GetArchitecture()); + + ArchSpec target_arch = GetTarget().GetArchitecture(); + ArchSpec core_arch(m_core_module_sp->GetArchitecture()); + target_arch.MergeFrom(core_arch); + GetTarget().SetArchitecture(target_arch); + + lldb::ModuleSP exe_module_sp = GetTarget().GetExecutableModule(); + if (!exe_module_sp) { + ModuleSpec exe_module_spec; + exe_module_spec.GetArchitecture() = arch; + exe_module_spec.GetFileSpec().SetFile(m_aixcore_header.User.process.pi_comm, + FileSpec::Style::native); + exe_module_sp = GetTarget().GetOrCreateModule(exe_module_spec, true); + GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsNo); + } + + return error; +} + +bool ProcessAIXCore::DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) +{ + const ThreadData &td = m_thread_data[0]; + + lldb::ThreadSP thread_sp = + std::make_shared(*this, td); + new_thread_list.AddThread(thread_sp); + + return true; +} + +void ProcessAIXCore::RefreshStateAfterStop() {} + +// Process Memory +size_t ProcessAIXCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size, + Status &error) { + if (lldb::ABISP abi_sp = GetABI()) + addr = abi_sp->FixAnyAddress(addr); + + // Don't allow the caching that lldb_private::Process::ReadMemory does since + // in core files we have it all cached our our core file anyway. + return DoReadMemory(addr, buf, size, error); +} + +size_t ProcessAIXCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, + Status &error) { return 0; } + +Status ProcessAIXCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo ®ion_info) { + return Status(); +} + +Status ProcessAIXCore::DoDestroy() { return Status(); } diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h new file mode 100644 index 0000000000000..9880c491689ca --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h @@ -0,0 +1,100 @@ +//===-- ProcessAIXCore.h ----------------------------------------*- 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 +// +// Notes about AIX Process core dumps: +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_PROCESSAIXCORE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_PROCESSAIXCORE_H + +#include +#include + +#include "lldb/Target/PostMortemProcess.h" +#include "lldb/Utility/Status.h" +#include "lldb/Target/Process.h" +#include "AIXCore.h" +#include "ThreadAIXCore.h" + +struct ThreadData; + +class ProcessAIXCore : public lldb_private::PostMortemProcess { +public: + // Constructors and Destructors + static lldb::ProcessSP + CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, + const lldb_private::FileSpec *crash_file_path, + bool can_connect); + + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "aix-core"; } + + static llvm::StringRef GetPluginDescriptionStatic(); + + // Constructors and Destructors + ProcessAIXCore(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, + const lldb_private::FileSpec &core_file); + + ~ProcessAIXCore() override; + + // PluginInterface protocol + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + // Process Control + lldb_private::Status DoDestroy() override; + + lldb_private::Status WillResume() override { + return lldb_private::Status::FromErrorStringWithFormatv( + "error: {0} does not support resuming processes", GetPluginName()); + } + + bool WarnBeforeDetach() const override { return false; } + + lldb_private::ArchSpec GetArchitecture(); + + bool CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) override; + + // Creating a new process, or attaching to an existing one + lldb_private::Status DoLoadCore() override; + + bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list, + lldb_private::ThreadList &new_thread_list) override; + + lldb_private::Status + DoGetMemoryRegionInfo(lldb::addr_t load_addr, + lldb_private::MemoryRegionInfo ®ion_info) override; + + void RefreshStateAfterStop() override; + + lldb_private::DynamicLoader *GetDynamicLoader() override; + + // Process Memory + size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size, + lldb_private::Status &error) override; + + size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, + lldb_private::Status &error) override; + + void ParseAIXCoreFile(); + + +private: + lldb::ModuleSP m_core_module_sp; + std::string m_dyld_plugin_name; + + // True if m_thread_contexts contains valid entries + bool m_thread_data_valid = false; + AIXCORE::AIXCore64Header m_aixcore_header; + + std::vector m_thread_data; +}; + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_PROCESSAIXCORE_H diff --git a/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.cpp b/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.cpp new file mode 100644 index 0000000000000..b243017bf9a2a --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.cpp @@ -0,0 +1,136 @@ +//===-- RegisterContextCoreAIX_ppc64.cpp ------------------------------===// +// +// 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 "RegisterContextCoreAIX_ppc64.h" + +#include "lldb/Target/Thread.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" + +#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" +#include "Plugins/Process/elf-core/RegisterUtilities.h" + +#include + +using namespace lldb_private; + +RegisterContextCoreAIX_ppc64::RegisterContextCoreAIX_ppc64( + Thread &thread, RegisterInfoInterface *register_info, + const DataExtractor &gpregset) + : RegisterContextPOSIX_ppc64le(thread, 0, register_info) { + m_gpr_buffer = std::make_shared(gpregset.GetDataStart(), + gpregset.GetByteSize()); + m_gpr.SetData(m_gpr_buffer); + m_gpr.SetByteOrder(gpregset.GetByteOrder()); + + // This Code is for Registers like FPR, VSR, VMX and is disabled right now. + // It will be implemented as per need. + + /* ArchSpec arch = register_info->GetTargetArchitecture(); + DataExtractor fpregset;// = getRegset(notes, arch.GetTriple(), FPR_Desc); + m_fpr_buffer = std::make_shared(fpregset.GetDataStart(), + fpregset.GetByteSize()); + m_fpr.SetData(m_fpr_buffer); + m_fpr.SetByteOrder(fpregset.GetByteOrder()); + + DataExtractor vmxregset;// = getRegset(notes, arch.GetTriple(), PPC_VMX_Desc); + m_vmx_buffer = std::make_shared(vmxregset.GetDataStart(), + vmxregset.GetByteSize()); + m_vmx.SetData(m_vmx_buffer); + m_vmx.SetByteOrder(vmxregset.GetByteOrder()); + + DataExtractor vsxregset;// = getRegset(notes, arch.GetTriple(), PPC_VSX_Desc); + m_vsx_buffer = std::make_shared(vsxregset.GetDataStart(), + vsxregset.GetByteSize()); + m_vsx.SetData(m_vsx_buffer); + m_vsx.SetByteOrder(vsxregset.GetByteOrder());*/ +} + +size_t RegisterContextCoreAIX_ppc64::GetFPRSize() const { + return k_num_fpr_registers_ppc64le * sizeof(uint64_t); +} + +size_t RegisterContextCoreAIX_ppc64::GetVMXSize() const { + return (k_num_vmx_registers_ppc64le - 1) * sizeof(uint64_t) * 2 + + sizeof(uint32_t); +} + +size_t RegisterContextCoreAIX_ppc64::GetVSXSize() const { + return k_num_vsx_registers_ppc64le * sizeof(uint64_t) * 2; +} + +bool RegisterContextCoreAIX_ppc64::ReadRegister( + const RegisterInfo *reg_info, RegisterValue &value) { + lldb::offset_t offset = reg_info->byte_offset; + + if (IsFPR(reg_info->kinds[lldb::eRegisterKindLLDB])) { + uint64_t v; + offset -= GetGPRSize(); + offset = m_fpr.CopyData(offset, reg_info->byte_size, &v); + + if (offset == reg_info->byte_size) { + value.SetBytes(&v, reg_info->byte_size, m_fpr.GetByteOrder()); + return true; + } + } else if (IsVMX(reg_info->kinds[lldb::eRegisterKindLLDB])) { + uint32_t v[4]; + offset -= GetGPRSize() + GetFPRSize(); + offset = m_vmx.CopyData(offset, reg_info->byte_size, &v); + + if (offset == reg_info->byte_size) { + value.SetBytes(v, reg_info->byte_size, m_vmx.GetByteOrder()); + return true; + } + } else if (IsVSX(reg_info->kinds[lldb::eRegisterKindLLDB])) { + uint32_t v[4]; + lldb::offset_t tmp_offset; + offset -= GetGPRSize() + GetFPRSize() + GetVMXSize(); + + if (offset < GetVSXSize() / 2) { + tmp_offset = m_vsx.CopyData(offset / 2, reg_info->byte_size / 2, &v); + + if (tmp_offset != reg_info->byte_size / 2) { + return false; + } + + uint8_t *dst = (uint8_t *)&v + sizeof(uint64_t); + tmp_offset = m_fpr.CopyData(offset / 2, reg_info->byte_size / 2, dst); + + if (tmp_offset != reg_info->byte_size / 2) { + return false; + } + + value.SetBytes(&v, reg_info->byte_size, m_vsx.GetByteOrder()); + return true; + } else { + offset = + m_vmx.CopyData(offset - GetVSXSize() / 2, reg_info->byte_size, &v); + if (offset == reg_info->byte_size) { + value.SetBytes(v, reg_info->byte_size, m_vmx.GetByteOrder()); + return true; + } + } + } else { + uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); + + if (offset == reg_info->byte_offset + reg_info->byte_size) { + if (reg_info->byte_size < sizeof(v)) + value = (uint32_t)v; + else + value = v; + return true; + } + } + + return false; +} + +bool RegisterContextCoreAIX_ppc64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue &value) { + return false; +} diff --git a/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.h b/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.h new file mode 100644 index 0000000000000..8f1f71ce8d884 --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.h @@ -0,0 +1,46 @@ +//===-- RegisterContextCoreAIX_ppc64.h ----------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_REGISTERCONTEXTAIXCORE_PPC64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_REGISTERCONTEXTAIXCORE_PPC64_H + +#include "Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h" +#include "lldb/Utility/DataExtractor.h" + +class RegisterContextCoreAIX_ppc64 : public RegisterContextPOSIX_ppc64le { +public: + RegisterContextCoreAIX_ppc64( + lldb_private::Thread &thread, + lldb_private::RegisterInfoInterface *register_info, + const lldb_private::DataExtractor &gpregset); + + bool ReadRegister(const lldb_private::RegisterInfo *reg_info, + lldb_private::RegisterValue &value) override; + + bool WriteRegister(const lldb_private::RegisterInfo *reg_info, + const lldb_private::RegisterValue &value) override; + +protected: + size_t GetFPRSize() const; + + size_t GetVMXSize() const; + + size_t GetVSXSize() const; + +private: + lldb::DataBufferSP m_gpr_buffer; + lldb::DataBufferSP m_fpr_buffer; + lldb::DataBufferSP m_vmx_buffer; + lldb::DataBufferSP m_vsx_buffer; + lldb_private::DataExtractor m_gpr; + lldb_private::DataExtractor m_fpr; + lldb_private::DataExtractor m_vmx; + lldb_private::DataExtractor m_vsx; +}; + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_REGISTERCONTEXTAIXCORE_PPC64_H diff --git a/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.cpp b/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.cpp new file mode 100644 index 0000000000000..979e5199fe24d --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.cpp @@ -0,0 +1,127 @@ +//===-- ThreadAIXCore.cpp -------------------------------------------------===// +// +// 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 "lldb/Target/RegisterContext.h" +#include "lldb/Target/StopInfo.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/UnixSignals.h" +#include "lldb/Target/Unwind.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/ProcessInfo.h" + +#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h" +#include "Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h" +#include "RegisterContextCoreAIX_ppc64.h" + +#include "ProcessAIXCore.h" +#include "AIXCore.h" +#include "ThreadAIXCore.h" + +#include +#include + +using namespace lldb; +using namespace lldb_private; + +// Construct a Thread object with given data +ThreadAIXCore::ThreadAIXCore(Process &process, const ThreadData &td) + : Thread(process, td.tid), m_thread_name(td.name), m_thread_reg_ctx_sp(), + m_gpregset_data(td.gpregset), + m_siginfo(std::move(td.siginfo)) {} + +ThreadAIXCore::~ThreadAIXCore() { DestroyThread(); } + +void ThreadAIXCore::RefreshStateAfterStop() { + GetRegisterContext()->InvalidateIfNeeded(false); +} + +RegisterContextSP ThreadAIXCore::GetRegisterContext() { + if (!m_reg_context_sp) { + m_reg_context_sp = CreateRegisterContextForFrame(nullptr); + } + return m_reg_context_sp; +} + +RegisterContextSP +ThreadAIXCore::CreateRegisterContextForFrame(StackFrame *frame) { + RegisterContextSP reg_ctx_sp; + uint32_t concrete_frame_idx = 0; + + if (frame) + concrete_frame_idx = frame->GetConcreteFrameIndex(); + + bool is_linux = false; + if (concrete_frame_idx == 0) { + if (m_thread_reg_ctx_sp) + return m_thread_reg_ctx_sp; + + ProcessAIXCore *process = static_cast(GetProcess().get()); + ArchSpec arch = process->GetArchitecture(); + RegisterInfoInterface *reg_interface = nullptr; + + switch (arch.GetMachine()) { + case llvm::Triple::ppc64: + reg_interface = new RegisterInfoPOSIX_ppc64le(arch); + m_thread_reg_ctx_sp = std::make_shared( + *this, reg_interface, m_gpregset_data); + break; + default: + break; + } + reg_ctx_sp = m_thread_reg_ctx_sp; + } else { + reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame); + } + return reg_ctx_sp; +} + +bool ThreadAIXCore::CalculateStopInfo() { + ProcessSP process_sp(GetProcess()); + if (!process_sp) + return false; + + lldb::UnixSignalsSP unix_signals_sp(process_sp->GetUnixSignals()); + if (!unix_signals_sp) + return false; + + const char *sig_description; + std::string description = m_siginfo.GetDescription(*unix_signals_sp); + if (description.empty()) + sig_description = nullptr; + else + sig_description = description.c_str(); + + SetStopInfo(StopInfo::CreateStopReasonWithSignal( + *this, m_siginfo.si_signo, sig_description, m_siginfo.si_code)); + + SetStopInfo(m_stop_info_sp); + return true; +} + +void AIXSigInfo::Parse(const AIXCORE::AIXCore64Header data, const ArchSpec &arch, + const lldb_private::UnixSignals &unix_signals) { + si_signo = data.SignalNum; + sigfault.si_addr = data.Fault.context.pc; +} + +AIXSigInfo::AIXSigInfo() { memset(this, 0, sizeof(AIXSigInfo)); } + +size_t AIXSigInfo::GetSize(const lldb_private::ArchSpec &arch) { + return sizeof(AIXSigInfo); +} + +std::string AIXSigInfo::GetDescription( + const lldb_private::UnixSignals &unix_signals) const { + return unix_signals.GetSignalDescription(si_signo, 0, + sigfault.si_addr); + +} diff --git a/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.h b/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.h new file mode 100644 index 0000000000000..9ee157e9b2b9b --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.h @@ -0,0 +1,110 @@ +//===-- ThreadAIXCore.h -----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_THREADAIXCORE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_THREADAIXCORE_H + +#include "lldb/Target/Thread.h" +#include "lldb/Utility/DataExtractor.h" +#include "llvm/ADT/DenseMap.h" +#include +#include +#include "ProcessAIXCore.h" +#include "AIXCore.h" +#include "ThreadAIXCore.h" + +namespace lldb_private { +class ProcessInstanceInfo; +} + +struct AIXSigInfo { + + //COPY siginfo_t correctly for AIX version + int32_t si_signo; // Order matters for the first 3. + int32_t si_errno; + int32_t si_code; + struct alignas(8) { + lldb::addr_t si_addr; + int16_t si_addr_lsb; + union { + struct { + lldb::addr_t _lower; + lldb::addr_t _upper; + } _addr_bnd; + uint32_t _pkey; + } bounds; + } sigfault; + + enum SigInfoNoteType : uint8_t { eUnspecified, eNT_SIGINFO }; + SigInfoNoteType note_type; + + AIXSigInfo(); + + void Parse(const AIXCORE::AIXCore64Header data, + const lldb_private::ArchSpec &arch, + const lldb_private::UnixSignals &unix_signals); + + std::string + GetDescription(const lldb_private::UnixSignals &unix_signals) const; + + static size_t GetSize(const lldb_private::ArchSpec &arch); +}; + +struct ThreadData { + lldb_private::DataExtractor gpregset; + std::vector notes; + lldb::tid_t tid; + std::string name; + AIXSigInfo siginfo; + int prstatus_sig = 0; +}; + +class ThreadAIXCore : public lldb_private::Thread { +public: + ThreadAIXCore(lldb_private::Process &process, const ThreadData &td); + + ~ThreadAIXCore() override; + + void RefreshStateAfterStop() override; + + lldb::RegisterContextSP GetRegisterContext() override; + + lldb::RegisterContextSP + CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override; + + static bool ThreadIDIsValid(lldb::tid_t thread) { return thread != 0; } + + const char *GetName() override { + if (m_thread_name.empty()) + return nullptr; + return m_thread_name.c_str(); + } + + void SetName(const char *name) override { + if (name && name[0]) + m_thread_name.assign(name); + else + m_thread_name.clear(); + } + + void CreateStopFromSigInfo(const AIXSigInfo &siginfo, + const lldb_private::UnixSignals &unix_signals); + +protected: + // Member variables. + std::string m_thread_name; + lldb::RegisterContextSP m_thread_reg_ctx_sp; + + lldb_private::DataExtractor m_gpregset_data; + std::vector m_notes; + AIXSigInfo m_siginfo; + + bool CalculateStopInfo() override; +}; + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_THREADAIXCORE_H >From 57cb8058646103eeada1f92e039d9c54ccd4788f Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 17 Mar 2025 07:31:26 -0500 Subject: [PATCH 40/49] Merge branch 'llvm:main' into llvmgh-101657 --- lldb/cmake/modules/LLDBConfig.cmake | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake index 312791ce36fc7..9df71edd8b359 100644 --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -292,11 +292,7 @@ endif() # Figure out if lldb could use lldb-server. If so, then we'll # ensure we build lldb-server when an lldb target is being built. -<<<<<<< HEAD -if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD|OpenBSD|Windows|AIX") -======= if (CMAKE_SYSTEM_NAME MATCHES "AIX|Android|Darwin|FreeBSD|Linux|NetBSD|OpenBSD|Windows") ->>>>>>> upstream/main set(LLDB_CAN_USE_LLDB_SERVER ON) else() set(LLDB_CAN_USE_LLDB_SERVER OFF) >From 0767ef036d3f82d1429e04a319feb6627ea08158 Mon Sep 17 00:00:00 2001 From: Dhruv Srivastava Date: Tue, 18 Mar 2025 15:03:17 +0530 Subject: [PATCH 41/49] Error Handling (#32) * Error Handling for aix core module --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 12 +++++++----- .../ObjectFile/AIXCore/ObjectFileAIXCore.cpp | 15 +++++++-------- lldb/source/Plugins/Process/aix-core/AIXCore.cpp | 2 +- .../Plugins/Process/aix-core/ProcessAIXCore.cpp | 11 ++++++++--- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 7e44ffbb1c051..12f24c049f373 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -235,17 +235,19 @@ bool DynamicLoaderAIXDYLD::IsCoreFile() const { void DynamicLoaderAIXDYLD::FillCoreLoaderData(lldb_private::DataExtractor &data, uint64_t loader_offset, uint64_t loader_size ) { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); static char *buffer = (char *)malloc(loader_size); - struct ld_info ldinfo[64]; - char *buffer_complete; + if (buffer == NULL) { + LLDB_LOG(log, "Buffer allocation failed error: {0}", std::strerror(errno)); + return; + } + struct ld_info ldinfo[64] = {}; struct ld_info *ptr; int i = 0; - Log *log = GetLog(LLDBLog::DynamicLoader); - LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); ByteOrder byteorder = data.GetByteOrder(); data.ExtractBytes(loader_offset, loader_size, eByteOrderBig, buffer); - buffer_complete = buffer + loader_size; ldinfo[0].ldinfo_next = 1; while (ldinfo[i++].ldinfo_next != 0) { diff --git a/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp index 5158fa4e25077..0ba1056866937 100644 --- a/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp +++ b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp @@ -73,8 +73,6 @@ ObjectFile *ObjectFileAIXCore::CreateInstance(const lldb::ModuleSP &module_sp, assert(data_sp); - const uint8_t *magic = data_sp->GetBytes() + data_offset; - // Update the data to contain the entire file if it doesn't already if (data_sp->GetByteSize() < length) { data_sp = MapFileDataWritable(*file, length, file_offset); @@ -82,7 +80,6 @@ ObjectFile *ObjectFileAIXCore::CreateInstance(const lldb::ModuleSP &module_sp, return nullptr; data_offset = 0; mapped_writable = true; - magic = data_sp->GetBytes(); } // If we didn't map the data as writable take ownership of the buffer. @@ -90,7 +87,6 @@ ObjectFile *ObjectFileAIXCore::CreateInstance(const lldb::ModuleSP &module_sp, data_sp = std::make_shared(data_sp->GetBytes(), data_sp->GetByteSize()); data_offset = 0; - magic = data_sp->GetBytes(); } std::unique_ptr objfile_up(new ObjectFileAIXCore( @@ -124,19 +120,22 @@ size_t ObjectFileAIXCore::GetModuleSpecifications( return specs.GetSize() - initial_count; } -static uint32_t AIXCoreHeaderCheckFromMagic(uint32_t magic) { +static bool AIXCoreHeaderCheckFromMagic(uint32_t magic) { Log *log = GetLog(LLDBLog::Modules); + bool ret = false; switch (magic) { case AIXCORE32: LLDB_LOGF(log, "ObjectFileAIXCore: 32-bit not supported"); break; case AIXCORE64: m_is_core = true; - return 1; + ret = true; + break; + default: break; } - return 0; + return ret; } bool ObjectFileAIXCore::MagicBytesMatch(DataBufferSP &data_sp, @@ -147,7 +146,7 @@ bool ObjectFileAIXCore::MagicBytesMatch(DataBufferSP &data_sp, lldb::offset_t offset = 0; offset += 4; // Skipping to the coredump version uint32_t magic = data.GetU32(&offset); - return AIXCoreHeaderCheckFromMagic(magic) != 0; + return AIXCoreHeaderCheckFromMagic(magic); } bool ObjectFileAIXCore::ParseHeader() { diff --git a/lldb/source/Plugins/Process/aix-core/AIXCore.cpp b/lldb/source/Plugins/Process/aix-core/AIXCore.cpp index 95e47b4d8be53..bc496b5af273f 100644 --- a/lldb/source/Plugins/Process/aix-core/AIXCore.cpp +++ b/lldb/source/Plugins/Process/aix-core/AIXCore.cpp @@ -110,7 +110,7 @@ bool AIXCore64Header::ParseCoreHeader(lldb_private::DataExtractor &data, ret = ParseThreadContext(data, offset); ret = ParseUserData(data, &offset_to_user); - return true; + return ret; } diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp index 9300aa14ac4db..cfcbe1a216116 100644 --- a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp @@ -208,8 +208,10 @@ Status ProcessAIXCore::DoLoadCore() { exe_module_spec.GetArchitecture() = arch; exe_module_spec.GetFileSpec().SetFile(m_aixcore_header.User.process.pi_comm, FileSpec::Style::native); - exe_module_sp = GetTarget().GetOrCreateModule(exe_module_spec, true); - GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsNo); + exe_module_sp = + GetTarget().GetOrCreateModule(exe_module_spec, true /* notify */); + if (exe_module_sp) + GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsNo); } return error; @@ -232,8 +234,11 @@ void ProcessAIXCore::RefreshStateAfterStop() {} // Process Memory size_t ProcessAIXCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size, Status &error) { + if(addr == LLDB_INVALID_ADDRESS) + return 0; + if (lldb::ABISP abi_sp = GetABI()) - addr = abi_sp->FixAnyAddress(addr); + addr = abi_sp->FixAnyAddress(addr); // Don't allow the caching that lldb_private::Process::ReadMemory does since // in core files we have it all cached our our core file anyway. >From 8214e5d8cc52b486d3c3f5f4615848b1782cfcf8 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 26 Mar 2025 01:34:36 -0500 Subject: [PATCH 42/49] Merge branch 'llvm:main' into gh-101657 --- lldb/source/Host/common/Host.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 575bb46216d19..6cf1112511c3f 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -20,7 +20,6 @@ #include #include #include -#endif #include #endif >From d00d28ae68c731efe6f9392000be9822ee74ff0a Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Wed, 26 Mar 2025 04:08:23 -0500 Subject: [PATCH 43/49] First time attach resolution --- .../Plugins/Process/AIX/NativeProcessAIX.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp index fc84763857453..83b8ae5eb3258 100644 --- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -2000,7 +2000,21 @@ Status NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid, void *addr, } else if (req == PT_WRITE_BLOCK) { ptrace64(req, pid, (long long)addr, (int)data_size, (int *)result); } else if (req == PT_ATTACH) { + // Block SIGCHLD signal during attach to the process, + // to prevent interruptions. + // The ptrace operation may send SIGCHLD signals in certain cases + // during the attach, which can interfere. + static sigset_t signal_set; + sigemptyset (&signal_set); + sigaddset (&signal_set, SIGCHLD); + if(!pthread_sigmask( SIG_BLOCK, &signal_set, NULL)) + LLDB_LOG(log,"NativeProcessAIX::pthread_sigmask(SIG_BLOCK) Failed"); + ptrace64(req, pid, 0, 0, nullptr); + + //Unblocking the SIGCHLD after attach work. + if(!pthread_sigmask( SIG_UNBLOCK, &signal_set, NULL )) + LLDB_LOG(log,"NativeProcessAIX::pthread_sigmask(SIG_UNBLOCK) Failed"); } else if (req == PT_WATCH) { ptrace64(req, pid, (long long)addr, (int)data_size, nullptr); } else if (req == PT_DETACH) { >From 9ff945e62a906e9711022bf8f77b86a0aa05c64e Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Tue, 1 Apr 2025 04:54:51 -0500 Subject: [PATCH 44/49] Invalid DWARF rangelist --- lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index cf11e5fb8f5a3..65bd1ee9781d8 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -578,6 +578,7 @@ SectionType ObjectFileXCOFF::GetSectionType(llvm::StringRef sect_name, .Case(".dwinfo", eSectionTypeDWARFDebugInfo) .Case(".dwline", eSectionTypeDWARFDebugLine) .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev) + .Case(".dwrnges", eSectionTypeDWARFDebugRanges) .Default(eSectionTypeInvalid); if (section_type != eSectionTypeInvalid) >From b443dd5b26354da73cd4d785a093d9d1582b25a8 Mon Sep 17 00:00:00 2001 From: Dhruv Srivastava Date: Wed, 2 Apr 2025 11:57:28 +0530 Subject: [PATCH 45/49] Fix for stack memory access from core file (#40) * Fix for stack memory access in core file --- .../Process/aix-core/ProcessAIXCore.cpp | 74 ++++++++++++++++++- .../Plugins/Process/aix-core/ProcessAIXCore.h | 11 +++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp index cfcbe1a216116..bb2db66e2980e 100644 --- a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp @@ -94,6 +94,33 @@ ProcessAIXCore::~ProcessAIXCore() { Finalize(true /* destructing */); } +lldb::addr_t ProcessAIXCore::AddAddressRanges(AIXCORE::AIXCore64Header header) { + const lldb::addr_t addr = header.StackBaseAddr; + FileRange file_range(header.StackOffset, header.StackSize); + VMRangeToFileOffset::Entry range_entry(addr, header.StackSize, file_range); + + if (header.StackSize > 0) { + VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back(); + if (last_entry && + last_entry->GetRangeEnd() == range_entry.GetRangeBase() && + last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase() && + last_entry->GetByteSize() == last_entry->data.GetByteSize()) { + last_entry->SetRangeEnd(range_entry.GetRangeEnd()); + last_entry->data.SetRangeEnd(range_entry.data.GetRangeEnd()); + } else { + m_core_aranges.Append(range_entry); + } + } + + const uint32_t permissions = lldb::ePermissionsReadable | + lldb::ePermissionsWritable; + + m_core_range_infos.Append( + VMRangeToPermissions::Entry(addr, header.StackSize, permissions)); + + return addr; +} + bool ProcessAIXCore::CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) { @@ -170,6 +197,7 @@ Status ProcessAIXCore::DoLoadCore() { } FileSpec file = m_core_module_sp->GetObjectFile()->GetFileSpec(); + Log *log = GetLog(LLDBLog::Process); if (file) { const size_t header_size = sizeof(AIXCORE::AIXCore64Header); @@ -180,6 +208,9 @@ Status ProcessAIXCore::DoLoadCore() { DataExtractor data(data_sp, lldb::eByteOrderBig, 4); lldb::offset_t data_offset = 0; m_aixcore_header.ParseCoreHeader(data, &data_offset); + lldb::addr_t addr = AddAddressRanges(m_aixcore_header); + if (addr == LLDB_INVALID_ADDRESS) + LLDB_LOGF(log, "ProcessAIXCore: Invalid base address. Stack information will be limited"); auto dyld = static_cast(GetDynamicLoader()); dyld->FillCoreLoaderData(data, m_aixcore_header.LoaderOffset, m_aixcore_header.LoaderSize); @@ -246,7 +277,48 @@ size_t ProcessAIXCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size, } size_t ProcessAIXCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, - Status &error) { return 0; } + Status &error) { + ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); + if (core_objfile == nullptr) + return 0; + // Get the address range + const VMRangeToFileOffset::Entry *address_range = + m_core_aranges.FindEntryThatContains(addr); + if (address_range == nullptr || address_range->GetRangeEnd() < addr) { + error = Status::FromErrorStringWithFormat( + "core file does not contain 0x%" PRIx64, addr); + return 0; + } + + // Convert the address into core file offset + const lldb::addr_t offset = addr - address_range->GetRangeBase(); + const lldb::addr_t file_start = address_range->data.GetRangeBase(); + const lldb::addr_t file_end = address_range->data.GetRangeEnd(); + size_t bytes_to_read = size; // Number of bytes to read from the core file + size_t bytes_copied = 0; // Number of bytes actually read from the core file + // Number of bytes available in the core file from the given address + lldb::addr_t bytes_left = 0; + + // Don't proceed if core file doesn't contain the actual data for this + // address range. + if (file_start == file_end) + return 0; + + // Figure out how many on-disk bytes remain in this segment starting at the + // given offset + if (file_end > file_start + offset) + bytes_left = file_end - (file_start + offset); + + if (bytes_to_read > bytes_left) + bytes_to_read = bytes_left; + + // If there is data available on the core file read it + if (bytes_to_read) + bytes_copied = + core_objfile->CopyData(offset + file_start, bytes_to_read, buf); + + return bytes_copied; +} Status ProcessAIXCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo ®ion_info) { diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h index 9880c491689ca..ffd9e401ee192 100644 --- a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h @@ -85,11 +85,22 @@ class ProcessAIXCore : public lldb_private::PostMortemProcess { void ParseAIXCoreFile(); + lldb::addr_t AddAddressRanges(AIXCORE::AIXCore64Header header); private: lldb::ModuleSP m_core_module_sp; std::string m_dyld_plugin_name; + typedef lldb_private::Range FileRange; + typedef lldb_private::RangeDataVector + VMRangeToFileOffset; + typedef lldb_private::RangeDataVector + VMRangeToPermissions; + + // Address ranges found in the core + VMRangeToFileOffset m_core_aranges; + VMRangeToPermissions m_core_range_infos; + // True if m_thread_contexts contains valid entries bool m_thread_data_valid = false; AIXCORE::AIXCore64Header m_aixcore_header; >From 96db5e3257436a222ee38049528d682166421fa1 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 2 Apr 2025 01:46:46 -0500 Subject: [PATCH 46/49] Build fail: SBMutex --- lldb/source/API/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index 0045edf6743d1..2c8f2d583c054 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -83,6 +83,7 @@ add_lldb_library(liblldb STATIC ${option_framework} SBMemoryRegionInfoList.cpp SBModule.cpp SBModuleSpec.cpp + SBMutex.cpp SBPlatform.cpp SBProcess.cpp SBProgress.cpp >From d7a892ef207cde5430021b8705279cc08dc4e0f7 Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Wed, 30 Apr 2025 04:53:28 -0500 Subject: [PATCH 47/49] Added change for step command issue --- .../Plugins/Process/AIX/NativeProcessAIX.cpp | 87 +++++++++++++------ 1 file changed, 61 insertions(+), 26 deletions(-) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp index 83b8ae5eb3258..ace9e11927bee 100644 --- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -19,7 +19,7 @@ #include #include #include - +#include #include "NativeThreadAIX.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" //#include "Plugins/Process/Utility/LinuxProcMaps.h" @@ -79,6 +79,7 @@ using namespace lldb_private; using namespace lldb_private::process_aix; using namespace llvm; +typedef std::function)> AIXMapCallback; // Private bits we only need internally. static bool ProcessVmReadvSupported() { @@ -988,13 +989,6 @@ Status NativeProcessAIX::GetMemoryRegionInfo(lldb::addr_t load_addr, for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end(); ++it) { MemoryRegionInfo &proc_entry_info = it->first; - - // Sanity check assumption that /proc/{pid}/maps entries are ascending. - assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) && - "descending /proc/pid/maps entries detected, unexpected"); - prev_base_address = proc_entry_info.GetRange().GetRangeBase(); - UNUSED_IF_ASSERT_DISABLED(prev_base_address); - // If the target address comes before this entry, indicate distance to next // region. if (load_addr < proc_entry_info.GetRange().GetRangeBase()) { @@ -1029,9 +1023,59 @@ Status NativeProcessAIX::GetMemoryRegionInfo(lldb::addr_t load_addr, return error; } +// Parsing the AIX map file /proc/PID/map +// The map file contains an array of prmap structures +// which has all the information like size, startaddress, object name, permissions +bool ParseAIXMapRegions(const char *aix_map, AIXMapCallback const &callback) { + MemoryRegionInfo region; + struct prmap *prmapData = (struct prmap *)aix_map; + struct prmap *entry; + uint32_t perm_flag; + + for(entry = prmapData;!(entry->pr_size == 0 && entry->pr_vaddr == NULL); entry++) { + const char *o_name = aix_map + entry->pr_pathoff; + lldb::addr_t start_address = (lldb::addr_t )entry->pr_vaddr; + lldb::addr_t end_address = start_address + entry->pr_size; + region.GetRange().SetRangeBase(start_address); + region.GetRange().SetRangeEnd(end_address); + region.SetMapped(MemoryRegionInfo::OptionalBool::eYes); + perm_flag = entry->pr_mflags; + + if(perm_flag & MA_READ) + region.SetReadable(MemoryRegionInfo::OptionalBool::eYes); + else + region.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + + if(perm_flag & MA_WRITE) + region.SetWritable(MemoryRegionInfo::OptionalBool::eYes); + else + region.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + + if(perm_flag & MA_EXEC) + region.SetExecutable(MemoryRegionInfo::OptionalBool::eYes); + else + region.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + + if((perm_flag & MA_SLIBTEXT) || (perm_flag & MA_SLIBDATA)) + region.SetShared(MemoryRegionInfo::OptionalBool::eYes); + else if ((perm_flag & MA_PLIBTEXT) || (perm_flag & MA_PLIBDATA)) + region.SetShared(MemoryRegionInfo::OptionalBool::eNo); + else + region.SetShared(MemoryRegionInfo::OptionalBool::eDontKnow); + + if(o_name) + region.SetName(o_name); + + callback(region); + region.Clear(); + } + + return true; +} + + Status NativeProcessAIX::PopulateMemoryRegionCache() { Log *log = GetLog(POSIXLog::Process); - // If our cache is empty, pull the latest. There should always be at least // one memory region if memory region handling is supported. if (!m_mem_region_cache.empty()) { @@ -1041,7 +1085,7 @@ Status NativeProcessAIX::PopulateMemoryRegionCache() { } Status Result; -#if 0 + AIXMapCallback callback = [&](llvm::Expected Info) { if (Info) { FileSpec file_spec(Info->GetName().GetCString()); @@ -1050,26 +1094,17 @@ Status NativeProcessAIX::PopulateMemoryRegionCache() { return true; } - Result = Info.takeError(); + Result = Status::FromError(Info.takeError()); m_supports_mem_region = LazyBool::eLazyBoolNo; LLDB_LOG(log, "failed to parse proc maps: {0}", Result); return false; }; - // AIX kernel since 2.6.14 has /proc/{pid}/smaps - // if CONFIG_PROC_PAGE_MONITOR is enabled - auto BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "smaps"); - if (BufferOrError) - ParseAIXSMapRegions(BufferOrError.get()->getBuffer(), callback); - else { - BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "maps"); - if (!BufferOrError) { - m_supports_mem_region = LazyBool::eLazyBoolNo; - return BufferOrError.getError(); - } - - ParseAIXMapRegions(BufferOrError.get()->getBuffer(), callback); - } + auto BufferOrError = getProcFile(GetID(), "map"); + if (BufferOrError) { + std::unique_ptr MapBuffer = std::move(*BufferOrError); + ParseAIXMapRegions(MapBuffer->getBufferStart(), callback); + } if (Result.Fail()) return Result; @@ -1090,7 +1125,7 @@ Status NativeProcessAIX::PopulateMemoryRegionCache() { // We support memory retrieval, remember that. m_supports_mem_region = LazyBool::eLazyBoolYes; -#endif + return Status(); } >From 09e392a16dba25a5a8ddccf7893289a0a8798a3b Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Wed, 14 May 2025 00:52:06 -0500 Subject: [PATCH 48/49] Removing netbsd license dependency --- lldb/source/Host/common/Host.cpp | 165 ++----------------------------- 1 file changed, 7 insertions(+), 158 deletions(-) diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 6cf1112511c3f..7444163366fe5 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -349,168 +349,16 @@ bool Host::ResolveExecutableInBundle(FileSpec &file) { return false; } #include extern char **p_xargv; -/* Fix missing Dl_info & dladdr in AIX - * The code is taken from netbsd.org (src/crypto/external/bsd/openssl/dist/crypto/dso/dso_dlfcn.c) - * except strlcpy & strlcat (those are taken from openbsd.org (src/lib/libc/string)) - */ -/*- - * See IBM's AIX Version 7.2, Technical Reference: - * Base Operating System and Extensions, Volume 1 and 2 - * https://www.ibm.com/support/knowledgecenter/ssw_aix_72/com.ibm.aix.base/technicalreferences.htm - */ -#include -#include - -/* strlcpy: - * Copy string src to buffer dst of size dsize. At most dsize-1 - * chars will be copied. Always NUL terminates (unless dsize == 0). - * Returns strlen(src); if retval >= dsize, truncation occurred. - */ -size_t strlcpy(char *dst, const char *src, size_t dsize) -{ - const char *osrc = src; - size_t nleft = dsize; - - /* Copy as many bytes as will fit. */ - if (nleft != 0) { - while (--nleft != 0) { - if ((*dst++ = *src++) == '\0') { - break; - } - } - } - - /* Not enough room in dst, add NUL and traverse rest of src. */ - if (nleft == 0) { - if (dsize != 0) { - *dst = '\0'; /* NUL-terminate dst */ - } - while (*src++) { - ; - } - } - - return src - osrc - 1; /* count does not include NUL */ -} - -/* strlcat: - * Appends src to string dst of size dsize (unlike strncat, dsize is the - * full size of dst, not space left). At most dsize-1 characters - * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). - * Returns strlen(src) + MIN(dsize, strlen(initial dst)). - * If retval >= dsize, truncation occurred. - */ -size_t strlcat(char *dst, const char *src, size_t dsize) -{ - const char *odst = dst; - const char *osrc = src; - size_t n = dsize; - size_t dlen; - - /* Find the end of dst and adjust bytes left but don't go past end. */ - while (n-- != 0 && *dst != '\0') { - dst++; - } - dlen = dst - odst; - n = dsize - dlen; - - if (n-- == 0) { - return dlen + strlen(src); - } - while (*src != '\0') { - if (n != 0) { - *dst++ = *src; - n--; - } - src++; - } - *dst = '\0'; - - return dlen + src - osrc; /* count does not include NUL */ -} - -/* ~ 64 * (sizeof(struct ld_info) + _XOPEN_PATH_MAX + _XOPEN_NAME_MAX) */ -# define DLFCN_LDINFO_SIZE 86976 -typedef struct Dl_info { - const char *dli_fname; -} Dl_info; -/* - * This dladdr()-implementation will also find the ptrgl (Pointer Glue) virtual - * address of a function, which is just located in the DATA segment instead of - * the TEXT segment. - */ -static int dladdr(const void *ptr, Dl_info *dl) -{ - uintptr_t addr = (uintptr_t)ptr; - struct ld_info *ldinfos; - struct ld_info *next_ldi; - struct ld_info *this_ldi; - - if ((ldinfos = (struct ld_info *)malloc(DLFCN_LDINFO_SIZE)) == NULL) { - dl->dli_fname = NULL; - return 0; - } - - if ((loadquery(L_GETINFO, (void *)ldinfos, DLFCN_LDINFO_SIZE)) < 0) { - /*- - * Error handling is done through errno and dlerror() reading errno: - * ENOMEM (ldinfos buffer is too small), - * EINVAL (invalid flags), - * EFAULT (invalid ldinfos ptr) - */ - free((void *)ldinfos); - dl->dli_fname = NULL; - return 0; - } - next_ldi = ldinfos; - - do { - this_ldi = next_ldi; - if (((addr >= (uintptr_t)this_ldi->ldinfo_textorg) - && (addr < ((uintptr_t)this_ldi->ldinfo_textorg + - this_ldi->ldinfo_textsize))) - || ((addr >= (uintptr_t)this_ldi->ldinfo_dataorg) - && (addr < ((uintptr_t)this_ldi->ldinfo_dataorg + - this_ldi->ldinfo_datasize)))) { - char *buffer = NULL; - char *member = NULL; - size_t buffer_sz; - size_t member_len; - - buffer_sz = strlen(this_ldi->ldinfo_filename) + 1; - member = this_ldi->ldinfo_filename + buffer_sz; - if ((member_len = strlen(member)) > 0) { - buffer_sz += 1 + member_len + 1; - } - if ((buffer = (char *)malloc(buffer_sz)) != NULL) { - strlcpy(buffer, this_ldi->ldinfo_filename, buffer_sz); - if (member_len > 0) { - /* - * Need to respect a possible member name and not just - * returning the path name in this case. See docs: - * sys/ldr.h, loadquery() and dlopen()/RTLD_MEMBER. - */ - strlcat(buffer, "(", buffer_sz); - strlcat(buffer, member, buffer_sz); - strlcat(buffer, ")", buffer_sz); - } - dl->dli_fname = buffer; - } - break; - } else { - next_ldi = (struct ld_info *)((uintptr_t)this_ldi + - this_ldi->ldinfo_next); - } - } while (this_ldi->ldinfo_next); - free((void *)ldinfos); - return dl->dli_fname != NULL; -} - #endif FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSpec module_filespec; #ifdef _AIX + // TODO: As the current AIX LLDB is static, we don't need dladdr which is + // only for shared library, Below is the hack to find the module name + // for static LLDB + // FIXME: If LLDB is later built as shared library, we have to find the way simillar to dladdr + // since AIX does not support the dladdr API. if (host_addr == reinterpret_cast(HostInfoBase::ComputeSharedLibraryDirectory)) { // FIXME: AIX dladdr return "lldb" for this case if (p_xargv[0]) { @@ -519,7 +367,7 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { return module_filespec; } } -#endif +#else #if !defined(__ANDROID__) Dl_info info; if (::dladdr(host_addr, &info)) { @@ -528,6 +376,7 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSystem::Instance().Resolve(module_filespec); } } +#endif #endif return module_filespec; } >From b158b8788fa6bf0e13d02373ce9de0d62a4a6aba Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Fri, 16 May 2025 00:51:25 -0500 Subject: [PATCH 49/49] Removed netbsd license files --- lldb/NOTICE.TXT | 7 - .../source/Host/common/LICENSE.aix-netbsd.txt | 125 ------------------ 2 files changed, 132 deletions(-) delete mode 100644 lldb/NOTICE.TXT delete mode 100644 lldb/source/Host/common/LICENSE.aix-netbsd.txt diff --git a/lldb/NOTICE.TXT b/lldb/NOTICE.TXT deleted file mode 100644 index d814272967476..0000000000000 --- a/lldb/NOTICE.TXT +++ /dev/null @@ -1,7 +0,0 @@ - -This product contains small piece of code to support AIX, taken from netbsd. - - * LICENSE: - * lldb/source/Host/common/LICENSE.aix-netbsd.txt (OpenSSL License) - * HOMEPAGE: - * https://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/crypto/external/bsd/openssl/dist diff --git a/lldb/source/Host/common/LICENSE.aix-netbsd.txt b/lldb/source/Host/common/LICENSE.aix-netbsd.txt deleted file mode 100644 index 9601ab43575f9..0000000000000 --- a/lldb/source/Host/common/LICENSE.aix-netbsd.txt +++ /dev/null @@ -1,125 +0,0 @@ - - LICENSE ISSUES - ============== - - The OpenSSL toolkit stays under a double license, i.e. both the conditions of - the OpenSSL License and the original SSLeay license apply to the toolkit. - See below for the actual license texts. - - OpenSSL License - --------------- - -/* ==================================================================== - * Copyright (c) 1998-2019 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core at openssl.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.openssl.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay at cryptsoft.com). This product includes software written by Tim - * Hudson (tjh at cryptsoft.com). - * - */ - - Original SSLeay License - ----------------------- - -/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay at cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh at cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay at cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh at cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ - From lldb-commits at lists.llvm.org Thu May 15 23:26:23 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Thu, 15 May 2025 23:26:23 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb]Make `list` command work with headers when possible. (PR #139002) In-Reply-To: Message-ID: <6826da8f.170a0220.3fb8c.434e@mx.google.com> ================ @@ -1113,17 +1123,25 @@ class CommandObjectSourceList : public CommandObjectParsed { ModuleSpec module_spec(module_file_spec); matching_modules.Clear(); target.GetImages().FindModules(module_spec, matching_modules); - num_matches += matching_modules.ResolveSymbolContextForFilePath( - filename, 0, check_inlines, + FileSpec file_spec(filename); + re_compute_check_inlines(file_spec); ---------------- labath wrote: What's up why the lambda? Is there any reason to not compute this directly on line 1105? AFAICT, nothing between here and there affects the computed result. https://github.com/llvm/llvm-project/pull/139002 From lldb-commits at lists.llvm.org Thu May 15 23:26:30 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Thu, 15 May 2025 23:26:30 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb]Make `list` command work with headers when possible. (PR #139002) In-Reply-To: Message-ID: <6826da96.170a0220.1bdfbf.3fe2@mx.google.com> https://github.com/labath edited https://github.com/llvm/llvm-project/pull/139002 From lldb-commits at lists.llvm.org Fri May 16 00:12:07 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Fri, 16 May 2025 00:12:07 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <6826e547.170a0220.1e52b1.78bd@mx.google.com> ================ @@ -111,7 +111,42 @@ ASTNodeUP DILParser::ParseUnaryExpression() { llvm_unreachable("invalid token kind"); } } - return ParsePrimaryExpression(); + return ParsePostfixExpression(); +} + +// Parse a postfix_expression. +// +// postfix_expression: +// primary_expression +// postfix_expression "[" integer_literal "]" +// +ASTNodeUP DILParser::ParsePostfixExpression() { + ASTNodeUP lhs = ParsePrimaryExpression(); + while (CurToken().Is(Token::l_square)) { + uint32_t loc = CurToken().GetLocation(); + Token token = CurToken(); + switch (token.GetKind()) { + case Token::l_square: { + m_dil_lexer.Advance(); + auto rhs = ParseIntegerConstant(); ---------------- labath wrote: LLVM generally has a very cautious stance towards auto: https://llvm.org/docs/CodingStandards.html#use-auto-type-deduction-to-make-code-more-readable In this case, the type of rhs is not obvious from the immediate, and for the correctness of the code, it is important to know whether the function returns `int`, `optional`, `Expected` or something else. https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Fri May 16 00:12:15 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Fri, 16 May 2025 00:12:15 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <6826e54f.170a0220.e42cb.4720@mx.google.com> https://github.com/labath edited https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Fri May 16 00:54:56 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 00:54:56 -0700 (PDT) Subject: [Lldb-commits] [lldb] Fix race condition during iteration through modules (#139283) (PR #139862) In-Reply-To: Message-ID: <6826ef50.170a0220.4398b.52e8@mx.google.com> nd wrote: Sorry, I haven't read the LLVM GitHub user guide before submitting the PR and didn't realize that force pushes are to be avoided. Please let me know if I need to rework the request somehow. https://github.com/llvm/llvm-project/pull/139862 From lldb-commits at lists.llvm.org Fri May 16 01:48:28 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Fri, 16 May 2025 01:48:28 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Added 32-bit XCOFF Executable support (PR #139875) In-Reply-To: Message-ID: <6826fbdc.630a0220.29c3e1.9960@mx.google.com> https://github.com/labath edited https://github.com/llvm/llvm-project/pull/139875 From lldb-commits at lists.llvm.org Fri May 16 01:48:28 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Fri, 16 May 2025 01:48:28 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Added 32-bit XCOFF Executable support (PR #139875) In-Reply-To: Message-ID: <6826fbdc.170a0220.33cc7b.4595@mx.google.com> ================ @@ -97,14 +97,26 @@ class ObjectFileXCOFF : public lldb_private::ObjectFile { lldb::DataBufferSP header_data_sp, const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + struct XCOFF32 { + using SectionHeader = llvm::object::XCOFFSectionHeader32; + static constexpr bool Is64Bit = false; + }; + struct XCOFF64 { + using SectionHeader = llvm::object::XCOFFSectionHeader64; + static constexpr bool Is64Bit = true; + }; + + template + void + CreateSectionsWithBitness(lldb_private::SectionList &unified_section_list); + ---------------- labath wrote: Could this be `private:` ? https://github.com/llvm/llvm-project/pull/139875 From lldb-commits at lists.llvm.org Fri May 16 01:48:28 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Fri, 16 May 2025 01:48:28 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Added 32-bit XCOFF Executable support (PR #139875) In-Reply-To: Message-ID: <6826fbdc.170a0220.15105f.166e@mx.google.com> ================ @@ -191,20 +193,36 @@ void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) {} bool ObjectFileXCOFF::IsStripped() { return false; } void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) { + if (m_sections_up) return; m_sections_up = std::make_unique(); - ModuleSP module_sp(GetModule()); + if (m_binary->is64Bit()) + CreateSectionsWithBitness(unified_section_list); + else + CreateSectionsWithBitness(unified_section_list); +} +template auto GetSections(llvm::object::XCOFFObjectFile *binary) { ---------------- labath wrote: ```suggestion template static auto GetSections(llvm::object::XCOFFObjectFile *binary) { ``` https://github.com/llvm/llvm-project/pull/139875 From lldb-commits at lists.llvm.org Fri May 16 01:48:29 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Fri, 16 May 2025 01:48:29 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Added 32-bit XCOFF Executable support (PR #139875) In-Reply-To: Message-ID: <6826fbdd.170a0220.f5784.4573@mx.google.com> https://github.com/labath approved this pull request. Looks fine. Ship it. https://github.com/llvm/llvm-project/pull/139875 From lldb-commits at lists.llvm.org Fri May 16 02:01:49 2025 From: lldb-commits at lists.llvm.org (David Spickett via lldb-commits) Date: Fri, 16 May 2025 02:01:49 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AArch64] Fix Apple M4 on Linux (PR #135563) In-Reply-To: Message-ID: <6826fefd.a70a0220.0854.5644@mx.google.com> DavidSpickett wrote: I think there are kernel issues that need to be fixed before all the LLDB features can work. So don't waste your own time on this right now, I will coordinate with Arm's kernel team to get this working. https://github.com/llvm/llvm-project/pull/135563 From lldb-commits at lists.llvm.org Fri May 16 02:16:14 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Fri, 16 May 2025 02:16:14 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Retcon SBValue::GetChildAtIndex(synthetic=true) (PR #140065) In-Reply-To: Message-ID: <6827025e.170a0220.99be3.4bd4@mx.google.com> https://github.com/labath updated https://github.com/llvm/llvm-project/pull/140065 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Fri May 16 02:16:28 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Fri, 16 May 2025 02:16:28 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Retcon SBValue::GetChildAtIndex(synthetic=true) (PR #140065) In-Reply-To: Message-ID: <6827026c.050a0220.2af1d7.5649@mx.google.com> ================ @@ -193,7 +188,7 @@ class LLDB_API SBValue { /// and also if the target can be run to figure out the dynamic /// type of the child value. /// - /// \param[in] can_create_synthetic + /// \param[in] use_synthetic ---------------- labath wrote: Sounds good. I wasn't too happy with the name myself. https://github.com/llvm/llvm-project/pull/140065 From lldb-commits at lists.llvm.org Fri May 16 02:40:23 2025 From: lldb-commits at lists.llvm.org (Pavel Labath via lldb-commits) Date: Fri, 16 May 2025 02:40:23 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Call Target::ClearAllLoadedSections even earlier (PR #140228) Message-ID: https://github.com/labath created https://github.com/llvm/llvm-project/pull/140228 This reapplies https://github.com/llvm/llvm-project/pull/138892, which was reverted in https://github.com/llvm/llvm-project/commit/5fb9dca14aeaf12219ff149bf3a4f94c8dc58d8b due to failures on windows. Windows loads modules from the Process class, and it does that quite early, and it kinda makes sense which is why I'm moving the clearing code even earlier. The original commit message was: Minidump files contain explicit information about load addresses of modules, so it can load them itself. This works on other platforms, but fails on darwin because DynamicLoaderDarwin nukes the loaded module list on initialization (which happens after the core file plugin has done its work). This used to work until https://github.com/llvm/llvm-project/pull/109477, which enabled the dynamic loader plugins for minidump files in order to get them to provide access to TLS. Clearing the load list makes sense, but I think we could do it earlier in the process, so that both Process and DynamicLoader plugins get a chance to load modules. This patch does that by calling the function early in the launch/attach/load core flows. This fixes TestDynamicValue.py:test_from_core_file on darwin. >From 438daf635e8d57cdd9cf854c505ec9a434d11358 Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Wed, 14 May 2025 11:16:55 +0200 Subject: [PATCH 1/2] [lldb] Call Target::ClearAllLoadedSections earlier (#138892) Minidump files contain explicit information about load addresses of modules, so it can load them itself. This works on other platforms, but fails on darwin because DynamicLoaderDarwin nukes the loaded module list on initialization (which happens after the core file plugin has done its work). This used to work until #109477, which enabled the dynamic loader plugins for minidump files in order to get them to provide access to TLS. Clearing the load list makes sense, but I think we could do it earlier in the process, so that both Process and DynamicLoader plugins get a chance to load modules. This patch does that by calling the function early in the launch/attach/load core flows. This fixes TestDynamicValue.py:test_from_core_file on darwin. --- .../Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp | 1 - lldb/source/Target/Process.cpp | 4 ++++ lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py | 1 - 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp index 578ab12268ea3..1270d57423c7b 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp @@ -872,7 +872,6 @@ void DynamicLoaderDarwin::PrivateInitialize(Process *process) { StateAsCString(m_process->GetState())); Clear(true); m_process = process; - m_process->GetTarget().ClearAllLoadedSections(); } // Member function that gets called when the process state changes. diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 13ff12b4ff953..7c5512598bbb6 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -2763,6 +2763,7 @@ Status Process::LaunchPrivate(ProcessLaunchInfo &launch_info, StateType &state, } if (state == eStateStopped || state == eStateCrashed) { + GetTarget().ClearAllLoadedSections(); DidLaunch(); // Now that we know the process type, update its signal responses from the @@ -2799,6 +2800,7 @@ Status Process::LaunchPrivate(ProcessLaunchInfo &launch_info, StateType &state, } Status Process::LoadCore() { + GetTarget().ClearAllLoadedSections(); Status error = DoLoadCore(); if (error.Success()) { ListenerSP listener_sp( @@ -3094,6 +3096,8 @@ void Process::CompleteAttach() { Log *log(GetLog(LLDBLog::Process | LLDBLog::Target)); LLDB_LOGF(log, "Process::%s()", __FUNCTION__); + GetTarget().ClearAllLoadedSections(); + // Let the process subclass figure out at much as it can about the process // before we go looking for a dynamic loader plug-in. ArchSpec process_arch; diff --git a/lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py b/lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py index cd95a9ff3fe8c..faa35421ff60b 100644 --- a/lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py +++ b/lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py @@ -282,7 +282,6 @@ def test_from_forward_decl(self): @no_debug_info_test @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24663") - @expectedFailureDarwin # dynamic loader unloads modules @expectedFailureAll(archs=["arm"]) # Minidump saving not implemented def test_from_core_file(self): """Test fetching C++ dynamic values from core files. Specifically, test >From 9d6d2807284802e8b722b012c4b5b67a8be9ecba Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Fri, 16 May 2025 11:17:25 +0200 Subject: [PATCH 2/2] [lldb] Call Target::ClearAllLoadedSections even earlier This reapplies #138892, which was reverted in 5fb9dca14aeaf12219ff149bf3a4f94c8dc58d8b due to failures on windows. Windows loads modules from the Process class, and it does that quite early, and it kinda makes sense which is why I'm moving the clearing code even earlier. --- lldb/source/Target/Process.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 7c5512598bbb6..c377feec86c16 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -2675,6 +2675,7 @@ Status Process::LaunchPrivate(ProcessLaunchInfo &launch_info, StateType &state, m_jit_loaders_up.reset(); m_system_runtime_up.reset(); m_os_up.reset(); + GetTarget().ClearAllLoadedSections(); { std::lock_guard guard(m_process_input_reader_mutex); @@ -2763,7 +2764,6 @@ Status Process::LaunchPrivate(ProcessLaunchInfo &launch_info, StateType &state, } if (state == eStateStopped || state == eStateCrashed) { - GetTarget().ClearAllLoadedSections(); DidLaunch(); // Now that we know the process type, update its signal responses from the @@ -2986,6 +2986,7 @@ Status Process::Attach(ProcessAttachInfo &attach_info) { m_jit_loaders_up.reset(); m_system_runtime_up.reset(); m_os_up.reset(); + GetTarget().ClearAllLoadedSections(); lldb::pid_t attach_pid = attach_info.GetProcessID(); Status error; @@ -3096,8 +3097,6 @@ void Process::CompleteAttach() { Log *log(GetLog(LLDBLog::Process | LLDBLog::Target)); LLDB_LOGF(log, "Process::%s()", __FUNCTION__); - GetTarget().ClearAllLoadedSections(); - // Let the process subclass figure out at much as it can about the process // before we go looking for a dynamic loader plug-in. ArchSpec process_arch; From lldb-commits at lists.llvm.org Fri May 16 02:40:59 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 02:40:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Call Target::ClearAllLoadedSections even earlier (PR #140228) In-Reply-To: Message-ID: <6827082b.170a0220.25653b.48e8@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Pavel Labath (labath)
Changes This reapplies https://github.com/llvm/llvm-project/pull/138892, which was reverted in https://github.com/llvm/llvm-project/commit/5fb9dca14aeaf12219ff149bf3a4f94c8dc58d8b due to failures on windows. Windows loads modules from the Process class, and it does that quite early, and it kinda makes sense which is why I'm moving the clearing code even earlier. The original commit message was: Minidump files contain explicit information about load addresses of modules, so it can load them itself. This works on other platforms, but fails on darwin because DynamicLoaderDarwin nukes the loaded module list on initialization (which happens after the core file plugin has done its work). This used to work until https://github.com/llvm/llvm-project/pull/109477, which enabled the dynamic loader plugins for minidump files in order to get them to provide access to TLS. Clearing the load list makes sense, but I think we could do it earlier in the process, so that both Process and DynamicLoader plugins get a chance to load modules. This patch does that by calling the function early in the launch/attach/load core flows. This fixes TestDynamicValue.py:test_from_core_file on darwin. --- Full diff: https://github.com/llvm/llvm-project/pull/140228.diff 3 Files Affected: - (modified) lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp (-1) - (modified) lldb/source/Target/Process.cpp (+3) - (modified) lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py (-1) ``````````diff diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp index 578ab12268ea3..1270d57423c7b 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp @@ -872,7 +872,6 @@ void DynamicLoaderDarwin::PrivateInitialize(Process *process) { StateAsCString(m_process->GetState())); Clear(true); m_process = process; - m_process->GetTarget().ClearAllLoadedSections(); } // Member function that gets called when the process state changes. diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 13ff12b4ff953..c377feec86c16 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -2675,6 +2675,7 @@ Status Process::LaunchPrivate(ProcessLaunchInfo &launch_info, StateType &state, m_jit_loaders_up.reset(); m_system_runtime_up.reset(); m_os_up.reset(); + GetTarget().ClearAllLoadedSections(); { std::lock_guard guard(m_process_input_reader_mutex); @@ -2799,6 +2800,7 @@ Status Process::LaunchPrivate(ProcessLaunchInfo &launch_info, StateType &state, } Status Process::LoadCore() { + GetTarget().ClearAllLoadedSections(); Status error = DoLoadCore(); if (error.Success()) { ListenerSP listener_sp( @@ -2984,6 +2986,7 @@ Status Process::Attach(ProcessAttachInfo &attach_info) { m_jit_loaders_up.reset(); m_system_runtime_up.reset(); m_os_up.reset(); + GetTarget().ClearAllLoadedSections(); lldb::pid_t attach_pid = attach_info.GetProcessID(); Status error; diff --git a/lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py b/lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py index cd95a9ff3fe8c..faa35421ff60b 100644 --- a/lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py +++ b/lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py @@ -282,7 +282,6 @@ def test_from_forward_decl(self): @no_debug_info_test @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24663") - @expectedFailureDarwin # dynamic loader unloads modules @expectedFailureAll(archs=["arm"]) # Minidump saving not implemented def test_from_core_file(self): """Test fetching C++ dynamic values from core files. Specifically, test ``````````
https://github.com/llvm/llvm-project/pull/140228 From lldb-commits at lists.llvm.org Fri May 16 03:27:52 2025 From: lldb-commits at lists.llvm.org (=?UTF-8?Q?Martin_Storsj=C3=B6?= via lldb-commits) Date: Fri, 16 May 2025 03:27:52 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AArch64] Fix Apple M4 on Linux (PR #135563) In-Reply-To: Message-ID: <68271328.170a0220.22a28a.4df1@mx.google.com> mstorsjo wrote: > > Therefore, this situation should only be an issue with older kernels, so perhaps it not something that regular user mode applications should need to worry about (unless specifically wanting to run with older kernels). > > I will test this PR with an older kernel as well. Would be nice if it works there too. Did you manage to test things with an older kernel, at least on the level of what hwcaps are presented - to confirm you'd get the inconsistent hwcaps in that case (sve2 enabled, sve1 disabled)? https://github.com/llvm/llvm-project/pull/135563 From lldb-commits at lists.llvm.org Fri May 16 03:53:39 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Fri, 16 May 2025 03:53:39 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Added 32-bit XCOFF Executable support (PR #139875) In-Reply-To: Message-ID: <68271933.170a0220.18d9da.4cea@mx.google.com> https://github.com/DhruvSrivastavaX updated https://github.com/llvm/llvm-project/pull/139875 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Fri May 16 05:10:17 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 05:10:17 -0700 (PDT) Subject: [Lldb-commits] [lldb] c02e6ca - [lldb][AIX] Added 32-bit XCOFF Executable support (#139875) Message-ID: <68272b29.170a0220.125567.57c3@mx.google.com> Author: Dhruv Srivastava Date: 2025-05-16T17:40:13+05:30 New Revision: c02e6ca3b3ea84566800043bb4c29c67eb63f223 URL: https://github.com/llvm/llvm-project/commit/c02e6ca3b3ea84566800043bb4c29c67eb63f223 DIFF: https://github.com/llvm/llvm-project/commit/c02e6ca3b3ea84566800043bb4c29c67eb63f223.diff LOG: [lldb][AIX] Added 32-bit XCOFF Executable support (#139875) This PR is in reference to porting LLDB on AIX. Link to discussions on llvm discourse and github: 1. https://discourse.llvm.org/t/port-lldb-to-ibm-aix/80640 2. https://github.com/llvm/llvm-project/issues/101657 The complete changes for porting are present in this draft PR: https://github.com/llvm/llvm-project/pull/102601 **Description:** Adding support for XCOFF 32 bit file format as well in lldb, up to the point where 64-bit support is implemented. Added a new test case for the same. This is an incremental PR on top of the previous couple of XCOFF support commits. Added: lldb/test/Shell/ObjectFile/XCOFF/basic-info32.yaml Modified: lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h Removed: ################################################################################ diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index 1666677c360ba..e629355cd40b9 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -39,7 +39,6 @@ using namespace lldb; using namespace lldb_private; LLDB_PLUGIN_DEFINE(ObjectFileXCOFF) - // FIXME: target 64bit at this moment. // Static methods. @@ -95,10 +94,11 @@ bool ObjectFileXCOFF::CreateBinary() { Log *log = GetLog(LLDBLog::Object); - auto binary = llvm::object::ObjectFile::createObjectFile( - llvm::MemoryBufferRef(toStringRef(m_data.GetData()), - m_file.GetFilename().GetStringRef()), - file_magic::xcoff_object_64); + auto memory_ref = llvm::MemoryBufferRef(toStringRef(m_data.GetData()), + m_file.GetFilename().GetStringRef()); + llvm::file_magic magic = llvm::identify_magic(memory_ref.getBuffer()); + + auto binary = llvm::object::ObjectFile::createObjectFile(memory_ref, magic); if (!binary) { LLDB_LOG_ERROR(log, binary.takeError(), "Failed to create binary for file ({1}): {0}", m_file); @@ -143,9 +143,9 @@ size_t ObjectFileXCOFF::GetModuleSpecifications( static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) { switch (magic) { - // TODO: 32bit not supported. - // case XCOFF::XCOFF32: - // return sizeof(struct llvm::object::XCOFFFileHeader32); + case XCOFF::XCOFF32: + return sizeof(struct llvm::object::XCOFFFileHeader32); + break; case XCOFF::XCOFF64: return sizeof(struct llvm::object::XCOFFFileHeader64); break; @@ -169,8 +169,9 @@ bool ObjectFileXCOFF::MagicBytesMatch(DataBufferSP &data_sp, } bool ObjectFileXCOFF::ParseHeader() { - // Only 64-bit is supported for now - return m_binary->fileHeader64()->Magic == XCOFF::XCOFF64; + if (m_binary->is64Bit()) + return m_binary->fileHeader64()->Magic == XCOFF::XCOFF64; + return m_binary->fileHeader32()->Magic == XCOFF::XCOFF32; } ByteOrder ObjectFileXCOFF::GetByteOrder() const { return eByteOrderBig; } @@ -178,8 +179,9 @@ ByteOrder ObjectFileXCOFF::GetByteOrder() const { return eByteOrderBig; } bool ObjectFileXCOFF::IsExecutable() const { return true; } uint32_t ObjectFileXCOFF::GetAddressByteSize() const { - // 32-bit not supported. return 8 for 64-bit XCOFF::XCOFF64 - return 8; + if (m_binary->is64Bit()) + return 8; + return 4; } AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) { @@ -191,20 +193,37 @@ void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) {} bool ObjectFileXCOFF::IsStripped() { return false; } void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) { + if (m_sections_up) return; m_sections_up = std::make_unique(); - ModuleSP module_sp(GetModule()); + if (m_binary->is64Bit()) + CreateSectionsWithBitness(unified_section_list); + else + CreateSectionsWithBitness(unified_section_list); +} +template +static auto GetSections(llvm::object::XCOFFObjectFile *binary) { + if constexpr (T::Is64Bit) + return binary->sections64(); + else + return binary->sections32(); +} + +template +void ObjectFileXCOFF::CreateSectionsWithBitness( + SectionList &unified_section_list) { + ModuleSP module_sp(GetModule()); if (!module_sp) return; std::lock_guard guard(module_sp->GetMutex()); int idx = 0; - for (const llvm::object::XCOFFSectionHeader64 §ion : - m_binary->sections64()) { + for (const typename T::SectionHeader §ion : + GetSections(m_binary.get())) { ConstString const_sect_name(section.Name); @@ -253,9 +272,13 @@ UUID ObjectFileXCOFF::GetUUID() { return UUID(); } uint32_t ObjectFileXCOFF::GetDependentModules(FileSpecList &files) { return 0; } ObjectFile::Type ObjectFileXCOFF::CalculateType() { - if (m_binary->fileHeader64()->Flags & XCOFF::F_EXEC) + + const auto flags = m_binary->is64Bit() ? m_binary->fileHeader64()->Flags + : m_binary->fileHeader32()->Flags; + + if (flags & XCOFF::F_EXEC) return eTypeExecutable; - else if (m_binary->fileHeader64()->Flags & XCOFF::F_SHROBJ) + else if (flags & XCOFF::F_SHROBJ) return eTypeSharedLibrary; return eTypeUnknown; } diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h index 2d4f9f3f2dab8..2cecd0315463a 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h @@ -104,6 +104,18 @@ class ObjectFileXCOFF : public lldb_private::ObjectFile { private: bool CreateBinary(); + template + void + CreateSectionsWithBitness(lldb_private::SectionList &unified_section_list); + + struct XCOFF32 { + using SectionHeader = llvm::object::XCOFFSectionHeader32; + static constexpr bool Is64Bit = false; + }; + struct XCOFF64 { + using SectionHeader = llvm::object::XCOFFSectionHeader64; + static constexpr bool Is64Bit = true; + }; std::unique_ptr m_binary; }; diff --git a/lldb/test/Shell/ObjectFile/XCOFF/basic-info32.yaml b/lldb/test/Shell/ObjectFile/XCOFF/basic-info32.yaml new file mode 100644 index 0000000000000..dd1569fe52994 --- /dev/null +++ b/lldb/test/Shell/ObjectFile/XCOFF/basic-info32.yaml @@ -0,0 +1,110 @@ +# RUN: yaml2obj %s -o %t +# RUN: lldb-test object-file %t | FileCheck %s + +# CHECK: Plugin name: xcoff +# CHECK: Architecture: powerpc64-ibm-aix +# CHECK: Executable: true +# CHECK: Stripped: false +# CHECK: Type: executable +# CHECK: Strata: unknown +# CHECK: Name: .text +# CHECK-NEXT: Type: code +# CHECK-NEXT: Permissions: r-x +# CHECK: Name: .data +# CHECK-NEXT: Type: data +# CHECK-NEXT: Permissions: rw- +# CHECK: Name: .bss +# CHECK-NEXT: Type: zero-fill +# CHECK-NEXT: Permissions: rw- +# CHECK: Name: .loader +# CHECK-NEXT: Type: regular +# CHECK-NEXT: Permissions: r-- +# CHECK: Name: .dwline +# CHECK-NEXT: Type: dwarf-line +# CHECK-NEXT: Permissions: r-- +# CHECK: Name: .dwinfo +# CHECK-NEXT: Type: dwarf-info +# CHECK-NEXT: Permissions: r-- +# CHECK: Name: .dwabrev +# CHECK-NEXT: Type: dwarf-abbrev +# CHECK-NEXT: Permissions: r-- + +--- !XCOFF +FileHeader: + MagicNumber: 0x1DF + NumberOfSections: 7 + CreationTime: 000000000 + Flags: 0x1002 +Sections: + - Name: .text + Address: 0x10000268 + Size: 0x512 + FileOffsetToData: 0x268 + FileOffsetToRelocations: 0xECC + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x24 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_TEXT ] + SectionData: 80C20000 + - Name: .data + Address: 0x2000077A + Size: 0x242 + FileOffsetToData: 0x77A + FileOffsetToRelocations: 0x1034 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x25 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_DATA ] + SectionData: '' + - Name: .bss + Address: 0x200009BC + Size: 0x10 + FileOffsetToData: 0x0 + FileOffsetToRelocations: 0x0 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x0 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_BSS ] + SectionData: '' + - Name: .loader + Address: 0x0 + Size: 0x3A4 + FileOffsetToData: 0x9BC + FileOffsetToRelocations: 0x0 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x0 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_LOADER ] + SectionData: 00000001 + - Name: .dwline + Address: 0x0 + Size: 0x73 + FileOffsetToData: 0xD60 + FileOffsetToRelocations: 0x11A6 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x5 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_DWARF ] + SectionData: FFFFFFFF + - Name: .dwinfo + Address: 0x0 + Size: 0xB4 + FileOffsetToData: 0xDD4 + FileOffsetToRelocations: 0x11D8 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x6 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_DWARF ] + SectionData: FFFFFFFF + - Name: .dwabrev + Address: 0x0 + Size: 0x43 + FileOffsetToData: 0xE88 + FileOffsetToRelocations: 0x0 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x0 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_DWARF ] + SectionData: 01110125 +StringTable: {} +... From lldb-commits at lists.llvm.org Fri May 16 05:10:21 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Fri, 16 May 2025 05:10:21 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][AIX] Added 32-bit XCOFF Executable support (PR #139875) In-Reply-To: Message-ID: <68272b2d.170a0220.1b54b6.64d2@mx.google.com> https://github.com/DhruvSrivastavaX closed https://github.com/llvm/llvm-project/pull/139875 From lldb-commits at lists.llvm.org Fri May 16 05:19:35 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Fri, 16 May 2025 05:19:35 -0700 (PDT) Subject: [Lldb-commits] [lldb] Extending LLDB to work on AIX (PR #102601) In-Reply-To: Message-ID: <68272d57.620a0220.3f70e.645b@mx.google.com> https://github.com/DhruvSrivastavaX updated https://github.com/llvm/llvm-project/pull/102601 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Fri May 16 05:36:33 2025 From: lldb-commits at lists.llvm.org (Dhruv Srivastava via lldb-commits) Date: Fri, 16 May 2025 05:36:33 -0700 (PDT) Subject: [Lldb-commits] [lldb] Extending LLDB to work on AIX (PR #102601) In-Reply-To: Message-ID: <68273151.630a0220.3a971c.a256@mx.google.com> https://github.com/DhruvSrivastavaX updated https://github.com/llvm/llvm-project/pull/102601 >From 39d395f75c306a0d932a783eef039fd93d66e246 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 7 Aug 2024 12:10:43 -0500 Subject: [PATCH 01/50] LLDB Support for AIX --- clang/lib/CodeGen/CGObjCMac.cpp | 6 +- lldb/CMakeLists.txt | 4 + lldb/cmake/modules/LLDBConfig.cmake | 2 +- lldb/include/lldb/Core/Module.h | 3 + lldb/include/lldb/Core/ModuleSpec.h | 23 +- lldb/include/lldb/Host/HostGetOpt.h | 2 +- lldb/include/lldb/Host/HostInfo.h | 3 + lldb/include/lldb/Host/HostInfoBase.h | 2 +- lldb/include/lldb/Host/XML.h | 5 + lldb/include/lldb/Host/aix/AbstractSocket.h | 25 + lldb/include/lldb/Host/aix/Host.h | 22 + lldb/include/lldb/Host/aix/HostInfoAIX.h | 42 + lldb/include/lldb/Host/aix/Ptrace.h | 62 + lldb/include/lldb/Host/aix/Support.h | 29 + lldb/include/lldb/Host/aix/Uio.h | 23 + lldb/include/lldb/Host/common/GetOptInc.h | 6 +- lldb/include/lldb/Symbol/ObjectFile.h | 5 + lldb/include/lldb/Target/ABI.h | 6 + lldb/include/lldb/Target/DynamicLoader.h | 6 + lldb/include/lldb/Target/Process.h | 14 + .../lldb/Target/RegisterContextUnwind.h | 4 + .../lldb/Target/ThreadPlanCallFunction.h | 6 + .../lldb/Utility/StringExtractorGDBRemote.h | 1 + lldb/include/lldb/lldb-private-enumerations.h | 1 + lldb/source/API/CMakeLists.txt | 108 + lldb/source/API/SBBreakpoint.cpp | 6 +- lldb/source/API/SBBreakpointLocation.cpp | 6 +- lldb/source/API/SBBreakpointName.cpp | 4 +- lldb/source/Core/DynamicLoader.cpp | 10 + lldb/source/Core/Mangled.cpp | 2 + lldb/source/Core/Module.cpp | 12 + lldb/source/Core/Section.cpp | 4 + lldb/source/Expression/DWARFExpression.cpp | 10 +- lldb/source/Host/CMakeLists.txt | 13 + lldb/source/Host/aix/AbstractSocket.cpp | 21 + lldb/source/Host/aix/Host.cpp | 304 +++ lldb/source/Host/aix/HostInfoAIX.cpp | 215 ++ lldb/source/Host/aix/Support.cpp | 44 + lldb/source/Host/common/GetOptInc.cpp | 2 +- lldb/source/Host/common/Host.cpp | 180 +- .../source/Host/common/LICENSE.aix-netbsd.txt | 125 + lldb/source/Host/common/XML.cpp | 3 + .../posix/ConnectionFileDescriptorPosix.cpp | 2 + lldb/source/Host/posix/FileSystemPosix.cpp | 2 + lldb/source/Host/posix/MainLoopPosix.cpp | 17 + .../Host/posix/ProcessLauncherPosixFork.cpp | 5 + lldb/source/Initialization/CMakeLists.txt | 2 +- .../SystemInitializerCommon.cpp | 4 +- .../Plugins/ABI/PowerPC/ABISysV_ppc64.cpp | 131 +- .../Plugins/ABI/PowerPC/ABISysV_ppc64.h | 6 + .../DynamicLoader/AIX-DYLD/CMakeLists.txt | 11 + .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 272 +++ .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 55 + .../Plugins/DynamicLoader/CMakeLists.txt | 1 + .../DynamicLoaderDarwinKernel.cpp | 4 +- .../MacOSX-DYLD/DynamicLoaderDarwin.cpp | 2 +- .../PPC64/EmulateInstructionPPC64.cpp | 196 +- .../PPC64/EmulateInstructionPPC64.h | 14 + ...nstrumentationRuntimeMainThreadChecker.cpp | 2 +- .../TSan/InstrumentationRuntimeTSan.cpp | 14 +- .../UBSan/InstrumentationRuntimeUBSan.cpp | 2 +- .../Plugins/JITLoader/GDB/JITLoaderGDB.cpp | 4 + lldb/source/Plugins/Language/ObjC/Cocoa.cpp | 2 + .../MemoryHistory/asan/MemoryHistoryASan.cpp | 2 +- .../BSD-Archive/ObjectContainerBSDArchive.cpp | 2 +- .../Big-Archive/CMakeLists.txt | 10 + .../Big-Archive/ObjectContainerBigArchive.cpp | 522 +++++ .../Big-Archive/ObjectContainerBigArchive.h | 177 ++ .../Plugins/ObjectContainer/CMakeLists.txt | 1 + lldb/source/Plugins/ObjectFile/CMakeLists.txt | 1 + .../ObjectFile/Mach-O/ObjectFileMachO.cpp | 6 +- .../Minidump/ObjectFileMinidump.cpp | 2 + .../Plugins/ObjectFile/PDB/ObjectFilePDB.cpp | 15 +- .../ObjectFile/PECOFF/ObjectFilePECOFF.cpp | 18 +- .../Plugins/ObjectFile/XCOFF/CMakeLists.txt | 13 + .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 780 +++++++ .../ObjectFile/XCOFF/ObjectFileXCOFF.h | 243 ++ .../Python/OperatingSystemPython.cpp | 2 +- .../Plugins/Platform/AIX/CMakeLists.txt | 13 + .../Plugins/Platform/AIX/PlatformAIX.cpp | 471 ++++ .../source/Plugins/Platform/AIX/PlatformAIX.h | 74 + lldb/source/Plugins/Platform/CMakeLists.txt | 1 + .../source/Plugins/Process/AIX/CMakeLists.txt | 19 + .../Plugins/Process/AIX/NativeProcessAIX.cpp | 2048 +++++++++++++++++ .../Plugins/Process/AIX/NativeProcessAIX.h | 283 +++ .../Process/AIX/NativeRegisterContextAIX.cpp | 157 ++ .../Process/AIX/NativeRegisterContextAIX.h | 133 ++ .../AIX/NativeRegisterContextAIX_ppc64.cpp | 744 ++++++ .../AIX/NativeRegisterContextAIX_ppc64.h | 138 ++ .../Plugins/Process/AIX/NativeThreadAIX.cpp | 526 +++++ .../Plugins/Process/AIX/NativeThreadAIX.h | 126 + lldb/source/Plugins/Process/CMakeLists.txt | 3 + .../Process/Utility/InferiorCallPOSIX.cpp | 33 + .../Utility/RegisterInfoPOSIX_ppc64le.cpp | 4 + .../Plugins/Process/Utility/ThreadMemory.cpp | 2 +- .../Plugins/Process/gdb-remote/CMakeLists.txt | 5 + .../GDBRemoteCommunicationClient.cpp | 30 + .../gdb-remote/GDBRemoteCommunicationClient.h | 7 + .../GDBRemoteCommunicationServerLLGS.cpp | 28 + .../GDBRemoteCommunicationServerLLGS.h | 2 + .../Process/gdb-remote/ProcessGDBRemote.cpp | 13 +- .../Process/gdb-remote/ProcessGDBRemote.h | 8 + .../Process/mach-core/ProcessMachCore.cpp | 8 +- .../ScriptInterpreter/Python/CMakeLists.txt | 5 + .../SymbolFile/DWARF/DWARFFormValue.cpp | 4 + .../Plugins/SymbolFile/DWARF/DWARFUnit.cpp | 12 +- .../MacOSX/AppleGetThreadItemInfoHandler.cpp | 2 +- lldb/source/Symbol/DWARFCallFrameInfo.cpp | 4 +- lldb/source/Target/ABI.cpp | 9 + lldb/source/Target/CMakeLists.txt | 5 + lldb/source/Target/Process.cpp | 10 + lldb/source/Target/RegisterContextUnwind.cpp | 46 + lldb/source/Target/ThreadPlanCallFunction.cpp | 34 + lldb/source/Target/UnwindLLDB.cpp | 15 + lldb/source/Utility/ArchSpec.cpp | 18 +- .../Utility/StringExtractorGDBRemote.cpp | 2 + lldb/test/CMakeLists.txt | 2 +- lldb/test/Shell/Expr/TestIRMemoryMap.test | 2 +- lldb/test/Shell/Process/TestEnvironment.test | 2 +- lldb/tools/driver/CMakeLists.txt | 5 + lldb/tools/driver/Driver.cpp | 5 +- lldb/tools/lldb-dap/CMakeLists.txt | 4 + lldb/tools/lldb-server/CMakeLists.txt | 7 + .../lldb-server/SystemInitializerLLGS.cpp | 15 + lldb/tools/lldb-server/lldb-gdbserver.cpp | 4 + lldb/unittests/Host/FileSystemTest.cpp | 2 +- lldb/unittests/Host/posix/TerminalTest.cpp | 4 + llvm/include/llvm/Object/XCOFFObjectFile.h | 4 +- llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 15 +- 129 files changed, 8950 insertions(+), 76 deletions(-) create mode 100644 lldb/include/lldb/Host/aix/AbstractSocket.h create mode 100644 lldb/include/lldb/Host/aix/Host.h create mode 100644 lldb/include/lldb/Host/aix/HostInfoAIX.h create mode 100644 lldb/include/lldb/Host/aix/Ptrace.h create mode 100644 lldb/include/lldb/Host/aix/Support.h create mode 100644 lldb/include/lldb/Host/aix/Uio.h create mode 100644 lldb/source/Host/aix/AbstractSocket.cpp create mode 100644 lldb/source/Host/aix/Host.cpp create mode 100644 lldb/source/Host/aix/HostInfoAIX.cpp create mode 100644 lldb/source/Host/aix/Support.cpp create mode 100644 lldb/source/Host/common/LICENSE.aix-netbsd.txt create mode 100644 lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt create mode 100644 lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp create mode 100644 lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h create mode 100644 lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt create mode 100644 lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp create mode 100644 lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h create mode 100644 lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt create mode 100644 lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp create mode 100644 lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h create mode 100644 lldb/source/Plugins/Platform/AIX/CMakeLists.txt create mode 100644 lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp create mode 100644 lldb/source/Plugins/Platform/AIX/PlatformAIX.h create mode 100644 lldb/source/Plugins/Process/AIX/CMakeLists.txt create mode 100644 lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeProcessAIX.h create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h create mode 100644 lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp create mode 100644 lldb/source/Plugins/Process/AIX/NativeThreadAIX.h diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index 30f3911a8b03c..fc91981db68c1 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -5052,10 +5052,14 @@ std::string CGObjCCommonMac::GetSectionName(StringRef Section, case llvm::Triple::COFF: assert(Section.starts_with("__") && "expected the name to begin with __"); return ("." + Section.substr(2) + "$B").str(); + case llvm::Triple::XCOFF: + // Hack to allow "p 10+1" on AIX for lldb + assert(Section.substr(0, 2) == "__" && + "expected the name to begin with __"); + return Section.substr(2).str(); case llvm::Triple::Wasm: case llvm::Triple::GOFF: case llvm::Triple::SPIRV: - case llvm::Triple::XCOFF: case llvm::Triple::DXContainer: llvm::report_fatal_error( "Objective-C support is unimplemented for object file format"); diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt index 59cdc4593463c..2e9ae0d0b3221 100644 --- a/lldb/CMakeLists.txt +++ b/lldb/CMakeLists.txt @@ -38,6 +38,10 @@ endif() include(LLDBConfig) include(AddLLDB) +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + add_definitions("-D__AIX__") +endif() + # Define the LLDB_CONFIGURATION_xxx matching the build type. if(uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" ) add_definitions(-DLLDB_CONFIGURATION_DEBUG) diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake index a60921990cf77..a0f118a11984c 100644 --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -299,7 +299,7 @@ endif() # Figure out if lldb could use lldb-server. If so, then we'll # ensure we build lldb-server when an lldb target is being built. -if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD|Windows") +if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD|Windows|AIX") set(LLDB_CAN_USE_LLDB_SERVER ON) else() set(LLDB_CAN_USE_LLDB_SERVER OFF) diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 5589c1c9a350d..3829386562795 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -196,6 +196,9 @@ class Module : public std::enable_shared_from_this, bool SetLoadAddress(Target &target, lldb::addr_t value, bool value_is_offset, bool &changed); + bool SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, bool &changed, int type_id); + /// \copydoc SymbolContextScope::CalculateSymbolContext(SymbolContext*) /// /// \see SymbolContextScope diff --git a/lldb/include/lldb/Core/ModuleSpec.h b/lldb/include/lldb/Core/ModuleSpec.h index 4cbbbfa8a26e1..4fe06412b6b0b 100644 --- a/lldb/include/lldb/Core/ModuleSpec.h +++ b/lldb/include/lldb/Core/ModuleSpec.h @@ -21,6 +21,7 @@ #include #include +#include namespace lldb_private { @@ -41,8 +42,26 @@ class ModuleSpec { } ModuleSpec(const FileSpec &file_spec, const ArchSpec &arch) - : m_file(file_spec), m_arch(arch), m_object_offset(0), - m_object_size(FileSystem::Instance().GetByteSize(file_spec)) {} + : m_arch(arch), m_object_offset(0) { + // parse object inside module format for example: /usr/ccs/lib/libc.a(shr_64.o) + llvm::SmallString<256> path_with_object; + file_spec.GetPath(path_with_object); + if (strstr(path_with_object.c_str(), "(") != nullptr) { + char *part; + char *str = (char *)path_with_object.c_str(); + part = strtok(str, "()"); + assert(part); + llvm::StringRef file_name(part); + part = strtok(nullptr, "()"); + assert(part); + m_object_name = ConstString(part); + m_file = FileSpec(file_name); + m_object_size = FileSystem::Instance().GetByteSize(m_file); + } else { + m_file = file_spec; + m_object_size = FileSystem::Instance().GetByteSize(file_spec); + } + } FileSpec *GetFileSpecPtr() { return (m_file ? &m_file : nullptr); } diff --git a/lldb/include/lldb/Host/HostGetOpt.h b/lldb/include/lldb/Host/HostGetOpt.h index 52cfdf4dbb89c..f450e561d6afb 100644 --- a/lldb/include/lldb/Host/HostGetOpt.h +++ b/lldb/include/lldb/Host/HostGetOpt.h @@ -9,7 +9,7 @@ #ifndef LLDB_HOST_HOSTGETOPT_H #define LLDB_HOST_HOSTGETOPT_H -#if !defined(_MSC_VER) && !defined(__NetBSD__) +#if !defined(_MSC_VER) && !defined(__NetBSD__) && !defined(__AIX__) #include #include diff --git a/lldb/include/lldb/Host/HostInfo.h b/lldb/include/lldb/Host/HostInfo.h index b7010d69d88e7..156df8cf6901d 100644 --- a/lldb/include/lldb/Host/HostInfo.h +++ b/lldb/include/lldb/Host/HostInfo.h @@ -55,6 +55,9 @@ #elif defined(__APPLE__) #include "lldb/Host/macosx/HostInfoMacOSX.h" #define HOST_INFO_TYPE HostInfoMacOSX +#elif defined(__AIX__) +#include "lldb/Host/aix/HostInfoAIX.h" +#define HOST_INFO_TYPE HostInfoAIX #else #include "lldb/Host/posix/HostInfoPosix.h" #define HOST_INFO_TYPE HostInfoPosix diff --git a/lldb/include/lldb/Host/HostInfoBase.h b/lldb/include/lldb/Host/HostInfoBase.h index 705aad559f3b7..29e6acf39bfb2 100644 --- a/lldb/include/lldb/Host/HostInfoBase.h +++ b/lldb/include/lldb/Host/HostInfoBase.h @@ -149,6 +149,7 @@ class HostInfoBase { return {}; } + static bool ComputeSharedLibraryDirectory(FileSpec &file_spec); /// Returns the distribution id of the host /// /// This will be something like "ubuntu", "fedora", etc. on Linux. @@ -158,7 +159,6 @@ class HostInfoBase { static llvm::StringRef GetDistributionId() { return llvm::StringRef(); } protected: - static bool ComputeSharedLibraryDirectory(FileSpec &file_spec); static bool ComputeSupportExeDirectory(FileSpec &file_spec); static bool ComputeProcessTempFileDirectory(FileSpec &file_spec); static bool ComputeGlobalTempFileDirectory(FileSpec &file_spec); diff --git a/lldb/include/lldb/Host/XML.h b/lldb/include/lldb/Host/XML.h index da0f9cd7aa8c0..cf359f7726d5d 100644 --- a/lldb/include/lldb/Host/XML.h +++ b/lldb/include/lldb/Host/XML.h @@ -11,6 +11,11 @@ #include "lldb/Host/Config.h" +#if defined(__AIX__) +//FIXME for AIX +#undef LLDB_ENABLE_LIBXML2 +#endif + #if LLDB_ENABLE_LIBXML2 #include #endif diff --git a/lldb/include/lldb/Host/aix/AbstractSocket.h b/lldb/include/lldb/Host/aix/AbstractSocket.h new file mode 100644 index 0000000000000..78a567a6b9095 --- /dev/null +++ b/lldb/include/lldb/Host/aix/AbstractSocket.h @@ -0,0 +1,25 @@ +//===-- AbstractSocket.h ----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_AbstractSocket_h_ +#define liblldb_AbstractSocket_h_ + +#include "lldb/Host/posix/DomainSocket.h" + +namespace lldb_private { +class AbstractSocket : public DomainSocket { +public: + AbstractSocket(bool child_processes_inherit); + +protected: + size_t GetNameOffset() const override; + void DeleteSocketFile(llvm::StringRef name) override; +}; +} + +#endif // ifndef liblldb_AbstractSocket_h_ diff --git a/lldb/include/lldb/Host/aix/Host.h b/lldb/include/lldb/Host/aix/Host.h new file mode 100644 index 0000000000000..1e3487752995f --- /dev/null +++ b/lldb/include/lldb/Host/aix/Host.h @@ -0,0 +1,22 @@ +//===-- Host.h --------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_HOST_AIX_HOST_H +#define LLDB_HOST_AIX_HOST_H + +#include "lldb/lldb-types.h" +#include + +namespace lldb_private { + +// Get PID (i.e. the primary thread ID) corresponding to the specified TID. +std::optional getPIDForTID(lldb::pid_t tid); + +} // namespace lldb_private + +#endif // #ifndef LLDB_HOST_AIX_HOST_H diff --git a/lldb/include/lldb/Host/aix/HostInfoAIX.h b/lldb/include/lldb/Host/aix/HostInfoAIX.h new file mode 100644 index 0000000000000..ced4cf34d38a8 --- /dev/null +++ b/lldb/include/lldb/Host/aix/HostInfoAIX.h @@ -0,0 +1,42 @@ +//===-- HostInfoAIX.h -----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_Host_aix_HostInfoAIX_h_ +#define lldb_Host_aix_HostInfoAIX_h_ + +#include "lldb/Host/posix/HostInfoPosix.h" +#include "lldb/Utility/FileSpec.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VersionTuple.h" + +#include + +namespace lldb_private { + +class HostInfoAIX : public HostInfoPosix { + friend class HostInfoBase; + +public: + static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr); + static void Terminate(); + + static llvm::VersionTuple GetOSVersion(); + static std::optional GetOSBuildString(); + static llvm::StringRef GetDistributionId(); + static FileSpec GetProgramFileSpec(); + +protected: + static bool ComputeSupportExeDirectory(FileSpec &file_spec); + static bool ComputeSystemPluginsDirectory(FileSpec &file_spec); + static bool ComputeUserPluginsDirectory(FileSpec &file_spec); + static void ComputeHostArchitectureSupport(ArchSpec &arch_32, + ArchSpec &arch_64); +}; +} + +#endif diff --git a/lldb/include/lldb/Host/aix/Ptrace.h b/lldb/include/lldb/Host/aix/Ptrace.h new file mode 100644 index 0000000000000..88928f18102d7 --- /dev/null +++ b/lldb/include/lldb/Host/aix/Ptrace.h @@ -0,0 +1,62 @@ +//===-- Ptrace.h ------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +// This file defines ptrace functions & structures + +#ifndef liblldb_Host_aix_Ptrace_h_ +#define liblldb_Host_aix_Ptrace_h_ + +#include + +#define DEBUG_PTRACE_MAXBYTES 20 + +// Support ptrace extensions even when compiled without required kernel support +#ifndef PTRACE_GETREGS +#define PTRACE_GETREGS (PT_COMMAND_MAX+1) +#endif +#ifndef PTRACE_SETREGS +#define PTRACE_SETREGS (PT_COMMAND_MAX+2) +#endif +#ifndef PTRACE_GETFPREGS +#define PTRACE_GETFPREGS (PT_COMMAND_MAX+3) +#endif +#ifndef PTRACE_SETFPREGS +#define PTRACE_SETFPREGS (PT_COMMAND_MAX+4) +#endif +#ifndef PTRACE_GETREGSET +#define PTRACE_GETREGSET 0x4204 +#endif +#ifndef PTRACE_SETREGSET +#define PTRACE_SETREGSET 0x4205 +#endif +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA (PT_COMMAND_MAX+5) +#endif +#ifndef PTRACE_ARCH_PRCTL +#define PTRACE_ARCH_PRCTL (PT_COMMAND_MAX+6) +#endif +#ifndef ARCH_GET_FS +#define ARCH_SET_GS 0x1001 +#define ARCH_SET_FS 0x1002 +#define ARCH_GET_FS 0x1003 +#define ARCH_GET_GS 0x1004 +#endif +#ifndef PTRACE_PEEKMTETAGS +#define PTRACE_PEEKMTETAGS (PT_COMMAND_MAX+7) +#endif +#ifndef PTRACE_POKEMTETAGS +#define PTRACE_POKEMTETAGS (PT_COMMAND_MAX+8) +#endif +#ifndef PTRACE_GETVRREGS +#define PTRACE_GETVRREGS (PT_COMMAND_MAX+9) +#endif +#ifndef PTRACE_GETVSRREGS +#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+10) +#endif + +#endif // liblldb_Host_aix_Ptrace_h_ diff --git a/lldb/include/lldb/Host/aix/Support.h b/lldb/include/lldb/Host/aix/Support.h new file mode 100644 index 0000000000000..27d6c2b50a35b --- /dev/null +++ b/lldb/include/lldb/Host/aix/Support.h @@ -0,0 +1,29 @@ +//===-- Support.h -----------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_HOST_AIX_SUPPORT_H +#define LLDB_HOST_AIX_SUPPORT_H + +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MemoryBuffer.h" +#include + +namespace lldb_private { + +llvm::ErrorOr> +getProcFile(::pid_t pid, ::pid_t tid, const llvm::Twine &file); + +llvm::ErrorOr> +getProcFile(::pid_t pid, const llvm::Twine &file); + +llvm::ErrorOr> +getProcFile(const llvm::Twine &file); + +} // namespace lldb_private + +#endif // #ifndef LLDB_HOST_AIX_SUPPORT_H diff --git a/lldb/include/lldb/Host/aix/Uio.h b/lldb/include/lldb/Host/aix/Uio.h new file mode 100644 index 0000000000000..acf79ecc6a1d0 --- /dev/null +++ b/lldb/include/lldb/Host/aix/Uio.h @@ -0,0 +1,23 @@ +//===-- Uio.h ---------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Host_aix_Uio_h_ +#define liblldb_Host_aix_Uio_h_ + +#include "lldb/Host/Config.h" +#include + +// We shall provide our own implementation of process_vm_readv if it is not +// present +#if !HAVE_PROCESS_VM_READV +ssize_t process_vm_readv(::pid_t pid, const struct iovec *local_iov, + unsigned long liovcnt, const struct iovec *remote_iov, + unsigned long riovcnt, unsigned long flags); +#endif + +#endif // liblldb_Host_aix_Uio_h_ diff --git a/lldb/include/lldb/Host/common/GetOptInc.h b/lldb/include/lldb/Host/common/GetOptInc.h index 3fb9add479541..ebb475bfaf6b8 100644 --- a/lldb/include/lldb/Host/common/GetOptInc.h +++ b/lldb/include/lldb/Host/common/GetOptInc.h @@ -11,11 +11,11 @@ #include "lldb/lldb-defines.h" -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__AIX__) #define REPLACE_GETOPT #define REPLACE_GETOPT_LONG #endif -#if defined(_MSC_VER) || defined(__NetBSD__) +#if defined(_MSC_VER) || defined(__NetBSD__) || defined(__AIX__) #define REPLACE_GETOPT_LONG_ONLY #endif @@ -35,7 +35,7 @@ struct option { int val; }; -int getopt(int argc, char *const argv[], const char *optstring); +int getopt(int argc, char *const argv[], const char *optstring) throw(); // from getopt.h extern char *optarg; diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h index 8592323322e38..bf66ccec263d2 100644 --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/lldb/include/lldb/Symbol/ObjectFile.h @@ -401,6 +401,11 @@ class ObjectFile : public std::enable_shared_from_this, return false; } + virtual bool SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) { + return false; + } + /// Gets whether endian swapping should occur when extracting data from this /// object file. /// diff --git a/lldb/include/lldb/Target/ABI.h b/lldb/include/lldb/Target/ABI.h index 7b646d743346b..281a89951ef88 100644 --- a/lldb/include/lldb/Target/ABI.h +++ b/lldb/include/lldb/Target/ABI.h @@ -47,6 +47,12 @@ class ABI : public PluginInterface { lldb::addr_t returnAddress, llvm::ArrayRef args) const = 0; + virtual bool PrepareTrivialCall(lldb_private::Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t tocAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef args) const; + // Prepare trivial call used from ThreadPlanFunctionCallUsingABI // AD: // . Because i don't want to change other ABI's this is not declared pure diff --git a/lldb/include/lldb/Target/DynamicLoader.h b/lldb/include/lldb/Target/DynamicLoader.h index 0629e2faae7e9..7dccd317c2dca 100644 --- a/lldb/include/lldb/Target/DynamicLoader.h +++ b/lldb/include/lldb/Target/DynamicLoader.h @@ -359,6 +359,12 @@ class DynamicLoader : public PluginInterface { lldb::addr_t base_addr, bool base_addr_is_offset); + virtual void UpdateLoadedSectionsByType(lldb::ModuleSP module, + lldb::addr_t link_map_addr, + lldb::addr_t base_addr, + bool base_addr_is_offset, + int type_id); + // Utility method so base classes can share implementation of // UpdateLoadedSections void UpdateLoadedSectionsCommon(lldb::ModuleSP module, lldb::addr_t base_addr, diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index cf16fbc812aa4..886ca766112c8 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -63,6 +63,10 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/VersionTuple.h" +#if defined(__AIX__) +struct ld_xinfo; +#endif + namespace lldb_private { template struct Range; @@ -1915,6 +1919,10 @@ class Process : public std::enable_shared_from_this, Status GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &range_info); +#if defined(__AIX__) + Status GetLDXINFO(struct ld_xinfo *info_ptr); +#endif + /// Obtain all the mapped memory regions within this process. /// /// \param[out] region_list @@ -2855,6 +2863,12 @@ void PruneThreadPlans(); return Status("Process::DoGetMemoryRegionInfo() not supported"); } +#if defined(__AIX__) + virtual Status DoGetLDXINFO(struct ld_xinfo *info_ptr) { + return Status("Process::DoGetLDXINFO() not supported"); + } +#endif + /// Provide an override value in the subclass for lldb's /// CPU-based logic for whether watchpoint exceptions are /// received before or after an instruction executes. diff --git a/lldb/include/lldb/Target/RegisterContextUnwind.h b/lldb/include/lldb/Target/RegisterContextUnwind.h index ef8ae88403866..00a95853800ed 100644 --- a/lldb/include/lldb/Target/RegisterContextUnwind.h +++ b/lldb/include/lldb/Target/RegisterContextUnwind.h @@ -67,6 +67,10 @@ class RegisterContextUnwind : public lldb_private::RegisterContext { bool ReadPC(lldb::addr_t &start_pc); +#ifdef __AIX__ + bool ReadLR(lldb::addr_t &lr); +#endif + // Indicates whether this frame *behaves* like frame zero -- the currently // executing frame -- or not. This can be true in the middle of the stack // above asynchronous trap handlers (sigtramp) for instance. diff --git a/lldb/include/lldb/Target/ThreadPlanCallFunction.h b/lldb/include/lldb/Target/ThreadPlanCallFunction.h index cb6e7caebb4ad..7880db1592e04 100644 --- a/lldb/include/lldb/Target/ThreadPlanCallFunction.h +++ b/lldb/include/lldb/Target/ThreadPlanCallFunction.h @@ -27,6 +27,12 @@ class ThreadPlanCallFunction : public ThreadPlan { llvm::ArrayRef args, const EvaluateExpressionOptions &options); + ThreadPlanCallFunction(Thread &thread, const Address &function, + const Address &toc, + const CompilerType &return_type, + llvm::ArrayRef args, + const EvaluateExpressionOptions &options); + ThreadPlanCallFunction(Thread &thread, const Address &function, const EvaluateExpressionOptions &options); diff --git a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h index dd468ef5bddef..9953bd6c24588 100644 --- a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h +++ b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h @@ -61,6 +61,7 @@ class StringExtractorGDBRemote : public StringExtractor { eServerPacketType_qQueryGDBServer, eServerPacketType_qKillSpawnedProcess, eServerPacketType_qLaunchSuccess, + eServerPacketType_qLDXINFO, eServerPacketType_qModuleInfo, eServerPacketType_qProcessInfoPID, eServerPacketType_qSpeedTest, diff --git a/lldb/include/lldb/lldb-private-enumerations.h b/lldb/include/lldb/lldb-private-enumerations.h index c24a3538f58da..98c1e956bf8f7 100644 --- a/lldb/include/lldb/lldb-private-enumerations.h +++ b/lldb/include/lldb/lldb-private-enumerations.h @@ -65,6 +65,7 @@ enum ArchitectureType { eArchTypeMachO, eArchTypeELF, eArchTypeCOFF, + eArchTypeXCOFF, kNumArchTypes }; diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index a32bc58507d8e..3ecdb11daef7d 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -40,6 +40,113 @@ add_custom_target(lldb-sbapi-dwarf-enums DEPENDS ${sb_languages_file}) set_target_properties(lldb-sbapi-dwarf-enums PROPERTIES FOLDER "LLDB/Tablegenning") +if(CMAKE_SYSTEM_NAME MATCHES "AIX") +add_lldb_library(liblldb STATIC ${option_framework} + SBAddress.cpp + SBAddressRange.cpp + SBAddressRangeList.cpp + SBAttachInfo.cpp + SBBlock.cpp + SBBreakpoint.cpp + SBBreakpointLocation.cpp + SBBreakpointName.cpp + SBBreakpointOptionCommon.cpp + SBBroadcaster.cpp + SBCommandInterpreter.cpp + SBCommandInterpreterRunOptions.cpp + SBCommandReturnObject.cpp + SBCommunication.cpp + SBCompileUnit.cpp + SBSaveCoreOptions.cpp + SBData.cpp + SBDebugger.cpp + SBDeclaration.cpp + SBEnvironment.cpp + SBError.cpp + SBEvent.cpp + SBExecutionContext.cpp + SBExpressionOptions.cpp + SBFileSpec.cpp + SBFile.cpp + SBFileSpecList.cpp + SBFormat.cpp + SBFrame.cpp + SBFunction.cpp + SBHostOS.cpp + SBInstruction.cpp + SBInstructionList.cpp + SBLanguageRuntime.cpp + SBLaunchInfo.cpp + SBLineEntry.cpp + SBListener.cpp + SBMemoryRegionInfo.cpp + SBMemoryRegionInfoList.cpp + SBModule.cpp + SBModuleSpec.cpp + SBPlatform.cpp + SBProcess.cpp + SBProcessInfo.cpp + SBProcessInfoList.cpp + SBQueue.cpp + SBQueueItem.cpp + SBReproducer.cpp + SBScriptObject.cpp + SBSection.cpp + SBSourceManager.cpp + SBStatisticsOptions.cpp + SBStream.cpp + SBStringList.cpp + SBStructuredData.cpp + SBSymbol.cpp + SBSymbolContext.cpp + SBSymbolContextList.cpp + SBTarget.cpp + SBThread.cpp + SBThreadCollection.cpp + SBThreadPlan.cpp + SBTrace.cpp + SBTraceCursor.cpp + SBType.cpp + SBTypeCategory.cpp + SBTypeEnumMember.cpp + SBTypeFilter.cpp + SBTypeFormat.cpp + SBTypeNameSpecifier.cpp + SBTypeSummary.cpp + SBTypeSynthetic.cpp + SBValue.cpp + SBValueList.cpp + SBVariablesOptions.cpp + SBWatchpoint.cpp + SBWatchpointOptions.cpp + SBUnixSignals.cpp + SystemInitializerFull.cpp + ${lldb_python_wrapper} + ${lldb_lua_wrapper} + + DEPENDS + lldb-sbapi-dwarf-enums + + LINK_LIBS + lldbBreakpoint + lldbCore + lldbDataFormatters + lldbExpression + lldbHost + lldbInitialization + lldbInterpreter + lldbSymbol + lldbTarget + lldbUtility + lldbVersion + ${LLDB_ALL_PLUGINS} + LINK_COMPONENTS + Support + + ${option_install_prefix} +) + +else() add_lldb_library(liblldb SHARED ${option_framework} SBAddress.cpp SBAddressRange.cpp @@ -144,6 +251,7 @@ add_lldb_library(liblldb SHARED ${option_framework} ${option_install_prefix} ) +endif() # lib/pythonX.Y/dist-packages/lldb/_lldb.so is a symlink to lib/liblldb.so, # which depends on lib/libLLVM*.so (BUILD_SHARED_LIBS) or lib/libLLVM-10git.so diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp index 3d908047f9455..728fe04d14d92 100644 --- a/lldb/source/API/SBBreakpoint.cpp +++ b/lldb/source/API/SBBreakpoint.cpp @@ -342,7 +342,7 @@ uint32_t SBBreakpoint::GetIgnoreCount() const { return count; } -void SBBreakpoint::SetThreadID(tid_t tid) { +void SBBreakpoint::SetThreadID(lldb::tid_t tid) { LLDB_INSTRUMENT_VA(this, tid); BreakpointSP bkpt_sp = GetSP(); @@ -353,10 +353,10 @@ void SBBreakpoint::SetThreadID(tid_t tid) { } } -tid_t SBBreakpoint::GetThreadID() { +lldb::tid_t SBBreakpoint::GetThreadID() { LLDB_INSTRUMENT_VA(this); - tid_t tid = LLDB_INVALID_THREAD_ID; + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; BreakpointSP bkpt_sp = GetSP(); if (bkpt_sp) { std::lock_guard guard( diff --git a/lldb/source/API/SBBreakpointLocation.cpp b/lldb/source/API/SBBreakpointLocation.cpp index 75b66364d4f1a..fad9a4076a54f 100644 --- a/lldb/source/API/SBBreakpointLocation.cpp +++ b/lldb/source/API/SBBreakpointLocation.cpp @@ -302,7 +302,7 @@ bool SBBreakpointLocation::GetCommandLineCommands(SBStringList &commands) { return has_commands; } -void SBBreakpointLocation::SetThreadID(tid_t thread_id) { +void SBBreakpointLocation::SetThreadID(lldb::tid_t thread_id) { LLDB_INSTRUMENT_VA(this, thread_id); BreakpointLocationSP loc_sp = GetSP(); @@ -313,10 +313,10 @@ void SBBreakpointLocation::SetThreadID(tid_t thread_id) { } } -tid_t SBBreakpointLocation::GetThreadID() { +lldb::tid_t SBBreakpointLocation::GetThreadID() { LLDB_INSTRUMENT_VA(this); - tid_t tid = LLDB_INVALID_THREAD_ID; + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; BreakpointLocationSP loc_sp = GetSP(); if (loc_sp) { std::lock_guard guard( diff --git a/lldb/source/API/SBBreakpointName.cpp b/lldb/source/API/SBBreakpointName.cpp index 7f63aaf6fa7d5..5c7c0a8f6504b 100644 --- a/lldb/source/API/SBBreakpointName.cpp +++ b/lldb/source/API/SBBreakpointName.cpp @@ -347,7 +347,7 @@ bool SBBreakpointName::GetAutoContinue() { return bp_name->GetOptions().IsAutoContinue(); } -void SBBreakpointName::SetThreadID(tid_t tid) { +void SBBreakpointName::SetThreadID(lldb::tid_t tid) { LLDB_INSTRUMENT_VA(this, tid); BreakpointName *bp_name = GetBreakpointName(); @@ -361,7 +361,7 @@ void SBBreakpointName::SetThreadID(tid_t tid) { UpdateName(*bp_name); } -tid_t SBBreakpointName::GetThreadID() { +lldb::tid_t SBBreakpointName::GetThreadID() { LLDB_INSTRUMENT_VA(this); BreakpointName *bp_name = GetBreakpointName(); diff --git a/lldb/source/Core/DynamicLoader.cpp b/lldb/source/Core/DynamicLoader.cpp index 7758a87403b5a..ea43a7f98b69f 100644 --- a/lldb/source/Core/DynamicLoader.cpp +++ b/lldb/source/Core/DynamicLoader.cpp @@ -113,6 +113,16 @@ void DynamicLoader::UpdateLoadedSections(ModuleSP module, addr_t link_map_addr, UpdateLoadedSectionsCommon(module, base_addr, base_addr_is_offset); } +void DynamicLoader::UpdateLoadedSectionsByType(lldb::ModuleSP module, + lldb::addr_t link_map_addr, + lldb::addr_t base_addr, + bool base_addr_is_offset, + int type_id) { + bool changed; + module->SetLoadAddressByType(m_process->GetTarget(), base_addr, base_addr_is_offset, + changed, type_id); +} + void DynamicLoader::UpdateLoadedSectionsCommon(ModuleSP module, addr_t base_addr, bool base_addr_is_offset) { diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp index 387c4fac6b0f8..43c5b043ef7a2 100644 --- a/lldb/source/Core/Mangled.cpp +++ b/lldb/source/Core/Mangled.cpp @@ -167,12 +167,14 @@ static char *GetItaniumDemangledStr(const char *M) { "Expected demangled_size to return length including trailing null"); } +#if !defined(__AIX__) if (Log *log = GetLog(LLDBLog::Demangle)) { if (demangled_cstr) LLDB_LOGF(log, "demangled itanium: %s -> \"%s\"", M, demangled_cstr); else LLDB_LOGF(log, "demangled itanium: %s -> error: failed to demangle", M); } +#endif return demangled_cstr; } diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index f9d7832254f46..044a5d29978e8 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -1510,6 +1510,18 @@ bool Module::SetLoadAddress(Target &target, lldb::addr_t value, return false; } +bool Module::SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, bool &changed, int type_id) { + ObjectFile *object_file = GetObjectFile(); + if (object_file != nullptr) { + changed = object_file->SetLoadAddressByType(target, value, value_is_offset, type_id); + return true; + } else { + changed = false; + } + return false; +} + bool Module::MatchesModuleSpec(const ModuleSpec &module_ref) { const UUID &uuid = module_ref.GetUUID(); diff --git a/lldb/source/Core/Section.cpp b/lldb/source/Core/Section.cpp index 0763e88d4608f..9ed55853930a6 100644 --- a/lldb/source/Core/Section.cpp +++ b/lldb/source/Core/Section.cpp @@ -263,6 +263,10 @@ bool Section::ResolveContainedAddress(addr_t offset, Address &so_addr, bool Section::ContainsFileAddress(addr_t vm_addr) const { const addr_t file_addr = GetFileAddress(); +#ifdef __AIX__ + if (file_addr == 0) + return false; +#endif if (file_addr != LLDB_INVALID_ADDRESS && !IsThreadSpecific()) { if (file_addr <= vm_addr) { const addr_t offset = (vm_addr - file_addr) * m_target_byte_size; diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index 444e44b392891..c1feec990f989 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -130,7 +130,7 @@ static llvm::Error ReadRegisterValueAsScalar(RegisterContext *reg_ctx, /// Return the length in bytes of the set of operands for \p op. No guarantees /// are made on the state of \p data after this call. -static offset_t GetOpcodeDataSize(const DataExtractor &data, +static lldb::offset_t GetOpcodeDataSize(const DataExtractor &data, const lldb::offset_t data_offset, const uint8_t op, const DWARFUnit *dwarf_cu) { lldb::offset_t offset = data_offset; @@ -358,7 +358,7 @@ lldb::addr_t DWARFExpression::GetLocation_DW_OP_addr(const DWARFUnit *dwarf_cu, error = true; break; } - const offset_t op_arg_size = + const lldb::offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op, dwarf_cu); if (op_arg_size == LLDB_INVALID_OFFSET) { error = true; @@ -418,7 +418,7 @@ bool DWARFExpression::Update_DW_OP_addr(const DWARFUnit *dwarf_cu, m_data.SetData(encoder.GetDataBuffer()); return true; } - const offset_t op_arg_size = + const lldb::offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op, dwarf_cu); if (op_arg_size == LLDB_INVALID_OFFSET) break; @@ -435,7 +435,7 @@ bool DWARFExpression::ContainsThreadLocalStorage( if (op == DW_OP_form_tls_address || op == DW_OP_GNU_push_tls_address) return true; - const offset_t op_arg_size = + const lldb::offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op, dwarf_cu); if (op_arg_size == LLDB_INVALID_OFFSET) return false; @@ -515,7 +515,7 @@ bool DWARFExpression::LinkThreadLocalStorage( } if (!decoded_data) { - const offset_t op_arg_size = + const lldb::offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op, dwarf_cu); if (op_arg_size == LLDB_INVALID_OFFSET) return false; diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index c2e091ee8555b..5374b16881950 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -7,6 +7,11 @@ if (APPLE AND LLVM_ENABLE_LOCAL_SUBMODULE_VISIBILITY) endif() endif() +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + macro(add_host_subdirectory group) list(APPEND HOST_SOURCES ${ARGN}) source_group(${group} FILES ${ARGN}) @@ -133,6 +138,14 @@ else() openbsd/Host.cpp openbsd/HostInfoOpenBSD.cpp ) + + elseif (CMAKE_SYSTEM_NAME MATCHES "AIX") + add_host_subdirectory(aix + aix/AbstractSocket.cpp + aix/Host.cpp + aix/HostInfoAIX.cpp + aix/Support.cpp + ) endif() endif() diff --git a/lldb/source/Host/aix/AbstractSocket.cpp b/lldb/source/Host/aix/AbstractSocket.cpp new file mode 100644 index 0000000000000..bfb67d452f7ec --- /dev/null +++ b/lldb/source/Host/aix/AbstractSocket.cpp @@ -0,0 +1,21 @@ +//===-- AbstractSocket.cpp ------------------------------------------------===// +// +// 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 "lldb/Host/aix/AbstractSocket.h" + +#include "llvm/ADT/StringRef.h" + +using namespace lldb; +using namespace lldb_private; + +AbstractSocket::AbstractSocket(bool child_processes_inherit) + : DomainSocket(ProtocolUnixAbstract, child_processes_inherit) {} + +size_t AbstractSocket::GetNameOffset() const { return 1; } + +void AbstractSocket::DeleteSocketFile(llvm::StringRef name) {} diff --git a/lldb/source/Host/aix/Host.cpp b/lldb/source/Host/aix/Host.cpp new file mode 100644 index 0000000000000..d82cb9049d389 --- /dev/null +++ b/lldb/source/Host/aix/Host.cpp @@ -0,0 +1,304 @@ +//===-- source/Host/aix/Host.cpp ----------------------------------------===// +// +// 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/ScopedPrinter.h" + +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/ProcessInfo.h" +#include "lldb/Utility/Status.h" + +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Host/aix/Host.h" +#include "lldb/Host/aix/Support.h" +#include "lldb/Utility/DataExtractor.h" +#include "llvm/BinaryFormat/XCOFF.h" + +#include +#include + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; + +namespace { +enum class ProcessState { + Unknown, + Dead, + DiskSleep, + Idle, + Paging, + Parked, + Running, + Sleeping, + TracedOrStopped, + Zombie, +}; +} + +namespace lldb_private { +class ProcessLaunchInfo; +} + +static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo, + ProcessState &State, ::pid_t &TracerPid, + ::pid_t &Tgid) { + Log *log = GetLog(LLDBLog::Host); + + auto BufferOrError = getProcFile(Pid, "status"); + if (!BufferOrError) + return false; + + llvm::StringRef Rest = BufferOrError.get()->getBuffer(); + while (!Rest.empty()) { + llvm::StringRef Line; + std::tie(Line, Rest) = Rest.split('\n'); + + if (Line.consume_front("Gid:")) { + // Real, effective, saved set, and file system GIDs. Read the first two. + Line = Line.ltrim(); + uint32_t RGid, EGid; + Line.consumeInteger(10, RGid); + Line = Line.ltrim(); + Line.consumeInteger(10, EGid); + + ProcessInfo.SetGroupID(RGid); + ProcessInfo.SetEffectiveGroupID(EGid); + } else if (Line.consume_front("Uid:")) { + // Real, effective, saved set, and file system UIDs. Read the first two. + Line = Line.ltrim(); + uint32_t RUid, EUid; + Line.consumeInteger(10, RUid); + Line = Line.ltrim(); + Line.consumeInteger(10, EUid); + + ProcessInfo.SetUserID(RUid); + ProcessInfo.SetEffectiveUserID(EUid); + } else if (Line.consume_front("PPid:")) { + ::pid_t PPid; + Line.ltrim().consumeInteger(10, PPid); + ProcessInfo.SetParentProcessID(PPid); + } else if (Line.consume_front("State:")) { + State = llvm::StringSwitch(Line.ltrim().take_front(1)) + .Case("D", ProcessState::DiskSleep) + .Case("I", ProcessState::Idle) + .Case("R", ProcessState::Running) + .Case("S", ProcessState::Sleeping) + .CaseLower("T", ProcessState::TracedOrStopped) + .Case("W", ProcessState::Paging) + .Case("P", ProcessState::Parked) + .Case("X", ProcessState::Dead) + .Case("Z", ProcessState::Zombie) + .Default(ProcessState::Unknown); + if (State == ProcessState::Unknown) { + LLDB_LOG(log, "Unknown process state {0}", Line); + } + } else if (Line.consume_front("TracerPid:")) { + Line = Line.ltrim(); + Line.consumeInteger(10, TracerPid); + } else if (Line.consume_front("Tgid:")) { + Line = Line.ltrim(); + Line.consumeInteger(10, Tgid); + } + } + return true; +} + +static bool IsDirNumeric(const char *dname) { + for (; *dname; dname++) { + if (!isdigit(*dname)) + return false; + } + return true; +} + +static void GetProcessArgs(::pid_t pid, ProcessInstanceInfo &process_info) { + auto BufferOrError = getProcFile(pid, "cmdline"); + if (!BufferOrError) + return; + std::unique_ptr Cmdline = std::move(*BufferOrError); + + llvm::StringRef Arg0, Rest; + std::tie(Arg0, Rest) = Cmdline->getBuffer().split('\0'); + process_info.SetArg0(Arg0); + while (!Rest.empty()) { + llvm::StringRef Arg; + std::tie(Arg, Rest) = Rest.split('\0'); + process_info.GetArguments().AppendArgument(Arg); + } +} + +static void GetExePathAndArch(::pid_t pid, ProcessInstanceInfo &process_info) { + Log *log = GetLog(LLDBLog::Process); + std::string ExePath(PATH_MAX, '\0'); + std::string Basename(PATH_MAX, '\0'); + struct psinfo psinfoData; + + // We can't use getProcFile here because proc/[pid]/exe is a symbolic link. + llvm::SmallString<64> ProcExe; + (llvm::Twine("/proc/") + llvm::Twine(pid) + "/cwd").toVector(ProcExe); + + ssize_t len = readlink(ProcExe.c_str(), &ExePath[0], PATH_MAX); + if (len > 0) { + ExePath.resize(len); + + //FIXME: hack to get basename + struct stat statData; + + std::ostringstream oss; + + oss << "/proc/" << std::dec << pid << "/psinfo"; + assert(stat(oss.str().c_str(), &statData) == 0); + + const int fd = open(oss.str().c_str(), O_RDONLY); + assert (fd >= 0); + + ssize_t readNum = read(fd, &psinfoData, sizeof(psinfoData)); + assert (readNum >= 0); + + close (fd); + } else { + LLDB_LOG(log, "failed to read link exe link for {0}: {1}", pid, + Status(errno, eErrorTypePOSIX)); + ExePath.resize(0); + } + + llvm::StringRef PathRef = std::string(&(psinfoData.pr_psargs[0])); + + if (!PathRef.empty()) { + process_info.GetExecutableFile().SetFile(PathRef, FileSpec::Style::native); + ArchSpec arch_spec = ArchSpec(); + arch_spec.SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX); + process_info.SetArchitecture(arch_spec); + } +} + +static void GetProcessEnviron(::pid_t pid, ProcessInstanceInfo &process_info) { + // Get the process environment. + auto BufferOrError = getProcFile(pid, "environ"); + if (!BufferOrError) + return; + + std::unique_ptr Environ = std::move(*BufferOrError); + llvm::StringRef Rest = Environ->getBuffer(); + while (!Rest.empty()) { + llvm::StringRef Var; + std::tie(Var, Rest) = Rest.split('\0'); + process_info.GetEnvironment().insert(Var); + } +} + +static bool GetProcessAndStatInfo(::pid_t pid, + ProcessInstanceInfo &process_info, + ProcessState &State, ::pid_t &tracerpid) { + ::pid_t tgid; + tracerpid = 0; + process_info.Clear(); + + process_info.SetProcessID(pid); + + GetExePathAndArch(pid, process_info); + GetProcessArgs(pid, process_info); + GetProcessEnviron(pid, process_info); + + // Get User and Group IDs and get tracer pid. + if (!GetStatusInfo(pid, process_info, State, tracerpid, tgid)) + return false; + + return true; +} + +uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { + static const char procdir[] = "/proc/"; + + DIR *dirproc = opendir(procdir); + if (dirproc) { + struct dirent *direntry = nullptr; + const uid_t our_uid = getuid(); + const lldb::pid_t our_pid = getpid(); + bool all_users = match_info.GetMatchAllUsers(); + + while ((direntry = readdir(dirproc)) != nullptr) { + /* + if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name)) + continue; + */ + + lldb::pid_t pid = atoi(direntry->d_name); + + // Skip this process. + if (pid == our_pid) + continue; + + ::pid_t tracerpid; + ProcessState State; + ProcessInstanceInfo process_info; + + if (!GetProcessAndStatInfo(pid, process_info, State, tracerpid)) + continue; + + // Skip if process is being debugged. + if (tracerpid != 0) + continue; + + if (State == ProcessState::Zombie) + continue; + + // Check for user match if we're not matching all users and not running + // as root. + if (!all_users && (our_uid != 0) && (process_info.GetUserID() != our_uid)) + continue; + + if (match_info.Matches(process_info)) { + process_infos.push_back(process_info); + } + } + + closedir(dirproc); + } + + return process_infos.size(); +} + +bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { + ::pid_t tracerpid; + ProcessState State; + return GetProcessAndStatInfo(pid, process_info, State, tracerpid); +} + +Environment Host::GetEnvironment() { return Environment(environ); } + +Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) { + return Status("unimplemented"); +} + +std::optional lldb_private::getPIDForTID(lldb::pid_t tid) { + ::pid_t tracerpid, tgid = LLDB_INVALID_PROCESS_ID; + ProcessInstanceInfo process_info; + ProcessState state; + + if (!GetStatusInfo(tid, process_info, state, tracerpid, tgid) || + tgid == LLDB_INVALID_PROCESS_ID) + return std::nullopt; + return tgid; +} diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp new file mode 100644 index 0000000000000..8bda09e01741b --- /dev/null +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -0,0 +1,215 @@ +//===-- HostInfoAIX.cpp -------------------------------------------------===// +// +// 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 "lldb/Host/aix/HostInfoAIX.h" +#include "lldb/Host/Config.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" + +#include "llvm/Support/Threading.h" + +#include +#include +#include +#include +#include + +#include +#include + +using namespace lldb_private; + +namespace { +struct HostInfoAIXFields { + llvm::once_flag m_distribution_once_flag; + std::string m_distribution_id; + llvm::once_flag m_os_version_once_flag; + llvm::VersionTuple m_os_version; +}; +} // namespace + +static HostInfoAIXFields *g_fields = nullptr; + +void HostInfoAIX::Initialize(SharedLibraryDirectoryHelper *helper) { + HostInfoPosix::Initialize(helper); + + g_fields = new HostInfoAIXFields(); +} + +void HostInfoAIX::Terminate() { + assert(g_fields && "Missing call to Initialize?"); + delete g_fields; + g_fields = nullptr; + HostInfoBase::Terminate(); +} + +llvm::VersionTuple HostInfoAIX::GetOSVersion() { + assert(g_fields && "Missing call to Initialize?"); + llvm::call_once(g_fields->m_os_version_once_flag, []() { + struct utsname un; + if (uname(&un) != 0) + return; + + llvm::StringRef release = un.release; + // The kernel release string can include a lot of stuff (e.g. + // 4.9.0-6-amd64). We're only interested in the numbered prefix. + release = release.substr(0, release.find_first_not_of("0123456789.")); + g_fields->m_os_version.tryParse(release); + }); + + return g_fields->m_os_version; +} + +std::optional HostInfoAIX::GetOSBuildString() { + struct utsname un; + ::memset(&un, 0, sizeof(utsname)); + + if (uname(&un) < 0) + return std::nullopt; + + return std::string(un.release); +} + +llvm::StringRef HostInfoAIX::GetDistributionId() { + assert(g_fields && "Missing call to Initialize?"); + // Try to run 'lbs_release -i', and use that response for the distribution + // id. + llvm::call_once(g_fields->m_distribution_once_flag, []() { + Log *log = GetLog(LLDBLog::Host); + LLDB_LOGF(log, "attempting to determine AIX distribution..."); + + // check if the lsb_release command exists at one of the following paths + const char *const exe_paths[] = {"/bin/lsb_release", + "/usr/bin/lsb_release"}; + + for (size_t exe_index = 0; + exe_index < sizeof(exe_paths) / sizeof(exe_paths[0]); ++exe_index) { + const char *const get_distribution_info_exe = exe_paths[exe_index]; + if (access(get_distribution_info_exe, F_OK)) { + // this exe doesn't exist, move on to next exe + LLDB_LOGF(log, "executable doesn't exist: %s", + get_distribution_info_exe); + continue; + } + + // execute the distribution-retrieval command, read output + std::string get_distribution_id_command(get_distribution_info_exe); + get_distribution_id_command += " -i"; + + FILE *file = popen(get_distribution_id_command.c_str(), "r"); + if (!file) { + LLDB_LOGF(log, + "failed to run command: \"%s\", cannot retrieve " + "platform information", + get_distribution_id_command.c_str()); + break; + } + + // retrieve the distribution id string. + char distribution_id[256] = {'\0'}; + if (fgets(distribution_id, sizeof(distribution_id) - 1, file) != + nullptr) { + LLDB_LOGF(log, "distribution id command returned \"%s\"", + distribution_id); + + const char *const distributor_id_key = "Distributor ID:\t"; + if (strstr(distribution_id, distributor_id_key)) { + // strip newlines + std::string id_string(distribution_id + strlen(distributor_id_key)); + id_string.erase(std::remove(id_string.begin(), id_string.end(), '\n'), + id_string.end()); + + // lower case it and convert whitespace to underscores + std::transform( + id_string.begin(), id_string.end(), id_string.begin(), + [](char ch) { return tolower(isspace(ch) ? '_' : ch); }); + + g_fields->m_distribution_id = id_string; + LLDB_LOGF(log, "distribution id set to \"%s\"", + g_fields->m_distribution_id.c_str()); + } else { + LLDB_LOGF(log, "failed to find \"%s\" field in \"%s\"", + distributor_id_key, distribution_id); + } + } else { + LLDB_LOGF(log, + "failed to retrieve distribution id, \"%s\" returned no" + " lines", + get_distribution_id_command.c_str()); + } + + // clean up the file + pclose(file); + } + }); + + return g_fields->m_distribution_id; +} + +FileSpec HostInfoAIX::GetProgramFileSpec() { + static FileSpec g_program_filespec; + + if (!g_program_filespec) { + char exe_path[PATH_MAX]; + ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); + if (len > 0) { + exe_path[len] = 0; + g_program_filespec.SetFile(exe_path, FileSpec::Style::native); + } + } + + return g_program_filespec; +} + +bool HostInfoAIX::ComputeSupportExeDirectory(FileSpec &file_spec) { + if (HostInfoPosix::ComputeSupportExeDirectory(file_spec) && + file_spec.IsAbsolute() && FileSystem::Instance().Exists(file_spec)) + return true; + file_spec.SetDirectory(GetProgramFileSpec().GetDirectory()); + return !file_spec.GetDirectory().IsEmpty(); +} + +bool HostInfoAIX::ComputeSystemPluginsDirectory(FileSpec &file_spec) { + FileSpec temp_file("/usr/" LLDB_INSTALL_LIBDIR_BASENAME "/lldb/plugins"); + FileSystem::Instance().Resolve(temp_file); + file_spec.SetDirectory(temp_file.GetPath()); + return true; +} + +bool HostInfoAIX::ComputeUserPluginsDirectory(FileSpec &file_spec) { + // XDG Base Directory Specification + // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html If + // XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb. + const char *xdg_data_home = getenv("XDG_DATA_HOME"); + if (xdg_data_home && xdg_data_home[0]) { + std::string user_plugin_dir(xdg_data_home); + user_plugin_dir += "/lldb"; + file_spec.SetDirectory(user_plugin_dir.c_str()); + } else + file_spec.SetDirectory("~/.local/share/lldb"); + return true; +} + +void HostInfoAIX::ComputeHostArchitectureSupport(ArchSpec &arch_32, + ArchSpec &arch_64) { + HostInfoPosix::ComputeHostArchitectureSupport(arch_32, arch_64); + + const char *distribution_id = GetDistributionId().data(); + + // On Linux, "unknown" in the vendor slot isn't what we want for the default + // triple. It's probably an artifact of config.guess. + if (arch_32.IsValid()) { + if (arch_32.GetTriple().getVendor() == llvm::Triple::UnknownVendor) + arch_32.GetTriple().setVendorName(llvm::StringRef()); + } + if (arch_64.IsValid()) { + if (arch_64.GetTriple().getVendor() == llvm::Triple::UnknownVendor) + arch_64.GetTriple().setVendorName(llvm::StringRef()); + } +} diff --git a/lldb/source/Host/aix/Support.cpp b/lldb/source/Host/aix/Support.cpp new file mode 100644 index 0000000000000..1bf2662190127 --- /dev/null +++ b/lldb/source/Host/aix/Support.cpp @@ -0,0 +1,44 @@ +//===-- Support.cpp -------------------------------------------------------===// +// +// 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 "lldb/Host/aix/Support.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "llvm/Support/MemoryBuffer.h" + +llvm::ErrorOr> +lldb_private::getProcFile(::pid_t pid, ::pid_t tid, const llvm::Twine &file) { + Log *log = GetLog(LLDBLog::Host); + std::string File = + ("/proc/" + llvm::Twine(pid) + "/task/" + llvm::Twine(tid) + "/" + file) + .str(); + auto Ret = llvm::MemoryBuffer::getFileAsStream(File); + if (!Ret) + LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message()); + return Ret; +} + +llvm::ErrorOr> +lldb_private::getProcFile(::pid_t pid, const llvm::Twine &file) { + Log *log = GetLog(LLDBLog::Host); + std::string File = ("/proc/" + llvm::Twine(pid) + "/" + file).str(); + auto Ret = llvm::MemoryBuffer::getFileAsStream(File); + if (!Ret) + LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message()); + return Ret; +} + +llvm::ErrorOr> +lldb_private::getProcFile(const llvm::Twine &file) { + Log *log = GetLog(LLDBLog::Host); + std::string File = ("/proc/" + file).str(); + auto Ret = llvm::MemoryBuffer::getFileAsStream(File); + if (!Ret) + LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message()); + return Ret; +} diff --git a/lldb/source/Host/common/GetOptInc.cpp b/lldb/source/Host/common/GetOptInc.cpp index c2044b6873221..e0ae2aa1774b3 100644 --- a/lldb/source/Host/common/GetOptInc.cpp +++ b/lldb/source/Host/common/GetOptInc.cpp @@ -409,7 +409,7 @@ static int getopt_internal(int nargc, char *const *nargv, const char *options, * [eventually this will replace the BSD getopt] */ #if defined(REPLACE_GETOPT) -int getopt(int nargc, char *const *nargv, const char *options) { +int getopt(int nargc, char *const *nargv, const char *options) throw() { /* * We don't pass FLAG_PERMUTE to getopt_internal() since diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index e03d36e9cad4a..2fd7111a94fb2 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -357,9 +357,183 @@ bool Host::ResolveExecutableInBundle(FileSpec &file) { return false; } #ifndef _WIN32 +#if defined(__AIX__) + +#include +extern char **p_xargv; + +/* Fix missing Dl_info & dladdr in AIX + * The code is taken from netbsd.org (src/crypto/external/bsd/openssl/dist/crypto/dso/dso_dlfcn.c) + * except strlcpy & strlcat (those are taken from openbsd.org (src/lib/libc/string)) + */ +/*- + * See IBM's AIX Version 7.2, Technical Reference: + * Base Operating System and Extensions, Volume 1 and 2 + * https://www.ibm.com/support/knowledgecenter/ssw_aix_72/com.ibm.aix.base/technicalreferences.htm + */ +#include +#include + +/* strlcpy: + * Copy string src to buffer dst of size dsize. At most dsize-1 + * chars will be copied. Always NUL terminates (unless dsize == 0). + * Returns strlen(src); if retval >= dsize, truncation occurred. + */ +size_t strlcpy(char *dst, const char *src, size_t dsize) +{ + const char *osrc = src; + size_t nleft = dsize; + + /* Copy as many bytes as will fit. */ + if (nleft != 0) { + while (--nleft != 0) { + if ((*dst++ = *src++) == '\0') { + break; + } + } + } + + /* Not enough room in dst, add NUL and traverse rest of src. */ + if (nleft == 0) { + if (dsize != 0) { + *dst = '\0'; /* NUL-terminate dst */ + } + while (*src++) { + ; + } + } + + return src - osrc - 1; /* count does not include NUL */ +} + +/* strlcat: + * Appends src to string dst of size dsize (unlike strncat, dsize is the + * full size of dst, not space left). At most dsize-1 characters + * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). + * Returns strlen(src) + MIN(dsize, strlen(initial dst)). + * If retval >= dsize, truncation occurred. + */ +size_t strlcat(char *dst, const char *src, size_t dsize) +{ + const char *odst = dst; + const char *osrc = src; + size_t n = dsize; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end. */ + while (n-- != 0 && *dst != '\0') { + dst++; + } + dlen = dst - odst; + n = dsize - dlen; + + if (n-- == 0) { + return dlen + strlen(src); + } + while (*src != '\0') { + if (n != 0) { + *dst++ = *src; + n--; + } + src++; + } + *dst = '\0'; + + return dlen + src - osrc; /* count does not include NUL */ +} + +/* ~ 64 * (sizeof(struct ld_info) + _XOPEN_PATH_MAX + _XOPEN_NAME_MAX) */ +# define DLFCN_LDINFO_SIZE 86976 +typedef struct Dl_info { + const char *dli_fname; +} Dl_info; +/* + * This dladdr()-implementation will also find the ptrgl (Pointer Glue) virtual + * address of a function, which is just located in the DATA segment instead of + * the TEXT segment. + */ +static int dladdr(const void *ptr, Dl_info *dl) +{ + uintptr_t addr = (uintptr_t)ptr; + struct ld_info *ldinfos; + struct ld_info *next_ldi; + struct ld_info *this_ldi; + + if ((ldinfos = (struct ld_info *)malloc(DLFCN_LDINFO_SIZE)) == NULL) { + dl->dli_fname = NULL; + return 0; + } + + if ((loadquery(L_GETINFO, (void *)ldinfos, DLFCN_LDINFO_SIZE)) < 0) { + /*- + * Error handling is done through errno and dlerror() reading errno: + * ENOMEM (ldinfos buffer is too small), + * EINVAL (invalid flags), + * EFAULT (invalid ldinfos ptr) + */ + free((void *)ldinfos); + dl->dli_fname = NULL; + return 0; + } + next_ldi = ldinfos; + + do { + this_ldi = next_ldi; + if (((addr >= (uintptr_t)this_ldi->ldinfo_textorg) + && (addr < ((uintptr_t)this_ldi->ldinfo_textorg + + this_ldi->ldinfo_textsize))) + || ((addr >= (uintptr_t)this_ldi->ldinfo_dataorg) + && (addr < ((uintptr_t)this_ldi->ldinfo_dataorg + + this_ldi->ldinfo_datasize)))) { + char *buffer = NULL; + char *member = NULL; + size_t buffer_sz; + size_t member_len; + + buffer_sz = strlen(this_ldi->ldinfo_filename) + 1; + member = this_ldi->ldinfo_filename + buffer_sz; + if ((member_len = strlen(member)) > 0) { + buffer_sz += 1 + member_len + 1; + } + if ((buffer = (char *)malloc(buffer_sz)) != NULL) { + strlcpy(buffer, this_ldi->ldinfo_filename, buffer_sz); + if (member_len > 0) { + /* + * Need to respect a possible member name and not just + * returning the path name in this case. See docs: + * sys/ldr.h, loadquery() and dlopen()/RTLD_MEMBER. + */ + strlcat(buffer, "(", buffer_sz); + strlcat(buffer, member, buffer_sz); + strlcat(buffer, ")", buffer_sz); + } + dl->dli_fname = buffer; + } + break; + } else { + next_ldi = (struct ld_info *)((uintptr_t)this_ldi + + this_ldi->ldinfo_next); + } + } while (this_ldi->ldinfo_next); + free((void *)ldinfos); + return dl->dli_fname != NULL; +} + +#endif + FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSpec module_filespec; #if !defined(__ANDROID__) +#ifdef __AIX__ + if (host_addr == reinterpret_cast(HostInfoBase::ComputeSharedLibraryDirectory)) { + // FIXME: AIX dladdr return "lldb" for this case + if (p_xargv[0]) { + module_filespec.SetFile(p_xargv[0], FileSpec::Style::native); + FileSystem::Instance().Resolve(module_filespec); + return module_filespec; + } + } +#endif Dl_info info; if (::dladdr(host_addr, &info)) { if (info.dli_fname) { @@ -373,12 +547,6 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { #endif -#if !defined(__linux__) -bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) { - return false; -} -#endif - struct ShellInfo { ShellInfo() : process_reaped(false) {} diff --git a/lldb/source/Host/common/LICENSE.aix-netbsd.txt b/lldb/source/Host/common/LICENSE.aix-netbsd.txt new file mode 100644 index 0000000000000..9601ab43575f9 --- /dev/null +++ b/lldb/source/Host/common/LICENSE.aix-netbsd.txt @@ -0,0 +1,125 @@ + + LICENSE ISSUES + ============== + + The OpenSSL toolkit stays under a double license, i.e. both the conditions of + the OpenSSL License and the original SSLeay license apply to the toolkit. + See below for the actual license texts. + + OpenSSL License + --------------- + +/* ==================================================================== + * Copyright (c) 1998-2019 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core at openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay at cryptsoft.com). This product includes software written by Tim + * Hudson (tjh at cryptsoft.com). + * + */ + + Original SSLeay License + ----------------------- + +/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay at cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh at cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay at cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh at cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + diff --git a/lldb/source/Host/common/XML.cpp b/lldb/source/Host/common/XML.cpp index f480ef3166a44..62cac78aaac23 100644 --- a/lldb/source/Host/common/XML.cpp +++ b/lldb/source/Host/common/XML.cpp @@ -10,6 +10,9 @@ #include "lldb/Host/XML.h" #include "llvm/ADT/StringExtras.h" +#if defined(__AIX__) +#undef LLDB_ENABLE_LIBXML2 +#endif using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index fceeff08ed9d3..143254bb12901 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -721,6 +721,7 @@ ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, ConnectionStatus ConnectionFileDescriptor::ConnectFile( llvm::StringRef s, socket_id_callback_type socket_id_callback, Status *error_ptr) { +#if !defined(__AIX__) #if LLDB_ENABLE_POSIX std::string addr_str = s.str(); // file:///PATH @@ -753,6 +754,7 @@ ConnectionStatus ConnectionFileDescriptor::ConnectFile( m_io_sp = std::make_shared(fd, File::eOpenOptionReadWrite, true); return eConnectionStatusSuccess; #endif // LLDB_ENABLE_POSIX +#endif llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX"); } diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index cdb76da626bc9..a7c50f6a3c835 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,7 +11,9 @@ // C includes #include #include +#if !defined(__AIX__) #include +#endif #include #include #include diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp index 5fe4d015251c8..e5be0db4cf19b 100644 --- a/lldb/source/Host/posix/MainLoopPosix.cpp +++ b/lldb/source/Host/posix/MainLoopPosix.cpp @@ -179,9 +179,21 @@ Status MainLoopPosix::RunImpl::Poll() { read_fds.push_back(pfd); } +#if defined(__AIX__) + sigset_t origmask; + int timeout; + + timeout = -1; + pthread_sigmask(SIG_SETMASK, &sigmask, &origmask); + int ready = poll(read_fds.data(), read_fds.size(), timeout); + pthread_sigmask(SIG_SETMASK, &origmask, nullptr); + if (ready == -1 && errno != EINTR) + return Status(errno, eErrorTypePOSIX); +#else if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 && errno != EINTR) return Status(errno, eErrorTypePOSIX); +#endif return Status(); } @@ -312,8 +324,13 @@ MainLoopPosix::RegisterSignal(int signo, const Callback &callback, // If we're using kqueue, the signal needs to be unblocked in order to // receive it. If using pselect/ppoll, we need to block it, and later unblock // it as a part of the system call. +#if defined(__AIX__) + //FIXME: where is signal unblocked? + ret = pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, &old_set); +#else ret = pthread_sigmask(HAVE_SYS_EVENT_H ? SIG_UNBLOCK : SIG_BLOCK, &new_action.sa_mask, &old_set); +#endif assert(ret == 0 && "pthread_sigmask failed"); info.was_blocked = sigismember(&old_set, signo); auto insert_ret = m_signals.insert({signo, info}); diff --git a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp index 0a832ebad13a7..cd106f605b1f4 100644 --- a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp +++ b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp @@ -193,8 +193,13 @@ struct ForkLaunchInfo { } // Start tracing this child that is about to exec. +#if !defined(__AIX__) if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1) ExitWithError(error_fd, "ptrace"); +#else + if (ptrace64(PT_TRACE_ME, 0, 0, 0, nullptr) == -1) + ExitWithError(error_fd, "ptrace"); +#endif } // Execute. We should never return... diff --git a/lldb/source/Initialization/CMakeLists.txt b/lldb/source/Initialization/CMakeLists.txt index c1a167826f76f..9f94830c8509f 100644 --- a/lldb/source/Initialization/CMakeLists.txt +++ b/lldb/source/Initialization/CMakeLists.txt @@ -1,4 +1,4 @@ -if ( CMAKE_SYSTEM_NAME MATCHES "Linux|Android|FreeBSD|NetBSD" ) +if ( CMAKE_SYSTEM_NAME MATCHES "Linux|Android|FreeBSD|NetBSD|AIX" ) list(APPEND EXTRA_PLUGINS lldbPluginProcessPOSIX) endif() diff --git a/lldb/source/Initialization/SystemInitializerCommon.cpp b/lldb/source/Initialization/SystemInitializerCommon.cpp index 1a172a95aa147..4b01442a94bac 100644 --- a/lldb/source/Initialization/SystemInitializerCommon.cpp +++ b/lldb/source/Initialization/SystemInitializerCommon.cpp @@ -19,7 +19,7 @@ #include "lldb/Version/Version.h" #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__OpenBSD__) + defined(__OpenBSD__) || defined(__AIX__) #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" #endif @@ -79,7 +79,7 @@ llvm::Error SystemInitializerCommon::Initialize() { process_gdb_remote::ProcessGDBRemoteLog::Initialize(); #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__OpenBSD__) + defined(__OpenBSD__) || defined(__AIX__) ProcessPOSIXLog::Initialize(); #endif #if defined(_WIN32) diff --git a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp index eac058701313b..feb0d7c0e09be 100644 --- a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp +++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp @@ -156,6 +156,9 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) return false; +#if defined(__AIX__) + assert(0); +#else // Read TOC pointer value. reg_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0); @@ -171,6 +174,132 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, (uint64_t)reg_value); if (!process_sp->WritePointerToMemory(sp + stack_offset, reg_value, error)) return false; +#endif + + // Read the current SP value. + reg_value = reg_ctx->ReadRegisterAsUnsigned(sp_reg_info, 0); + + // Save current SP onto the stack. + LLDB_LOGF(log, "Writing SP at SP(0x%" PRIx64 ")+0: 0x%" PRIx64, (uint64_t)sp, + (uint64_t)reg_value); + if (!process_sp->WritePointerToMemory(sp, reg_value, error)) + return false; + + // %r1 is set to the actual stack value. + LLDB_LOGF(log, "Writing SP: 0x%" PRIx64, (uint64_t)sp); + + if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_info, sp)) + return false; + + // %pc is set to the address of the called function. + + LLDB_LOGF(log, "Writing IP: 0x%" PRIx64, (uint64_t)func_addr); + + if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_info, func_addr)) + return false; + + return true; +} + +bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, + addr_t func_addr, addr_t toc_addr, + addr_t return_addr, + llvm::ArrayRef args) const { + Log *log = GetLog(LLDBLog::Expressions); + + if (log) { + StreamString s; + s.Printf("ABISysV_ppc64::PrepareTrivialCall (tid = 0x%" PRIx64 + ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 + ", return_addr = 0x%" PRIx64, + thread.GetID(), (uint64_t)sp, (uint64_t)func_addr, + (uint64_t)return_addr); + + for (size_t i = 0; i < args.size(); ++i) + s.Printf(", arg%" PRIu64 " = 0x%" PRIx64, static_cast(i + 1), + args[i]); + s.PutCString(")"); + log->PutString(s.GetString()); + } + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return false; + + const RegisterInfo *reg_info = nullptr; + + if (args.size() > 8) // TODO handle more than 8 arguments + return false; + + for (size_t i = 0; i < args.size(); ++i) { + reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_ARG1 + i); + LLDB_LOGF(log, "About to write arg%" PRIu64 " (0x%" PRIx64 ") into %s", + static_cast(i + 1), args[i], reg_info->name); + if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) + return false; + } + + // First, align the SP + + LLDB_LOGF(log, "16-byte aligning SP: 0x%" PRIx64 " to 0x%" PRIx64, + (uint64_t)sp, (uint64_t)(sp & ~0xfull)); + + sp &= ~(0xfull); // 16-byte alignment + + sp -= 544; // allocate frame to save TOC, RA and SP. + + Status error; + uint64_t reg_value; + const RegisterInfo *pc_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + const RegisterInfo *sp_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); + ProcessSP process_sp(thread.GetProcess()); + const RegisterInfo *lr_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); + const RegisterInfo *r2_reg_info = reg_ctx->GetRegisterInfoAtIndex(2); + const RegisterInfo *r12_reg_info = reg_ctx->GetRegisterInfoAtIndex(12); + + // Save return address onto the stack. + LLDB_LOGF(log, + "Pushing the return address onto the stack: 0x%" PRIx64 + "(+16): 0x%" PRIx64, + (uint64_t)sp, (uint64_t)return_addr); + if (!process_sp->WritePointerToMemory(sp + 16, return_addr, error)) + return false; + + // Write the return address to link register. + LLDB_LOGF(log, "Writing LR: 0x%" PRIx64, (uint64_t)return_addr); + if (!reg_ctx->WriteRegisterFromUnsigned(lr_reg_info, return_addr)) + return false; + + // Write target address to %r12 register. + LLDB_LOGF(log, "Writing R12: 0x%" PRIx64, (uint64_t)func_addr); + if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) + return false; + +#if defined(__AIX__) + LLDB_LOGF(log, "Writing R2: 0x%" PRIx64, (uint64_t)toc_addr); + if (!reg_ctx->WriteRegisterFromUnsigned(r2_reg_info, toc_addr)) + return false; +#else + // Read TOC pointer value. + reg_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0); + + // Write TOC pointer onto the stack. + uint64_t stack_offset; + if (GetByteOrder() == lldb::eByteOrderLittle) + stack_offset = 24; + else + stack_offset = 40; + + LLDB_LOGF(log, "Writing R2 (TOC) at SP(0x%" PRIx64 ")+%d: 0x%" PRIx64, + (uint64_t)(sp + stack_offset), (int)stack_offset, + (uint64_t)reg_value); + if (!process_sp->WritePointerToMemory(sp + stack_offset, reg_value, error)) + return false; +#endif // Read the current SP value. reg_value = reg_ctx->ReadRegisterAsUnsigned(sp_reg_info, 0); @@ -641,7 +770,7 @@ class ReturnValueExtractor { DataExtractor de(&raw_data, sizeof(raw_data), m_byte_order, m_addr_size); - offset_t offset = 0; + lldb::offset_t offset = 0; std::optional byte_size = type.GetByteSize(m_process_sp.get()); if (!byte_size) return {}; diff --git a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h index bfa96cc0df703..d752a8ded9748 100644 --- a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h +++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h @@ -23,6 +23,12 @@ class ABISysV_ppc64 : public lldb_private::RegInfoBasedABI { lldb::addr_t returnAddress, llvm::ArrayRef args) const override; + bool PrepareTrivialCall(lldb_private::Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t tocAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef args) const override; + bool GetArgumentValues(lldb_private::Thread &thread, lldb_private::ValueList &values) const override; diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt new file mode 100644 index 0000000000000..02fe0d617955a --- /dev/null +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt @@ -0,0 +1,11 @@ +add_definitions("-D_ALL_SOURCE") + +add_lldb_library(lldbPluginDynamicLoaderAIXDYLD PLUGIN + DynamicLoaderAIXDYLD.cpp + + LINK_LIBS + lldbCore + lldbTarget + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp new file mode 100644 index 0000000000000..62663974134b0 --- /dev/null +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -0,0 +1,272 @@ +//===-- DynamicLoaderAIXDYLD.cpp --------------------------------------===// +// +// 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 "DynamicLoaderAIXDYLD.h" + +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Platform.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/ThreadPlanStepInstruction.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#if defined(__AIX__) +#include +#endif + +/*#include "llvm/ADT/Triple.h" +*/ + +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(DynamicLoaderAIXDYLD) + +DynamicLoaderAIXDYLD::DynamicLoaderAIXDYLD(Process *process) + : DynamicLoader(process) {} + +DynamicLoaderAIXDYLD::~DynamicLoaderAIXDYLD() = default; + +void DynamicLoaderAIXDYLD::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); +} + +void DynamicLoaderAIXDYLD::Terminate() {} + +llvm::StringRef DynamicLoaderAIXDYLD::GetPluginDescriptionStatic() { + return "Dynamic loader plug-in that watches for shared library " + "loads/unloads in AIX processes."; +} + +DynamicLoader *DynamicLoaderAIXDYLD::CreateInstance(Process *process, + bool force) { + bool should_create = force; + if (!should_create) { + const llvm::Triple &triple_ref = + process->GetTarget().GetArchitecture().GetTriple(); + if (triple_ref.getOS() == llvm::Triple::AIX) + should_create = true; + } + + if (should_create) + return new DynamicLoaderAIXDYLD(process); + + return nullptr; +} + +void DynamicLoaderAIXDYLD::OnLoadModule(lldb::ModuleSP module_sp, + const ModuleSpec module_spec, + lldb::addr_t module_addr) { + + // Resolve the module unless we already have one. + if (!module_sp) { + Status error; + module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, + true /* notify */, &error); + if (error.Fail()) + return; + } + + m_loaded_modules[module_sp] = module_addr; + UpdateLoadedSectionsCommon(module_sp, module_addr, false); + ModuleList module_list; + module_list.Append(module_sp); + m_process->GetTarget().ModulesDidLoad(module_list); +} + +void DynamicLoaderAIXDYLD::OnUnloadModule(lldb::addr_t module_addr) { + Address resolved_addr; + if (!m_process->GetTarget().ResolveLoadAddress(module_addr, resolved_addr)) + return; + + ModuleSP module_sp = resolved_addr.GetModule(); + if (module_sp) { + m_loaded_modules.erase(module_sp); + UnloadSectionsCommon(module_sp); + ModuleList module_list; + module_list.Append(module_sp); + m_process->GetTarget().ModulesDidUnload(module_list, false); + } +} + +lldb::addr_t DynamicLoaderAIXDYLD::GetLoadAddress(ModuleSP executable) { + // First, see if the load address is already cached. + auto it = m_loaded_modules.find(executable); + if (it != m_loaded_modules.end() && it->second != LLDB_INVALID_ADDRESS) + return it->second; + + lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; + + // Second, try to get it through the process plugins. For a remote process, + // the remote platform will be responsible for providing it. + FileSpec file_spec(executable->GetPlatformFileSpec()); + bool is_loaded = false; + Status status = + m_process->GetFileLoadAddress(file_spec, is_loaded, load_addr); + // Servers other than lldb server could respond with a bogus address. + if (status.Success() && is_loaded && load_addr != LLDB_INVALID_ADDRESS) { + m_loaded_modules[executable] = load_addr; + return load_addr; + } + + //// Hack to try set breakpoint + //Breakpoint *dyld_break = m_process->GetTarget().CreateBreakpoint(0x100000638, true, false).get(); + //dyld_break->SetCallback(DynamicLoaderAIXDYLD::NotifyBreakpointHit, this, true); + //dyld_break->SetBreakpointKind("hack-debug"); + + return LLDB_INVALID_ADDRESS; +} + +bool DynamicLoaderAIXDYLD::NotifyBreakpointHit( + void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, + lldb::user_id_t break_loc_id) { +} + +void DynamicLoaderAIXDYLD::DidAttach() { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); + + ModuleSP executable = GetTargetExecutable(); + + if (!executable.get()) + return; + + // Try to fetch the load address of the file from the process, since there + // could be randomization of the load address. + lldb::addr_t load_addr = GetLoadAddress(executable); + if (load_addr == LLDB_INVALID_ADDRESS) + return; + + // Request the process base address. + lldb::addr_t image_base = m_process->GetImageInfoAddress(); + if (image_base == load_addr) + return; + + // Rebase the process's modules if there is a mismatch. + UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_addr, false); + + ModuleList module_list; + module_list.Append(executable); + m_process->GetTarget().ModulesDidLoad(module_list); + auto error = m_process->LoadModules(); + LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}"); + +#if defined(__AIX__) + // Get struct ld_xinfo (FIXME) + struct ld_xinfo ldinfo[64]; + Status status = m_process->GetLDXINFO(&(ldinfo[0])); + if (status.Fail()) { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOG(log, "LDXINFO failed: {0}", status); + return; + } + struct ld_xinfo *ptr = &(ldinfo[0]); + bool skip_current = true; + while (ptr != nullptr) { + char *pathName = (char *)ptr + ptr->ldinfo_filename; + char *memberName = pathName + (strlen(pathName) + 1); + if (!skip_current) { + // FIXME: buffer size + char pathWithMember[128] = {0}; + if (strlen(memberName) > 0) { + sprintf(pathWithMember, "%s(%s)", pathName, memberName); + } else { + sprintf(pathWithMember, "%s", pathName); + } + FileSpec file(pathWithMember); + ModuleSpec module_spec(file, m_process->GetTarget().GetArchitecture()); + if (ModuleSP module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, true /* notify */)) { + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_textorg, false, 1); + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_dataorg, false, 2); + // FIXME: .tdata, .bss + } + } else { + skip_current = false; + } + if (ptr->ldinfo_next == 0) { + ptr = nullptr; + } else { + ptr = (struct ld_xinfo *)((char *)ptr + ptr->ldinfo_next); + } + } +#endif +} + +void DynamicLoaderAIXDYLD::DidLaunch() { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); + + ModuleSP executable = GetTargetExecutable(); + if (!executable.get()) + return; + + lldb::addr_t load_addr = GetLoadAddress(executable); + if (load_addr != LLDB_INVALID_ADDRESS) { + // Update the loaded sections so that the breakpoints can be resolved. + UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_addr, false); + + ModuleList module_list; + module_list.Append(executable); + m_process->GetTarget().ModulesDidLoad(module_list); + auto error = m_process->LoadModules(); + LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}"); + } + +#if defined(__AIX__) + // Get struct ld_xinfo (FIXME) + struct ld_xinfo ldinfo[64]; + Status status = m_process->GetLDXINFO(&(ldinfo[0])); + if (status.Fail()) { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOG(log, "LDXINFO failed: {0}", status); + return; + } + struct ld_xinfo *ptr = &(ldinfo[0]); + bool skip_current = true; + while (ptr != nullptr) { + char *pathName = (char *)ptr + ptr->ldinfo_filename; + char *memberName = pathName + (strlen(pathName) + 1); + if (!skip_current) { + // FIXME: buffer size + char pathWithMember[128] = {0}; + if (strlen(memberName) > 0) { + sprintf(pathWithMember, "%s(%s)", pathName, memberName); + } else { + sprintf(pathWithMember, "%s", pathName); + } + FileSpec file(pathWithMember); + ModuleSpec module_spec(file, m_process->GetTarget().GetArchitecture()); + if (ModuleSP module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, true /* notify */)) { + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_textorg, false, 1); + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_dataorg, false, 2); + // FIXME: .tdata, .bss + } + } else { + skip_current = false; + } + if (ptr->ldinfo_next == 0) { + ptr = nullptr; + } else { + ptr = (struct ld_xinfo *)((char *)ptr + ptr->ldinfo_next); + } + } +#endif +} + +Status DynamicLoaderAIXDYLD::CanLoadImage() { return Status(); } + +ThreadPlanSP +DynamicLoaderAIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, + bool stop) { + //FIXME + return ThreadPlanSP(); +} diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h new file mode 100644 index 0000000000000..ae4b7aca66dcc --- /dev/null +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -0,0 +1,55 @@ +//===-- DynamicLoaderAIXDYLD.h ------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_DYNAMICLOADER_AIX_DYLD_DYNAMICLOADERAIXDYLD_H +#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_AIX_DYLD_DYNAMICLOADERAIXDYLD_H + +#include "lldb/Target/DynamicLoader.h" +#include "lldb/lldb-forward.h" + +#include + +namespace lldb_private { + +class DynamicLoaderAIXDYLD : public DynamicLoader { +public: + DynamicLoaderAIXDYLD(Process *process); + + ~DynamicLoaderAIXDYLD() override; + + static void Initialize(); + static void Terminate(); + static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; } + static llvm::StringRef GetPluginDescriptionStatic(); + + static DynamicLoader *CreateInstance(Process *process, bool force); + + void OnLoadModule(lldb::ModuleSP module_sp, const ModuleSpec module_spec, + lldb::addr_t module_addr); + void OnUnloadModule(lldb::addr_t module_addr); + + void DidAttach() override; + void DidLaunch() override; + Status CanLoadImage() override; + lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread, + bool stop) override; + + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + static bool NotifyBreakpointHit(void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id); + +protected: + lldb::addr_t GetLoadAddress(lldb::ModuleSP executable); + +private: + std::map m_loaded_modules; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_AIX_DYLD_DYNAMICLOADERWAIXDYLD_H diff --git a/lldb/source/Plugins/DynamicLoader/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/CMakeLists.txt index 30607159acdc0..4f3fb693faae1 100644 --- a/lldb/source/Plugins/DynamicLoader/CMakeLists.txt +++ b/lldb/source/Plugins/DynamicLoader/CMakeLists.txt @@ -5,4 +5,5 @@ add_subdirectory(POSIX-DYLD) add_subdirectory(Static) add_subdirectory(Hexagon-DYLD) add_subdirectory(Windows-DYLD) +add_subdirectory(AIX-DYLD) add_subdirectory(wasm-DYLD) diff --git a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp index 20e5652c65bf8..26abea0fdd24d 100644 --- a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp +++ b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp @@ -256,7 +256,7 @@ DynamicLoaderDarwinKernel::SearchForKernelWithDebugHints(Process *process) { if (process->ReadMemoryFromInferior (kernel_addresses_64[i], uval, 8, read_err) == 8) { DataExtractor data (&uval, 8, process->GetByteOrder(), process->GetAddressByteSize()); - offset_t offset = 0; + lldb::offset_t offset = 0; uint64_t addr = data.GetU64 (&offset); if (CheckForKernelImageAtAddress(addr, process).IsValid()) { return addr; @@ -270,7 +270,7 @@ DynamicLoaderDarwinKernel::SearchForKernelWithDebugHints(Process *process) { if (process->ReadMemoryFromInferior (kernel_addresses_32[i], uval, 4, read_err) == 4) { DataExtractor data (&uval, 4, process->GetByteOrder(), process->GetAddressByteSize()); - offset_t offset = 0; + lldb::offset_t offset = 0; uint32_t addr = data.GetU32 (&offset); if (CheckForKernelImageAtAddress(addr, process).IsValid()) { return addr; diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp index 3863b6b3520db..624848dee6ec3 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp @@ -1151,7 +1151,7 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp, // TLS data for the pthread_key on a specific thread yet. If we have we // can re-use it since its location will not change unless the process // execs. - const tid_t tid = thread_sp->GetID(); + const lldb::tid_t tid = thread_sp->GetID(); auto tid_pos = m_tid_to_tls_map.find(tid); if (tid_pos != m_tid_to_tls_map.end()) { auto tls_pos = tid_pos->second.find(key); diff --git a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp index 3035c51341778..d14ae2daeb47d 100644 --- a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp +++ b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp @@ -146,7 +146,25 @@ EmulateInstructionPPC64::GetOpcodeForInstruction(uint32_t opcode) { {0xfc000000, 0x38000000, &EmulateInstructionPPC64::EmulateADDI, "addi RT, RA, SI"}, {0xfc000003, 0xe8000000, &EmulateInstructionPPC64::EmulateLD, - "ld RT, DS(RA)"}}; + "ld RT, DS(RA)"}, +// {0xffff0003, 0x40820000, &EmulateInstructionPPC64::EmulateBNE, +// "bne TARGET"}, + {0xfc000002, 0x48000000, &EmulateInstructionPPC64::EmulateB, + "b TARGET"}, + {0xfc000003, 0x48000002, &EmulateInstructionPPC64::EmulateBA, + "ba TARGET"}, + {0xfc000003, 0x48000003, &EmulateInstructionPPC64::EmulateBLA, + "bla TARGET"}, + {0xfc000002, 0x40000000, &EmulateInstructionPPC64::EmulateBC, + "bc BO,BI,TARGET"}, + {0xfc000002, 0x40000002, &EmulateInstructionPPC64::EmulateBCA, + "bca BO,BI,TARGET"}, + {0xfc0007fe, 0x4c000020, &EmulateInstructionPPC64::EmulateBCLR, + "bclr BO,BI,BH"}, + {0xfc0007fe, 0x4c000420, &EmulateInstructionPPC64::EmulateBCCTR, + "bcctr BO,BI,BH"}, + {0xfc0007fe, 0x4c000460, &EmulateInstructionPPC64::EmulateBCTAR, + "bctar BO,BI,BH"}}; static const size_t k_num_ppc_opcodes = std::size(g_opcodes); for (size_t i = 0; i < k_num_ppc_opcodes; ++i) { @@ -169,12 +187,13 @@ bool EmulateInstructionPPC64::EvaluateInstruction(uint32_t evaluate_options) { bool success = false; - uint32_t orig_pc_value = 0; + uint64_t orig_pc_value = 0; if (auto_advance_pc) { orig_pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); if (!success) return false; + LLDB_LOG(GetLog(LLDBLog::Unwind), "orig_pc_value:{0}", orig_pc_value); } // Call the Emulate... function. @@ -183,11 +202,13 @@ bool EmulateInstructionPPC64::EvaluateInstruction(uint32_t evaluate_options) { return false; if (auto_advance_pc) { - uint32_t new_pc_value = + uint64_t new_pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); if (!success) return false; + LLDB_LOG(GetLog(LLDBLog::Unwind), "new_pc_value:{0}", new_pc_value); + if (new_pc_value == orig_pc_value) { EmulateInstruction::Context context; context.type = eContextAdvancePC; @@ -389,5 +410,174 @@ bool EmulateInstructionPPC64::EmulateADDI(uint32_t opcode) { return false; WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_r1_ppc64le, r1 + si_val); LLDB_LOG(log, "EmulateADDI: success!"); + + // FIX the next-pc + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + + return true; +} + +bool EmulateInstructionPPC64::EmulateBC(uint32_t opcode) { + // FIXME:32bit M + uint32_t M = 0; + uint32_t target32 = Bits32(opcode, 15, 2) << 2; + uint64_t target = (uint64_t)target32 + ((target32 & 0x8000) ? 0xffffffffffff0000UL : 0); + uint32_t BO = Bits32(opcode, 25, 21); + bool success; + uint64_t ctr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success); + if ((~BO) & (1U << 2)) + ctr_value = ctr_value - 1; + bool ctr_ok = (bool)(BO & (1U << 2)) | ((bool)(ctr_value != 0) ^ (bool)(BO & (1U << 1))); + uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success); + uint32_t BI = Bits32(opcode, 20, 16); + bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U)); + + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + if (ctr_ok & cond_ok) + next_pc = pc_value + target; + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + Log *log = GetLog(LLDBLog::Unwind); + LLDB_LOG(log, "EmulateBC: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBCA(uint32_t opcode) { + // FIXME:32bit M + uint32_t M = 0; + uint32_t target32 = Bits32(opcode, 15, 2) << 2; + uint64_t target = (uint64_t)target32 + ((target32 & 0x8000) ? 0xffffffffffff0000UL : 0); + uint32_t BO = Bits32(opcode, 25, 21); + bool success; + uint64_t ctr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success); + if ((~BO) & (1U << 2)) + ctr_value = ctr_value - 1; + bool ctr_ok = (bool)(BO & (1U << 2)) | ((bool)(ctr_value != 0) ^ (bool)(BO & (1U << 1))); + uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success); + uint32_t BI = Bits32(opcode, 20, 16); + bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U)); + + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + if (ctr_ok & cond_ok) + next_pc = target; + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + Log *log = GetLog(LLDBLog::Unwind); + LLDB_LOG(log, "EmulateBCA: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBCLR(uint32_t opcode) { + // FIXME:32bit M + uint32_t M = 0; + uint32_t BO = Bits32(opcode, 25, 21); + bool success; + uint64_t ctr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success); + if ((~BO) & (1U << 2)) + ctr_value = ctr_value - 1; + bool ctr_ok = (bool)(BO & (1U << 2)) | ((bool)(ctr_value != 0) ^ (bool)(BO & (1U << 1))); + uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success); + uint32_t BI = Bits32(opcode, 20, 16); + bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U)); + + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + if (ctr_ok & cond_ok) { + next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success); + next_pc &= ~((1UL << 2) - 1); + } + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + Log *log = GetLog(LLDBLog::Unwind); + LLDB_LOG(log, "EmulateBCLR: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBCCTR(uint32_t opcode) { + // FIXME:32bit M + uint32_t M = 0; + uint32_t BO = Bits32(opcode, 25, 21); + bool success; + uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success); + uint32_t BI = Bits32(opcode, 20, 16); + bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U)); + + Log *log = GetLog(LLDBLog::Unwind); + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + if (cond_ok) { + next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success); + next_pc &= ~((1UL << 2) - 1); + if (next_pc < 0x4000000) { + LLDB_LOGF(log, "EmulateBCCTR: next address %lx out of range, emulate by goto LR!"); + next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success); + } + } + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + LLDB_LOG(log, "EmulateBCCTR: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBCTAR(uint32_t opcode) { + // Not supported yet. + LLDB_LOG(GetLog(LLDBLog::Unwind), "EmulateBCTAR: not supported!"); + assert(0); + return false; +} + +bool EmulateInstructionPPC64::EmulateB(uint32_t opcode) { + uint32_t target32 = Bits32(opcode, 25, 2) << 2; + uint64_t target = (uint64_t)target32 + ((target32 & 0x2000000) ? 0xfffffffffc000000UL : 0); + + bool success; + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + target; + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + Log *log = GetLog(LLDBLog::Unwind); + LLDB_LOG(log, "EmulateB: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBA(uint32_t opcode) { + Log *log = GetLog(LLDBLog::Unwind); + + bool success; + uint64_t next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success); + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + LLDB_LOG(log, "EmulateBA: emulate by branch to lr!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateBLA(uint32_t opcode) { + Log *log = GetLog(LLDBLog::Unwind); + + bool success; + uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + uint64_t next_pc = pc_value + 4; + + Context ctx; + ctx.type = eContextAdjustPC; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc); + LLDB_LOG(log, "EmulateBLA: emulate by branch to lr!"); return true; } diff --git a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h index a9424f16b0ad0..1576c9700e557 100644 --- a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h +++ b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h @@ -39,6 +39,12 @@ class EmulateInstructionPPC64 : public EmulateInstruction { return true; case eInstructionTypePCModifying: +#if defined(__AIX__) + return true; +#else + return false; +#endif + case eInstructionTypeAll: return false; } @@ -84,6 +90,14 @@ class EmulateInstructionPPC64 : public EmulateInstruction { bool EmulateSTD(uint32_t opcode); bool EmulateOR(uint32_t opcode); bool EmulateADDI(uint32_t opcode); + bool EmulateB(uint32_t opcode); + bool EmulateBA(uint32_t opcode); + bool EmulateBLA(uint32_t opcode); + bool EmulateBC(uint32_t opcode); + bool EmulateBCA(uint32_t opcode); + bool EmulateBCLR(uint32_t opcode); + bool EmulateBCCTR(uint32_t opcode); + bool EmulateBCTAR(uint32_t opcode); }; } // namespace lldb_private diff --git a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp index b7cd2b1ac6bf6..876e74056face 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp @@ -261,7 +261,7 @@ InstrumentationRuntimeMainThreadChecker::GetBacktracesFromExtendedStopInfo( StructuredData::ObjectSP thread_id_obj = info->GetObjectForDotSeparatedPath("tid"); - tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; + lldb::tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; // We gather symbolication addresses above, so no need for HistoryThread to // try to infer the call addresses. diff --git a/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp b/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp index b2781aa5e7db1..7a827a3ea76f9 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp @@ -770,13 +770,13 @@ std::string InstrumentationRuntimeTSan::GetLocationDescription( Sprintf("Location is a %ld-byte heap object at 0x%llx", size, addr); } } else if (type == "stack") { - tid_t tid = loc->GetAsDictionary() + lldb::tid_t tid = loc->GetAsDictionary() ->GetValueForKey("thread_id") ->GetUnsignedIntegerValue(); result = Sprintf("Location is stack of thread %d", tid); } else if (type == "tls") { - tid_t tid = loc->GetAsDictionary() + lldb::tid_t tid = loc->GetAsDictionary() ->GetValueForKey("thread_id") ->GetUnsignedIntegerValue(); @@ -948,7 +948,7 @@ static std::string GenerateThreadName(const std::string &path, if (path == "mops") { size_t size = o->GetObjectForDotSeparatedPath("size")->GetUnsignedIntegerValue(); - tid_t thread_id = + lldb::tid_t thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); bool is_write = o->GetObjectForDotSeparatedPath("is_write")->GetBooleanValue(); @@ -979,7 +979,7 @@ static std::string GenerateThreadName(const std::string &path, } if (path == "threads") { - tid_t thread_id = + lldb::tid_t thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); result = Sprintf("Thread %zu created", thread_id); } @@ -987,7 +987,7 @@ static std::string GenerateThreadName(const std::string &path, if (path == "locs") { std::string type = std::string( o->GetAsDictionary()->GetValueForKey("type")->GetStringValue()); - tid_t thread_id = + lldb::tid_t thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); int fd = o->GetObjectForDotSeparatedPath("file_descriptor") ->GetSignedIntegerValue(); @@ -1007,7 +1007,7 @@ static std::string GenerateThreadName(const std::string &path, } if (path == "stacks") { - tid_t thread_id = + lldb::tid_t thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); result = Sprintf("Thread %" PRIu64, thread_id); } @@ -1034,7 +1034,7 @@ static void AddThreadsForPath(const std::string &path, StructuredData::ObjectSP thread_id_obj = o->GetObjectForDotSeparatedPath("thread_os_id"); - tid_t tid = + lldb::tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; ThreadSP new_thread_sp = diff --git a/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp index 1c58922e8d36c..de9719ad4a89e 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp @@ -321,7 +321,7 @@ InstrumentationRuntimeUBSan::GetBacktracesFromExtendedStopInfo( StructuredData::ObjectSP thread_id_obj = info->GetObjectForDotSeparatedPath("tid"); - tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; + lldb::tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; // We gather symbolication addresses above, so no need for HistoryThread to // try to infer the call addresses. diff --git a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp index 1688fb27430a7..690fb0d60a09a 100644 --- a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp +++ b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp @@ -194,6 +194,10 @@ void JITLoaderGDB::SetJITBreakpoint(lldb_private::ModuleList &module_list) { if (jit_addr == LLDB_INVALID_ADDRESS) return; +#if defined(__AIX__) + return; +#endif + m_jit_descriptor_addr = GetSymbolAddress( module_list, ConstString("__jit_debug_descriptor"), eSymbolTypeData); if (m_jit_descriptor_addr == LLDB_INVALID_ADDRESS) { diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index 341923108e321..fb5bc2c58e6fb 100644 --- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -1227,6 +1227,7 @@ bool lldb_private::formatters::ObjCSELSummaryProvider( time_t lldb_private::formatters::GetOSXEpoch() { static time_t epoch = 0; if (!epoch) { +#if !defined(__AIX__) #ifndef _WIN32 tzset(); tm tm_epoch; @@ -1240,6 +1241,7 @@ time_t lldb_private::formatters::GetOSXEpoch() { tm_epoch.tm_gmtoff = 0; tm_epoch.tm_zone = nullptr; epoch = timegm(&tm_epoch); +#endif #endif } return epoch; diff --git a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp index 6efd2516578ff..fe6c5a0544be3 100644 --- a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp +++ b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp @@ -107,7 +107,7 @@ static void CreateHistoryThreadFromValueObject(ProcessSP process_sp, return; int count = count_sp->GetValueAsUnsigned(0); - tid_t tid = tid_sp->GetValueAsUnsigned(0) + 1; + lldb::tid_t tid = tid_sp->GetValueAsUnsigned(0) + 1; if (count <= 0) return; diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 7aa5b8d81890a..5ea55772c3aba 100644 --- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -8,7 +8,7 @@ #include "ObjectContainerBSDArchive.h" -#if defined(_WIN32) || defined(__ANDROID__) +#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__) // Defines from ar, missing on Windows #define SARMAG 8 #define ARFMAG "`\n" diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt b/lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt new file mode 100644 index 0000000000000..612a36265b536 --- /dev/null +++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt @@ -0,0 +1,10 @@ +add_lldb_library(lldbPluginObjectContainerBigArchive PLUGIN + ObjectContainerBigArchive.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp new file mode 100644 index 0000000000000..050ad73f1d19a --- /dev/null +++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp @@ -0,0 +1,522 @@ +//===-- ObjectContainerBigArchive.cpp -------------------------------------===// +// +// 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 "ObjectContainerBigArchive.h" + +#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__) +// Defines from ar, missing on Windows +#define ARMAG "!\n" +#define SARMAG 8 +#define ARFMAG "`\n" + +typedef struct ar_hdr { + char ar_name[16]; + char ar_date[12]; + char ar_uid[6], ar_gid[6]; + char ar_mode[8]; + char ar_size[10]; + char ar_fmag[2]; +} ar_hdr; +#else +#include +#endif + +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/Timer.h" + +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Object/Archive.h" +#include "llvm/Support/Chrono.h" + +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ObjectContainerBigArchive) + +ObjectContainerBigArchive::Object::Object() : ar_name() {} + +void ObjectContainerBigArchive::Object::Clear() { + ar_name.Clear(); + modification_time = 0; + uid = 0; + gid = 0; + mode = 0; + size = 0; + file_offset = 0; + file_size = 0; +} + +lldb::offset_t +ObjectContainerBigArchive::Object::Extract(const DataExtractor &data, + lldb::offset_t offset) { + size_t ar_name_len = 0; + std::string str; + char *err; + + // File header + // + // The common format is as follows. + // + // Offset Length Name Format + // 0 16 File name ASCII right padded with spaces (no spaces + // allowed in file name) + // 16 12 File mod Decimal as cstring right padded with + // spaces + // 28 6 Owner ID Decimal as cstring right padded with + // spaces + // 34 6 Group ID Decimal as cstring right padded with + // spaces + // 40 8 File mode Octal as cstring right padded with + // spaces + // 48 10 File byte size Decimal as cstring right padded with + // spaces + // 58 2 File magic 0x60 0x0A + + // Make sure there is enough data for the file header and bail if not + if (!data.ValidOffsetForDataOfSize(offset, 60)) + return LLDB_INVALID_OFFSET; + + str.assign((const char *)data.GetData(&offset, 16), 16); + if (llvm::StringRef(str).starts_with("#1/")) { + // If the name is longer than 16 bytes, or contains an embedded space then + // it will use this format where the length of the name is here and the + // name characters are after this header. + ar_name_len = strtoul(str.c_str() + 3, &err, 10); + } else { + // Strip off any trailing spaces. + const size_t last_pos = str.find_last_not_of(' '); + if (last_pos != std::string::npos) { + if (last_pos + 1 < 16) + str.erase(last_pos + 1); + } + ar_name.SetCString(str.c_str()); + } + + str.assign((const char *)data.GetData(&offset, 12), 12); + modification_time = strtoul(str.c_str(), &err, 10); + + str.assign((const char *)data.GetData(&offset, 6), 6); + uid = strtoul(str.c_str(), &err, 10); + + str.assign((const char *)data.GetData(&offset, 6), 6); + gid = strtoul(str.c_str(), &err, 10); + + str.assign((const char *)data.GetData(&offset, 8), 8); + mode = strtoul(str.c_str(), &err, 8); + + str.assign((const char *)data.GetData(&offset, 10), 10); + size = strtoul(str.c_str(), &err, 10); + + str.assign((const char *)data.GetData(&offset, 2), 2); + if (str == ARFMAG) { + if (ar_name_len > 0) { + const void *ar_name_ptr = data.GetData(&offset, ar_name_len); + // Make sure there was enough data for the string value and bail if not + if (ar_name_ptr == nullptr) + return LLDB_INVALID_OFFSET; + str.assign((const char *)ar_name_ptr, ar_name_len); + ar_name.SetCString(str.c_str()); + } + file_offset = offset; + file_size = size - ar_name_len; + return offset; + } + return LLDB_INVALID_OFFSET; +} + +ObjectContainerBigArchive::Archive::Archive(const lldb_private::ArchSpec &arch, + const llvm::sys::TimePoint<> &time, + lldb::offset_t file_offset, + lldb_private::DataExtractor &data) + : m_arch(arch), m_modification_time(time), m_file_offset(file_offset), + m_objects(), m_data(data) {} + +ObjectContainerBigArchive::Archive::~Archive() = default; + +size_t ObjectContainerBigArchive::Archive::ParseObjects() { + DataExtractor &data = m_data; + std::string str; + lldb::offset_t offset = 0; + str.assign((const char *)data.GetData(&offset, (sizeof(llvm::object::BigArchiveMagic) - 1)), + (sizeof(llvm::object::BigArchiveMagic) - 1)); + if (str == llvm::object::BigArchiveMagic) { + llvm::Error err = llvm::Error::success(); + llvm::object::BigArchive bigAr(llvm::MemoryBufferRef(toStringRef(m_data.GetData()), llvm::StringRef("")), err); + if (err) + return 0; + + for (const llvm::object::Archive::Child &child : bigAr.children(err)) { + if (err) + continue; + if (!child.getParent()) + continue; + Object obj; + obj.Clear(); + // FIXME: check errors + llvm::Expected childNameOrErr = child.getName(); + if (!childNameOrErr) + continue; + obj.ar_name.SetCString(childNameOrErr->str().c_str()); + llvm::Expected> lastModifiedOrErr = child.getLastModified(); + if (!lastModifiedOrErr) + continue; + obj.modification_time = (uint32_t)llvm::sys::toTimeT(*(lastModifiedOrErr)); + llvm::Expected getUIDOrErr = child.getUID(); + if (!getUIDOrErr) + continue; + obj.uid = (uint16_t)*getUIDOrErr; + llvm::Expected getGIDOrErr = child.getGID(); + if (!getGIDOrErr) + continue; + obj.gid = (uint16_t)*getGIDOrErr; + llvm::Expected getAccessModeOrErr = child.getAccessMode(); + if (!getAccessModeOrErr) + continue; + obj.mode = (uint16_t)*getAccessModeOrErr; + llvm::Expected getRawSizeOrErr = child.getRawSize(); + if (!getRawSizeOrErr) + continue; + obj.size = (uint32_t)*getRawSizeOrErr; + + obj.file_offset = (lldb::offset_t)child.getDataOffset(); + + llvm::Expected getSizeOrErr = child.getSize(); + if (!getSizeOrErr) + continue; + obj.file_size = (lldb::offset_t)*getSizeOrErr; + + size_t obj_idx = m_objects.size(); + m_objects.push_back(obj); + // Insert all of the C strings out of order for now... + m_object_name_to_index_map.Append(obj.ar_name, obj_idx); + } + if (err) + return 0; + + // Now sort all of the object name pointers + m_object_name_to_index_map.Sort(); + } + return m_objects.size(); +} + +ObjectContainerBigArchive::Object * +ObjectContainerBigArchive::Archive::FindObject( + ConstString object_name, const llvm::sys::TimePoint<> &object_mod_time) { + const ObjectNameToIndexMap::Entry *match = + m_object_name_to_index_map.FindFirstValueForName(object_name); + if (!match) + return nullptr; + if (object_mod_time == llvm::sys::TimePoint<>()) + return &m_objects[match->value]; + + const uint64_t object_modification_date = llvm::sys::toTimeT(object_mod_time); + if (m_objects[match->value].modification_time == object_modification_date) + return &m_objects[match->value]; + + const ObjectNameToIndexMap::Entry *next_match = + m_object_name_to_index_map.FindNextValueForName(match); + while (next_match) { + if (m_objects[next_match->value].modification_time == + object_modification_date) + return &m_objects[next_match->value]; + next_match = m_object_name_to_index_map.FindNextValueForName(next_match); + } + + return nullptr; +} + +ObjectContainerBigArchive::Archive::shared_ptr +ObjectContainerBigArchive::Archive::FindCachedArchive( + const FileSpec &file, const ArchSpec &arch, + const llvm::sys::TimePoint<> &time, lldb::offset_t file_offset) { + std::lock_guard guard(Archive::GetArchiveCacheMutex()); + shared_ptr archive_sp; + Archive::Map &archive_map = Archive::GetArchiveCache(); + Archive::Map::iterator pos = archive_map.find(file); + // Don't cache a value for "archive_map.end()" below since we might delete an + // archive entry... + while (pos != archive_map.end() && pos->first == file) { + bool match = true; + if (arch.IsValid() && + !pos->second->GetArchitecture().IsCompatibleMatch(arch)) + match = false; + else if (file_offset != LLDB_INVALID_OFFSET && + pos->second->GetFileOffset() != file_offset) + match = false; + if (match) { + if (pos->second->GetModificationTime() == time) { + return pos->second; + } else { + // We have a file at the same path with the same architecture whose + // modification time doesn't match. It doesn't make sense for us to + // continue to use this Big archive since we cache only the object info + // which consists of file time info and also the file offset and file + // size of any contained objects. Since this information is now out of + // date, we won't get the correct information if we go and extract the + // file data, so we should remove the old and outdated entry. + archive_map.erase(pos); + pos = archive_map.find(file); + continue; // Continue to next iteration so we don't increment pos + // below... + } + } + ++pos; + } + return archive_sp; +} + +ObjectContainerBigArchive::Archive::shared_ptr +ObjectContainerBigArchive::Archive::ParseAndCacheArchiveForFile( + const FileSpec &file, const ArchSpec &arch, + const llvm::sys::TimePoint<> &time, lldb::offset_t file_offset, + DataExtractor &data) { + shared_ptr archive_sp(new Archive(arch, time, file_offset, data)); + if (archive_sp) { + const size_t num_objects = archive_sp->ParseObjects(); + if (num_objects > 0) { + std::lock_guard guard( + Archive::GetArchiveCacheMutex()); + Archive::GetArchiveCache().insert(std::make_pair(file, archive_sp)); + } else { + archive_sp.reset(); + } + } + return archive_sp; +} + +ObjectContainerBigArchive::Archive::Map & +ObjectContainerBigArchive::Archive::GetArchiveCache() { + static Archive::Map g_archive_map; + return g_archive_map; +} + +std::recursive_mutex & +ObjectContainerBigArchive::Archive::GetArchiveCacheMutex() { + static std::recursive_mutex g_archive_map_mutex; + return g_archive_map_mutex; +} + +void ObjectContainerBigArchive::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + GetModuleSpecifications); +} + +void ObjectContainerBigArchive::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ObjectContainer *ObjectContainerBigArchive::CreateInstance( + const lldb::ModuleSP &module_sp, DataBufferSP &data_sp, + lldb::offset_t data_offset, const FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length) { + ConstString object_name(module_sp->GetObjectName()); + if (!object_name) + return nullptr; + + if (data_sp) { + // We have data, which means this is the first 512 bytes of the file Check + // to see if the magic bytes match and if they do, read the entire table of + // contents for the archive and cache it + DataExtractor data; + data.SetData(data_sp, data_offset, length); + if (file && data_sp && ObjectContainerBigArchive::MagicBytesMatch(data)) { + LLDB_SCOPED_TIMERF( + "ObjectContainerBigArchive::CreateInstance (module = %s, file = " + "%p, file_offset = 0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")", + module_sp->GetFileSpec().GetPath().c_str(), + static_cast(file), static_cast(file_offset), + static_cast(length)); + + // Map the entire .a file to be sure that we don't lose any data if the + // file gets updated by a new build while this .a file is being used for + // debugging + DataBufferSP archive_data_sp = + FileSystem::Instance().CreateDataBuffer(*file, length, file_offset); + if (!archive_data_sp) + return nullptr; + + lldb::offset_t archive_data_offset = 0; + + Archive::shared_ptr archive_sp(Archive::FindCachedArchive( + *file, module_sp->GetArchitecture(), module_sp->GetModificationTime(), + file_offset)); + std::unique_ptr container_up( + new ObjectContainerBigArchive(module_sp, archive_data_sp, + archive_data_offset, file, file_offset, + length)); + + if (container_up) { + if (archive_sp) { + // We already have this archive in our cache, use it + container_up->SetArchive(archive_sp); + return container_up.release(); + } else if (container_up->ParseHeader()) + return container_up.release(); + } + } + } else { + // No data, just check for a cached archive + Archive::shared_ptr archive_sp(Archive::FindCachedArchive( + *file, module_sp->GetArchitecture(), module_sp->GetModificationTime(), + file_offset)); + if (archive_sp) { + std::unique_ptr container_up( + new ObjectContainerBigArchive(module_sp, data_sp, data_offset, file, + file_offset, length)); + + if (container_up) { + // We already have this archive in our cache, use it + container_up->SetArchive(archive_sp); + return container_up.release(); + } + } + } + return nullptr; +} + +bool ObjectContainerBigArchive::MagicBytesMatch(const DataExtractor &data) { + uint32_t offset = 0; + const char *armag = (const char *)data.PeekData(offset, (sizeof(llvm::object::BigArchiveMagic) - 1)); + if (armag && ::strncmp(armag, llvm::object::BigArchiveMagic, (sizeof(llvm::object::BigArchiveMagic) - 1)) == 0) + return true; + return false; +} + +ObjectContainerBigArchive::ObjectContainerBigArchive( + const lldb::ModuleSP &module_sp, DataBufferSP &data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t size) + : ObjectContainer(module_sp, file, file_offset, size, data_sp, data_offset), + m_archive_sp() {} +void ObjectContainerBigArchive::SetArchive(Archive::shared_ptr &archive_sp) { + m_archive_sp = archive_sp; +} + +ObjectContainerBigArchive::~ObjectContainerBigArchive() = default; + +bool ObjectContainerBigArchive::ParseHeader() { + if (m_archive_sp.get() == nullptr) { + if (m_data.GetByteSize() > 0) { + ModuleSP module_sp(GetModule()); + if (module_sp) { + m_archive_sp = Archive::ParseAndCacheArchiveForFile( + m_file, module_sp->GetArchitecture(), + module_sp->GetModificationTime(), m_offset, m_data); + } + // Clear the m_data that contains the entire archive data and let our + // m_archive_sp hold onto the data. + m_data.Clear(); + } + } + return m_archive_sp.get() != nullptr; +} + +void ObjectContainerBigArchive::Object::Dump(Stream *s) const { + printf("name = \"%s\"\n", ar_name.GetCString()); + printf("mtime = 0x%8.8" PRIx32 "\n", modification_time); + printf("size = 0x%8.8" PRIx32 " (%" PRIu32 ")\n", size, size); + printf("file_offset = 0x%16.16" PRIx64 " (%" PRIu64 ")\n", file_offset, + file_offset); + printf("file_size = 0x%16.16" PRIx64 " (%" PRIu64 ")\n\n", file_size, + file_size); +} + +ObjectFileSP ObjectContainerBigArchive::GetObjectFile(const FileSpec *file) { + ModuleSP module_sp(GetModule()); + if (module_sp) { + if (module_sp->GetObjectName() && m_archive_sp) { + Object *object = m_archive_sp->FindObject( + module_sp->GetObjectName(), module_sp->GetObjectModificationTime()); + if (object) { + lldb::offset_t data_offset = object->file_offset; + return ObjectFile::FindPlugin( + module_sp, file, m_offset + object->file_offset, object->file_size, + m_archive_sp->GetData().GetSharedDataBuffer(), data_offset); + } + } + } + return ObjectFileSP(); +} + +size_t ObjectContainerBigArchive::GetModuleSpecifications( + const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, lldb::offset_t file_offset, + lldb::offset_t file_size, lldb_private::ModuleSpecList &specs) { + + // We have data, which means this is the first 512 bytes of the file Check to + // see if the magic bytes match and if they do, read the entire table of + // contents for the archive and cache it + DataExtractor data; + data.SetData(data_sp, data_offset, data_sp->GetByteSize()); + if (!file || !data_sp || !ObjectContainerBigArchive::MagicBytesMatch(data)) + return 0; + + const size_t initial_count = specs.GetSize(); + llvm::sys::TimePoint<> file_mod_time = FileSystem::Instance().GetModificationTime(file); + Archive::shared_ptr archive_sp( + Archive::FindCachedArchive(file, ArchSpec(), file_mod_time, file_offset)); + bool set_archive_arch = false; + if (!archive_sp) { + set_archive_arch = true; + data_sp = + FileSystem::Instance().CreateDataBuffer(file, file_size, file_offset); + if (data_sp) { + data.SetData(data_sp, 0, data_sp->GetByteSize()); + archive_sp = Archive::ParseAndCacheArchiveForFile( + file, ArchSpec(), file_mod_time, file_offset, data); + } + } + + if (archive_sp) { + const size_t num_objects = archive_sp->GetNumObjects(); + for (size_t idx = 0; idx < num_objects; ++idx) { + const Object *object = archive_sp->GetObjectAtIndex(idx); + if (object) { + 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( + file, object_file_offset, file_size - object_file_offset, + specs)) { + ModuleSpec &spec = + specs.GetModuleSpecRefAtIndex(specs.GetSize() - 1); + llvm::sys::TimePoint<> object_mod_time( + std::chrono::seconds(object->modification_time)); + spec.GetObjectName() = object->ar_name; + spec.SetObjectOffset(object_file_offset); + spec.SetObjectSize(file_size - object_file_offset); + spec.GetObjectModificationTime() = object_mod_time; + } + } + } + } + } + const size_t end_count = specs.GetSize(); + size_t num_specs_added = end_count - initial_count; + if (set_archive_arch && num_specs_added > 0) { + // The archive was created but we didn't have an architecture so we need to + // set it + for (size_t i = initial_count; i < end_count; ++i) { + ModuleSpec module_spec; + if (specs.GetModuleSpecAtIndex(i, module_spec)) { + if (module_spec.GetArchitecture().IsValid()) { + archive_sp->SetArchitecture(module_spec.GetArchitecture()); + break; + } + } + } + } + return num_specs_added; +} diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h new file mode 100644 index 0000000000000..ad9b814048a87 --- /dev/null +++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h @@ -0,0 +1,177 @@ +//===-- ObjectContainerBigArchive.h -----------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BIG_ARCHIVE_OBJECTCONTAINERBIGARCHIVE_H +#define LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BIG_ARCHIVE_OBJECTCONTAINERBIGARCHIVE_H + +#include "lldb/Core/UniqueCStringMap.h" +#include "lldb/Symbol/ObjectContainer.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/FileSpec.h" + +#include "llvm/Support/Chrono.h" + +#include +#include +#include + +class ObjectContainerBigArchive : public lldb_private::ObjectContainer { +public: + ObjectContainerBigArchive(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + ~ObjectContainerBigArchive() override; + + // Static Functions + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "big-archive"; } + + static llvm::StringRef GetPluginDescriptionStatic() { + return "Big Archive object container reader."; + } + + static lldb_private::ObjectContainer * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + static size_t GetModuleSpecifications(const lldb_private::FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + lldb_private::ModuleSpecList &specs); + + static bool MagicBytesMatch(const lldb_private::DataExtractor &data); + + // Member Functions + bool ParseHeader() override; + + size_t GetNumObjects() const override { + if (m_archive_sp) + return m_archive_sp->GetNumObjects(); + return 0; + } + + lldb::ObjectFileSP GetObjectFile(const lldb_private::FileSpec *file) override; + + // PluginInterface protocol + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + +protected: + struct Object { + Object(); + + void Clear(); + + lldb::offset_t Extract(const lldb_private::DataExtractor &data, + lldb::offset_t offset); + /// Object name in the archive. + lldb_private::ConstString ar_name; + + /// Object modification time in the archive. + uint32_t modification_time = 0; + + /// Object user id in the archive. + uint16_t uid = 0; + + /// Object group id in the archive. + uint16_t gid = 0; + + /// Object octal file permissions in the archive. + uint16_t mode = 0; + + /// Object size in bytes in the archive. + uint32_t size = 0; + + /// File offset in bytes from the beginning of the file of the object data. + lldb::offset_t file_offset = 0; + + /// Length of the object data. + lldb::offset_t file_size = 0; + + void Dump(lldb_private::Stream *s) const; + }; + + class Archive { + public: + typedef std::shared_ptr shared_ptr; + typedef std::multimap Map; + + Archive(const lldb_private::ArchSpec &arch, + const llvm::sys::TimePoint<> &mod_time, lldb::offset_t file_offset, + lldb_private::DataExtractor &data); + + ~Archive(); + + static Map &GetArchiveCache(); + + static std::recursive_mutex &GetArchiveCacheMutex(); + + static Archive::shared_ptr FindCachedArchive( + const lldb_private::FileSpec &file, const lldb_private::ArchSpec &arch, + const llvm::sys::TimePoint<> &mod_time, lldb::offset_t file_offset); + + static Archive::shared_ptr ParseAndCacheArchiveForFile( + const lldb_private::FileSpec &file, const lldb_private::ArchSpec &arch, + const llvm::sys::TimePoint<> &mod_time, lldb::offset_t file_offset, + lldb_private::DataExtractor &data); + + size_t GetNumObjects() const { return m_objects.size(); } + + const Object *GetObjectAtIndex(size_t idx) { + if (idx < m_objects.size()) + return &m_objects[idx]; + return nullptr; + } + + size_t ParseObjects(); + + Object *FindObject(lldb_private::ConstString object_name, + const llvm::sys::TimePoint<> &object_mod_time); + + lldb::offset_t GetFileOffset() const { return m_file_offset; } + + const llvm::sys::TimePoint<> &GetModificationTime() { + return m_modification_time; + } + + const lldb_private::ArchSpec &GetArchitecture() const { return m_arch; } + + void SetArchitecture(const lldb_private::ArchSpec &arch) { m_arch = arch; } + + bool HasNoExternalReferences() const; + + lldb_private::DataExtractor &GetData() { return m_data; } + + protected: + typedef lldb_private::UniqueCStringMap ObjectNameToIndexMap; + // Member Variables + lldb_private::ArchSpec m_arch; + llvm::sys::TimePoint<> m_modification_time; + lldb::offset_t m_file_offset; + std::vector m_objects; + ObjectNameToIndexMap m_object_name_to_index_map; + lldb_private::DataExtractor m_data; ///< The data for this object container + ///so we don't lose data if the .a files + ///gets modified + }; + + void SetArchive(Archive::shared_ptr &archive_sp); + + Archive::shared_ptr m_archive_sp; +}; + +#endif // LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BIG_ARCHIVE_OBJECTCONTAINERBIGARCHIVE_H diff --git a/lldb/source/Plugins/ObjectContainer/CMakeLists.txt b/lldb/source/Plugins/ObjectContainer/CMakeLists.txt index cda0c8151dd8a..2492798bb13ef 100644 --- a/lldb/source/Plugins/ObjectContainer/CMakeLists.txt +++ b/lldb/source/Plugins/ObjectContainer/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(BSD-Archive) +add_subdirectory(Big-Archive) add_subdirectory(Universal-Mach-O) add_subdirectory(Mach-O-Fileset) diff --git a/lldb/source/Plugins/ObjectFile/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/CMakeLists.txt index 773241c8944c8..7abd0c96f4fd7 100644 --- a/lldb/source/Plugins/ObjectFile/CMakeLists.txt +++ b/lldb/source/Plugins/ObjectFile/CMakeLists.txt @@ -6,5 +6,6 @@ add_subdirectory(Mach-O) add_subdirectory(Minidump) add_subdirectory(PDB) add_subdirectory(PECOFF) +add_subdirectory(XCOFF) add_subdirectory(Placeholder) add_subdirectory(wasm) diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index ce095bcc48374..bcb6330cbb1f9 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -5673,7 +5673,7 @@ bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &value, return false; } -bool ObjectFileMachO::GetCorefileThreadExtraInfos(std::vector &tids) { +bool ObjectFileMachO::GetCorefileThreadExtraInfos(std::vector &tids) { tids.clear(); ModuleSP module_sp(GetModule()); if (module_sp) { @@ -5724,8 +5724,8 @@ bool ObjectFileMachO::GetCorefileThreadExtraInfos(std::vector &tids) { return false; } StructuredData::Dictionary *thread = *maybe_thread; - tid_t tid = LLDB_INVALID_THREAD_ID; - if (thread->GetValueForKeyAsInteger("thread_id", tid)) + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; + if (thread->GetValueForKeyAsInteger("thread_id", tid)) if (tid == 0) tid = LLDB_INVALID_THREAD_ID; tids.push_back(tid); diff --git a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp index faa144bfb5f6a..d27cdfc60de85 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp +++ b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp @@ -51,7 +51,9 @@ size_t ObjectFileMinidump::GetModuleSpecifications( const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, lldb_private::ModuleSpecList &specs) { +#if !defined(__AIX__) specs.Clear(); +#endif return 0; } diff --git a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp index f0832dbf07347..75cc54e4f0d48 100644 --- a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp +++ b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp @@ -116,18 +116,31 @@ size_t ObjectFilePDB::GetModuleSpecifications( ModuleSpec module_spec(file); llvm::BumpPtrAllocator allocator; std::unique_ptr pdb_file = loadPDBFile(file.GetPath(), allocator); - if (!pdb_file) + if (!pdb_file){ +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif + } auto info_stream = pdb_file->getPDBInfoStream(); if (!info_stream) { llvm::consumeError(info_stream.takeError()); +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif } auto dbi_stream = pdb_file->getPDBDbiStream(); if (!dbi_stream) { llvm::consumeError(dbi_stream.takeError()); +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif } lldb_private::UUID &uuid = module_spec.GetUUID(); diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index bda691ade8af0..db8fa78043fdc 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -252,8 +252,13 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, lldb_private::ModuleSpecList &specs) { const size_t initial_count = specs.GetSize(); - if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp)) + if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp)){ +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif + } Log *log = GetLog(LLDBLog::Object); @@ -266,12 +271,21 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( if (!binary) { LLDB_LOG_ERROR(log, binary.takeError(), "Failed to create binary for file ({1}): {0}", file); +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif } auto *COFFObj = llvm::dyn_cast(binary->get()); - if (!COFFObj) + if (!COFFObj){ +#if !defined(__AIX__) return initial_count; +#else + return specs.GetSize() - initial_count; +#endif + } ModuleSpec module_spec(file); ArchSpec &spec = module_spec.GetArchitecture(); diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt new file mode 100644 index 0000000000000..8840248574c88 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt @@ -0,0 +1,13 @@ +add_lldb_library(lldbPluginObjectFileXCOFF PLUGIN + ObjectFileXCOFF.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + lldbTarget + LINK_COMPONENTS + BinaryFormat + Object + Support + ) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp new file mode 100644 index 0000000000000..a4d9ea295b4c3 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -0,0 +1,780 @@ +//===-- ObjectFileXCOFF.cpp -------------------------------------------------===// +// +// 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 "ObjectFileXCOFF.h" + +#include +#include +#include +#include + +#include "lldb/Utility/FileSpecList.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Progress.h" +#include "lldb/Core/Section.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/LZMA.h" +#include "lldb/Symbol/DWARFCallFrameInfo.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RangeMap.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/Timer.h" +#include "llvm/ADT/IntervalMap.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/Object/Decompressor.h" +#include "llvm/Support/CRC.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Object/XCOFFObjectFile.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ObjectFileXCOFF) + +char ObjectFileXCOFF::ID; + +// FIXME: target 64bit at this moment. + +// Static methods. +void ObjectFileXCOFF::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + CreateMemoryInstance, GetModuleSpecifications); +} + +void ObjectFileXCOFF::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; + +ObjectFile *ObjectFileXCOFF::CreateInstance(const lldb::ModuleSP &module_sp, + DataBufferSP data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t file_offset, + lldb::offset_t length) { + if (!data_sp) { + data_sp = MapFileData(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + } + + if (!ObjectFileXCOFF::MagicBytesMatch(data_sp, data_offset, length)) + return nullptr; + + // Update the data to contain the entire file if it doesn't already + if (data_sp->GetByteSize() < length) { + data_sp = MapFileData(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + } + auto objfile_up = std::make_unique( + module_sp, data_sp, data_offset, file, file_offset, length); + if (!objfile_up) + return nullptr; + + // Cache xcoff binary. + if (!objfile_up->CreateBinary()) + return nullptr; + + if (!objfile_up->ParseHeader()) + //FIXME objfile leak + return nullptr; + + UGLY_FLAG_FOR_AIX = true; + return objfile_up.release(); +} + +bool ObjectFileXCOFF::CreateBinary() { + if (m_binary) + return true; + + Log *log = GetLog(LLDBLog::Object); + + auto binary = llvm::object::XCOFFObjectFile::createObjectFile(llvm::MemoryBufferRef( + toStringRef(m_data.GetData()), m_file.GetFilename().GetStringRef()), + file_magic::xcoff_object_64); + if (!binary) { + LLDB_LOG_ERROR(log, binary.takeError(), + "Failed to create binary for file ({1}): {0}", m_file); + return false; + } + + // Make sure we only handle COFF format. + m_binary = + llvm::unique_dyn_cast(std::move(*binary)); + if (!m_binary) + return false; + + LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}", + this, GetModule().get(), GetModule()->GetSpecificationDescription(), + m_file.GetPath(), m_binary.get()); + return true; +} + +ObjectFile *ObjectFileXCOFF::CreateMemoryInstance( + const lldb::ModuleSP &module_sp, WritableDataBufferSP data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) { + return nullptr; +} + +size_t ObjectFileXCOFF::GetModuleSpecifications( + const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, lldb::offset_t file_offset, + lldb::offset_t length, lldb_private::ModuleSpecList &specs) { + const size_t initial_count = specs.GetSize(); + + if (ObjectFileXCOFF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) { + ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + ModuleSpec spec(file, arch_spec); + spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX); + specs.Append(spec); + } + return specs.GetSize() - initial_count; +} + +static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) { + switch (magic) { + /* TODO: 32bit not supported yet + case XCOFF::XCOFF32: + return sizeof(struct llvm::object::XCOFFFileHeader32); + */ + + case XCOFF::XCOFF64: + return sizeof(struct llvm::object::XCOFFFileHeader64); + break; + + default: + break; + } + return 0; +} + +bool ObjectFileXCOFF::MagicBytesMatch(DataBufferSP &data_sp, + lldb::addr_t data_offset, + lldb::addr_t data_length) { + lldb_private::DataExtractor data; + data.SetData(data_sp, data_offset, data_length); + lldb::offset_t offset = 0; + uint16_t magic = data.GetU16(&offset); + return XCOFFHeaderSizeFromMagic(magic) != 0; +} + +bool ObjectFileXCOFF::ParseHeader() { + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard guard(module_sp->GetMutex()); + m_sect_headers.clear(); + lldb::offset_t offset = 0; + + if (ParseXCOFFHeader(m_data, &offset, m_xcoff_header)) { + m_data.SetAddressByteSize(GetAddressByteSize()); + if (m_xcoff_header.auxhdrsize > 0) + ParseXCOFFOptionalHeader(m_data, &offset); + ParseSectionHeaders(offset); + } + return true; + } + + return false; +} + +bool ObjectFileXCOFF::ParseXCOFFHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + xcoff_header_t &xcoff_header) { + //FIXME: data.ValidOffsetForDataOfSize + xcoff_header.magic = data.GetU16(offset_ptr); + xcoff_header.nsects = data.GetU16(offset_ptr); + xcoff_header.modtime = data.GetU32(offset_ptr); + xcoff_header.symoff = data.GetU64(offset_ptr); + xcoff_header.auxhdrsize = data.GetU16(offset_ptr); + xcoff_header.flags = data.GetU16(offset_ptr); + xcoff_header.nsyms = data.GetU32(offset_ptr); + return true; +} + +bool ObjectFileXCOFF::ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr) { + lldb::offset_t init_offset = *offset_ptr; + //FIXME: data.ValidOffsetForDataOfSize + m_xcoff_aux_header.AuxMagic = data.GetU16(offset_ptr); + m_xcoff_aux_header.Version = data.GetU16(offset_ptr); + m_xcoff_aux_header.ReservedForDebugger = data.GetU32(offset_ptr); + m_xcoff_aux_header.TextStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.DataStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.TOCAnchorAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfEntryPoint = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTOC = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfLoader = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.ModuleType = data.GetU16(offset_ptr); + m_xcoff_aux_header.CpuFlag = data.GetU8(offset_ptr); + m_xcoff_aux_header.CpuType = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.DataPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.StackPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.FlagAndTDataAlignment = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.InitDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.BssDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.EntryPointAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxStackSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfTData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.XCOFF64Flag = data.GetU16(offset_ptr); + lldb::offset_t last_offset = *offset_ptr; + if ((last_offset - init_offset) < m_xcoff_header.auxhdrsize) + *offset_ptr += (m_xcoff_header.auxhdrsize - (last_offset - init_offset)); + return true; +} + +bool ObjectFileXCOFF::ParseSectionHeaders( + uint32_t section_header_data_offset) { + const uint32_t nsects = m_xcoff_header.nsects; + m_sect_headers.clear(); + + if (nsects > 0) { + const size_t section_header_byte_size = nsects * m_binary->getSectionHeaderSize(); + lldb_private::DataExtractor section_header_data = + ReadImageData(section_header_data_offset, section_header_byte_size); + + lldb::offset_t offset = 0; + //FIXME: section_header_data.ValidOffsetForDataOfSize + m_sect_headers.resize(nsects); + + for (uint32_t idx = 0; idx < nsects; ++idx) { + const void *name_data = section_header_data.GetData(&offset, 8); + if (name_data) { + memcpy(m_sect_headers[idx].name, name_data, 8); + m_sect_headers[idx].phyaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].vmaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].size = section_header_data.GetU64(&offset); + m_sect_headers[idx].offset = section_header_data.GetU64(&offset); + m_sect_headers[idx].reloff = section_header_data.GetU64(&offset); + m_sect_headers[idx].lineoff = section_header_data.GetU64(&offset); + m_sect_headers[idx].nreloc = section_header_data.GetU32(&offset); + m_sect_headers[idx].nline = section_header_data.GetU32(&offset); + m_sect_headers[idx].flags = section_header_data.GetU32(&offset); + offset += 4; + } else { + offset += (m_binary->getSectionHeaderSize() - 8); + } + } + } + + return !m_sect_headers.empty(); +} + +lldb_private::DataExtractor ObjectFileXCOFF::ReadImageData(uint32_t offset, size_t size) { + if (!size) + return {}; + + if (m_data.ValidOffsetForDataOfSize(offset, size)) + return lldb_private::DataExtractor(m_data, offset, size); + + assert(0); + ProcessSP process_sp(m_process_wp.lock()); + lldb_private::DataExtractor data; + if (process_sp) { + auto data_up = std::make_unique(size, 0); + Status readmem_error; + size_t bytes_read = + process_sp->ReadMemory(offset, data_up->GetBytes(), + data_up->GetByteSize(), readmem_error); + if (bytes_read == size) { + DataBufferSP buffer_sp(data_up.release()); + data.SetData(buffer_sp, 0, buffer_sp->GetByteSize()); + } + } + return data; +} + +bool ObjectFileXCOFF::SetLoadAddress(Target &target, lldb::addr_t value, + bool value_is_offset) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (section_sp && !section_sp->IsThreadSpecific()) { + bool use_offset = false; + if (strcmp(section_sp->GetName().AsCString(), ".text") == 0 || + strcmp(section_sp->GetName().AsCString(), ".data") == 0 || + strcmp(section_sp->GetName().AsCString(), ".bss") == 0) + use_offset = true; + + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, (use_offset ? + (section_sp->GetFileOffset() + value) : (section_sp->GetFileAddress() + value)))) + ++num_loaded_sections; + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (type_id == 1 && section_sp && strcmp(section_sp->GetName().AsCString(), ".text") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileOffset() + value)) + ++num_loaded_sections; + } + } else if (type_id == 2 && section_sp && strcmp(section_sp->GetName().AsCString(), ".data") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileAddress() + value)) + ++num_loaded_sections; + } + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +ByteOrder ObjectFileXCOFF::GetByteOrder() const { + return eByteOrderBig; +} + +bool ObjectFileXCOFF::IsExecutable() const { + return true; +} + +uint32_t ObjectFileXCOFF::GetAddressByteSize() const { + if (m_xcoff_header.magic == XCOFF::XCOFF64) + return 8; + else if (m_xcoff_header.magic == XCOFF::XCOFF32) + return 4; + return 4; +} + +AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) { + return AddressClass::eUnknown; +} + +lldb::SymbolType ObjectFileXCOFF::MapSymbolType(llvm::object::SymbolRef::Type sym_type) { + if (sym_type == llvm::object::SymbolRef::ST_Function) + return lldb::eSymbolTypeCode; + else if (sym_type == llvm::object::SymbolRef::ST_Data) + return lldb::eSymbolTypeData; + return lldb::eSymbolTypeInvalid; +} + +void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) { + SectionList *sect_list = GetSectionList(); + const uint32_t num_syms = m_xcoff_header.nsyms; + uint32_t sidx = 0; + if (num_syms > 0 && m_xcoff_header.symoff > 0) { + const uint32_t symbol_size = XCOFF::SymbolTableEntrySize; + const size_t symbol_data_size = num_syms * symbol_size; + lldb_private::DataExtractor symtab_data = + ReadImageData(m_xcoff_header.symoff, symbol_data_size); + + lldb::offset_t offset = 0; + std::string symbol_name; + Symbol *symbols = lldb_symtab.Resize(num_syms); + llvm::object::symbol_iterator SI = m_binary->symbol_begin(); + for (uint32_t i = 0; i < num_syms; ++i, ++SI) { + xcoff_symbol_t symbol; + const uint32_t symbol_offset = offset; + symbol.value = symtab_data.GetU64(&offset); + symbol.offset = symtab_data.GetU32(&offset); + Expected symbol_name_or_err = m_binary->getStringTableEntry(symbol.offset); + if (!symbol_name_or_err) { + consumeError(symbol_name_or_err.takeError()); + return; + } + StringRef symbol_name_str = symbol_name_or_err.get(); + symbol_name.assign(symbol_name_str.data()); + symbol.sect = symtab_data.GetU16(&offset); + symbol.type = symtab_data.GetU16(&offset); + symbol.storage = symtab_data.GetU8(&offset); + symbol.naux = symtab_data.GetU8(&offset); + // Allow C_HIDEXT TOC symbol, and check others. + if (symbol.storage == XCOFF::C_HIDEXT && strcmp(symbol_name.c_str(), "TOC") != 0) { + if (symbol.naux == 0) + continue; + if (symbol.naux > 1) { + i += symbol.naux; + offset += symbol.naux * symbol_size; + continue; + } + /* Allow XCOFF::C_HIDEXT with following SMC and AT: + StorageMappingClass: XMC_PR (0x0) + Auxiliary Type: AUX_CSECT (0xFB) + */ + xcoff_sym_csect_aux_entry_t symbol_aux; + symbol_aux.section_or_len_low_byte = symtab_data.GetU32(&offset); + symbol_aux.parameter_hash_index = symtab_data.GetU32(&offset); + symbol_aux.type_check_sect_num = symtab_data.GetU16(&offset); + symbol_aux.symbol_alignment_and_type = symtab_data.GetU8(&offset); + symbol_aux.storage_mapping_class = symtab_data.GetU8(&offset); + symbol_aux.section_or_len_high_byte = symtab_data.GetU32(&offset); + symbol_aux.pad = symtab_data.GetU8(&offset); + symbol_aux.aux_type = symtab_data.GetU8(&offset); + offset -= symbol.naux * symbol_size; + if (symbol_aux.storage_mapping_class != XCOFF::XMC_PR || symbol_aux.aux_type != XCOFF::AUX_CSECT) { + i += symbol.naux; + offset += symbol.naux * symbol_size; + continue; + } + } + // Remove the dot prefix for demangle + if (symbol_name_str.size() > 1 && symbol_name_str.data()[0] == '.') { + symbols[sidx].GetMangled().SetValue(ConstString(symbol_name.c_str() + 1)); + } else { + symbols[sidx].GetMangled().SetValue(ConstString(symbol_name.c_str())); + } + if ((int16_t)symbol.sect >= 1) { + Address symbol_addr(sect_list->GetSectionAtIndex((size_t)(symbol.sect - 1)), + (symbol.value - sect_list->GetSectionAtIndex((size_t)(symbol.sect - 1))->GetFileAddress())); + symbols[sidx].GetAddressRef() = symbol_addr; + + Expected sym_type_or_err = SI->getType(); + if (!sym_type_or_err) { + consumeError(sym_type_or_err.takeError()); + return; + } + symbols[sidx].SetType(MapSymbolType(sym_type_or_err.get())); + } + ++sidx; + + if (symbol.naux > 0) { + i += symbol.naux; + offset += symbol.naux * symbol_size; + } + } + lldb_symtab.Resize(sidx); + } +} + +bool ObjectFileXCOFF::IsStripped() { + return false; +} + +void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) { + if (m_sections_up) + return; + m_sections_up = std::make_unique(); + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard guard(module_sp->GetMutex()); + + const uint32_t nsects = m_sect_headers.size(); + ModuleSP module_sp(GetModule()); + for (uint32_t idx = 0; idx < nsects; ++idx) { + llvm::StringRef sect_name = GetSectionName(m_sect_headers[idx]); + ConstString const_sect_name(sect_name); + SectionType section_type = GetSectionType(sect_name, m_sect_headers[idx]); + + SectionSP section_sp(new Section( + module_sp, // Module to which this section belongs + this, // Object file to which this section belongs + idx + 1, // Section ID is the 1 based section index. + const_sect_name, // Name of this section + section_type, + m_sect_headers[idx].vmaddr, // File VM address == addresses as + // they are found in the object file + m_sect_headers[idx].size, // VM size in bytes of this section + m_sect_headers[idx].offset, // Offset to the data for this section in the file + m_sect_headers[idx].size, // Size in bytes of this section as found in the file + 0, // FIXME: alignment + m_sect_headers[idx].flags)); // Flags for this section + + // FIXME + uint32_t permissions = 0; + permissions |= ePermissionsReadable; + if (m_sect_headers[idx].flags & (XCOFF::STYP_DATA | XCOFF::STYP_BSS)) + permissions |= ePermissionsWritable; + if (m_sect_headers[idx].flags & XCOFF::STYP_TEXT) + permissions |= ePermissionsExecutable; + section_sp->SetPermissions(permissions); + + m_sections_up->AddSection(section_sp); + unified_section_list.AddSection(section_sp); + } + } +} + +llvm::StringRef ObjectFileXCOFF::GetSectionName(const section_header_t §) { + llvm::StringRef hdr_name(sect.name, std::size(sect.name)); + hdr_name = hdr_name.split('\0').first; + if (hdr_name.consume_front("/")) { + lldb::offset_t stroff; + if (!to_integer(hdr_name, stroff, 10)) + return ""; + lldb::offset_t string_file_offset = + m_xcoff_header.symoff + (m_xcoff_header.nsyms * static_cast(XCOFF::SymbolTableEntrySize)) + stroff; + if (const char *name = m_data.GetCStr(&string_file_offset)) + return name; + return ""; + } + return hdr_name; +} + +SectionType ObjectFileXCOFF::GetSectionType(llvm::StringRef sect_name, + const section_header_t §) { + if (sect.flags & XCOFF::STYP_TEXT) + return eSectionTypeCode; + if (sect.flags & XCOFF::STYP_DATA) + return eSectionTypeData; + if (sect.flags & XCOFF::STYP_BSS) + return eSectionTypeZeroFill; + if (sect.flags & XCOFF::STYP_DWARF) { + SectionType section_type = + llvm::StringSwitch(sect_name) + .Case(".dwinfo", eSectionTypeDWARFDebugInfo) + .Case(".dwline", eSectionTypeDWARFDebugLine) + .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev) + .Default(eSectionTypeInvalid); + + if (section_type != eSectionTypeInvalid) + return section_type; + } + return eSectionTypeOther; +} + +void ObjectFileXCOFF::Dump(Stream *s) { +} + +ArchSpec ObjectFileXCOFF::GetArchitecture() { + ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + return arch_spec; +} + +UUID ObjectFileXCOFF::GetUUID() { + return UUID(); +} + +std::optional ObjectFileXCOFF::GetDebugLink() { + return std::nullopt; +} + +uint32_t ObjectFileXCOFF::ParseDependentModules() { + ModuleSP module_sp(GetModule()); + if (!module_sp) + return 0; + + std::lock_guard guard(module_sp->GetMutex()); + if (m_deps_filespec) + return m_deps_filespec->GetSize(); + + // Cache coff binary if it is not done yet. + if (!CreateBinary()) + return 0; + + Log *log = GetLog(LLDBLog::Object); + LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}", + this, GetModule().get(), GetModule()->GetSpecificationDescription(), + m_file.GetPath(), m_binary.get()); + + m_deps_filespec = FileSpecList(); + + auto ImportFilesOrError = m_binary->getImportFileTable(); + if (!ImportFilesOrError) { + consumeError(ImportFilesOrError.takeError()); + return 0; + } + +#if 0 + StringRef ImportFileTable = ImportFilesOrError.get(); + const char *CurrentStr = ImportFileTable.data(); + const char *TableEnd = ImportFileTable.end(); + const char *Basename = nullptr; + + for (size_t StrIndex = 0; CurrentStr < TableEnd; + ++StrIndex, CurrentStr += strlen(CurrentStr) + 1) { + if (StrIndex >= 3 && StrIndex % 3 == 1) { + // base_name + llvm::StringRef dll_name(CurrentStr); + Basename = CurrentStr; + + // At this moment we only have the base name of the DLL. The full path can + // only be seen after the dynamic loading. Our best guess is Try to get it + // with the help of the object file's directory. + llvm::SmallString<128> dll_fullpath; + FileSpec dll_specs(dll_name); + // FIXME: hack to get libc.a loaded + if (strcmp(CurrentStr, "libc.a") == 0) { + dll_specs.GetDirectory().SetString("/usr/lib"); + } else { + dll_specs.GetDirectory().SetString(m_file.GetDirectory().GetCString()); + } + + if (!llvm::sys::fs::real_path(dll_specs.GetPath(), dll_fullpath)) + //m_deps_filespec->EmplaceBack(dll_fullpath); + m_deps_filespec->EmplaceBack("/usr/lib/libc.a(shr_64.o)"); + else { + // Known DLLs or DLL not found in the object file directory. + m_deps_filespec->EmplaceBack(dll_name); + } + } else if (StrIndex >= 3 && StrIndex % 3 == 2) { + // archive_member_name + if (strcmp(CurrentStr, "") == 0) { + continue; + } + assert(strcmp(Basename, "") != 0); + std::map>::iterator iter = m_deps_base_members.find(std::string(Basename)); + if (iter == m_deps_base_members.end()) { + m_deps_base_members[std::string(Basename)] = std::vector(); + iter = m_deps_base_members.find(std::string(Basename)); + } + iter->second.push_back(std::string(CurrentStr)); + } + } +#endif + return m_deps_filespec->GetSize(); +} + +uint32_t ObjectFileXCOFF::GetDependentModules(FileSpecList &files) { + auto num_modules = ParseDependentModules(); + auto original_size = files.GetSize(); + + for (unsigned i = 0; i < num_modules; ++i) + files.AppendIfUnique(m_deps_filespec->GetFileSpecAtIndex(i)); + + return files.GetSize() - original_size; +} + +Address ObjectFileXCOFF::GetImageInfoAddress(Target *target) { + return Address(); +} + +lldb_private::Address ObjectFileXCOFF::GetEntryPointAddress() { + if (m_entry_point_address.IsValid()) + return m_entry_point_address; + + if (!ParseHeader() || !IsExecutable()) + return m_entry_point_address; + + SectionList *section_list = GetSectionList(); + addr_t vm_addr = m_xcoff_aux_header.EntryPointAddr; + SectionSP section_sp( + section_list->FindSectionContainingFileAddress(vm_addr)); + if (section_sp) { + lldb::offset_t offset_ptr = section_sp->GetFileOffset() + (vm_addr - section_sp->GetFileAddress()); + vm_addr = m_data.GetU64(&offset_ptr); + } + + if (!section_list) + m_entry_point_address.SetOffset(vm_addr); + else + m_entry_point_address.ResolveAddressUsingFileSections(vm_addr, + section_list); + + return m_entry_point_address; +} + +lldb_private::Address ObjectFileXCOFF::GetBaseAddress() { + return lldb_private::Address(); +} + +ObjectFile::Type ObjectFileXCOFF::CalculateType() { + if (m_xcoff_header.flags & XCOFF::F_EXEC) + return eTypeExecutable; + else if (m_xcoff_header.flags & XCOFF::F_SHROBJ) + return eTypeSharedLibrary; + return eTypeUnknown; +} + +ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { + return eStrataUnknown; +} + +llvm::StringRef +ObjectFileXCOFF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const { + return llvm::StringRef(); +} + +void ObjectFileXCOFF::RelocateSection(lldb_private::Section *section) +{ +} + +std::vector +ObjectFileXCOFF::GetLoadableData(Target &target) { + std::vector loadables; + return loadables; +} + +lldb::WritableDataBufferSP +ObjectFileXCOFF::MapFileDataWritable(const FileSpec &file, uint64_t Size, + uint64_t Offset) { + return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size, + Offset); +} + +ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp, + DataBufferSP data_sp, lldb::offset_t data_offset, + const FileSpec *file, lldb::offset_t file_offset, + lldb::offset_t length) + : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset), + m_xcoff_header(), m_sect_headers(), m_deps_filespec(), m_deps_base_members(), + m_entry_point_address() { + ::memset(&m_xcoff_header, 0, sizeof(m_xcoff_header)); + if (file) + m_file = *file; +} + +ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp, + DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, + addr_t header_addr) + : ObjectFile(module_sp, process_sp, header_addr, header_data_sp), + m_xcoff_header(), m_sect_headers(), m_deps_filespec(), m_deps_base_members(), + m_entry_point_address() { + ::memset(&m_xcoff_header, 0, sizeof(m_xcoff_header)); +} diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h new file mode 100644 index 0000000000000..5a12d16886489 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h @@ -0,0 +1,243 @@ +//===-- ObjectFileXCOFF.h --------------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H + +#include + +#include + +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/UUID.h" +#include "lldb/lldb-private.h" +#include "llvm/Object/XCOFFObjectFile.h" + +/// \class ObjectFileXCOFF +/// Generic XCOFF object file reader. +/// +/// This class provides a generic XCOFF (32/64 bit) reader plugin implementing +/// the ObjectFile protocol. +class ObjectFileXCOFF : public lldb_private::ObjectFile { +public: + // Static Functions + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "xcoff"; } + + static llvm::StringRef GetPluginDescriptionStatic() { + return "XCOFF object file reader."; + } + + static lldb_private::ObjectFile * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length); + + static lldb_private::ObjectFile *CreateMemoryInstance( + const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + + static size_t GetModuleSpecifications(const lldb_private::FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + lldb_private::ModuleSpecList &specs); + + static bool MagicBytesMatch(lldb::DataBufferSP &data_sp, lldb::addr_t offset, + lldb::addr_t length); + + static lldb::SymbolType MapSymbolType(llvm::object::SymbolRef::Type sym_type); + + // PluginInterface protocol + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + // LLVM RTTI support + static char ID; + bool isA(const void *ClassID) const override { + return ClassID == &ID || ObjectFile::isA(ClassID); + } + static bool classof(const ObjectFile *obj) { return obj->isA(&ID); } + + // ObjectFile Protocol. + bool ParseHeader() override; + + bool SetLoadAddress(lldb_private::Target &target, lldb::addr_t value, + bool value_is_offset) override; + + bool SetLoadAddressByType(lldb_private::Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) override; + + lldb::ByteOrder GetByteOrder() const override; + + bool IsExecutable() const override; + + uint32_t GetAddressByteSize() const override; + + lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override; + + void ParseSymtab(lldb_private::Symtab &symtab) override; + + bool IsStripped() override; + + void CreateSections(lldb_private::SectionList &unified_section_list) override; + + void Dump(lldb_private::Stream *s) override; + + lldb_private::ArchSpec GetArchitecture() override; + + lldb_private::UUID GetUUID() override; + + /// Return the contents of the .gnu_debuglink section, if the object file + /// contains it. + std::optional GetDebugLink(); + + uint32_t GetDependentModules(lldb_private::FileSpecList &files) override; + + lldb_private::Address + GetImageInfoAddress(lldb_private::Target *target) override; + + lldb_private::Address GetEntryPointAddress() override; + + lldb_private::Address GetBaseAddress() override; + + ObjectFile::Type CalculateType() override; + + ObjectFile::Strata CalculateStrata() override; + + llvm::StringRef + StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const override; + + void RelocateSection(lldb_private::Section *section) override; + + lldb_private::DataExtractor ReadImageData(uint32_t offset, size_t size); + + ObjectFileXCOFF(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + ObjectFileXCOFF(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + +protected: + + typedef struct xcoff_header { + uint16_t magic; + uint16_t nsects; + uint32_t modtime; + uint64_t symoff; + uint32_t nsyms; + uint16_t auxhdrsize; + uint16_t flags; + } xcoff_header_t; + + typedef struct xcoff_aux_header { + uint16_t AuxMagic; + uint16_t Version; + uint32_t ReservedForDebugger; + uint64_t TextStartAddr; + uint64_t DataStartAddr; + uint64_t TOCAnchorAddr; + uint16_t SecNumOfEntryPoint; + uint16_t SecNumOfText; + uint16_t SecNumOfData; + uint16_t SecNumOfTOC; + uint16_t SecNumOfLoader; + uint16_t SecNumOfBSS; + uint16_t MaxAlignOfText; + uint16_t MaxAlignOfData; + uint16_t ModuleType; + uint8_t CpuFlag; + uint8_t CpuType; + uint8_t TextPageSize; + uint8_t DataPageSize; + uint8_t StackPageSize; + uint8_t FlagAndTDataAlignment; + uint64_t TextSize; + uint64_t InitDataSize; + uint64_t BssDataSize; + uint64_t EntryPointAddr; + uint64_t MaxStackSize; + uint64_t MaxDataSize; + uint16_t SecNumOfTData; + uint16_t SecNumOfTBSS; + uint16_t XCOFF64Flag; + } xcoff_aux_header_t; + + typedef struct section_header { + char name[8]; + uint64_t phyaddr; // Physical Addr + uint64_t vmaddr; // Virtual Addr + uint64_t size; // Section size + uint64_t offset; // File offset to raw data + uint64_t reloff; // Offset to relocations + uint64_t lineoff; // Offset to line table entries + uint32_t nreloc; // Number of relocation entries + uint32_t nline; // Number of line table entries + uint32_t flags; + } section_header_t; + + typedef struct xcoff_symbol { + uint64_t value; + uint32_t offset; + uint16_t sect; + uint16_t type; + uint8_t storage; + uint8_t naux; + } xcoff_symbol_t; + + typedef struct xcoff_sym_csect_aux_entry { + uint32_t section_or_len_low_byte; + uint32_t parameter_hash_index; + uint16_t type_check_sect_num; + uint8_t symbol_alignment_and_type; + uint8_t storage_mapping_class; + uint32_t section_or_len_high_byte; + uint8_t pad; + uint8_t aux_type; + } xcoff_sym_csect_aux_entry_t; + + static bool ParseXCOFFHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + xcoff_header_t &xcoff_header); + bool ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr); + bool ParseSectionHeaders(uint32_t offset); + + std::vector + GetLoadableData(lldb_private::Target &target) override; + + static lldb::WritableDataBufferSP + MapFileDataWritable(const lldb_private::FileSpec &file, uint64_t Size, + uint64_t Offset); + llvm::StringRef GetSectionName(const section_header_t §); + static lldb::SectionType GetSectionType(llvm::StringRef sect_name, + const section_header_t §); + + uint32_t ParseDependentModules(); + typedef std::vector SectionHeaderColl; + +private: + bool CreateBinary(); + + xcoff_header_t m_xcoff_header; + xcoff_aux_header_t m_xcoff_aux_header; + SectionHeaderColl m_sect_headers; + std::unique_ptr m_binary; + lldb_private::Address m_entry_point_address; + std::optional m_deps_filespec; + std::map> m_deps_base_members; +}; + +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H diff --git a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp index e026ffefd645e..106e38b6e25ae 100644 --- a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp +++ b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp @@ -227,7 +227,7 @@ ThreadSP OperatingSystemPython::CreateThreadFromThreadInfo( ThreadList &old_thread_list, std::vector &core_used_map, bool *did_create_ptr) { ThreadSP thread_sp; - tid_t tid = LLDB_INVALID_THREAD_ID; + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; if (!thread_dict.GetValueForKeyAsInteger("tid", tid)) return ThreadSP(); diff --git a/lldb/source/Plugins/Platform/AIX/CMakeLists.txt b/lldb/source/Plugins/Platform/AIX/CMakeLists.txt new file mode 100644 index 0000000000000..85ff0a315eabd --- /dev/null +++ b/lldb/source/Plugins/Platform/AIX/CMakeLists.txt @@ -0,0 +1,13 @@ +add_definitions("-D_ALL_SOURCE") + +add_lldb_library(lldbPluginPlatformAIX PLUGIN + PlatformAIX.cpp + + LINK_LIBS + lldbBreakpoint + lldbCore + lldbHost + lldbInterpreter + lldbTarget + lldbPluginPlatformPOSIX + ) diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp new file mode 100644 index 0000000000000..b6b08b73bec41 --- /dev/null +++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp @@ -0,0 +1,471 @@ +//===-- PlatformAIX.cpp -------------------------------------------------===// +// +// 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 "PlatformAIX.h" +#include "lldb/Host/Config.h" + +#include +#if LLDB_ENABLE_POSIX +#include +#endif + +#include "Utility/ARM64_DWARF_Registers.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/StreamString.h" + +// Define these constants from AIX mman.h for use when targeting remote aix +// systems even when host has different values. + +#if defined(__AIX__) +#include +#endif + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::platform_aix; + +LLDB_PLUGIN_DEFINE(PlatformAIX) + +static uint32_t g_initialize_count = 0; + + +PlatformSP PlatformAIX::CreateInstance(bool force, const ArchSpec *arch) { + Log *log = GetLog(LLDBLog::Platform); + LLDB_LOG(log, "force = {0}, arch=({1}, {2})", force, + arch ? arch->GetArchitectureName() : "", + arch ? arch->GetTriple().getTriple() : ""); + + bool create = force; + if (!create && arch && arch->IsValid()) { + const llvm::Triple &triple = arch->GetTriple(); + switch (triple.getOS()) { + case llvm::Triple::AIX: + create = true; + break; + + default: + break; + } + } + + LLDB_LOG(log, "create = {0}", create); + if (create) { + return PlatformSP(new PlatformAIX(false)); + } + return PlatformSP(); +} + +llvm::StringRef PlatformAIX::GetPluginDescriptionStatic(bool is_host) { + if (is_host) + return "Local AIX user platform plug-in."; + return "Remote AIX user platform plug-in."; +} + +void PlatformAIX::Initialize() { + PlatformPOSIX::Initialize(); + + if (g_initialize_count++ == 0) { +#if defined(__AIX__) + PlatformSP default_platform_sp(new PlatformAIX(true)); + default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); + Platform::SetHostPlatform(default_platform_sp); +#endif + PluginManager::RegisterPlugin( + PlatformAIX::GetPluginNameStatic(false), + PlatformAIX::GetPluginDescriptionStatic(false), + PlatformAIX::CreateInstance, nullptr); + } +} + +void PlatformAIX::Terminate() { + if (g_initialize_count > 0) { + if (--g_initialize_count == 0) { + PluginManager::UnregisterPlugin(PlatformAIX::CreateInstance); + } + } + + PlatformPOSIX::Terminate(); +} + +/// Default Constructor +PlatformAIX::PlatformAIX(bool is_host) + : PlatformPOSIX(is_host) // This is the local host platform +{ + if (is_host) { + ArchSpec hostArch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault); + m_supported_architectures.push_back(hostArch); + if (hostArch.GetTriple().isArch64Bit()) { + m_supported_architectures.push_back( + HostInfo::GetArchitecture(HostInfo::eArchKind32)); + } + } else { + m_supported_architectures = CreateArchList( + {llvm::Triple::x86_64, llvm::Triple::x86, llvm::Triple::arm, + llvm::Triple::aarch64, llvm::Triple::mips64, llvm::Triple::mips64, + llvm::Triple::hexagon, llvm::Triple::mips, llvm::Triple::mips64el, + llvm::Triple::mipsel, llvm::Triple::systemz}, + llvm::Triple::AIX); + } +} + +std::vector +PlatformAIX::GetSupportedArchitectures(const ArchSpec &process_host_arch) { + if (m_remote_platform_sp) + return m_remote_platform_sp->GetSupportedArchitectures(process_host_arch); + return m_supported_architectures; +} + +void PlatformAIX::GetStatus(Stream &strm) { + Platform::GetStatus(strm); + +#if LLDB_ENABLE_POSIX + // Display local kernel information only when we are running in host mode. + // Otherwise, we would end up printing non-AIX information (when running on + // Mac OS for example). + if (IsHost()) { + struct utsname un; + + if (uname(&un)) + return; + + strm.Printf(" Kernel: %s\n", un.sysname); + strm.Printf(" Release: %s\n", un.release); + strm.Printf(" Version: %s\n", un.version); + } +#endif +} + +uint32_t +PlatformAIX::GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) { + uint32_t resume_count = 0; + + // Always resume past the initial stop when we use eLaunchFlagDebug + if (launch_info.GetFlags().Test(eLaunchFlagDebug)) { + // Resume past the stop for the final exec into the true inferior. + ++resume_count; + } + + // If we're not launching a shell, we're done. + const FileSpec &shell = launch_info.GetShell(); + if (!shell) + return resume_count; + + std::string shell_string = shell.GetPath(); + // We're in a shell, so for sure we have to resume past the shell exec. + ++resume_count; + + // Figure out what shell we're planning on using. + const char *shell_name = strrchr(shell_string.c_str(), '/'); + if (shell_name == nullptr) + shell_name = shell_string.c_str(); + else + shell_name++; + + if (strcmp(shell_name, "csh") == 0 || strcmp(shell_name, "tcsh") == 0 || + strcmp(shell_name, "zsh") == 0 || strcmp(shell_name, "sh") == 0) { + // These shells seem to re-exec themselves. Add another resume. + ++resume_count; + } + + return resume_count; +} + +bool PlatformAIX::CanDebugProcess() { + if (IsHost()) { + return true; + } else { + // If we're connected, we can debug. + return IsConnected(); + } +} + +void PlatformAIX::CalculateTrapHandlerSymbolNames() { + m_trap_handlers.push_back(ConstString("_sigtramp")); + m_trap_handlers.push_back(ConstString("__kernel_rt_sigreturn")); + m_trap_handlers.push_back(ConstString("__restore_rt")); +} + +static lldb::UnwindPlanSP GetAArch64TrapHanlderUnwindPlan(ConstString name) { + UnwindPlanSP unwind_plan_sp; + if (name != "__kernel_rt_sigreturn") + return unwind_plan_sp; + + UnwindPlan::RowSP row = std::make_shared(); + row->SetOffset(0); + + // In the signal trampoline frame, sp points to an rt_sigframe[1], which is: + // - 128-byte siginfo struct + // - ucontext struct: + // - 8-byte long (uc_flags) + // - 8-byte pointer (uc_link) + // - 24-byte stack_t + // - 128-byte signal set + // - 8 bytes of padding because sigcontext has 16-byte alignment + // - sigcontext/mcontext_t + // [1] + // https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/signal.c + int32_t offset = 128 + 8 + 8 + 24 + 128 + 8; + // Then sigcontext[2] is: + // - 8 byte fault address + // - 31 8 byte registers + // - 8 byte sp + // - 8 byte pc + // [2] + // https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/sigcontext.h + + // Skip fault address + offset += 8; + row->GetCFAValue().SetIsRegisterPlusOffset(arm64_dwarf::sp, offset); + + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x0, 0 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x1, 1 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x2, 2 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x3, 3 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x4, 4 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x5, 5 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x6, 6 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x7, 7 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x8, 8 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x9, 9 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x10, 10 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x11, 11 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x12, 12 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x13, 13 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x14, 14 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x15, 15 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x16, 16 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x17, 17 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x18, 18 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x19, 19 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x20, 20 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x21, 21 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x22, 22 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x23, 23 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x24, 24 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x25, 25 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x26, 26 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x27, 27 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x28, 28 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::fp, 29 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x30, 30 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::sp, 31 * 8, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::pc, 32 * 8, false); + + // The sigcontext may also contain floating point and SVE registers. + // However this would require a dynamic unwind plan so they are not included + // here. + + unwind_plan_sp = std::make_shared(eRegisterKindDWARF); + unwind_plan_sp->AppendRow(row); + unwind_plan_sp->SetSourceName("AArch64 AIX sigcontext"); + unwind_plan_sp->SetSourcedFromCompiler(eLazyBoolYes); + // Because sp is the same throughout the function + unwind_plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolYes); + unwind_plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolYes); + + return unwind_plan_sp; +} + +lldb::UnwindPlanSP +PlatformAIX::GetTrapHandlerUnwindPlan(const llvm::Triple &triple, + ConstString name) { + if (triple.isAArch64()) + return GetAArch64TrapHanlderUnwindPlan(name); + + return {}; +} + +MmapArgList PlatformAIX::GetMmapArgumentList(const ArchSpec &arch, + addr_t addr, addr_t length, + unsigned prot, unsigned flags, + addr_t fd, addr_t offset) { +#if defined(__AIX__) + unsigned flags_platform = MAP_VARIABLE | MAP_PRIVATE | MAP_ANONYMOUS; +#else + unsigned flags_platform = 0; +#endif + MmapArgList args({addr, length, prot, flags_platform, fd, offset}); + return args; +} + +CompilerType PlatformAIX::GetSiginfoType(const llvm::Triple &triple) { + if (!m_type_system_up) + m_type_system_up.reset(new TypeSystemClang("siginfo", triple)); + TypeSystemClang *ast = m_type_system_up.get(); + + bool si_errno_then_code = true; + + switch (triple.getArch()) { + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + // mips has si_code and si_errno swapped + si_errno_then_code = false; + break; + default: + break; + } + + // generic types + CompilerType int_type = ast->GetBasicType(eBasicTypeInt); + CompilerType uint_type = ast->GetBasicType(eBasicTypeUnsignedInt); + CompilerType short_type = ast->GetBasicType(eBasicTypeShort); + CompilerType long_type = ast->GetBasicType(eBasicTypeLong); + CompilerType voidp_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); + + // platform-specific types + CompilerType &pid_type = int_type; + CompilerType &uid_type = uint_type; + CompilerType &clock_type = long_type; + CompilerType &band_type = long_type; + + CompilerType sigval_type = ast->CreateRecordType( + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_sigval_t", + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); + ast->StartTagDeclarationDefinition(sigval_type); + ast->AddFieldToRecordType(sigval_type, "sival_int", int_type, + lldb::eAccessPublic, 0); + ast->AddFieldToRecordType(sigval_type, "sival_ptr", voidp_type, + lldb::eAccessPublic, 0); + ast->CompleteTagDeclarationDefinition(sigval_type); + + CompilerType sigfault_bounds_type = ast->CreateRecordType( + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); + ast->StartTagDeclarationDefinition(sigfault_bounds_type); + ast->AddFieldToRecordType(sigfault_bounds_type, "_addr_bnd", + ast->CreateStructForIdentifier(ConstString(), + { + {"_lower", voidp_type}, + {"_upper", voidp_type}, + }), + lldb::eAccessPublic, 0); + ast->AddFieldToRecordType(sigfault_bounds_type, "_pkey", uint_type, + lldb::eAccessPublic, 0); + ast->CompleteTagDeclarationDefinition(sigfault_bounds_type); + + // siginfo_t + CompilerType siginfo_type = ast->CreateRecordType( + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_siginfo_t", + llvm::to_underlying(clang::TagTypeKind::Struct), lldb::eLanguageTypeC); + ast->StartTagDeclarationDefinition(siginfo_type); + ast->AddFieldToRecordType(siginfo_type, "si_signo", int_type, + lldb::eAccessPublic, 0); + + if (si_errno_then_code) { + ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type, + lldb::eAccessPublic, 0); + ast->AddFieldToRecordType(siginfo_type, "si_code", int_type, + lldb::eAccessPublic, 0); + } else { + ast->AddFieldToRecordType(siginfo_type, "si_code", int_type, + lldb::eAccessPublic, 0); + ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type, + lldb::eAccessPublic, 0); + } + + // the structure is padded on 64-bit arches to fix alignment + if (triple.isArch64Bit()) + ast->AddFieldToRecordType(siginfo_type, "__pad0", int_type, + lldb::eAccessPublic, 0); + + // union used to hold the signal data + CompilerType union_type = ast->CreateRecordType( + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", + llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); + ast->StartTagDeclarationDefinition(union_type); + + ast->AddFieldToRecordType( + union_type, "_kill", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_pid", pid_type}, + {"si_uid", uid_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_timer", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_tid", int_type}, + {"si_overrun", int_type}, + {"si_sigval", sigval_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_rt", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_pid", pid_type}, + {"si_uid", uid_type}, + {"si_sigval", sigval_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_sigchld", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_pid", pid_type}, + {"si_uid", uid_type}, + {"si_status", int_type}, + {"si_utime", clock_type}, + {"si_stime", clock_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_sigfault", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_addr", voidp_type}, + {"si_addr_lsb", short_type}, + {"_bounds", sigfault_bounds_type}, + }), + lldb::eAccessPublic, 0); + + ast->AddFieldToRecordType( + union_type, "_sigpoll", + ast->CreateStructForIdentifier(ConstString(), + { + {"si_band", band_type}, + {"si_fd", int_type}, + }), + lldb::eAccessPublic, 0); + + // NB: SIGSYS is not present on ia64 but we don't seem to support that + ast->AddFieldToRecordType( + union_type, "_sigsys", + ast->CreateStructForIdentifier(ConstString(), + { + {"_call_addr", voidp_type}, + {"_syscall", int_type}, + {"_arch", uint_type}, + }), + lldb::eAccessPublic, 0); + + ast->CompleteTagDeclarationDefinition(union_type); + ast->AddFieldToRecordType(siginfo_type, "_sifields", union_type, + lldb::eAccessPublic, 0); + + ast->CompleteTagDeclarationDefinition(siginfo_type); + return siginfo_type; +} diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.h b/lldb/source/Plugins/Platform/AIX/PlatformAIX.h new file mode 100644 index 0000000000000..3ae8089a48d71 --- /dev/null +++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.h @@ -0,0 +1,74 @@ +//===-- PlatformAIX.h -----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PLATFORM_AIX_PLATFORMAIX_H +#define LLDB_SOURCE_PLUGINS_PLATFORM_AIX_PLATFORMAIX_H + +#include "Plugins/Platform/POSIX/PlatformPOSIX.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" + +namespace lldb_private { +namespace platform_aix { + +class PlatformAIX : public PlatformPOSIX { +public: + PlatformAIX(bool is_host); + + static void Initialize(); + + static void Terminate(); + + // lldb_private::PluginInterface functions + static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch); + + static llvm::StringRef GetPluginNameStatic(bool is_host) { + return is_host ? Platform::GetHostPlatformName() : "remote-AIX"; + } + + static llvm::StringRef GetPluginDescriptionStatic(bool is_host); + + llvm::StringRef GetPluginName() override { + return GetPluginNameStatic(IsHost()); + } + + // lldb_private::Platform functions + llvm::StringRef GetDescription() override { + return GetPluginDescriptionStatic(IsHost()); + } + + void GetStatus(Stream &strm) override; + + std::vector + GetSupportedArchitectures(const ArchSpec &process_host_arch) override; + + uint32_t GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) override; + + bool CanDebugProcess() override; + + void CalculateTrapHandlerSymbolNames() override; + + lldb::UnwindPlanSP GetTrapHandlerUnwindPlan(const llvm::Triple &triple, + ConstString name) override; + + MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr, + lldb::addr_t length, unsigned prot, + unsigned flags, lldb::addr_t fd, + lldb::addr_t offset) override; + + CompilerType GetSiginfoType(const llvm::Triple &triple) override; + + std::vector m_supported_architectures; + +private: + std::unique_ptr m_type_system_up; +}; + +} // namespace platform_AIX +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_PLATFORM_AIX_PLATFORMAIX_H diff --git a/lldb/source/Plugins/Platform/CMakeLists.txt b/lldb/source/Plugins/Platform/CMakeLists.txt index 6869587f917eb..9d0afd97cff85 100644 --- a/lldb/source/Plugins/Platform/CMakeLists.txt +++ b/lldb/source/Plugins/Platform/CMakeLists.txt @@ -8,3 +8,4 @@ add_subdirectory(OpenBSD) add_subdirectory(POSIX) add_subdirectory(QemuUser) add_subdirectory(Windows) +add_subdirectory(AIX) diff --git a/lldb/source/Plugins/Process/AIX/CMakeLists.txt b/lldb/source/Plugins/Process/AIX/CMakeLists.txt new file mode 100644 index 0000000000000..e9d83266f5857 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/CMakeLists.txt @@ -0,0 +1,19 @@ +add_definitions("-D_ALL_SOURCE") + +add_lldb_library(lldbPluginProcessAIX + NativeProcessAIX.cpp + NativeRegisterContextAIX.cpp + NativeRegisterContextAIX_ppc64.cpp + NativeThreadAIX.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + lldbTarget + lldbUtility + lldbPluginProcessPOSIX + lldbPluginProcessUtility + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp new file mode 100644 index 0000000000000..882f20d30a3bf --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -0,0 +1,2048 @@ +//===-- NativeProcessAIX.cpp --------------------------------------------===// +// +// 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 "NativeProcessAIX.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "NativeThreadAIX.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +//#include "Plugins/Process/Utility/LinuxProcMaps.h" +//#include "Procfs.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/HostProcess.h" +#include "lldb/Host/ProcessLaunchInfo.h" +#include "lldb/Host/PseudoTerminal.h" +#include "lldb/Host/ThreadLauncher.h" +#include "lldb/Host/common/NativeRegisterContext.h" +#include "lldb/Host/aix/Ptrace.h" +//#include "lldb/Host/linux/Host.h" +//#include "lldb/Host/linux/Uio.h" +#include "lldb/Host/posix/ProcessLauncherPosixFork.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/State.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/StringExtractor.h" +#include "llvm/ADT/ScopeExit.h" +#include "llvm/Support/Errno.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Threading.h" + +#include +#include +#include +#include +//#include +#include +#include +#include +#include + +#ifdef __aarch64__ +#include +#include +#endif + +// Support hardware breakpoints in case it has not been defined +#ifndef TRAP_HWBKPT +#define TRAP_HWBKPT 4 +#endif + +#ifndef HWCAP2_MTE +#define HWCAP2_MTE (1 << 18) +#endif + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; +using namespace llvm; + +// Private bits we only need internally. + +static bool ProcessVmReadvSupported() { + static bool is_supported; + static llvm::once_flag flag; + + llvm::call_once(flag, [] { + Log *log = GetLog(POSIXLog::Process); + + uint32_t source = 0x47424742; + uint32_t dest = 0; + + struct iovec local, remote; + remote.iov_base = &source; + local.iov_base = &dest; + remote.iov_len = local.iov_len = sizeof source; + +#if 0 + // We shall try if cross-process-memory reads work by attempting to read a + // value from our own process. + ssize_t res = process_vm_readv(getpid(), &local, 1, &remote, 1, 0); + is_supported = (res == sizeof(source) && source == dest); + if (is_supported) + LLDB_LOG(log, + "Detected kernel support for process_vm_readv syscall. " + "Fast memory reads enabled."); + else + LLDB_LOG(log, + "syscall process_vm_readv failed (error: {0}). Fast memory " + "reads disabled.", + llvm::sys::StrError()); +#endif + }); + + return is_supported; +} + +static void MaybeLogLaunchInfo(const ProcessLaunchInfo &info) { + Log *log = GetLog(POSIXLog::Process); + if (!log) + return; + + if (const FileAction *action = info.GetFileActionForFD(STDIN_FILENO)) + LLDB_LOG(log, "setting STDIN to '{0}'", action->GetFileSpec()); + else + LLDB_LOG(log, "leaving STDIN as is"); + + if (const FileAction *action = info.GetFileActionForFD(STDOUT_FILENO)) + LLDB_LOG(log, "setting STDOUT to '{0}'", action->GetFileSpec()); + else + LLDB_LOG(log, "leaving STDOUT as is"); + + if (const FileAction *action = info.GetFileActionForFD(STDERR_FILENO)) + LLDB_LOG(log, "setting STDERR to '{0}'", action->GetFileSpec()); + else + LLDB_LOG(log, "leaving STDERR as is"); + + int i = 0; + for (const char **args = info.GetArguments().GetConstArgumentVector(); *args; + ++args, ++i) + LLDB_LOG(log, "arg {0}: '{1}'", i, *args); +} + +static void DisplayBytes(StreamString &s, void *bytes, uint32_t count) { + uint8_t *ptr = (uint8_t *)bytes; + const uint32_t loop_count = std::min(DEBUG_PTRACE_MAXBYTES, count); + for (uint32_t i = 0; i < loop_count; i++) { + s.Printf("[%x]", *ptr); + ptr++; + } +} + +static void PtraceDisplayBytes(int &req, void *data, size_t data_size) { + Log *log = GetLog(POSIXLog::Ptrace); + if (!log) + return; + StreamString buf; + + switch (req) { + case PTRACE_POKETEXT: { + DisplayBytes(buf, &data, 8); + LLDB_LOGV(log, "PTRACE_POKETEXT {0}", buf.GetData()); + break; + } + case PTRACE_POKEDATA: { + DisplayBytes(buf, &data, 8); + LLDB_LOGV(log, "PTRACE_POKEDATA {0}", buf.GetData()); + break; + } + case PTRACE_POKEUSER: { + DisplayBytes(buf, &data, 8); + LLDB_LOGV(log, "PTRACE_POKEUSER {0}", buf.GetData()); + break; + } + case PTRACE_SETREGS: { + DisplayBytes(buf, data, data_size); + LLDB_LOGV(log, "PTRACE_SETREGS {0}", buf.GetData()); + break; + } + case PTRACE_SETFPREGS: { + DisplayBytes(buf, data, data_size); + LLDB_LOGV(log, "PTRACE_SETFPREGS {0}", buf.GetData()); + break; + } +#if 0 + case PTRACE_SETSIGINFO: { + DisplayBytes(buf, data, sizeof(siginfo_t)); + LLDB_LOGV(log, "PTRACE_SETSIGINFO {0}", buf.GetData()); + break; + } +#endif + case PTRACE_SETREGSET: { + // Extract iov_base from data, which is a pointer to the struct iovec + DisplayBytes(buf, *(void **)data, data_size); + LLDB_LOGV(log, "PTRACE_SETREGSET {0}", buf.GetData()); + break; + } + default: {} + } +} + +static constexpr unsigned k_ptrace_word_size = sizeof(void *); +static_assert(sizeof(long) >= k_ptrace_word_size, + "Size of long must be larger than ptrace word size"); + +// Simple helper function to ensure flags are enabled on the given file +// descriptor. +static Status EnsureFDFlags(int fd, int flags) { + Status error; + + int status = fcntl(fd, F_GETFL); + if (status == -1) { + error.SetErrorToErrno(); + return error; + } + + if (fcntl(fd, F_SETFL, status | flags) == -1) { + error.SetErrorToErrno(); + return error; + } + + return error; +} + +#if 0 +static llvm::Error AddPtraceScopeNote(llvm::Error original_error) { + Expected ptrace_scope = GetPtraceScope(); + if (auto E = ptrace_scope.takeError()) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "error reading value of ptrace_scope: {0}", E); + + // The original error is probably more interesting than not being able to + // read or interpret ptrace_scope. + return original_error; + } + + // We only have suggestions to provide for 1-3. + switch (*ptrace_scope) { + case 1: + case 2: + return llvm::createStringError( + std::error_code(errno, std::generic_category()), + "The current value of ptrace_scope is %d, which can cause ptrace to " + "fail to attach to a running process. To fix this, run:\n" + "\tsudo sysctl -w kernel.yama.ptrace_scope=0\n" + "For more information, see: " + "https://www.kernel.org/doc/Documentation/security/Yama.txt.", + *ptrace_scope); + case 3: + return llvm::createStringError( + std::error_code(errno, std::generic_category()), + "The current value of ptrace_scope is 3, which will cause ptrace to " + "fail to attach to a running process. This value cannot be changed " + "without rebooting.\n" + "For more information, see: " + "https://www.kernel.org/doc/Documentation/security/Yama.txt."); + case 0: + default: + return original_error; + } +} +#endif + +NativeProcessAIX::Manager::Manager(MainLoop &mainloop) + : NativeProcessProtocol::Manager(mainloop) { + Status status; + m_sigchld_handle = mainloop.RegisterSignal( + SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status); + assert(m_sigchld_handle && status.Success()); +} + +// Public Static Methods + +llvm::Expected> +NativeProcessAIX::Manager::Launch(ProcessLaunchInfo &launch_info, + NativeDelegate &native_delegate) { + Log *log = GetLog(POSIXLog::Process); + + MaybeLogLaunchInfo(launch_info); + + Status status; + ::pid_t pid = ProcessLauncherPosixFork() + .LaunchProcess(launch_info, status) + .GetProcessId(); + LLDB_LOG(log, "pid = {0:x}", pid); + if (status.Fail()) { + LLDB_LOG(log, "failed to launch process: {0}", status); + return status.ToError(); + } + + // Wait for the child process to trap on its call to execve. + int wstatus = 0; + ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0); + assert(wpid == pid); + UNUSED_IF_ASSERT_DISABLED(wpid); + if (!WIFSTOPPED(wstatus)) { + LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}", + WaitStatus::Decode(wstatus)); + return llvm::make_error("Could not sync with inferior process", + llvm::inconvertibleErrorCode()); + } + LLDB_LOG(log, "inferior started, now in stopped state"); + + ProcessInstanceInfo Info; + if (!Host::GetProcessInfo(pid, Info)) { + return llvm::make_error("Cannot get process architectrue", + llvm::inconvertibleErrorCode()); + } + /*llvm::Expected arch_or = + NativeRegisterContextAIX::DetermineArchitecture(pid); + if (!arch_or) + return arch_or.takeError();*/ + + // Set the architecture to the exe architecture. + LLDB_LOG(log, "pid = {0}, detected architecture {1}", pid, + Info.GetArchitecture().GetArchitectureName()); + + return std::unique_ptr(new NativeProcessAIX( + pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate, + Info.GetArchitecture(), *this, {pid})); +} + +llvm::Expected> +NativeProcessAIX::Manager::Attach( + lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "pid = {0:x}", pid); + + ProcessInstanceInfo Info; + if (!Host::GetProcessInfo(pid, Info)) { + return llvm::make_error("Cannot get process architectrue", + llvm::inconvertibleErrorCode()); + } + auto tids_or = NativeProcessAIX::Attach(pid); + if (!tids_or) + return tids_or.takeError(); +#if 0 + ArrayRef<::pid_t> tids = *tids_or; + llvm::Expected arch_or = + NativeRegisterContextAIX::DetermineArchitecture(tids[0]); + if (!arch_or) + return arch_or.takeError(); +#endif + + return std::unique_ptr( + new NativeProcessAIX(pid, -1, native_delegate, Info.GetArchitecture(), *this, *tids_or)); +} + +lldb::addr_t NativeProcessAIX::GetSharedLibraryInfoAddress() { + // punt on this for now + return LLDB_INVALID_ADDRESS; +} + +NativeProcessAIX::Extension +NativeProcessAIX::Manager::GetSupportedExtensions() const { + NativeProcessAIX::Extension supported = + Extension::multiprocess | Extension::fork | Extension::vfork | + Extension::pass_signals | Extension::auxv | Extension::libraries_svr4 | + Extension::siginfo_read; + +#ifdef __aarch64__ + // At this point we do not have a process so read auxv directly. + if ((getauxval(AT_HWCAP2) & HWCAP2_MTE)) + supported |= Extension::memory_tagging; +#endif + + return supported; +} + +static std::optional> WaitPid() { + Log *log = GetLog(POSIXLog::Process); + + int status; + ::pid_t wait_pid = llvm::sys::RetryAfterSignal( + -1, ::waitpid, -1, &status, /*__WALL | __WNOTHREAD |*/ WNOHANG); + + if (wait_pid == 0) + return std::nullopt; + + if (wait_pid == -1) { + Status error(errno, eErrorTypePOSIX); + LLDB_LOG(log, "waitpid(-1, &status, _) failed: {1}", error); + return std::nullopt; + } + + WaitStatus wait_status = WaitStatus::Decode(status); + + LLDB_LOG(log, "waitpid(-1, &status, _) = {0}, status = {1}", wait_pid, + wait_status); + return std::make_pair(wait_pid, wait_status); +} + +void NativeProcessAIX::Manager::SigchldHandler() { + Log *log = GetLog(POSIXLog::Process); + while (true) { + auto wait_result = WaitPid(); + if (!wait_result) + return; + lldb::pid_t pid = wait_result->first; + WaitStatus status = wait_result->second; + + // Ask each process whether it wants to handle the event. Each event should + // be handled by exactly one process, but thread creation events require + // special handling. + // Thread creation consists of two events (one on the parent and one on the + // child thread) and they can arrive in any order nondeterministically. The + // parent event carries the information about the child thread, but not + // vice-versa. This means that if the child event arrives first, it may not + // be handled by any process (because it doesn't know the thread belongs to + // it). + bool handled = llvm::any_of(m_processes, [&](NativeProcessAIX *process) { + return process->TryHandleWaitStatus(pid, status); + }); + if (!handled) { + if (status.type == WaitStatus::Stop && status.status == SIGSTOP) { + // Store the thread creation event for later collection. + m_unowned_threads.insert(pid); + } else { + LLDB_LOG(log, "Ignoring waitpid event {0} for pid {1}", status, pid); + } + } + } +} + +void NativeProcessAIX::Manager::CollectThread(::pid_t tid) { + Log *log = GetLog(POSIXLog::Process); + + if (m_unowned_threads.erase(tid)) + return; // We've encountered this thread already. + + // The TID is not tracked yet, let's wait for it to appear. + int status = -1; + LLDB_LOG(log, + "received clone event for tid {0}. tid not tracked yet, " + "waiting for it to appear...", + tid); + ::pid_t wait_pid = + llvm::sys::RetryAfterSignal(-1, ::waitpid, tid, &status, P_ALL/*__WALL*/); + + // It's theoretically possible to get other events if the entire process was + // SIGKILLed before we got a chance to check this. In that case, we'll just + // clean everything up when we get the process exit event. + + LLDB_LOG(log, + "waitpid({0}, &status, __WALL) => {1} (errno: {2}, status = {3})", + tid, wait_pid, errno, WaitStatus::Decode(status)); +} + +// Public Instance Methods + +NativeProcessAIX::NativeProcessAIX(::pid_t pid, int terminal_fd, + NativeDelegate &delegate, + const ArchSpec &arch, Manager &manager, + llvm::ArrayRef<::pid_t> tids) + : NativeProcessProtocol(pid, terminal_fd, delegate), m_manager(manager), + m_arch(arch) { + manager.AddProcess(*this); + if (m_terminal_fd != -1) { + Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK); + assert(status.Success()); + } + + for (const auto &tid : tids) { + NativeThreadAIX &thread = AddThread(tid, /*resume*/ false); + ThreadWasCreated(thread); + } + + // Let our process instance know the thread has stopped. + SetCurrentThreadID(tids[0]); + SetState(StateType::eStateStopped, false); +} + +llvm::Expected> NativeProcessAIX::Attach(::pid_t pid) { + Log *log = GetLog(POSIXLog::Process); + + Status status; + if ((status = PtraceWrapper(PT_ATTACH, pid)).Fail()) { + return status.ToError(); + } + + int wpid = + llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, nullptr, WNOHANG); + if (wpid <= 0) { + return llvm::errorCodeToError( + std::error_code(errno, std::generic_category())); + } + + LLDB_LOG(log, "adding pid = {0}", pid); + + std::vector<::pid_t> tids; + tids.push_back(pid); + return std::move(tids); +} + +bool NativeProcessAIX::TryHandleWaitStatus(lldb::pid_t pid, + WaitStatus status) { + if (pid == GetID() && + (status.type == WaitStatus::Exit || status.type == WaitStatus::Signal)) { + // The process exited. We're done monitoring. Report to delegate. + SetExitStatus(status, true); + return true; + } + if (NativeThreadAIX *thread = GetThreadByID(pid)) { + MonitorCallback(*thread, status); + return true; + } + return false; +} + +// Handles all waitpid events from the inferior process. +void NativeProcessAIX::MonitorCallback(NativeThreadAIX &thread, + WaitStatus status) { + Log *log = GetLog(LLDBLog::Process); + + // Certain activities differ based on whether the pid is the tid of the main + // thread. + const bool is_main_thread = (thread.GetID() == GetID()); + + // Handle when the thread exits. + if (status.type == WaitStatus::Exit || status.type == WaitStatus::Signal) { + LLDB_LOG(log, + "got exit status({0}) , tid = {1} ({2} main thread), process " + "state = {3}", + status, thread.GetID(), is_main_thread ? "is" : "is not", + GetState()); + + // This is a thread that exited. Ensure we're not tracking it anymore. + StopTrackingThread(thread); + + assert(!is_main_thread && "Main thread exits handled elsewhere"); + return; + } + + int8_t signo = GetSignalInfo(status); + + // Get details on the signal raised. + if (signo) { + // We have retrieved the signal info. Dispatch appropriately. + if (signo == SIGTRAP) + MonitorSIGTRAP(status, thread); + else + MonitorSignal(status, thread); + } else { + assert(0); + } +} + + +void NativeProcessAIX::MonitorSIGTRAP(const WaitStatus status, + NativeThreadAIX &thread) { + Log *log = GetLog(POSIXLog::Process); + const bool is_main_thread = (thread.GetID() == GetID()); + + NativeRegisterContextAIX ®_ctx = thread.GetRegisterContext(); + const RegisterInfo *pc_info = reg_ctx.GetRegisterInfoByName("pc", 0); + RegisterValue pc_value; + + switch (status.status) { + case SIGTRAP: + // Determine the source of SIGTRAP by checking current instruction: + // if that is trap instruction, then this is breakpoint, otherwise + // this is watchpoint. + reg_ctx.ReadRegister(pc_info, pc_value); + + MonitorBreakpoint(thread); + break; + default: + LLDB_LOG(log, "received unknown SIGTRAP stop event ({0}, pid {1} tid {2}", + status.status, GetID(), thread.GetID()); + MonitorSignal(status, thread); + break; + } +} + +void NativeProcessAIX::MonitorTrace(NativeThreadAIX &thread) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "received trace event, pid = {0}", thread.GetID()); + + // This thread is currently stopped. + thread.SetStoppedByTrace(); + + StopRunningThreads(thread.GetID()); +} + +void NativeProcessAIX::MonitorBreakpoint(NativeThreadAIX &thread) { + Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints); + LLDB_LOG(log, "received breakpoint event, pid = {0}", thread.GetID()); + + // Mark the thread as stopped at breakpoint. + thread.SetStoppedByBreakpoint(); + FixupBreakpointPCAsNeeded(thread); + + if (m_threads_stepping_with_breakpoint.find(thread.GetID()) != + m_threads_stepping_with_breakpoint.end()) + thread.SetStoppedByTrace(); + + StopRunningThreads(thread.GetID()); +} + +void NativeProcessAIX::MonitorWatchpoint(NativeThreadAIX &thread, + uint32_t wp_index) { + Log *log = GetLog(LLDBLog::Process | LLDBLog::Watchpoints); + LLDB_LOG(log, "received watchpoint event, pid = {0}, wp_index = {1}", + thread.GetID(), wp_index); + + // Mark the thread as stopped at watchpoint. The address is at + // (lldb::addr_t)info->si_addr if we need it. + thread.SetStoppedByWatchpoint(wp_index); + + // We need to tell all other running threads before we notify the delegate + // about this stop. + StopRunningThreads(thread.GetID()); +} + +void NativeProcessAIX::MonitorSignal(const WaitStatus status, + NativeThreadAIX &thread) { + int8_t signo = GetSignalInfo(status); +#if 0 + const bool is_from_llgs = info.si_pid == getpid(); +#endif + + Log *log = GetLog(POSIXLog::Process); + + // POSIX says that process behaviour is undefined after it ignores a SIGFPE, + // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a kill(2) + // or raise(3). Similarly for tgkill(2) on AIX. + // + // IOW, user generated signals never generate what we consider to be a + // "crash". + // + // Similarly, ACK signals generated by this monitor. + + // Handle the signal. + LLDB_LOG(log, + "received signal {0} ({1}) with code NA, (siginfo pid = {2}, " + "waitpid pid = {3})", + Host::GetSignalAsCString(signo), signo, thread.GetID(), GetID()); + +#if 0 + // Check for thread stop notification. + // FIXME + if (is_from_llgs /*&& (info.si_code == SI_TKILL)*/ && (signo == SIGSTOP)) { + // This is a tgkill()-based stop. + LLDB_LOG(log, "pid {0} tid {1}, thread stopped", GetID(), thread.GetID()); + + // Check that we're not already marked with a stop reason. Note this thread + // really shouldn't already be marked as stopped - if we were, that would + // imply that the kernel signaled us with the thread stopping which we + // handled and marked as stopped, and that, without an intervening resume, + // we received another stop. It is more likely that we are missing the + // marking of a run state somewhere if we find that the thread was marked + // as stopped. + const StateType thread_state = thread.GetState(); + if (!StateIsStoppedState(thread_state, false)) { + // An inferior thread has stopped because of a SIGSTOP we have sent it. + // Generally, these are not important stops and we don't want to report + // them as they are just used to stop other threads when one thread (the + // one with the *real* stop reason) hits a breakpoint (watchpoint, + // etc...). However, in the case of an asynchronous Interrupt(), this + // *is* the real stop reason, so we leave the signal intact if this is + // the thread that was chosen as the triggering thread. + if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID) { + if (m_pending_notification_tid == thread.GetID()) + thread.SetStoppedBySignal(SIGSTOP, &info); + else + thread.SetStoppedWithNoReason(); + + SetCurrentThreadID(thread.GetID()); + SignalIfAllThreadsStopped(); + } else { + // We can end up here if stop was initiated by LLGS but by this time a + // thread stop has occurred - maybe initiated by another event. + Status error = ResumeThread(thread, thread.GetState(), 0); + if (error.Fail()) + LLDB_LOG(log, "failed to resume thread {0}: {1}", thread.GetID(), + error); + } + } else { + LLDB_LOG(log, + "pid {0} tid {1}, thread was already marked as a stopped " + "state (state={2}), leaving stop signal as is", + GetID(), thread.GetID(), thread_state); + SignalIfAllThreadsStopped(); + } + + // Done handling. + return; + } +#endif + + // Check if debugger should stop at this signal or just ignore it and resume + // the inferior. + if (m_signals_to_ignore.contains(signo) || signo == SIGCHLD) { + ResumeThread(thread, thread.GetState(), signo); + return; + } + + // This thread is stopped. + LLDB_LOG(log, "received signal {0}", Host::GetSignalAsCString(signo)); + thread.SetStoppedBySignal(signo); + + // Send a stop to the debugger after we get all other threads to stop. + StopRunningThreads(thread.GetID()); +} + +bool NativeProcessAIX::MonitorClone(NativeThreadAIX &parent, + lldb::pid_t child_pid, int event) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "parent_tid={0}, child_pid={1}, event={2}", parent.GetID(), + child_pid, event); + + // WaitForCloneNotification(child_pid); + + switch (event) { +#if 0 + case PTRACE_EVENT_CLONE: { + // PTRACE_EVENT_CLONE can either mean a new thread or a new process. + // Try to grab the new process' PGID to figure out which one it is. + // If PGID is the same as the PID, then it's a new process. Otherwise, + // it's a thread. + auto tgid_ret = getPIDForTID(child_pid); + if (tgid_ret != child_pid) { + // A new thread should have PGID matching our process' PID. + assert(!tgid_ret || tgid_ret.getValue() == GetID()); + + NativeThreadAIX &child_thread = AddThread(child_pid, /*resume*/ true); + ThreadWasCreated(child_thread); + + // Resume the parent. + ResumeThread(parent, parent.GetState(), LLDB_INVALID_SIGNAL_NUMBER); + break; + } + } + LLVM_FALLTHROUGH; + case PTRACE_EVENT_FORK: + case PTRACE_EVENT_VFORK: { + bool is_vfork = event == PTRACE_EVENT_VFORK; + std::unique_ptr child_process{new NativeProcessAIX( + static_cast<::pid_t>(child_pid), m_terminal_fd, m_delegate, m_arch, + m_main_loop, {static_cast<::pid_t>(child_pid)})}; + if (!is_vfork) + child_process->m_software_breakpoints = m_software_breakpoints; + + Extension expected_ext = is_vfork ? Extension::vfork : Extension::fork; + if (bool(m_enabled_extensions & expected_ext)) { + m_delegate.NewSubprocess(this, std::move(child_process)); + // NB: non-vfork clone() is reported as fork + parent.SetStoppedByFork(is_vfork, child_pid); + StopRunningThreads(parent.GetID()); + } else { + child_process->Detach(); + ResumeThread(parent, parent.GetState(), LLDB_INVALID_SIGNAL_NUMBER); + } + break; + } +#endif + default: + llvm_unreachable("unknown clone_info.event"); + } + + return true; +} + +bool NativeProcessAIX::SupportHardwareSingleStepping() const { + return false; +} + +Status NativeProcessAIX::Resume(const ResumeActionList &resume_actions) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "pid {0}", GetID()); + + bool software_single_step = !SupportHardwareSingleStepping(); + + if (software_single_step) { + for (const auto &thread : m_threads) { + assert(thread && "thread list should not contain NULL threads"); + + const ResumeAction *const action = + resume_actions.GetActionForThread(thread->GetID(), true); + if (action == nullptr) + continue; + + if (action->state == eStateStepping) { + Status error = SetupSoftwareSingleStepping( + static_cast(*thread)); + if (error.Fail()) + return error; + } + } + } + + for (const auto &thread : m_threads) { + assert(thread && "thread list should not contain NULL threads"); + + const ResumeAction *const action = + resume_actions.GetActionForThread(thread->GetID(), true); + + if (action == nullptr) { + LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(), + thread->GetID()); + continue; + } + + LLDB_LOG(log, "processing resume action state {0} for pid {1} tid {2}", + action->state, GetID(), thread->GetID()); + + switch (action->state) { + case eStateRunning: + case eStateStepping: { + // Run the thread, possibly feeding it the signal. + const int signo = action->signal; + Status error = ResumeThread(static_cast(*thread), + action->state, signo); + if (error.Fail()) + return Status("NativeProcessAIX::%s: failed to resume thread " + "for pid %" PRIu64 ", tid %" PRIu64 ", error = %s", + __FUNCTION__, GetID(), thread->GetID(), + error.AsCString()); + + break; + } + + case eStateSuspended: + case eStateStopped: + break; + + default: + return Status("NativeProcessAIX::%s (): unexpected state %s specified " + "for pid %" PRIu64 ", tid %" PRIu64, + __FUNCTION__, StateAsCString(action->state), GetID(), + thread->GetID()); + } + } + + return Status(); +} + +Status NativeProcessAIX::Halt() { + Status error; + + if (kill(GetID(), SIGSTOP) != 0) + error.SetErrorToErrno(); + + return error; +} + +Status NativeProcessAIX::Detach() { + Status error; + + // Tell ptrace to detach from the process. + if (GetID() == LLDB_INVALID_PROCESS_ID) + return error; + + // Cancel out any SIGSTOPs we may have sent while stopping the process. + // Otherwise, the process may stop as soon as we detach from it. + kill(GetID(), SIGCONT); + + for (const auto &thread : m_threads) { + Status e = Detach(thread->GetID()); + if (e.Fail()) + error = + e; // Save the error, but still attempt to detach from other threads. + } + + return error; +} + +Status NativeProcessAIX::Signal(int signo) { + Status error; + + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "sending signal {0} ({1}) to pid {1}", signo, + Host::GetSignalAsCString(signo), GetID()); + + if (kill(GetID(), signo)) + error.SetErrorToErrno(); + + return error; +} + +Status NativeProcessAIX::Interrupt() { + // Pick a running thread (or if none, a not-dead stopped thread) as the + // chosen thread that will be the stop-reason thread. + Log *log = GetLog(POSIXLog::Process); + + NativeThreadProtocol *running_thread = nullptr; + NativeThreadProtocol *stopped_thread = nullptr; + + LLDB_LOG(log, "selecting running thread for interrupt target"); + for (const auto &thread : m_threads) { + // If we have a running or stepping thread, we'll call that the target of + // the interrupt. + const auto thread_state = thread->GetState(); + if (thread_state == eStateRunning || thread_state == eStateStepping) { + running_thread = thread.get(); + break; + } else if (!stopped_thread && StateIsStoppedState(thread_state, true)) { + // Remember the first non-dead stopped thread. We'll use that as a + // backup if there are no running threads. + stopped_thread = thread.get(); + } + } + + if (!running_thread && !stopped_thread) { + Status error("found no running/stepping or live stopped threads as target " + "for interrupt"); + LLDB_LOG(log, "skipping due to error: {0}", error); + + return error; + } + + NativeThreadProtocol *deferred_signal_thread = + running_thread ? running_thread : stopped_thread; + + LLDB_LOG(log, "pid {0} {1} tid {2} chosen for interrupt target", GetID(), + running_thread ? "running" : "stopped", + deferred_signal_thread->GetID()); + + StopRunningThreads(deferred_signal_thread->GetID()); + + return Status(); +} + +Status NativeProcessAIX::Kill() { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "pid {0}", GetID()); + + Status error; + + switch (m_state) { + case StateType::eStateInvalid: + case StateType::eStateExited: + case StateType::eStateCrashed: + case StateType::eStateDetached: + case StateType::eStateUnloaded: + // Nothing to do - the process is already dead. + LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(), + m_state); + return error; + + case StateType::eStateConnected: + case StateType::eStateAttaching: + case StateType::eStateLaunching: + case StateType::eStateStopped: + case StateType::eStateRunning: + case StateType::eStateStepping: + case StateType::eStateSuspended: + // We can try to kill a process in these states. + break; + } + + if (kill(GetID(), SIGKILL) != 0) { + error.SetErrorToErrno(); + return error; + } + + return error; +} + +Status NativeProcessAIX::GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info) { + // FIXME review that the final memory region returned extends to the end of + // the virtual address space, + // with no perms if it is not mapped. + + // Use an approach that reads memory regions from /proc/{pid}/maps. Assume + // proc maps entries are in ascending order. + // FIXME assert if we find differently. + + if (m_supports_mem_region == LazyBool::eLazyBoolNo) { + // We're done. + return Status("unsupported"); + } + + Status error = PopulateMemoryRegionCache(); + if (error.Fail()) { + return error; + } + + lldb::addr_t prev_base_address = 0; + + // FIXME start by finding the last region that is <= target address using + // binary search. Data is sorted. + // There can be a ton of regions on pthreads apps with lots of threads. + for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end(); + ++it) { + MemoryRegionInfo &proc_entry_info = it->first; + + // Sanity check assumption that /proc/{pid}/maps entries are ascending. + assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) && + "descending /proc/pid/maps entries detected, unexpected"); + prev_base_address = proc_entry_info.GetRange().GetRangeBase(); + UNUSED_IF_ASSERT_DISABLED(prev_base_address); + + // If the target address comes before this entry, indicate distance to next + // region. + if (load_addr < proc_entry_info.GetRange().GetRangeBase()) { + range_info.GetRange().SetRangeBase(load_addr); + range_info.GetRange().SetByteSize( + proc_entry_info.GetRange().GetRangeBase() - load_addr); + range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); + + return error; + } else if (proc_entry_info.GetRange().Contains(load_addr)) { + // The target address is within the memory region we're processing here. + range_info = proc_entry_info; + return error; + } + + // The target memory address comes somewhere after the region we just + // parsed. + } + + // If we made it here, we didn't find an entry that contained the given + // address. Return the load_addr as start and the amount of bytes betwwen + // load address and the end of the memory as size. + range_info.GetRange().SetRangeBase(load_addr); + range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS); + range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); + return error; +} + +Status NativeProcessAIX::PopulateMemoryRegionCache() { + Log *log = GetLog(POSIXLog::Process); + + // If our cache is empty, pull the latest. There should always be at least + // one memory region if memory region handling is supported. + if (!m_mem_region_cache.empty()) { + LLDB_LOG(log, "reusing {0} cached memory region entries", + m_mem_region_cache.size()); + return Status(); + } + + Status Result; +#if 0 + AIXMapCallback callback = [&](llvm::Expected Info) { + if (Info) { + FileSpec file_spec(Info->GetName().GetCString()); + FileSystem::Instance().Resolve(file_spec); + m_mem_region_cache.emplace_back(*Info, file_spec); + return true; + } + + Result = Info.takeError(); + m_supports_mem_region = LazyBool::eLazyBoolNo; + LLDB_LOG(log, "failed to parse proc maps: {0}", Result); + return false; + }; + + // AIX kernel since 2.6.14 has /proc/{pid}/smaps + // if CONFIG_PROC_PAGE_MONITOR is enabled + auto BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "smaps"); + if (BufferOrError) + ParseAIXSMapRegions(BufferOrError.get()->getBuffer(), callback); + else { + BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "maps"); + if (!BufferOrError) { + m_supports_mem_region = LazyBool::eLazyBoolNo; + return BufferOrError.getError(); + } + + ParseAIXMapRegions(BufferOrError.get()->getBuffer(), callback); + } + + if (Result.Fail()) + return Result; + + if (m_mem_region_cache.empty()) { + // No entries after attempting to read them. This shouldn't happen if + // /proc/{pid}/maps is supported. Assume we don't support map entries via + // procfs. + m_supports_mem_region = LazyBool::eLazyBoolNo; + LLDB_LOG(log, + "failed to find any procfs maps entries, assuming no support " + "for memory region metadata retrieval"); + return Status("not supported"); + } + + LLDB_LOG(log, "read {0} memory region entries from /proc/{1}/maps", + m_mem_region_cache.size(), GetID()); + + // We support memory retrieval, remember that. + m_supports_mem_region = LazyBool::eLazyBoolYes; +#endif + return Status(); +} + +void NativeProcessAIX::DoStopIDBumped(uint32_t newBumpId) { + Log *log = GetLog(POSIXLog::Process); + LLDB_LOG(log, "newBumpId={0}", newBumpId); + LLDB_LOG(log, "clearing {0} entries from memory region cache", + m_mem_region_cache.size()); + m_mem_region_cache.clear(); +} + +llvm::Expected +NativeProcessAIX::Syscall(llvm::ArrayRef args) { + PopulateMemoryRegionCache(); + auto region_it = llvm::find_if(m_mem_region_cache, [](const auto &pair) { + return pair.first.GetExecutable() == MemoryRegionInfo::eYes && + pair.first.GetShared() != MemoryRegionInfo::eYes; + }); + if (region_it == m_mem_region_cache.end()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "No executable memory region found!"); + + addr_t exe_addr = region_it->first.GetRange().GetRangeBase(); + + NativeThreadAIX &thread = *GetCurrentThread(); + assert(thread.GetState() == eStateStopped); + NativeRegisterContextAIX ®_ctx = thread.GetRegisterContext(); + + NativeRegisterContextAIX::SyscallData syscall_data = + *reg_ctx.GetSyscallData(); + + WritableDataBufferSP registers_sp; + if (llvm::Error Err = reg_ctx.ReadAllRegisterValues(registers_sp).ToError()) + return std::move(Err); + auto restore_regs = llvm::make_scope_exit( + [&] { reg_ctx.WriteAllRegisterValues(registers_sp); }); + + llvm::SmallVector memory(syscall_data.Insn.size()); + size_t bytes_read; + if (llvm::Error Err = + ReadMemory(exe_addr, memory.data(), memory.size(), bytes_read) + .ToError()) { + return std::move(Err); + } + + auto restore_mem = llvm::make_scope_exit( + [&] { WriteMemory(exe_addr, memory.data(), memory.size(), bytes_read); }); + + if (llvm::Error Err = reg_ctx.SetPC(exe_addr).ToError()) + return std::move(Err); + + for (const auto &zip : llvm::zip_first(args, syscall_data.Args)) { + if (llvm::Error Err = + reg_ctx + .WriteRegisterFromUnsigned(std::get<1>(zip), std::get<0>(zip)) + .ToError()) { + return std::move(Err); + } + } + if (llvm::Error Err = WriteMemory(exe_addr, syscall_data.Insn.data(), + syscall_data.Insn.size(), bytes_read) + .ToError()) + return std::move(Err); + + m_mem_region_cache.clear(); + + // With software single stepping the syscall insn buffer must also include a + // trap instruction to stop the process. + int req = SupportHardwareSingleStepping() ? PTRACE_SINGLESTEP : PTRACE_CONT; + if (llvm::Error Err = + PtraceWrapper(req, thread.GetID(), nullptr, nullptr).ToError()) + return std::move(Err); + + //FIXME + int status; + ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, ::waitpid, thread.GetID(), + &status, P_ALL/*__WALL*/); + if (wait_pid == -1) { + return llvm::errorCodeToError( + std::error_code(errno, std::generic_category())); + } + assert((unsigned)wait_pid == thread.GetID()); + + uint64_t result = reg_ctx.ReadRegisterAsUnsigned(syscall_data.Result, -ESRCH); + + // Values larger than this are actually negative errno numbers. + uint64_t errno_threshold = + (uint64_t(-1) >> (64 - 8 * m_arch.GetAddressByteSize())) - 0x1000; + if (result > errno_threshold) { + return llvm::errorCodeToError( + std::error_code(-result & 0xfff, std::generic_category())); + } + + return result; +} + +llvm::Expected +NativeProcessAIX::AllocateMemory(size_t size, uint32_t permissions) { + + std::optional mmap_data = + GetCurrentThread()->GetRegisterContext().GetMmapData(); + if (!mmap_data) + return llvm::make_error(); + + unsigned prot = PROT_NONE; + assert((permissions & (ePermissionsReadable | ePermissionsWritable | + ePermissionsExecutable)) == permissions && + "Unknown permission!"); + if (permissions & ePermissionsReadable) + prot |= PROT_READ; + if (permissions & ePermissionsWritable) + prot |= PROT_WRITE; + if (permissions & ePermissionsExecutable) + prot |= PROT_EXEC; + + llvm::Expected Result = + Syscall({mmap_data->SysMmap, 0, size, prot, MAP_ANONYMOUS | MAP_PRIVATE, + uint64_t(-1), 0}); + if (Result) + m_allocated_memory.try_emplace(*Result, size); + return Result; +} + +llvm::Error NativeProcessAIX::DeallocateMemory(lldb::addr_t addr) { + std::optional mmap_data = + GetCurrentThread()->GetRegisterContext().GetMmapData(); + if (!mmap_data) + return llvm::make_error(); + + auto it = m_allocated_memory.find(addr); + if (it == m_allocated_memory.end()) + return llvm::createStringError(llvm::errc::invalid_argument, + "Memory not allocated by the debugger."); + + llvm::Expected Result = + Syscall({mmap_data->SysMunmap, addr, it->second}); + if (!Result) + return Result.takeError(); + + m_allocated_memory.erase(it); + return llvm::Error::success(); +} + +Status NativeProcessAIX::ReadMemoryTags(int32_t type, lldb::addr_t addr, + size_t len, + std::vector &tags) { + llvm::Expected details = + GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); + if (!details) + return Status(details.takeError()); + + // Ignore 0 length read + if (!len) + return Status(); + + // lldb will align the range it requests but it is not required to by + // the protocol so we'll do it again just in case. + // Remove tag bits too. Ptrace calls may work regardless but that + // is not a guarantee. + MemoryTagManager::TagRange range(details->manager->RemoveTagBits(addr), len); + range = details->manager->ExpandToGranule(range); + + // Allocate enough space for all tags to be read + size_t num_tags = range.GetByteSize() / details->manager->GetGranuleSize(); + tags.resize(num_tags * details->manager->GetTagSizeInBytes()); + + struct iovec tags_iovec; + uint8_t *dest = tags.data(); + lldb::addr_t read_addr = range.GetRangeBase(); + + // This call can return partial data so loop until we error or + // get all tags back. + while (num_tags) { + tags_iovec.iov_base = dest; + tags_iovec.iov_len = num_tags; + + Status error = NativeProcessAIX::PtraceWrapper( + details->ptrace_read_req, GetCurrentThreadID(), + reinterpret_cast(read_addr), static_cast(&tags_iovec), + 0, nullptr); + + if (error.Fail()) { + // Discard partial reads + tags.resize(0); + return error; + } + + size_t tags_read = tags_iovec.iov_len; + assert(tags_read && (tags_read <= num_tags)); + + dest += tags_read * details->manager->GetTagSizeInBytes(); + read_addr += details->manager->GetGranuleSize() * tags_read; + num_tags -= tags_read; + } + + return Status(); +} + +Status NativeProcessAIX::WriteMemoryTags(int32_t type, lldb::addr_t addr, + size_t len, + const std::vector &tags) { + llvm::Expected details = + GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); + if (!details) + return Status(details.takeError()); + + // Ignore 0 length write + if (!len) + return Status(); + + // lldb will align the range it requests but it is not required to by + // the protocol so we'll do it again just in case. + // Remove tag bits too. Ptrace calls may work regardless but that + // is not a guarantee. + MemoryTagManager::TagRange range(details->manager->RemoveTagBits(addr), len); + range = details->manager->ExpandToGranule(range); + + // Not checking number of tags here, we may repeat them below + llvm::Expected> unpacked_tags_or_err = + details->manager->UnpackTagsData(tags); + if (!unpacked_tags_or_err) + return Status(unpacked_tags_or_err.takeError()); + + llvm::Expected> repeated_tags_or_err = + details->manager->RepeatTagsForRange(*unpacked_tags_or_err, range); + if (!repeated_tags_or_err) + return Status(repeated_tags_or_err.takeError()); + + // Repack them for ptrace to use + llvm::Expected> final_tag_data = + details->manager->PackTags(*repeated_tags_or_err); + if (!final_tag_data) + return Status(final_tag_data.takeError()); + + struct iovec tags_vec; + uint8_t *src = final_tag_data->data(); + lldb::addr_t write_addr = range.GetRangeBase(); + // unpacked tags size because the number of bytes per tag might not be 1 + size_t num_tags = repeated_tags_or_err->size(); + + // This call can partially write tags, so we loop until we + // error or all tags have been written. + while (num_tags > 0) { + tags_vec.iov_base = src; + tags_vec.iov_len = num_tags; + + Status error = NativeProcessAIX::PtraceWrapper( + details->ptrace_write_req, GetCurrentThreadID(), + reinterpret_cast(write_addr), static_cast(&tags_vec), 0, + nullptr); + + if (error.Fail()) { + // Don't attempt to restore the original values in the case of a partial + // write + return error; + } + + size_t tags_written = tags_vec.iov_len; + assert(tags_written && (tags_written <= num_tags)); + + src += tags_written * details->manager->GetTagSizeInBytes(); + write_addr += details->manager->GetGranuleSize() * tags_written; + num_tags -= tags_written; + } + + return Status(); +} + +size_t NativeProcessAIX::UpdateThreads() { + // The NativeProcessAIX monitoring threads are always up to date with + // respect to thread state and they keep the thread list populated properly. + // All this method needs to do is return the thread count. + return m_threads.size(); +} + +Status NativeProcessAIX::SetBreakpoint(lldb::addr_t addr, uint32_t size, + bool hardware) { + if (hardware) + return SetHardwareBreakpoint(addr, size); + else + return SetSoftwareBreakpoint(addr, size); +} + +Status NativeProcessAIX::RemoveBreakpoint(lldb::addr_t addr, bool hardware) { + if (hardware) + return RemoveHardwareBreakpoint(addr); + else + return NativeProcessProtocol::RemoveBreakpoint(addr); +} + +llvm::Expected> +NativeProcessAIX::GetSoftwareBreakpointTrapOpcode(size_t size_hint) { + // The ARM reference recommends the use of 0xe7fddefe and 0xdefe but the + // linux kernel does otherwise. + static const uint8_t g_arm_opcode[] = {0xf0, 0x01, 0xf0, 0xe7}; + static const uint8_t g_thumb_opcode[] = {0x01, 0xde}; + + switch (GetArchitecture().GetMachine()) { + case llvm::Triple::arm: + switch (size_hint) { + case 2: + return llvm::ArrayRef(g_thumb_opcode); + case 4: + return llvm::ArrayRef(g_arm_opcode); + default: + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Unrecognised trap opcode size hint!"); + } + default: + return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint); + } +} + +Status NativeProcessAIX::ReadMemory(lldb::addr_t addr, void *buf, size_t size, + size_t &bytes_read) { + unsigned char *dst = static_cast(buf); + size_t remainder; + long data; + + Log *log = GetLog(POSIXLog::Memory); + LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); + + for (bytes_read = 0; bytes_read < size; bytes_read += remainder) { + Status error = NativeProcessAIX::PtraceWrapper( + PT_READ_BLOCK, GetCurrentThreadID(), (void *)addr, nullptr, sizeof(data), &data); + if (error.Fail()) + return error; + + remainder = size - bytes_read; + remainder = remainder > k_ptrace_word_size ? k_ptrace_word_size : remainder; + + // Copy the data into our buffer + memcpy(dst, &data, remainder); + + LLDB_LOG(log, "[{0:x}]:{1:x}", addr, data); + addr += k_ptrace_word_size; + dst += k_ptrace_word_size; + } + return Status(); +} + +Status NativeProcessAIX::WriteMemory(lldb::addr_t addr, const void *buf, + size_t size, size_t &bytes_written) { + const unsigned char *src = static_cast(buf); + size_t remainder; + Status error; + + Log *log = GetLog(POSIXLog::Memory); + LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); + + error = NativeProcessAIX::PtraceWrapper( + PT_WRITE_BLOCK, GetCurrentThreadID(), (void *)addr, nullptr, (int)size, (long *)buf); + if (error.Fail()) + return error; + + bytes_written = size; + return error; +} + +int8_t NativeProcessAIX::GetSignalInfo(WaitStatus wstatus) const { + return wstatus.status; +} + +Status NativeProcessAIX::GetEventMessage(lldb::tid_t tid, + unsigned long *message) { + //FIXME + return PtraceWrapper(PT_CLEAR/*PTRACE_GETEVENTMSG*/, tid, nullptr, message); +} + +Status NativeProcessAIX::Detach(lldb::tid_t tid) { + if (tid == LLDB_INVALID_THREAD_ID) + return Status(); + + return PtraceWrapper(PT_DETACH, tid); +} + +bool NativeProcessAIX::HasThreadNoLock(lldb::tid_t thread_id) { + for (const auto &thread : m_threads) { + assert(thread && "thread list should not contain NULL threads"); + if (thread->GetID() == thread_id) { + // We have this thread. + return true; + } + } + + // We don't have this thread. + return false; +} + +void NativeProcessAIX::StopTrackingThread(NativeThreadAIX &thread) { + Log *const log = GetLog(POSIXLog::Thread); + lldb::tid_t thread_id = thread.GetID(); + LLDB_LOG(log, "tid: {0}", thread_id); + + auto it = llvm::find_if(m_threads, [&](const auto &thread_up) { + return thread_up.get() == &thread; + }); + assert(it != m_threads.end()); + m_threads.erase(it); + + NotifyTracersOfThreadDestroyed(thread_id); + SignalIfAllThreadsStopped(); +} + +void NativeProcessAIX::NotifyTracersProcessDidStop() { +} + +void NativeProcessAIX::NotifyTracersProcessWillResume() { +} + +Status NativeProcessAIX::NotifyTracersOfNewThread(lldb::tid_t tid) { + Log *log = GetLog(POSIXLog::Thread); + Status error; + return error; +} + +Status NativeProcessAIX::NotifyTracersOfThreadDestroyed(lldb::tid_t tid) { + Log *log = GetLog(POSIXLog::Thread); + Status error; + return error; +} + +NativeThreadAIX &NativeProcessAIX::AddThread(lldb::tid_t thread_id, + bool resume) { + Log *log = GetLog(POSIXLog::Thread); + LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id); + + assert(!HasThreadNoLock(thread_id) && + "attempted to add a thread by id that already exists"); + + // If this is the first thread, save it as the current thread + if (m_threads.empty()) + SetCurrentThreadID(thread_id); + + m_threads.push_back(std::make_unique(*this, thread_id)); + NativeThreadAIX &thread = + static_cast(*m_threads.back()); + + Status tracing_error = NotifyTracersOfNewThread(thread.GetID()); + if (tracing_error.Fail()) { + thread.SetStoppedByProcessorTrace(tracing_error.AsCString()); + StopRunningThreads(thread.GetID()); + } else if (resume) + ResumeThread(thread, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); + else + thread.SetStoppedBySignal(SIGSTOP); + + return thread; +} + +Status NativeProcessAIX::GetLoadedModuleFileSpec(const char *module_path, + FileSpec &file_spec) { + Status error = PopulateMemoryRegionCache(); + if (error.Fail()) + return error; + + FileSpec module_file_spec(module_path); + FileSystem::Instance().Resolve(module_file_spec); + + file_spec.Clear(); + for (const auto &it : m_mem_region_cache) { + if (it.second.GetFilename() == module_file_spec.GetFilename()) { + file_spec = it.second; + return Status(); + } + } + return Status("Module file (%s) not found in /proc/%" PRIu64 "/maps file!", + module_file_spec.GetFilename().AsCString(), GetID()); +} + +Status NativeProcessAIX::GetFileLoadAddress(const llvm::StringRef &file_name, + lldb::addr_t &load_addr) { + load_addr = LLDB_INVALID_ADDRESS; + + NativeThreadAIX &thread = *GetCurrentThread(); + NativeRegisterContextAIX ®_ctx = thread.GetRegisterContext(); + + // FIXME: buffer size + struct ld_xinfo info[64]; + if (ptrace64(PT_LDXINFO, reg_ctx.GetThread().GetID(), (long long)&(info[0]), sizeof(info), nullptr) == 0) { + load_addr = (unsigned long)info[0].ldinfo_textorg; + return Status(); + } + return Status("No load address found for specified file."); +} + +NativeThreadAIX *NativeProcessAIX::GetThreadByID(lldb::tid_t tid) { + return static_cast( + NativeProcessProtocol::GetThreadByID(tid)); +} + +NativeThreadAIX *NativeProcessAIX::GetCurrentThread() { + return static_cast( + NativeProcessProtocol::GetCurrentThread()); +} + +Status NativeProcessAIX::ResumeThread(NativeThreadAIX &thread, + lldb::StateType state, int signo) { + Log *const log = GetLog(POSIXLog::Thread); + LLDB_LOG(log, "tid: {0}", thread.GetID()); + + // Before we do the resume below, first check if we have a pending stop + // notification that is currently waiting for all threads to stop. This is + // potentially a buggy situation since we're ostensibly waiting for threads + // to stop before we send out the pending notification, and here we are + // resuming one before we send out the pending stop notification. + if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID) { + LLDB_LOG(log, + "about to resume tid {0} per explicit request but we have a " + "pending stop notification (tid {1}) that is actively " + "waiting for this thread to stop. Valid sequence of events?", + thread.GetID(), m_pending_notification_tid); + } + + // Request a resume. We expect this to be synchronous and the system to + // reflect it is running after this completes. + switch (state) { + case eStateRunning: { + const auto resume_result = thread.Resume(signo); + if (resume_result.Success()) + SetState(eStateRunning, true); + return resume_result; + } + case eStateStepping: { + const auto step_result = thread.SingleStep(signo); + if (step_result.Success()) + SetState(eStateRunning, true); + return step_result; + } + default: + LLDB_LOG(log, "Unhandled state {0}.", state); + llvm_unreachable("Unhandled state for resume"); + } +} + +//===----------------------------------------------------------------------===// + +void NativeProcessAIX::StopRunningThreads(const lldb::tid_t triggering_tid) { + Log *const log = GetLog(POSIXLog::Thread); + LLDB_LOG(log, "about to process event: (triggering_tid: {0})", + triggering_tid); + + m_pending_notification_tid = triggering_tid; + + // Request a stop for all the thread stops that need to be stopped and are + // not already known to be stopped. + for (const auto &thread : m_threads) { + if (StateIsRunningState(thread->GetState())) + static_cast(thread.get())->RequestStop(); + } + + SignalIfAllThreadsStopped(); + LLDB_LOG(log, "event processing done"); +} + +void NativeProcessAIX::SignalIfAllThreadsStopped() { + if (m_pending_notification_tid == LLDB_INVALID_THREAD_ID) + return; // No pending notification. Nothing to do. + + for (const auto &thread_sp : m_threads) { + if (StateIsRunningState(thread_sp->GetState())) + return; // Some threads are still running. Don't signal yet. + } + + // We have a pending notification and all threads have stopped. + Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints); + + // Clear any temporary breakpoints we used to implement software single + // stepping. + for (const auto &thread_info : m_threads_stepping_with_breakpoint) { + Status error = RemoveBreakpoint(thread_info.second); + if (error.Fail()) + LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}", + thread_info.first, error); + } + m_threads_stepping_with_breakpoint.clear(); + + // Notify the delegate about the stop + SetCurrentThreadID(m_pending_notification_tid); + SetState(StateType::eStateStopped, true); + m_pending_notification_tid = LLDB_INVALID_THREAD_ID; +} + +void NativeProcessAIX::ThreadWasCreated(NativeThreadAIX &thread) { + Log *const log = GetLog(POSIXLog::Thread); + LLDB_LOG(log, "tid: {0}", thread.GetID()); + + if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID && + StateIsRunningState(thread.GetState())) { + // We will need to wait for this new thread to stop as well before firing + // the notification. + thread.RequestStop(); + } +} + +#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT +#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h" +#undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT + +static void GetRegister(lldb::pid_t pid, long long addr, void *buf) { + uint64_t val = 0; + ptrace64(PT_READ_GPR, pid, addr, 0, (int *)&val); + *(uint64_t *)buf = llvm::byteswap(val); +} + +static void SetRegister(lldb::pid_t pid, long long addr, void *buf) { + uint64_t val = llvm::byteswap(*(uint64_t *)buf); + ptrace64(PT_WRITE_GPR, pid, addr, 0, (int *)&val); +} + +static void GetFPRegister(lldb::pid_t pid, long long addr, void *buf) { + uint64_t val = 0; + ptrace64(PT_READ_FPR, pid, addr, 0, (int *)&val); + *(uint64_t *)buf = llvm::byteswap(val); +} + +static void GetVMRegister(lldb::tid_t tid, long long addr, void *buf) { + uint64_t val = 0; + ptrace64(PTT_READ_VEC, tid, addr, 0, (int *)&val); + //*(uint64_t *)buf = llvm::byteswap(val); +} + +static void GetVSRegister(lldb::tid_t tid, long long addr, void *buf) { + uint64_t val = 0; + ptrace64(PTT_READ_VSX, tid, addr, 0, (int *)&val); + //*(uint64_t *)buf = llvm::byteswap(val); +} + +// Wrapper for ptrace to catch errors and log calls. Note that ptrace sets +// errno on error because -1 can be a valid result (i.e. for PTRACE_PEEK*) +Status NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid, void *addr, + void *data, size_t data_size, + long *result) { + Status error; + long int ret; + + Log *log = GetLog(POSIXLog::Ptrace); + + PtraceDisplayBytes(req, data, data_size); + + errno = 0; + + // for PTT_* + const char procdir[] = "/proc/"; + const char lwpdir[] = "/lwp/"; + std::string process_task_dir = procdir + std::to_string(pid) + lwpdir; + DIR *dirproc = opendir(process_task_dir.c_str()); + + lldb::tid_t tid = 0; + if (dirproc) { + struct dirent *direntry = nullptr; + while ((direntry = readdir(dirproc)) != nullptr) { + if (strcmp(direntry->d_name, ".") == 0 || strcmp(direntry->d_name, "..") == 0) { + continue; + } + tid = atoi(direntry->d_name); + break; + } + closedir(dirproc); + } + + if (req == PTRACE_GETREGS) { + GetRegister(pid, GPR0, &(((GPR *)data)->r0)); + GetRegister(pid, GPR1, &(((GPR *)data)->r1)); + GetRegister(pid, GPR2, &(((GPR *)data)->r2)); + GetRegister(pid, GPR3, &(((GPR *)data)->r3)); + GetRegister(pid, GPR4, &(((GPR *)data)->r4)); + GetRegister(pid, GPR5, &(((GPR *)data)->r5)); + GetRegister(pid, GPR6, &(((GPR *)data)->r6)); + GetRegister(pid, GPR7, &(((GPR *)data)->r7)); + GetRegister(pid, GPR8, &(((GPR *)data)->r8)); + GetRegister(pid, GPR9, &(((GPR *)data)->r9)); + GetRegister(pid, GPR10, &(((GPR *)data)->r10)); + GetRegister(pid, GPR11, &(((GPR *)data)->r11)); + GetRegister(pid, GPR12, &(((GPR *)data)->r12)); + GetRegister(pid, GPR13, &(((GPR *)data)->r13)); + GetRegister(pid, GPR14, &(((GPR *)data)->r14)); + GetRegister(pid, GPR15, &(((GPR *)data)->r15)); + GetRegister(pid, GPR16, &(((GPR *)data)->r16)); + GetRegister(pid, GPR17, &(((GPR *)data)->r17)); + GetRegister(pid, GPR18, &(((GPR *)data)->r18)); + GetRegister(pid, GPR19, &(((GPR *)data)->r19)); + GetRegister(pid, GPR20, &(((GPR *)data)->r20)); + GetRegister(pid, GPR21, &(((GPR *)data)->r21)); + GetRegister(pid, GPR22, &(((GPR *)data)->r22)); + GetRegister(pid, GPR23, &(((GPR *)data)->r23)); + GetRegister(pid, GPR24, &(((GPR *)data)->r24)); + GetRegister(pid, GPR25, &(((GPR *)data)->r25)); + GetRegister(pid, GPR26, &(((GPR *)data)->r26)); + GetRegister(pid, GPR27, &(((GPR *)data)->r27)); + GetRegister(pid, GPR28, &(((GPR *)data)->r28)); + GetRegister(pid, GPR29, &(((GPR *)data)->r29)); + GetRegister(pid, GPR30, &(((GPR *)data)->r30)); + GetRegister(pid, GPR31, &(((GPR *)data)->r31)); + GetRegister(pid, IAR, &(((GPR *)data)->pc)); + GetRegister(pid, MSR, &(((GPR *)data)->msr)); + //FIXME: origr3/softe/trap on AIX? + GetRegister(pid, CTR, &(((GPR *)data)->ctr)); + GetRegister(pid, LR, &(((GPR *)data)->lr)); + GetRegister(pid, XER, &(((GPR *)data)->xer)); + GetRegister(pid, CR, &(((GPR *)data)->cr)); + } else if (req == PTRACE_SETREGS) { + SetRegister(pid, GPR0, &(((GPR *)data)->r0)); + SetRegister(pid, GPR1, &(((GPR *)data)->r1)); + SetRegister(pid, GPR2, &(((GPR *)data)->r2)); + SetRegister(pid, GPR3, &(((GPR *)data)->r3)); + SetRegister(pid, GPR4, &(((GPR *)data)->r4)); + SetRegister(pid, GPR5, &(((GPR *)data)->r5)); + SetRegister(pid, GPR6, &(((GPR *)data)->r6)); + SetRegister(pid, GPR7, &(((GPR *)data)->r7)); + SetRegister(pid, GPR8, &(((GPR *)data)->r8)); + SetRegister(pid, GPR9, &(((GPR *)data)->r9)); + SetRegister(pid, GPR10, &(((GPR *)data)->r10)); + SetRegister(pid, GPR11, &(((GPR *)data)->r11)); + SetRegister(pid, GPR12, &(((GPR *)data)->r12)); + SetRegister(pid, GPR13, &(((GPR *)data)->r13)); + SetRegister(pid, GPR14, &(((GPR *)data)->r14)); + SetRegister(pid, GPR15, &(((GPR *)data)->r15)); + SetRegister(pid, GPR16, &(((GPR *)data)->r16)); + SetRegister(pid, GPR17, &(((GPR *)data)->r17)); + SetRegister(pid, GPR18, &(((GPR *)data)->r18)); + SetRegister(pid, GPR19, &(((GPR *)data)->r19)); + SetRegister(pid, GPR20, &(((GPR *)data)->r20)); + SetRegister(pid, GPR21, &(((GPR *)data)->r21)); + SetRegister(pid, GPR22, &(((GPR *)data)->r22)); + SetRegister(pid, GPR23, &(((GPR *)data)->r23)); + SetRegister(pid, GPR24, &(((GPR *)data)->r24)); + SetRegister(pid, GPR25, &(((GPR *)data)->r25)); + SetRegister(pid, GPR26, &(((GPR *)data)->r26)); + SetRegister(pid, GPR27, &(((GPR *)data)->r27)); + SetRegister(pid, GPR28, &(((GPR *)data)->r28)); + SetRegister(pid, GPR29, &(((GPR *)data)->r29)); + SetRegister(pid, GPR30, &(((GPR *)data)->r30)); + SetRegister(pid, GPR31, &(((GPR *)data)->r31)); + SetRegister(pid, IAR, &(((GPR *)data)->pc)); + SetRegister(pid, MSR, &(((GPR *)data)->msr)); + //FIXME: origr3/softe/trap on AIX? + SetRegister(pid, CTR, &(((GPR *)data)->ctr)); + SetRegister(pid, LR, &(((GPR *)data)->lr)); + SetRegister(pid, XER, &(((GPR *)data)->xer)); + SetRegister(pid, CR, &(((GPR *)data)->cr)); + } else if (req == PTRACE_GETFPREGS) { + GetFPRegister(pid, FPR0, &(((FPR *)data)->f0)); + GetFPRegister(pid, FPR1, &(((FPR *)data)->f1)); + GetFPRegister(pid, FPR2, &(((FPR *)data)->f2)); + GetFPRegister(pid, FPR3, &(((FPR *)data)->f3)); + GetFPRegister(pid, FPR4, &(((FPR *)data)->f4)); + GetFPRegister(pid, FPR5, &(((FPR *)data)->f5)); + GetFPRegister(pid, FPR6, &(((FPR *)data)->f6)); + GetFPRegister(pid, FPR7, &(((FPR *)data)->f7)); + GetFPRegister(pid, FPR8, &(((FPR *)data)->f8)); + GetFPRegister(pid, FPR9, &(((FPR *)data)->f9)); + GetFPRegister(pid, FPR10, &(((FPR *)data)->f10)); + GetFPRegister(pid, FPR11, &(((FPR *)data)->f11)); + GetFPRegister(pid, FPR12, &(((FPR *)data)->f12)); + GetFPRegister(pid, FPR13, &(((FPR *)data)->f13)); + GetFPRegister(pid, FPR14, &(((FPR *)data)->f14)); + GetFPRegister(pid, FPR15, &(((FPR *)data)->f15)); + GetFPRegister(pid, FPR16, &(((FPR *)data)->f16)); + GetFPRegister(pid, FPR17, &(((FPR *)data)->f17)); + GetFPRegister(pid, FPR18, &(((FPR *)data)->f18)); + GetFPRegister(pid, FPR19, &(((FPR *)data)->f19)); + GetFPRegister(pid, FPR20, &(((FPR *)data)->f20)); + GetFPRegister(pid, FPR21, &(((FPR *)data)->f21)); + GetFPRegister(pid, FPR22, &(((FPR *)data)->f22)); + GetFPRegister(pid, FPR23, &(((FPR *)data)->f23)); + GetFPRegister(pid, FPR24, &(((FPR *)data)->f24)); + GetFPRegister(pid, FPR25, &(((FPR *)data)->f25)); + GetFPRegister(pid, FPR26, &(((FPR *)data)->f26)); + GetFPRegister(pid, FPR27, &(((FPR *)data)->f27)); + GetFPRegister(pid, FPR28, &(((FPR *)data)->f28)); + GetFPRegister(pid, FPR29, &(((FPR *)data)->f29)); + GetFPRegister(pid, FPR30, &(((FPR *)data)->f30)); + GetFPRegister(pid, FPR31, &(((FPR *)data)->f31)); + GetFPRegister(pid, FPSCR, &(((FPR *)data)->fpscr)); + } else if (req == PTRACE_GETVRREGS && tid) { + GetVMRegister(tid, VR0, &(((VMX *)data)->vr0[0])); + GetVMRegister(tid, VR1, &(((VMX *)data)->vr1[0])); + GetVMRegister(tid, VR2, &(((VMX *)data)->vr2[0])); + GetVMRegister(tid, VR3, &(((VMX *)data)->vr3[0])); + GetVMRegister(tid, VR4, &(((VMX *)data)->vr4[0])); + GetVMRegister(tid, VR5, &(((VMX *)data)->vr5[0])); + GetVMRegister(tid, VR6, &(((VMX *)data)->vr6[0])); + GetVMRegister(tid, VR7, &(((VMX *)data)->vr7[0])); + GetVMRegister(tid, VR8, &(((VMX *)data)->vr8[0])); + GetVMRegister(tid, VR9, &(((VMX *)data)->vr9[0])); + GetVMRegister(tid, VR10, &(((VMX *)data)->vr10[0])); + GetVMRegister(tid, VR11, &(((VMX *)data)->vr11[0])); + GetVMRegister(tid, VR12, &(((VMX *)data)->vr12[0])); + GetVMRegister(tid, VR13, &(((VMX *)data)->vr13[0])); + GetVMRegister(tid, VR14, &(((VMX *)data)->vr14[0])); + GetVMRegister(tid, VR15, &(((VMX *)data)->vr15[0])); + GetVMRegister(tid, VR16, &(((VMX *)data)->vr16[0])); + GetVMRegister(tid, VR17, &(((VMX *)data)->vr17[0])); + GetVMRegister(tid, VR18, &(((VMX *)data)->vr18[0])); + GetVMRegister(tid, VR19, &(((VMX *)data)->vr19[0])); + GetVMRegister(tid, VR20, &(((VMX *)data)->vr20[0])); + GetVMRegister(tid, VR21, &(((VMX *)data)->vr21[0])); + GetVMRegister(tid, VR22, &(((VMX *)data)->vr22[0])); + GetVMRegister(tid, VR23, &(((VMX *)data)->vr23[0])); + GetVMRegister(tid, VR24, &(((VMX *)data)->vr24[0])); + GetVMRegister(tid, VR25, &(((VMX *)data)->vr25[0])); + GetVMRegister(tid, VR26, &(((VMX *)data)->vr26[0])); + GetVMRegister(tid, VR27, &(((VMX *)data)->vr27[0])); + GetVMRegister(tid, VR28, &(((VMX *)data)->vr28[0])); + GetVMRegister(tid, VR29, &(((VMX *)data)->vr29[0])); + GetVMRegister(tid, VR30, &(((VMX *)data)->vr30[0])); + GetVMRegister(tid, VR31, &(((VMX *)data)->vr31[0])); + GetVMRegister(tid, VSCR, &(((VMX *)data)->vscr[0])); + GetVMRegister(tid, VRSAVE, &(((VMX *)data)->vrsave)); + } else if (req == PTRACE_GETVSRREGS && tid) { + GetVSRegister(tid, VSR0, &(((VSX *)data)->vs0[0])); + GetVSRegister(tid, VSR1, &(((VSX *)data)->vs1[0])); + GetVSRegister(tid, VSR2, &(((VSX *)data)->vs2[0])); + GetVSRegister(tid, VSR3, &(((VSX *)data)->vs3[0])); + GetVSRegister(tid, VSR4, &(((VSX *)data)->vs4[0])); + GetVSRegister(tid, VSR5, &(((VSX *)data)->vs5[0])); + GetVSRegister(tid, VSR6, &(((VSX *)data)->vs6[0])); + GetVSRegister(tid, VSR7, &(((VSX *)data)->vs7[0])); + GetVSRegister(tid, VSR8, &(((VSX *)data)->vs8[0])); + GetVSRegister(tid, VSR9, &(((VSX *)data)->vs9[0])); + GetVSRegister(tid, VSR10, &(((VSX *)data)->vs10[0])); + GetVSRegister(tid, VSR11, &(((VSX *)data)->vs11[0])); + GetVSRegister(tid, VSR12, &(((VSX *)data)->vs12[0])); + GetVSRegister(tid, VSR13, &(((VSX *)data)->vs13[0])); + GetVSRegister(tid, VSR14, &(((VSX *)data)->vs14[0])); + GetVSRegister(tid, VSR15, &(((VSX *)data)->vs15[0])); + GetVSRegister(tid, VSR16, &(((VSX *)data)->vs16[0])); + GetVSRegister(tid, VSR17, &(((VSX *)data)->vs17[0])); + GetVSRegister(tid, VSR18, &(((VSX *)data)->vs18[0])); + GetVSRegister(tid, VSR19, &(((VSX *)data)->vs19[0])); + GetVSRegister(tid, VSR20, &(((VSX *)data)->vs20[0])); + GetVSRegister(tid, VSR21, &(((VSX *)data)->vs21[0])); + GetVSRegister(tid, VSR22, &(((VSX *)data)->vs22[0])); + GetVSRegister(tid, VSR23, &(((VSX *)data)->vs23[0])); + GetVSRegister(tid, VSR24, &(((VSX *)data)->vs24[0])); + GetVSRegister(tid, VSR25, &(((VSX *)data)->vs25[0])); + GetVSRegister(tid, VSR26, &(((VSX *)data)->vs26[0])); + GetVSRegister(tid, VSR27, &(((VSX *)data)->vs27[0])); + GetVSRegister(tid, VSR28, &(((VSX *)data)->vs28[0])); + GetVSRegister(tid, VSR29, &(((VSX *)data)->vs29[0])); + GetVSRegister(tid, VSR30, &(((VSX *)data)->vs30[0])); + GetVSRegister(tid, VSR31, &(((VSX *)data)->vs31[0])); + GetVSRegister(tid, VSR32, &(((VSX *)data)->vs32[0])); + GetVSRegister(tid, VSR33, &(((VSX *)data)->vs33[0])); + GetVSRegister(tid, VSR34, &(((VSX *)data)->vs34[0])); + GetVSRegister(tid, VSR35, &(((VSX *)data)->vs35[0])); + GetVSRegister(tid, VSR36, &(((VSX *)data)->vs36[0])); + GetVSRegister(tid, VSR37, &(((VSX *)data)->vs37[0])); + GetVSRegister(tid, VSR38, &(((VSX *)data)->vs38[0])); + GetVSRegister(tid, VSR39, &(((VSX *)data)->vs39[0])); + GetVSRegister(tid, VSR40, &(((VSX *)data)->vs40[0])); + GetVSRegister(tid, VSR41, &(((VSX *)data)->vs41[0])); + GetVSRegister(tid, VSR42, &(((VSX *)data)->vs42[0])); + GetVSRegister(tid, VSR43, &(((VSX *)data)->vs43[0])); + GetVSRegister(tid, VSR44, &(((VSX *)data)->vs44[0])); + GetVSRegister(tid, VSR45, &(((VSX *)data)->vs45[0])); + GetVSRegister(tid, VSR46, &(((VSX *)data)->vs46[0])); + GetVSRegister(tid, VSR47, &(((VSX *)data)->vs47[0])); + GetVSRegister(tid, VSR48, &(((VSX *)data)->vs48[0])); + GetVSRegister(tid, VSR49, &(((VSX *)data)->vs49[0])); + GetVSRegister(tid, VSR50, &(((VSX *)data)->vs50[0])); + GetVSRegister(tid, VSR51, &(((VSX *)data)->vs51[0])); + GetVSRegister(tid, VSR52, &(((VSX *)data)->vs52[0])); + GetVSRegister(tid, VSR53, &(((VSX *)data)->vs53[0])); + GetVSRegister(tid, VSR54, &(((VSX *)data)->vs54[0])); + GetVSRegister(tid, VSR55, &(((VSX *)data)->vs55[0])); + GetVSRegister(tid, VSR56, &(((VSX *)data)->vs56[0])); + GetVSRegister(tid, VSR57, &(((VSX *)data)->vs57[0])); + GetVSRegister(tid, VSR58, &(((VSX *)data)->vs58[0])); + GetVSRegister(tid, VSR59, &(((VSX *)data)->vs59[0])); + GetVSRegister(tid, VSR60, &(((VSX *)data)->vs60[0])); + GetVSRegister(tid, VSR61, &(((VSX *)data)->vs61[0])); + GetVSRegister(tid, VSR62, &(((VSX *)data)->vs62[0])); + GetVSRegister(tid, VSR63, &(((VSX *)data)->vs63[0])); + } else if (req < PT_COMMAND_MAX) { + if (req == PT_CONTINUE) { +#if 0 + // Use PTT_CONTINUE + const char procdir[] = "/proc/"; + const char lwpdir[] = "/lwp/"; + std::string process_task_dir = procdir + std::to_string(pid) + lwpdir; + DIR *dirproc = opendir(process_task_dir.c_str()); + + struct ptthreads64 pts; + int idx = 0; + lldb::tid_t tid = 0; + if (dirproc) { + struct dirent *direntry = nullptr; + while ((direntry = readdir(dirproc)) != nullptr) { + if (strcmp(direntry->d_name, ".") == 0 || strcmp(direntry->d_name, "..") == 0) { + continue; + } + tid = atoi(direntry->d_name); + pts.th[idx++] = tid; + } + closedir(dirproc); + } + pts.th[idx] = 0; + ret = ptrace64(PTT_CONTINUE, tid, (long long)1, (int)(size_t)data, (int *)&pts); +#else + int buf; + ptrace64(req, pid, 1, (int)(size_t)data, &buf); +#endif + } else if (req == PT_READ_BLOCK) { + ptrace64(req, pid, (long long)addr, (int)data_size, (int *)result); + } else if (req == PT_WRITE_BLOCK) { + ptrace64(req, pid, (long long)addr, (int)data_size, (int *)result); + } else if (req == PT_ATTACH) { + ptrace64(req, pid, 0, 0, nullptr); + } else if (req == PT_WATCH) { + ptrace64(req, pid, (long long)addr, (int)data_size, nullptr); + } else if (req == PT_DETACH) { + ptrace64(req, pid, 0, 0, nullptr); + } else { + assert(0 && "Not supported yet."); + } + } else { + assert(0 && "Not supported yet."); + } + + if (errno) { + error.SetErrorToErrno(); + ret = -1; + } + + LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3}, {4})={5:x}", req, pid, addr, data, + data_size, ret); + + PtraceDisplayBytes(req, data, data_size); + + if (error.Fail()) + LLDB_LOG(log, "ptrace() failed: {0}", error); + + return error; +} + +llvm::Expected NativeProcessAIX::TraceSupported() { + return NativeProcessProtocol::TraceSupported(); +} + +Error NativeProcessAIX::TraceStart(StringRef json_request, StringRef type) { + return NativeProcessProtocol::TraceStart(json_request, type); +} + +Error NativeProcessAIX::TraceStop(const TraceStopRequest &request) { + return NativeProcessProtocol::TraceStop(request); +} + +Expected NativeProcessAIX::TraceGetState(StringRef type) { + return NativeProcessProtocol::TraceGetState(type); +} + +Expected> NativeProcessAIX::TraceGetBinaryData( + const TraceGetBinaryDataRequest &request) { + return NativeProcessProtocol::TraceGetBinaryData(request); +} diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h new file mode 100644 index 0000000000000..bdb6f7c500885 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h @@ -0,0 +1,283 @@ +//===-- NativeProcessAIX.h ---------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeProcessAIX_H_ +#define liblldb_NativeProcessAIX_H_ + +#include +#include + +#include "lldb/Host/Debug.h" +#include "lldb/Host/HostThread.h" +#include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/lldb-types.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "lldb/Host/aix/Support.h" + +#include "NativeThreadAIX.h" +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h" + +namespace lldb_private { +class Status; +class Scalar; + +namespace process_aix { +/// \class NativeProcessAIX +/// Manages communication with the inferior (debugee) process. +/// +/// Upon construction, this class prepares and launches an inferior process +/// for debugging. +/// +/// Changes in the inferior process state are broadcasted. +class NativeProcessAIX : public NativeProcessProtocol, + private NativeProcessSoftwareSingleStep { +public: + class Manager : public NativeProcessProtocol::Manager { + public: + Manager(MainLoop &mainloop); + + llvm::Expected> + Launch(ProcessLaunchInfo &launch_info, + NativeDelegate &native_delegate) override; + + llvm::Expected> + Attach(lldb::pid_t pid, NativeDelegate &native_delegate) override; + + Extension GetSupportedExtensions() const override; + + void AddProcess(NativeProcessAIX &process) { + m_processes.insert(&process); + } + + void RemoveProcess(NativeProcessAIX &process) { + m_processes.erase(&process); + } + + // Collect an event for the given tid, waiting for it if necessary. + void CollectThread(::pid_t tid); + + private: + MainLoop::SignalHandleUP m_sigchld_handle; + + llvm::SmallPtrSet m_processes; + + // Threads (events) which haven't been claimed by any process. + llvm::DenseSet<::pid_t> m_unowned_threads; + + void SigchldHandler(); + }; + + // NativeProcessProtocol Interface + + ~NativeProcessAIX() override { m_manager.RemoveProcess(*this); } + + Status Resume(const ResumeActionList &resume_actions) override; + + Status Halt() override; + + Status Detach() override; + + Status Signal(int signo) override; + + Status Interrupt() override; + + Status Kill() override; + + lldb::addr_t GetSharedLibraryInfoAddress() override; + + Status GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info) override; + + Status ReadMemory(lldb::addr_t addr, void *buf, size_t size, + size_t &bytes_read) override; + + Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, + size_t &bytes_written) override; + + llvm::Expected AllocateMemory(size_t size, + uint32_t permissions) override; + + llvm::Error DeallocateMemory(lldb::addr_t addr) override; + + Status ReadMemoryTags(int32_t type, lldb::addr_t addr, size_t len, + std::vector &tags) override; + + Status WriteMemoryTags(int32_t type, lldb::addr_t addr, size_t len, + const std::vector &tags) override; + + size_t UpdateThreads() override; + + const ArchSpec &GetArchitecture() const override { return m_arch; } + + Status SetBreakpoint(lldb::addr_t addr, uint32_t size, + bool hardware) override; + + Status RemoveBreakpoint(lldb::addr_t addr, bool hardware = false) override; + + void DoStopIDBumped(uint32_t newBumpId) override; + + Status GetLoadedModuleFileSpec(const char *module_path, + FileSpec &file_spec) override; + + Status GetFileLoadAddress(const llvm::StringRef &file_name, + lldb::addr_t &load_addr) override; + + NativeThreadAIX *GetThreadByID(lldb::tid_t id); + NativeThreadAIX *GetCurrentThread(); + + llvm::ErrorOr> + GetAuxvData() const override { + // Not available on this target. + return llvm::errc::not_supported; + } + + /// Tracing + /// These methods implement the jLLDBTrace packets + /// \{ + llvm::Error TraceStart(llvm::StringRef json_request, + llvm::StringRef type) override; + + llvm::Error TraceStop(const TraceStopRequest &request) override; + + llvm::Expected + TraceGetState(llvm::StringRef type) override; + + llvm::Expected> + TraceGetBinaryData(const TraceGetBinaryDataRequest &request) override; + + llvm::Expected TraceSupported() override; + /// } + + // Interface used by NativeRegisterContext-derived classes. + static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr, + void *data = nullptr, size_t data_size = 0, + long *result = nullptr); + + bool SupportHardwareSingleStepping() const; + + /// Writes a siginfo_t structure corresponding to the given thread ID to the + /// memory region pointed to by \p siginfo. + int8_t GetSignalInfo(WaitStatus wstatus) const; + +protected: + llvm::Expected> + GetSoftwareBreakpointTrapOpcode(size_t size_hint) override; + + llvm::Expected Syscall(llvm::ArrayRef args); + +private: + Manager &m_manager; + /*MainLoop::SignalHandleUP m_sigchld_handle;*/ + ArchSpec m_arch; + /*MainLoop& m_main_loop;*/ + + LazyBool m_supports_mem_region = eLazyBoolCalculate; + std::vector> m_mem_region_cache; + + lldb::tid_t m_pending_notification_tid = LLDB_INVALID_THREAD_ID; + + /// Inferior memory (allocated by us) and its size. + llvm::DenseMap m_allocated_memory; + + // Private Instance Methods + NativeProcessAIX(::pid_t pid, int terminal_fd, NativeDelegate &delegate, + const ArchSpec &arch, Manager &manager, + llvm::ArrayRef<::pid_t> tids); + + // Returns a list of process threads that we have attached to. + static llvm::Expected> Attach(::pid_t pid); + + static Status SetDefaultPtraceOpts(const lldb::pid_t); + + bool TryHandleWaitStatus(lldb::pid_t pid, WaitStatus status); + + void MonitorCallback(NativeThreadAIX &thread, WaitStatus status); + + void MonitorSIGTRAP(const WaitStatus status, NativeThreadAIX &thread); + + void MonitorTrace(NativeThreadAIX &thread); + + void MonitorBreakpoint(NativeThreadAIX &thread); + + void MonitorWatchpoint(NativeThreadAIX &thread, uint32_t wp_index); + + void MonitorSignal(const WaitStatus status, NativeThreadAIX &thread); + + bool HasThreadNoLock(lldb::tid_t thread_id); + + void StopTrackingThread(NativeThreadAIX &thread); + + /// Create a new thread. + /// + /// If process tracing is enabled and the thread can't be traced, then the + /// thread is left stopped with a \a eStopReasonProcessorTrace status, and + /// then the process is stopped. + /// + /// \param[in] resume + /// If a tracing error didn't happen, then resume the thread after + /// creation if \b true, or leave it stopped with SIGSTOP if \b false. + NativeThreadAIX &AddThread(lldb::tid_t thread_id, bool resume); + + /// Start tracing a new thread if process tracing is enabled. + /// + /// Trace mechanisms should modify this method to provide automatic tracing + /// for new threads. + Status NotifyTracersOfNewThread(lldb::tid_t tid); + + /// Stop tracing threads upon a destroy event. + /// + /// Trace mechanisms should modify this method to provide automatic trace + /// stopping for threads being destroyed. + Status NotifyTracersOfThreadDestroyed(lldb::tid_t tid); + + void NotifyTracersProcessWillResume() override; + + void NotifyTracersProcessDidStop() override; + /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG) + /// corresponding to the given thread ID to the memory pointed to by @p + /// message. + Status GetEventMessage(lldb::tid_t tid, unsigned long *message); + + void NotifyThreadDeath(lldb::tid_t tid); + + Status Detach(lldb::tid_t tid); + + // This method is requests a stop on all threads which are still running. It + // sets up a + // deferred delegate notification, which will fire once threads report as + // stopped. The + // triggerring_tid will be set as the current thread (main stop reason). + void StopRunningThreads(lldb::tid_t triggering_tid); + + // Notify the delegate if all threads have stopped. + void SignalIfAllThreadsStopped(); + + // Resume the given thread, optionally passing it the given signal. The type + // of resume + // operation (continue, single-step) depends on the state parameter. + Status ResumeThread(NativeThreadAIX &thread, lldb::StateType state, + int signo); + + void ThreadWasCreated(NativeThreadAIX &thread); + + void SigchldHandler(); + + Status PopulateMemoryRegionCache(); + + // Handle a clone()-like event. + bool MonitorClone(NativeThreadAIX &parent, lldb::pid_t child_pid, + int event); +}; + +} // namespace process_aix +} // namespace lldb_private + +#endif // #ifndef liblldb_NativeProcessAIX_H_ diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp new file mode 100644 index 0000000000000..0859f9501c1b6 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp @@ -0,0 +1,157 @@ +//===-- NativeRegisterContextAIX.cpp ------------------------------------===// +// +// 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 "NativeRegisterContextAIX.h" + +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/Utility/RegisterValue.h" + +#include "Plugins/Process/AIX/NativeProcessAIX.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "lldb/Host/aix/Ptrace.h" + +using namespace lldb_private; +using namespace lldb_private::process_aix; + +lldb::ByteOrder NativeRegisterContextAIX::GetByteOrder() const { + return m_thread.GetProcess().GetByteOrder(); +} + +Status NativeRegisterContextAIX::ReadRegisterRaw(uint32_t reg_index, + RegisterValue ®_value) { + const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); + if (!reg_info) + return Status("register %" PRIu32 " not found", reg_index); + + return DoReadRegisterValue(GetPtraceOffset(reg_index), reg_info->name, + reg_info->byte_size, reg_value); +} + +Status +NativeRegisterContextAIX::WriteRegisterRaw(uint32_t reg_index, + const RegisterValue ®_value) { + uint32_t reg_to_write = reg_index; + RegisterValue value_to_write = reg_value; + + // Check if this is a subregister of a full register. + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index); + if (reg_info->invalidate_regs && + (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) { + Status error; + + RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + error = ReadRegister(full_reg_info, full_value); + if (error.Fail()) + return error; + + lldb::ByteOrder byte_order = GetByteOrder(); + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData( + *full_reg_info, dst, sizeof(dst), byte_order, error); + if (error.Success() && dest_size) { + uint8_t src[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = reg_value.GetAsMemoryData( + *reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) { + // Copy the src bytes to the destination. + memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(*full_reg_info); + reg_to_write = full_reg; + } + } + } + + const RegisterInfo *const register_to_write_info_p = + GetRegisterInfoAtIndex(reg_to_write); + assert(register_to_write_info_p && + "register to write does not have valid RegisterInfo"); + if (!register_to_write_info_p) + return Status("NativeRegisterContextAIX::%s failed to get RegisterInfo " + "for write register index %" PRIu32, + __FUNCTION__, reg_to_write); + + return DoWriteRegisterValue(GetPtraceOffset(reg_index), reg_info->name, + reg_value); +} + +Status NativeRegisterContextAIX::ReadGPR() { + return NativeProcessAIX::PtraceWrapper( + PTRACE_GETREGS, m_thread.GetID(), nullptr, GetGPRBuffer(), GetGPRSize()); +} + +Status NativeRegisterContextAIX::WriteGPR() { + return NativeProcessAIX::PtraceWrapper( + PTRACE_SETREGS, m_thread.GetID(), nullptr, GetGPRBuffer(), GetGPRSize()); +} + +Status NativeRegisterContextAIX::ReadFPR() { + return NativeProcessAIX::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(), + nullptr, GetFPRBuffer(), + GetFPRSize()); +} + +Status NativeRegisterContextAIX::WriteFPR() { + return NativeProcessAIX::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(), + nullptr, GetFPRBuffer(), + GetFPRSize()); +} + +Status NativeRegisterContextAIX::ReadRegisterSet(void *buf, size_t buf_size, + unsigned int regset) { + return NativeProcessAIX::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), + static_cast(®set), buf, + buf_size); +} + +Status NativeRegisterContextAIX::WriteRegisterSet(void *buf, size_t buf_size, + unsigned int regset) { + return NativeProcessAIX::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), + static_cast(®set), buf, + buf_size); +} + +Status NativeRegisterContextAIX::DoReadRegisterValue(uint32_t offset, + const char *reg_name, + uint32_t size, + RegisterValue &value) { + Log *log = GetLog(POSIXLog::Registers); + + long data; + Status error = NativeProcessAIX::PtraceWrapper( + PTRACE_PEEKUSER, m_thread.GetID(), reinterpret_cast(offset), + nullptr, 0, &data); + + if (error.Success()) + // First cast to an unsigned of the same size to avoid sign extension. + value.SetUInt(static_cast(data), size); + + LLDB_LOG(log, "{0}: {1:x}", reg_name, data); + return error; +} + +Status NativeRegisterContextAIX::DoWriteRegisterValue( + uint32_t offset, const char *reg_name, const RegisterValue &value) { + Log *log = GetLog(POSIXLog::Registers); + + void *buf = reinterpret_cast(value.GetAsUInt64()); + LLDB_LOG(log, "{0}: {1}", reg_name, buf); + + return NativeProcessAIX::PtraceWrapper( + PTRACE_POKEUSER, m_thread.GetID(), reinterpret_cast(offset), buf); +} diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h new file mode 100644 index 0000000000000..9c2a326856c0b --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h @@ -0,0 +1,133 @@ +//===-- NativeRegisterContextAIX.h ----------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_NativeRegisterContextAIX_h +#define lldb_NativeRegisterContextAIX_h + +#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h" +#include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/Target/MemoryTagManager.h" +#include "llvm/Support/Error.h" + +namespace lldb_private { +namespace process_aix { + +class NativeThreadAIX; + +class NativeRegisterContextAIX + : public virtual NativeRegisterContextRegisterInfo { +public: + // This function is implemented in the NativeRegisterContextAIX_* subclasses + // to create a new instance of the host specific NativeRegisterContextAIX. + // The implementations can't collide as only one NativeRegisterContextAIX_* + // variant should be compiled into the final executable. + static std::unique_ptr + CreateHostNativeRegisterContextAIX(const ArchSpec &target_arch, + NativeThreadAIX &native_thread); + + // Invalidates cached values in register context data structures + virtual void InvalidateAllRegisters(){} + + struct SyscallData { + /// The syscall instruction. If the architecture uses software + /// single-stepping, the instruction should also be followed by a trap to + /// ensure the process is stopped after the syscall. + llvm::ArrayRef Insn; + + /// Registers used for syscall arguments. The first register is used to + /// store the syscall number. + llvm::ArrayRef Args; + + uint32_t Result; ///< Register containing the syscall result. + }; + /// Return architecture-specific data needed to make inferior syscalls, if + /// they are supported. + virtual std::optional GetSyscallData() { return std::nullopt; } + + struct MmapData { + // Syscall numbers can be found (e.g.) in /usr/include/asm/unistd.h for the + // relevant architecture. + unsigned SysMmap; ///< mmap syscall number. + unsigned SysMunmap; ///< munmap syscall number + }; + /// Return the architecture-specific data needed to make mmap syscalls, if + /// they are supported. + virtual std::optional GetMmapData() { return std::nullopt; } + + struct MemoryTaggingDetails { + /// Object with tag handling utilities. If the function below returns + /// a valid structure, you can assume that this pointer is valid. + std::unique_ptr manager; + int ptrace_read_req; /// ptrace operation number for memory tag read + int ptrace_write_req; /// ptrace operation number for memory tag write + }; + /// Return architecture specific data needed to use memory tags, + /// if they are supported. + virtual llvm::Expected + GetMemoryTaggingDetails(int32_t type) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Architecture does not support memory tagging"); + } + +protected: + // NB: This constructor is here only because gcc<=6.5 requires a virtual base + // class initializer on abstract class (even though it is never used). It can + // be deleted once we move to gcc>=7.0. + NativeRegisterContextAIX(NativeThreadProtocol &thread) + : NativeRegisterContextRegisterInfo(thread, nullptr) {} + + lldb::ByteOrder GetByteOrder() const; + + virtual Status ReadRegisterRaw(uint32_t reg_index, RegisterValue ®_value); + + virtual Status WriteRegisterRaw(uint32_t reg_index, + const RegisterValue ®_value); + + virtual Status ReadRegisterSet(void *buf, size_t buf_size, + unsigned int regset); + + virtual Status WriteRegisterSet(void *buf, size_t buf_size, + unsigned int regset); + + virtual Status ReadGPR(); + + virtual Status WriteGPR(); + + virtual Status ReadFPR(); + + virtual Status WriteFPR(); + + virtual void *GetGPRBuffer() = 0; + + virtual size_t GetGPRSize() const { + return GetRegisterInfoInterface().GetGPRSize(); + } + + virtual void *GetFPRBuffer() = 0; + + virtual size_t GetFPRSize() = 0; + + virtual uint32_t GetPtraceOffset(uint32_t reg_index) { + return GetRegisterInfoAtIndex(reg_index)->byte_offset; + } + + // The Do*** functions are executed on the privileged thread and can perform + // ptrace + // operations directly. + virtual Status DoReadRegisterValue(uint32_t offset, const char *reg_name, + uint32_t size, RegisterValue &value); + + virtual Status DoWriteRegisterValue(uint32_t offset, const char *reg_name, + const RegisterValue &value); +}; + +} // namespace process_aix +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextAIX_h diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp new file mode 100644 index 0000000000000..1996373791748 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp @@ -0,0 +1,744 @@ +//===-- NativeRegisterContextAIX_ppc64.cpp ----------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// This implementation is related to the OpenPOWER ABI for Power Architecture +// 64-bit ELF V2 ABI + +#if defined(__powerpc64__) + +#include "NativeRegisterContextAIX_ppc64.h" + +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Status.h" +#include "lldb/Host/aix/Ptrace.h" + +#include "Plugins/Process/AIX/NativeProcessAIX.h" +#include "Plugins/Process/Linux/Procfs.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h" + +// System includes - They have to be included after framework includes because +// they define some macros which collide with variable names in other modules +#include +#include +#include +#include + +#define REG_CONTEXT_SIZE \ + (GetGPRSize() + GetFPRSize() + sizeof(m_vmx_ppc64le) + sizeof(m_vsx_ppc64le)) +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; + +static const uint32_t g_gpr_regnums_ppc64le[] = { + gpr_r0_ppc64le, gpr_r1_ppc64le, gpr_r2_ppc64le, gpr_r3_ppc64le, + gpr_r4_ppc64le, gpr_r5_ppc64le, gpr_r6_ppc64le, gpr_r7_ppc64le, + gpr_r8_ppc64le, gpr_r9_ppc64le, gpr_r10_ppc64le, gpr_r11_ppc64le, + gpr_r12_ppc64le, gpr_r13_ppc64le, gpr_r14_ppc64le, gpr_r15_ppc64le, + gpr_r16_ppc64le, gpr_r17_ppc64le, gpr_r18_ppc64le, gpr_r19_ppc64le, + gpr_r20_ppc64le, gpr_r21_ppc64le, gpr_r22_ppc64le, gpr_r23_ppc64le, + gpr_r24_ppc64le, gpr_r25_ppc64le, gpr_r26_ppc64le, gpr_r27_ppc64le, + gpr_r28_ppc64le, gpr_r29_ppc64le, gpr_r30_ppc64le, gpr_r31_ppc64le, + gpr_pc_ppc64le, gpr_msr_ppc64le, gpr_origr3_ppc64le, gpr_ctr_ppc64le, + gpr_lr_ppc64le, gpr_xer_ppc64le, gpr_cr_ppc64le, gpr_softe_ppc64le, + gpr_trap_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +static const uint32_t g_fpr_regnums_ppc64le[] = { + fpr_f0_ppc64le, fpr_f1_ppc64le, fpr_f2_ppc64le, fpr_f3_ppc64le, + fpr_f4_ppc64le, fpr_f5_ppc64le, fpr_f6_ppc64le, fpr_f7_ppc64le, + fpr_f8_ppc64le, fpr_f9_ppc64le, fpr_f10_ppc64le, fpr_f11_ppc64le, + fpr_f12_ppc64le, fpr_f13_ppc64le, fpr_f14_ppc64le, fpr_f15_ppc64le, + fpr_f16_ppc64le, fpr_f17_ppc64le, fpr_f18_ppc64le, fpr_f19_ppc64le, + fpr_f20_ppc64le, fpr_f21_ppc64le, fpr_f22_ppc64le, fpr_f23_ppc64le, + fpr_f24_ppc64le, fpr_f25_ppc64le, fpr_f26_ppc64le, fpr_f27_ppc64le, + fpr_f28_ppc64le, fpr_f29_ppc64le, fpr_f30_ppc64le, fpr_f31_ppc64le, + fpr_fpscr_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +static const uint32_t g_vmx_regnums_ppc64le[] = { + vmx_vr0_ppc64le, vmx_vr1_ppc64le, vmx_vr2_ppc64le, vmx_vr3_ppc64le, + vmx_vr4_ppc64le, vmx_vr5_ppc64le, vmx_vr6_ppc64le, vmx_vr7_ppc64le, + vmx_vr8_ppc64le, vmx_vr9_ppc64le, vmx_vr10_ppc64le, vmx_vr11_ppc64le, + vmx_vr12_ppc64le, vmx_vr13_ppc64le, vmx_vr14_ppc64le, vmx_vr15_ppc64le, + vmx_vr16_ppc64le, vmx_vr17_ppc64le, vmx_vr18_ppc64le, vmx_vr19_ppc64le, + vmx_vr20_ppc64le, vmx_vr21_ppc64le, vmx_vr22_ppc64le, vmx_vr23_ppc64le, + vmx_vr24_ppc64le, vmx_vr25_ppc64le, vmx_vr26_ppc64le, vmx_vr27_ppc64le, + vmx_vr28_ppc64le, vmx_vr29_ppc64le, vmx_vr30_ppc64le, vmx_vr31_ppc64le, + vmx_vscr_ppc64le, vmx_vrsave_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +static const uint32_t g_vsx_regnums_ppc64le[] = { + vsx_vs0_ppc64le, vsx_vs1_ppc64le, vsx_vs2_ppc64le, vsx_vs3_ppc64le, + vsx_vs4_ppc64le, vsx_vs5_ppc64le, vsx_vs6_ppc64le, vsx_vs7_ppc64le, + vsx_vs8_ppc64le, vsx_vs9_ppc64le, vsx_vs10_ppc64le, vsx_vs11_ppc64le, + vsx_vs12_ppc64le, vsx_vs13_ppc64le, vsx_vs14_ppc64le, vsx_vs15_ppc64le, + vsx_vs16_ppc64le, vsx_vs17_ppc64le, vsx_vs18_ppc64le, vsx_vs19_ppc64le, + vsx_vs20_ppc64le, vsx_vs21_ppc64le, vsx_vs22_ppc64le, vsx_vs23_ppc64le, + vsx_vs24_ppc64le, vsx_vs25_ppc64le, vsx_vs26_ppc64le, vsx_vs27_ppc64le, + vsx_vs28_ppc64le, vsx_vs29_ppc64le, vsx_vs30_ppc64le, vsx_vs31_ppc64le, + vsx_vs32_ppc64le, vsx_vs33_ppc64le, vsx_vs34_ppc64le, vsx_vs35_ppc64le, + vsx_vs36_ppc64le, vsx_vs37_ppc64le, vsx_vs38_ppc64le, vsx_vs39_ppc64le, + vsx_vs40_ppc64le, vsx_vs41_ppc64le, vsx_vs42_ppc64le, vsx_vs43_ppc64le, + vsx_vs44_ppc64le, vsx_vs45_ppc64le, vsx_vs46_ppc64le, vsx_vs47_ppc64le, + vsx_vs48_ppc64le, vsx_vs49_ppc64le, vsx_vs50_ppc64le, vsx_vs51_ppc64le, + vsx_vs52_ppc64le, vsx_vs53_ppc64le, vsx_vs54_ppc64le, vsx_vs55_ppc64le, + vsx_vs56_ppc64le, vsx_vs57_ppc64le, vsx_vs58_ppc64le, vsx_vs59_ppc64le, + vsx_vs60_ppc64le, vsx_vs61_ppc64le, vsx_vs62_ppc64le, vsx_vs63_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +// Number of register sets provided by this context. +static constexpr int k_num_register_sets = 4; + +static const RegisterSet g_reg_sets_ppc64le[k_num_register_sets] = { + {"General Purpose Registers", "gpr", k_num_gpr_registers_ppc64le, + g_gpr_regnums_ppc64le}, + {"Floating Point Registers", "fpr", k_num_fpr_registers_ppc64le, + g_fpr_regnums_ppc64le}, + {"AltiVec/VMX Registers", "vmx", k_num_vmx_registers_ppc64le, + g_vmx_regnums_ppc64le}, + {"VSX Registers", "vsx", k_num_vsx_registers_ppc64le, + g_vsx_regnums_ppc64le}, +}; + +std::unique_ptr +NativeRegisterContextAIX::CreateHostNativeRegisterContextAIX( + const ArchSpec &target_arch, NativeThreadAIX &native_thread) { + switch (target_arch.GetMachine()) { + case llvm::Triple::ppc64: + return std::make_unique(target_arch, + native_thread); + default: + llvm_unreachable("have no register context for architecture"); + } +} + +NativeRegisterContextAIX_ppc64::NativeRegisterContextAIX_ppc64( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + : NativeRegisterContextRegisterInfo( + native_thread, new RegisterInfoPOSIX_ppc64le(target_arch)), + NativeRegisterContextAIX(native_thread) { + if (target_arch.GetMachine() != llvm::Triple::ppc64) { + llvm_unreachable("Unhandled target architecture."); + } + + ::memset(&m_gpr_ppc64le, 0, sizeof(m_gpr_ppc64le)); + ::memset(&m_fpr_ppc64le, 0, sizeof(m_fpr_ppc64le)); + ::memset(&m_vmx_ppc64le, 0, sizeof(m_vmx_ppc64le)); + ::memset(&m_vsx_ppc64le, 0, sizeof(m_vsx_ppc64le)); + ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); +} + +uint32_t NativeRegisterContextAIX_ppc64::GetRegisterSetCount() const { + return k_num_register_sets; +} + +const RegisterSet * +NativeRegisterContextAIX_ppc64::GetRegisterSet(uint32_t set_index) const { + if (set_index < k_num_register_sets) + return &g_reg_sets_ppc64le[set_index]; + + return nullptr; +} + +uint32_t NativeRegisterContextAIX_ppc64::GetUserRegisterCount() const { + uint32_t count = 0; + for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) + count += g_reg_sets_ppc64le[set_index].num_registers; + return count; +} + +Status NativeRegisterContextAIX_ppc64::ReadRegister( + const RegisterInfo *reg_info, RegisterValue ®_value) { + Status error; + + if (!reg_info) { + error.SetErrorString("reg_info NULL"); + return error; + } + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (IsFPR(reg)) { + error = ReadFPR(); + if (error.Fail()) + return error; + + // Get pointer to m_fpr_ppc64le variable and set the data from it. + uint32_t fpr_offset = CalculateFprOffset(reg_info); + assert(fpr_offset < sizeof m_fpr_ppc64le); + uint8_t *src = (uint8_t *)&m_fpr_ppc64le + fpr_offset; + reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } else if (IsVSX(reg)) { + uint32_t vsx_offset = CalculateVsxOffset(reg_info); + assert(vsx_offset < sizeof(m_vsx_ppc64le)); + + if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) { + error = ReadVSX(); + if (error.Fail()) + return error; + + error = ReadFPR(); + if (error.Fail()) + return error; + + uint64_t value[2]; + uint8_t *dst, *src; + dst = (uint8_t *)&value; + src = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + dst += 8; + src = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + reg_value.SetFromMemoryData(*reg_info, &value, reg_info->byte_size, + eByteOrderLittle, error); + } else { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data from it. + uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2; + uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } + } else if (IsVMX(reg)) { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data from it. + uint32_t vmx_offset = CalculateVmxOffset(reg_info); + assert(vmx_offset < sizeof m_vmx_ppc64le); + uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } else if (IsGPR(reg)) { + error = ReadGPR(); + if (error.Fail()) + return error; + + uint8_t *src = (uint8_t *) &m_gpr_ppc64le + reg_info->byte_offset; + reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } else { + return Status("failed - register wasn't recognized to be a GPR, FPR, VSX " + "or VMX, read strategy unknown"); + } + + return error; +} + +Status NativeRegisterContextAIX_ppc64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue ®_value) { + Status error; + if (!reg_info) + return Status("reg_info NULL"); + + const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; + if (reg_index == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : ""); + + if (IsGPR(reg_index)) { + error = ReadGPR(); + if (error.Fail()) + return error; + + uint8_t *dst = (uint8_t *)&m_gpr_ppc64le + reg_info->byte_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + *(uint64_t *)dst = llvm::byteswap(*(uint64_t *)dst); + + error = WriteGPR(); + if (error.Fail()) + return error; + + return Status(); + } + + if (IsFPR(reg_index)) { + error = ReadFPR(); + if (error.Fail()) + return error; + + // Get pointer to m_fpr_ppc64le variable and set the data to it. + uint32_t fpr_offset = CalculateFprOffset(reg_info); + assert(fpr_offset < GetFPRSize()); + uint8_t *dst = (uint8_t *)&m_fpr_ppc64le + fpr_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + + error = WriteFPR(); + if (error.Fail()) + return error; + + return Status(); + } + + if (IsVMX(reg_index)) { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data to it. + uint32_t vmx_offset = CalculateVmxOffset(reg_info); + assert(vmx_offset < sizeof(m_vmx_ppc64le)); + uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + + error = WriteVMX(); + if (error.Fail()) + return error; + + return Status(); + } + + if (IsVSX(reg_index)) { + uint32_t vsx_offset = CalculateVsxOffset(reg_info); + assert(vsx_offset < sizeof(m_vsx_ppc64le)); + + if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) { + error = ReadVSX(); + if (error.Fail()) + return error; + + error = ReadFPR(); + if (error.Fail()) + return error; + + uint64_t value[2]; + ::memcpy(value, reg_value.GetBytes(), 16); + uint8_t *dst, *src; + src = (uint8_t *)value; + dst = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + src += 8; + dst = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + + WriteVSX(); + WriteFPR(); + } else { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data from it. + uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2; + uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + WriteVMX(); + } + + return Status(); + } + + return Status("failed - register wasn't recognized to be a GPR, FPR, VSX " + "or VMX, write strategy unknown"); +} + +Status NativeRegisterContextAIX_ppc64::ReadAllRegisterValues( + lldb::WritableDataBufferSP &data_sp) { + Status error; + + data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); + error = ReadGPR(); + if (error.Fail()) + return error; + + error = ReadFPR(); + if (error.Fail()) + return error; + + error = ReadVMX(); + if (error.Fail()) + return error; + + error = ReadVSX(); + if (error.Fail()) + return error; + + uint8_t *dst = data_sp->GetBytes(); + ::memcpy(dst, &m_gpr_ppc64le, GetGPRSize()); + dst += GetGPRSize(); + ::memcpy(dst, &m_fpr_ppc64le, GetFPRSize()); + dst += GetFPRSize(); + ::memcpy(dst, &m_vmx_ppc64le, sizeof(m_vmx_ppc64le)); + dst += sizeof(m_vmx_ppc64le); + ::memcpy(dst, &m_vsx_ppc64le, sizeof(m_vsx_ppc64le)); + + return error; +} + +Status NativeRegisterContextAIX_ppc64::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + Status error; + + if (!data_sp) { + error.SetErrorStringWithFormat( + "NativeRegisterContextAIX_ppc64::%s invalid data_sp provided", + __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { + error.SetErrorStringWithFormat( + "NativeRegisterContextAIX_ppc64::%s data_sp contained mismatched " + "data size, expected %" PRIu64 ", actual %" PRIu64, + __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); + return error; + } + + const uint8_t *src = data_sp->GetBytes(); + if (src == nullptr) { + error.SetErrorStringWithFormat("NativeRegisterContextAIX_ppc64::%s " + "DataBuffer::GetBytes() returned a null " + "pointer", + __FUNCTION__); + return error; + } + + ::memcpy(&m_gpr_ppc64le, src, GetGPRSize()); + error = WriteGPR(); + + if (error.Fail()) + return error; + + src += GetGPRSize(); + ::memcpy(&m_fpr_ppc64le, src, GetFPRSize()); + + error = WriteFPR(); + if (error.Fail()) + return error; + + src += GetFPRSize(); + ::memcpy(&m_vmx_ppc64le, src, sizeof(m_vmx_ppc64le)); + + error = WriteVMX(); + if (error.Fail()) + return error; + + src += sizeof(m_vmx_ppc64le); + ::memcpy(&m_vsx_ppc64le, src, sizeof(m_vsx_ppc64le)); + error = WriteVSX(); + + return error; +} + +bool NativeRegisterContextAIX_ppc64::IsGPR(unsigned reg) const { + return reg <= k_last_gpr_ppc64le; // GPR's come first. +} + +bool NativeRegisterContextAIX_ppc64::IsFPR(unsigned reg) const { + return (k_first_fpr_ppc64le <= reg && reg <= k_last_fpr_ppc64le); +} + +uint32_t NativeRegisterContextAIX_ppc64::CalculateFprOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - + GetRegisterInfoAtIndex(k_first_fpr_ppc64le)->byte_offset; +} + +uint32_t NativeRegisterContextAIX_ppc64::CalculateVmxOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - + GetRegisterInfoAtIndex(k_first_vmx_ppc64le)->byte_offset; +} + +uint32_t NativeRegisterContextAIX_ppc64::CalculateVsxOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - + GetRegisterInfoAtIndex(k_first_vsx_ppc64le)->byte_offset; +} + +Status NativeRegisterContextAIX_ppc64::ReadVMX() { + return NativeProcessAIX::PtraceWrapper(PTRACE_GETVRREGS, m_thread.GetID(), + nullptr, &m_vmx_ppc64le, + sizeof(m_vmx_ppc64le)); +} + +Status NativeRegisterContextAIX_ppc64::WriteVMX() { + //FIXME + int regset = 0/*NT_PPC_VMX*/; + return NativeProcessAIX::PtraceWrapper(PT_CLEAR/*PTRACE_SETVRREGS*/, m_thread.GetID(), + ®set, &m_vmx_ppc64le, + sizeof(m_vmx_ppc64le)); +} + +Status NativeRegisterContextAIX_ppc64::ReadVSX() { + return NativeProcessAIX::PtraceWrapper(PTRACE_GETVSRREGS, m_thread.GetID(), + nullptr, &m_vsx_ppc64le, + sizeof(m_vsx_ppc64le)); +} + +Status NativeRegisterContextAIX_ppc64::WriteVSX() { + //FIXME + int regset = 0/*NT_PPC_VSX*/; + return NativeProcessAIX::PtraceWrapper(PT_CLEAR/*PTRACE_SETVSRREGS*/, m_thread.GetID(), + ®set, &m_vsx_ppc64le, + sizeof(m_vsx_ppc64le)); +} + +bool NativeRegisterContextAIX_ppc64::IsVMX(unsigned reg) { + return (reg >= k_first_vmx_ppc64le) && (reg <= k_last_vmx_ppc64le); +} + +bool NativeRegisterContextAIX_ppc64::IsVSX(unsigned reg) { + return (reg >= k_first_vsx_ppc64le) && (reg <= k_last_vsx_ppc64le); +} + +uint32_t NativeRegisterContextAIX_ppc64::NumSupportedHardwareWatchpoints() { + Log *log = GetLog(POSIXLog::Watchpoints); + + // Read hardware breakpoint and watchpoint information. + Status error = ReadHardwareDebugInfo(); + + if (error.Fail()) + return 0; + + LLDB_LOG(log, "{0}", m_max_hwp_supported); + return m_max_hwp_supported; +} + +uint32_t NativeRegisterContextAIX_ppc64::SetHardwareWatchpoint( + lldb::addr_t addr, size_t size, uint32_t watch_flags) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size, + watch_flags); + + // Read hardware breakpoint and watchpoint information. + Status error = ReadHardwareDebugInfo(); + + if (error.Fail()) + return LLDB_INVALID_INDEX32; + + uint32_t control_value = 0, wp_index = 0; + lldb::addr_t real_addr = addr; + uint32_t rw_mode = 0; + + // Check if we are setting watchpoint other than read/write/access Update + // watchpoint flag to match ppc64le write-read bit configuration. + switch (watch_flags) { + case eWatchpointKindWrite: + //FIXME + //rw_mode = 0/*PPC_BREAKPOINT_TRIGGER_WRITE*/; + watch_flags = 2; + break; + // Watchpoint read not supported + case eWatchpointKindRead: + case (eWatchpointKindRead | eWatchpointKindWrite): + default: + return LLDB_INVALID_INDEX32; + } + + // Check if size has a valid hardware watchpoint length. + if (size != 8) + return LLDB_INVALID_INDEX32; + + // Check 8-byte alignment for hardware watchpoint target address. Below is a + // hack to recalculate address and size in order to make sure we can watch + // non 8-byte aligned addresses as well. + if (addr & 0x07) { + + addr_t begin = llvm::alignDown(addr, 8); + addr_t end = llvm::alignTo(addr + size, 8); + size = llvm::PowerOf2Ceil(end - begin); + + addr = addr & (~0x07); + } + + // Setup control value + control_value = watch_flags << 3; + control_value |= ((1 << size) - 1) << 5; + control_value |= (2 << 1) | 1; + + // Iterate over stored watchpoints and find a free wp_index + wp_index = LLDB_INVALID_INDEX32; + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + if ((m_hwp_regs[i].control & 1) == 0) { + wp_index = i; // Mark last free slot + } else if (m_hwp_regs[i].address == addr) { + return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints. + } + } + + if (wp_index == LLDB_INVALID_INDEX32) + return LLDB_INVALID_INDEX32; + + // Update watchpoint in local cache + m_hwp_regs[wp_index].real_addr = real_addr; + m_hwp_regs[wp_index].address = addr; + m_hwp_regs[wp_index].control = control_value; + //m_hwp_regs[wp_index].mode = rw_mode; + + // PTRACE call to set corresponding watchpoint register. + error = WriteHardwareDebugRegs(); + + if (error.Fail()) { + m_hwp_regs[wp_index].address = 0; + m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros(1); + + return LLDB_INVALID_INDEX32; + } + + return wp_index; +} + +bool NativeRegisterContextAIX_ppc64::ClearHardwareWatchpoint( + uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + // Read hardware breakpoint and watchpoint information. + Status error = ReadHardwareDebugInfo(); + + if (error.Fail()) + return false; + + if (wp_index >= m_max_hwp_supported) + return false; + + // Create a backup we can revert to in case of failure. + lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; + uint32_t tempControl = m_hwp_regs[wp_index].control; + long *tempSlot = reinterpret_cast(m_hwp_regs[wp_index].slot); + + // Update watchpoint in local cache + m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros(1); + m_hwp_regs[wp_index].address = 0; + m_hwp_regs[wp_index].slot = 0; + m_hwp_regs[wp_index].mode = 0; + + // Ptrace call to update hardware debug registers + //FIXME + error = NativeProcessAIX::PtraceWrapper(PT_CLEAR/*PPC_PTRACE_DELHWDEBUG*/, + m_thread.GetID(), 0, tempSlot); + + if (error.Fail()) { + m_hwp_regs[wp_index].control = tempControl; + m_hwp_regs[wp_index].address = tempAddr; + m_hwp_regs[wp_index].slot = reinterpret_cast(tempSlot); + + return false; + } + + return true; +} + +uint32_t +NativeRegisterContextAIX_ppc64::GetWatchpointSize(uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + unsigned control = (m_hwp_regs[wp_index].control >> 5) & 0xff; + if (llvm::isPowerOf2_32(control + 1)) { + return llvm::popcount(control); + } + + return 0; +} + +bool NativeRegisterContextAIX_ppc64::WatchpointIsEnabled( + uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + return !!((m_hwp_regs[wp_index].control & 0x1) == 0x1); +} + +Status NativeRegisterContextAIX_ppc64::GetWatchpointHitIndex( + uint32_t &wp_index, lldb::addr_t trap_addr) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr); + + uint32_t watch_size; + lldb::addr_t watch_addr; + + for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) { + watch_size = GetWatchpointSize(wp_index); + watch_addr = m_hwp_regs[wp_index].address; + + if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr && + trap_addr <= watch_addr + watch_size) { + m_hwp_regs[wp_index].hit_addr = trap_addr; + return Status(); + } + } + + wp_index = LLDB_INVALID_INDEX32; + return Status(); +} + +lldb::addr_t +NativeRegisterContextAIX_ppc64::GetWatchpointAddress(uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + if (wp_index >= m_max_hwp_supported) + return LLDB_INVALID_ADDRESS; + + if (WatchpointIsEnabled(wp_index)) + return m_hwp_regs[wp_index].real_addr; + else + return LLDB_INVALID_ADDRESS; +} + +lldb::addr_t +NativeRegisterContextAIX_ppc64::GetWatchpointHitAddress(uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + if (wp_index >= m_max_hwp_supported) + return LLDB_INVALID_ADDRESS; + + if (WatchpointIsEnabled(wp_index)) + return m_hwp_regs[wp_index].hit_addr; + + return LLDB_INVALID_ADDRESS; +} + +Status NativeRegisterContextAIX_ppc64::ReadHardwareDebugInfo() { + if (!m_refresh_hwdebug_info) { + return Status(); + } + + m_max_hwp_supported = 1; + m_max_hbp_supported = 0; + m_refresh_hwdebug_info = false; + + return Status(); +} + +Status NativeRegisterContextAIX_ppc64::WriteHardwareDebugRegs() { + Status error; + long ret; + + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + if ((m_hwp_regs[i].control & 1) == 0) + continue; + + error = NativeProcessAIX::PtraceWrapper(PT_WATCH, m_thread.GetID(), (void *)m_hwp_regs[i].address, nullptr, 8, &ret); + + if (error.Fail()) + return error; + + m_hwp_regs[i].slot = ret; + } + return error; +} + +#endif // defined(__powerpc64__) diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h new file mode 100644 index 0000000000000..a29f786f2313a --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h @@ -0,0 +1,138 @@ +//===-- NativeRegisterContextAIX_ppc64.h --------------------*- 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 +// +//===----------------------------------------------------------------------===// + +// This implementation is related to the OpenPOWER ABI for Power Architecture +// 64-bit ELF V2 ABI + +#if defined(__powerpc64__) + +#ifndef lldb_NativeRegisterContextAIX_ppc64_h +#define lldb_NativeRegisterContextAIX_ppc64_h + +#include "Plugins/Process/AIX/NativeRegisterContextAIX.h" +#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" + +#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT +#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h" +#undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT + +namespace lldb_private { +namespace process_aix { + +class NativeProcessAIX; + +class NativeRegisterContextAIX_ppc64 : public NativeRegisterContextAIX { +public: + NativeRegisterContextAIX_ppc64(const ArchSpec &target_arch, + NativeThreadProtocol &native_thread); + + uint32_t GetRegisterSetCount() const override; + + uint32_t GetUserRegisterCount() const override; + + const RegisterSet *GetRegisterSet(uint32_t set_index) const override; + + Status ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + + Status WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + + Status ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override; + + Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + // Hardware watchpoint management functions + + uint32_t NumSupportedHardwareWatchpoints() override; + + uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags) override; + + bool ClearHardwareWatchpoint(uint32_t hw_index) override; + + Status GetWatchpointHitIndex(uint32_t &wp_index, + lldb::addr_t trap_addr) override; + + lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override; + + lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; + + uint32_t GetWatchpointSize(uint32_t wp_index); + + bool WatchpointIsEnabled(uint32_t wp_index); + +protected: + bool IsVMX(unsigned reg); + + bool IsVSX(unsigned reg); + + Status ReadVMX(); + + Status WriteVMX(); + + Status ReadVSX(); + + Status WriteVSX(); + + void *GetGPRBuffer() override { return &m_gpr_ppc64le; } + + void *GetFPRBuffer() override { return &m_fpr_ppc64le; } + + size_t GetFPRSize() override { return sizeof(m_fpr_ppc64le); } + +private: + GPR m_gpr_ppc64le; // 64-bit general purpose registers. + FPR m_fpr_ppc64le; // floating-point registers including extended register. + VMX m_vmx_ppc64le; // VMX registers. + VSX m_vsx_ppc64le; // Last lower bytes from first VSX registers. + + bool IsGPR(unsigned reg) const; + + bool IsFPR(unsigned reg) const; + + bool IsVMX(unsigned reg) const; + + bool IsVSX(unsigned reg) const; + + uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const; + + uint32_t CalculateVmxOffset(const RegisterInfo *reg_info) const; + + uint32_t CalculateVsxOffset(const RegisterInfo *reg_info) const; + + Status ReadHardwareDebugInfo(); + + Status WriteHardwareDebugRegs(); + + // Debug register info for hardware watchpoints management. + struct DREG { + lldb::addr_t address; // Breakpoint/watchpoint address value. + lldb::addr_t hit_addr; // Address at which last watchpoint trigger + // exception occurred. + lldb::addr_t real_addr; // Address value that should cause target to stop. + uint32_t control; // Breakpoint/watchpoint control value. + uint32_t refcount; // Serves as enable/disable and reference counter. + long slot; // Saves the value returned from PTRACE_SETHWDEBUG. + int mode; // Defines if watchpoint is read/write/access. + }; + + std::array m_hwp_regs; + + // 16 is just a maximum value, query hardware for actual watchpoint count + uint32_t m_max_hwp_supported = 16; + uint32_t m_max_hbp_supported = 16; + bool m_refresh_hwdebug_info = true; +}; + +} // namespace process_aix +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextAIX_ppc64_h + +#endif // defined(__powerpc64__) diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp new file mode 100644 index 0000000000000..e07daccdff550 --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp @@ -0,0 +1,526 @@ +//===-- NativeThreadAIX.cpp ---------------------------------------------===// +// +// 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 "NativeThreadAIX.h" + +#include +#include + +#include "NativeProcessAIX.h" +#include "NativeRegisterContextAIX.h" + +#include "lldb/Host/HostNativeThread.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" +#include "lldb/lldb-enumerations.h" + +#include "llvm/ADT/SmallString.h" + +#include "Plugins/Process/POSIX/CrashReason.h" + +#include +#include +#include + +#if 0 +#include +// Try to define a macro to encapsulate the tgkill syscall +#define tgkill(pid, tid, sig) \ + syscall(__NR_tgkill, static_cast<::pid_t>(pid), static_cast<::pid_t>(tid), \ + sig) +#endif + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_aix; + +namespace { +void LogThreadStopInfo(Log &log, const ThreadStopInfo &stop_info, + const char *const header) { + switch (stop_info.reason) { + case eStopReasonNone: + log.Printf("%s: %s no stop reason", __FUNCTION__, header); + return; + case eStopReasonTrace: + log.Printf("%s: %s trace, stopping signal 0x%" PRIx32, __FUNCTION__, header, + stop_info.signo); + return; + case eStopReasonBreakpoint: + log.Printf("%s: %s breakpoint, stopping signal 0x%" PRIx32, __FUNCTION__, + header, stop_info.signo); + return; + case eStopReasonWatchpoint: + log.Printf("%s: %s watchpoint, stopping signal 0x%" PRIx32, __FUNCTION__, + header, stop_info.signo); + return; + case eStopReasonSignal: + log.Printf("%s: %s signal 0x%02" PRIx32, __FUNCTION__, header, + stop_info.signo); + return; + case eStopReasonException: + log.Printf("%s: %s exception type 0x%02" PRIx64, __FUNCTION__, header, + stop_info.details.exception.type); + return; + case eStopReasonExec: + log.Printf("%s: %s exec, stopping signal 0x%" PRIx32, __FUNCTION__, header, + stop_info.signo); + return; + case eStopReasonPlanComplete: + log.Printf("%s: %s plan complete", __FUNCTION__, header); + return; + case eStopReasonThreadExiting: + log.Printf("%s: %s thread exiting", __FUNCTION__, header); + return; + case eStopReasonInstrumentation: + log.Printf("%s: %s instrumentation", __FUNCTION__, header); + return; + case eStopReasonProcessorTrace: + log.Printf("%s: %s processor trace", __FUNCTION__, header); + return; + default: + log.Printf("%s: %s invalid stop reason %" PRIu32, __FUNCTION__, header, + static_cast(stop_info.reason)); + } +} +} + +NativeThreadAIX::NativeThreadAIX(NativeProcessAIX &process, + lldb::tid_t tid) + : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid), + m_stop_info(), + m_reg_context_up( + NativeRegisterContextAIX::CreateHostNativeRegisterContextAIX( + process.GetArchitecture(), *this)), + m_stop_description() {} + +std::string NativeThreadAIX::GetName() { + NativeProcessAIX &process = GetProcess(); + + auto BufferOrError = getProcFile(process.GetID(), GetID(), "comm"); + if (!BufferOrError) + return ""; + return std::string(BufferOrError.get()->getBuffer().rtrim('\n')); +} + +lldb::StateType NativeThreadAIX::GetState() { return m_state; } + +bool NativeThreadAIX::GetStopReason(ThreadStopInfo &stop_info, + std::string &description) { + Log *log = GetLog(LLDBLog::Thread); + + description.clear(); + + switch (m_state) { + case eStateStopped: + case eStateCrashed: + case eStateExited: + case eStateSuspended: + case eStateUnloaded: + if (log) + LogThreadStopInfo(*log, m_stop_info, "m_stop_info in thread:"); + stop_info = m_stop_info; + description = m_stop_description; + if (log) + LogThreadStopInfo(*log, stop_info, "returned stop_info:"); + + return true; + + case eStateInvalid: + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + case eStateRunning: + case eStateStepping: + case eStateDetached: + if (log) { + LLDB_LOGF(log, + "NativeThreadAIX::%s tid %" PRIu64 + " in state %s cannot answer stop reason", + __FUNCTION__, GetID(), StateAsCString(m_state)); + } + return false; + } + llvm_unreachable("unhandled StateType!"); +} + +Status NativeThreadAIX::SetWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags, bool hardware) { + if (!hardware) + return Status("not implemented"); + if (m_state == eStateLaunching) + return Status(); + Status error = RemoveWatchpoint(addr); + if (error.Fail()) + return error; + uint32_t wp_index = + m_reg_context_up->SetHardwareWatchpoint(addr, size, watch_flags); + if (wp_index == LLDB_INVALID_INDEX32) + return Status("Setting hardware watchpoint failed."); + m_watchpoint_index_map.insert({addr, wp_index}); + return Status(); +} + +Status NativeThreadAIX::RemoveWatchpoint(lldb::addr_t addr) { + auto wp = m_watchpoint_index_map.find(addr); + if (wp == m_watchpoint_index_map.end()) + return Status(); + uint32_t wp_index = wp->second; + m_watchpoint_index_map.erase(wp); + if (m_reg_context_up->ClearHardwareWatchpoint(wp_index)) + return Status(); + return Status("Clearing hardware watchpoint failed."); +} + +Status NativeThreadAIX::SetHardwareBreakpoint(lldb::addr_t addr, + size_t size) { + if (m_state == eStateLaunching) + return Status(); + + Status error = RemoveHardwareBreakpoint(addr); + if (error.Fail()) + return error; + + uint32_t bp_index = m_reg_context_up->SetHardwareBreakpoint(addr, size); + + if (bp_index == LLDB_INVALID_INDEX32) + return Status("Setting hardware breakpoint failed."); + + m_hw_break_index_map.insert({addr, bp_index}); + return Status(); +} + +Status NativeThreadAIX::RemoveHardwareBreakpoint(lldb::addr_t addr) { + auto bp = m_hw_break_index_map.find(addr); + if (bp == m_hw_break_index_map.end()) + return Status(); + + uint32_t bp_index = bp->second; + if (m_reg_context_up->ClearHardwareBreakpoint(bp_index)) { + m_hw_break_index_map.erase(bp); + return Status(); + } + + return Status("Clearing hardware breakpoint failed."); +} + +Status NativeThreadAIX::Resume(uint32_t signo) { + const StateType new_state = StateType::eStateRunning; + MaybeLogStateChange(new_state); + m_state = new_state; + + m_stop_info.reason = StopReason::eStopReasonNone; + m_stop_description.clear(); + + // If watchpoints have been set, but none on this thread, then this is a new + // thread. So set all existing watchpoints. + if (m_watchpoint_index_map.empty()) { + NativeProcessAIX &process = GetProcess(); + + const auto &watchpoint_map = process.GetWatchpointMap(); + m_reg_context_up->ClearAllHardwareWatchpoints(); + for (const auto &pair : watchpoint_map) { + const auto &wp = pair.second; + SetWatchpoint(wp.m_addr, wp.m_size, wp.m_watch_flags, wp.m_hardware); + } + } + + // Set all active hardware breakpoint on all threads. + if (m_hw_break_index_map.empty()) { + NativeProcessAIX &process = GetProcess(); + + const auto &hw_breakpoint_map = process.GetHardwareBreakpointMap(); + m_reg_context_up->ClearAllHardwareBreakpoints(); + for (const auto &pair : hw_breakpoint_map) { + const auto &bp = pair.second; + SetHardwareBreakpoint(bp.m_addr, bp.m_size); + } + } + + intptr_t data = 0; + + if (signo != LLDB_INVALID_SIGNAL_NUMBER) + data = signo; + + return NativeProcessAIX::PtraceWrapper(PT_CONTINUE, GetID(), nullptr, + reinterpret_cast(data)); +} + +Status NativeThreadAIX::SingleStep(uint32_t signo) { + const StateType new_state = StateType::eStateStepping; + MaybeLogStateChange(new_state); + m_state = new_state; + m_stop_info.reason = StopReason::eStopReasonNone; + + intptr_t data = 0; + if (signo != LLDB_INVALID_SIGNAL_NUMBER) + data = signo; + + // If hardware single-stepping is not supported, we just do a continue. The + // breakpoint on the next instruction has been setup in + // NativeProcessAIX::Resume. + return NativeProcessAIX::PtraceWrapper( + GetProcess().SupportHardwareSingleStepping() ? PT_STEP : PT_CONTINUE, + m_tid, nullptr, reinterpret_cast(data)); +} + +void NativeThreadAIX::SetStoppedBySignal(uint32_t signo, + const siginfo_t *info) { + Log *log = GetLog(LLDBLog::Thread); + LLDB_LOGF(log, "NativeThreadAIX::%s called with signal 0x%02" PRIx32, + __FUNCTION__, signo); + + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonSignal; + m_stop_info.signo = signo; + + m_stop_description.clear(); + switch (signo) { + case SIGSEGV: + case SIGBUS: + case SIGFPE: + case SIGILL: + break; + } +} + +void NativeThreadAIX::AnnotateSyncTagCheckFault(const siginfo_t *info) { + int32_t allocation_tag_type = 0; + switch (GetProcess().GetArchitecture().GetMachine()) { + default: + return; + } + + auto details = + GetRegisterContext().GetMemoryTaggingDetails(allocation_tag_type); + if (!details) { + llvm::consumeError(details.takeError()); + return; + } + + // We assume that the stop description is currently: + // signal SIGSEGV: sync tag check fault (fault address: ) + // Remove the closing ) + m_stop_description.pop_back(); + + std::stringstream ss; + lldb::addr_t fault_addr = reinterpret_cast(info->si_addr); + std::unique_ptr manager(std::move(details->manager)); + + ss << " logical tag: 0x" << std::hex << manager->GetLogicalTag(fault_addr); + + std::vector allocation_tag_data; + // The fault address may not be granule aligned. ReadMemoryTags will granule + // align any range you give it, potentially making it larger. + // To prevent this set len to 1. This always results in a range that is at + // most 1 granule in size and includes fault_addr. + Status status = GetProcess().ReadMemoryTags(allocation_tag_type, fault_addr, + 1, allocation_tag_data); + + if (status.Success()) { + llvm::Expected> allocation_tag = + manager->UnpackTagsData(allocation_tag_data, 1); + if (allocation_tag) { + ss << " allocation tag: 0x" << std::hex << allocation_tag->front() << ")"; + } else { + llvm::consumeError(allocation_tag.takeError()); + ss << ")"; + } + } else + ss << ")"; + + m_stop_description += ss.str(); +} + +bool NativeThreadAIX::IsStopped(int *signo) { + if (!StateIsStoppedState(m_state, false)) + return false; + + // If we are stopped by a signal, return the signo. + if (signo && m_state == StateType::eStateStopped && + m_stop_info.reason == StopReason::eStopReasonSignal) { + *signo = m_stop_info.signo; + } + + // Regardless, we are stopped. + return true; +} + +void NativeThreadAIX::SetStopped() { + // On every stop, clear any cached register data structures + GetRegisterContext().InvalidateAllRegisters(); + + const StateType new_state = StateType::eStateStopped; + MaybeLogStateChange(new_state); + m_state = new_state; + m_stop_description.clear(); +} + +void NativeThreadAIX::SetStoppedByExec() { + Log *log = GetLog(LLDBLog::Thread); + LLDB_LOGF(log, "NativeThreadAIX::%s()", __FUNCTION__); + + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonExec; + m_stop_info.signo = SIGSTOP; +} + +void NativeThreadAIX::SetStoppedByBreakpoint() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonBreakpoint; + m_stop_info.signo = SIGTRAP; + m_stop_description.clear(); +} + +void NativeThreadAIX::SetStoppedByWatchpoint(uint32_t wp_index) { + SetStopped(); + + lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); + + std::ostringstream ostr; + ostr << m_reg_context_up->GetWatchpointAddress(wp_index) << " "; + ostr << wp_index; + + /* + * MIPS: Last 3bits of the watchpoint address are masked by the kernel. For + * example: + * 'n' is at 0x120010d00 and 'm' is 0x120010d04. When a watchpoint is set at + * 'm', then + * watch exception is generated even when 'n' is read/written. To handle this + * case, + * find the base address of the load/store instruction and append it in the + * stop-info + * packet. + */ + ostr << " " << m_reg_context_up->GetWatchpointHitAddress(wp_index); + + m_stop_description = ostr.str(); + + m_stop_info.reason = StopReason::eStopReasonWatchpoint; + m_stop_info.signo = SIGTRAP; +} + +bool NativeThreadAIX::IsStoppedAtBreakpoint() { + return GetState() == StateType::eStateStopped && + m_stop_info.reason == StopReason::eStopReasonBreakpoint; +} + +bool NativeThreadAIX::IsStoppedAtWatchpoint() { + return GetState() == StateType::eStateStopped && + m_stop_info.reason == StopReason::eStopReasonWatchpoint; +} + +void NativeThreadAIX::SetStoppedByTrace() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonTrace; + m_stop_info.signo = SIGTRAP; +} + +void NativeThreadAIX::SetStoppedByFork(bool is_vfork, lldb::pid_t child_pid) { + SetStopped(); + + m_stop_info.reason = + is_vfork ? StopReason::eStopReasonVFork : StopReason::eStopReasonFork; + m_stop_info.details.fork.child_pid = child_pid; + m_stop_info.details.fork.child_tid = child_pid; +} + +void NativeThreadAIX::SetStoppedByVForkDone() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonVForkDone; +} + +void NativeThreadAIX::SetStoppedWithNoReason() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonNone; + m_stop_info.signo = 0; +} + +void NativeThreadAIX::SetStoppedByProcessorTrace( + llvm::StringRef description) { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonProcessorTrace; + m_stop_info.signo = 0; + m_stop_description = description.str(); +} + +void NativeThreadAIX::SetExited() { + const StateType new_state = StateType::eStateExited; + MaybeLogStateChange(new_state); + m_state = new_state; + + m_stop_info.reason = StopReason::eStopReasonThreadExiting; +} + +Status NativeThreadAIX::RequestStop() { + Log *log = GetLog(LLDBLog::Thread); + + NativeProcessAIX &process = GetProcess(); + + lldb::pid_t pid = process.GetID(); + lldb::tid_t tid = GetID(); + + LLDB_LOGF(log, + "NativeThreadAIX::%s requesting thread stop(pid: %" PRIu64 + ", tid: %" PRIu64 ")", + __FUNCTION__, pid, tid); + + Status err; + errno = 0; + if (::kill(pid, SIGSTOP) != 0) { + err.SetErrorToErrno(); + LLDB_LOGF(log, + "NativeThreadAIX::%s kill(%" PRIu64 ", SIGSTOP) failed: %s", + __FUNCTION__, pid, err.AsCString()); + } + return err; +} + +void NativeThreadAIX::MaybeLogStateChange(lldb::StateType new_state) { + Log *log = GetLog(LLDBLog::Thread); + // If we're not logging, we're done. + if (!log) + return; + + // If this is a state change to the same state, we're done. + lldb::StateType old_state = m_state; + if (new_state == old_state) + return; + + LLDB_LOG(log, "pid={0}, tid={1}: changing from state {2} to {3}", + m_process.GetID(), GetID(), old_state, new_state); +} + +NativeProcessAIX &NativeThreadAIX::GetProcess() { + return static_cast(m_process); +} + +const NativeProcessAIX &NativeThreadAIX::GetProcess() const { + return static_cast(m_process); +} + +llvm::Expected> +NativeThreadAIX::GetSiginfo() const { + auto siginfo_buf = + llvm::WritableMemoryBuffer::getNewUninitMemBuffer(sizeof(siginfo_t)); +#if 0 + Status error = + GetProcess().GetSignalInfo(GetID(), siginfo_buf->getBufferStart()); + if (!error.Success()) + return error.ToError(); +#endif + return std::move(siginfo_buf); +} diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h new file mode 100644 index 0000000000000..706a7ce69da8e --- /dev/null +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h @@ -0,0 +1,126 @@ +//===-- NativeThreadAIX.h ----------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeThreadAIX_H_ +#define liblldb_NativeThreadAIX_H_ + +#include "Plugins/Process/AIX/NativeRegisterContextAIX.h" +#include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/lldb-private-forward.h" + +#include "llvm/ADT/StringRef.h" + +#include +#include +#include +#include + +namespace lldb_private { +namespace process_aix { + +class NativeProcessAIX; + +class NativeThreadAIX : public NativeThreadProtocol { + friend class NativeProcessAIX; + +public: + NativeThreadAIX(NativeProcessAIX &process, lldb::tid_t tid); + + // NativeThreadProtocol Interface + std::string GetName() override; + + lldb::StateType GetState() override; + + bool GetStopReason(ThreadStopInfo &stop_info, + std::string &description) override; + + NativeRegisterContextAIX &GetRegisterContext() override { + return *m_reg_context_up; + } + + Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, + bool hardware) override; + + Status RemoveWatchpoint(lldb::addr_t addr) override; + + Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override; + + Status RemoveHardwareBreakpoint(lldb::addr_t addr) override; + + NativeProcessAIX &GetProcess(); + + const NativeProcessAIX &GetProcess() const; + + llvm::Expected> + GetSiginfo() const override; + +private: + // Interface for friend classes + + /// Resumes the thread. If \p signo is anything but + /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. + Status Resume(uint32_t signo); + + /// Single steps the thread. If \p signo is anything but + /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. + Status SingleStep(uint32_t signo); + + void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr); + + /// Return true if the thread is stopped. + /// If stopped by a signal, indicate the signo in the signo argument. + /// Otherwise, return LLDB_INVALID_SIGNAL_NUMBER. + bool IsStopped(int *signo); + + void SetStoppedByExec(); + + void SetStoppedByBreakpoint(); + + void SetStoppedByWatchpoint(uint32_t wp_index); + + bool IsStoppedAtBreakpoint(); + + bool IsStoppedAtWatchpoint(); + + void SetStoppedByTrace(); + + void SetStoppedByFork(bool is_vfork, lldb::pid_t child_pid); + + void SetStoppedByVForkDone(); + + void SetStoppedWithNoReason(); + + void SetStoppedByProcessorTrace(llvm::StringRef description); + + void SetExited(); + + Status RequestStop(); + + // Private interface + void MaybeLogStateChange(lldb::StateType new_state); + + void SetStopped(); + + /// Extend m_stop_description with logical and allocation tag values. + /// If there is an error along the way just add the information we were able + /// to get. + void AnnotateSyncTagCheckFault(const siginfo_t *info); + + // Member Variables + lldb::StateType m_state; + ThreadStopInfo m_stop_info; + std::unique_ptr m_reg_context_up; + std::string m_stop_description; + using WatchpointIndexMap = std::map; + WatchpointIndexMap m_watchpoint_index_map; + WatchpointIndexMap m_hw_break_index_map; +}; +} // namespace process_aix +} // namespace lldb_private + +#endif // #ifndef liblldb_NativeThreadAIX_H_ diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt index a51d0f7afd175..01bb5f462eba4 100644 --- a/lldb/source/Plugins/Process/CMakeLists.txt +++ b/lldb/source/Plugins/Process/CMakeLists.txt @@ -7,6 +7,9 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD") add_subdirectory(NetBSD) add_subdirectory(POSIX) +elseif (CMAKE_SYSTEM_NAME MATCHES "AIX") + add_subdirectory(AIX) + add_subdirectory(POSIX) elseif (CMAKE_SYSTEM_NAME MATCHES "Windows") add_subdirectory(Windows/Common) elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin") diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 32c71d87c7f58..db271357d792a 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -46,8 +46,34 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, function_options.include_inlines = false; SymbolContextList sc_list; +#if !defined(__AIX__) process->GetTarget().GetImages().FindFunctions( ConstString("mmap"), eFunctionNameTypeFull, function_options, sc_list); +#else + process->GetTarget().GetImages().FindFunctions( + ConstString("mmap64"), eFunctionNameTypeFull, function_options, sc_list); + SymbolContextList toc_list; + process->GetTarget().GetImages().FindSymbolsWithNameAndType( + ConstString("TOC"), lldb::eSymbolTypeAny, toc_list); + + AddressRange toc_range; + if (sc_list.GetSize() > 0) { + SymbolContext sc; + if (sc_list.GetContextAtIndex(0, sc)) { + for (int i = 0; i < toc_list.GetSize(); ++i) { + SymbolContext tocSC; + if (toc_list.GetContextAtIndex(i, tocSC)) { + if (tocSC.module_sp == sc.module_sp) { + if (tocSC.GetAddressRange(eSymbolContextSymbol, 0, false, + toc_range)) { + break; + } + } + } + } + } + } +#endif const uint32_t count = sc_list.GetSize(); if (count > 0) { SymbolContext sc; @@ -96,9 +122,16 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, MmapArgList args = process->GetTarget().GetPlatform()->GetMmapArgumentList( arch, addr, length, prot_arg, flags, fd, offset); +#if defined(__AIX__) + lldb::ThreadPlanSP call_plan_sp( + new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(), + toc_range.GetBaseAddress(), + void_ptr_type, args, options)); +#else lldb::ThreadPlanSP call_plan_sp( new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(), void_ptr_type, args, options)); +#endif if (call_plan_sp) { DiagnosticManager diagnostics; diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp index 159fd2856443c..d9b41d595147f 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp @@ -23,6 +23,8 @@ static const lldb_private::RegisterInfo * GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { + //HH + case llvm::Triple::ppc64: case llvm::Triple::ppc64le: return g_register_infos_ppc64le; default: @@ -34,6 +36,8 @@ GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) { static uint32_t GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { + //HitchHike + case llvm::Triple::ppc64: case llvm::Triple::ppc64le: return static_cast(sizeof(g_register_infos_ppc64le) / sizeof(g_register_infos_ppc64le[0])); diff --git a/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp b/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp index 89ecc757a68f5..550b53688fd39 100644 --- a/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp +++ b/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp @@ -20,7 +20,7 @@ using namespace lldb; using namespace lldb_private; -ThreadMemory::ThreadMemory(Process &process, tid_t tid, +ThreadMemory::ThreadMemory(Process &process, lldb::tid_t tid, const ValueObjectSP &thread_info_valobj_sp) : Thread(process, tid), m_backing_thread_sp(), m_thread_info_valobj_sp(thread_info_valobj_sp), m_name(), m_queue(), diff --git a/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt b/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt index 6755999b18185..4eddbb5ec4cfd 100644 --- a/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt +++ b/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt @@ -6,6 +6,11 @@ lldb_tablegen(ProcessGDBRemotePropertiesEnum.inc -gen-lldb-property-enum-defs SOURCE ProcessGDBRemoteProperties.td TARGET LLDBPluginProcessGDBRemotePropertiesEnumGen) +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + set(LLDB_PLUGINS lldbPluginProcessUtility ) diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 74e392249a94e..b7ecf7a5dc328 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -40,6 +40,10 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/JSON.h" +#if defined(__AIX__) +#include +#endif + #if defined(HAVE_LIBCOMPRESSION) #include #endif @@ -1710,6 +1714,32 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( return error; } +#if defined(__AIX__) +Status GDBRemoteCommunicationClient::GetLDXINFO(struct ld_xinfo *info_ptr) +{ + Status error; + + char packet[64]; + const int packet_len = ::snprintf(packet, sizeof(packet), "qLDXINFO"); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response) == + PacketResult::Success && + response.GetResponseType() == StringExtractorGDBRemote::eResponse) { + llvm::MutableArrayRef infoData((uint8_t *)info_ptr, sizeof(struct ld_xinfo)*64); + size_t got_bytes = response.GetHexBytesAvail(infoData); + if (got_bytes != sizeof(struct ld_xinfo)*64) { + error.SetErrorString("qLDXINFO ret bad size"); + return error; + } + } else { + error.SetErrorString("qLDXINFO is not supported"); + } + return error; +} +#endif + Status GDBRemoteCommunicationClient::GetQXferMemoryMapRegionInfo( lldb::addr_t addr, MemoryRegionInfo ®ion) { Status error = LoadQXferMemoryMap(); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 898d176abc346..520f37ac56716 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -32,6 +32,10 @@ #include "llvm/Support/VersionTuple.h" +#if defined(__AIX__) +struct ld_xinfo; +#endif + namespace lldb_private { namespace process_gdb_remote { @@ -196,6 +200,9 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase { Status GetMemoryRegionInfo(lldb::addr_t addr, MemoryRegionInfo &range_info); std::optional GetWatchpointSlotCount(); +#if defined(__AIX__) + Status GetLDXINFO(struct ld_xinfo *info_ptr); +#endif std::optional GetWatchpointReportedAfter(); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index a0b08a219ae14..f019062986925 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -48,6 +48,9 @@ #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "lldb/Utility/StringExtractorGDBRemote.h" +#if defined(__AIX__) +#include +#endif using namespace lldb; using namespace lldb_private; @@ -193,6 +196,8 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { &GDBRemoteCommunicationServerLLGS::Handle_Z); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_z, &GDBRemoteCommunicationServerLLGS::Handle_z); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLDXINFO, + &GDBRemoteCommunicationServerLLGS::Handle_qLDXINFO); RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_QPassSignals, &GDBRemoteCommunicationServerLLGS::Handle_QPassSignals); @@ -3006,6 +3011,29 @@ GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) { } } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_qLDXINFO(StringExtractorGDBRemote &packet) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { + Log *log = GetLog(LLDBLog::Process); + LLDB_LOG(log, "qLDXINFO failed, no process available"); + return SendErrorResponse(0xff); + } + +#if defined(__AIX__) + // FIXME: buffer size + struct ld_xinfo info[64]; + if (ptrace64(PT_LDXINFO, m_current_process->GetID(), (long long)&(info[0]), sizeof(info), nullptr) != 0) { + return SendErrorResponse(0xff); + } + StreamGDBRemote response; + response.PutBytesAsRawHex8(&(info[0]), sizeof(info)); + return SendPacketNoLock(response.GetString()); +#else + return SendErrorResponse(0xff); +#endif +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index 646b6a102abf6..a464479e178de 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -211,6 +211,8 @@ class GDBRemoteCommunicationServerLLGS PacketResult Handle_z(StringExtractorGDBRemote &packet); + PacketResult Handle_qLDXINFO(StringExtractorGDBRemote &packet); + PacketResult Handle_s(StringExtractorGDBRemote &packet); PacketResult Handle_qXfer(StringExtractorGDBRemote &packet); diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 6f9c2cc1e4b4e..10fbaa2b3c837 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -92,6 +92,10 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/raw_ostream.h" +#if defined(__AIX__) +#include +#endif + #define DEBUGSERVER_BASENAME "debugserver" using namespace lldb; using namespace lldb_private; @@ -1513,7 +1517,7 @@ bool ProcessGDBRemote::DoUpdateThreadList(ThreadList &old_thread_list, ThreadList old_thread_list_copy(old_thread_list); if (num_thread_ids > 0) { for (size_t i = 0; i < num_thread_ids; ++i) { - tid_t tid = m_thread_ids[i]; + lldb::tid_t tid = m_thread_ids[i]; ThreadSP thread_sp( old_thread_list_copy.RemoveThreadByProtocolID(tid, false)); if (!thread_sp) { @@ -2945,6 +2949,13 @@ Status ProcessGDBRemote::DoGetMemoryRegionInfo(addr_t load_addr, return error; } +#if defined(__AIX__) +Status ProcessGDBRemote::DoGetLDXINFO(struct ld_xinfo *info_ptr) { + Status error(m_gdb_comm.GetLDXINFO(info_ptr)); + return error; +} +#endif + std::optional ProcessGDBRemote::GetWatchpointSlotCount() { return m_gdb_comm.GetWatchpointSlotCount(); } diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 2492795851388..82200fbea21cd 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -37,6 +37,10 @@ #include "GDBRemoteCommunicationClient.h" #include "GDBRemoteRegisterContext.h" +#if defined(__AIX__) +struct ld_xinfo; +#endif + #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" @@ -423,6 +427,10 @@ class ProcessGDBRemote : public Process, Status DoGetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo ®ion_info) override; +#if defined(__AIX__) + Status DoGetLDXINFO(struct ld_xinfo *info_ptr) override; +#endif + private: // For ProcessGDBRemote only std::string m_partial_profile_data; diff --git a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp index 1da7696c9a352..930c707604bb3 100644 --- a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp +++ b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp @@ -593,19 +593,19 @@ bool ProcessMachCore::DoUpdateThreadList(ThreadList &old_thread_list, ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); if (core_objfile) { - std::set used_tids; + std::set used_tids; const uint32_t num_threads = core_objfile->GetNumThreadContexts(); - std::vector tids; + std::vector tids; if (core_objfile->GetCorefileThreadExtraInfos(tids)) { assert(tids.size() == num_threads); // Find highest tid value. - tid_t highest_tid = 0; + lldb::tid_t highest_tid = 0; for (uint32_t i = 0; i < num_threads; i++) { if (tids[i] != LLDB_INVALID_THREAD_ID && tids[i] > highest_tid) highest_tid = tids[i]; } - tid_t current_unused_tid = highest_tid + 1; + lldb::tid_t current_unused_tid = highest_tid + 1; for (uint32_t i = 0; i < num_threads; i++) { if (tids[i] == LLDB_INVALID_THREAD_ID) { tids[i] = current_unused_tid++; diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt index 7523d65abf0f8..1ce60a0b66154 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt +++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt @@ -20,6 +20,11 @@ if (LLDB_ENABLE_LIBEDIT) endif() add_subdirectory(Interfaces) +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + add_lldb_library(lldbPluginScriptInterpreterPython PLUGIN PythonDataObjects.cpp diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp index e1f73f1997e36..92882cfc3da31 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -500,6 +500,8 @@ dw_addr_t DWARFFormValue::Address() const { &offset, index_size); } +bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; + std::pair DWARFFormValue::ReferencedUnitAndOffset() const { uint64_t value = m_value.value.uval; @@ -512,6 +514,8 @@ DWARFFormValue::ReferencedUnitAndOffset() const { assert(m_unit); // Unit must be valid for DW_FORM_ref forms that are compile // unit relative or we will get this wrong value += m_unit->GetOffset(); + if (UGLY_FLAG_FOR_AIX) + value -= 8; if (!m_unit->ContainsDIEOffset(value)) { m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( "DW_FORM_ref* DIE reference {0:x16} is outside of its CU", value); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index 66a762bf9b685..6721c1895a576 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -924,6 +924,12 @@ const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() { return *m_func_aranges_up; } +/* AIX-NOTE - TODO: Removed conflicting code due to merge conflicts + * Refer Patches: 27,28,29,30,35 and 76 + * and modify the code accordingly. */ + +bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; + llvm::Expected DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid, const DWARFDataExtractor &debug_info, @@ -1002,6 +1008,10 @@ const lldb_private::DWARFDataExtractor &DWARFUnit::GetData() const { uint32_t DWARFUnit::GetHeaderByteSize() const { switch (m_header.getUnitType()) { case llvm::dwarf::DW_UT_compile: + if (UGLY_FLAG_FOR_AIX) + return 11 + 4/*GetDWARFSizeOfOffset*/; + else + return GetVersion() < 5 ? 11 : 12; case llvm::dwarf::DW_UT_partial: return GetVersion() < 5 ? 11 : 12; case llvm::dwarf::DW_UT_skeleton: @@ -1016,7 +1026,7 @@ uint32_t DWARFUnit::GetHeaderByteSize() const { std::optional DWARFUnit::GetStringOffsetSectionItem(uint32_t index) const { - offset_t offset = GetStrOffsetsBase() + index * 4; + lldb::offset_t offset = GetStrOffsetsBase() + index * 4; return m_dwarf.GetDWARFContext().getOrLoadStrOffsetsData().GetU32(&offset); } diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp index 2064b73dc3ea5..824528fc3acfa 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp @@ -216,7 +216,7 @@ lldb::addr_t AppleGetThreadItemInfoHandler::SetupGetThreadItemInfoFunction( AppleGetThreadItemInfoHandler::GetThreadItemInfoReturnInfo AppleGetThreadItemInfoHandler::GetThreadItemInfo(Thread &thread, - tid_t thread_id, + lldb::tid_t thread_id, addr_t page_to_free, uint64_t page_to_free_size, Status &error) { diff --git a/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/lldb/source/Symbol/DWARFCallFrameInfo.cpp index f3df8a2c27f5a..de244e372579d 100644 --- a/lldb/source/Symbol/DWARFCallFrameInfo.cpp +++ b/lldb/source/Symbol/DWARFCallFrameInfo.cpp @@ -33,7 +33,7 @@ using namespace lldb_private::dwarf; // Used for calls when the value type is specified by a DWARF EH Frame pointer // encoding. static uint64_t -GetGNUEHPointer(const DataExtractor &DE, offset_t *offset_ptr, +GetGNUEHPointer(const DataExtractor &DE, lldb::offset_t *offset_ptr, uint32_t eh_ptr_enc, addr_t pc_rel_addr, addr_t text_addr, addr_t data_addr) //, BSDRelocs *data_relocs) const { @@ -588,7 +588,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset, if (cie->augmentation[0] == 'z') { uint32_t aug_data_len = (uint32_t)m_cfi_data.GetULEB128(&offset); if (aug_data_len != 0 && cie->lsda_addr_encoding != DW_EH_PE_omit) { - offset_t saved_offset = offset; + lldb::offset_t saved_offset = offset; lsda_data_file_address = GetGNUEHPointer(m_cfi_data, &offset, cie->lsda_addr_encoding, pc_rel_addr, text_addr, data_addr); diff --git a/lldb/source/Target/ABI.cpp b/lldb/source/Target/ABI.cpp index 110b5c86fc425..6df03533cda29 100644 --- a/lldb/source/Target/ABI.cpp +++ b/lldb/source/Target/ABI.cpp @@ -208,6 +208,15 @@ bool ABI::PrepareTrivialCall(Thread &thread, lldb::addr_t sp, llvm_unreachable("Should never get here!"); } +bool ABI::PrepareTrivialCall(Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t tocAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef args) const { + // dummy prepare trivial call + llvm_unreachable("Should never get here!"); +} + bool ABI::GetFallbackRegisterLocation( const RegisterInfo *reg_info, UnwindPlan::Row::RegisterLocation &unwind_regloc) { diff --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt index a42c44b761dc5..833489b16dfd7 100644 --- a/lldb/source/Target/CMakeLists.txt +++ b/lldb/source/Target/CMakeLists.txt @@ -1,3 +1,8 @@ +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + lldb_tablegen(TargetProperties.inc -gen-lldb-property-defs SOURCE TargetProperties.td TARGET LLDBTargetPropertiesGen) diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index e3c4f2ee398cc..e31245178b2f2 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -75,6 +75,10 @@ #include "lldb/Utility/State.h" #include "lldb/Utility/Timer.h" +#if defined(__AIX__) +#include +#endif + using namespace lldb; using namespace lldb_private; using namespace std::chrono; @@ -6206,6 +6210,12 @@ Status Process::GetMemoryRegionInfo(lldb::addr_t load_addr, return DoGetMemoryRegionInfo(load_addr, range_info); } +#if defined(__AIX__) +Status Process::GetLDXINFO(struct ld_xinfo *info_ptr) { + return DoGetLDXINFO(info_ptr); +} +#endif + Status Process::GetMemoryRegions(lldb_private::MemoryRegionInfos ®ion_list) { Status error; diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index a61228d092d89..57f42ea56cb18 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -40,6 +40,9 @@ #include #include +#ifdef __AIX__ +#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" +#endif using namespace lldb; using namespace lldb_private; @@ -1257,6 +1260,10 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( // Answer the question: Where did THIS frame save the CALLER frame ("previous" // frame)'s register value? +#ifdef __AIX__ +extern bool UGLY_HACK_NULL_TOPFRAME; +#endif + enum UnwindLLDB::RegisterSearchResult RegisterContextUnwind::SavedLocationForRegister( uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc) { @@ -1517,6 +1524,11 @@ RegisterContextUnwind::SavedLocationForRegister( new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext; new_regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); +#ifdef __AIX__ + if (UGLY_HACK_NULL_TOPFRAME && new_regloc.location.register_number == 0x20) { + new_regloc.location.register_number = 0x24; + } +#endif m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; regloc = new_regloc; UnwindLogMsg("supplying caller's register %s (%d) from the live " @@ -2368,6 +2380,40 @@ bool RegisterContextUnwind::ReadPC(addr_t &pc) { } } +#ifdef __AIX__ +bool RegisterContextUnwind::ReadLR(addr_t &lr) { + if (!IsValid()) + return false; + + bool above_trap_handler = false; + if (GetNextFrame().get() && GetNextFrame()->IsValid() && + GetNextFrame()->IsTrapHandlerFrame()) + above_trap_handler = true; + + if (ReadGPRValue(eRegisterKindLLDB, gpr_lr_ppc64le, lr)) { + // A lr value of 0 or 1 is impossible in the middle of the stack -- it + // indicates the end of a stack walk. + // On the currently executing frame (or such a frame interrupted + // asynchronously by sigtramp et al) this may occur if code has jumped + // through a NULL pointer -- we want to be able to unwind past that frame + // to help find the bug. + + ProcessSP process_sp (m_thread.GetProcess()); + if (process_sp) + { + ABI *abi = process_sp->GetABI().get(); + if (abi) + lr = abi->FixCodeAddress(lr); + } + + return !(m_all_registers_available == false && + above_trap_handler == false && (lr == 0 || lr == 1)); + } else { + return false; + } +} +#endif + void RegisterContextUnwind::UnwindLogMsg(const char *fmt, ...) { Log *log = GetLog(LLDBLog::Unwind); if (!log) diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp index 50dcb66b9719f..0926579ea2930 100644 --- a/lldb/source/Target/ThreadPlanCallFunction.cpp +++ b/lldb/source/Target/ThreadPlanCallFunction.cpp @@ -127,6 +127,40 @@ ThreadPlanCallFunction::ThreadPlanCallFunction( m_valid = true; } +ThreadPlanCallFunction::ThreadPlanCallFunction( + Thread &thread, const Address &function, const Address &toc, + const CompilerType &return_type, + llvm::ArrayRef args, const EvaluateExpressionOptions &options) + : ThreadPlan(ThreadPlan::eKindCallFunction, "Call function plan", thread, + eVoteNoOpinion, eVoteNoOpinion), + m_valid(false), m_stop_other_threads(options.GetStopOthers()), + m_unwind_on_error(options.DoesUnwindOnError()), + m_ignore_breakpoints(options.DoesIgnoreBreakpoints()), + m_debug_execution(options.GetDebug()), + m_trap_exceptions(options.GetTrapExceptions()), m_function_addr(function), + m_function_sp(0), m_takedown_done(false), + m_should_clear_objc_exception_bp(false), + m_should_clear_cxx_exception_bp(false), + m_stop_address(LLDB_INVALID_ADDRESS), m_return_type(return_type) { + lldb::addr_t start_load_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t function_load_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t toc_addr = LLDB_INVALID_ADDRESS; + ABI *abi = nullptr; + + if (!ConstructorSetup(thread, abi, start_load_addr, function_load_addr)) + return; + + toc_addr = toc.GetLoadAddress(&GetTarget()); + + if (!abi->PrepareTrivialCall(thread, m_function_sp, function_load_addr, + toc_addr, start_load_addr, args)) + return; + + ReportRegisterState("Function call was set up. Register state was:"); + + m_valid = true; +} + ThreadPlanCallFunction::ThreadPlanCallFunction( Thread &thread, const Address &function, const EvaluateExpressionOptions &options) diff --git a/lldb/source/Target/UnwindLLDB.cpp b/lldb/source/Target/UnwindLLDB.cpp index f43e940492b09..255b829738ba2 100644 --- a/lldb/source/Target/UnwindLLDB.cpp +++ b/lldb/source/Target/UnwindLLDB.cpp @@ -68,6 +68,10 @@ uint32_t UnwindLLDB::DoGetFrameCount() { return m_frames.size(); } +#ifdef __AIX__ +bool UGLY_HACK_NULL_TOPFRAME = false; +#endif + bool UnwindLLDB::AddFirstFrame() { if (m_frames.size() > 0) return true; @@ -91,6 +95,17 @@ bool UnwindLLDB::AddFirstFrame() { if (!reg_ctx_sp->ReadPC(first_cursor_sp->start_pc)) goto unwind_done; +#ifdef __AIX__ + lldb::addr_t lr; + if (!reg_ctx_sp->ReadLR(lr)) + goto unwind_done; + + if (first_cursor_sp->start_pc == 0) { + first_cursor_sp->start_pc = lr; + UGLY_HACK_NULL_TOPFRAME = true; + } +#endif + // Everything checks out, so release the auto pointer value and let the // cursor own it in its shared pointer first_cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp; diff --git a/lldb/source/Utility/ArchSpec.cpp b/lldb/source/Utility/ArchSpec.cpp index 07ef435ef451d..3868f77169cc6 100644 --- a/lldb/source/Utility/ArchSpec.cpp +++ b/lldb/source/Utility/ArchSpec.cpp @@ -14,6 +14,7 @@ #include "lldb/lldb-defines.h" #include "llvm/ADT/STLExtras.h" #include "llvm/BinaryFormat/COFF.h" +#include "llvm/BinaryFormat/XCOFF.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Compiler.h" @@ -459,10 +460,22 @@ static const ArchDefinition g_coff_arch_def = { "pe-coff", }; +static const ArchDefinitionEntry g_xcoff_arch_entries[] = { + {ArchSpec::eCore_ppc_generic, llvm::XCOFF::TCPU_COM, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, + {ArchSpec::eCore_ppc64_generic, llvm::XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu} +}; + +static const ArchDefinition g_xcoff_arch_def = { + eArchTypeXCOFF, + std::size(g_xcoff_arch_entries), + g_xcoff_arch_entries, + "xcoff", +}; + //===----------------------------------------------------------------------===// // Table of all ArchDefinitions static const ArchDefinition *g_arch_definitions[] = { - &g_macho_arch_def, &g_elf_arch_def, &g_coff_arch_def}; + &g_macho_arch_def, &g_elf_arch_def, &g_coff_arch_def, &g_xcoff_arch_def}; //===----------------------------------------------------------------------===// // Static helper functions. @@ -903,6 +916,9 @@ bool ArchSpec::SetArchitecture(ArchitectureType arch_type, uint32_t cpu, } else if (arch_type == eArchTypeCOFF && os == llvm::Triple::Win32) { m_triple.setVendor(llvm::Triple::PC); m_triple.setOS(llvm::Triple::Win32); + } else if (arch_type == eArchTypeXCOFF && os == llvm::Triple::AIX) { + m_triple.setVendor(llvm::Triple::IBM); + m_triple.setOS(llvm::Triple::AIX); } else { m_triple.setVendor(llvm::Triple::UnknownVendor); m_triple.setOS(llvm::Triple::UnknownOS); diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp index 9f79d2271b1e6..dbd3236536f8c 100644 --- a/lldb/source/Utility/StringExtractorGDBRemote.cpp +++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -227,6 +227,8 @@ StringExtractorGDBRemote::GetServerPacketType() const { return eServerPacketType_qLaunchGDBServer; if (PACKET_MATCHES("qLaunchSuccess")) return eServerPacketType_qLaunchSuccess; + if (PACKET_MATCHES("qLDXINFO")) + return eServerPacketType_qLDXINFO; break; case 'M': diff --git a/lldb/test/CMakeLists.txt b/lldb/test/CMakeLists.txt index 5ac474736eb63..413a1e5120288 100644 --- a/lldb/test/CMakeLists.txt +++ b/lldb/test/CMakeLists.txt @@ -155,7 +155,7 @@ if(TARGET clang) add_lldb_test_dependency(clang) # TestFullLtoStepping depends on LTO, and only runs when the compiler is clang. - add_lldb_test_dependency(LTO) + #add_lldb_test_dependency(LTO) if (TARGET libcxx OR ("libcxx" IN_LIST LLVM_ENABLE_RUNTIMES)) set(LLDB_HAS_LIBCXX ON) diff --git a/lldb/test/Shell/Expr/TestIRMemoryMap.test b/lldb/test/Shell/Expr/TestIRMemoryMap.test index 9dd0413be14cf..5ed61ad33ffc4 100644 --- a/lldb/test/Shell/Expr/TestIRMemoryMap.test +++ b/lldb/test/Shell/Expr/TestIRMemoryMap.test @@ -1,6 +1,6 @@ # UNSUPPORTED: system-windows -# RUN: %clangxx_host %p/Inputs/call-function.cpp -g -o %t +# RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t # RUN: lldb-test ir-memory-map %t %S/Inputs/ir-memory-map-basic # RUN: lldb-test ir-memory-map -host-only %t %S/Inputs/ir-memory-map-basic diff --git a/lldb/test/Shell/Process/TestEnvironment.test b/lldb/test/Shell/Process/TestEnvironment.test index e6d6e56fc9203..2ead258719f32 100644 --- a/lldb/test/Shell/Process/TestEnvironment.test +++ b/lldb/test/Shell/Process/TestEnvironment.test @@ -3,7 +3,7 @@ UNSUPPORTED: lldb-repro The double quotes around "BAR" ensure we don't match the command. -RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t +RUN: %clangxx_host -std=c++11 -I/compgpfs/build/xlcit/rings/openxlC/aix/wyvern_dev/ring0/latest/opt/IBM/openxlC/17.1.2/include/c++/v1/ %p/Inputs/env.cpp -o %t RUN: %lldb %t -o 'process launch --environment FOO="BAR"' | FileCheck %s RUN: %lldb %t -o 'env FOO="BAR"' -o 'process launch' | FileCheck %s diff --git a/lldb/tools/driver/CMakeLists.txt b/lldb/tools/driver/CMakeLists.txt index cd304a047dea6..78617be24f780 100644 --- a/lldb/tools/driver/CMakeLists.txt +++ b/lldb/tools/driver/CMakeLists.txt @@ -11,6 +11,11 @@ if(APPLE) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_BINARY_DIR}/lldb-Info.plist") endif() +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + remove_definitions("-D_XOPEN_SOURCE=700") + add_definitions("-D_ALL_SOURCE") +endif() + add_lldb_tool(lldb Driver.cpp Platform.cpp diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp index 14371da64f2f2..f7eaf56738d7d 100644 --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -639,7 +639,7 @@ void sigwinch_handler(int signo) { } void sigint_handler(int signo) { -#ifdef _WIN32 // Restore handler as it is not persistent on Windows +#if defined(_WIN32) || defined(__AIX__) // Restore handler as it is not persistent on Windows signal(SIGINT, sigint_handler); #endif static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT; @@ -727,8 +727,11 @@ static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) { int main(int argc, char const *argv[]) { // Editline uses for example iswprint which is dependent on LC_CTYPE. + // FIXME: this caused unexpected SIGTRAP on AIX +#ifndef __AIX__ std::setlocale(LC_ALL, ""); std::setlocale(LC_CTYPE, ""); +#endif // Setup LLVM signal handlers and make sure we call llvm_shutdown() on // destruction. diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index f8f0d86453f58..2fa6f6c9a5369 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -6,6 +6,10 @@ if (HAVE_LIBPTHREAD) list(APPEND extra_libs pthread) endif () +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + add_definitions("-D_AIX") + add_definitions("-D_ALL_SOURCE") +endif() if(APPLE) configure_file( diff --git a/lldb/tools/lldb-server/CMakeLists.txt b/lldb/tools/lldb-server/CMakeLists.txt index 9030ed709a647..0d69ae32a008f 100644 --- a/lldb/tools/lldb-server/CMakeLists.txt +++ b/lldb/tools/lldb-server/CMakeLists.txt @@ -8,6 +8,10 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux|Android") list(APPEND LLDB_PLUGINS lldbPluginProcessLinux) endif() +if(CMAKE_SYSTEM_NAME MATCHES "AIX") + list(APPEND LLDB_PLUGINS lldbPluginProcessAIX) +endif() + if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") list(APPEND LLDB_PLUGINS lldbPluginProcessFreeBSD) endif() @@ -20,6 +24,8 @@ if(CMAKE_SYSTEM_NAME MATCHES "Darwin") list(APPEND LLDB_PLUGINS lldbPluginObjectFileMachO) elseif(CMAKE_SYSTEM_NAME MATCHES "Windows") list(APPEND LLDB_PLUGINS lldbPluginObjectFilePECOFF) +elseif(CMAKE_SYSTEM_NAME MATCHES "AIX") + list(APPEND LLDB_PLUGINS lldbPluginObjectFileXCOFF) else() list(APPEND LLDB_PLUGINS lldbPluginObjectFileELF) endif() @@ -54,6 +60,7 @@ add_lldb_tool(lldb-server lldbPluginInstructionMIPS lldbPluginInstructionMIPS64 lldbPluginInstructionRISCV + lldbPluginInstructionPPC64 ${LLDB_SYSTEM_LIBS} LINK_COMPONENTS diff --git a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp index 4233252a84dfc..91bb2083a88b5 100644 --- a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp +++ b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp @@ -14,6 +14,9 @@ using HostObjectFile = ObjectFileMachO; #elif defined(_WIN32) #include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" using HostObjectFile = ObjectFilePECOFF; +#elif defined(__AIX__) +#include "Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h" +using HostObjectFile = ObjectFileXCOFF; #else #include "Plugins/ObjectFile/ELF/ObjectFileELF.h" using HostObjectFile = ObjectFileELF; @@ -46,6 +49,10 @@ using HostObjectFile = ObjectFileELF; #include "Plugins/Instruction/MIPS/EmulateInstructionMIPS.h" #endif +#if defined(__AIX__) +#include "Plugins/Instruction/PPC64/EmulateInstructionPPC64.h" +#endif + #if defined(__riscv) #define LLDB_TARGET_RISCV #include "Plugins/Instruction/RISCV/EmulateInstructionRISCV.h" @@ -75,6 +82,10 @@ llvm::Error SystemInitializerLLGS::Initialize() { EmulateInstructionRISCV::Initialize(); #endif +#if defined(__AIX__) + EmulateInstructionPPC64::Initialize(); +#endif + return llvm::Error::success(); } @@ -97,5 +108,9 @@ void SystemInitializerLLGS::Terminate() { EmulateInstructionRISCV::Terminate(); #endif +#if defined(__AIX__) + EmulateInstructionPPC64::Terminate(); +#endif + SystemInitializerCommon::Terminate(); } diff --git a/lldb/tools/lldb-server/lldb-gdbserver.cpp b/lldb/tools/lldb-server/lldb-gdbserver.cpp index 563284730bc70..2a14f4f9c82aa 100644 --- a/lldb/tools/lldb-server/lldb-gdbserver.cpp +++ b/lldb/tools/lldb-server/lldb-gdbserver.cpp @@ -45,6 +45,8 @@ #include "Plugins/Process/NetBSD/NativeProcessNetBSD.h" #elif defined(_WIN32) #include "Plugins/Process/Windows/Common/NativeProcessWindows.h" +#elif defined(__AIX__) +#include "Plugins/Process/AIX/NativeProcessAIX.h" #endif #ifndef LLGS_PROGRAM_NAME @@ -70,6 +72,8 @@ typedef process_freebsd::NativeProcessFreeBSD::Manager NativeProcessManager; typedef process_netbsd::NativeProcessNetBSD::Manager NativeProcessManager; #elif defined(_WIN32) typedef NativeProcessWindows::Manager NativeProcessManager; +#elif defined(__AIX__) +typedef process_aix::NativeProcessAIX::Manager NativeProcessManager; #else // Dummy implementation to make sure the code compiles class NativeProcessManager : public NativeProcessProtocol::Manager { diff --git a/lldb/unittests/Host/FileSystemTest.cpp b/lldb/unittests/Host/FileSystemTest.cpp index 58887f6b2467e..89d0f5b87171a 100644 --- a/lldb/unittests/Host/FileSystemTest.cpp +++ b/lldb/unittests/Host/FileSystemTest.cpp @@ -59,7 +59,7 @@ class DummyFileSystem : public vfs::FileSystem { return I->second; } ErrorOr> - openFileForRead(const Twine &Path) override { + openFileForRead(const Twine &Path, bool IsText) override { auto S = status(Path); if (S) return std::unique_ptr(new DummyFile{*S}); diff --git a/lldb/unittests/Host/posix/TerminalTest.cpp b/lldb/unittests/Host/posix/TerminalTest.cpp index 5187a0c20a68b..f3de92c0852b1 100644 --- a/lldb/unittests/Host/posix/TerminalTest.cpp +++ b/lldb/unittests/Host/posix/TerminalTest.cpp @@ -94,15 +94,19 @@ TEST_F(TerminalTest, SetRaw) { TEST_F(TerminalTest, SetBaudRate) { struct termios terminfo; +#if (defined(__AIX__) && defined(B38400)) || !defined(__AIX__) ASSERT_THAT_ERROR(m_term.SetBaudRate(38400), llvm::Succeeded()); ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0); EXPECT_EQ(cfgetispeed(&terminfo), static_cast(B38400)); EXPECT_EQ(cfgetospeed(&terminfo), static_cast(B38400)); +#endif +#if (defined(__AIX__) && defined(B115200)) || !defined(__AIX__) ASSERT_THAT_ERROR(m_term.SetBaudRate(115200), llvm::Succeeded()); ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0); EXPECT_EQ(cfgetispeed(&terminfo), static_cast(B115200)); EXPECT_EQ(cfgetospeed(&terminfo), static_cast(B115200)); +#endif // uncommon value #if defined(B153600) diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h index 5a7cd8e38f2b7..fa9c6781e24f5 100644 --- a/llvm/include/llvm/Object/XCOFFObjectFile.h +++ b/llvm/include/llvm/Object/XCOFFObjectFile.h @@ -542,7 +542,6 @@ class XCOFFObjectFile : public ObjectFile { template const T *sectionHeaderTable() const; size_t getFileHeaderSize() const; - size_t getSectionHeaderSize() const; const XCOFFSectionHeader32 *toSection32(DataRefImpl Ref) const; const XCOFFSectionHeader64 *toSection64(DataRefImpl Ref) const; @@ -578,6 +577,9 @@ class XCOFFObjectFile : public ObjectFile { void checkSectionAddress(uintptr_t Addr, uintptr_t TableAddr) const; public: + size_t getSectionHeaderSize() const; + Expected getLoaderSectionAddress() const; + static constexpr uint64_t InvalidRelocOffset = std::numeric_limits::max(); diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp index bdd04b00f557b..9c96df1bbdc54 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -251,10 +251,16 @@ Expected DWARFUnit::getStringOffsetSectionItem(uint32_t Index) const { return DA.getRelocatedValue(ItemSize, &Offset); } +bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; + Error DWARFUnitHeader::extract(DWARFContext &Context, const DWARFDataExtractor &debug_info, uint64_t *offset_ptr, DWARFSectionKind SectionKind) { + if (UGLY_FLAG_FOR_AIX) { + // FIXME: hack to get version + *offset_ptr += 8; + } Offset = *offset_ptr; Error Err = Error::success(); IndexEntry = nullptr; @@ -267,8 +273,13 @@ Error DWARFUnitHeader::extract(DWARFContext &Context, AbbrOffset = debug_info.getRelocatedValue( FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err); } else { - AbbrOffset = debug_info.getRelocatedValue( - FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err); + if (UGLY_FLAG_FOR_AIX) { + AbbrOffset = debug_info.getRelocatedValue( + 8, offset_ptr, nullptr, &Err); + } else { + AbbrOffset = debug_info.getRelocatedValue( + FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err); + } FormParams.AddrSize = debug_info.getU8(offset_ptr, &Err); // Fake a unit type based on the section type. This isn't perfect, // but distinguishing compile and type units is generally enough. >From b1da5b1cf35829fcbf4ad6564c6005c755012e47 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 7 Aug 2024 12:18:45 -0500 Subject: [PATCH 02/50] Code license notice --- lldb/NOTICE.TXT | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 lldb/NOTICE.TXT diff --git a/lldb/NOTICE.TXT b/lldb/NOTICE.TXT new file mode 100644 index 0000000000000..d814272967476 --- /dev/null +++ b/lldb/NOTICE.TXT @@ -0,0 +1,7 @@ + +This product contains small piece of code to support AIX, taken from netbsd. + + * LICENSE: + * lldb/source/Host/common/LICENSE.aix-netbsd.txt (OpenSSL License) + * HOMEPAGE: + * https://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/crypto/external/bsd/openssl/dist >From 50ad673a78029fd6c47d90317e2c61ca2b59d5c5 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 7 Aug 2024 13:27:20 -0500 Subject: [PATCH 03/50] Reverting .tests --- lldb/test/Shell/Expr/TestIRMemoryMap.test | 2 +- lldb/test/Shell/Process/TestEnvironment.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/test/Shell/Expr/TestIRMemoryMap.test b/lldb/test/Shell/Expr/TestIRMemoryMap.test index 5ed61ad33ffc4..9dd0413be14cf 100644 --- a/lldb/test/Shell/Expr/TestIRMemoryMap.test +++ b/lldb/test/Shell/Expr/TestIRMemoryMap.test @@ -1,6 +1,6 @@ # UNSUPPORTED: system-windows -# RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t +# RUN: %clangxx_host %p/Inputs/call-function.cpp -g -o %t # RUN: lldb-test ir-memory-map %t %S/Inputs/ir-memory-map-basic # RUN: lldb-test ir-memory-map -host-only %t %S/Inputs/ir-memory-map-basic diff --git a/lldb/test/Shell/Process/TestEnvironment.test b/lldb/test/Shell/Process/TestEnvironment.test index 2ead258719f32..e6d6e56fc9203 100644 --- a/lldb/test/Shell/Process/TestEnvironment.test +++ b/lldb/test/Shell/Process/TestEnvironment.test @@ -3,7 +3,7 @@ UNSUPPORTED: lldb-repro The double quotes around "BAR" ensure we don't match the command. -RUN: %clangxx_host -std=c++11 -I/compgpfs/build/xlcit/rings/openxlC/aix/wyvern_dev/ring0/latest/opt/IBM/openxlC/17.1.2/include/c++/v1/ %p/Inputs/env.cpp -o %t +RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t RUN: %lldb %t -o 'process launch --environment FOO="BAR"' | FileCheck %s RUN: %lldb %t -o 'env FOO="BAR"' -o 'process launch' | FileCheck %s >From c1967be8fe14d469cb5ae9d41d115a7003ff39b6 Mon Sep 17 00:00:00 2001 From: Lakshmi Surekha Kovvuri Date: Thu, 22 Aug 2024 08:49:50 -0500 Subject: [PATCH 04/50] For TestSuite Run --- lldb/unittests/Host/FileSystemTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/unittests/Host/FileSystemTest.cpp b/lldb/unittests/Host/FileSystemTest.cpp index 89d0f5b87171a..58887f6b2467e 100644 --- a/lldb/unittests/Host/FileSystemTest.cpp +++ b/lldb/unittests/Host/FileSystemTest.cpp @@ -59,7 +59,7 @@ class DummyFileSystem : public vfs::FileSystem { return I->second; } ErrorOr> - openFileForRead(const Twine &Path, bool IsText) override { + openFileForRead(const Twine &Path) override { auto S = status(Path); if (S) return std::unique_ptr(new DummyFile{*S}); >From 758ab642d0974e799ac902d8ad240a3a90aeb24d Mon Sep 17 00:00:00 2001 From: Lakshmi Surekha Kovvuri Date: Fri, 30 Aug 2024 08:33:32 -0500 Subject: [PATCH 05/50] Changes made to AIX-specific files to eliminate errors encountered during CI when updating LLDB. --- .../Plugins/Process/AIX/NativeProcessAIX.cpp | 20 ++++++++++--------- .../Process/AIX/NativeRegisterContextAIX.cpp | 4 ++-- .../AIX/NativeRegisterContextAIX_ppc64.cpp | 10 +++++----- .../Plugins/Process/AIX/NativeThreadAIX.cpp | 2 +- .../GDBRemoteCommunicationClient.cpp | 4 ++-- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp index 882f20d30a3bf..5b01a66b0453f 100644 --- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -211,12 +211,14 @@ static Status EnsureFDFlags(int fd, int flags) { int status = fcntl(fd, F_GETFL); if (status == -1) { - error.SetErrorToErrno(); + error = Status::FromErrno(); + // error.SetErrorToErrno(); return error; } if (fcntl(fd, F_SETFL, status | flags) == -1) { - error.SetErrorToErrno(); + error = Status::FromErrno(); + // error.SetErrorToErrno(); return error; } @@ -813,7 +815,7 @@ Status NativeProcessAIX::Resume(const ResumeActionList &resume_actions) { Status error = ResumeThread(static_cast(*thread), action->state, signo); if (error.Fail()) - return Status("NativeProcessAIX::%s: failed to resume thread " + return Status::FromErrorStringWithFormat("NativeProcessAIX::%s: failed to resume thread " "for pid %" PRIu64 ", tid %" PRIu64 ", error = %s", __FUNCTION__, GetID(), thread->GetID(), error.AsCString()); @@ -826,7 +828,7 @@ Status NativeProcessAIX::Resume(const ResumeActionList &resume_actions) { break; default: - return Status("NativeProcessAIX::%s (): unexpected state %s specified " + return Status::FromErrorStringWithFormat("NativeProcessAIX::%s (): unexpected state %s specified " "for pid %" PRIu64 ", tid %" PRIu64, __FUNCTION__, StateAsCString(action->state), GetID(), thread->GetID()); @@ -840,7 +842,7 @@ Status NativeProcessAIX::Halt() { Status error; if (kill(GetID(), SIGSTOP) != 0) - error.SetErrorToErrno(); + error = Status::FromErrno(); return error; } @@ -874,7 +876,7 @@ Status NativeProcessAIX::Signal(int signo) { Host::GetSignalAsCString(signo), GetID()); if (kill(GetID(), signo)) - error.SetErrorToErrno(); + error = Status::FromErrno(); return error; } @@ -951,7 +953,7 @@ Status NativeProcessAIX::Kill() { } if (kill(GetID(), SIGKILL) != 0) { - error.SetErrorToErrno(); + error = Status::FromErrno(); return error; } @@ -1555,7 +1557,7 @@ Status NativeProcessAIX::GetLoadedModuleFileSpec(const char *module_path, return Status(); } } - return Status("Module file (%s) not found in /proc/%" PRIu64 "/maps file!", + return Status::FromErrorStringWithFormat("Module file (%s) not found in /proc/%" PRIu64 "/maps file!", module_file_spec.GetFilename().AsCString(), GetID()); } @@ -2011,7 +2013,7 @@ Status NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid, void *addr, } if (errno) { - error.SetErrorToErrno(); + error = Status::FromErrno(); ret = -1; } diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp index 0859f9501c1b6..071e55543cc3c 100644 --- a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp @@ -27,7 +27,7 @@ Status NativeRegisterContextAIX::ReadRegisterRaw(uint32_t reg_index, RegisterValue ®_value) { const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); if (!reg_info) - return Status("register %" PRIu32 " not found", reg_index); + return Status::FromErrorStringWithFormat("register %" PRIu32 " not found", reg_index); return DoReadRegisterValue(GetPtraceOffset(reg_index), reg_info->name, reg_info->byte_size, reg_value); @@ -82,7 +82,7 @@ NativeRegisterContextAIX::WriteRegisterRaw(uint32_t reg_index, assert(register_to_write_info_p && "register to write does not have valid RegisterInfo"); if (!register_to_write_info_p) - return Status("NativeRegisterContextAIX::%s failed to get RegisterInfo " + return Status::FromErrorStringWithFormat("NativeRegisterContextAIX::%s failed to get RegisterInfo " "for write register index %" PRIu32, __FUNCTION__, reg_to_write); diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp index 1996373791748..0132b52dec6f2 100644 --- a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp @@ -165,7 +165,7 @@ Status NativeRegisterContextAIX_ppc64::ReadRegister( Status error; if (!reg_info) { - error.SetErrorString("reg_info NULL"); + error.FromErrorString("reg_info NULL"); return error; } @@ -251,7 +251,7 @@ Status NativeRegisterContextAIX_ppc64::WriteRegister( const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; if (reg_index == LLDB_INVALID_REGNUM) - return Status("no lldb regnum for %s", reg_info && reg_info->name + return Status::FromErrorStringWithFormat("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : ""); @@ -389,14 +389,14 @@ Status NativeRegisterContextAIX_ppc64::WriteAllRegisterValues( Status error; if (!data_sp) { - error.SetErrorStringWithFormat( + error = Status::FromErrorStringWithFormat( "NativeRegisterContextAIX_ppc64::%s invalid data_sp provided", __FUNCTION__); return error; } if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { - error.SetErrorStringWithFormat( + error = Status::FromErrorStringWithFormat( "NativeRegisterContextAIX_ppc64::%s data_sp contained mismatched " "data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); @@ -405,7 +405,7 @@ Status NativeRegisterContextAIX_ppc64::WriteAllRegisterValues( const uint8_t *src = data_sp->GetBytes(); if (src == nullptr) { - error.SetErrorStringWithFormat("NativeRegisterContextAIX_ppc64::%s " + error = Status::FromErrorStringWithFormat("NativeRegisterContextAIX_ppc64::%s " "DataBuffer::GetBytes() returned a null " "pointer", __FUNCTION__); diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp index e07daccdff550..bb14b6ab4a05e 100644 --- a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp @@ -481,7 +481,7 @@ Status NativeThreadAIX::RequestStop() { Status err; errno = 0; if (::kill(pid, SIGSTOP) != 0) { - err.SetErrorToErrno(); + err = Status::FromErrno(); LLDB_LOGF(log, "NativeThreadAIX::%s kill(%" PRIu64 ", SIGSTOP) failed: %s", __FUNCTION__, pid, err.AsCString()); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 17926f8e4ab53..0aa68a4a09cbe 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -1728,11 +1728,11 @@ Status GDBRemoteCommunicationClient::GetLDXINFO(struct ld_xinfo *info_ptr) llvm::MutableArrayRef infoData((uint8_t *)info_ptr, sizeof(struct ld_xinfo)*64); size_t got_bytes = response.GetHexBytesAvail(infoData); if (got_bytes != sizeof(struct ld_xinfo)*64) { - error.SetErrorString("qLDXINFO ret bad size"); + error.FromErrorString("qLDXINFO ret bad size"); return error; } } else { - error.SetErrorString("qLDXINFO is not supported"); + error.FromErrorString("qLDXINFO is not supported"); } return error; } >From 33d561f4bb74a2efd0da163ebde416c9ad1c2925 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Tue, 10 Sep 2024 02:00:09 -0500 Subject: [PATCH 06/50] Removed non-required PTRACE defs --- lldb/include/lldb/Host/aix/Ptrace.h | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/lldb/include/lldb/Host/aix/Ptrace.h b/lldb/include/lldb/Host/aix/Ptrace.h index 88928f18102d7..393928a89add3 100644 --- a/lldb/include/lldb/Host/aix/Ptrace.h +++ b/lldb/include/lldb/Host/aix/Ptrace.h @@ -34,29 +34,11 @@ #ifndef PTRACE_SETREGSET #define PTRACE_SETREGSET 0x4205 #endif -#ifndef PTRACE_GET_THREAD_AREA -#define PTRACE_GET_THREAD_AREA (PT_COMMAND_MAX+5) -#endif -#ifndef PTRACE_ARCH_PRCTL -#define PTRACE_ARCH_PRCTL (PT_COMMAND_MAX+6) -#endif -#ifndef ARCH_GET_FS -#define ARCH_SET_GS 0x1001 -#define ARCH_SET_FS 0x1002 -#define ARCH_GET_FS 0x1003 -#define ARCH_GET_GS 0x1004 -#endif -#ifndef PTRACE_PEEKMTETAGS -#define PTRACE_PEEKMTETAGS (PT_COMMAND_MAX+7) -#endif -#ifndef PTRACE_POKEMTETAGS -#define PTRACE_POKEMTETAGS (PT_COMMAND_MAX+8) -#endif #ifndef PTRACE_GETVRREGS -#define PTRACE_GETVRREGS (PT_COMMAND_MAX+9) +#define PTRACE_GETVRREGS (PT_COMMAND_MAX+5) #endif #ifndef PTRACE_GETVSRREGS -#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+10) +#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+6) #endif #endif // liblldb_Host_aix_Ptrace_h_ >From 450793d7270999ecdd6714c4222663517dab3928 Mon Sep 17 00:00:00 2001 From: Lakshmi Surekha Kovvuri Date: Wed, 11 Sep 2024 02:52:41 -0500 Subject: [PATCH 07/50] Patch for running of unit testcases without hang --- lldb/unittests/Host/MainLoopTest.cpp | 4 +++- lldb/unittests/Host/PipeTest.cpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lldb/unittests/Host/MainLoopTest.cpp b/lldb/unittests/Host/MainLoopTest.cpp index 4084e90782fd5..9e92ec1470d4d 100644 --- a/lldb/unittests/Host/MainLoopTest.cpp +++ b/lldb/unittests/Host/MainLoopTest.cpp @@ -183,7 +183,7 @@ TEST_F(MainLoopTest, PendingCallbackAfterLoopExited) { loop.AddPendingCallback([&](MainLoopBase &loop) {}); } -#ifdef LLVM_ON_UNIX +#if defined(LLVM_ON_UNIX) && !defined(__AIX__) TEST_F(MainLoopTest, DetectsEOF) { PseudoTerminal term; @@ -202,7 +202,9 @@ TEST_F(MainLoopTest, DetectsEOF) { ASSERT_TRUE(loop.Run().Success()); ASSERT_EQ(1u, callback_count); } +// #endif +// #ifdef LLVM_ON_UNIX TEST_F(MainLoopTest, Signal) { MainLoop loop; Status error; diff --git a/lldb/unittests/Host/PipeTest.cpp b/lldb/unittests/Host/PipeTest.cpp index 506f3d225a21e..c1013aa7a7e4e 100644 --- a/lldb/unittests/Host/PipeTest.cpp +++ b/lldb/unittests/Host/PipeTest.cpp @@ -55,6 +55,7 @@ TEST_F(PipeTest, OpenAsReader) { } #endif +#if !defined(__AIX__) TEST_F(PipeTest, WriteWithTimeout) { Pipe pipe; ASSERT_THAT_ERROR(pipe.CreateNew(false).ToError(), llvm::Succeeded()); @@ -150,3 +151,4 @@ TEST_F(PipeTest, WriteWithTimeout) { .ToError(), llvm::Succeeded()); } +#endif >From 61e7843b431ff3657e3c4b39d1559401ff3de891 Mon Sep 17 00:00:00 2001 From: Lakshmi Surekha Kovvuri Date: Thu, 12 Sep 2024 13:22:03 -0500 Subject: [PATCH 08/50] changes applied to NativeProcessAIX.cpp file to solve build errors while making LLDB up to date --- .../Plugins/Process/AIX/NativeProcessAIX.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp index 5b01a66b0453f..fc84763857453 100644 --- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -862,7 +862,7 @@ Status NativeProcessAIX::Detach() { Status e = Detach(thread->GetID()); if (e.Fail()) error = - e; // Save the error, but still attempt to detach from other threads. + e.Clone(); // Save the error, but still attempt to detach from other threads. } return error; @@ -1240,7 +1240,7 @@ Status NativeProcessAIX::ReadMemoryTags(int32_t type, lldb::addr_t addr, llvm::Expected details = GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); if (!details) - return Status(details.takeError()); + return Status::FromError(details.takeError()); // Ignore 0 length read if (!len) @@ -1295,7 +1295,7 @@ Status NativeProcessAIX::WriteMemoryTags(int32_t type, lldb::addr_t addr, llvm::Expected details = GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); if (!details) - return Status(details.takeError()); + return Status::FromError(details.takeError()); // Ignore 0 length write if (!len) @@ -1312,18 +1312,18 @@ Status NativeProcessAIX::WriteMemoryTags(int32_t type, lldb::addr_t addr, llvm::Expected> unpacked_tags_or_err = details->manager->UnpackTagsData(tags); if (!unpacked_tags_or_err) - return Status(unpacked_tags_or_err.takeError()); + return Status::FromError(unpacked_tags_or_err.takeError()); llvm::Expected> repeated_tags_or_err = details->manager->RepeatTagsForRange(*unpacked_tags_or_err, range); if (!repeated_tags_or_err) - return Status(repeated_tags_or_err.takeError()); + return Status::FromError(repeated_tags_or_err.takeError()); // Repack them for ptrace to use llvm::Expected> final_tag_data = details->manager->PackTags(*repeated_tags_or_err); if (!final_tag_data) - return Status(final_tag_data.takeError()); + return Status::FromError(final_tag_data.takeError()); struct iovec tags_vec; uint8_t *src = final_tag_data->data(); @@ -1609,13 +1609,13 @@ Status NativeProcessAIX::ResumeThread(NativeThreadAIX &thread, // reflect it is running after this completes. switch (state) { case eStateRunning: { - const auto resume_result = thread.Resume(signo); + Status resume_result = thread.Resume(signo); if (resume_result.Success()) SetState(eStateRunning, true); return resume_result; } case eStateStepping: { - const auto step_result = thread.SingleStep(signo); + Status step_result = thread.SingleStep(signo); if (step_result.Success()) SetState(eStateRunning, true); return step_result; >From 627a5427daba3fc5ea03ae481874f4aa1b4d2ed0 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Fri, 13 Sep 2024 16:25:47 +0530 Subject: [PATCH 09/50] Revert "Removed non-required PTRACE defs" --- lldb/include/lldb/Host/aix/Ptrace.h | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/lldb/include/lldb/Host/aix/Ptrace.h b/lldb/include/lldb/Host/aix/Ptrace.h index 393928a89add3..88928f18102d7 100644 --- a/lldb/include/lldb/Host/aix/Ptrace.h +++ b/lldb/include/lldb/Host/aix/Ptrace.h @@ -34,11 +34,29 @@ #ifndef PTRACE_SETREGSET #define PTRACE_SETREGSET 0x4205 #endif +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA (PT_COMMAND_MAX+5) +#endif +#ifndef PTRACE_ARCH_PRCTL +#define PTRACE_ARCH_PRCTL (PT_COMMAND_MAX+6) +#endif +#ifndef ARCH_GET_FS +#define ARCH_SET_GS 0x1001 +#define ARCH_SET_FS 0x1002 +#define ARCH_GET_FS 0x1003 +#define ARCH_GET_GS 0x1004 +#endif +#ifndef PTRACE_PEEKMTETAGS +#define PTRACE_PEEKMTETAGS (PT_COMMAND_MAX+7) +#endif +#ifndef PTRACE_POKEMTETAGS +#define PTRACE_POKEMTETAGS (PT_COMMAND_MAX+8) +#endif #ifndef PTRACE_GETVRREGS -#define PTRACE_GETVRREGS (PT_COMMAND_MAX+5) +#define PTRACE_GETVRREGS (PT_COMMAND_MAX+9) #endif #ifndef PTRACE_GETVSRREGS -#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+6) +#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+10) #endif #endif // liblldb_Host_aix_Ptrace_h_ >From ea34b15d8568b4639b4e850ef032e684d82dd971 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Thu, 10 Oct 2024 00:38:18 -0500 Subject: [PATCH 10/50] Replaced __AIX__ with _AIX --- clang/test/SemaCXX/class-layout.cpp | 2 +- lldb/CMakeLists.txt | 2 +- lldb/include/lldb/Host/HostGetOpt.h | 2 +- lldb/include/lldb/Host/HostInfo.h | 2 +- lldb/include/lldb/Host/XML.h | 2 +- lldb/include/lldb/Host/common/GetOptInc.h | 4 ++-- lldb/include/lldb/Target/Process.h | 6 +++--- lldb/include/lldb/Target/RegisterContextUnwind.h | 2 +- lldb/source/Core/Mangled.cpp | 2 +- lldb/source/Core/Section.cpp | 2 +- lldb/source/Host/common/Host.cpp | 4 ++-- lldb/source/Host/common/XML.cpp | 2 +- lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp | 2 +- lldb/source/Host/posix/FileSystemPosix.cpp | 2 +- lldb/source/Host/posix/MainLoopPosix.cpp | 4 ++-- lldb/source/Host/posix/ProcessLauncherPosixFork.cpp | 2 +- lldb/source/Initialization/SystemInitializerCommon.cpp | 4 ++-- lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp | 4 ++-- .../DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 6 +++--- .../Plugins/Instruction/PPC64/EmulateInstructionPPC64.h | 2 +- lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp | 2 +- lldb/source/Plugins/Language/ObjC/Cocoa.cpp | 2 +- .../BSD-Archive/ObjectContainerBSDArchive.cpp | 2 +- .../Big-Archive/ObjectContainerBigArchive.cpp | 2 +- .../Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp | 2 +- lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp | 6 +++--- .../source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp | 6 +++--- lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp | 6 +++--- lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp | 4 ++-- .../Process/gdb-remote/GDBRemoteCommunicationClient.cpp | 4 ++-- .../Process/gdb-remote/GDBRemoteCommunicationClient.h | 4 ++-- .../gdb-remote/GDBRemoteCommunicationServerLLGS.cpp | 4 ++-- .../Plugins/Process/gdb-remote/ProcessGDBRemote.cpp | 4 ++-- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h | 4 ++-- lldb/source/Target/Process.cpp | 4 ++-- lldb/source/Target/RegisterContextUnwind.cpp | 8 ++++---- lldb/source/Target/UnwindLLDB.cpp | 4 ++-- lldb/tools/driver/Driver.cpp | 4 ++-- lldb/tools/lldb-server/SystemInitializerLLGS.cpp | 8 ++++---- lldb/tools/lldb-server/lldb-gdbserver.cpp | 4 ++-- lldb/unittests/Host/MainLoopTest.cpp | 2 +- lldb/unittests/Host/PipeTest.cpp | 2 +- lldb/unittests/Host/posix/TerminalTest.cpp | 4 ++-- 43 files changed, 75 insertions(+), 75 deletions(-) diff --git a/clang/test/SemaCXX/class-layout.cpp b/clang/test/SemaCXX/class-layout.cpp index 22fb34b8419c5..0931d905a9749 100644 --- a/clang/test/SemaCXX/class-layout.cpp +++ b/clang/test/SemaCXX/class-layout.cpp @@ -639,7 +639,7 @@ namespace PR37275 { #pragma pack(pop) } -#endif // !defined(__MVS__) && !defined(__AIX__) +#endif // !defined(__MVS__) && !defined(_AIX) namespace non_pod { struct t1 { diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt index 2e9ae0d0b3221..a4fd8bccf056d 100644 --- a/lldb/CMakeLists.txt +++ b/lldb/CMakeLists.txt @@ -39,7 +39,7 @@ include(LLDBConfig) include(AddLLDB) if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") - add_definitions("-D__AIX__") + add_definitions("-D_AIX") endif() # Define the LLDB_CONFIGURATION_xxx matching the build type. diff --git a/lldb/include/lldb/Host/HostGetOpt.h b/lldb/include/lldb/Host/HostGetOpt.h index f450e561d6afb..b2b436e64a692 100644 --- a/lldb/include/lldb/Host/HostGetOpt.h +++ b/lldb/include/lldb/Host/HostGetOpt.h @@ -9,7 +9,7 @@ #ifndef LLDB_HOST_HOSTGETOPT_H #define LLDB_HOST_HOSTGETOPT_H -#if !defined(_MSC_VER) && !defined(__NetBSD__) && !defined(__AIX__) +#if !defined(_MSC_VER) && !defined(__NetBSD__) && !defined(_AIX) #include #include diff --git a/lldb/include/lldb/Host/HostInfo.h b/lldb/include/lldb/Host/HostInfo.h index 156df8cf6901d..0f7ec0e0aa0d2 100644 --- a/lldb/include/lldb/Host/HostInfo.h +++ b/lldb/include/lldb/Host/HostInfo.h @@ -55,7 +55,7 @@ #elif defined(__APPLE__) #include "lldb/Host/macosx/HostInfoMacOSX.h" #define HOST_INFO_TYPE HostInfoMacOSX -#elif defined(__AIX__) +#elif defined(_AIX) #include "lldb/Host/aix/HostInfoAIX.h" #define HOST_INFO_TYPE HostInfoAIX #else diff --git a/lldb/include/lldb/Host/XML.h b/lldb/include/lldb/Host/XML.h index cf359f7726d5d..483589f1abc75 100644 --- a/lldb/include/lldb/Host/XML.h +++ b/lldb/include/lldb/Host/XML.h @@ -11,7 +11,7 @@ #include "lldb/Host/Config.h" -#if defined(__AIX__) +#if defined(_AIX) //FIXME for AIX #undef LLDB_ENABLE_LIBXML2 #endif diff --git a/lldb/include/lldb/Host/common/GetOptInc.h b/lldb/include/lldb/Host/common/GetOptInc.h index ebb475bfaf6b8..652e6174ff8b6 100644 --- a/lldb/include/lldb/Host/common/GetOptInc.h +++ b/lldb/include/lldb/Host/common/GetOptInc.h @@ -11,11 +11,11 @@ #include "lldb/lldb-defines.h" -#if defined(_MSC_VER) || defined(__AIX__) +#if defined(_MSC_VER) || defined(_AIX) #define REPLACE_GETOPT #define REPLACE_GETOPT_LONG #endif -#if defined(_MSC_VER) || defined(__NetBSD__) || defined(__AIX__) +#if defined(_MSC_VER) || defined(__NetBSD__) || defined(_AIX) #define REPLACE_GETOPT_LONG_ONLY #endif diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index 4a47ffd8d779d..d1527d316d678 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -65,7 +65,7 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/VersionTuple.h" -#if defined(__AIX__) +#if defined(_AIX) struct ld_xinfo; #endif @@ -1884,7 +1884,7 @@ class Process : public std::enable_shared_from_this, Status GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &range_info); -#if defined(__AIX__) +#if defined(_AIX) Status GetLDXINFO(struct ld_xinfo *info_ptr); #endif @@ -2823,7 +2823,7 @@ void PruneThreadPlans(); "Process::DoGetMemoryRegionInfo() not supported"); } -#if defined(__AIX__) +#if defined(_AIX) virtual Status DoGetLDXINFO(struct ld_xinfo *info_ptr) { return Status("Process::DoGetLDXINFO() not supported"); } diff --git a/lldb/include/lldb/Target/RegisterContextUnwind.h b/lldb/include/lldb/Target/RegisterContextUnwind.h index 46c06cb422caf..b6176f8e5727f 100644 --- a/lldb/include/lldb/Target/RegisterContextUnwind.h +++ b/lldb/include/lldb/Target/RegisterContextUnwind.h @@ -67,7 +67,7 @@ class RegisterContextUnwind : public lldb_private::RegisterContext { bool ReadPC(lldb::addr_t &start_pc); -#ifdef __AIX__ +#ifdef _AIX bool ReadLR(lldb::addr_t &lr); #endif diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp index 43c5b043ef7a2..8f2e3562f6577 100644 --- a/lldb/source/Core/Mangled.cpp +++ b/lldb/source/Core/Mangled.cpp @@ -167,7 +167,7 @@ static char *GetItaniumDemangledStr(const char *M) { "Expected demangled_size to return length including trailing null"); } -#if !defined(__AIX__) +#if !defined(_AIX) if (Log *log = GetLog(LLDBLog::Demangle)) { if (demangled_cstr) LLDB_LOGF(log, "demangled itanium: %s -> \"%s\"", M, demangled_cstr); diff --git a/lldb/source/Core/Section.cpp b/lldb/source/Core/Section.cpp index 9ed55853930a6..e0a9f7fcc7135 100644 --- a/lldb/source/Core/Section.cpp +++ b/lldb/source/Core/Section.cpp @@ -263,7 +263,7 @@ bool Section::ResolveContainedAddress(addr_t offset, Address &so_addr, bool Section::ContainsFileAddress(addr_t vm_addr) const { const addr_t file_addr = GetFileAddress(); -#ifdef __AIX__ +#ifdef _AIX if (file_addr == 0) return false; #endif diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 94b1d0fd57d07..dc48cb87b5ce6 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -358,7 +358,7 @@ bool Host::ResolveExecutableInBundle(FileSpec &file) { return false; } #ifndef _WIN32 -#if defined(__AIX__) +#if defined(_AIX) #include extern char **p_xargv; @@ -525,7 +525,7 @@ static int dladdr(const void *ptr, Dl_info *dl) FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSpec module_filespec; #if !defined(__ANDROID__) -#ifdef __AIX__ +#ifdef _AIX if (host_addr == reinterpret_cast(HostInfoBase::ComputeSharedLibraryDirectory)) { // FIXME: AIX dladdr return "lldb" for this case if (p_xargv[0]) { diff --git a/lldb/source/Host/common/XML.cpp b/lldb/source/Host/common/XML.cpp index 62cac78aaac23..fbc409105fe60 100644 --- a/lldb/source/Host/common/XML.cpp +++ b/lldb/source/Host/common/XML.cpp @@ -10,7 +10,7 @@ #include "lldb/Host/XML.h" #include "llvm/ADT/StringExtras.h" -#if defined(__AIX__) +#if defined(_AIX) #undef LLDB_ENABLE_LIBXML2 #endif diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index bd204c812b7e3..09c3fd2af6d3e 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -722,7 +722,7 @@ ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, ConnectionStatus ConnectionFileDescriptor::ConnectFile( llvm::StringRef s, socket_id_callback_type socket_id_callback, Status *error_ptr) { -#if !defined(__AIX__) +#if !defined(_AIX) #if LLDB_ENABLE_POSIX std::string addr_str = s.str(); // file:///PATH diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index 866fd8ac96c7b..21da5612ff6b8 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,7 +11,7 @@ // C includes #include #include -#if !defined(__AIX__) +#if !defined(_AIX) #include #endif #include diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp index d1eba52791a78..015570236b9d3 100644 --- a/lldb/source/Host/posix/MainLoopPosix.cpp +++ b/lldb/source/Host/posix/MainLoopPosix.cpp @@ -179,7 +179,7 @@ Status MainLoopPosix::RunImpl::Poll() { read_fds.push_back(pfd); } -#if defined(__AIX__) +#if defined(_AIX) sigset_t origmask; int timeout; @@ -325,7 +325,7 @@ MainLoopPosix::RegisterSignal(int signo, const Callback &callback, // If we're using kqueue, the signal needs to be unblocked in order to // receive it. If using pselect/ppoll, we need to block it, and later unblock // it as a part of the system call. -#if defined(__AIX__) +#if defined(_AIX) //FIXME: where is signal unblocked? ret = pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, &old_set); #else diff --git a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp index b8a96fbd19f02..f9f99decd39c2 100644 --- a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp +++ b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp @@ -193,7 +193,7 @@ struct ForkLaunchInfo { } // Start tracing this child that is about to exec. -#if !defined(__AIX__) +#if !defined(_AIX) if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1) ExitWithError(error_fd, "ptrace"); #else diff --git a/lldb/source/Initialization/SystemInitializerCommon.cpp b/lldb/source/Initialization/SystemInitializerCommon.cpp index 4b01442a94bac..2e2d622d9981c 100644 --- a/lldb/source/Initialization/SystemInitializerCommon.cpp +++ b/lldb/source/Initialization/SystemInitializerCommon.cpp @@ -19,7 +19,7 @@ #include "lldb/Version/Version.h" #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__OpenBSD__) || defined(__AIX__) + defined(__OpenBSD__) || defined(_AIX) #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" #endif @@ -79,7 +79,7 @@ llvm::Error SystemInitializerCommon::Initialize() { process_gdb_remote::ProcessGDBRemoteLog::Initialize(); #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__OpenBSD__) || defined(__AIX__) + defined(__OpenBSD__) || defined(_AIX) ProcessPOSIXLog::Initialize(); #endif #if defined(_WIN32) diff --git a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp index 88a82f4a0d20c..a3abb15ee625b 100644 --- a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp +++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp @@ -156,7 +156,7 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) return false; -#if defined(__AIX__) +#if defined(_AIX) assert(0); #else // Read TOC pointer value. @@ -279,7 +279,7 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) return false; -#if defined(__AIX__) +#if defined(_AIX) LLDB_LOGF(log, "Writing R2: 0x%" PRIx64, (uint64_t)toc_addr); if (!reg_ctx->WriteRegisterFromUnsigned(r2_reg_info, toc_addr)) return false; diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 62663974134b0..7f3a638d5b028 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -18,7 +18,7 @@ #include "lldb/Target/ThreadPlanStepInstruction.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -160,7 +160,7 @@ void DynamicLoaderAIXDYLD::DidAttach() { auto error = m_process->LoadModules(); LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}"); -#if defined(__AIX__) +#if defined(_AIX) // Get struct ld_xinfo (FIXME) struct ld_xinfo ldinfo[64]; Status status = m_process->GetLDXINFO(&(ldinfo[0])); @@ -221,7 +221,7 @@ void DynamicLoaderAIXDYLD::DidLaunch() { LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}"); } -#if defined(__AIX__) +#if defined(_AIX) // Get struct ld_xinfo (FIXME) struct ld_xinfo ldinfo[64]; Status status = m_process->GetLDXINFO(&(ldinfo[0])); diff --git a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h index 1576c9700e557..d98b2880ca3b4 100644 --- a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h +++ b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h @@ -39,7 +39,7 @@ class EmulateInstructionPPC64 : public EmulateInstruction { return true; case eInstructionTypePCModifying: -#if defined(__AIX__) +#if defined(_AIX) return true; #else return false; diff --git a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp index 690fb0d60a09a..9a52fb2f2adc5 100644 --- a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp +++ b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp @@ -194,7 +194,7 @@ void JITLoaderGDB::SetJITBreakpoint(lldb_private::ModuleList &module_list) { if (jit_addr == LLDB_INVALID_ADDRESS) return; -#if defined(__AIX__) +#if defined(_AIX) return; #endif diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index fb5bc2c58e6fb..71f2b127afb12 100644 --- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -1227,7 +1227,7 @@ bool lldb_private::formatters::ObjCSELSummaryProvider( time_t lldb_private::formatters::GetOSXEpoch() { static time_t epoch = 0; if (!epoch) { -#if !defined(__AIX__) +#if !defined(_AIX) #ifndef _WIN32 tzset(); tm tm_epoch; diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 5ea55772c3aba..4f747ab20c9ef 100644 --- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -8,7 +8,7 @@ #include "ObjectContainerBSDArchive.h" -#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__) +#if defined(_WIN32) || defined(__ANDROID__) || defined(_AIX) // Defines from ar, missing on Windows #define SARMAG 8 #define ARFMAG "`\n" diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp index 050ad73f1d19a..38756a0dd2969 100644 --- a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp @@ -8,7 +8,7 @@ #include "ObjectContainerBigArchive.h" -#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__) +#if defined(_WIN32) || defined(__ANDROID__) || defined(_AIX) // Defines from ar, missing on Windows #define ARMAG "!\n" #define SARMAG 8 diff --git a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp index d8834af2c33ef..9aab76c6c48ba 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp +++ b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp @@ -51,7 +51,7 @@ size_t ObjectFileMinidump::GetModuleSpecifications( const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, lldb_private::ModuleSpecList &specs) { -#if !defined(__AIX__) +#if !defined(_AIX) specs.Clear(); #endif return 0; diff --git a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp index 75cc54e4f0d48..d76d6adb1be2c 100644 --- a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp +++ b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp @@ -117,7 +117,7 @@ size_t ObjectFilePDB::GetModuleSpecifications( llvm::BumpPtrAllocator allocator; std::unique_ptr pdb_file = loadPDBFile(file.GetPath(), allocator); if (!pdb_file){ -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; @@ -127,7 +127,7 @@ size_t ObjectFilePDB::GetModuleSpecifications( auto info_stream = pdb_file->getPDBInfoStream(); if (!info_stream) { llvm::consumeError(info_stream.takeError()); -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; @@ -136,7 +136,7 @@ size_t ObjectFilePDB::GetModuleSpecifications( auto dbi_stream = pdb_file->getPDBDbiStream(); if (!dbi_stream) { llvm::consumeError(dbi_stream.takeError()); -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index 519ce2ca4a0b2..02a86234bd363 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -254,7 +254,7 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( lldb::offset_t length, lldb_private::ModuleSpecList &specs) { const size_t initial_count = specs.GetSize(); if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp)){ -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; @@ -272,7 +272,7 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( if (!binary) { LLDB_LOG_ERROR(log, binary.takeError(), "Failed to create binary for file ({1}): {0}", file); -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; @@ -281,7 +281,7 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( auto *COFFObj = llvm::dyn_cast(binary->get()); if (!COFFObj){ -#if !defined(__AIX__) +#if !defined(_AIX) return initial_count; #else return specs.GetSize() - initial_count; diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp index b6b08b73bec41..5c94477002978 100644 --- a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp +++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp @@ -31,7 +31,7 @@ // Define these constants from AIX mman.h for use when targeting remote aix // systems even when host has different values. -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -80,7 +80,7 @@ void PlatformAIX::Initialize() { PlatformPOSIX::Initialize(); if (g_initialize_count++ == 0) { -#if defined(__AIX__) +#if defined(_AIX) PlatformSP default_platform_sp(new PlatformAIX(true)); default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); Platform::SetHostPlatform(default_platform_sp); @@ -294,7 +294,7 @@ MmapArgList PlatformAIX::GetMmapArgumentList(const ArchSpec &arch, addr_t addr, addr_t length, unsigned prot, unsigned flags, addr_t fd, addr_t offset) { -#if defined(__AIX__) +#if defined(_AIX) unsigned flags_platform = MAP_VARIABLE | MAP_PRIVATE | MAP_ANONYMOUS; #else unsigned flags_platform = 0; diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index db271357d792a..ea758caa653a1 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -46,7 +46,7 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, function_options.include_inlines = false; SymbolContextList sc_list; -#if !defined(__AIX__) +#if !defined(_AIX) process->GetTarget().GetImages().FindFunctions( ConstString("mmap"), eFunctionNameTypeFull, function_options, sc_list); #else @@ -122,7 +122,7 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, MmapArgList args = process->GetTarget().GetPlatform()->GetMmapArgumentList( arch, addr, length, prot_arg, flags, fd, offset); -#if defined(__AIX__) +#if defined(_AIX) lldb::ThreadPlanSP call_plan_sp( new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(), toc_range.GetBaseAddress(), diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 443b7c7b2c7fb..fa0a3b5d4dc38 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -41,7 +41,7 @@ #include "llvm/Config/llvm-config.h" // for LLVM_ENABLE_ZLIB #include "llvm/Support/JSON.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -1715,7 +1715,7 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( return error; } -#if defined(__AIX__) +#if defined(_AIX) Status GDBRemoteCommunicationClient::GetLDXINFO(struct ld_xinfo *info_ptr) { Status error; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 520f37ac56716..1812fc9b7ca65 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -32,7 +32,7 @@ #include "llvm/Support/VersionTuple.h" -#if defined(__AIX__) +#if defined(_AIX) struct ld_xinfo; #endif @@ -200,7 +200,7 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase { Status GetMemoryRegionInfo(lldb::addr_t addr, MemoryRegionInfo &range_info); std::optional GetWatchpointSlotCount(); -#if defined(__AIX__) +#if defined(_AIX) Status GetLDXINFO(struct ld_xinfo *info_ptr); #endif diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 4f1ef0898ba08..27be61a474238 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -48,7 +48,7 @@ #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "lldb/Utility/StringExtractorGDBRemote.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -3011,7 +3011,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qLDXINFO(StringExtractorGDBRemote &pack return SendErrorResponse(0xff); } -#if defined(__AIX__) +#if defined(_AIX) // FIXME: buffer size struct ld_xinfo info[64]; if (ptrace64(PT_LDXINFO, m_current_process->GetID(), (long long)&(info[0]), sizeof(info), nullptr) != 0) { diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index ca381290d0e9f..5b7ce5f1424d9 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -92,7 +92,7 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/raw_ostream.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -2963,7 +2963,7 @@ Status ProcessGDBRemote::DoGetMemoryRegionInfo(addr_t load_addr, return error; } -#if defined(__AIX__) +#if defined(_AIX) Status ProcessGDBRemote::DoGetLDXINFO(struct ld_xinfo *info_ptr) { Status error(m_gdb_comm.GetLDXINFO(info_ptr)); return error; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 82200fbea21cd..2bf3a04d213d4 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -37,7 +37,7 @@ #include "GDBRemoteCommunicationClient.h" #include "GDBRemoteRegisterContext.h" -#if defined(__AIX__) +#if defined(_AIX) struct ld_xinfo; #endif @@ -427,7 +427,7 @@ class ProcessGDBRemote : public Process, Status DoGetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo ®ion_info) override; -#if defined(__AIX__) +#if defined(_AIX) Status DoGetLDXINFO(struct ld_xinfo *info_ptr) override; #endif diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index a9aef7ef21855..e6ae7fc559ef4 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -75,7 +75,7 @@ #include "lldb/Utility/State.h" #include "lldb/Utility/Timer.h" -#if defined(__AIX__) +#if defined(_AIX) #include #endif @@ -6188,7 +6188,7 @@ Status Process::GetMemoryRegionInfo(lldb::addr_t load_addr, return DoGetMemoryRegionInfo(load_addr, range_info); } -#if defined(__AIX__) +#if defined(_AIX) Status Process::GetLDXINFO(struct ld_xinfo *info_ptr) { return DoGetLDXINFO(info_ptr); } diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index fbdbc8c63a5d0..fdf269a3d3653 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -40,7 +40,7 @@ #include #include -#ifdef __AIX__ +#ifdef _AIX #include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" #endif @@ -1260,7 +1260,7 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol( // Answer the question: Where did THIS frame save the CALLER frame ("previous" // frame)'s register value? -#ifdef __AIX__ +#ifdef _AIX extern bool UGLY_HACK_NULL_TOPFRAME; #endif @@ -1525,7 +1525,7 @@ RegisterContextUnwind::SavedLocationForRegister( new_regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterInLiveRegisterContext; new_regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); -#ifdef __AIX__ +#ifdef _AIX if (UGLY_HACK_NULL_TOPFRAME && new_regloc.location.register_number == 0x20) { new_regloc.location.register_number = 0x24; } @@ -2390,7 +2390,7 @@ bool RegisterContextUnwind::ReadPC(addr_t &pc) { } } -#ifdef __AIX__ +#ifdef _AIX bool RegisterContextUnwind::ReadLR(addr_t &lr) { if (!IsValid()) return false; diff --git a/lldb/source/Target/UnwindLLDB.cpp b/lldb/source/Target/UnwindLLDB.cpp index 8edf359cac497..764bea5bf86c6 100644 --- a/lldb/source/Target/UnwindLLDB.cpp +++ b/lldb/source/Target/UnwindLLDB.cpp @@ -68,7 +68,7 @@ uint32_t UnwindLLDB::DoGetFrameCount() { return m_frames.size(); } -#ifdef __AIX__ +#ifdef _AIX bool UGLY_HACK_NULL_TOPFRAME = false; #endif @@ -95,7 +95,7 @@ bool UnwindLLDB::AddFirstFrame() { if (!reg_ctx_sp->ReadPC(first_cursor_sp->start_pc)) goto unwind_done; -#ifdef __AIX__ +#ifdef _AIX lldb::addr_t lr; if (!reg_ctx_sp->ReadLR(lr)) goto unwind_done; diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp index 45837503e8b73..d17ed77485d31 100644 --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -640,7 +640,7 @@ void sigwinch_handler(int signo) { } void sigint_handler(int signo) { -#if defined(_WIN32) || defined(__AIX__) // Restore handler as it is not persistent on Windows +#if defined(_WIN32) || defined(_AIX) // Restore handler as it is not persistent on Windows signal(SIGINT, sigint_handler); #endif static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT; @@ -729,7 +729,7 @@ static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) { int main(int argc, char const *argv[]) { // Editline uses for example iswprint which is dependent on LC_CTYPE. // FIXME: this caused unexpected SIGTRAP on AIX -#ifndef __AIX__ +#ifndef _AIX std::setlocale(LC_ALL, ""); std::setlocale(LC_CTYPE, ""); #endif diff --git a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp index 91bb2083a88b5..52c2eae0c9033 100644 --- a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp +++ b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp @@ -14,7 +14,7 @@ using HostObjectFile = ObjectFileMachO; #elif defined(_WIN32) #include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" using HostObjectFile = ObjectFilePECOFF; -#elif defined(__AIX__) +#elif defined(_AIX) #include "Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h" using HostObjectFile = ObjectFileXCOFF; #else @@ -49,7 +49,7 @@ using HostObjectFile = ObjectFileELF; #include "Plugins/Instruction/MIPS/EmulateInstructionMIPS.h" #endif -#if defined(__AIX__) +#if defined(_AIX) #include "Plugins/Instruction/PPC64/EmulateInstructionPPC64.h" #endif @@ -82,7 +82,7 @@ llvm::Error SystemInitializerLLGS::Initialize() { EmulateInstructionRISCV::Initialize(); #endif -#if defined(__AIX__) +#if defined(_AIX) EmulateInstructionPPC64::Initialize(); #endif @@ -108,7 +108,7 @@ void SystemInitializerLLGS::Terminate() { EmulateInstructionRISCV::Terminate(); #endif -#if defined(__AIX__) +#if defined(_AIX) EmulateInstructionPPC64::Terminate(); #endif diff --git a/lldb/tools/lldb-server/lldb-gdbserver.cpp b/lldb/tools/lldb-server/lldb-gdbserver.cpp index 844a6370bdb2e..dcbb421a73e25 100644 --- a/lldb/tools/lldb-server/lldb-gdbserver.cpp +++ b/lldb/tools/lldb-server/lldb-gdbserver.cpp @@ -45,7 +45,7 @@ #include "Plugins/Process/NetBSD/NativeProcessNetBSD.h" #elif defined(_WIN32) #include "Plugins/Process/Windows/Common/NativeProcessWindows.h" -#elif defined(__AIX__) +#elif defined(_AIX) #include "Plugins/Process/AIX/NativeProcessAIX.h" #endif @@ -72,7 +72,7 @@ typedef process_freebsd::NativeProcessFreeBSD::Manager NativeProcessManager; typedef process_netbsd::NativeProcessNetBSD::Manager NativeProcessManager; #elif defined(_WIN32) typedef NativeProcessWindows::Manager NativeProcessManager; -#elif defined(__AIX__) +#elif defined(_AIX) typedef process_aix::NativeProcessAIX::Manager NativeProcessManager; #else // Dummy implementation to make sure the code compiles diff --git a/lldb/unittests/Host/MainLoopTest.cpp b/lldb/unittests/Host/MainLoopTest.cpp index c76476c947054..5c042261b9ef2 100644 --- a/lldb/unittests/Host/MainLoopTest.cpp +++ b/lldb/unittests/Host/MainLoopTest.cpp @@ -223,7 +223,7 @@ TEST_F(MainLoopTest, PendingCallbackAfterLoopExited) { loop.AddPendingCallback([&](MainLoopBase &loop) {}); } -#if defined(LLVM_ON_UNIX) && !defined(__AIX__) +#if defined(LLVM_ON_UNIX) && !defined(_AIX) TEST_F(MainLoopTest, DetectsEOF) { PseudoTerminal term; diff --git a/lldb/unittests/Host/PipeTest.cpp b/lldb/unittests/Host/PipeTest.cpp index c1013aa7a7e4e..00ffd33d68f7a 100644 --- a/lldb/unittests/Host/PipeTest.cpp +++ b/lldb/unittests/Host/PipeTest.cpp @@ -55,7 +55,7 @@ TEST_F(PipeTest, OpenAsReader) { } #endif -#if !defined(__AIX__) +#if !defined(_AIX) TEST_F(PipeTest, WriteWithTimeout) { Pipe pipe; ASSERT_THAT_ERROR(pipe.CreateNew(false).ToError(), llvm::Succeeded()); diff --git a/lldb/unittests/Host/posix/TerminalTest.cpp b/lldb/unittests/Host/posix/TerminalTest.cpp index f3de92c0852b1..64e6be64db80c 100644 --- a/lldb/unittests/Host/posix/TerminalTest.cpp +++ b/lldb/unittests/Host/posix/TerminalTest.cpp @@ -94,14 +94,14 @@ TEST_F(TerminalTest, SetRaw) { TEST_F(TerminalTest, SetBaudRate) { struct termios terminfo; -#if (defined(__AIX__) && defined(B38400)) || !defined(__AIX__) +#if (defined(_AIX) && defined(B38400)) || !defined(_AIX) ASSERT_THAT_ERROR(m_term.SetBaudRate(38400), llvm::Succeeded()); ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0); EXPECT_EQ(cfgetispeed(&terminfo), static_cast(B38400)); EXPECT_EQ(cfgetospeed(&terminfo), static_cast(B38400)); #endif -#if (defined(__AIX__) && defined(B115200)) || !defined(__AIX__) +#if (defined(_AIX) && defined(B115200)) || !defined(_AIX) ASSERT_THAT_ERROR(m_term.SetBaudRate(115200), llvm::Succeeded()); ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0); EXPECT_EQ(cfgetispeed(&terminfo), static_cast(B115200)); >From a8020a6a8692f059679195ae1a0ef5e0eeee94c8 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Thu, 10 Oct 2024 04:52:08 -0500 Subject: [PATCH 11/50] Removed from lldb/CMakeLists --- lldb/CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt index a4fd8bccf056d..59cdc4593463c 100644 --- a/lldb/CMakeLists.txt +++ b/lldb/CMakeLists.txt @@ -38,10 +38,6 @@ endif() include(LLDBConfig) include(AddLLDB) -if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") - add_definitions("-D_AIX") -endif() - # Define the LLDB_CONFIGURATION_xxx matching the build type. if(uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" ) add_definitions(-DLLDB_CONFIGURATION_DEBUG) >From 7609ad339bfab48412221be54edc2d2d146279c3 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Thu, 14 Nov 2024 13:23:59 -0600 Subject: [PATCH 12/50] Patch for the Merge conflict of xcoff first merge with llvm --- .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 253 +++++++++++++++++- 1 file changed, 252 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index 395a126a01fce..a4d9ea295b4c3 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -188,7 +188,258 @@ bool ObjectFileXCOFF::ParseHeader() { if (module_sp) { std::lock_guard guard(module_sp->GetMutex()); m_sect_headers.clear(); - lldb::offs + lldb::offset_t offset = 0; + + if (ParseXCOFFHeader(m_data, &offset, m_xcoff_header)) { + m_data.SetAddressByteSize(GetAddressByteSize()); + if (m_xcoff_header.auxhdrsize > 0) + ParseXCOFFOptionalHeader(m_data, &offset); + ParseSectionHeaders(offset); + } + return true; + } + + return false; +} + +bool ObjectFileXCOFF::ParseXCOFFHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + xcoff_header_t &xcoff_header) { + //FIXME: data.ValidOffsetForDataOfSize + xcoff_header.magic = data.GetU16(offset_ptr); + xcoff_header.nsects = data.GetU16(offset_ptr); + xcoff_header.modtime = data.GetU32(offset_ptr); + xcoff_header.symoff = data.GetU64(offset_ptr); + xcoff_header.auxhdrsize = data.GetU16(offset_ptr); + xcoff_header.flags = data.GetU16(offset_ptr); + xcoff_header.nsyms = data.GetU32(offset_ptr); + return true; +} + +bool ObjectFileXCOFF::ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr) { + lldb::offset_t init_offset = *offset_ptr; + //FIXME: data.ValidOffsetForDataOfSize + m_xcoff_aux_header.AuxMagic = data.GetU16(offset_ptr); + m_xcoff_aux_header.Version = data.GetU16(offset_ptr); + m_xcoff_aux_header.ReservedForDebugger = data.GetU32(offset_ptr); + m_xcoff_aux_header.TextStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.DataStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.TOCAnchorAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfEntryPoint = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTOC = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfLoader = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.ModuleType = data.GetU16(offset_ptr); + m_xcoff_aux_header.CpuFlag = data.GetU8(offset_ptr); + m_xcoff_aux_header.CpuType = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.DataPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.StackPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.FlagAndTDataAlignment = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.InitDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.BssDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.EntryPointAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxStackSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfTData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.XCOFF64Flag = data.GetU16(offset_ptr); + lldb::offset_t last_offset = *offset_ptr; + if ((last_offset - init_offset) < m_xcoff_header.auxhdrsize) + *offset_ptr += (m_xcoff_header.auxhdrsize - (last_offset - init_offset)); + return true; +} + +bool ObjectFileXCOFF::ParseSectionHeaders( + uint32_t section_header_data_offset) { + const uint32_t nsects = m_xcoff_header.nsects; + m_sect_headers.clear(); + + if (nsects > 0) { + const size_t section_header_byte_size = nsects * m_binary->getSectionHeaderSize(); + lldb_private::DataExtractor section_header_data = + ReadImageData(section_header_data_offset, section_header_byte_size); + + lldb::offset_t offset = 0; + //FIXME: section_header_data.ValidOffsetForDataOfSize + m_sect_headers.resize(nsects); + + for (uint32_t idx = 0; idx < nsects; ++idx) { + const void *name_data = section_header_data.GetData(&offset, 8); + if (name_data) { + memcpy(m_sect_headers[idx].name, name_data, 8); + m_sect_headers[idx].phyaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].vmaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].size = section_header_data.GetU64(&offset); + m_sect_headers[idx].offset = section_header_data.GetU64(&offset); + m_sect_headers[idx].reloff = section_header_data.GetU64(&offset); + m_sect_headers[idx].lineoff = section_header_data.GetU64(&offset); + m_sect_headers[idx].nreloc = section_header_data.GetU32(&offset); + m_sect_headers[idx].nline = section_header_data.GetU32(&offset); + m_sect_headers[idx].flags = section_header_data.GetU32(&offset); + offset += 4; + } else { + offset += (m_binary->getSectionHeaderSize() - 8); + } + } + } + + return !m_sect_headers.empty(); +} + +lldb_private::DataExtractor ObjectFileXCOFF::ReadImageData(uint32_t offset, size_t size) { + if (!size) + return {}; + + if (m_data.ValidOffsetForDataOfSize(offset, size)) + return lldb_private::DataExtractor(m_data, offset, size); + + assert(0); + ProcessSP process_sp(m_process_wp.lock()); + lldb_private::DataExtractor data; + if (process_sp) { + auto data_up = std::make_unique(size, 0); + Status readmem_error; + size_t bytes_read = + process_sp->ReadMemory(offset, data_up->GetBytes(), + data_up->GetByteSize(), readmem_error); + if (bytes_read == size) { + DataBufferSP buffer_sp(data_up.release()); + data.SetData(buffer_sp, 0, buffer_sp->GetByteSize()); + } + } + return data; +} + +bool ObjectFileXCOFF::SetLoadAddress(Target &target, lldb::addr_t value, + bool value_is_offset) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (section_sp && !section_sp->IsThreadSpecific()) { + bool use_offset = false; + if (strcmp(section_sp->GetName().AsCString(), ".text") == 0 || + strcmp(section_sp->GetName().AsCString(), ".data") == 0 || + strcmp(section_sp->GetName().AsCString(), ".bss") == 0) + use_offset = true; + + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, (use_offset ? + (section_sp->GetFileOffset() + value) : (section_sp->GetFileAddress() + value)))) + ++num_loaded_sections; + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (type_id == 1 && section_sp && strcmp(section_sp->GetName().AsCString(), ".text") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileOffset() + value)) + ++num_loaded_sections; + } + } else if (type_id == 2 && section_sp && strcmp(section_sp->GetName().AsCString(), ".data") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileAddress() + value)) + ++num_loaded_sections; + } + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +ByteOrder ObjectFileXCOFF::GetByteOrder() const { + return eByteOrderBig; +} + +bool ObjectFileXCOFF::IsExecutable() const { + return true; +} + +uint32_t ObjectFileXCOFF::GetAddressByteSize() const { + if (m_xcoff_header.magic == XCOFF::XCOFF64) + return 8; + else if (m_xcoff_header.magic == XCOFF::XCOFF32) + return 4; + return 4; +} + +AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) { + return AddressClass::eUnknown; +} + +lldb::SymbolType ObjectFileXCOFF::MapSymbolType(llvm::object::SymbolRef::Type sym_type) { + if (sym_type == llvm::object::SymbolRef::ST_Function) + return lldb::eSymbolTypeCode; + else if (sym_type == llvm::object::SymbolRef::ST_Data) + return lldb::eSymbolTypeData; + return lldb::eSymbolTypeInvalid; +} + +void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) { + SectionList *sect_list = GetSectionList(); + const uint32_t num_syms = m_xcoff_header.nsyms; + uint32_t sidx = 0; + if (num_syms > 0 && m_xcoff_header.symoff > 0) { + const uint32_t symbol_size = XCOFF::SymbolTableEntrySize; + const size_t symbol_data_size = num_syms * symbol_size; + lldb_private::DataExtractor symtab_data = + ReadImageData(m_xcoff_header.symoff, symbol_data_size); + + lldb::offset_t offset = 0; + std::string symbol_name; + Symbol *symbols = lldb_symtab.Resize(num_syms); + llvm::object::symbol_iterator SI = m_binary->symbol_begin(); + for (uint32_t i = 0; i < num_syms; ++i, ++SI) { + xcoff_symbol_t symbol; + const uint32_t symbol_offset = offset; + symbol.value = symtab_data.GetU64(&offset); + symbol.offset = symtab_data.GetU32(&offset); + Expected symbol_name_or_err = m_binary->getStringTableEntry(symbol.offset); + if (!symbol_name_or_err) { + consumeError(symbol_name_or_err.takeError()); + return; + } + StringRef symbol_name_str = symbol_name_or_err.get(); + symbol_name.assign(symbol_name_str.data()); symbol.sect = symtab_data.GetU16(&offset); symbol.type = symtab_data.GetU16(&offset); symbol.storage = symtab_data.GetU8(&offset); >From dd56fce276b60b40e1997292b3f554a20157661a Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 17 Nov 2024 00:15:01 -0600 Subject: [PATCH 13/50] Attach fix for AIX --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 130 ++++++++++++++++++ .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 5 +- 2 files changed, 134 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 7f3a638d5b028..acaa6a72edded 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -18,8 +18,13 @@ #include "lldb/Target/ThreadPlanStepInstruction.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" +#include "llvm/Support/FileSystem.h" #if defined(_AIX) #include +#include +#include +#include +#include #endif /*#include "llvm/ADT/Triple.h" @@ -131,14 +136,139 @@ bool DynamicLoaderAIXDYLD::NotifyBreakpointHit( lldb::user_id_t break_loc_id) { } + +void DynamicLoaderAIXDYLD::ResolveExecutableModule( + lldb::ModuleSP &module_sp) { + Log *log = GetLog(LLDBLog::DynamicLoader); + + if (m_process == nullptr) + return; + + auto &target = m_process->GetTarget(); + const auto platform_sp = target.GetPlatform(); + + ProcessInstanceInfo process_info; + if (!m_process->GetProcessInfo(process_info)) { + LLDB_LOGF(log, + "DynamicLoaderPOSIXDYLD::%s - failed to get process info for " + "pid %" PRIu64, + __FUNCTION__, m_process->GetID()); + return; + } + + char procinfo_path[64], exe_path[PATH_MAX], arg_buffer[8192]; + struct procsinfo64 procs_info; + int32long64_t pid = m_process->GetID(); + std::string proc_file = "/proc/" + std::to_string(pid) + "/psinfo"; + std::string cwd_link = "/proc/" + std::to_string(pid) + "/cwd"; + psinfo_t psinfo; + std::ifstream file(proc_file, std::ios::binary); + if(!file.is_open()) + { + LLDB_LOGF(log, "Error psinfo "); + } + file.read(reinterpret_cast(&psinfo), sizeof(psinfo_t)); + if(!file) + LLDB_LOGF(log, "Error psinfo: Failed to read "); + + std::string relative_path(psinfo.pr_fname); + LLDB_LOGF(log, "relative path %s",relative_path.c_str()); + + char cwd[PATH_MAX]; + char resolved_path[PATH_MAX]; + std::string executable_name; + bool found = 0; + if(readlink(cwd_link.c_str(), cwd, sizeof(cwd)) != -1){ + std::filesystem::path full_path = std::filesystem::path(cwd)/relative_path; + if(realpath(full_path.c_str(), resolved_path)) { + LLDB_LOGF(log, " RESOLVED PATH: %s", resolved_path); + found = 1; + } + else + perror("realpath error");} + + executable_name = resolved_path; + if(found == 0) { + std::string command_line(psinfo.pr_psargs); + LLDB_LOGF(log, "command line %s",command_line.c_str()); + if (!command_line.empty()) { + size_t space1 = command_line.find(' '); + executable_name = command_line.substr(0, space1); + LLDB_LOGF(log, "executable name %s",executable_name.c_str()); + } + } + + LLDB_LOGF(log, "executable name %s",executable_name.c_str()); + /*target.SetExecutableModule(target.GetOrCreateModule(lldb_private::FileSpec(resolved_path), + true),true);*/ + process_info.SetExecutableFile(lldb_private::FileSpec(executable_name), + true); + +/* snprintf(procinfo_path, sizeof(procinfo_path), "/proc/%d/object/a.out", pid); + ssize_t len = readlink(procinfo_path, exe_path, sizeof(exe_path) - 1); + exe_path[len] = '\0'; + int num_procs = getprocs64(&procs_info, sizeof(struct procsinfo64), NULL, 0, + &pid, + 1); + int result = getargs(pid, arg_buffer, sizeof(arg_buffer)); + std::vector args; + char *arg_start = arg_buffer; + while(*arg_start != '\0') { + args.emplace_back(arg_start); + arg_start += strlen(arg_start) + 1; + } + + LLDB_LOGF( + log, "1. DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s" + ", pid: %d, current_path: %s", + __FUNCTION__, m_process->GetID(), + args[0], pid, current_path.c_str()); + LLDB_LOGF( + log, "1. DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s" + "num_procs: %d, pid: %d", + __FUNCTION__, m_process->GetID(), + std::string(procs_info.pi_comm).c_str(), num_procs, pid); + if(num_procs <= 0) + perror("getprocs64 failed"); */ + + LLDB_LOGF( + log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s", + __FUNCTION__, m_process->GetID(), + process_info.GetExecutableFile().GetPath().c_str()); + + ModuleSpec module_spec(process_info.GetExecutableFile(), + process_info.GetArchitecture()); + if (module_sp && module_sp->MatchesModuleSpec(module_spec)) + return; + + const auto executable_search_paths(Target::GetDefaultExecutableSearchPaths()); + auto error = platform_sp->ResolveExecutable( + module_spec, module_sp, + !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr); + if (error.Fail()) { + StreamString stream; + module_spec.Dump(stream); + + LLDB_LOGF(log, + "DynamicLoaderPOSIXDYLD::%s - failed to resolve executable " + "with module spec \"%s\": %s", + __FUNCTION__, stream.GetData(), error.AsCString()); + return; + } + + target.SetExecutableModule(module_sp, eLoadDependentsNo); +} + void DynamicLoaderAIXDYLD::DidAttach() { Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); ModuleSP executable = GetTargetExecutable(); + ResolveExecutableModule(executable); if (!executable.get()) return; + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); // Try to fetch the load address of the file from the process, since there // could be randomization of the load address. diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h index ae4b7aca66dcc..0ffbe688e0069 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -24,7 +24,7 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { static void Initialize(); static void Terminate(); - static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; } + static llvm::StringRef GetPluginNameStatic() { return "aix-dyld"; } static llvm::StringRef GetPluginDescriptionStatic(); static DynamicLoader *CreateInstance(Process *process, bool force); @@ -46,6 +46,9 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { protected: lldb::addr_t GetLoadAddress(lldb::ModuleSP executable); + /// Loads Module from inferior process. + void ResolveExecutableModule(lldb::ModuleSP &module_sp); + private: std::map m_loaded_modules; }; >From 48b8b1b6532181acab0ee1710d5f4ab92903ae78 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 18 Nov 2024 02:56:31 -0600 Subject: [PATCH 14/50] Cleanup --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 65 +++++-------------- 1 file changed, 17 insertions(+), 48 deletions(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index acaa6a72edded..1a98bb9334043 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -156,81 +156,50 @@ void DynamicLoaderAIXDYLD::ResolveExecutableModule( return; } - char procinfo_path[64], exe_path[PATH_MAX], arg_buffer[8192]; - struct procsinfo64 procs_info; int32long64_t pid = m_process->GetID(); + char cwd[PATH_MAX], resolved_path[PATH_MAX]; + std::string executable_name; + bool path_resolved = false; + psinfo_t psinfo; + std::string proc_file = "/proc/" + std::to_string(pid) + "/psinfo"; std::string cwd_link = "/proc/" + std::to_string(pid) + "/cwd"; - psinfo_t psinfo; std::ifstream file(proc_file, std::ios::binary); if(!file.is_open()) - { - LLDB_LOGF(log, "Error psinfo "); - } + LLDB_LOGF(log, "Error: Unable to access process info "); + file.read(reinterpret_cast(&psinfo), sizeof(psinfo_t)); if(!file) - LLDB_LOGF(log, "Error psinfo: Failed to read "); + LLDB_LOGF(log, "Process info error: Failed to read "); std::string relative_path(psinfo.pr_fname); - LLDB_LOGF(log, "relative path %s",relative_path.c_str()); + LLDB_LOGF(log, "Relative path %s",relative_path.c_str()); - char cwd[PATH_MAX]; - char resolved_path[PATH_MAX]; - std::string executable_name; - bool found = 0; if(readlink(cwd_link.c_str(), cwd, sizeof(cwd)) != -1){ std::filesystem::path full_path = std::filesystem::path(cwd)/relative_path; if(realpath(full_path.c_str(), resolved_path)) { - LLDB_LOGF(log, " RESOLVED PATH: %s", resolved_path); - found = 1; + LLDB_LOGF(log, "Resolved Path using process info : %s", resolved_path); + path_resolved = true; } else - perror("realpath error");} + LLDB_LOGF(log, "Realpath error: Unable to resolve. "); + } executable_name = resolved_path; - if(found == 0) { + if(path_resolved == false) { std::string command_line(psinfo.pr_psargs); - LLDB_LOGF(log, "command line %s",command_line.c_str()); + LLDB_LOGF(log, "Command line: %s",command_line.c_str()); if (!command_line.empty()) { size_t space1 = command_line.find(' '); executable_name = command_line.substr(0, space1); - LLDB_LOGF(log, "executable name %s",executable_name.c_str()); + LLDB_LOGF(log, "Resolved path using command line arg %s",executable_name.c_str()); } } - LLDB_LOGF(log, "executable name %s",executable_name.c_str()); - /*target.SetExecutableModule(target.GetOrCreateModule(lldb_private::FileSpec(resolved_path), - true),true);*/ + LLDB_LOGF(log, "Executable Name %s",executable_name.c_str()); process_info.SetExecutableFile(lldb_private::FileSpec(executable_name), true); -/* snprintf(procinfo_path, sizeof(procinfo_path), "/proc/%d/object/a.out", pid); - ssize_t len = readlink(procinfo_path, exe_path, sizeof(exe_path) - 1); - exe_path[len] = '\0'; - int num_procs = getprocs64(&procs_info, sizeof(struct procsinfo64), NULL, 0, - &pid, - 1); - int result = getargs(pid, arg_buffer, sizeof(arg_buffer)); - std::vector args; - char *arg_start = arg_buffer; - while(*arg_start != '\0') { - args.emplace_back(arg_start); - arg_start += strlen(arg_start) + 1; - } - - LLDB_LOGF( - log, "1. DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s" - ", pid: %d, current_path: %s", - __FUNCTION__, m_process->GetID(), - args[0], pid, current_path.c_str()); - LLDB_LOGF( - log, "1. DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s" - "num_procs: %d, pid: %d", - __FUNCTION__, m_process->GetID(), - std::string(procs_info.pi_comm).c_str(), num_procs, pid); - if(num_procs <= 0) - perror("getprocs64 failed"); */ - LLDB_LOGF( log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s", __FUNCTION__, m_process->GetID(), >From d410734184a681b3e95949d3953142995682d7f6 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Tue, 19 Nov 2024 09:44:42 -0600 Subject: [PATCH 15/50] Patch in MainLoopPosix.cpp for runtime issue --- lldb/source/Host/posix/MainLoopPosix.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp index f68268f114075..4c617cdde67ba 100644 --- a/lldb/source/Host/posix/MainLoopPosix.cpp +++ b/lldb/source/Host/posix/MainLoopPosix.cpp @@ -149,7 +149,7 @@ Status MainLoopPosix::RunImpl::Poll() { int timeout; timeout = -1; - pthread_sigmask(SIG_SETMASK, &sigmask, &origmask); + pthread_sigmask(SIG_SETMASK, nullptr, &origmask); int ready = poll(read_fds.data(), read_fds.size(), timeout); pthread_sigmask(SIG_SETMASK, &origmask, nullptr); if (ready == -1 && errno != EINTR) >From 48f39dadbbdb4874fbd9b6350933dc67e8823339 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Thu, 5 Dec 2024 05:13:14 -0600 Subject: [PATCH 16/50] Patch for compilation failure in DomainSocket.cpp, AbstractSocket.cpp and AbstractSocket.h --- lldb/include/lldb/Host/aix/AbstractSocket.h | 2 +- lldb/source/Host/aix/AbstractSocket.cpp | 3 +-- lldb/source/Host/posix/DomainSocket.cpp | 4 ++++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lldb/include/lldb/Host/aix/AbstractSocket.h b/lldb/include/lldb/Host/aix/AbstractSocket.h index 78a567a6b9095..accfd01457a5e 100644 --- a/lldb/include/lldb/Host/aix/AbstractSocket.h +++ b/lldb/include/lldb/Host/aix/AbstractSocket.h @@ -14,7 +14,7 @@ namespace lldb_private { class AbstractSocket : public DomainSocket { public: - AbstractSocket(bool child_processes_inherit); + AbstractSocket(); protected: size_t GetNameOffset() const override; diff --git a/lldb/source/Host/aix/AbstractSocket.cpp b/lldb/source/Host/aix/AbstractSocket.cpp index bfb67d452f7ec..fddf78f54f46d 100644 --- a/lldb/source/Host/aix/AbstractSocket.cpp +++ b/lldb/source/Host/aix/AbstractSocket.cpp @@ -13,8 +13,7 @@ using namespace lldb; using namespace lldb_private; -AbstractSocket::AbstractSocket(bool child_processes_inherit) - : DomainSocket(ProtocolUnixAbstract, child_processes_inherit) {} +AbstractSocket::AbstractSocket() : DomainSocket(ProtocolUnixAbstract) {} size_t AbstractSocket::GetNameOffset() const { return 1; } diff --git a/lldb/source/Host/posix/DomainSocket.cpp b/lldb/source/Host/posix/DomainSocket.cpp index 9a0b385d998bf..6cbffb2d9c4bd 100644 --- a/lldb/source/Host/posix/DomainSocket.cpp +++ b/lldb/source/Host/posix/DomainSocket.cpp @@ -17,6 +17,10 @@ #include #include +#if defined(_AIX) +#include +#endif + using namespace lldb; using namespace lldb_private; >From 97531f7bf6e385f0f51d860c6eea17aeb32f6594 Mon Sep 17 00:00:00 2001 From: Lakshmi-Surekha Date: Thu, 19 Dec 2024 06:38:36 -0600 Subject: [PATCH 17/50] Patch for merge conflict in ObjectFileXCOFF.cpp & ObjectFileXCOFF.h --- .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 253 +++++++++++++++++- 1 file changed, 252 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index 395a126a01fce..a4d9ea295b4c3 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -188,7 +188,258 @@ bool ObjectFileXCOFF::ParseHeader() { if (module_sp) { std::lock_guard guard(module_sp->GetMutex()); m_sect_headers.clear(); - lldb::offs + lldb::offset_t offset = 0; + + if (ParseXCOFFHeader(m_data, &offset, m_xcoff_header)) { + m_data.SetAddressByteSize(GetAddressByteSize()); + if (m_xcoff_header.auxhdrsize > 0) + ParseXCOFFOptionalHeader(m_data, &offset); + ParseSectionHeaders(offset); + } + return true; + } + + return false; +} + +bool ObjectFileXCOFF::ParseXCOFFHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + xcoff_header_t &xcoff_header) { + //FIXME: data.ValidOffsetForDataOfSize + xcoff_header.magic = data.GetU16(offset_ptr); + xcoff_header.nsects = data.GetU16(offset_ptr); + xcoff_header.modtime = data.GetU32(offset_ptr); + xcoff_header.symoff = data.GetU64(offset_ptr); + xcoff_header.auxhdrsize = data.GetU16(offset_ptr); + xcoff_header.flags = data.GetU16(offset_ptr); + xcoff_header.nsyms = data.GetU32(offset_ptr); + return true; +} + +bool ObjectFileXCOFF::ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr) { + lldb::offset_t init_offset = *offset_ptr; + //FIXME: data.ValidOffsetForDataOfSize + m_xcoff_aux_header.AuxMagic = data.GetU16(offset_ptr); + m_xcoff_aux_header.Version = data.GetU16(offset_ptr); + m_xcoff_aux_header.ReservedForDebugger = data.GetU32(offset_ptr); + m_xcoff_aux_header.TextStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.DataStartAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.TOCAnchorAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfEntryPoint = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTOC = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfLoader = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfText = data.GetU16(offset_ptr); + m_xcoff_aux_header.MaxAlignOfData = data.GetU16(offset_ptr); + m_xcoff_aux_header.ModuleType = data.GetU16(offset_ptr); + m_xcoff_aux_header.CpuFlag = data.GetU8(offset_ptr); + m_xcoff_aux_header.CpuType = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.DataPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.StackPageSize = data.GetU8(offset_ptr); + m_xcoff_aux_header.FlagAndTDataAlignment = data.GetU8(offset_ptr); + m_xcoff_aux_header.TextSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.InitDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.BssDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.EntryPointAddr = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxStackSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.MaxDataSize = data.GetU64(offset_ptr); + m_xcoff_aux_header.SecNumOfTData = data.GetU16(offset_ptr); + m_xcoff_aux_header.SecNumOfTBSS = data.GetU16(offset_ptr); + m_xcoff_aux_header.XCOFF64Flag = data.GetU16(offset_ptr); + lldb::offset_t last_offset = *offset_ptr; + if ((last_offset - init_offset) < m_xcoff_header.auxhdrsize) + *offset_ptr += (m_xcoff_header.auxhdrsize - (last_offset - init_offset)); + return true; +} + +bool ObjectFileXCOFF::ParseSectionHeaders( + uint32_t section_header_data_offset) { + const uint32_t nsects = m_xcoff_header.nsects; + m_sect_headers.clear(); + + if (nsects > 0) { + const size_t section_header_byte_size = nsects * m_binary->getSectionHeaderSize(); + lldb_private::DataExtractor section_header_data = + ReadImageData(section_header_data_offset, section_header_byte_size); + + lldb::offset_t offset = 0; + //FIXME: section_header_data.ValidOffsetForDataOfSize + m_sect_headers.resize(nsects); + + for (uint32_t idx = 0; idx < nsects; ++idx) { + const void *name_data = section_header_data.GetData(&offset, 8); + if (name_data) { + memcpy(m_sect_headers[idx].name, name_data, 8); + m_sect_headers[idx].phyaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].vmaddr = section_header_data.GetU64(&offset); + m_sect_headers[idx].size = section_header_data.GetU64(&offset); + m_sect_headers[idx].offset = section_header_data.GetU64(&offset); + m_sect_headers[idx].reloff = section_header_data.GetU64(&offset); + m_sect_headers[idx].lineoff = section_header_data.GetU64(&offset); + m_sect_headers[idx].nreloc = section_header_data.GetU32(&offset); + m_sect_headers[idx].nline = section_header_data.GetU32(&offset); + m_sect_headers[idx].flags = section_header_data.GetU32(&offset); + offset += 4; + } else { + offset += (m_binary->getSectionHeaderSize() - 8); + } + } + } + + return !m_sect_headers.empty(); +} + +lldb_private::DataExtractor ObjectFileXCOFF::ReadImageData(uint32_t offset, size_t size) { + if (!size) + return {}; + + if (m_data.ValidOffsetForDataOfSize(offset, size)) + return lldb_private::DataExtractor(m_data, offset, size); + + assert(0); + ProcessSP process_sp(m_process_wp.lock()); + lldb_private::DataExtractor data; + if (process_sp) { + auto data_up = std::make_unique(size, 0); + Status readmem_error; + size_t bytes_read = + process_sp->ReadMemory(offset, data_up->GetBytes(), + data_up->GetByteSize(), readmem_error); + if (bytes_read == size) { + DataBufferSP buffer_sp(data_up.release()); + data.SetData(buffer_sp, 0, buffer_sp->GetByteSize()); + } + } + return data; +} + +bool ObjectFileXCOFF::SetLoadAddress(Target &target, lldb::addr_t value, + bool value_is_offset) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (section_sp && !section_sp->IsThreadSpecific()) { + bool use_offset = false; + if (strcmp(section_sp->GetName().AsCString(), ".text") == 0 || + strcmp(section_sp->GetName().AsCString(), ".data") == 0 || + strcmp(section_sp->GetName().AsCString(), ".bss") == 0) + use_offset = true; + + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, (use_offset ? + (section_sp->GetFileOffset() + value) : (section_sp->GetFileAddress() + value)))) + ++num_loaded_sections; + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, + bool value_is_offset, int type_id) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (type_id == 1 && section_sp && strcmp(section_sp->GetName().AsCString(), ".text") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileOffset() + value)) + ++num_loaded_sections; + } + } else if (type_id == 2 && section_sp && strcmp(section_sp->GetName().AsCString(), ".data") == 0) { + if (!section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileAddress() + value)) + ++num_loaded_sections; + } + } + } + changed = num_loaded_sections > 0; + } + } + return changed; +} + +ByteOrder ObjectFileXCOFF::GetByteOrder() const { + return eByteOrderBig; +} + +bool ObjectFileXCOFF::IsExecutable() const { + return true; +} + +uint32_t ObjectFileXCOFF::GetAddressByteSize() const { + if (m_xcoff_header.magic == XCOFF::XCOFF64) + return 8; + else if (m_xcoff_header.magic == XCOFF::XCOFF32) + return 4; + return 4; +} + +AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) { + return AddressClass::eUnknown; +} + +lldb::SymbolType ObjectFileXCOFF::MapSymbolType(llvm::object::SymbolRef::Type sym_type) { + if (sym_type == llvm::object::SymbolRef::ST_Function) + return lldb::eSymbolTypeCode; + else if (sym_type == llvm::object::SymbolRef::ST_Data) + return lldb::eSymbolTypeData; + return lldb::eSymbolTypeInvalid; +} + +void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) { + SectionList *sect_list = GetSectionList(); + const uint32_t num_syms = m_xcoff_header.nsyms; + uint32_t sidx = 0; + if (num_syms > 0 && m_xcoff_header.symoff > 0) { + const uint32_t symbol_size = XCOFF::SymbolTableEntrySize; + const size_t symbol_data_size = num_syms * symbol_size; + lldb_private::DataExtractor symtab_data = + ReadImageData(m_xcoff_header.symoff, symbol_data_size); + + lldb::offset_t offset = 0; + std::string symbol_name; + Symbol *symbols = lldb_symtab.Resize(num_syms); + llvm::object::symbol_iterator SI = m_binary->symbol_begin(); + for (uint32_t i = 0; i < num_syms; ++i, ++SI) { + xcoff_symbol_t symbol; + const uint32_t symbol_offset = offset; + symbol.value = symtab_data.GetU64(&offset); + symbol.offset = symtab_data.GetU32(&offset); + Expected symbol_name_or_err = m_binary->getStringTableEntry(symbol.offset); + if (!symbol_name_or_err) { + consumeError(symbol_name_or_err.takeError()); + return; + } + StringRef symbol_name_str = symbol_name_or_err.get(); + symbol_name.assign(symbol_name_str.data()); symbol.sect = symtab_data.GetU16(&offset); symbol.type = symtab_data.GetU16(&offset); symbol.storage = symtab_data.GetU8(&offset); >From 71d2fcff8975831e7f0a657481220749b0a473dc Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Tue, 24 Dec 2024 02:05:35 -0600 Subject: [PATCH 18/50] Added upcoming clang-format and other merge changes --- .../posix/ConnectionFileDescriptorPosix.cpp | 9 ++-- lldb/source/Host/posix/DomainSocket.cpp | 5 ++- lldb/source/Host/posix/FileSystemPosix.cpp | 2 +- lldb/source/Host/posix/MainLoopPosix.cpp | 43 ++++++++----------- .../Host/posix/ProcessLauncherPosixFork.cpp | 2 +- lldb/source/Plugins/Language/ObjC/Cocoa.cpp | 17 +++----- .../BSD-Archive/ObjectContainerBSDArchive.cpp | 29 +++++++------ lldb/source/Utility/ArchSpec.cpp | 1 - 8 files changed, 49 insertions(+), 59 deletions(-) diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index 32d034e60d26c..e3d1300cf76ed 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -119,8 +119,7 @@ bool ConnectionFileDescriptor::IsConnected() const { ConnectionStatus ConnectionFileDescriptor::Connect(llvm::StringRef path, Status *error_ptr) { - return Connect( - path, [](llvm::StringRef) {}, error_ptr); + return Connect(path, [](llvm::StringRef) {}, error_ptr); } ConnectionStatus @@ -716,8 +715,7 @@ ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, ConnectionStatus ConnectionFileDescriptor::ConnectFile( llvm::StringRef s, socket_id_callback_type socket_id_callback, Status *error_ptr) { -#if !defined(_AIX) -#if LLDB_ENABLE_POSIX +#if LLDB_ENABLE_POSIX && !defined(_AIX) std::string addr_str = s.str(); // file:///PATH int fd = FileSystem::Instance().Open(addr_str.c_str(), O_RDWR); @@ -748,8 +746,7 @@ ConnectionStatus ConnectionFileDescriptor::ConnectFile( m_io_sp = std::make_shared(fd, File::eOpenOptionReadWrite, true); return eConnectionStatusSuccess; -#endif // LLDB_ENABLE_POSIX -#endif +#endif // LLDB_ENABLE_POSIX && !defined(_AIX) llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX"); } diff --git a/lldb/source/Host/posix/DomainSocket.cpp b/lldb/source/Host/posix/DomainSocket.cpp index 6cbffb2d9c4bd..28db5964a5a8a 100644 --- a/lldb/source/Host/posix/DomainSocket.cpp +++ b/lldb/source/Host/posix/DomainSocket.cpp @@ -89,8 +89,9 @@ Status DomainSocket::Connect(llvm::StringRef name) { m_socket = CreateSocket(kDomain, kType, 0, error); if (error.Fail()) return error; - if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(), - (struct sockaddr *)&saddr_un, saddr_un_len) < 0) + if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(), + (struct sockaddr *)&saddr_un, + saddr_un_len) < 0) SetLastError(error); return error; diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index 21da5612ff6b8..1a84f550662d7 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,7 +11,7 @@ // C includes #include #include -#if !defined(_AIX) +#ifndef _AIX #include #endif #include diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp index 125b954023dc0..e4ff928a58962 100644 --- a/lldb/source/Host/posix/MainLoopPosix.cpp +++ b/lldb/source/Host/posix/MainLoopPosix.cpp @@ -99,6 +99,7 @@ class MainLoopPosix::RunImpl { ~RunImpl() = default; Status Poll(); + int StartPoll(std::optional point); void ProcessReadEvents(); private: @@ -159,6 +160,22 @@ MainLoopPosix::RunImpl::RunImpl(MainLoopPosix &loop) : loop(loop) { read_fds.reserve(loop.m_read_fds.size()); } +int MainLoopPosix::RunImpl::StartPoll( + std::optional point) { +#if HAVE_PPOLL + return ppoll(read_fds.data(), read_fds.size(), ToTimeSpec(point), + /*sigmask=*/nullptr); +#else + using namespace std::chrono; + int timeout = -1; + if (point) { + nanoseconds dur = std::max(*point - steady_clock::now(), nanoseconds(0)); + timeout = ceil(dur).count(); + } + return poll(read_fds.data(), read_fds.size(), timeout); +#endif +} + Status MainLoopPosix::RunImpl::Poll() { read_fds.clear(); @@ -169,24 +186,10 @@ Status MainLoopPosix::RunImpl::Poll() { pfd.revents = 0; read_fds.push_back(pfd); } + int ready = StartPoll(loop.GetNextWakeupTime()); -#if defined(_AIX) - sigset_t origmask; - int timeout; - - timeout = -1; - pthread_sigmask(SIG_SETMASK, nullptr, &origmask); - int ready = poll(read_fds.data(), read_fds.size(), timeout); - pthread_sigmask(SIG_SETMASK, &origmask, nullptr); if (ready == -1 && errno != EINTR) return Status(errno, eErrorTypePOSIX); -#else - if (ppoll(read_fds.data(), read_fds.size(), - ToTimeSpec(loop.GetNextWakeupTime()), - /*sigmask=*/nullptr) == -1 && - errno != EINTR) - return Status(errno, eErrorTypePOSIX); -#endif return Status(); } @@ -291,16 +294,6 @@ MainLoopPosix::RegisterSignal(int signo, const Callback &callback, UNUSED_IF_ASSERT_DISABLED(ret); assert(ret == 0 && "sigaction failed"); -#if HAVE_SYS_EVENT_H - struct kevent ev; - EV_SET(&ev, signo, EVFILT_SIGNAL, EV_ADD, 0, 0, 0); - ret = kevent(m_kqueue, &ev, 1, nullptr, 0, nullptr); - assert(ret == 0); -#endif - - // If we're using kqueue, the signal needs to be unblocked in order to - // receive it. If using pselect/ppoll, we need to block it, and later unblock - // it as a part of the system call. ret = pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, &old_set); assert(ret == 0 && "pthread_sigmask failed"); info.was_blocked = sigismember(&old_set, signo); diff --git a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp index 52fc58aa21bf4..7b8b42a4b7fe0 100644 --- a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp +++ b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp @@ -197,7 +197,7 @@ struct ForkLaunchInfo { #else if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1) #endif - ExitWithError(error_fd, "ptrace"); + ExitWithError(error_fd, "ptrace"); } // Execute. We should never return... diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index 1d841a032aa6e..1d79edbede5d6 100644 --- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -31,7 +31,6 @@ #include "llvm/ADT/APInt.h" #include "llvm/ADT/bit.h" - using namespace lldb; using namespace lldb_private; using namespace lldb_private::formatters; @@ -267,21 +266,21 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider( if (class_name == "NSIndexSet" || class_name == "NSMutableIndexSet") { // Foundation version 2000 added a bitmask if the index set fit in 64 bits // and a Tagged Pointer version if the bitmask is small enough to fit in - // the tagged pointer payload. + // the tagged pointer payload. // It also changed the layout (but not the size) of the set descriptor. // First check whether this is a tagged pointer. The bitmask will be in // the payload of the tagged pointer. uint64_t payload; - if (runtime->GetFoundationVersion() >= 2000 - && descriptor->GetTaggedPointerInfo(nullptr, nullptr, &payload)) { + if (runtime->GetFoundationVersion() >= 2000 && + descriptor->GetTaggedPointerInfo(nullptr, nullptr, &payload)) { count = llvm::popcount(payload); break; } // The first 32 bits describe the index set in all cases: Status error; uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory( - valobj_addr + ptr_size, 4, 0, error); + valobj_addr + ptr_size, 4, 0, error); if (error.Fail()) return false; // Now check if the index is held in a bitmask in the object: @@ -292,7 +291,7 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider( if ((mode & 2) == 2) { // The bitfield is a 64 bit uint at the beginning of the data var. uint64_t bitfield = process_sp->ReadUnsignedIntegerFromMemory( - valobj_addr + 2 * ptr_size, 8, 0, error); + valobj_addr + 2 * ptr_size, 8, 0, error); if (error.Fail()) return false; count = llvm::popcount(bitfield); @@ -309,7 +308,7 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider( count = 0; break; } - + if ((mode & 2) == 2) mode = 1; // this means the set only has one range else @@ -1227,8 +1226,7 @@ bool lldb_private::formatters::ObjCSELSummaryProvider( time_t lldb_private::formatters::GetOSXEpoch() { static time_t epoch = 0; if (!epoch) { -#if !defined(_AIX) -#ifndef _WIN32 +#if !defined(_WIN32) && !defined(_AIX) tzset(); tm tm_epoch; tm_epoch.tm_sec = 0; @@ -1241,7 +1239,6 @@ time_t lldb_private::formatters::GetOSXEpoch() { tm_epoch.tm_gmtoff = 0; tm_epoch.tm_zone = nullptr; epoch = timegm(&tm_epoch); -#endif #endif } return epoch; diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 4f747ab20c9ef..b202898ff438a 100644 --- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -81,10 +81,10 @@ size_t ObjectContainerBSDArchive::Archive::ParseObjects() { std::unique_ptr mem_buffer = llvm::MemoryBuffer::getMemBuffer( - llvm::StringRef((const char *)data.GetDataStart(), - data.GetByteSize()), - llvm::StringRef(), - /*RequiresNullTerminator=*/false); + llvm::StringRef((const char *)data.GetDataStart(), + data.GetByteSize()), + llvm::StringRef(), + /*RequiresNullTerminator=*/false); auto exp_ar = llvm::object::Archive::create(mem_buffer->getMemBufferRef()); if (!exp_ar) { @@ -95,7 +95,7 @@ size_t ObjectContainerBSDArchive::Archive::ParseObjects() { llvm::Error iter_err = llvm::Error::success(); Object obj; - for (const auto &child: llvm_archive->children(iter_err)) { + for (const auto &child : llvm_archive->children(iter_err)) { obj.Clear(); auto exp_name = child.getName(); if (exp_name) { @@ -111,7 +111,9 @@ size_t ObjectContainerBSDArchive::Archive::ParseObjects() { obj.modification_time = std::chrono::duration_cast( std::chrono::time_point_cast( - exp_mtime.get()).time_since_epoch()).count(); + exp_mtime.get()) + .time_since_epoch()) + .count(); } else { LLDB_LOG_ERROR(l, exp_mtime.takeError(), "failed to get archive object time: {0}"); @@ -331,21 +333,21 @@ ObjectContainer *ObjectContainerBSDArchive::CreateInstance( ArchiveType ObjectContainerBSDArchive::MagicBytesMatch(const DataExtractor &data) { uint32_t offset = 0; - const char *armag = (const char *)data.PeekData(offset, - sizeof(ar_hdr) + SARMAG); + const char *armag = + (const char *)data.PeekData(offset, sizeof(ar_hdr) + SARMAG); if (armag == nullptr) return ArchiveType::Invalid; ArchiveType result = ArchiveType::Invalid; if (strncmp(armag, ArchiveMagic, SARMAG) == 0) - result = ArchiveType::Archive; + result = ArchiveType::Archive; else if (strncmp(armag, ThinArchiveMagic, SARMAG) == 0) - result = ArchiveType::ThinArchive; + result = ArchiveType::ThinArchive; else - return ArchiveType::Invalid; + return ArchiveType::Invalid; armag += offsetof(struct ar_hdr, ar_fmag) + SARMAG; if (strncmp(armag, ARFMAG, 2) == 0) - return result; + return result; return ArchiveType::Invalid; } @@ -443,7 +445,8 @@ size_t ObjectContainerBSDArchive::GetModuleSpecifications( return 0; const size_t initial_count = specs.GetSize(); - llvm::sys::TimePoint<> file_mod_time = FileSystem::Instance().GetModificationTime(file); + llvm::sys::TimePoint<> file_mod_time = + FileSystem::Instance().GetModificationTime(file); Archive::shared_ptr archive_sp( Archive::FindCachedArchive(file, ArchSpec(), file_mod_time, file_offset)); bool set_archive_arch = false; diff --git a/lldb/source/Utility/ArchSpec.cpp b/lldb/source/Utility/ArchSpec.cpp index ac91183a271cc..85bb85044ec15 100644 --- a/lldb/source/Utility/ArchSpec.cpp +++ b/lldb/source/Utility/ArchSpec.cpp @@ -14,7 +14,6 @@ #include "lldb/lldb-defines.h" #include "llvm/ADT/STLExtras.h" #include "llvm/BinaryFormat/COFF.h" -#include "llvm/BinaryFormat/XCOFF.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/BinaryFormat/XCOFF.h" >From 8fcf69ed77148f8b339b87f75ed97e5ce719b4ba Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Fri, 27 Dec 2024 06:50:27 -0600 Subject: [PATCH 19/50] Some Updates --- lldb/include/lldb/Host/aix/HostInfoAIX.h | 11 +-- lldb/source/Host/aix/HostInfoAIX.cpp | 65 +------------- .../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 87 +++++++++---------- .../ObjectFile/XCOFF/ObjectFileXCOFF.h | 11 ++- 4 files changed, 50 insertions(+), 124 deletions(-) diff --git a/lldb/include/lldb/Host/aix/HostInfoAIX.h b/lldb/include/lldb/Host/aix/HostInfoAIX.h index ced4cf34d38a8..ba727e1d5f171 100644 --- a/lldb/include/lldb/Host/aix/HostInfoAIX.h +++ b/lldb/include/lldb/Host/aix/HostInfoAIX.h @@ -6,16 +6,14 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_Host_aix_HostInfoAIX_h_ -#define lldb_Host_aix_HostInfoAIX_h_ +#ifndef LLDB_HOST_AIX_HOSTINFOAIX_H_ +#define LLDB_HOST_AIX_HOSTINFOAIX_H_ #include "lldb/Host/posix/HostInfoPosix.h" #include "lldb/Utility/FileSpec.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/VersionTuple.h" -#include - namespace lldb_private { class HostInfoAIX : public HostInfoPosix { @@ -25,15 +23,10 @@ class HostInfoAIX : public HostInfoPosix { static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr); static void Terminate(); - static llvm::VersionTuple GetOSVersion(); - static std::optional GetOSBuildString(); static llvm::StringRef GetDistributionId(); static FileSpec GetProgramFileSpec(); protected: - static bool ComputeSupportExeDirectory(FileSpec &file_spec); - static bool ComputeSystemPluginsDirectory(FileSpec &file_spec); - static bool ComputeUserPluginsDirectory(FileSpec &file_spec); static void ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64); }; diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp index 8bda09e01741b..ef07b07c8cab2 100644 --- a/lldb/source/Host/aix/HostInfoAIX.cpp +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -29,8 +29,6 @@ namespace { struct HostInfoAIXFields { llvm::once_flag m_distribution_once_flag; std::string m_distribution_id; - llvm::once_flag m_os_version_once_flag; - llvm::VersionTuple m_os_version; }; } // namespace @@ -49,33 +47,6 @@ void HostInfoAIX::Terminate() { HostInfoBase::Terminate(); } -llvm::VersionTuple HostInfoAIX::GetOSVersion() { - assert(g_fields && "Missing call to Initialize?"); - llvm::call_once(g_fields->m_os_version_once_flag, []() { - struct utsname un; - if (uname(&un) != 0) - return; - - llvm::StringRef release = un.release; - // The kernel release string can include a lot of stuff (e.g. - // 4.9.0-6-amd64). We're only interested in the numbered prefix. - release = release.substr(0, release.find_first_not_of("0123456789.")); - g_fields->m_os_version.tryParse(release); - }); - - return g_fields->m_os_version; -} - -std::optional HostInfoAIX::GetOSBuildString() { - struct utsname un; - ::memset(&un, 0, sizeof(utsname)); - - if (uname(&un) < 0) - return std::nullopt; - - return std::string(un.release); -} - llvm::StringRef HostInfoAIX::GetDistributionId() { assert(g_fields && "Missing call to Initialize?"); // Try to run 'lbs_release -i', and use that response for the distribution @@ -122,8 +93,7 @@ llvm::StringRef HostInfoAIX::GetDistributionId() { if (strstr(distribution_id, distributor_id_key)) { // strip newlines std::string id_string(distribution_id + strlen(distributor_id_key)); - id_string.erase(std::remove(id_string.begin(), id_string.end(), '\n'), - id_string.end()); + llvm::erase(id_string, '\n'); // lower case it and convert whitespace to underscores std::transform( @@ -167,42 +137,11 @@ FileSpec HostInfoAIX::GetProgramFileSpec() { return g_program_filespec; } -bool HostInfoAIX::ComputeSupportExeDirectory(FileSpec &file_spec) { - if (HostInfoPosix::ComputeSupportExeDirectory(file_spec) && - file_spec.IsAbsolute() && FileSystem::Instance().Exists(file_spec)) - return true; - file_spec.SetDirectory(GetProgramFileSpec().GetDirectory()); - return !file_spec.GetDirectory().IsEmpty(); -} - -bool HostInfoAIX::ComputeSystemPluginsDirectory(FileSpec &file_spec) { - FileSpec temp_file("/usr/" LLDB_INSTALL_LIBDIR_BASENAME "/lldb/plugins"); - FileSystem::Instance().Resolve(temp_file); - file_spec.SetDirectory(temp_file.GetPath()); - return true; -} - -bool HostInfoAIX::ComputeUserPluginsDirectory(FileSpec &file_spec) { - // XDG Base Directory Specification - // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html If - // XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb. - const char *xdg_data_home = getenv("XDG_DATA_HOME"); - if (xdg_data_home && xdg_data_home[0]) { - std::string user_plugin_dir(xdg_data_home); - user_plugin_dir += "/lldb"; - file_spec.SetDirectory(user_plugin_dir.c_str()); - } else - file_spec.SetDirectory("~/.local/share/lldb"); - return true; -} - void HostInfoAIX::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64) { HostInfoPosix::ComputeHostArchitectureSupport(arch_32, arch_64); - const char *distribution_id = GetDistributionId().data(); - - // On Linux, "unknown" in the vendor slot isn't what we want for the default + // "unknown" in the vendor slot isn't what we want for the default // triple. It's probably an artifact of config.guess. if (arch_32.IsValid()) { if (arch_32.GetTriple().getVendor() == llvm::Triple::UnknownVendor) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index a4d9ea295b4c3..afd8027bab06c 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -1,4 +1,5 @@ -//===-- ObjectFileXCOFF.cpp -------------------------------------------------===// +//===-- ObjectFileXCOFF.cpp +//-------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,13 +8,6 @@ //===----------------------------------------------------------------------===// #include "ObjectFileXCOFF.h" - -#include -#include -#include -#include - -#include "lldb/Utility/FileSpecList.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" @@ -28,6 +22,7 @@ #include "lldb/Target/Target.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/FileSpecList.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RangeMap.h" @@ -38,12 +33,16 @@ #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/Object/XCOFFObjectFile.h" #include "llvm/Object/Decompressor.h" #include "llvm/Support/CRC.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Object/XCOFFObjectFile.h" +#include +#include +#include +#include using namespace llvm; using namespace lldb; @@ -69,21 +68,19 @@ void ObjectFileXCOFF::Terminate() { bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false; ObjectFile *ObjectFileXCOFF::CreateInstance(const lldb::ModuleSP &module_sp, - DataBufferSP data_sp, - lldb::offset_t data_offset, - const lldb_private::FileSpec *file, - lldb::offset_t file_offset, - lldb::offset_t length) { + DataBufferSP data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t file_offset, + lldb::offset_t length) { if (!data_sp) { data_sp = MapFileData(*file, length, file_offset); if (!data_sp) return nullptr; data_offset = 0; } - if (!ObjectFileXCOFF::MagicBytesMatch(data_sp, data_offset, length)) return nullptr; - // Update the data to contain the entire file if it doesn't already if (data_sp->GetByteSize() < length) { data_sp = MapFileData(*file, length, file_offset); @@ -114,15 +111,15 @@ bool ObjectFileXCOFF::CreateBinary() { Log *log = GetLog(LLDBLog::Object); - auto binary = llvm::object::XCOFFObjectFile::createObjectFile(llvm::MemoryBufferRef( - toStringRef(m_data.GetData()), m_file.GetFilename().GetStringRef()), - file_magic::xcoff_object_64); + auto binary = llvm::object::ObjectFile::createObjectFile( + llvm::MemoryBufferRef(toStringRef(m_data.GetData()), + m_file.GetFilename().GetStringRef()), + file_magic::xcoff_object_64); if (!binary) { LLDB_LOG_ERROR(log, binary.takeError(), "Failed to create binary for file ({1}): {0}", m_file); return false; } - // Make sure we only handle COFF format. m_binary = llvm::unique_dyn_cast(std::move(*binary)); @@ -132,6 +129,7 @@ bool ObjectFileXCOFF::CreateBinary() { LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}", this, GetModule().get(), GetModule()->GetSpecificationDescription(), m_file.GetPath(), m_binary.get()); + return true; } @@ -148,9 +146,12 @@ size_t ObjectFileXCOFF::GetModuleSpecifications( const size_t initial_count = specs.GetSize(); if (ObjectFileXCOFF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) { - ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + ArchSpec arch_spec = + ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); ModuleSpec spec(file, arch_spec); - spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX); + spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, + LLDB_INVALID_CPUTYPE, + llvm::Triple::AIX); specs.Append(spec); } return specs.GetSize() - initial_count; @@ -158,11 +159,9 @@ size_t ObjectFileXCOFF::GetModuleSpecifications( static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) { switch (magic) { - /* TODO: 32bit not supported yet - case XCOFF::XCOFF32: - return sizeof(struct llvm::object::XCOFFFileHeader32); - */ - + // TODO: 32bit not supported. + // case XCOFF::XCOFF32: + // return sizeof(struct llvm::object::XCOFFFileHeader32); case XCOFF::XCOFF64: return sizeof(struct llvm::object::XCOFFFileHeader64); break; @@ -174,10 +173,12 @@ static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) { } bool ObjectFileXCOFF::MagicBytesMatch(DataBufferSP &data_sp, - lldb::addr_t data_offset, - lldb::addr_t data_length) { - lldb_private::DataExtractor data; + lldb::addr_t data_offset, + lldb::addr_t data_length) { + lldb_private::DataExtractor data; data.SetData(data_sp, data_offset, data_length); + // Need to set this as XCOFF is only compatible with Big Endian + data.SetByteOrder(eByteOrderBig); lldb::offset_t offset = 0; uint16_t magic = data.GetU16(&offset); return XCOFFHeaderSizeFromMagic(magic) != 0; @@ -386,13 +387,10 @@ bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, return changed; } -ByteOrder ObjectFileXCOFF::GetByteOrder() const { - return eByteOrderBig; -} -bool ObjectFileXCOFF::IsExecutable() const { - return true; -} +ByteOrder ObjectFileXCOFF::GetByteOrder() const { return eByteOrderBig; } + +bool ObjectFileXCOFF::IsExecutable() const { return true; } uint32_t ObjectFileXCOFF::GetAddressByteSize() const { if (m_xcoff_header.magic == XCOFF::XCOFF64) @@ -592,13 +590,12 @@ void ObjectFileXCOFF::Dump(Stream *s) { } ArchSpec ObjectFileXCOFF::GetArchitecture() { - ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + ArchSpec arch_spec = + ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); return arch_spec; } -UUID ObjectFileXCOFF::GetUUID() { - return UUID(); -} +UUID ObjectFileXCOFF::GetUUID() { return UUID(); } std::optional ObjectFileXCOFF::GetDebugLink() { return std::nullopt; @@ -724,16 +721,14 @@ lldb_private::Address ObjectFileXCOFF::GetBaseAddress() { } ObjectFile::Type ObjectFileXCOFF::CalculateType() { - if (m_xcoff_header.flags & XCOFF::F_EXEC) + if (m_binary->fileHeader64()->Flags & XCOFF::F_EXEC) return eTypeExecutable; - else if (m_xcoff_header.flags & XCOFF::F_SHROBJ) + else if (m_binary->fileHeader64()->Flags & XCOFF::F_SHROBJ) return eTypeSharedLibrary; return eTypeUnknown; } -ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { - return eStrataUnknown; -} +ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { return eStrataUnknown; } llvm::StringRef ObjectFileXCOFF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const { @@ -752,7 +747,7 @@ ObjectFileXCOFF::GetLoadableData(Target &target) { lldb::WritableDataBufferSP ObjectFileXCOFF::MapFileDataWritable(const FileSpec &file, uint64_t Size, - uint64_t Offset) { + uint64_t Offset) { return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size, Offset); } diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h index 5a12d16886489..f827fca3932f4 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h @@ -1,4 +1,5 @@ -//===-- ObjectFileXCOFF.h --------------------------------------- -*- C++ -*-===// +//===-- ObjectFileXCOFF.h --------------------------------------- -*- C++ +//-*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -9,16 +10,14 @@ #ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H #define LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H -#include - -#include - #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/UUID.h" #include "lldb/lldb-private.h" #include "llvm/Object/XCOFFObjectFile.h" +#include +#include /// \class ObjectFileXCOFF /// Generic XCOFF object file reader. @@ -240,4 +239,4 @@ class ObjectFileXCOFF : public lldb_private::ObjectFile { std::map> m_deps_base_members; }; -#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILE_H >From f8b05dfc9fc75177a63dfa2d6df4a9af143b09b8 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 5 Jan 2025 05:01:47 -0600 Subject: [PATCH 20/50] HostInfoAIX Cleanup --- lldb/include/lldb/Host/aix/HostInfoAIX.h | 4 - lldb/source/Host/aix/HostInfoAIX.cpp | 108 ----------------------- 2 files changed, 112 deletions(-) diff --git a/lldb/include/lldb/Host/aix/HostInfoAIX.h b/lldb/include/lldb/Host/aix/HostInfoAIX.h index ba727e1d5f171..5a52c42fa6199 100644 --- a/lldb/include/lldb/Host/aix/HostInfoAIX.h +++ b/lldb/include/lldb/Host/aix/HostInfoAIX.h @@ -23,12 +23,8 @@ class HostInfoAIX : public HostInfoPosix { static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr); static void Terminate(); - static llvm::StringRef GetDistributionId(); static FileSpec GetProgramFileSpec(); -protected: - static void ComputeHostArchitectureSupport(ArchSpec &arch_32, - ArchSpec &arch_64); }; } diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp index ef07b07c8cab2..2996fcb55f811 100644 --- a/lldb/source/Host/aix/HostInfoAIX.cpp +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -11,117 +11,25 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" - #include "llvm/Support/Threading.h" - #include #include #include #include #include - #include #include using namespace lldb_private; -namespace { -struct HostInfoAIXFields { - llvm::once_flag m_distribution_once_flag; - std::string m_distribution_id; -}; -} // namespace - -static HostInfoAIXFields *g_fields = nullptr; - void HostInfoAIX::Initialize(SharedLibraryDirectoryHelper *helper) { HostInfoPosix::Initialize(helper); - - g_fields = new HostInfoAIXFields(); } void HostInfoAIX::Terminate() { - assert(g_fields && "Missing call to Initialize?"); - delete g_fields; - g_fields = nullptr; HostInfoBase::Terminate(); } -llvm::StringRef HostInfoAIX::GetDistributionId() { - assert(g_fields && "Missing call to Initialize?"); - // Try to run 'lbs_release -i', and use that response for the distribution - // id. - llvm::call_once(g_fields->m_distribution_once_flag, []() { - Log *log = GetLog(LLDBLog::Host); - LLDB_LOGF(log, "attempting to determine AIX distribution..."); - - // check if the lsb_release command exists at one of the following paths - const char *const exe_paths[] = {"/bin/lsb_release", - "/usr/bin/lsb_release"}; - - for (size_t exe_index = 0; - exe_index < sizeof(exe_paths) / sizeof(exe_paths[0]); ++exe_index) { - const char *const get_distribution_info_exe = exe_paths[exe_index]; - if (access(get_distribution_info_exe, F_OK)) { - // this exe doesn't exist, move on to next exe - LLDB_LOGF(log, "executable doesn't exist: %s", - get_distribution_info_exe); - continue; - } - - // execute the distribution-retrieval command, read output - std::string get_distribution_id_command(get_distribution_info_exe); - get_distribution_id_command += " -i"; - - FILE *file = popen(get_distribution_id_command.c_str(), "r"); - if (!file) { - LLDB_LOGF(log, - "failed to run command: \"%s\", cannot retrieve " - "platform information", - get_distribution_id_command.c_str()); - break; - } - - // retrieve the distribution id string. - char distribution_id[256] = {'\0'}; - if (fgets(distribution_id, sizeof(distribution_id) - 1, file) != - nullptr) { - LLDB_LOGF(log, "distribution id command returned \"%s\"", - distribution_id); - - const char *const distributor_id_key = "Distributor ID:\t"; - if (strstr(distribution_id, distributor_id_key)) { - // strip newlines - std::string id_string(distribution_id + strlen(distributor_id_key)); - llvm::erase(id_string, '\n'); - - // lower case it and convert whitespace to underscores - std::transform( - id_string.begin(), id_string.end(), id_string.begin(), - [](char ch) { return tolower(isspace(ch) ? '_' : ch); }); - - g_fields->m_distribution_id = id_string; - LLDB_LOGF(log, "distribution id set to \"%s\"", - g_fields->m_distribution_id.c_str()); - } else { - LLDB_LOGF(log, "failed to find \"%s\" field in \"%s\"", - distributor_id_key, distribution_id); - } - } else { - LLDB_LOGF(log, - "failed to retrieve distribution id, \"%s\" returned no" - " lines", - get_distribution_id_command.c_str()); - } - - // clean up the file - pclose(file); - } - }); - - return g_fields->m_distribution_id; -} - FileSpec HostInfoAIX::GetProgramFileSpec() { static FileSpec g_program_filespec; @@ -136,19 +44,3 @@ FileSpec HostInfoAIX::GetProgramFileSpec() { return g_program_filespec; } - -void HostInfoAIX::ComputeHostArchitectureSupport(ArchSpec &arch_32, - ArchSpec &arch_64) { - HostInfoPosix::ComputeHostArchitectureSupport(arch_32, arch_64); - - // "unknown" in the vendor slot isn't what we want for the default - // triple. It's probably an artifact of config.guess. - if (arch_32.IsValid()) { - if (arch_32.GetTriple().getVendor() == llvm::Triple::UnknownVendor) - arch_32.GetTriple().setVendorName(llvm::StringRef()); - } - if (arch_64.IsValid()) { - if (arch_64.GetTriple().getVendor() == llvm::Triple::UnknownVendor) - arch_64.GetTriple().setVendorName(llvm::StringRef()); - } -} >From 57d080e44e80203a6ab848c362469954a7c9f067 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 5 Jan 2025 05:49:40 -0600 Subject: [PATCH 21/50] Cleanup HostInfoAIX Including the previous commit, Removed: GetDistributionID, ComputeHostArchitectureSupport and Reduced GetProgramFileSpec as it was not needed --- lldb/source/Host/aix/HostInfoAIX.cpp | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp index 2996fcb55f811..d09b9052668af 100644 --- a/lldb/source/Host/aix/HostInfoAIX.cpp +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -26,21 +26,9 @@ void HostInfoAIX::Initialize(SharedLibraryDirectoryHelper *helper) { HostInfoPosix::Initialize(helper); } -void HostInfoAIX::Terminate() { - HostInfoBase::Terminate(); -} +void HostInfoAIX::Terminate() { HostInfoBase::Terminate(); } FileSpec HostInfoAIX::GetProgramFileSpec() { static FileSpec g_program_filespec; - - if (!g_program_filespec) { - char exe_path[PATH_MAX]; - ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); - if (len > 0) { - exe_path[len] = 0; - g_program_filespec.SetFile(exe_path, FileSpec::Style::native); - } - } - return g_program_filespec; } >From 673713a9339de4e4ea395ee2e7f65dc1db43bcf9 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 5 Jan 2025 15:35:23 -0600 Subject: [PATCH 22/50] Removing headers --- lldb/include/lldb/Host/aix/HostInfoAIX.h | 2 -- lldb/source/Host/aix/HostInfoAIX.cpp | 12 ------------ 2 files changed, 14 deletions(-) diff --git a/lldb/include/lldb/Host/aix/HostInfoAIX.h b/lldb/include/lldb/Host/aix/HostInfoAIX.h index 5a52c42fa6199..331a274630850 100644 --- a/lldb/include/lldb/Host/aix/HostInfoAIX.h +++ b/lldb/include/lldb/Host/aix/HostInfoAIX.h @@ -11,8 +11,6 @@ #include "lldb/Host/posix/HostInfoPosix.h" #include "lldb/Utility/FileSpec.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/VersionTuple.h" namespace lldb_private { diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp index d09b9052668af..61b47462dd647 100644 --- a/lldb/source/Host/aix/HostInfoAIX.cpp +++ b/lldb/source/Host/aix/HostInfoAIX.cpp @@ -7,18 +7,6 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/aix/HostInfoAIX.h" -#include "lldb/Host/Config.h" -#include "lldb/Host/FileSystem.h" -#include "lldb/Utility/LLDBLog.h" -#include "lldb/Utility/Log.h" -#include "llvm/Support/Threading.h" -#include -#include -#include -#include -#include -#include -#include using namespace lldb_private; >From cdc31f3963365e4595247ff5a7155662df1ce1af Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 6 Jan 2025 09:28:56 -0600 Subject: [PATCH 23/50] Reverted merge blunder CMakeLists --- lldb/source/Host/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index f326bc07dc1f6..f4fca8acc4d83 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -141,7 +141,10 @@ else() elseif (CMAKE_SYSTEM_NAME MATCHES "AIX") add_host_subdirectory(aix + aix/AbstractSocket.cpp + aix/Host.cpp aix/HostInfoAIX.cpp + aix/Support.cpp ) endif() endif() >From 713a6cbbb97b9bc56b039ab050a1690eccc017e3 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 6 Jan 2025 09:39:36 -0600 Subject: [PATCH 24/50] Removed DomainSocket.cpp FileSystemPosix.cpp includes --- lldb/source/Host/posix/DomainSocket.cpp | 4 ---- lldb/source/Host/posix/FileSystemPosix.cpp | 3 --- 2 files changed, 7 deletions(-) diff --git a/lldb/source/Host/posix/DomainSocket.cpp b/lldb/source/Host/posix/DomainSocket.cpp index f30e84d83efca..be8fcdf2c8f2c 100644 --- a/lldb/source/Host/posix/DomainSocket.cpp +++ b/lldb/source/Host/posix/DomainSocket.cpp @@ -17,10 +17,6 @@ #include #include -#if defined(_AIX) -#include -#endif - using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index 1a84f550662d7..a631bb01209ec 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,9 +11,6 @@ // C includes #include #include -#ifndef _AIX -#include -#endif #include #include #include >From 0a706d29dabeefa62e354fc9358d650f89032048 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 6 Jan 2025 09:44:10 -0600 Subject: [PATCH 25/50] sys/mount.h --- lldb/source/Host/posix/FileSystemPosix.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index a631bb01209ec..945e2affc8371 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,6 +11,7 @@ // C includes #include #include +#include #include #include #include >From 84ebb4ec9b542c38fe1b60261a3253383e9fbf5d Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 6 Jan 2025 09:54:58 -0600 Subject: [PATCH 26/50] sys/mount.h --- lldb/source/Host/posix/FileSystemPosix.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp index 945e2affc8371..1a84f550662d7 100644 --- a/lldb/source/Host/posix/FileSystemPosix.cpp +++ b/lldb/source/Host/posix/FileSystemPosix.cpp @@ -11,7 +11,9 @@ // C includes #include #include +#ifndef _AIX #include +#endif #include #include #include >From 844f7980040de9e13620e9d65a3fcaef56b6c8d6 Mon Sep 17 00:00:00 2001 From: Dhruv Srivastava Date: Thu, 9 Jan 2025 09:47:43 +0530 Subject: [PATCH 27/50] Removed _AIX from ConnectionFileDescriptorPosix.cpp --- lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index 2530c8fa353ba..0ed2016667162 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -715,7 +715,7 @@ ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, ConnectionStatus ConnectionFileDescriptor::ConnectFile( llvm::StringRef s, socket_id_callback_type socket_id_callback, Status *error_ptr) { -#if LLDB_ENABLE_POSIX && !defined(_AIX) +#if LLDB_ENABLE_POSIX std::string addr_str = s.str(); // file:///PATH int fd = FileSystem::Instance().Open(addr_str.c_str(), O_RDWR); @@ -756,7 +756,7 @@ ConnectionStatus ConnectionFileDescriptor::ConnectFile( m_io_sp = std::make_shared(fd, File::eOpenOptionReadWrite, true); return eConnectionStatusSuccess; -#endif // LLDB_ENABLE_POSIX && !defined(_AIX) +#endif // LLDB_ENABLE_POSIX llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX"); } >From 4fe42cda7c2f4990b18a39c1d6563094fb88775f Mon Sep 17 00:00:00 2001 From: ravindra shinde Date: Fri, 17 Jan 2025 13:58:13 +0530 Subject: [PATCH 28/50] [ObjectFileXCOFF] Fix access to protected member 'GetSectionLoadList' in Target - Added a public method to Target for accessing 'GetSectionLoadList' safely. - Updated ObjectFileXCOFF to use the new public method, ensuring compliance with encapsulation rules. This resolves the build error caused by direct access to the protected member. Signed-off-by: ravindra shinde --- lldb/include/lldb/Target/Target.h | 5 +++++ lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index f31ac381391b4..75f9c9c2e999c 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -522,6 +522,7 @@ class Target : public std::enable_shared_from_this, eBroadcastBitSymbolsChanged = (1 << 5), }; + // These two functions fill out the Broadcaster interface: static llvm::StringRef GetStaticBroadcasterClass(); @@ -1644,6 +1645,10 @@ class Target : public std::enable_shared_from_this, TargetStats &GetStatistics() { return m_stats; } +public: + SectionLoadList &GetSectionLoadListPublic() { + return GetSectionLoadList(); + } protected: /// Construct with optional file and arch. /// diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index afd8027bab06c..cf11e5fb8f5a3 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -340,7 +340,7 @@ bool ObjectFileXCOFF::SetLoadAddress(Target &target, lldb::addr_t value, strcmp(section_sp->GetName().AsCString(), ".bss") == 0) use_offset = true; - if (target.GetSectionLoadList().SetSectionLoadAddress( + if (target.GetSectionLoadListPublic().SetSectionLoadAddress( section_sp, (use_offset ? (section_sp->GetFileOffset() + value) : (section_sp->GetFileAddress() + value)))) ++num_loaded_sections; @@ -369,13 +369,13 @@ bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value, SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); if (type_id == 1 && section_sp && strcmp(section_sp->GetName().AsCString(), ".text") == 0) { if (!section_sp->IsThreadSpecific()) { - if (target.GetSectionLoadList().SetSectionLoadAddress( + if (target.GetSectionLoadListPublic().SetSectionLoadAddress( section_sp, section_sp->GetFileOffset() + value)) ++num_loaded_sections; } } else if (type_id == 2 && section_sp && strcmp(section_sp->GetName().AsCString(), ".data") == 0) { if (!section_sp->IsThreadSpecific()) { - if (target.GetSectionLoadList().SetSectionLoadAddress( + if (target.GetSectionLoadListPublic().SetSectionLoadAddress( section_sp, section_sp->GetFileAddress() + value)) ++num_loaded_sections; } >From e5ed4f21c5bbc709e5e2eff0f83995cc6d89de48 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sun, 19 Jan 2025 03:43:11 -0600 Subject: [PATCH 29/50] Resolved cmake failure for SBProgress.cpp --- lldb/source/API/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index eb348e2b97232..0a03e000c0cae 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -85,6 +85,7 @@ add_lldb_library(liblldb STATIC ${option_framework} SBModuleSpec.cpp SBPlatform.cpp SBProcess.cpp + SBProgress.cpp SBProcessInfo.cpp SBProcessInfoList.cpp SBQueue.cpp >From 82dbcb0e776c438e5f40c9f8d8c8e8eb81b7febd Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 27 Jan 2025 06:35:19 -0600 Subject: [PATCH 30/50] Host.cpp ANDROID --- lldb/source/Host/common/Host.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 758e9f49ade2c..adf74df8aa90b 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -1,4 +1,4 @@ -//===-- Host.cpp ----------------------------------------------------------===// + // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -516,7 +516,6 @@ static int dladdr(const void *ptr, Dl_info *dl) FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSpec module_filespec; -#if !defined(__ANDROID__) #ifdef _AIX if (host_addr == reinterpret_cast(HostInfoBase::ComputeSharedLibraryDirectory)) { // FIXME: AIX dladdr return "lldb" for this case @@ -527,6 +526,7 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { } } #endif +#if !defined(__ANDROID__) Dl_info info; if (::dladdr(host_addr, &info)) { if (info.dli_fname) { @@ -534,6 +534,7 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSystem::Instance().Resolve(module_filespec); } } +#endif return module_filespec; } >From 60294eaa1611632afc94b9da503752e34ad2703d Mon Sep 17 00:00:00 2001 From: Ravindra Shinde Date: Tue, 4 Feb 2025 03:23:56 -0600 Subject: [PATCH 31/50] Resolving the fatal error while build Build is failing due to the fatal error: 'sys/syscall.h' file not found Signed-off-by: Ravindra Shinde --- lldb/source/Host/common/Host.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 40ce76d70d6e8..b5bd68b8539bd 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -18,8 +18,12 @@ #include #include #include + +#ifndef _AIX #include #include +#endif + #include #include #endif >From 2644be59b13a61c69cc635875c94b0b4645fe76c Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 10 Feb 2025 01:49:12 -0600 Subject: [PATCH 32/50] InferiorCallPOSIX.cpp --- lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index d1f9fe851119e..8e74cce097894 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -120,12 +120,13 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, arch, addr, length, prot_arg, flags, fd, offset); #if defined(_AIX) lldb::ThreadPlanSP call_plan_sp( - new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(), + new ThreadPlanCallFunction(*thread, mmap_addr, toc_range.GetBaseAddress(), void_ptr_type, args, options)); #else lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallFunction( *thread, mmap_addr, void_ptr_type, args, options)); +#endif if (call_plan_sp) { DiagnosticManager diagnostics; >From 4805b13cba964b58def39a66ad4c4309a9b2c501 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 12 Feb 2025 07:33:04 -0600 Subject: [PATCH 33/50] Merge branch gh-101657 --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 97 ------------------- .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 5 +- 2 files changed, 1 insertion(+), 101 deletions(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 1a98bb9334043..375d879c7a995 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -21,10 +21,6 @@ #include "llvm/Support/FileSystem.h" #if defined(_AIX) #include -#include -#include -#include -#include #endif /*#include "llvm/ADT/Triple.h" @@ -137,107 +133,14 @@ bool DynamicLoaderAIXDYLD::NotifyBreakpointHit( } -void DynamicLoaderAIXDYLD::ResolveExecutableModule( - lldb::ModuleSP &module_sp) { - Log *log = GetLog(LLDBLog::DynamicLoader); - - if (m_process == nullptr) - return; - - auto &target = m_process->GetTarget(); - const auto platform_sp = target.GetPlatform(); - - ProcessInstanceInfo process_info; - if (!m_process->GetProcessInfo(process_info)) { - LLDB_LOGF(log, - "DynamicLoaderPOSIXDYLD::%s - failed to get process info for " - "pid %" PRIu64, - __FUNCTION__, m_process->GetID()); - return; - } - - int32long64_t pid = m_process->GetID(); - char cwd[PATH_MAX], resolved_path[PATH_MAX]; - std::string executable_name; - bool path_resolved = false; - psinfo_t psinfo; - - std::string proc_file = "/proc/" + std::to_string(pid) + "/psinfo"; - std::string cwd_link = "/proc/" + std::to_string(pid) + "/cwd"; - std::ifstream file(proc_file, std::ios::binary); - if(!file.is_open()) - LLDB_LOGF(log, "Error: Unable to access process info "); - - file.read(reinterpret_cast(&psinfo), sizeof(psinfo_t)); - if(!file) - LLDB_LOGF(log, "Process info error: Failed to read "); - - std::string relative_path(psinfo.pr_fname); - LLDB_LOGF(log, "Relative path %s",relative_path.c_str()); - - if(readlink(cwd_link.c_str(), cwd, sizeof(cwd)) != -1){ - std::filesystem::path full_path = std::filesystem::path(cwd)/relative_path; - if(realpath(full_path.c_str(), resolved_path)) { - LLDB_LOGF(log, "Resolved Path using process info : %s", resolved_path); - path_resolved = true; - } - else - LLDB_LOGF(log, "Realpath error: Unable to resolve. "); - } - - executable_name = resolved_path; - if(path_resolved == false) { - std::string command_line(psinfo.pr_psargs); - LLDB_LOGF(log, "Command line: %s",command_line.c_str()); - if (!command_line.empty()) { - size_t space1 = command_line.find(' '); - executable_name = command_line.substr(0, space1); - LLDB_LOGF(log, "Resolved path using command line arg %s",executable_name.c_str()); - } - } - - LLDB_LOGF(log, "Executable Name %s",executable_name.c_str()); - process_info.SetExecutableFile(lldb_private::FileSpec(executable_name), - true); - - LLDB_LOGF( - log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s", - __FUNCTION__, m_process->GetID(), - process_info.GetExecutableFile().GetPath().c_str()); - - ModuleSpec module_spec(process_info.GetExecutableFile(), - process_info.GetArchitecture()); - if (module_sp && module_sp->MatchesModuleSpec(module_spec)) - return; - - const auto executable_search_paths(Target::GetDefaultExecutableSearchPaths()); - auto error = platform_sp->ResolveExecutable( - module_spec, module_sp, - !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr); - if (error.Fail()) { - StreamString stream; - module_spec.Dump(stream); - - LLDB_LOGF(log, - "DynamicLoaderPOSIXDYLD::%s - failed to resolve executable " - "with module spec \"%s\": %s", - __FUNCTION__, stream.GetData(), error.AsCString()); - return; - } - - target.SetExecutableModule(module_sp, eLoadDependentsNo); -} - void DynamicLoaderAIXDYLD::DidAttach() { Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); ModuleSP executable = GetTargetExecutable(); - ResolveExecutableModule(executable); if (!executable.get()) return; - LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); // Try to fetch the load address of the file from the process, since there // could be randomization of the load address. diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h index 0ffbe688e0069..ae4b7aca66dcc 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -24,7 +24,7 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { static void Initialize(); static void Terminate(); - static llvm::StringRef GetPluginNameStatic() { return "aix-dyld"; } + static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; } static llvm::StringRef GetPluginDescriptionStatic(); static DynamicLoader *CreateInstance(Process *process, bool force); @@ -46,9 +46,6 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { protected: lldb::addr_t GetLoadAddress(lldb::ModuleSP executable); - /// Loads Module from inferior process. - void ResolveExecutableModule(lldb::ModuleSP &module_sp); - private: std::map m_loaded_modules; }; >From cff574b36903e12385e5d6cddf4532ba279f47de Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 12 Feb 2025 07:52:04 -0600 Subject: [PATCH 34/50] Fix for Debugging Attach to AIX Process --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 97 +++++++++++++++++++ .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 5 +- 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 375d879c7a995..1a98bb9334043 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -21,6 +21,10 @@ #include "llvm/Support/FileSystem.h" #if defined(_AIX) #include +#include +#include +#include +#include #endif /*#include "llvm/ADT/Triple.h" @@ -133,14 +137,107 @@ bool DynamicLoaderAIXDYLD::NotifyBreakpointHit( } +void DynamicLoaderAIXDYLD::ResolveExecutableModule( + lldb::ModuleSP &module_sp) { + Log *log = GetLog(LLDBLog::DynamicLoader); + + if (m_process == nullptr) + return; + + auto &target = m_process->GetTarget(); + const auto platform_sp = target.GetPlatform(); + + ProcessInstanceInfo process_info; + if (!m_process->GetProcessInfo(process_info)) { + LLDB_LOGF(log, + "DynamicLoaderPOSIXDYLD::%s - failed to get process info for " + "pid %" PRIu64, + __FUNCTION__, m_process->GetID()); + return; + } + + int32long64_t pid = m_process->GetID(); + char cwd[PATH_MAX], resolved_path[PATH_MAX]; + std::string executable_name; + bool path_resolved = false; + psinfo_t psinfo; + + std::string proc_file = "/proc/" + std::to_string(pid) + "/psinfo"; + std::string cwd_link = "/proc/" + std::to_string(pid) + "/cwd"; + std::ifstream file(proc_file, std::ios::binary); + if(!file.is_open()) + LLDB_LOGF(log, "Error: Unable to access process info "); + + file.read(reinterpret_cast(&psinfo), sizeof(psinfo_t)); + if(!file) + LLDB_LOGF(log, "Process info error: Failed to read "); + + std::string relative_path(psinfo.pr_fname); + LLDB_LOGF(log, "Relative path %s",relative_path.c_str()); + + if(readlink(cwd_link.c_str(), cwd, sizeof(cwd)) != -1){ + std::filesystem::path full_path = std::filesystem::path(cwd)/relative_path; + if(realpath(full_path.c_str(), resolved_path)) { + LLDB_LOGF(log, "Resolved Path using process info : %s", resolved_path); + path_resolved = true; + } + else + LLDB_LOGF(log, "Realpath error: Unable to resolve. "); + } + + executable_name = resolved_path; + if(path_resolved == false) { + std::string command_line(psinfo.pr_psargs); + LLDB_LOGF(log, "Command line: %s",command_line.c_str()); + if (!command_line.empty()) { + size_t space1 = command_line.find(' '); + executable_name = command_line.substr(0, space1); + LLDB_LOGF(log, "Resolved path using command line arg %s",executable_name.c_str()); + } + } + + LLDB_LOGF(log, "Executable Name %s",executable_name.c_str()); + process_info.SetExecutableFile(lldb_private::FileSpec(executable_name), + true); + + LLDB_LOGF( + log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s", + __FUNCTION__, m_process->GetID(), + process_info.GetExecutableFile().GetPath().c_str()); + + ModuleSpec module_spec(process_info.GetExecutableFile(), + process_info.GetArchitecture()); + if (module_sp && module_sp->MatchesModuleSpec(module_spec)) + return; + + const auto executable_search_paths(Target::GetDefaultExecutableSearchPaths()); + auto error = platform_sp->ResolveExecutable( + module_spec, module_sp, + !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr); + if (error.Fail()) { + StreamString stream; + module_spec.Dump(stream); + + LLDB_LOGF(log, + "DynamicLoaderPOSIXDYLD::%s - failed to resolve executable " + "with module spec \"%s\": %s", + __FUNCTION__, stream.GetData(), error.AsCString()); + return; + } + + target.SetExecutableModule(module_sp, eLoadDependentsNo); +} + void DynamicLoaderAIXDYLD::DidAttach() { Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); ModuleSP executable = GetTargetExecutable(); + ResolveExecutableModule(executable); if (!executable.get()) return; + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); // Try to fetch the load address of the file from the process, since there // could be randomization of the load address. diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h index ae4b7aca66dcc..0ffbe688e0069 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -24,7 +24,7 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { static void Initialize(); static void Terminate(); - static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; } + static llvm::StringRef GetPluginNameStatic() { return "aix-dyld"; } static llvm::StringRef GetPluginDescriptionStatic(); static DynamicLoader *CreateInstance(Process *process, bool force); @@ -46,6 +46,9 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { protected: lldb::addr_t GetLoadAddress(lldb::ModuleSP executable); + /// Loads Module from inferior process. + void ResolveExecutableModule(lldb::ModuleSP &module_sp); + private: std::map m_loaded_modules; }; >From 303fa3bc078d7572702fb302726d4dd1bd13ddb2 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Fri, 21 Feb 2025 06:18:33 -0600 Subject: [PATCH 35/50] Merge branch 'llvm:main' into gh-101657 --- lldb/source/Plugins/Platform/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/lldb/source/Plugins/Platform/CMakeLists.txt b/lldb/source/Plugins/Platform/CMakeLists.txt index f5b0dbdd5e0a9..0220e734b36d1 100644 --- a/lldb/source/Plugins/Platform/CMakeLists.txt +++ b/lldb/source/Plugins/Platform/CMakeLists.txt @@ -9,4 +9,3 @@ add_subdirectory(OpenBSD) add_subdirectory(POSIX) add_subdirectory(QemuUser) add_subdirectory(Windows) -add_subdirectory(AIX) >From 6947dec02bb527f710c1bea3827b2c16d89f308a Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Fri, 21 Feb 2025 07:02:53 -0600 Subject: [PATCH 36/50] Merge branch 'llvm:main' into gh-101657 --- .../Plugins/Platform/AIX/PlatformAIX.cpp | 171 +----------------- 1 file changed, 1 insertion(+), 170 deletions(-) diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp index 0d66325d16267..21724d83133e9 100644 --- a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp +++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp @@ -130,12 +130,6 @@ void PlatformAIX::GetStatus(Stream &strm) { #endif } -void PlatformAIX::CalculateTrapHandlerSymbolNames() { - m_trap_handlers.push_back(ConstString("_sigtramp")); - m_trap_handlers.push_back(ConstString("__kernel_rt_sigreturn")); - m_trap_handlers.push_back(ConstString("__restore_rt")); -} - void PlatformAIX::CalculateTrapHandlerSymbolNames() {} lldb::UnwindPlanSP @@ -160,168 +154,5 @@ MmapArgList PlatformAIX::GetMmapArgumentList(const ArchSpec &arch, addr_t addr, } CompilerType PlatformAIX::GetSiginfoType(const llvm::Triple &triple) { - if (!m_type_system_up) - m_type_system_up.reset(new TypeSystemClang("siginfo", triple)); - TypeSystemClang *ast = m_type_system_up.get(); - - bool si_errno_then_code = true; - - switch (triple.getArch()) { - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - // mips has si_code and si_errno swapped - si_errno_then_code = false; - break; - default: - break; - } - - // generic types - CompilerType int_type = ast->GetBasicType(eBasicTypeInt); - CompilerType uint_type = ast->GetBasicType(eBasicTypeUnsignedInt); - CompilerType short_type = ast->GetBasicType(eBasicTypeShort); - CompilerType long_type = ast->GetBasicType(eBasicTypeLong); - CompilerType voidp_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); - - // platform-specific types - CompilerType &pid_type = int_type; - CompilerType &uid_type = uint_type; - CompilerType &clock_type = long_type; - CompilerType &band_type = long_type; - - CompilerType sigval_type = ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_sigval_t", - llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); - ast->StartTagDeclarationDefinition(sigval_type); - ast->AddFieldToRecordType(sigval_type, "sival_int", int_type, - lldb::eAccessPublic, 0); - ast->AddFieldToRecordType(sigval_type, "sival_ptr", voidp_type, - lldb::eAccessPublic, 0); - ast->CompleteTagDeclarationDefinition(sigval_type); - - CompilerType sigfault_bounds_type = ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", - llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); - ast->StartTagDeclarationDefinition(sigfault_bounds_type); - ast->AddFieldToRecordType(sigfault_bounds_type, "_addr_bnd", - ast->CreateStructForIdentifier(ConstString(), - { - {"_lower", voidp_type}, - {"_upper", voidp_type}, - }), - lldb::eAccessPublic, 0); - ast->AddFieldToRecordType(sigfault_bounds_type, "_pkey", uint_type, - lldb::eAccessPublic, 0); - ast->CompleteTagDeclarationDefinition(sigfault_bounds_type); - - // siginfo_t - CompilerType siginfo_type = ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_siginfo_t", - llvm::to_underlying(clang::TagTypeKind::Struct), lldb::eLanguageTypeC); - ast->StartTagDeclarationDefinition(siginfo_type); - ast->AddFieldToRecordType(siginfo_type, "si_signo", int_type, - lldb::eAccessPublic, 0); - - if (si_errno_then_code) { - ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type, - lldb::eAccessPublic, 0); - ast->AddFieldToRecordType(siginfo_type, "si_code", int_type, - lldb::eAccessPublic, 0); - } else { - ast->AddFieldToRecordType(siginfo_type, "si_code", int_type, - lldb::eAccessPublic, 0); - ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type, - lldb::eAccessPublic, 0); - } - - // the structure is padded on 64-bit arches to fix alignment - if (triple.isArch64Bit()) - ast->AddFieldToRecordType(siginfo_type, "__pad0", int_type, - lldb::eAccessPublic, 0); - - // union used to hold the signal data - CompilerType union_type = ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "", - llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC); - ast->StartTagDeclarationDefinition(union_type); - - ast->AddFieldToRecordType( - union_type, "_kill", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_pid", pid_type}, - {"si_uid", uid_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_timer", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_tid", int_type}, - {"si_overrun", int_type}, - {"si_sigval", sigval_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_rt", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_pid", pid_type}, - {"si_uid", uid_type}, - {"si_sigval", sigval_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_sigchld", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_pid", pid_type}, - {"si_uid", uid_type}, - {"si_status", int_type}, - {"si_utime", clock_type}, - {"si_stime", clock_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_sigfault", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_addr", voidp_type}, - {"si_addr_lsb", short_type}, - {"_bounds", sigfault_bounds_type}, - }), - lldb::eAccessPublic, 0); - - ast->AddFieldToRecordType( - union_type, "_sigpoll", - ast->CreateStructForIdentifier(ConstString(), - { - {"si_band", band_type}, - {"si_fd", int_type}, - }), - lldb::eAccessPublic, 0); - - // NB: SIGSYS is not present on ia64 but we don't seem to support that - ast->AddFieldToRecordType( - union_type, "_sigsys", - ast->CreateStructForIdentifier(ConstString(), - { - {"_call_addr", voidp_type}, - {"_syscall", int_type}, - {"_arch", uint_type}, - }), - lldb::eAccessPublic, 0); - - ast->CompleteTagDeclarationDefinition(union_type); - ast->AddFieldToRecordType(siginfo_type, "_sifields", union_type, - lldb::eAccessPublic, 0); - - ast->CompleteTagDeclarationDefinition(siginfo_type); - return siginfo_type; + return CompilerType(); } >From 24615119addcdf9fe5a8c5b2ebd0c15d75651279 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Sat, 22 Feb 2025 03:42:26 -0600 Subject: [PATCH 37/50] Removed un-needed changes --- lldb/include/lldb/Host/aix/AbstractSocket.h | 25 --------------------- lldb/include/lldb/Host/aix/Uio.h | 23 ------------------- lldb/source/Host/CMakeLists.txt | 1 - lldb/source/Host/aix/AbstractSocket.cpp | 20 ----------------- 4 files changed, 69 deletions(-) delete mode 100644 lldb/include/lldb/Host/aix/AbstractSocket.h delete mode 100644 lldb/include/lldb/Host/aix/Uio.h delete mode 100644 lldb/source/Host/aix/AbstractSocket.cpp diff --git a/lldb/include/lldb/Host/aix/AbstractSocket.h b/lldb/include/lldb/Host/aix/AbstractSocket.h deleted file mode 100644 index accfd01457a5e..0000000000000 --- a/lldb/include/lldb/Host/aix/AbstractSocket.h +++ /dev/null @@ -1,25 +0,0 @@ -//===-- AbstractSocket.h ----------------------------------------*- 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 -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_AbstractSocket_h_ -#define liblldb_AbstractSocket_h_ - -#include "lldb/Host/posix/DomainSocket.h" - -namespace lldb_private { -class AbstractSocket : public DomainSocket { -public: - AbstractSocket(); - -protected: - size_t GetNameOffset() const override; - void DeleteSocketFile(llvm::StringRef name) override; -}; -} - -#endif // ifndef liblldb_AbstractSocket_h_ diff --git a/lldb/include/lldb/Host/aix/Uio.h b/lldb/include/lldb/Host/aix/Uio.h deleted file mode 100644 index acf79ecc6a1d0..0000000000000 --- a/lldb/include/lldb/Host/aix/Uio.h +++ /dev/null @@ -1,23 +0,0 @@ -//===-- Uio.h ---------------------------------------------------*- 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 -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_Host_aix_Uio_h_ -#define liblldb_Host_aix_Uio_h_ - -#include "lldb/Host/Config.h" -#include - -// We shall provide our own implementation of process_vm_readv if it is not -// present -#if !HAVE_PROCESS_VM_READV -ssize_t process_vm_readv(::pid_t pid, const struct iovec *local_iov, - unsigned long liovcnt, const struct iovec *remote_iov, - unsigned long riovcnt, unsigned long flags); -#endif - -#endif // liblldb_Host_aix_Uio_h_ diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index bb6b5befa16e4..5a14b4c629825 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -140,7 +140,6 @@ else() elseif (CMAKE_SYSTEM_NAME MATCHES "AIX") add_host_subdirectory(aix - aix/AbstractSocket.cpp aix/Host.cpp aix/HostInfoAIX.cpp aix/Support.cpp diff --git a/lldb/source/Host/aix/AbstractSocket.cpp b/lldb/source/Host/aix/AbstractSocket.cpp deleted file mode 100644 index fddf78f54f46d..0000000000000 --- a/lldb/source/Host/aix/AbstractSocket.cpp +++ /dev/null @@ -1,20 +0,0 @@ -//===-- AbstractSocket.cpp ------------------------------------------------===// -// -// 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 "lldb/Host/aix/AbstractSocket.h" - -#include "llvm/ADT/StringRef.h" - -using namespace lldb; -using namespace lldb_private; - -AbstractSocket::AbstractSocket() : DomainSocket(ProtocolUnixAbstract) {} - -size_t AbstractSocket::GetNameOffset() const { return 1; } - -void AbstractSocket::DeleteSocketFile(llvm::StringRef name) {} >From 25bea9ca48dc458c1dddd72f10a483e76926a04e Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Wed, 26 Feb 2025 01:10:15 -0600 Subject: [PATCH 38/50] Resolving coredump issue while attach with library calls --- lldb/include/lldb/Core/ModuleSpec.h | 2 ++ lldb/source/Core/ModuleList.cpp | 12 +++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lldb/include/lldb/Core/ModuleSpec.h b/lldb/include/lldb/Core/ModuleSpec.h index 4fe06412b6b0b..9d79992b48c7e 100644 --- a/lldb/include/lldb/Core/ModuleSpec.h +++ b/lldb/include/lldb/Core/ModuleSpec.h @@ -122,6 +122,8 @@ class ModuleSpec { ConstString &GetObjectName() { return m_object_name; } ConstString GetObjectName() const { return m_object_name; } + + void SetObjectName(ConstString objName) { m_object_name = objName; } uint64_t GetObjectOffset() const { return m_object_offset; } diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index 2b8ccab2406c6..862a2729c1afb 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -260,7 +260,17 @@ void ModuleList::ReplaceEquivalent( module_sp->GetArchitecture()); equivalent_module_spec.GetPlatformFileSpec() = module_sp->GetPlatformFileSpec(); - +#ifdef _AIX + // To remove the exact equivalent module, the object name must be + // specified. When the equivalent_module_spec object is created, its + // object name is initially set to NULL. This is because the module_sp's + // GetPath() returns a path in the format (/usr/ccs/libc.a), which does + // not include the object name. As a result, MatchesModuleSpec may return + // true even though the object name is NULL and doesn't match any loaded + // module. To fix this, set the object name of the equivalent_module_spec + // to be the same as the object name of the module_sp. */ + equivalent_module_spec.SetObjectName(module_sp->GetObjectName()); +#endif size_t idx = 0; while (idx < m_modules.size()) { ModuleSP test_module_sp(m_modules[idx]); >From 349ec0064668a0ee1d3af7c2f38fa7427b4b2d36 Mon Sep 17 00:00:00 2001 From: Dhruv Srivastava Date: Fri, 28 Feb 2025 23:44:40 +0530 Subject: [PATCH 39/50] [AIX][Coredump] AIX Coredump debugging Implementation (#25) Creates a general framework to be able to debug an AIX generated coredump file. At this point, we are only supporting 64-bit core files using this general framework. With this implementation, LLDB can recognise and debug any 64-bit AIX coredump file. Most of the generic debugging commands work after this: # bin/lldb --core /home/dhruv/LLDB/tests/core (lldb) target create --core "/home/dhruv/LLDB/tests/core" Core file '/home/dhruv/LLDB/tests/core' (powerpc64) was loaded. (lldb) bt * thread #1, stop reason = SIGSEGV * frame #0: 0x0000000100000940 coretest64`main at core.c:5 frame #1: 0x00000001000004ac coretest64`__start + 116 (lldb) process status Process 18446744071562067991 stopped * thread #1, stop reason = SIGSEGV frame #0: 0x0000000100000940 coretest64`main at core.c:5 2 char *str; 3 int a = 10; 4 str = "GfG"; -> 5 *(str+1) = 'n'; 6 return a; 7 } And others like memory read, image list, image dump sections, disassembly etc --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 62 ++++- .../AIX-DYLD/DynamicLoaderAIXDYLD.h | 6 + .../Plugins/ObjectFile/AIXCore/CMakeLists.txt | 13 + .../ObjectFile/AIXCore/ObjectFileAIXCore.cpp | 254 ++++++++++++++++++ .../ObjectFile/AIXCore/ObjectFileAIXCore.h | 121 +++++++++ lldb/source/Plugins/ObjectFile/CMakeLists.txt | 1 + lldb/source/Plugins/Process/CMakeLists.txt | 1 + .../Plugins/Process/aix-core/AIXCore.cpp | 116 ++++++++ .../source/Plugins/Process/aix-core/AIXCore.h | 125 +++++++++ .../Plugins/Process/aix-core/CMakeLists.txt | 16 ++ .../Process/aix-core/ProcessAIXCore.cpp | 251 +++++++++++++++++ .../Plugins/Process/aix-core/ProcessAIXCore.h | 100 +++++++ .../aix-core/RegisterContextCoreAIX_ppc64.cpp | 136 ++++++++++ .../aix-core/RegisterContextCoreAIX_ppc64.h | 46 ++++ .../Process/aix-core/ThreadAIXCore.cpp | 127 +++++++++ .../Plugins/Process/aix-core/ThreadAIXCore.h | 110 ++++++++ 16 files changed, 1484 insertions(+), 1 deletion(-) create mode 100644 lldb/source/Plugins/ObjectFile/AIXCore/CMakeLists.txt create mode 100644 lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp create mode 100644 lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.h create mode 100644 lldb/source/Plugins/Process/aix-core/AIXCore.cpp create mode 100644 lldb/source/Plugins/Process/aix-core/AIXCore.h create mode 100644 lldb/source/Plugins/Process/aix-core/CMakeLists.txt create mode 100644 lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp create mode 100644 lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h create mode 100644 lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.cpp create mode 100644 lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.h create mode 100644 lldb/source/Plugins/Process/aix-core/ThreadAIXCore.cpp create mode 100644 lldb/source/Plugins/Process/aix-core/ThreadAIXCore.h diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 1a98bb9334043..7e44ffbb1c051 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -228,6 +228,65 @@ void DynamicLoaderAIXDYLD::ResolveExecutableModule( target.SetExecutableModule(module_sp, eLoadDependentsNo); } +bool DynamicLoaderAIXDYLD::IsCoreFile() const { + return !m_process->IsLiveDebugSession(); +} + +void DynamicLoaderAIXDYLD::FillCoreLoaderData(lldb_private::DataExtractor &data, + uint64_t loader_offset, uint64_t loader_size ) { + + static char *buffer = (char *)malloc(loader_size); + struct ld_info ldinfo[64]; + char *buffer_complete; + struct ld_info *ptr; + int i = 0; + + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); + ByteOrder byteorder = data.GetByteOrder(); + data.ExtractBytes(loader_offset, loader_size, eByteOrderBig, buffer); + buffer_complete = buffer + loader_size; + ldinfo[0].ldinfo_next = 1; + + while (ldinfo[i++].ldinfo_next != 0) { + + ptr = (struct ld_info *)buffer; + ldinfo[i].ldinfo_next = ptr->ldinfo_next; + ldinfo[i].ldinfo_flags = ptr->ldinfo_flags; + ldinfo[i].ldinfo_core = ptr->ldinfo_core; + ldinfo[i].ldinfo_textorg = ptr->ldinfo_textorg; + ldinfo[i].ldinfo_textsize = ptr->ldinfo_textsize; + ldinfo[i].ldinfo_dataorg = ptr->ldinfo_dataorg; + ldinfo[i].ldinfo_datasize = ptr->ldinfo_datasize; + + char *filename = &ptr->ldinfo_filename[0]; + char *membername = filename + (strlen(filename) + 1); + strcpy(ldinfo[i].ldinfo_filename, filename); + + buffer += ptr->ldinfo_next; + struct ld_info *ptr2 = &(ldinfo[i]); + char *pathName = ptr2->ldinfo_filename; + char pathWithMember[PATH_MAX] = {0}; + if (strlen(membername) > 0) { + sprintf(pathWithMember, "%s(%s)", pathName, membername); + } else { + sprintf(pathWithMember, "%s", pathName); + } + + FileSpec file(pathWithMember); + ModuleSpec module_spec(file, m_process->GetTarget().GetArchitecture()); + LLDB_LOGF(log, "Module :%s", pathWithMember); + if (ModuleSP module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, true /* notify */)) { + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr2->ldinfo_textorg, false, 1); + UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr2->ldinfo_dataorg, false, 2); + // FIXME: .tdata, .bss + } + if (ptr2->ldinfo_next == 0) { + ptr2 = nullptr; + } + } +} + void DynamicLoaderAIXDYLD::DidAttach() { Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); @@ -361,7 +420,8 @@ void DynamicLoaderAIXDYLD::DidLaunch() { #endif } -Status DynamicLoaderAIXDYLD::CanLoadImage() { return Status(); } +Status DynamicLoaderAIXDYLD::CanLoadImage() { + return Status(); } ThreadPlanSP DynamicLoaderAIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h index 0ffbe688e0069..097f8d048b77f 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h @@ -33,6 +33,9 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { lldb::addr_t module_addr); void OnUnloadModule(lldb::addr_t module_addr); + void FillCoreLoaderData(lldb_private::DataExtractor &data, + uint64_t loader_offset, uint64_t loader_size); + void DidAttach() override; void DidLaunch() override; Status CanLoadImage() override; @@ -49,6 +52,9 @@ class DynamicLoaderAIXDYLD : public DynamicLoader { /// Loads Module from inferior process. void ResolveExecutableModule(lldb::ModuleSP &module_sp); + /// Returns true if the process is for a core file. + bool IsCoreFile() const; + private: std::map m_loaded_modules; }; diff --git a/lldb/source/Plugins/ObjectFile/AIXCore/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/AIXCore/CMakeLists.txt new file mode 100644 index 0000000000000..5656b33a61726 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/AIXCore/CMakeLists.txt @@ -0,0 +1,13 @@ +add_lldb_library(lldbPluginObjectFileAIXCore PLUGIN + ObjectFileAIXCore.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + lldbTarget + lldbUtility + lldbPluginProcessUtility + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp new file mode 100644 index 0000000000000..5158fa4e25077 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp @@ -0,0 +1,254 @@ +//===-- ObjectFileAIXCore.cpp -------------------------------------------------===// +// +// 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 "ObjectFileAIXCore.h" + +#include +#include +#include +#include + +#include "lldb/Utility/FileSpecList.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Stream.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Object/XCOFFObjectFile.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ObjectFileAIXCore) + +enum CoreVersion : uint64_t {AIXCORE32 = 0xFEEDDB1, AIXCORE64 = 0xFEEDDB2}; + +bool m_is_core = false; + +// Static methods. +void ObjectFileAIXCore::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + CreateMemoryInstance, GetModuleSpecifications); +} + +void ObjectFileAIXCore::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ObjectFile *ObjectFileAIXCore::CreateInstance(const lldb::ModuleSP &module_sp, + DataBufferSP data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t file_offset, + lldb::offset_t length) { + + if(m_is_core) + { + + bool mapped_writable = false; + if (!data_sp) { + data_sp = MapFileDataWritable(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + mapped_writable = true; + } + + assert(data_sp); + + const uint8_t *magic = data_sp->GetBytes() + data_offset; + + // Update the data to contain the entire file if it doesn't already + if (data_sp->GetByteSize() < length) { + data_sp = MapFileDataWritable(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + mapped_writable = true; + magic = data_sp->GetBytes(); + } + + // If we didn't map the data as writable take ownership of the buffer. + if (!mapped_writable) { + data_sp = std::make_shared(data_sp->GetBytes(), + data_sp->GetByteSize()); + data_offset = 0; + magic = data_sp->GetBytes(); + } + + std::unique_ptr objfile_up(new ObjectFileAIXCore( + module_sp, data_sp, data_offset, file, file_offset, length)); + ArchSpec spec = objfile_up->GetArchitecture(); + objfile_up->SetModulesArchitecture(spec); + return objfile_up.release(); + + } +} + +ObjectFile *ObjectFileAIXCore::CreateMemoryInstance( + const lldb::ModuleSP &module_sp, WritableDataBufferSP data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) { + return nullptr; +} + +size_t ObjectFileAIXCore::GetModuleSpecifications( + const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, lldb::offset_t file_offset, + lldb::offset_t length, lldb_private::ModuleSpecList &specs) { + const size_t initial_count = specs.GetSize(); + + if (ObjectFileAIXCore::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) { + // Need new ArchType??? + ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + ModuleSpec spec(file, arch_spec); + spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX); + specs.Append(spec); + } + return specs.GetSize() - initial_count; +} + +static uint32_t AIXCoreHeaderCheckFromMagic(uint32_t magic) { + + Log *log = GetLog(LLDBLog::Modules); + switch (magic) { + case AIXCORE32: + LLDB_LOGF(log, "ObjectFileAIXCore: 32-bit not supported"); + break; + case AIXCORE64: + m_is_core = true; + return 1; + break; + } + return 0; +} + +bool ObjectFileAIXCore::MagicBytesMatch(DataBufferSP &data_sp, + lldb::addr_t data_offset, + lldb::addr_t data_length) { + lldb_private::DataExtractor data; + data.SetData(data_sp, data_offset, data_length); + lldb::offset_t offset = 0; + offset += 4; // Skipping to the coredump version + uint32_t magic = data.GetU32(&offset); + return AIXCoreHeaderCheckFromMagic(magic) != 0; +} + +bool ObjectFileAIXCore::ParseHeader() { + + return false; +} + +ByteOrder ObjectFileAIXCore::GetByteOrder() const { + return eByteOrderBig; +} + +bool ObjectFileAIXCore::IsExecutable() const { + return false; +} + +uint32_t ObjectFileAIXCore::GetAddressByteSize() const { + return 8; +} + +AddressClass ObjectFileAIXCore::GetAddressClass(addr_t file_addr) { + return AddressClass::eUnknown; +} + +lldb::SymbolType ObjectFileAIXCore::MapSymbolType(llvm::object::SymbolRef::Type sym_type) { + if (sym_type == llvm::object::SymbolRef::ST_Function) + return lldb::eSymbolTypeCode; + else if (sym_type == llvm::object::SymbolRef::ST_Data) + return lldb::eSymbolTypeData; + return lldb::eSymbolTypeInvalid; +} + +void ObjectFileAIXCore::ParseSymtab(Symtab &lldb_symtab) { +} + +bool ObjectFileAIXCore::IsStripped() { + return false; +} + +void ObjectFileAIXCore::CreateSections(SectionList &unified_section_list) { +} + +void ObjectFileAIXCore::Dump(Stream *s) { +} + +ArchSpec ObjectFileAIXCore::GetArchitecture() { + ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE); + return arch_spec; +} + +UUID ObjectFileAIXCore::GetUUID() { + return UUID(); +} + +uint32_t ObjectFileAIXCore::GetDependentModules(FileSpecList &files) { + + auto original_size = files.GetSize(); + return files.GetSize() - original_size; +} + +Address ObjectFileAIXCore::GetImageInfoAddress(Target *target) { + return Address(); +} + +lldb_private::Address ObjectFileAIXCore::GetBaseAddress() { + return lldb_private::Address(); +} +ObjectFile::Type ObjectFileAIXCore::CalculateType() { + return eTypeCoreFile; +} + +ObjectFile::Strata ObjectFileAIXCore::CalculateStrata() { + return eStrataUnknown; +} + +std::vector +ObjectFileAIXCore::GetLoadableData(Target &target) { + std::vector loadables; + return loadables; +} + +lldb::WritableDataBufferSP +ObjectFileAIXCore::MapFileDataWritable(const FileSpec &file, uint64_t Size, + uint64_t Offset) { + return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size, + Offset); +} + +ObjectFileAIXCore::ObjectFileAIXCore(const lldb::ModuleSP &module_sp, + DataBufferSP data_sp, lldb::offset_t data_offset, + const FileSpec *file, lldb::offset_t file_offset, + lldb::offset_t length) + : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset) + { + if (file) + m_file = *file; +} + +ObjectFileAIXCore::ObjectFileAIXCore(const lldb::ModuleSP &module_sp, + DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, + addr_t header_addr) + : ObjectFile(module_sp, process_sp, header_addr, header_data_sp) + { +} diff --git a/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.h b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.h new file mode 100644 index 0000000000000..5dbd78d919bb6 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.h @@ -0,0 +1,121 @@ +//===-- ObjectFileAIXCore.h --------------------------------------- -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_AIXCORE_OBJECTFILEAIXCORE_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_AIXCORE_OBJECTFILEAIXCORE_H + +#include + +#include + +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/UUID.h" +#include "lldb/lldb-private.h" +#include "llvm/Object/XCOFFObjectFile.h" + +/// \class ObjectFileAIXCore +/// Generic AIX CORE object file reader. +/// +/// This class provides a generic AIX Core (32/64 bit) reader plugin implementing +/// the ObjectFile protocol. +class ObjectFileAIXCore : public lldb_private::ObjectFile { +public: + // Static Functions + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "aix-core-obj"; } + + static llvm::StringRef GetPluginDescriptionStatic() { + return "AIX core object file reader."; + } + + static lldb_private::ObjectFile * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length); + + static lldb_private::ObjectFile *CreateMemoryInstance( + const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + + static size_t GetModuleSpecifications(const lldb_private::FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + lldb_private::ModuleSpecList &specs); + + static bool MagicBytesMatch(lldb::DataBufferSP &data_sp, lldb::addr_t offset, + lldb::addr_t length); + + static lldb::SymbolType MapSymbolType(llvm::object::SymbolRef::Type sym_type); + + // PluginInterface protocol + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + // ObjectFile Protocol. + bool ParseHeader() override; + + lldb::ByteOrder GetByteOrder() const override; + + bool IsExecutable() const override; + + uint32_t GetAddressByteSize() const override; + + lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override; + + void ParseSymtab(lldb_private::Symtab &symtab) override; + + bool IsStripped() override; + + void CreateSections(lldb_private::SectionList &unified_section_list) override; + + void Dump(lldb_private::Stream *s) override; + + lldb_private::ArchSpec GetArchitecture() override; + + lldb_private::UUID GetUUID() override; + + uint32_t GetDependentModules(lldb_private::FileSpecList &files) override; + + lldb_private::Address + GetImageInfoAddress(lldb_private::Target *target) override; + lldb_private::Address GetBaseAddress() override; + + ObjectFile::Type CalculateType() override; + + ObjectFile::Strata CalculateStrata() override; + + ObjectFileAIXCore(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + ObjectFileAIXCore(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP header_data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + +protected: + + static bool ParseAIXCoreHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr + ); + + std::vector + GetLoadableData(lldb_private::Target &target) override; + + static lldb::WritableDataBufferSP + MapFileDataWritable(const lldb_private::FileSpec &file, uint64_t Size, + uint64_t Offset); + +}; + +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_AIXCORE_OBJECTFILEAIXCORE_H diff --git a/lldb/source/Plugins/ObjectFile/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/CMakeLists.txt index 7abd0c96f4fd7..1605356fdb7f1 100644 --- a/lldb/source/Plugins/ObjectFile/CMakeLists.txt +++ b/lldb/source/Plugins/ObjectFile/CMakeLists.txt @@ -9,3 +9,4 @@ add_subdirectory(PECOFF) add_subdirectory(XCOFF) add_subdirectory(Placeholder) add_subdirectory(wasm) +add_subdirectory(AIXCore) diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt index 058b4b9ad2157..0b66ea18c82ce 100644 --- a/lldb/source/Plugins/Process/CMakeLists.txt +++ b/lldb/source/Plugins/Process/CMakeLists.txt @@ -24,3 +24,4 @@ add_subdirectory(elf-core) add_subdirectory(mach-core) add_subdirectory(minidump) add_subdirectory(FreeBSDKernel) +add_subdirectory(aix-core) diff --git a/lldb/source/Plugins/Process/aix-core/AIXCore.cpp b/lldb/source/Plugins/Process/aix-core/AIXCore.cpp new file mode 100644 index 0000000000000..95e47b4d8be53 --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/AIXCore.cpp @@ -0,0 +1,116 @@ +//===-- AIXCore.cpp ------------------------------------------------===// +// +// 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 + +#include "lldb/Core/Section.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" + +#include "AIXCore.h" + +using namespace AIXCORE; +using namespace lldb; +using namespace lldb_private; + +AIXCore64Header::AIXCore64Header() { memset(this, 0, sizeof(AIXCore64Header)); } + + +bool AIXCore64Header::ParseRegisterContext(lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + // The data is arranged in this order in this coredump file + // so we have to fetch in this exact order. But need to change + // the context structure order according to Infos_ppc64 + for(int i = 0; i < 32; i++) + Fault.context.gpr[i] = data.GetU64(offset); + Fault.context.msr = data.GetU64(offset); + Fault.context.pc = data.GetU64(offset); + Fault.context.lr = data.GetU64(offset); + Fault.context.ctr = data.GetU64(offset); + Fault.context.cr = data.GetU32(offset); + Fault.context.xer = data.GetU32(offset); + Fault.context.fpscr = data.GetU32(offset); + Fault.context.fpscrx = data.GetU32(offset); + Fault.context.except[0] = data.GetU64(offset); + for(int i = 0; i < 32; i++) + Fault.context.fpr[i] = data.GetU64(offset); + Fault.context.fpeu = data.GetU8(offset); + Fault.context.fpinfo = data.GetU8(offset); + Fault.context.fpscr24_31 = data.GetU8(offset); + Fault.context.pad[0] = data.GetU8(offset); + Fault.context.excp_type = data.GetU32(offset); + + return true; +} +bool AIXCore64Header::ParseThreadContext(lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + + lldb::offset_t offset_to_regctx = *offset; + offset_to_regctx += sizeof(thrdentry64); + Fault.thread.ti_tid = data.GetU64(offset); + Fault.thread.ti_pid = data.GetU32(offset); + int ret = ParseRegisterContext(data, &offset_to_regctx); + return true; +} + +bool AIXCore64Header::ParseUserData(lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + User.process.pi_pid = data.GetU32(offset); + User.process.pi_ppid = data.GetU32(offset); + User.process.pi_sid = data.GetU32(offset); + User.process.pi_pgrp = data.GetU32(offset); + User.process.pi_uid = data.GetU32(offset); + User.process.pi_suid = data.GetU32(offset); + + *offset += 76; + + ByteOrder byteorder = data.GetByteOrder(); + size_t size = 33; + data.ExtractBytes(*offset, size, byteorder, User.process.pi_comm); + offset += size; + + return true; +} + +bool AIXCore64Header::ParseCoreHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + + SignalNum = data.GetU8(offset); + Flag = data.GetU8(offset); + Entries = data.GetU16(offset); + Version = data.GetU32(offset); + FDInfo = data.GetU64(offset); + + LoaderOffset = data.GetU64(offset); + LoaderSize = data.GetU64(offset); + NumberOfThreads = data.GetU32(offset); + Reserved0 = data.GetU32(offset); + ThreadContextOffset = data.GetU64(offset); + NumSegRegion = data.GetU64(offset); + SegRegionOffset = data.GetU64(offset); + StackOffset = data.GetU64(offset); + StackBaseAddr = data.GetU64(offset); + StackSize = data.GetU64(offset); + DataRegionOffset = data.GetU64(offset); + DataBaseAddr = data.GetU64(offset); + DataSize = data.GetU64(offset); + + *offset += 104; + lldb::offset_t offset_to_user = (*offset + sizeof(ThreadContext64)); + int ret = 0; + ret = ParseThreadContext(data, offset); + ret = ParseUserData(data, &offset_to_user); + + return true; + +} + diff --git a/lldb/source/Plugins/Process/aix-core/AIXCore.h b/lldb/source/Plugins/Process/aix-core/AIXCore.h new file mode 100644 index 0000000000000..3d78d5e92c7ab --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/AIXCore.h @@ -0,0 +1,125 @@ +//===-- AIXCore.h ----------------------------------------*- 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 +// +// Notes about AIX Process core dumps: +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_AIXCORE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_AIXCORE_H + +#include "llvm/ADT/StringRef.h" +#include +#include +#include + +#include +#include + +namespace AIXCORE { + +struct RegContext { + // The data is arranged in order as filled by AIXCore.cpp in this coredump file + // so we have to fetch in that exact order, refer there. + // But need to change + // the context structure in order according to Infos_ppc64 + uint64_t gpr[32]; /* 64-bit gprs */ + unsigned long pc; /* msr */ + unsigned long msr; /* iar */ + unsigned long origr3; /* iar */ + unsigned long ctr; /* CTR */ + unsigned long lr; /* LR */ + unsigned long xer; /* XER */ + unsigned long cr; /* CR */ + unsigned long softe; /* CR */ + unsigned long trap; /* CR */ + unsigned int fpscr; /* floating pt status reg */ + unsigned int fpscrx; /* software ext to fpscr */ + unsigned long except[1]; /* exception address */ + double fpr[32]; /* floating pt regs */ + char fpeu; /* floating pt ever used */ + char fpinfo; /* floating pt info */ + char fpscr24_31; /* bits 24-31 of 64-bit FPSCR */ + char pad[1]; + int excp_type; /* exception type */ +}; + + struct ThreadContext64 { + struct thrdentry64 thread; + struct RegContext context; + }; + + struct UserData { + + struct procentry64 process; + unsigned long long reserved[16]; + }; + + struct AIXCore64Header { + + int8_t SignalNum; /* signal number (cause of error) */ + int8_t Flag; /* flag to describe core dump type */ + uint16_t Entries; /* number of core dump modules */ + uint32_t Version; /* core file format number */ + uint64_t FDInfo; /* offset to fd region in file */ + + uint64_t LoaderOffset; /* offset to loader region in file */ + uint64_t LoaderSize; /* size of loader region */ + + uint32_t NumberOfThreads ; /* number of elements in thread table */ + uint32_t Reserved0; /* Padding */ + uint64_t ThreadContextOffset; /* offset to thread context table */ + + uint64_t NumSegRegion; /* n of elements in segregion */ + uint64_t SegRegionOffset; /* offset to start of segregion table */ + + uint64_t StackOffset; /* offset of user stack in file */ + uint64_t StackBaseAddr; /* base address of user stack region */ + uint64_t StackSize; /* size of user stack region */ + + uint64_t DataRegionOffset; /* offset to user data region */ + uint64_t DataBaseAddr; /* base address of user data region */ + uint64_t DataSize; /* size of user data region */ + uint64_t SDataBase; /* base address of sdata region */ + uint64_t SDataSize; /* size of sdata region */ + + uint64_t NumVMRegions; /* number of anonymously mapped areas */ + uint64_t VMOffset; /* offset to start of vm_infox table */ + + int32_t ProcessorImplementation; /* processor implementation */ + uint32_t NumElementsCTX; /* n of elements in extended ctx table*/ + uint64_t CPRSOffset; /* Checkpoint/Restart offset */ + uint64_t ExtendedContextOffset; /* extended context offset */ + uint64_t OffsetUserKey; /* Offset to user-key exception data */ + uint64_t OffsetLoaderTLS; /* offset to the loader region in file + when a process uses TLS data */ + uint64_t TLSLoaderSize; /* size of the above loader region */ + uint64_t ExtendedProcEntry; /* Extended procentry64 information */ + uint64_t Reserved[2]; + + struct ThreadContext64 Fault; + + struct UserData User; + + AIXCore64Header(); + + bool ParseCoreHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + bool ParseThreadContext(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + bool ParseUserData(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + bool ParseRegisterContext(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + bool ParseLoaderData(lldb_private::DataExtractor &data, + lldb::offset_t *offset); + + }; + + +} + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_AIXCORE_H diff --git a/lldb/source/Plugins/Process/aix-core/CMakeLists.txt b/lldb/source/Plugins/Process/aix-core/CMakeLists.txt new file mode 100644 index 0000000000000..347717a362491 --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/CMakeLists.txt @@ -0,0 +1,16 @@ +add_definitions("-D_ALL_SOURCE") + +add_lldb_library(lldbPluginProcessAIXCore PLUGIN + ProcessAIXCore.cpp + AIXCore.cpp + ThreadAIXCore.cpp + RegisterContextCoreAIX_ppc64.cpp + + LINK_LIBS + lldbCore + lldbTarget + lldbPluginProcessUtility + LINK_COMPONENTS + BinaryFormat + Support + ) diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp new file mode 100644 index 0000000000000..9300aa14ac4db --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp @@ -0,0 +1,251 @@ +//===-- ProcessAIXCore.cpp ------------------------------------------------===// +// +// 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 + +#include +#include + +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Section.h" +#include "lldb/Target/ABI.h" +#include "lldb/Target/DynamicLoader.h" +#include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/UnixSignals.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" + +#include "llvm/Support/Threading.h" +#include "Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h" + +#include "ProcessAIXCore.h" +#include "AIXCore.h" +#include "ThreadAIXCore.h" + +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ProcessAIXCore) + +llvm::StringRef ProcessAIXCore::GetPluginDescriptionStatic() { + return "AIX core dump plug-in."; +} + +void ProcessAIXCore::Initialize() { + static llvm::once_flag g_once_flag; + + llvm::call_once(g_once_flag, []() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); + }); +} + +void ProcessAIXCore::Terminate() { + PluginManager::UnregisterPlugin(ProcessAIXCore::CreateInstance); +} + +lldb::ProcessSP ProcessAIXCore::CreateInstance(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const FileSpec *crash_file, + bool can_connect) { + lldb::ProcessSP process_sp; + if (crash_file && !can_connect) { + const size_t header_size = sizeof(AIXCORE::AIXCore64Header); + + auto data_sp = FileSystem::Instance().CreateDataBuffer( + crash_file->GetPath(), header_size, 0); + + if (data_sp && data_sp->GetByteSize() == header_size) { + AIXCORE::AIXCore64Header aixcore_header; + DataExtractor data(data_sp, lldb::eByteOrderBig, 4); + lldb::offset_t data_offset = 0; + if(aixcore_header.ParseCoreHeader(data, &data_offset)) { + process_sp = std::make_shared(target_sp, listener_sp, + *crash_file); + } + } + + } + return process_sp; +} + +// ProcessAIXCore constructor +ProcessAIXCore::ProcessAIXCore(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const FileSpec &core_file) + : PostMortemProcess(target_sp, listener_sp, core_file) {} + +// Destructor +ProcessAIXCore::~ProcessAIXCore() { + Clear(); + // We need to call finalize on the process before destroying ourselves to + // make sure all of the broadcaster cleanup goes as planned. If we destruct + // this class, then Process::~Process() might have problems trying to fully + // destroy the broadcaster. + Finalize(true /* destructing */); +} + +bool ProcessAIXCore::CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) { + + if (!m_core_module_sp && FileSystem::Instance().Exists(m_core_file)) { + ModuleSpec core_module_spec(m_core_file, target_sp->GetArchitecture()); + Status error(ModuleList::GetSharedModule(core_module_spec, m_core_module_sp, + nullptr, nullptr, nullptr)); + if (m_core_module_sp) { + ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); + if (core_objfile && core_objfile->GetType() == ObjectFile::eTypeCoreFile){ + return true; + } + } + } + return false; + +} + +ArchSpec ProcessAIXCore::GetArchitecture() { + + ArchSpec arch = m_core_module_sp->GetObjectFile()->GetArchitecture(); + + ArchSpec target_arch = GetTarget().GetArchitecture(); + arch.MergeFrom(target_arch); + + return arch; +} + +lldb_private::DynamicLoader *ProcessAIXCore::GetDynamicLoader() { + if (m_dyld_up.get() == nullptr) { + m_dyld_up.reset(DynamicLoader::FindPlugin( + this, DynamicLoaderAIXDYLD::GetPluginNameStatic())); + } + return m_dyld_up.get(); +} + +void ProcessAIXCore::ParseAIXCoreFile() { + + Log *log = GetLog(LLDBLog::Process); + AIXSigInfo siginfo; + ThreadData thread_data; + + const lldb_private::UnixSignals &unix_signals = *GetUnixSignals(); + const ArchSpec &arch = GetArchitecture(); + + siginfo.Parse(m_aixcore_header, arch, unix_signals); + thread_data.siginfo = siginfo; + SetID(m_aixcore_header.User.process.pi_pid); + + thread_data.name.assign (m_aixcore_header.User.process.pi_comm, + strnlen (m_aixcore_header.User.process.pi_comm, + sizeof (m_aixcore_header.User.process.pi_comm))); + + lldb::DataBufferSP data_buffer_sp(new lldb_private::DataBufferHeap(sizeof(m_aixcore_header.Fault.context), 0)); + + memcpy(static_cast(const_cast(data_buffer_sp->GetBytes())), + &m_aixcore_header.Fault.context, sizeof(m_aixcore_header.Fault.context)); + + lldb_private::DataExtractor data(data_buffer_sp, lldb::eByteOrderBig, 8); + + thread_data.gpregset = DataExtractor(data, 0, sizeof(m_aixcore_header.Fault.context)); + m_thread_data.push_back(thread_data); + LLDB_LOGF(log, "ProcessAIXCore: Parsing Complete!"); + +} + +// Process Control +Status ProcessAIXCore::DoLoadCore() { + + Status error; + if (!m_core_module_sp) { + error = Status::FromErrorString("invalid core module"); + return error; + } + + FileSpec file = m_core_module_sp->GetObjectFile()->GetFileSpec(); + + if (file) { + const size_t header_size = sizeof(AIXCORE::AIXCore64Header); + auto data_sp = FileSystem::Instance().CreateDataBuffer( + file.GetPath(), -1, 0); + if (data_sp && data_sp->GetByteSize() != 0) { + + DataExtractor data(data_sp, lldb::eByteOrderBig, 4); + lldb::offset_t data_offset = 0; + m_aixcore_header.ParseCoreHeader(data, &data_offset); + auto dyld = static_cast(GetDynamicLoader()); + dyld->FillCoreLoaderData(data, m_aixcore_header.LoaderOffset, + m_aixcore_header.LoaderSize); + + } else { + error = Status::FromErrorString("invalid data"); + return error; + } + } else { + error = Status::FromErrorString("invalid file"); + return error; + } + + m_thread_data_valid = true; + ParseAIXCoreFile(); + ArchSpec arch(m_core_module_sp->GetArchitecture()); + + ArchSpec target_arch = GetTarget().GetArchitecture(); + ArchSpec core_arch(m_core_module_sp->GetArchitecture()); + target_arch.MergeFrom(core_arch); + GetTarget().SetArchitecture(target_arch); + + lldb::ModuleSP exe_module_sp = GetTarget().GetExecutableModule(); + if (!exe_module_sp) { + ModuleSpec exe_module_spec; + exe_module_spec.GetArchitecture() = arch; + exe_module_spec.GetFileSpec().SetFile(m_aixcore_header.User.process.pi_comm, + FileSpec::Style::native); + exe_module_sp = GetTarget().GetOrCreateModule(exe_module_spec, true); + GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsNo); + } + + return error; +} + +bool ProcessAIXCore::DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) +{ + const ThreadData &td = m_thread_data[0]; + + lldb::ThreadSP thread_sp = + std::make_shared(*this, td); + new_thread_list.AddThread(thread_sp); + + return true; +} + +void ProcessAIXCore::RefreshStateAfterStop() {} + +// Process Memory +size_t ProcessAIXCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size, + Status &error) { + if (lldb::ABISP abi_sp = GetABI()) + addr = abi_sp->FixAnyAddress(addr); + + // Don't allow the caching that lldb_private::Process::ReadMemory does since + // in core files we have it all cached our our core file anyway. + return DoReadMemory(addr, buf, size, error); +} + +size_t ProcessAIXCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, + Status &error) { return 0; } + +Status ProcessAIXCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo ®ion_info) { + return Status(); +} + +Status ProcessAIXCore::DoDestroy() { return Status(); } diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h new file mode 100644 index 0000000000000..9880c491689ca --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h @@ -0,0 +1,100 @@ +//===-- ProcessAIXCore.h ----------------------------------------*- 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 +// +// Notes about AIX Process core dumps: +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_PROCESSAIXCORE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_PROCESSAIXCORE_H + +#include +#include + +#include "lldb/Target/PostMortemProcess.h" +#include "lldb/Utility/Status.h" +#include "lldb/Target/Process.h" +#include "AIXCore.h" +#include "ThreadAIXCore.h" + +struct ThreadData; + +class ProcessAIXCore : public lldb_private::PostMortemProcess { +public: + // Constructors and Destructors + static lldb::ProcessSP + CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, + const lldb_private::FileSpec *crash_file_path, + bool can_connect); + + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "aix-core"; } + + static llvm::StringRef GetPluginDescriptionStatic(); + + // Constructors and Destructors + ProcessAIXCore(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, + const lldb_private::FileSpec &core_file); + + ~ProcessAIXCore() override; + + // PluginInterface protocol + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + // Process Control + lldb_private::Status DoDestroy() override; + + lldb_private::Status WillResume() override { + return lldb_private::Status::FromErrorStringWithFormatv( + "error: {0} does not support resuming processes", GetPluginName()); + } + + bool WarnBeforeDetach() const override { return false; } + + lldb_private::ArchSpec GetArchitecture(); + + bool CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) override; + + // Creating a new process, or attaching to an existing one + lldb_private::Status DoLoadCore() override; + + bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list, + lldb_private::ThreadList &new_thread_list) override; + + lldb_private::Status + DoGetMemoryRegionInfo(lldb::addr_t load_addr, + lldb_private::MemoryRegionInfo ®ion_info) override; + + void RefreshStateAfterStop() override; + + lldb_private::DynamicLoader *GetDynamicLoader() override; + + // Process Memory + size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size, + lldb_private::Status &error) override; + + size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, + lldb_private::Status &error) override; + + void ParseAIXCoreFile(); + + +private: + lldb::ModuleSP m_core_module_sp; + std::string m_dyld_plugin_name; + + // True if m_thread_contexts contains valid entries + bool m_thread_data_valid = false; + AIXCORE::AIXCore64Header m_aixcore_header; + + std::vector m_thread_data; +}; + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_PROCESSAIXCORE_H diff --git a/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.cpp b/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.cpp new file mode 100644 index 0000000000000..b243017bf9a2a --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.cpp @@ -0,0 +1,136 @@ +//===-- RegisterContextCoreAIX_ppc64.cpp ------------------------------===// +// +// 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 "RegisterContextCoreAIX_ppc64.h" + +#include "lldb/Target/Thread.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" + +#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" +#include "Plugins/Process/elf-core/RegisterUtilities.h" + +#include + +using namespace lldb_private; + +RegisterContextCoreAIX_ppc64::RegisterContextCoreAIX_ppc64( + Thread &thread, RegisterInfoInterface *register_info, + const DataExtractor &gpregset) + : RegisterContextPOSIX_ppc64le(thread, 0, register_info) { + m_gpr_buffer = std::make_shared(gpregset.GetDataStart(), + gpregset.GetByteSize()); + m_gpr.SetData(m_gpr_buffer); + m_gpr.SetByteOrder(gpregset.GetByteOrder()); + + // This Code is for Registers like FPR, VSR, VMX and is disabled right now. + // It will be implemented as per need. + + /* ArchSpec arch = register_info->GetTargetArchitecture(); + DataExtractor fpregset;// = getRegset(notes, arch.GetTriple(), FPR_Desc); + m_fpr_buffer = std::make_shared(fpregset.GetDataStart(), + fpregset.GetByteSize()); + m_fpr.SetData(m_fpr_buffer); + m_fpr.SetByteOrder(fpregset.GetByteOrder()); + + DataExtractor vmxregset;// = getRegset(notes, arch.GetTriple(), PPC_VMX_Desc); + m_vmx_buffer = std::make_shared(vmxregset.GetDataStart(), + vmxregset.GetByteSize()); + m_vmx.SetData(m_vmx_buffer); + m_vmx.SetByteOrder(vmxregset.GetByteOrder()); + + DataExtractor vsxregset;// = getRegset(notes, arch.GetTriple(), PPC_VSX_Desc); + m_vsx_buffer = std::make_shared(vsxregset.GetDataStart(), + vsxregset.GetByteSize()); + m_vsx.SetData(m_vsx_buffer); + m_vsx.SetByteOrder(vsxregset.GetByteOrder());*/ +} + +size_t RegisterContextCoreAIX_ppc64::GetFPRSize() const { + return k_num_fpr_registers_ppc64le * sizeof(uint64_t); +} + +size_t RegisterContextCoreAIX_ppc64::GetVMXSize() const { + return (k_num_vmx_registers_ppc64le - 1) * sizeof(uint64_t) * 2 + + sizeof(uint32_t); +} + +size_t RegisterContextCoreAIX_ppc64::GetVSXSize() const { + return k_num_vsx_registers_ppc64le * sizeof(uint64_t) * 2; +} + +bool RegisterContextCoreAIX_ppc64::ReadRegister( + const RegisterInfo *reg_info, RegisterValue &value) { + lldb::offset_t offset = reg_info->byte_offset; + + if (IsFPR(reg_info->kinds[lldb::eRegisterKindLLDB])) { + uint64_t v; + offset -= GetGPRSize(); + offset = m_fpr.CopyData(offset, reg_info->byte_size, &v); + + if (offset == reg_info->byte_size) { + value.SetBytes(&v, reg_info->byte_size, m_fpr.GetByteOrder()); + return true; + } + } else if (IsVMX(reg_info->kinds[lldb::eRegisterKindLLDB])) { + uint32_t v[4]; + offset -= GetGPRSize() + GetFPRSize(); + offset = m_vmx.CopyData(offset, reg_info->byte_size, &v); + + if (offset == reg_info->byte_size) { + value.SetBytes(v, reg_info->byte_size, m_vmx.GetByteOrder()); + return true; + } + } else if (IsVSX(reg_info->kinds[lldb::eRegisterKindLLDB])) { + uint32_t v[4]; + lldb::offset_t tmp_offset; + offset -= GetGPRSize() + GetFPRSize() + GetVMXSize(); + + if (offset < GetVSXSize() / 2) { + tmp_offset = m_vsx.CopyData(offset / 2, reg_info->byte_size / 2, &v); + + if (tmp_offset != reg_info->byte_size / 2) { + return false; + } + + uint8_t *dst = (uint8_t *)&v + sizeof(uint64_t); + tmp_offset = m_fpr.CopyData(offset / 2, reg_info->byte_size / 2, dst); + + if (tmp_offset != reg_info->byte_size / 2) { + return false; + } + + value.SetBytes(&v, reg_info->byte_size, m_vsx.GetByteOrder()); + return true; + } else { + offset = + m_vmx.CopyData(offset - GetVSXSize() / 2, reg_info->byte_size, &v); + if (offset == reg_info->byte_size) { + value.SetBytes(v, reg_info->byte_size, m_vmx.GetByteOrder()); + return true; + } + } + } else { + uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); + + if (offset == reg_info->byte_offset + reg_info->byte_size) { + if (reg_info->byte_size < sizeof(v)) + value = (uint32_t)v; + else + value = v; + return true; + } + } + + return false; +} + +bool RegisterContextCoreAIX_ppc64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue &value) { + return false; +} diff --git a/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.h b/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.h new file mode 100644 index 0000000000000..8f1f71ce8d884 --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/RegisterContextCoreAIX_ppc64.h @@ -0,0 +1,46 @@ +//===-- RegisterContextCoreAIX_ppc64.h ----------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_REGISTERCONTEXTAIXCORE_PPC64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_REGISTERCONTEXTAIXCORE_PPC64_H + +#include "Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h" +#include "lldb/Utility/DataExtractor.h" + +class RegisterContextCoreAIX_ppc64 : public RegisterContextPOSIX_ppc64le { +public: + RegisterContextCoreAIX_ppc64( + lldb_private::Thread &thread, + lldb_private::RegisterInfoInterface *register_info, + const lldb_private::DataExtractor &gpregset); + + bool ReadRegister(const lldb_private::RegisterInfo *reg_info, + lldb_private::RegisterValue &value) override; + + bool WriteRegister(const lldb_private::RegisterInfo *reg_info, + const lldb_private::RegisterValue &value) override; + +protected: + size_t GetFPRSize() const; + + size_t GetVMXSize() const; + + size_t GetVSXSize() const; + +private: + lldb::DataBufferSP m_gpr_buffer; + lldb::DataBufferSP m_fpr_buffer; + lldb::DataBufferSP m_vmx_buffer; + lldb::DataBufferSP m_vsx_buffer; + lldb_private::DataExtractor m_gpr; + lldb_private::DataExtractor m_fpr; + lldb_private::DataExtractor m_vmx; + lldb_private::DataExtractor m_vsx; +}; + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_REGISTERCONTEXTAIXCORE_PPC64_H diff --git a/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.cpp b/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.cpp new file mode 100644 index 0000000000000..979e5199fe24d --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.cpp @@ -0,0 +1,127 @@ +//===-- ThreadAIXCore.cpp -------------------------------------------------===// +// +// 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 "lldb/Target/RegisterContext.h" +#include "lldb/Target/StopInfo.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/UnixSignals.h" +#include "lldb/Target/Unwind.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/ProcessInfo.h" + +#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h" +#include "Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h" +#include "RegisterContextCoreAIX_ppc64.h" + +#include "ProcessAIXCore.h" +#include "AIXCore.h" +#include "ThreadAIXCore.h" + +#include +#include + +using namespace lldb; +using namespace lldb_private; + +// Construct a Thread object with given data +ThreadAIXCore::ThreadAIXCore(Process &process, const ThreadData &td) + : Thread(process, td.tid), m_thread_name(td.name), m_thread_reg_ctx_sp(), + m_gpregset_data(td.gpregset), + m_siginfo(std::move(td.siginfo)) {} + +ThreadAIXCore::~ThreadAIXCore() { DestroyThread(); } + +void ThreadAIXCore::RefreshStateAfterStop() { + GetRegisterContext()->InvalidateIfNeeded(false); +} + +RegisterContextSP ThreadAIXCore::GetRegisterContext() { + if (!m_reg_context_sp) { + m_reg_context_sp = CreateRegisterContextForFrame(nullptr); + } + return m_reg_context_sp; +} + +RegisterContextSP +ThreadAIXCore::CreateRegisterContextForFrame(StackFrame *frame) { + RegisterContextSP reg_ctx_sp; + uint32_t concrete_frame_idx = 0; + + if (frame) + concrete_frame_idx = frame->GetConcreteFrameIndex(); + + bool is_linux = false; + if (concrete_frame_idx == 0) { + if (m_thread_reg_ctx_sp) + return m_thread_reg_ctx_sp; + + ProcessAIXCore *process = static_cast(GetProcess().get()); + ArchSpec arch = process->GetArchitecture(); + RegisterInfoInterface *reg_interface = nullptr; + + switch (arch.GetMachine()) { + case llvm::Triple::ppc64: + reg_interface = new RegisterInfoPOSIX_ppc64le(arch); + m_thread_reg_ctx_sp = std::make_shared( + *this, reg_interface, m_gpregset_data); + break; + default: + break; + } + reg_ctx_sp = m_thread_reg_ctx_sp; + } else { + reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame); + } + return reg_ctx_sp; +} + +bool ThreadAIXCore::CalculateStopInfo() { + ProcessSP process_sp(GetProcess()); + if (!process_sp) + return false; + + lldb::UnixSignalsSP unix_signals_sp(process_sp->GetUnixSignals()); + if (!unix_signals_sp) + return false; + + const char *sig_description; + std::string description = m_siginfo.GetDescription(*unix_signals_sp); + if (description.empty()) + sig_description = nullptr; + else + sig_description = description.c_str(); + + SetStopInfo(StopInfo::CreateStopReasonWithSignal( + *this, m_siginfo.si_signo, sig_description, m_siginfo.si_code)); + + SetStopInfo(m_stop_info_sp); + return true; +} + +void AIXSigInfo::Parse(const AIXCORE::AIXCore64Header data, const ArchSpec &arch, + const lldb_private::UnixSignals &unix_signals) { + si_signo = data.SignalNum; + sigfault.si_addr = data.Fault.context.pc; +} + +AIXSigInfo::AIXSigInfo() { memset(this, 0, sizeof(AIXSigInfo)); } + +size_t AIXSigInfo::GetSize(const lldb_private::ArchSpec &arch) { + return sizeof(AIXSigInfo); +} + +std::string AIXSigInfo::GetDescription( + const lldb_private::UnixSignals &unix_signals) const { + return unix_signals.GetSignalDescription(si_signo, 0, + sigfault.si_addr); + +} diff --git a/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.h b/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.h new file mode 100644 index 0000000000000..9ee157e9b2b9b --- /dev/null +++ b/lldb/source/Plugins/Process/aix-core/ThreadAIXCore.h @@ -0,0 +1,110 @@ +//===-- ThreadAIXCore.h -----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_THREADAIXCORE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_THREADAIXCORE_H + +#include "lldb/Target/Thread.h" +#include "lldb/Utility/DataExtractor.h" +#include "llvm/ADT/DenseMap.h" +#include +#include +#include "ProcessAIXCore.h" +#include "AIXCore.h" +#include "ThreadAIXCore.h" + +namespace lldb_private { +class ProcessInstanceInfo; +} + +struct AIXSigInfo { + + //COPY siginfo_t correctly for AIX version + int32_t si_signo; // Order matters for the first 3. + int32_t si_errno; + int32_t si_code; + struct alignas(8) { + lldb::addr_t si_addr; + int16_t si_addr_lsb; + union { + struct { + lldb::addr_t _lower; + lldb::addr_t _upper; + } _addr_bnd; + uint32_t _pkey; + } bounds; + } sigfault; + + enum SigInfoNoteType : uint8_t { eUnspecified, eNT_SIGINFO }; + SigInfoNoteType note_type; + + AIXSigInfo(); + + void Parse(const AIXCORE::AIXCore64Header data, + const lldb_private::ArchSpec &arch, + const lldb_private::UnixSignals &unix_signals); + + std::string + GetDescription(const lldb_private::UnixSignals &unix_signals) const; + + static size_t GetSize(const lldb_private::ArchSpec &arch); +}; + +struct ThreadData { + lldb_private::DataExtractor gpregset; + std::vector notes; + lldb::tid_t tid; + std::string name; + AIXSigInfo siginfo; + int prstatus_sig = 0; +}; + +class ThreadAIXCore : public lldb_private::Thread { +public: + ThreadAIXCore(lldb_private::Process &process, const ThreadData &td); + + ~ThreadAIXCore() override; + + void RefreshStateAfterStop() override; + + lldb::RegisterContextSP GetRegisterContext() override; + + lldb::RegisterContextSP + CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override; + + static bool ThreadIDIsValid(lldb::tid_t thread) { return thread != 0; } + + const char *GetName() override { + if (m_thread_name.empty()) + return nullptr; + return m_thread_name.c_str(); + } + + void SetName(const char *name) override { + if (name && name[0]) + m_thread_name.assign(name); + else + m_thread_name.clear(); + } + + void CreateStopFromSigInfo(const AIXSigInfo &siginfo, + const lldb_private::UnixSignals &unix_signals); + +protected: + // Member variables. + std::string m_thread_name; + lldb::RegisterContextSP m_thread_reg_ctx_sp; + + lldb_private::DataExtractor m_gpregset_data; + std::vector m_notes; + AIXSigInfo m_siginfo; + + bool CalculateStopInfo() override; +}; + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_AIX_CORE_THREADAIXCORE_H >From 57cb8058646103eeada1f92e039d9c54ccd4788f Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Mon, 17 Mar 2025 07:31:26 -0500 Subject: [PATCH 40/50] Merge branch 'llvm:main' into llvmgh-101657 --- lldb/cmake/modules/LLDBConfig.cmake | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake index 312791ce36fc7..9df71edd8b359 100644 --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -292,11 +292,7 @@ endif() # Figure out if lldb could use lldb-server. If so, then we'll # ensure we build lldb-server when an lldb target is being built. -<<<<<<< HEAD -if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD|OpenBSD|Windows|AIX") -======= if (CMAKE_SYSTEM_NAME MATCHES "AIX|Android|Darwin|FreeBSD|Linux|NetBSD|OpenBSD|Windows") ->>>>>>> upstream/main set(LLDB_CAN_USE_LLDB_SERVER ON) else() set(LLDB_CAN_USE_LLDB_SERVER OFF) >From 0767ef036d3f82d1429e04a319feb6627ea08158 Mon Sep 17 00:00:00 2001 From: Dhruv Srivastava Date: Tue, 18 Mar 2025 15:03:17 +0530 Subject: [PATCH 41/50] Error Handling (#32) * Error Handling for aix core module --- .../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 12 +++++++----- .../ObjectFile/AIXCore/ObjectFileAIXCore.cpp | 15 +++++++-------- lldb/source/Plugins/Process/aix-core/AIXCore.cpp | 2 +- .../Plugins/Process/aix-core/ProcessAIXCore.cpp | 11 ++++++++--- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp index 7e44ffbb1c051..12f24c049f373 100644 --- a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp @@ -235,17 +235,19 @@ bool DynamicLoaderAIXDYLD::IsCoreFile() const { void DynamicLoaderAIXDYLD::FillCoreLoaderData(lldb_private::DataExtractor &data, uint64_t loader_offset, uint64_t loader_size ) { + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); static char *buffer = (char *)malloc(loader_size); - struct ld_info ldinfo[64]; - char *buffer_complete; + if (buffer == NULL) { + LLDB_LOG(log, "Buffer allocation failed error: {0}", std::strerror(errno)); + return; + } + struct ld_info ldinfo[64] = {}; struct ld_info *ptr; int i = 0; - Log *log = GetLog(LLDBLog::DynamicLoader); - LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__); ByteOrder byteorder = data.GetByteOrder(); data.ExtractBytes(loader_offset, loader_size, eByteOrderBig, buffer); - buffer_complete = buffer + loader_size; ldinfo[0].ldinfo_next = 1; while (ldinfo[i++].ldinfo_next != 0) { diff --git a/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp index 5158fa4e25077..0ba1056866937 100644 --- a/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp +++ b/lldb/source/Plugins/ObjectFile/AIXCore/ObjectFileAIXCore.cpp @@ -73,8 +73,6 @@ ObjectFile *ObjectFileAIXCore::CreateInstance(const lldb::ModuleSP &module_sp, assert(data_sp); - const uint8_t *magic = data_sp->GetBytes() + data_offset; - // Update the data to contain the entire file if it doesn't already if (data_sp->GetByteSize() < length) { data_sp = MapFileDataWritable(*file, length, file_offset); @@ -82,7 +80,6 @@ ObjectFile *ObjectFileAIXCore::CreateInstance(const lldb::ModuleSP &module_sp, return nullptr; data_offset = 0; mapped_writable = true; - magic = data_sp->GetBytes(); } // If we didn't map the data as writable take ownership of the buffer. @@ -90,7 +87,6 @@ ObjectFile *ObjectFileAIXCore::CreateInstance(const lldb::ModuleSP &module_sp, data_sp = std::make_shared(data_sp->GetBytes(), data_sp->GetByteSize()); data_offset = 0; - magic = data_sp->GetBytes(); } std::unique_ptr objfile_up(new ObjectFileAIXCore( @@ -124,19 +120,22 @@ size_t ObjectFileAIXCore::GetModuleSpecifications( return specs.GetSize() - initial_count; } -static uint32_t AIXCoreHeaderCheckFromMagic(uint32_t magic) { +static bool AIXCoreHeaderCheckFromMagic(uint32_t magic) { Log *log = GetLog(LLDBLog::Modules); + bool ret = false; switch (magic) { case AIXCORE32: LLDB_LOGF(log, "ObjectFileAIXCore: 32-bit not supported"); break; case AIXCORE64: m_is_core = true; - return 1; + ret = true; + break; + default: break; } - return 0; + return ret; } bool ObjectFileAIXCore::MagicBytesMatch(DataBufferSP &data_sp, @@ -147,7 +146,7 @@ bool ObjectFileAIXCore::MagicBytesMatch(DataBufferSP &data_sp, lldb::offset_t offset = 0; offset += 4; // Skipping to the coredump version uint32_t magic = data.GetU32(&offset); - return AIXCoreHeaderCheckFromMagic(magic) != 0; + return AIXCoreHeaderCheckFromMagic(magic); } bool ObjectFileAIXCore::ParseHeader() { diff --git a/lldb/source/Plugins/Process/aix-core/AIXCore.cpp b/lldb/source/Plugins/Process/aix-core/AIXCore.cpp index 95e47b4d8be53..bc496b5af273f 100644 --- a/lldb/source/Plugins/Process/aix-core/AIXCore.cpp +++ b/lldb/source/Plugins/Process/aix-core/AIXCore.cpp @@ -110,7 +110,7 @@ bool AIXCore64Header::ParseCoreHeader(lldb_private::DataExtractor &data, ret = ParseThreadContext(data, offset); ret = ParseUserData(data, &offset_to_user); - return true; + return ret; } diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp index 9300aa14ac4db..cfcbe1a216116 100644 --- a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp @@ -208,8 +208,10 @@ Status ProcessAIXCore::DoLoadCore() { exe_module_spec.GetArchitecture() = arch; exe_module_spec.GetFileSpec().SetFile(m_aixcore_header.User.process.pi_comm, FileSpec::Style::native); - exe_module_sp = GetTarget().GetOrCreateModule(exe_module_spec, true); - GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsNo); + exe_module_sp = + GetTarget().GetOrCreateModule(exe_module_spec, true /* notify */); + if (exe_module_sp) + GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsNo); } return error; @@ -232,8 +234,11 @@ void ProcessAIXCore::RefreshStateAfterStop() {} // Process Memory size_t ProcessAIXCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size, Status &error) { + if(addr == LLDB_INVALID_ADDRESS) + return 0; + if (lldb::ABISP abi_sp = GetABI()) - addr = abi_sp->FixAnyAddress(addr); + addr = abi_sp->FixAnyAddress(addr); // Don't allow the caching that lldb_private::Process::ReadMemory does since // in core files we have it all cached our our core file anyway. >From 8214e5d8cc52b486d3c3f5f4615848b1782cfcf8 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 26 Mar 2025 01:34:36 -0500 Subject: [PATCH 42/50] Merge branch 'llvm:main' into gh-101657 --- lldb/source/Host/common/Host.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 575bb46216d19..6cf1112511c3f 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -20,7 +20,6 @@ #include #include #include -#endif #include #endif >From d00d28ae68c731efe6f9392000be9822ee74ff0a Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Wed, 26 Mar 2025 04:08:23 -0500 Subject: [PATCH 43/50] First time attach resolution --- .../Plugins/Process/AIX/NativeProcessAIX.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp index fc84763857453..83b8ae5eb3258 100644 --- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -2000,7 +2000,21 @@ Status NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid, void *addr, } else if (req == PT_WRITE_BLOCK) { ptrace64(req, pid, (long long)addr, (int)data_size, (int *)result); } else if (req == PT_ATTACH) { + // Block SIGCHLD signal during attach to the process, + // to prevent interruptions. + // The ptrace operation may send SIGCHLD signals in certain cases + // during the attach, which can interfere. + static sigset_t signal_set; + sigemptyset (&signal_set); + sigaddset (&signal_set, SIGCHLD); + if(!pthread_sigmask( SIG_BLOCK, &signal_set, NULL)) + LLDB_LOG(log,"NativeProcessAIX::pthread_sigmask(SIG_BLOCK) Failed"); + ptrace64(req, pid, 0, 0, nullptr); + + //Unblocking the SIGCHLD after attach work. + if(!pthread_sigmask( SIG_UNBLOCK, &signal_set, NULL )) + LLDB_LOG(log,"NativeProcessAIX::pthread_sigmask(SIG_UNBLOCK) Failed"); } else if (req == PT_WATCH) { ptrace64(req, pid, (long long)addr, (int)data_size, nullptr); } else if (req == PT_DETACH) { >From 9ff945e62a906e9711022bf8f77b86a0aa05c64e Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Tue, 1 Apr 2025 04:54:51 -0500 Subject: [PATCH 44/50] Invalid DWARF rangelist --- lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp index cf11e5fb8f5a3..65bd1ee9781d8 100644 --- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp @@ -578,6 +578,7 @@ SectionType ObjectFileXCOFF::GetSectionType(llvm::StringRef sect_name, .Case(".dwinfo", eSectionTypeDWARFDebugInfo) .Case(".dwline", eSectionTypeDWARFDebugLine) .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev) + .Case(".dwrnges", eSectionTypeDWARFDebugRanges) .Default(eSectionTypeInvalid); if (section_type != eSectionTypeInvalid) >From b443dd5b26354da73cd4d785a093d9d1582b25a8 Mon Sep 17 00:00:00 2001 From: Dhruv Srivastava Date: Wed, 2 Apr 2025 11:57:28 +0530 Subject: [PATCH 45/50] Fix for stack memory access from core file (#40) * Fix for stack memory access in core file --- .../Process/aix-core/ProcessAIXCore.cpp | 74 ++++++++++++++++++- .../Plugins/Process/aix-core/ProcessAIXCore.h | 11 +++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp index cfcbe1a216116..bb2db66e2980e 100644 --- a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.cpp @@ -94,6 +94,33 @@ ProcessAIXCore::~ProcessAIXCore() { Finalize(true /* destructing */); } +lldb::addr_t ProcessAIXCore::AddAddressRanges(AIXCORE::AIXCore64Header header) { + const lldb::addr_t addr = header.StackBaseAddr; + FileRange file_range(header.StackOffset, header.StackSize); + VMRangeToFileOffset::Entry range_entry(addr, header.StackSize, file_range); + + if (header.StackSize > 0) { + VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back(); + if (last_entry && + last_entry->GetRangeEnd() == range_entry.GetRangeBase() && + last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase() && + last_entry->GetByteSize() == last_entry->data.GetByteSize()) { + last_entry->SetRangeEnd(range_entry.GetRangeEnd()); + last_entry->data.SetRangeEnd(range_entry.data.GetRangeEnd()); + } else { + m_core_aranges.Append(range_entry); + } + } + + const uint32_t permissions = lldb::ePermissionsReadable | + lldb::ePermissionsWritable; + + m_core_range_infos.Append( + VMRangeToPermissions::Entry(addr, header.StackSize, permissions)); + + return addr; +} + bool ProcessAIXCore::CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) { @@ -170,6 +197,7 @@ Status ProcessAIXCore::DoLoadCore() { } FileSpec file = m_core_module_sp->GetObjectFile()->GetFileSpec(); + Log *log = GetLog(LLDBLog::Process); if (file) { const size_t header_size = sizeof(AIXCORE::AIXCore64Header); @@ -180,6 +208,9 @@ Status ProcessAIXCore::DoLoadCore() { DataExtractor data(data_sp, lldb::eByteOrderBig, 4); lldb::offset_t data_offset = 0; m_aixcore_header.ParseCoreHeader(data, &data_offset); + lldb::addr_t addr = AddAddressRanges(m_aixcore_header); + if (addr == LLDB_INVALID_ADDRESS) + LLDB_LOGF(log, "ProcessAIXCore: Invalid base address. Stack information will be limited"); auto dyld = static_cast(GetDynamicLoader()); dyld->FillCoreLoaderData(data, m_aixcore_header.LoaderOffset, m_aixcore_header.LoaderSize); @@ -246,7 +277,48 @@ size_t ProcessAIXCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size, } size_t ProcessAIXCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, - Status &error) { return 0; } + Status &error) { + ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); + if (core_objfile == nullptr) + return 0; + // Get the address range + const VMRangeToFileOffset::Entry *address_range = + m_core_aranges.FindEntryThatContains(addr); + if (address_range == nullptr || address_range->GetRangeEnd() < addr) { + error = Status::FromErrorStringWithFormat( + "core file does not contain 0x%" PRIx64, addr); + return 0; + } + + // Convert the address into core file offset + const lldb::addr_t offset = addr - address_range->GetRangeBase(); + const lldb::addr_t file_start = address_range->data.GetRangeBase(); + const lldb::addr_t file_end = address_range->data.GetRangeEnd(); + size_t bytes_to_read = size; // Number of bytes to read from the core file + size_t bytes_copied = 0; // Number of bytes actually read from the core file + // Number of bytes available in the core file from the given address + lldb::addr_t bytes_left = 0; + + // Don't proceed if core file doesn't contain the actual data for this + // address range. + if (file_start == file_end) + return 0; + + // Figure out how many on-disk bytes remain in this segment starting at the + // given offset + if (file_end > file_start + offset) + bytes_left = file_end - (file_start + offset); + + if (bytes_to_read > bytes_left) + bytes_to_read = bytes_left; + + // If there is data available on the core file read it + if (bytes_to_read) + bytes_copied = + core_objfile->CopyData(offset + file_start, bytes_to_read, buf); + + return bytes_copied; +} Status ProcessAIXCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo ®ion_info) { diff --git a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h index 9880c491689ca..ffd9e401ee192 100644 --- a/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h +++ b/lldb/source/Plugins/Process/aix-core/ProcessAIXCore.h @@ -85,11 +85,22 @@ class ProcessAIXCore : public lldb_private::PostMortemProcess { void ParseAIXCoreFile(); + lldb::addr_t AddAddressRanges(AIXCORE::AIXCore64Header header); private: lldb::ModuleSP m_core_module_sp; std::string m_dyld_plugin_name; + typedef lldb_private::Range FileRange; + typedef lldb_private::RangeDataVector + VMRangeToFileOffset; + typedef lldb_private::RangeDataVector + VMRangeToPermissions; + + // Address ranges found in the core + VMRangeToFileOffset m_core_aranges; + VMRangeToPermissions m_core_range_infos; + // True if m_thread_contexts contains valid entries bool m_thread_data_valid = false; AIXCORE::AIXCore64Header m_aixcore_header; >From 96db5e3257436a222ee38049528d682166421fa1 Mon Sep 17 00:00:00 2001 From: Dhruv-Srivastava Date: Wed, 2 Apr 2025 01:46:46 -0500 Subject: [PATCH 46/50] Build fail: SBMutex --- lldb/source/API/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index 0045edf6743d1..2c8f2d583c054 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -83,6 +83,7 @@ add_lldb_library(liblldb STATIC ${option_framework} SBMemoryRegionInfoList.cpp SBModule.cpp SBModuleSpec.cpp + SBMutex.cpp SBPlatform.cpp SBProcess.cpp SBProgress.cpp >From d7a892ef207cde5430021b8705279cc08dc4e0f7 Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Wed, 30 Apr 2025 04:53:28 -0500 Subject: [PATCH 47/50] Added change for step command issue --- .../Plugins/Process/AIX/NativeProcessAIX.cpp | 87 +++++++++++++------ 1 file changed, 61 insertions(+), 26 deletions(-) diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp index 83b8ae5eb3258..ace9e11927bee 100644 --- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp @@ -19,7 +19,7 @@ #include #include #include - +#include #include "NativeThreadAIX.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" //#include "Plugins/Process/Utility/LinuxProcMaps.h" @@ -79,6 +79,7 @@ using namespace lldb_private; using namespace lldb_private::process_aix; using namespace llvm; +typedef std::function)> AIXMapCallback; // Private bits we only need internally. static bool ProcessVmReadvSupported() { @@ -988,13 +989,6 @@ Status NativeProcessAIX::GetMemoryRegionInfo(lldb::addr_t load_addr, for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end(); ++it) { MemoryRegionInfo &proc_entry_info = it->first; - - // Sanity check assumption that /proc/{pid}/maps entries are ascending. - assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) && - "descending /proc/pid/maps entries detected, unexpected"); - prev_base_address = proc_entry_info.GetRange().GetRangeBase(); - UNUSED_IF_ASSERT_DISABLED(prev_base_address); - // If the target address comes before this entry, indicate distance to next // region. if (load_addr < proc_entry_info.GetRange().GetRangeBase()) { @@ -1029,9 +1023,59 @@ Status NativeProcessAIX::GetMemoryRegionInfo(lldb::addr_t load_addr, return error; } +// Parsing the AIX map file /proc/PID/map +// The map file contains an array of prmap structures +// which has all the information like size, startaddress, object name, permissions +bool ParseAIXMapRegions(const char *aix_map, AIXMapCallback const &callback) { + MemoryRegionInfo region; + struct prmap *prmapData = (struct prmap *)aix_map; + struct prmap *entry; + uint32_t perm_flag; + + for(entry = prmapData;!(entry->pr_size == 0 && entry->pr_vaddr == NULL); entry++) { + const char *o_name = aix_map + entry->pr_pathoff; + lldb::addr_t start_address = (lldb::addr_t )entry->pr_vaddr; + lldb::addr_t end_address = start_address + entry->pr_size; + region.GetRange().SetRangeBase(start_address); + region.GetRange().SetRangeEnd(end_address); + region.SetMapped(MemoryRegionInfo::OptionalBool::eYes); + perm_flag = entry->pr_mflags; + + if(perm_flag & MA_READ) + region.SetReadable(MemoryRegionInfo::OptionalBool::eYes); + else + region.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + + if(perm_flag & MA_WRITE) + region.SetWritable(MemoryRegionInfo::OptionalBool::eYes); + else + region.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + + if(perm_flag & MA_EXEC) + region.SetExecutable(MemoryRegionInfo::OptionalBool::eYes); + else + region.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + + if((perm_flag & MA_SLIBTEXT) || (perm_flag & MA_SLIBDATA)) + region.SetShared(MemoryRegionInfo::OptionalBool::eYes); + else if ((perm_flag & MA_PLIBTEXT) || (perm_flag & MA_PLIBDATA)) + region.SetShared(MemoryRegionInfo::OptionalBool::eNo); + else + region.SetShared(MemoryRegionInfo::OptionalBool::eDontKnow); + + if(o_name) + region.SetName(o_name); + + callback(region); + region.Clear(); + } + + return true; +} + + Status NativeProcessAIX::PopulateMemoryRegionCache() { Log *log = GetLog(POSIXLog::Process); - // If our cache is empty, pull the latest. There should always be at least // one memory region if memory region handling is supported. if (!m_mem_region_cache.empty()) { @@ -1041,7 +1085,7 @@ Status NativeProcessAIX::PopulateMemoryRegionCache() { } Status Result; -#if 0 + AIXMapCallback callback = [&](llvm::Expected Info) { if (Info) { FileSpec file_spec(Info->GetName().GetCString()); @@ -1050,26 +1094,17 @@ Status NativeProcessAIX::PopulateMemoryRegionCache() { return true; } - Result = Info.takeError(); + Result = Status::FromError(Info.takeError()); m_supports_mem_region = LazyBool::eLazyBoolNo; LLDB_LOG(log, "failed to parse proc maps: {0}", Result); return false; }; - // AIX kernel since 2.6.14 has /proc/{pid}/smaps - // if CONFIG_PROC_PAGE_MONITOR is enabled - auto BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "smaps"); - if (BufferOrError) - ParseAIXSMapRegions(BufferOrError.get()->getBuffer(), callback); - else { - BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "maps"); - if (!BufferOrError) { - m_supports_mem_region = LazyBool::eLazyBoolNo; - return BufferOrError.getError(); - } - - ParseAIXMapRegions(BufferOrError.get()->getBuffer(), callback); - } + auto BufferOrError = getProcFile(GetID(), "map"); + if (BufferOrError) { + std::unique_ptr MapBuffer = std::move(*BufferOrError); + ParseAIXMapRegions(MapBuffer->getBufferStart(), callback); + } if (Result.Fail()) return Result; @@ -1090,7 +1125,7 @@ Status NativeProcessAIX::PopulateMemoryRegionCache() { // We support memory retrieval, remember that. m_supports_mem_region = LazyBool::eLazyBoolYes; -#endif + return Status(); } >From 09e392a16dba25a5a8ddccf7893289a0a8798a3b Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Wed, 14 May 2025 00:52:06 -0500 Subject: [PATCH 48/50] Removing netbsd license dependency --- lldb/source/Host/common/Host.cpp | 165 ++----------------------------- 1 file changed, 7 insertions(+), 158 deletions(-) diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 6cf1112511c3f..7444163366fe5 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -349,168 +349,16 @@ bool Host::ResolveExecutableInBundle(FileSpec &file) { return false; } #include extern char **p_xargv; -/* Fix missing Dl_info & dladdr in AIX - * The code is taken from netbsd.org (src/crypto/external/bsd/openssl/dist/crypto/dso/dso_dlfcn.c) - * except strlcpy & strlcat (those are taken from openbsd.org (src/lib/libc/string)) - */ -/*- - * See IBM's AIX Version 7.2, Technical Reference: - * Base Operating System and Extensions, Volume 1 and 2 - * https://www.ibm.com/support/knowledgecenter/ssw_aix_72/com.ibm.aix.base/technicalreferences.htm - */ -#include -#include - -/* strlcpy: - * Copy string src to buffer dst of size dsize. At most dsize-1 - * chars will be copied. Always NUL terminates (unless dsize == 0). - * Returns strlen(src); if retval >= dsize, truncation occurred. - */ -size_t strlcpy(char *dst, const char *src, size_t dsize) -{ - const char *osrc = src; - size_t nleft = dsize; - - /* Copy as many bytes as will fit. */ - if (nleft != 0) { - while (--nleft != 0) { - if ((*dst++ = *src++) == '\0') { - break; - } - } - } - - /* Not enough room in dst, add NUL and traverse rest of src. */ - if (nleft == 0) { - if (dsize != 0) { - *dst = '\0'; /* NUL-terminate dst */ - } - while (*src++) { - ; - } - } - - return src - osrc - 1; /* count does not include NUL */ -} - -/* strlcat: - * Appends src to string dst of size dsize (unlike strncat, dsize is the - * full size of dst, not space left). At most dsize-1 characters - * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). - * Returns strlen(src) + MIN(dsize, strlen(initial dst)). - * If retval >= dsize, truncation occurred. - */ -size_t strlcat(char *dst, const char *src, size_t dsize) -{ - const char *odst = dst; - const char *osrc = src; - size_t n = dsize; - size_t dlen; - - /* Find the end of dst and adjust bytes left but don't go past end. */ - while (n-- != 0 && *dst != '\0') { - dst++; - } - dlen = dst - odst; - n = dsize - dlen; - - if (n-- == 0) { - return dlen + strlen(src); - } - while (*src != '\0') { - if (n != 0) { - *dst++ = *src; - n--; - } - src++; - } - *dst = '\0'; - - return dlen + src - osrc; /* count does not include NUL */ -} - -/* ~ 64 * (sizeof(struct ld_info) + _XOPEN_PATH_MAX + _XOPEN_NAME_MAX) */ -# define DLFCN_LDINFO_SIZE 86976 -typedef struct Dl_info { - const char *dli_fname; -} Dl_info; -/* - * This dladdr()-implementation will also find the ptrgl (Pointer Glue) virtual - * address of a function, which is just located in the DATA segment instead of - * the TEXT segment. - */ -static int dladdr(const void *ptr, Dl_info *dl) -{ - uintptr_t addr = (uintptr_t)ptr; - struct ld_info *ldinfos; - struct ld_info *next_ldi; - struct ld_info *this_ldi; - - if ((ldinfos = (struct ld_info *)malloc(DLFCN_LDINFO_SIZE)) == NULL) { - dl->dli_fname = NULL; - return 0; - } - - if ((loadquery(L_GETINFO, (void *)ldinfos, DLFCN_LDINFO_SIZE)) < 0) { - /*- - * Error handling is done through errno and dlerror() reading errno: - * ENOMEM (ldinfos buffer is too small), - * EINVAL (invalid flags), - * EFAULT (invalid ldinfos ptr) - */ - free((void *)ldinfos); - dl->dli_fname = NULL; - return 0; - } - next_ldi = ldinfos; - - do { - this_ldi = next_ldi; - if (((addr >= (uintptr_t)this_ldi->ldinfo_textorg) - && (addr < ((uintptr_t)this_ldi->ldinfo_textorg + - this_ldi->ldinfo_textsize))) - || ((addr >= (uintptr_t)this_ldi->ldinfo_dataorg) - && (addr < ((uintptr_t)this_ldi->ldinfo_dataorg + - this_ldi->ldinfo_datasize)))) { - char *buffer = NULL; - char *member = NULL; - size_t buffer_sz; - size_t member_len; - - buffer_sz = strlen(this_ldi->ldinfo_filename) + 1; - member = this_ldi->ldinfo_filename + buffer_sz; - if ((member_len = strlen(member)) > 0) { - buffer_sz += 1 + member_len + 1; - } - if ((buffer = (char *)malloc(buffer_sz)) != NULL) { - strlcpy(buffer, this_ldi->ldinfo_filename, buffer_sz); - if (member_len > 0) { - /* - * Need to respect a possible member name and not just - * returning the path name in this case. See docs: - * sys/ldr.h, loadquery() and dlopen()/RTLD_MEMBER. - */ - strlcat(buffer, "(", buffer_sz); - strlcat(buffer, member, buffer_sz); - strlcat(buffer, ")", buffer_sz); - } - dl->dli_fname = buffer; - } - break; - } else { - next_ldi = (struct ld_info *)((uintptr_t)this_ldi + - this_ldi->ldinfo_next); - } - } while (this_ldi->ldinfo_next); - free((void *)ldinfos); - return dl->dli_fname != NULL; -} - #endif FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSpec module_filespec; #ifdef _AIX + // TODO: As the current AIX LLDB is static, we don't need dladdr which is + // only for shared library, Below is the hack to find the module name + // for static LLDB + // FIXME: If LLDB is later built as shared library, we have to find the way simillar to dladdr + // since AIX does not support the dladdr API. if (host_addr == reinterpret_cast(HostInfoBase::ComputeSharedLibraryDirectory)) { // FIXME: AIX dladdr return "lldb" for this case if (p_xargv[0]) { @@ -519,7 +367,7 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { return module_filespec; } } -#endif +#else #if !defined(__ANDROID__) Dl_info info; if (::dladdr(host_addr, &info)) { @@ -528,6 +376,7 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { FileSystem::Instance().Resolve(module_filespec); } } +#endif #endif return module_filespec; } >From b158b8788fa6bf0e13d02373ce9de0d62a4a6aba Mon Sep 17 00:00:00 2001 From: HemangGadhavi Date: Fri, 16 May 2025 00:51:25 -0500 Subject: [PATCH 49/50] Removed netbsd license files --- lldb/NOTICE.TXT | 7 - .../source/Host/common/LICENSE.aix-netbsd.txt | 125 ------------------ 2 files changed, 132 deletions(-) delete mode 100644 lldb/NOTICE.TXT delete mode 100644 lldb/source/Host/common/LICENSE.aix-netbsd.txt diff --git a/lldb/NOTICE.TXT b/lldb/NOTICE.TXT deleted file mode 100644 index d814272967476..0000000000000 --- a/lldb/NOTICE.TXT +++ /dev/null @@ -1,7 +0,0 @@ - -This product contains small piece of code to support AIX, taken from netbsd. - - * LICENSE: - * lldb/source/Host/common/LICENSE.aix-netbsd.txt (OpenSSL License) - * HOMEPAGE: - * https://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/crypto/external/bsd/openssl/dist diff --git a/lldb/source/Host/common/LICENSE.aix-netbsd.txt b/lldb/source/Host/common/LICENSE.aix-netbsd.txt deleted file mode 100644 index 9601ab43575f9..0000000000000 --- a/lldb/source/Host/common/LICENSE.aix-netbsd.txt +++ /dev/null @@ -1,125 +0,0 @@ - - LICENSE ISSUES - ============== - - The OpenSSL toolkit stays under a double license, i.e. both the conditions of - the OpenSSL License and the original SSLeay license apply to the toolkit. - See below for the actual license texts. - - OpenSSL License - --------------- - -/* ==================================================================== - * Copyright (c) 1998-2019 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core at openssl.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.openssl.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay at cryptsoft.com). This product includes software written by Tim - * Hudson (tjh at cryptsoft.com). - * - */ - - Original SSLeay License - ----------------------- - -/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay at cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh at cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay at cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh at cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ - >From 8dd3bd995bf08e50d89a21f7c3bf227ed856798a Mon Sep 17 00:00:00 2001 From: Dhruv Srivastava Date: Fri, 16 May 2025 18:05:57 +0530 Subject: [PATCH 50/50] Fix for GetName() (#61) Need to access process/main-thread name from psinfo on aix rather than comm on linux. (0) root @ unobosdev002: /home/dhruv/dio_fs/LLDB/build-lldb # bin/lldb ../tests/1 (lldb) target create "../tests/1" Current executable set to '/home/dhruv/dio_fs/LLDB/tests/1' (powerpc64). (lldb) b main Breakpoint 1: where = 1`main + 8 at 1.c:3, address = 0x0000000100000928 (lldb) r Process 44433678 launched: '/home/dhruv/dio_fs/LLDB/tests/1' (powerpc64) Process 44433678 stopped * thread #1, name = '1', stop reason = breakpoint 1.1 frame #0: 0x0000000100000928 1`main at 1.c:3 1 int main() 2 { -> 3 int x = 10; 4 x++; 5 return x; 6 } (lldb) thread info thread #1: tid = 0x2a6010e, 0x0000000100000928 1`main at 1.c:3, name = '1', stop reason = breakpoint 1.1 --- lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp index bb14b6ab4a05e..337caa7c750e8 100644 --- a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp +++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp @@ -24,7 +24,8 @@ #include "llvm/ADT/SmallString.h" #include "Plugins/Process/POSIX/CrashReason.h" - +#include +#include #include #include #include @@ -102,11 +103,15 @@ NativeThreadAIX::NativeThreadAIX(NativeProcessAIX &process, std::string NativeThreadAIX::GetName() { NativeProcessAIX &process = GetProcess(); - - auto BufferOrError = getProcFile(process.GetID(), GetID(), "comm"); + auto BufferOrError = getProcFile(process.GetID(), "psinfo"); if (!BufferOrError) return ""; - return std::string(BufferOrError.get()->getBuffer().rtrim('\n')); + auto &Buffer = *BufferOrError; + if (Buffer->getBufferSize() < sizeof(psinfo_t)) + return ""; + const psinfo_t *psinfo = + reinterpret_cast(Buffer->getBufferStart()); + return std::string(psinfo->pr_fname); } lldb::StateType NativeThreadAIX::GetState() { return m_state; } From lldb-commits at lists.llvm.org Fri May 16 07:11:39 2025 From: lldb-commits at lists.llvm.org (Michael Buch via lldb-commits) Date: Fri, 16 May 2025 07:11:39 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][DataFormatters] Adjust retrieval of unordered_map element type (PR #140256) Message-ID: https://github.com/Michael137 created https://github.com/llvm/llvm-project/pull/140256 A user ran into an issue where the libc++ std::unordered_map` formatter fails because it can't deduce the `element_type`. That happens because the `node_type` is a forwad declaration. And, in fact, dsymutil stripped the definition for `std::__1::__hash_node<...>` for a particular instantiation. While I'm still unclear whether this is a dsymutil bug, this patch works around said issue by getting the element type from the `__table_` member. Drive-by: - Set the `m_element_type` in `Update`, which is where the other members are initialized I don't have a reduced example of this unfortunately. But the crux of the issue is that `std::__1::__hash_node<...>` only has a forward declaration in the dsym. Then trying to call `GetTypeTemplateArgument` on that `CompilerType` fails. And even if the definition was present in the dsym it seems like we're stopped in a context where the CU only had a forward declaration DIE for that type and the `node_type` never ends up being completed with the definition that lives in another CU. rdar://150813798 >From f1b931c5b80abb623ff98ef5e55aa662765de50e Mon Sep 17 00:00:00 2001 From: Michael Buch Date: Fri, 16 May 2025 11:17:32 +0100 Subject: [PATCH] [lldb][DataFormatters] Adjust retrieval of unordered_map element type A user ran into an issue where the libc++ std::unordered_map` formatter fails because it can't deduce the `element_type`. That happens because the `node_type` is a forwad declaration. And, in fact, dsymutil stripped the definition for `std::__1::__hash_node<...>` for a particular instantiation. While I'm still unclear whether this is a dsymutil bug, this patch works around said issue by getting the element type from the `__table_` member. Drive-by: - Set the `m_element_type` in `Update`, which is where the other members are initialized I don't have a reduced example of this unfortunately. But the crux of the issue is that `std::__1::__hash_node<...>` only has a forward declaration in the dsym. Then trying to call `GetTypeTemplateArgument` on that `CompilerType` fails. And even if the definition was present in the dsym it seems like we're stopped in a context where the CU only had a forward declaration DIE for that type and the `node_type` never ends up being completed with the definition that lives in another CU. rdar://150813798 --- .../Language/CPlusPlus/LibCxxUnorderedMap.cpp | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp index aad387137ea50..642723dd91132 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp @@ -44,7 +44,7 @@ class LibcxxStdUnorderedMapSyntheticFrontEnd private: CompilerType GetNodeType(); - CompilerType GetElementType(CompilerType node_type); + CompilerType GetElementType(CompilerType table_type); llvm::Expected CalculateNumChildrenImpl(ValueObject &table); CompilerType m_element_type; @@ -98,8 +98,8 @@ static bool isUnorderedMap(ConstString type_name) { } CompilerType lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: - GetElementType(CompilerType node_type) { - CompilerType element_type = node_type.GetTypeTemplateArgument(0); + GetElementType(CompilerType table_type) { + auto element_type = table_type.GetTypedefedType().GetTypeTemplateArgument(0); // This synthetic provider is used for both unordered_(multi)map and // unordered_(multi)set. For unordered_map, the element type has an @@ -114,7 +114,7 @@ CompilerType lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: element_type.GetFieldAtIndex(0, name, nullptr, nullptr, nullptr); CompilerType actual_type = field_type.GetTypedefedType(); if (isStdTemplate(actual_type.GetTypeName(), "pair")) - element_type = actual_type; + return actual_type; } return element_type; @@ -161,13 +161,6 @@ lldb::ValueObjectSP lldb_private::formatters:: ValueObjectSP value_sp = node_sp->GetChildMemberWithName("__value_"); ValueObjectSP hash_sp = node_sp->GetChildMemberWithName("__hash_"); if (!hash_sp || !value_sp) { - if (!m_element_type) { - m_node_type = GetNodeType(); - if (!m_node_type) - return nullptr; - - m_element_type = GetElementType(m_node_type); - } node_sp = m_next_element->Cast(m_node_type.GetPointerType()) ->Dereference(error); if (!node_sp || error.Fail()) @@ -271,6 +264,14 @@ lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::Update() { if (!table_sp) return lldb::ChildCacheState::eRefetch; + m_node_type = GetNodeType(); + if (!m_node_type) + return lldb::ChildCacheState::eRefetch; + + m_element_type = GetElementType(table_sp->GetCompilerType()); + if (!m_element_type) + return lldb::ChildCacheState::eRefetch; + ValueObjectSP tree_sp = GetTreePointer(*table_sp); if (!tree_sp) return lldb::ChildCacheState::eRefetch; From lldb-commits at lists.llvm.org Fri May 16 07:12:18 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 07:12:18 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][DataFormatters] Adjust retrieval of unordered_map element type (PR #140256) In-Reply-To: Message-ID: <682747c2.170a0220.22ecea.9aef@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Michael Buch (Michael137)
Changes A user ran into an issue where the libc++ std::unordered_map` formatter fails because it can't deduce the `element_type`. That happens because the `node_type` is a forwad declaration. And, in fact, dsymutil stripped the definition for `std::__1::__hash_node<...>` for a particular instantiation. While I'm still unclear whether this is a dsymutil bug, this patch works around said issue by getting the element type from the `__table_` member. Drive-by: - Set the `m_element_type` in `Update`, which is where the other members are initialized I don't have a reduced example of this unfortunately. But the crux of the issue is that `std::__1::__hash_node<...>` only has a forward declaration in the dsym. Then trying to call `GetTypeTemplateArgument` on that `CompilerType` fails. And even if the definition was present in the dsym it seems like we're stopped in a context where the CU only had a forward declaration DIE for that type and the `node_type` never ends up being completed with the definition that lives in another CU. rdar://150813798 --- Full diff: https://github.com/llvm/llvm-project/pull/140256.diff 1 Files Affected: - (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp (+12-11) ``````````diff diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp index aad387137ea50..642723dd91132 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp @@ -44,7 +44,7 @@ class LibcxxStdUnorderedMapSyntheticFrontEnd private: CompilerType GetNodeType(); - CompilerType GetElementType(CompilerType node_type); + CompilerType GetElementType(CompilerType table_type); llvm::Expected CalculateNumChildrenImpl(ValueObject &table); CompilerType m_element_type; @@ -98,8 +98,8 @@ static bool isUnorderedMap(ConstString type_name) { } CompilerType lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: - GetElementType(CompilerType node_type) { - CompilerType element_type = node_type.GetTypeTemplateArgument(0); + GetElementType(CompilerType table_type) { + auto element_type = table_type.GetTypedefedType().GetTypeTemplateArgument(0); // This synthetic provider is used for both unordered_(multi)map and // unordered_(multi)set. For unordered_map, the element type has an @@ -114,7 +114,7 @@ CompilerType lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: element_type.GetFieldAtIndex(0, name, nullptr, nullptr, nullptr); CompilerType actual_type = field_type.GetTypedefedType(); if (isStdTemplate(actual_type.GetTypeName(), "pair")) - element_type = actual_type; + return actual_type; } return element_type; @@ -161,13 +161,6 @@ lldb::ValueObjectSP lldb_private::formatters:: ValueObjectSP value_sp = node_sp->GetChildMemberWithName("__value_"); ValueObjectSP hash_sp = node_sp->GetChildMemberWithName("__hash_"); if (!hash_sp || !value_sp) { - if (!m_element_type) { - m_node_type = GetNodeType(); - if (!m_node_type) - return nullptr; - - m_element_type = GetElementType(m_node_type); - } node_sp = m_next_element->Cast(m_node_type.GetPointerType()) ->Dereference(error); if (!node_sp || error.Fail()) @@ -271,6 +264,14 @@ lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::Update() { if (!table_sp) return lldb::ChildCacheState::eRefetch; + m_node_type = GetNodeType(); + if (!m_node_type) + return lldb::ChildCacheState::eRefetch; + + m_element_type = GetElementType(table_sp->GetCompilerType()); + if (!m_element_type) + return lldb::ChildCacheState::eRefetch; + ValueObjectSP tree_sp = GetTreePointer(*table_sp); if (!tree_sp) return lldb::ChildCacheState::eRefetch; ``````````
https://github.com/llvm/llvm-project/pull/140256 From lldb-commits at lists.llvm.org Fri May 16 07:44:52 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Fri, 16 May 2025 07:44:52 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Basic implementation of a deferred request. (PR #140260) Message-ID: https://github.com/da-viper created https://github.com/llvm/llvm-project/pull/140260 Fixes #140154 Basic implementation of defering requests. It no longer depends on a white list of request, So if there is any future breakpoint types added to the DAP specification. it will not break existing binary. It can further be extended to defer depending of the request arguments. Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Fri May 16 07:45:34 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 07:45:34 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Basic implementation of a deferred request. (PR #140260) In-Reply-To: Message-ID: <68274f8e.170a0220.152f6e.e117@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Ebuka Ezike (da-viper)
Changes Fixes #140154 Basic implementation of defering requests. It no longer depends on a white list of request, So if there is any future breakpoint types added to the DAP specification. it will not break existing binary. It can further be extended to defer depending of the request arguments. --- Full diff: https://github.com/llvm/llvm-project/pull/140260.diff 6 Files Affected: - (modified) lldb/tools/lldb-dap/DAP.cpp (+8-11) - (modified) lldb/tools/lldb-dap/DAP.h (+1-1) - (modified) lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp (+4) - (modified) lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp (+4) - (modified) lldb/tools/lldb-dap/Handler/RequestHandler.cpp (+6-2) - (modified) lldb/tools/lldb-dap/Handler/RequestHandler.h (+7-1) ``````````diff diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 56a0c38b00037..a1f738eef5fcc 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -726,7 +726,7 @@ void DAP::SetTarget(const lldb::SBTarget target) { } } -bool DAP::HandleObject(const Message &M) { +bool DAP::HandleObject(const Message &M, bool &defer) { TelemetryDispatcher dispatcher(&debugger); dispatcher.Set("client_name", transport.GetClientName().str()); if (const auto *req = std::get_if(&M)) { @@ -748,7 +748,7 @@ bool DAP::HandleObject(const Message &M) { dispatcher.Set("client_data", llvm::Twine("request_command:", req->command).str()); if (handler_pos != request_handlers.end()) { - handler_pos->second->Run(*req); + defer = handler_pos->second->Run(*req); return true; // Success } @@ -918,17 +918,11 @@ llvm::Error DAP::Loop() { // The launch sequence is special and we need to carefully handle // packets in the right order. Until we've handled configurationDone, - bool add_to_pending_queue = false; - if (const protocol::Request *req = std::get_if(&*next)) { llvm::StringRef command = req->command; if (command == "disconnect") disconnecting = true; - if (!configuration_done) - add_to_pending_queue = - command != "initialize" && command != "configurationDone" && - command != "disconnect" && !command.ends_with("Breakpoints"); } const std::optional cancel_args = @@ -956,8 +950,7 @@ llvm::Error DAP::Loop() { { std::lock_guard guard(m_queue_mutex); - auto &queue = add_to_pending_queue ? m_pending_queue : m_queue; - queue.push_back(std::move(*next)); + m_queue.push_back(std::move(*next)); } m_queue_cv.notify_one(); } @@ -984,9 +977,13 @@ llvm::Error DAP::Loop() { // Unlock while we're processing the event. lock.unlock(); - if (!HandleObject(next)) + bool defer_message = false; + if (!HandleObject(next, defer_message)) return llvm::createStringError(llvm::inconvertibleErrorCode(), "unhandled packet"); + if (defer_message) { + m_pending_queue.push_back(next); + } } return ToError(queue_reader.get()); diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c1a1130b1e59f..a77a1561c5db2 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -339,7 +339,7 @@ struct DAP { /// listeing for its breakpoint events. void SetTarget(const lldb::SBTarget target); - bool HandleObject(const protocol::Message &M); + bool HandleObject(const protocol::Message &M, bool &defer); /// Disconnect the DAP session. llvm::Error Disconnect(); diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp index 0293ffbd0c922..96fb7682f240a 100644 --- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp @@ -160,4 +160,8 @@ void AttachRequestHandler::PostRun() const { dap.target.GetProcess().Continue(); } +bool AttachRequestHandler::DeferRequest() const { + return !dap.configuration_done; +} + } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp index 22d1a090187d8..e4163827ac69c 100644 --- a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp @@ -88,4 +88,8 @@ void LaunchRequestHandler::PostRun() const { dap.target.GetProcess().Continue(); } +bool LaunchRequestHandler::DeferRequest() const { + return !dap.configuration_done; +} + } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp index 93bc80a38e29d..074a76c928240 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp @@ -126,7 +126,7 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) { error.GetCString()); } -void BaseRequestHandler::Run(const Request &request) { +bool BaseRequestHandler::Run(const Request &request) { // If this request was cancelled, send a cancelled response. if (dap.IsCancelled(request)) { Response cancelled{/*request_seq=*/request.seq, @@ -135,12 +135,15 @@ void BaseRequestHandler::Run(const Request &request) { /*message=*/eResponseMessageCancelled, /*body=*/std::nullopt}; dap.Send(cancelled); - return; + return false; } lldb::SBMutex lock = dap.GetAPIMutex(); std::lock_guard guard(lock); + if (DeferRequest()) { + return true; + } // FIXME: After all the requests have migrated from LegacyRequestHandler > // RequestHandler<> we should be able to move this into // RequestHandler<>::operator(). @@ -149,6 +152,7 @@ void BaseRequestHandler::Run(const Request &request) { // FIXME: After all the requests have migrated from LegacyRequestHandler > // RequestHandler<> we should be able to check `debugger.InterruptRequest` and // mark the response as cancelled. + return false; } llvm::Error BaseRequestHandler::LaunchProcess( diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index eaebaf6619bbd..bac193e6ce59e 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -46,7 +46,11 @@ class BaseRequestHandler { virtual ~BaseRequestHandler() = default; - void Run(const protocol::Request &); + /// Return `true` if the request should be deferred. + [[nodiscard]] + bool Run(const protocol::Request &); + + virtual bool DeferRequest() const { return false; }; virtual void operator()(const protocol::Request &request) const = 0; @@ -203,6 +207,7 @@ class AttachRequestHandler static llvm::StringLiteral GetCommand() { return "attach"; } llvm::Error Run(const protocol::AttachRequestArguments &args) const override; void PostRun() const override; + bool DeferRequest() const override; }; class BreakpointLocationsRequestHandler @@ -302,6 +307,7 @@ class LaunchRequestHandler llvm::Error Run(const protocol::LaunchRequestArguments &arguments) const override; void PostRun() const override; + bool DeferRequest() const override; }; class RestartRequestHandler : public LegacyRequestHandler { ``````````
https://github.com/llvm/llvm-project/pull/140260 From lldb-commits at lists.llvm.org Fri May 16 07:46:10 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 07:46:10 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Add support for displaying `__float128` variables (PR #98369) In-Reply-To: Message-ID: <68274fb2.170a0220.16df54.e348@mx.google.com> https://github.com/beetrees updated https://github.com/llvm/llvm-project/pull/98369 >From b96a6a1b6ef96702461a6cf32b361847c318bf8a Mon Sep 17 00:00:00 2001 From: beetrees Date: Wed, 10 Jul 2024 18:49:45 +0100 Subject: [PATCH] [lldb] Add support for displaying `__float128` variables --- lldb/bindings/python/python-extensions.swig | 1 + lldb/docs/python_api_enums.rst | 2 ++ lldb/include/lldb/Symbol/TypeSystem.h | 3 ++- lldb/include/lldb/lldb-enumerations.h | 7 +++++- lldb/source/Commands/CommandObjectMemory.cpp | 2 ++ lldb/source/Core/DumpDataExtractor.cpp | 14 ++++++++--- lldb/source/DataFormatters/FormatManager.cpp | 1 + lldb/source/DataFormatters/VectorType.cpp | 2 ++ .../TypeSystem/Clang/TypeSystemClang.cpp | 25 ++++++++++++++++++- .../TypeSystem/Clang/TypeSystemClang.h | 3 ++- lldb/source/ValueObject/ValueObject.cpp | 5 ++-- lldb/unittests/Core/DumpDataExtractorTest.cpp | 6 +++++ lldb/unittests/Symbol/TestTypeSystemClang.cpp | 2 ++ 13 files changed, 63 insertions(+), 10 deletions(-) diff --git a/lldb/bindings/python/python-extensions.swig b/lldb/bindings/python/python-extensions.swig index 4ba1607c70909..40fa76872ee96 100644 --- a/lldb/bindings/python/python-extensions.swig +++ b/lldb/bindings/python/python-extensions.swig @@ -594,6 +594,7 @@ def is_numeric_type(basic_type): if basic_type == eBasicTypeFloat: return (True,True) if basic_type == eBasicTypeDouble: return (True,True) if basic_type == eBasicTypeLongDouble: return (True,True) + if basic_type == eBasicTypeFloat128: return (True,True) if basic_type == eBasicTypeFloatComplex: return (True,True) if basic_type == eBasicTypeDoubleComplex: return (True,True) if basic_type == eBasicTypeLongDoubleComplex: return (True,True) diff --git a/lldb/docs/python_api_enums.rst b/lldb/docs/python_api_enums.rst index b6a2497ea878e..a43a47b8d6985 100644 --- a/lldb/docs/python_api_enums.rst +++ b/lldb/docs/python_api_enums.rst @@ -321,6 +321,7 @@ Format .. py:data:: eFormatInstruction .. py:data:: eFormatVoid .. py:data:: eFormatUnicode8 +.. py:data:: eFormatFloat128 .. _DescriptionLevel: @@ -1045,6 +1046,7 @@ BasicType .. py:data:: eBasicTypeObjCSel .. py:data:: eBasicTypeNullPtr .. py:data:: eBasicTypeOther +.. py:data:: eBasicTypeFloat128 .. _TraceType: diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h index df87fea32b72a..636bea5adcf83 100644 --- a/lldb/include/lldb/Symbol/TypeSystem.h +++ b/lldb/include/lldb/Symbol/TypeSystem.h @@ -310,7 +310,8 @@ class TypeSystem : public PluginInterface, // Exploring the type - virtual const llvm::fltSemantics &GetFloatTypeSemantics(size_t byte_size) = 0; + virtual const llvm::fltSemantics & + GetFloatTypeSemantics(size_t byte_size, bool prefer_float128) = 0; virtual llvm::Expected GetBitSize(lldb::opaque_compiler_type_t type, diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h index 6d10cc8bcffcb..311a18b850e0a 100644 --- a/lldb/include/lldb/lldb-enumerations.h +++ b/lldb/include/lldb/lldb-enumerations.h @@ -203,6 +203,10 @@ enum Format { eFormatInstruction, ///< Disassemble an opcode eFormatVoid, ///< Do not print this eFormatUnicode8, + eFormatFloat128, ///< Disambiguate between 128-bit `long double` (which uses + ///< `eFormatFloat`) and `__float128` (which uses + ///< `eFormatFloat128`). If the value being formatted is not + ///< 128 bits, then this is identical to `eFormatFloat`. kNumFormats }; @@ -837,7 +841,8 @@ enum BasicType { eBasicTypeObjCClass, eBasicTypeObjCSel, eBasicTypeNullPtr, - eBasicTypeOther + eBasicTypeOther, + eBasicTypeFloat128 }; /// Deprecated diff --git a/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp index 7140333bb3cde..5ccd4be7741e6 100644 --- a/lldb/source/Commands/CommandObjectMemory.cpp +++ b/lldb/source/Commands/CommandObjectMemory.cpp @@ -156,6 +156,7 @@ class OptionGroupReadMemory : public OptionGroup { case eFormatBinary: case eFormatFloat: + case eFormatFloat128: case eFormatOctal: case eFormatDecimal: case eFormatEnum: @@ -1330,6 +1331,7 @@ class CommandObjectMemoryWrite : public CommandObjectParsed { switch (m_format_options.GetFormat()) { case kNumFormats: case eFormatFloat: // TODO: add support for floats soon + case eFormatFloat128: case eFormatCharPrintable: case eFormatBytesWithASCII: case eFormatComplex: diff --git a/lldb/source/Core/DumpDataExtractor.cpp b/lldb/source/Core/DumpDataExtractor.cpp index 72140736d8877..137a54d7aab29 100644 --- a/lldb/source/Core/DumpDataExtractor.cpp +++ b/lldb/source/Core/DumpDataExtractor.cpp @@ -318,14 +318,15 @@ static void printMemoryTags(const DataExtractor &DE, Stream *s, } static const llvm::fltSemantics &GetFloatSemantics(const TargetSP &target_sp, - size_t byte_size) { + size_t byte_size, + bool prefer_float128) { if (target_sp) { auto type_system_or_err = target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC); if (!type_system_or_err) llvm::consumeError(type_system_or_err.takeError()); else if (auto ts = *type_system_or_err) - return ts->GetFloatTypeSemantics(byte_size); + return ts->GetFloatTypeSemantics(byte_size, prefer_float128); } // No target, just make a reasonable guess switch(byte_size) { @@ -335,6 +336,10 @@ static const llvm::fltSemantics &GetFloatSemantics(const TargetSP &target_sp, return llvm::APFloat::IEEEsingle(); case 8: return llvm::APFloat::IEEEdouble(); + case 16: + if (prefer_float128) { + return llvm::APFloat::IEEEquad(); + } } return llvm::APFloat::Bogus(); } @@ -653,6 +658,7 @@ lldb::offset_t lldb_private::DumpDataExtractor( } } break; + case eFormatFloat128: case eFormatFloat: { TargetSP target_sp; if (exe_scope) @@ -665,8 +671,8 @@ lldb::offset_t lldb_private::DumpDataExtractor( // Show full precision when printing float values const unsigned format_precision = 0; - const llvm::fltSemantics &semantics = - GetFloatSemantics(target_sp, item_byte_size); + const llvm::fltSemantics &semantics = GetFloatSemantics( + target_sp, item_byte_size, item_format == eFormatFloat128); // Recalculate the byte size in case of a difference. This is possible // when item_byte_size is 16 (128-bit), because you could get back the diff --git a/lldb/source/DataFormatters/FormatManager.cpp b/lldb/source/DataFormatters/FormatManager.cpp index 3b891cecb1c8b..6ff4948eec34a 100644 --- a/lldb/source/DataFormatters/FormatManager.cpp +++ b/lldb/source/DataFormatters/FormatManager.cpp @@ -72,6 +72,7 @@ static constexpr FormatInfo g_format_infos[] = { {eFormatInstruction, 'i', "instruction"}, {eFormatVoid, 'v', "void"}, {eFormatUnicode8, 'u', "unicode8"}, + {eFormatFloat128, '\0', "float128"}, }; static_assert((sizeof(g_format_infos) / sizeof(g_format_infos[0])) == diff --git a/lldb/source/DataFormatters/VectorType.cpp b/lldb/source/DataFormatters/VectorType.cpp index eab2612d1e941..2cea366c44adf 100644 --- a/lldb/source/DataFormatters/VectorType.cpp +++ b/lldb/source/DataFormatters/VectorType.cpp @@ -55,6 +55,8 @@ static CompilerType GetCompilerTypeForFormat(lldb::Format format, case lldb::eFormatFloat: return type_system->GetBasicTypeFromAST(lldb::eBasicTypeFloat); + case lldb::eFormatFloat128: + return type_system->GetBasicTypeFromAST(lldb::eBasicTypeFloat128); case lldb::eFormatHex: case lldb::eFormatHexUppercase: diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 1a2b3d4133e51..969c27a0abc18 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -809,6 +809,8 @@ TypeSystemClang::GetBuiltinTypeForEncodingAndBitSize(Encoding encoding, return GetType(ast.LongDoubleTy); if (QualTypeMatchesBitSize(bit_size, ast, ast.HalfTy)) return GetType(ast.HalfTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.Float128Ty)) + return GetType(ast.Float128Ty); break; case eEncodingVector: @@ -970,6 +972,13 @@ CompilerType TypeSystemClang::GetBuiltinTypeForDWARFEncodingAndBitSize( if (type_name == "long double" && QualTypeMatchesBitSize(bit_size, ast, ast.LongDoubleTy)) return GetType(ast.LongDoubleTy); + // As Rust currently uses `TypeSystemClang`, match `f128` here as well so it + // doesn't get misinterpreted as `long double` on targets where they are + // the same size but different formats. + if ((type_name == "__float128" || type_name == "_Float128" || + type_name == "f128") && + QualTypeMatchesBitSize(bit_size, ast, ast.Float128Ty)) + return GetType(ast.Float128Ty); // Fall back to not requiring a name match if (QualTypeMatchesBitSize(bit_size, ast, ast.FloatTy)) return GetType(ast.FloatTy); @@ -979,6 +988,8 @@ CompilerType TypeSystemClang::GetBuiltinTypeForDWARFEncodingAndBitSize( return GetType(ast.LongDoubleTy); if (QualTypeMatchesBitSize(bit_size, ast, ast.HalfTy)) return GetType(ast.HalfTy); + if (QualTypeMatchesBitSize(bit_size, ast, ast.Float128Ty)) + return GetType(ast.Float128Ty); break; case DW_ATE_signed: @@ -2068,6 +2079,8 @@ TypeSystemClang::GetOpaqueCompilerType(clang::ASTContext *ast, return ast->DoubleTy.getAsOpaquePtr(); case eBasicTypeLongDouble: return ast->LongDoubleTy.getAsOpaquePtr(); + case eBasicTypeFloat128: + return ast->Float128Ty.getAsOpaquePtr(); case eBasicTypeFloatComplex: return ast->getComplexType(ast->FloatTy).getAsOpaquePtr(); case eBasicTypeDoubleComplex: @@ -4737,19 +4750,23 @@ CompilerType TypeSystemClang::CreateGenericFunctionPrototype() { // Exploring the type const llvm::fltSemantics & -TypeSystemClang::GetFloatTypeSemantics(size_t byte_size) { +TypeSystemClang::GetFloatTypeSemantics(size_t byte_size, bool prefer_float128) { clang::ASTContext &ast = getASTContext(); const size_t bit_size = byte_size * 8; if (bit_size == ast.getTypeSize(ast.FloatTy)) return ast.getFloatTypeSemantics(ast.FloatTy); else if (bit_size == ast.getTypeSize(ast.DoubleTy)) return ast.getFloatTypeSemantics(ast.DoubleTy); + else if (prefer_float128 && bit_size == ast.getTypeSize(ast.Float128Ty)) + return ast.getFloatTypeSemantics(ast.Float128Ty); else if (bit_size == ast.getTypeSize(ast.LongDoubleTy) || bit_size == llvm::APFloat::semanticsSizeInBits( ast.getFloatTypeSemantics(ast.LongDoubleTy))) return ast.getFloatTypeSemantics(ast.LongDoubleTy); else if (bit_size == ast.getTypeSize(ast.HalfTy)) return ast.getFloatTypeSemantics(ast.HalfTy); + else if (bit_size == ast.getTypeSize(ast.Float128Ty)) + return ast.getFloatTypeSemantics(ast.Float128Ty); return llvm::APFloatBase::Bogus(); } @@ -5222,6 +5239,8 @@ lldb::Format TypeSystemClang::GetFormat(lldb::opaque_compiler_type_t type) { case clang::BuiltinType::Double: case clang::BuiltinType::LongDouble: return lldb::eFormatFloat; + case clang::BuiltinType::Float128: + return lldb::eFormatFloat128; default: return lldb::eFormatHex; } @@ -5545,6 +5564,8 @@ TypeSystemClang::GetBasicTypeEnumeration(lldb::opaque_compiler_type_t type) { return eBasicTypeDouble; case clang::BuiltinType::LongDouble: return eBasicTypeLongDouble; + case clang::BuiltinType::Float128: + return eBasicTypeFloat128; case clang::BuiltinType::NullPtr: return eBasicTypeNullPtr; @@ -6106,6 +6127,7 @@ uint32_t TypeSystemClang::GetNumPointeeChildren(clang::QualType type) { case clang::BuiltinType::Float: case clang::BuiltinType::Double: case clang::BuiltinType::LongDouble: + case clang::BuiltinType::Float128: case clang::BuiltinType::Dependent: case clang::BuiltinType::Overload: case clang::BuiltinType::ObjCId: @@ -8837,6 +8859,7 @@ bool TypeSystemClang::DumpTypeValue( case eFormatHex: case eFormatHexUppercase: case eFormatFloat: + case eFormatFloat128: case eFormatOctal: case eFormatOSType: case eFormatUnsigned: diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 93933846d114d..23d86239b8d16 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -826,7 +826,8 @@ class TypeSystemClang : public TypeSystem { // Exploring the type - const llvm::fltSemantics &GetFloatTypeSemantics(size_t byte_size) override; + const llvm::fltSemantics & + GetFloatTypeSemantics(size_t byte_size, bool prefer_float128) override; llvm::Expected GetByteSize(lldb::opaque_compiler_type_t type, ExecutionContextScope *exe_scope) { diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp index e1c66763ff0b8..ddd95122aafa3 100644 --- a/lldb/source/ValueObject/ValueObject.cpp +++ b/lldb/source/ValueObject/ValueObject.cpp @@ -1468,8 +1468,9 @@ bool ValueObject::DumpPrintableRepresentation( (custom_format == eFormatComplexFloat) || (custom_format == eFormatDecimal) || (custom_format == eFormatHex) || (custom_format == eFormatHexUppercase) || - (custom_format == eFormatFloat) || (custom_format == eFormatOctal) || - (custom_format == eFormatOSType) || + (custom_format == eFormatFloat) || + (custom_format == eFormatFloat128) || + (custom_format == eFormatOctal) || (custom_format == eFormatOSType) || (custom_format == eFormatUnicode16) || (custom_format == eFormatUnicode32) || (custom_format == eFormatUnsigned) || diff --git a/lldb/unittests/Core/DumpDataExtractorTest.cpp b/lldb/unittests/Core/DumpDataExtractorTest.cpp index 3d1e8bc5e4623..6302f1e1d31a6 100644 --- a/lldb/unittests/Core/DumpDataExtractorTest.cpp +++ b/lldb/unittests/Core/DumpDataExtractorTest.cpp @@ -163,6 +163,9 @@ TEST_F(DumpDataExtractorTest, Formats) { TestDump(0xcafef00d, lldb::Format::eFormatHex, "0xcafef00d"); TestDump(0xcafef00d, lldb::Format::eFormatHexUppercase, "0xCAFEF00D"); TestDump(0.456, lldb::Format::eFormatFloat, "0.45600000000000002"); + TestDump(std::vector{0x47ae147ae147ae14, 0x40011147ae147ae1}, + lldb::Format::eFormatFloat128, + "4.26999999999999999999999999999999963"); TestDump(9, lldb::Format::eFormatOctal, "011"); // Chars packed into an integer. TestDump(0x4C4C4442, lldb::Format::eFormatOSType, "'LLDB'"); @@ -388,6 +391,9 @@ TEST_F(DumpDataExtractorTest, ItemByteSizeErrors) { TestDumpWithItemByteSize( 18, lldb::Format::eFormatFloat, "error: unsupported byte size (18) for float format"); + TestDumpWithItemByteSize( + 17, lldb::Format::eFormatFloat128, + "error: unsupported byte size (17) for float format"); // We want sizes to exactly match one of float/double. TestDumpWithItemByteSize( diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp index a9b0c87c4fbce..a3a982ee596a9 100644 --- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp @@ -76,6 +76,8 @@ TEST_F(TestTypeSystemClang, TestGetBasicTypeFromEnum) { context.getComplexType(context.FloatTy))); EXPECT_TRUE( context.hasSameType(GetBasicQualType(eBasicTypeHalf), context.HalfTy)); + EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeFloat128), + context.Float128Ty)); EXPECT_TRUE( context.hasSameType(GetBasicQualType(eBasicTypeInt), context.IntTy)); EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeInt128), From lldb-commits at lists.llvm.org Fri May 16 07:46:51 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Fri, 16 May 2025 07:46:51 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Basic implementation of a deferred request. (PR #140260) In-Reply-To: Message-ID: <68274fdb.170a0220.15befc.201c@mx.google.com> https://github.com/da-viper updated https://github.com/llvm/llvm-project/pull/140260 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Fri May 16 07:48:01 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 07:48:01 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Add support for displaying `__float128` variables (PR #98369) In-Reply-To: Message-ID: <68275021.170a0220.17abf9.eaad@mx.google.com> ================ @@ -666,7 +667,9 @@ lldb::offset_t lldb_private::DumpDataExtractor( const unsigned format_precision = 0; const llvm::fltSemantics &semantics = - GetFloatSemantics(target_sp, item_byte_size); + item_format == eFormatFloat128 && item_byte_size == 16 + ? llvm::APFloat::IEEEquad() + : GetFloatSemantics(target_sp, item_byte_size); ---------------- beetrees wrote: I've moved the it inside `GetFloatSemantics`. https://github.com/llvm/llvm-project/pull/98369 From lldb-commits at lists.llvm.org Fri May 16 08:14:51 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 08:14:51 -0700 (PDT) Subject: [Lldb-commits] [lldb] [llvm] [NFC] Separate high-level-dependent portions of DWARFExpression (PR #139175) In-Reply-To: Message-ID: <6827566b.170a0220.1990bf.0ea8@mx.google.com> Sterling-Augustine wrote: Anyone? https://github.com/llvm/llvm-project/pull/139175 From lldb-commits at lists.llvm.org Fri May 16 08:24:57 2025 From: lldb-commits at lists.llvm.org (Jeremy Morse via lldb-commits) Date: Fri, 16 May 2025 08:24:57 -0700 (PDT) Subject: [Lldb-commits] [lldb] [llvm] [NFC] Separate high-level-dependent portions of DWARFExpression (PR #139175) In-Reply-To: Message-ID: <682758c9.170a0220.af901.08ff@mx.google.com> jmorse wrote: This disappeared into a black hole in my inbox sorry; step forwards @SLTozer! (We're not rated for the reader-side of things but can probably comment on the writer). https://github.com/llvm/llvm-project/pull/139175 From lldb-commits at lists.llvm.org Fri May 16 08:44:48 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 08:44:48 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Basic implementation of a deferred request. (PR #140260) In-Reply-To: Message-ID: <68275d70.170a0220.152f28.0ead@mx.google.com> ================ @@ -748,7 +748,7 @@ bool DAP::HandleObject(const Message &M) { dispatcher.Set("client_data", llvm::Twine("request_command:", req->command).str()); if (handler_pos != request_handlers.end()) { - handler_pos->second->Run(*req); + defer = handler_pos->second->Run(*req); ---------------- ashgti wrote: Should we check the deferred call here like? ```cpp if (handler_pos->second->DeferRequest()) m_pending_queue.push_back(M); else handler_pos->second->Run(*req); ``` https://github.com/llvm/llvm-project/pull/140260 From lldb-commits at lists.llvm.org Fri May 16 08:44:49 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 08:44:49 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Basic implementation of a deferred request. (PR #140260) In-Reply-To: Message-ID: <68275d71.170a0220.2d0568.1133@mx.google.com> ================ @@ -46,7 +46,14 @@ class BaseRequestHandler { virtual ~BaseRequestHandler() = default; - void Run(const protocol::Request &); + /// Return `true` if the request should be deferred. + [[nodiscard]] + bool Run(const protocol::Request &); + + [[nodiscard]] + virtual bool DeferRequest() const { ---------------- ashgti wrote: This is specifically about deferring until configurationDone is called. We don't really have support for an async request handler yet. I thought about implementing an `AsyncRequestHandler` that would allow the request handler to unblock the handler queue before sending a reply, but I haven't needed it just yet so I haven't sent that out for a PR. Thats a long winded way of saying, should we make this more specific? Maybe `DeferUntilConfigurationDone`? I'm open to other names, just want to be clear. https://github.com/llvm/llvm-project/pull/140260 From lldb-commits at lists.llvm.org Fri May 16 08:46:35 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 08:46:35 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding additional asserts to unit tests. (PR #140107) In-Reply-To: Message-ID: <68275ddb.a70a0220.341666.23d9@mx.google.com> ================ @@ -60,7 +60,7 @@ def test_breakpoint_events(self): response = self.dap_server.request_setBreakpoints( main_source_path, [main_bp_line] ) - self.assertTrue(response) + self.assertTrue(response["success"]) ---------------- ashgti wrote: I can send a follow up for that. https://github.com/llvm/llvm-project/pull/140107 From lldb-commits at lists.llvm.org Fri May 16 08:47:05 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 08:47:05 -0700 (PDT) Subject: [Lldb-commits] [lldb] 087a5d2 - [lldb-dap] Adding additional asserts to unit tests. (#140107) Message-ID: <68275df9.630a0220.16ad5c.54b2@mx.google.com> Author: John Harrison Date: 2025-05-16T08:47:01-07:00 New Revision: 087a5d2ec7897cd99d3787820711fec76a8e1792 URL: https://github.com/llvm/llvm-project/commit/087a5d2ec7897cd99d3787820711fec76a8e1792 DIFF: https://github.com/llvm/llvm-project/commit/087a5d2ec7897cd99d3787820711fec76a8e1792.diff LOG: [lldb-dap] Adding additional asserts to unit tests. (#140107) Adding an assert that the 'continue' request succeeds caused a number of tests to fail. This showed a number of tests that were not specifying if they should be stopped or not at key points in the test. This is likely contributing to these tests being flaky since the debugger is not in the expected state. Additionally, I spent a little time trying to improve the readability of the dap_server.py and lldbdap_testcase.py. Added: Modified: lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py lldb/test/API/tools/lldb-dap/commands/TestDAP_commands.py lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py lldb/test/API/tools/lldb-dap/console/TestDAP_console.py lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py lldb/test/API/tools/lldb-dap/exception/TestDAP_exception.py lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py lldb/test/API/tools/lldb-dap/module/TestDAP_module.py lldb/test/API/tools/lldb-dap/output/TestDAP_output.py lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py lldb/tools/lldb-dap/DAPError.cpp lldb/tools/lldb-dap/DAPError.h lldb/tools/lldb-dap/Handler/ContinueRequestHandler.cpp lldb/tools/lldb-dap/Handler/RequestHandler.h Removed: ################################################################################ diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index 73f7b0e91d57a..d3589e78b6bc7 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -12,6 +12,13 @@ import sys import threading import time +from typing import Any, Optional, Union, BinaryIO, TextIO + +## DAP type references +Event = dict[str, Any] +Request = dict[str, Any] +Response = dict[str, Any] +ProtocolMessage = Union[Event, Request, Response] def dump_memory(base_addr, data, num_per_line, outfile): @@ -98,55 +105,40 @@ def dump_dap_log(log_file): print("========= END =========", file=sys.stderr) -def read_packet_thread(vs_comm, log_file): - done = False - try: - while not done: - packet = read_packet(vs_comm.recv, trace_file=vs_comm.trace_file) - # `packet` will be `None` on EOF. We want to pass it down to - # handle_recv_packet anyway so the main thread can handle unexpected - # termination of lldb-dap and stop waiting for new packets. - done = not vs_comm.handle_recv_packet(packet) - finally: - # Wait for the process to fully exit before dumping the log file to - # ensure we have the entire log contents. - if vs_comm.process is not None: - try: - # Do not wait forever, some logs are better than none. - vs_comm.process.wait(timeout=20) - except subprocess.TimeoutExpired: - pass - dump_dap_log(log_file) - - class DebugCommunication(object): - def __init__(self, recv, send, init_commands, log_file=None): - self.trace_file = None + def __init__( + self, + recv: BinaryIO, + send: BinaryIO, + init_commands: list[str], + log_file: Optional[TextIO] = None, + ): + # For debugging test failures, try setting `trace_file = sys.stderr`. + self.trace_file: Optional[TextIO] = None + self.log_file = log_file self.send = send self.recv = recv - self.recv_packets = [] + self.recv_packets: list[Optional[ProtocolMessage]] = [] self.recv_condition = threading.Condition() - self.recv_thread = threading.Thread( - target=read_packet_thread, args=(self, log_file) - ) + self.recv_thread = threading.Thread(target=self._read_packet_thread) self.process_event_body = None - self.exit_status = None + self.exit_status: Optional[int] = None self.initialize_body = None - self.thread_stop_reasons = {} - self.progress_events = [] + self.progress_events: list[Event] = [] self.reverse_requests = [] self.sequence = 1 self.threads = None + self.thread_stop_reasons = {} self.recv_thread.start() self.output_condition = threading.Condition() - self.output = {} + self.output: dict[str, list[str]] = {} self.configuration_done_sent = False self.frame_scopes = {} self.init_commands = init_commands self.disassembled_instructions = {} @classmethod - def encode_content(cls, s): + def encode_content(cls, s: str) -> bytes: return ("Content-Length: %u\r\n\r\n%s" % (len(s), s)).encode("utf-8") @classmethod @@ -156,6 +148,18 @@ def validate_response(cls, command, response): if command["seq"] != response["request_seq"]: raise ValueError("seq mismatch in response") + def _read_packet_thread(self): + done = False + try: + while not done: + packet = read_packet(self.recv, trace_file=self.trace_file) + # `packet` will be `None` on EOF. We want to pass it down to + # handle_recv_packet anyway so the main thread can handle unexpected + # termination of lldb-dap and stop waiting for new packets. + done = not self._handle_recv_packet(packet) + finally: + dump_dap_log(self.log_file) + def get_modules(self): module_list = self.request_modules()["body"]["modules"] modules = {} @@ -190,13 +194,13 @@ def collect_output(self, category, timeout_secs, pattern, clear=True): break return collected_output if collected_output else None - def enqueue_recv_packet(self, packet): + def _enqueue_recv_packet(self, packet: Optional[ProtocolMessage]): self.recv_condition.acquire() self.recv_packets.append(packet) self.recv_condition.notify() self.recv_condition.release() - def handle_recv_packet(self, packet): + def _handle_recv_packet(self, packet: Optional[ProtocolMessage]) -> bool: """Called by the read thread that is waiting for all incoming packets to store the incoming packet in "self.recv_packets" in a thread safe way. This function will then signal the "self.recv_condition" to @@ -205,7 +209,7 @@ def handle_recv_packet(self, packet): """ # If EOF, notify the read thread by enqueuing a None. if not packet: - self.enqueue_recv_packet(None) + self._enqueue_recv_packet(None) return False # Check the packet to see if is an event packet @@ -235,6 +239,18 @@ def handle_recv_packet(self, packet): # When a new process is attached or launched, remember the # details that are available in the body of the event self.process_event_body = body + elif event == "exited": + # Process exited, mark the status to indicate the process is not + # alive. + self.exit_status = body["exitCode"] + elif event == "continued": + # When the process continues, clear the known threads and + # thread_stop_reasons. + all_threads_continued = body.get("allThreadsContinued", True) + tid = body["threadId"] + if tid in self.thread_stop_reasons: + del self.thread_stop_reasons[tid] + self._process_continued(all_threads_continued) elif event == "stopped": # Each thread that stops with a reason will send a # 'stopped' event. We need to remember the thread stop @@ -252,10 +268,16 @@ def handle_recv_packet(self, packet): elif packet_type == "response": if packet["command"] == "disconnect": keepGoing = False - self.enqueue_recv_packet(packet) + self._enqueue_recv_packet(packet) return keepGoing - def send_packet(self, command_dict, set_sequence=True): + def _process_continued(self, all_threads_continued: bool): + self.threads = None + self.frame_scopes = {} + if all_threads_continued: + self.thread_stop_reasons = {} + + def send_packet(self, command_dict: Request, set_sequence=True): """Take the "command_dict" python dictionary and encode it as a JSON string and send the contents as a packet to the VSCode debug adapter""" @@ -273,7 +295,12 @@ def send_packet(self, command_dict, set_sequence=True): self.send.write(self.encode_content(json_str)) self.send.flush() - def recv_packet(self, filter_type=None, filter_event=None, timeout=None): + def recv_packet( + self, + filter_type: Optional[str] = None, + filter_event: Optional[Union[str, list[str]]] = None, + timeout: Optional[float] = None, + ) -> Optional[ProtocolMessage]: """Get a JSON packet from the VSCode debug adapter. This function assumes a thread that reads packets is running and will deliver any received packets by calling handle_recv_packet(...). This @@ -309,8 +336,6 @@ def recv_packet(self, filter_type=None, filter_event=None, timeout=None): finally: self.recv_condition.release() - return None - def send_recv(self, command): """Send a command python dictionary as JSON and receive the JSON response. Validates that the response is the correct sequence and @@ -360,47 +385,36 @@ def send_recv(self, command): return None - def wait_for_event(self, filter=None, timeout=None): - while True: - return self.recv_packet( - filter_type="event", filter_event=filter, timeout=timeout - ) - return None - - def wait_for_events(self, events, timeout=None): - """Wait for a list of events in `events` in any order. - Return the events not hit before the timeout expired""" - events = events[:] # Make a copy to avoid modifying the input - while events: - event_dict = self.wait_for_event(filter=events, timeout=timeout) - if event_dict is None: - break - events.remove(event_dict["event"]) - return events + def wait_for_event( + self, filter: Union[str, list[str]], timeout: Optional[float] = None + ) -> Optional[Event]: + """Wait for the first event that matches the filter.""" + return self.recv_packet( + filter_type="event", filter_event=filter, timeout=timeout + ) - def wait_for_stopped(self, timeout=None): + def wait_for_stopped( + self, timeout: Optional[float] = None + ) -> Optional[list[Event]]: stopped_events = [] stopped_event = self.wait_for_event( filter=["stopped", "exited"], timeout=timeout ) - exited = False while stopped_event: stopped_events.append(stopped_event) # If we exited, then we are done if stopped_event["event"] == "exited": - self.exit_status = stopped_event["body"]["exitCode"] - exited = True break # Otherwise we stopped and there might be one or more 'stopped' # events for each thread that stopped with a reason, so keep # checking for more 'stopped' events and return all of them - stopped_event = self.wait_for_event(filter="stopped", timeout=0.25) - if exited: - self.threads = [] + stopped_event = self.wait_for_event( + filter=["stopped", "exited"], timeout=0.25 + ) return stopped_events - def wait_for_breakpoint_events(self, timeout=None): - breakpoint_events = [] + def wait_for_breakpoint_events(self, timeout: Optional[float] = None): + breakpoint_events: list[Event] = [] while True: event = self.wait_for_event("breakpoint", timeout=timeout) if not event: @@ -408,14 +422,14 @@ def wait_for_breakpoint_events(self, timeout=None): breakpoint_events.append(event) return breakpoint_events - def wait_for_exited(self): - event_dict = self.wait_for_event("exited") + def wait_for_exited(self, timeout: Optional[float] = None): + event_dict = self.wait_for_event("exited", timeout=timeout) if event_dict is None: raise ValueError("didn't get exited event") return event_dict - def wait_for_terminated(self): - event_dict = self.wait_for_event("terminated") + def wait_for_terminated(self, timeout: Optional[float] = None): + event_dict = self.wait_for_event("terminated", timeout) if event_dict is None: raise ValueError("didn't get terminated event") return event_dict @@ -576,32 +590,30 @@ def replay_packets(self, replay_file_path): def request_attach( self, - program=None, - pid=None, - waitFor=None, - trace=None, - initCommands=None, - preRunCommands=None, - stopCommands=None, - exitCommands=None, - attachCommands=None, - terminateCommands=None, - coreFile=None, + *, + program: Optional[str] = None, + pid: Optional[int] = None, + waitFor=False, + initCommands: Optional[list[str]] = None, + preRunCommands: Optional[list[str]] = None, + attachCommands: Optional[list[str]] = None, + postRunCommands: Optional[list[str]] = None, + stopCommands: Optional[list[str]] = None, + exitCommands: Optional[list[str]] = None, + terminateCommands: Optional[list[str]] = None, + coreFile: Optional[str] = None, stopOnAttach=True, - postRunCommands=None, - sourceMap=None, - gdbRemotePort=None, - gdbRemoteHostname=None, + sourceMap: Optional[Union[list[tuple[str, str]], dict[str, str]]] = None, + gdbRemotePort: Optional[int] = None, + gdbRemoteHostname: Optional[str] = None, ): args_dict = {} if pid is not None: args_dict["pid"] = pid if program is not None: args_dict["program"] = program - if waitFor is not None: + if waitFor: args_dict["waitFor"] = waitFor - if trace: - args_dict["trace"] = trace args_dict["initCommands"] = self.init_commands if initCommands: args_dict["initCommands"].extend(initCommands) @@ -671,7 +683,7 @@ def _process_stopped(self): self.threads = None self.frame_scopes = {} - def request_continue(self, threadId=None): + def request_continue(self, threadId=None, singleThread=False): if self.exit_status is not None: raise ValueError("request_continue called after process exited") # If we have launched or attached, then the first continue is done by @@ -681,13 +693,18 @@ def request_continue(self, threadId=None): args_dict = {} if threadId is None: threadId = self.get_thread_id() - args_dict["threadId"] = threadId + if threadId: + args_dict["threadId"] = threadId + if singleThread: + args_dict["singleThread"] = True command_dict = { "command": "continue", "type": "request", "arguments": args_dict, } response = self.send_recv(command_dict) + if response["success"]: + self._process_continued(response["body"]["allThreadsContinued"]) # Caller must still call wait_for_stopped. return response @@ -775,7 +792,7 @@ def request_exceptionInfo(self, threadId=None): } return self.send_recv(command_dict) - def request_initialize(self, sourceInitFile): + def request_initialize(self, sourceInitFile=False): command_dict = { "command": "initialize", "type": "request", @@ -802,32 +819,32 @@ def request_initialize(self, sourceInitFile): def request_launch( self, - program, - args=None, - cwd=None, - env=None, - stopOnEntry=False, + program: str, + *, + args: Optional[list[str]] = None, + cwd: Optional[str] = None, + env: Optional[dict[str, str]] = None, + stopOnEntry=True, disableASLR=True, disableSTDIO=False, shellExpandArguments=False, - trace=False, - initCommands=None, - preRunCommands=None, - stopCommands=None, - exitCommands=None, - terminateCommands=None, - sourcePath=None, - debuggerRoot=None, - launchCommands=None, - sourceMap=None, runInTerminal=False, - postRunCommands=None, enableAutoVariableSummaries=False, displayExtendedBacktrace=False, enableSyntheticChildDebugging=False, - commandEscapePrefix=None, - customFrameFormat=None, - customThreadFormat=None, + initCommands: Optional[list[str]] = None, + preRunCommands: Optional[list[str]] = None, + launchCommands: Optional[list[str]] = None, + postRunCommands: Optional[list[str]] = None, + stopCommands: Optional[list[str]] = None, + exitCommands: Optional[list[str]] = None, + terminateCommands: Optional[list[str]] = None, + sourceMap: Optional[Union[list[tuple[str, str]], dict[str, str]]] = None, + sourcePath: Optional[str] = None, + debuggerRoot: Optional[str] = None, + commandEscapePrefix: Optional[str] = None, + customFrameFormat: Optional[str] = None, + customThreadFormat: Optional[str] = None, ): args_dict = {"program": program} if args: @@ -842,8 +859,6 @@ def request_launch( args_dict["disableSTDIO"] = disableSTDIO if shellExpandArguments: args_dict["shellExpandArguments"] = shellExpandArguments - if trace: - args_dict["trace"] = trace args_dict["initCommands"] = self.init_commands if initCommands: args_dict["initCommands"].extend(initCommands) @@ -1190,7 +1205,8 @@ def request_testGetTargetBreakpoints(self): def terminate(self): self.send.close() - # self.recv.close() + if self.recv_thread.is_alive(): + self.recv_thread.join() def request_setInstructionBreakpoints(self, memory_reference=[]): breakpoints = [] @@ -1211,11 +1227,11 @@ def request_setInstructionBreakpoints(self, memory_reference=[]): class DebugAdapterServer(DebugCommunication): def __init__( self, - executable=None, - connection=None, - init_commands=[], - log_file=None, - env=None, + executable: Optional[str] = None, + connection: Optional[str] = None, + init_commands: list[str] = [], + log_file: Optional[TextIO] = None, + env: Optional[dict[str, str]] = None, ): self.process = None self.connection = None @@ -1247,7 +1263,14 @@ def __init__( ) @classmethod - def launch(cls, /, executable, env=None, log_file=None, connection=None): + def launch( + cls, + *, + executable: str, + env: Optional[dict[str, str]] = None, + log_file: Optional[TextIO] = None, + connection: Optional[str] = None, + ) -> tuple[subprocess.Popen, Optional[str]]: adapter_env = os.environ.copy() if env is not None: adapter_env.update(env) @@ -1289,26 +1312,29 @@ def launch(cls, /, executable, env=None, log_file=None, connection=None): return (process, connection) - def get_pid(self): + def get_pid(self) -> int: if self.process: return self.process.pid return -1 def terminate(self): - super(DebugAdapterServer, self).terminate() - if self.process is not None: - process = self.process - self.process = None - try: - # When we close stdin it should signal the lldb-dap that no - # new messages will arrive and it should shutdown on its own. - process.stdin.close() - process.wait(timeout=20) - except subprocess.TimeoutExpired: - process.kill() - process.wait() - if process.returncode != 0: - raise DebugAdapterProcessError(process.returncode) + try: + if self.process is not None: + process = self.process + self.process = None + try: + # When we close stdin it should signal the lldb-dap that no + # new messages will arrive and it should shutdown on its + # own. + process.stdin.close() + process.wait(timeout=20) + except subprocess.TimeoutExpired: + process.kill() + process.wait() + if process.returncode != 0: + raise DebugAdapterProcessError(process.returncode) + finally: + super(DebugAdapterServer, self).terminate() class DebugAdapterError(Exception): diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index c5a7eb76a58c7..d7cf8e2864324 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -1,5 +1,6 @@ import os import time +from typing import Optional import uuid import dap_server @@ -11,10 +12,14 @@ class DAPTestCaseBase(TestBase): # set timeout based on whether ASAN was enabled or not. Increase # timeout by a factor of 10 if ASAN is enabled. - timeoutval = 10 * (10 if ("ASAN_OPTIONS" in os.environ) else 1) + DEFAULT_TIMEOUT = 10 * (10 if ("ASAN_OPTIONS" in os.environ) else 1) NO_DEBUG_INFO_TESTCASE = True - def create_debug_adapter(self, lldbDAPEnv=None, connection=None): + def create_debug_adapter( + self, + lldbDAPEnv: Optional[dict[str, str]] = None, + connection: Optional[str] = None, + ): """Create the Visual Studio Code debug adapter""" self.assertTrue( is_exe(self.lldbDAPExec), "lldb-dap must exist and be executable" @@ -28,7 +33,11 @@ def create_debug_adapter(self, lldbDAPEnv=None, connection=None): env=lldbDAPEnv, ) - def build_and_create_debug_adapter(self, lldbDAPEnv=None, dictionary=None): + def build_and_create_debug_adapter( + self, + lldbDAPEnv: Optional[dict[str, str]] = None, + dictionary: Optional[dict] = None, + ): self.build(dictionary=dictionary) self.create_debug_adapter(lldbDAPEnv) @@ -78,13 +87,13 @@ def waitUntil(self, condition_callback): time.sleep(0.5) return False - def verify_breakpoint_hit(self, breakpoint_ids): + def verify_breakpoint_hit(self, breakpoint_ids, timeout=DEFAULT_TIMEOUT): """Wait for the process we are debugging to stop, and verify we hit any breakpoint location in the "breakpoint_ids" array. "breakpoint_ids" should be a list of breakpoint ID strings (["1", "2"]). The return value from self.set_source_breakpoints() or self.set_function_breakpoints() can be passed to this function""" - stopped_events = self.dap_server.wait_for_stopped() + stopped_events = self.dap_server.wait_for_stopped(timeout) for stopped_event in stopped_events: if "body" in stopped_event: body = stopped_event["body"] @@ -110,16 +119,15 @@ def verify_breakpoint_hit(self, breakpoint_ids): match_desc = "breakpoint %s." % (breakpoint_id) if match_desc in description: return - self.assertTrue(False, "breakpoint not hit") + self.assertTrue(False, f"breakpoint not hit, stopped_events={stopped_events}") - def verify_stop_exception_info(self, expected_description, timeout=timeoutval): + def verify_stop_exception_info(self, expected_description, timeout=DEFAULT_TIMEOUT): """Wait for the process we are debugging to stop, and verify the stop reason is 'exception' and that the description matches 'expected_description' """ - stopped_events = self.dap_server.wait_for_stopped(timeout=timeout) + stopped_events = self.dap_server.wait_for_stopped(timeout) for stopped_event in stopped_events: - print("stopped_event", stopped_event) if "body" in stopped_event: body = stopped_event["body"] if "reason" not in body: @@ -263,46 +271,61 @@ def set_global(self, name, value, id=None): return self.dap_server.request_setVariable(2, name, str(value), id=id) def stepIn( - self, threadId=None, targetId=None, waitForStop=True, granularity="statement" + self, + threadId=None, + targetId=None, + waitForStop=True, + granularity="statement", + timeout=DEFAULT_TIMEOUT, ): response = self.dap_server.request_stepIn( threadId=threadId, targetId=targetId, granularity=granularity ) self.assertTrue(response["success"]) if waitForStop: - return self.dap_server.wait_for_stopped() + return self.dap_server.wait_for_stopped(timeout) return None - def stepOver(self, threadId=None, waitForStop=True, granularity="statement"): + def stepOver( + self, + threadId=None, + waitForStop=True, + granularity="statement", + timeout=DEFAULT_TIMEOUT, + ): self.dap_server.request_next(threadId=threadId, granularity=granularity) if waitForStop: - return self.dap_server.wait_for_stopped() + return self.dap_server.wait_for_stopped(timeout) return None - def stepOut(self, threadId=None, waitForStop=True): + def stepOut(self, threadId=None, waitForStop=True, timeout=DEFAULT_TIMEOUT): self.dap_server.request_stepOut(threadId=threadId) if waitForStop: - return self.dap_server.wait_for_stopped() + return self.dap_server.wait_for_stopped(timeout) return None - def continue_to_next_stop(self): - self.dap_server.request_continue() - return self.dap_server.wait_for_stopped() + def do_continue(self): # `continue` is a keyword. + resp = self.dap_server.request_continue() + self.assertTrue(resp["success"], f"continue request failed: {resp}") + + def continue_to_next_stop(self, timeout=DEFAULT_TIMEOUT): + self.do_continue() + return self.dap_server.wait_for_stopped(timeout) - def continue_to_breakpoints(self, breakpoint_ids): - self.dap_server.request_continue() - self.verify_breakpoint_hit(breakpoint_ids) + def continue_to_breakpoints(self, breakpoint_ids, timeout=DEFAULT_TIMEOUT): + self.do_continue() + self.verify_breakpoint_hit(breakpoint_ids, timeout) - def continue_to_exception_breakpoint(self, filter_label): - self.dap_server.request_continue() + def continue_to_exception_breakpoint(self, filter_label, timeout=DEFAULT_TIMEOUT): + self.do_continue() self.assertTrue( - self.verify_stop_exception_info(filter_label), + self.verify_stop_exception_info(filter_label, timeout), 'verify we got "%s"' % (filter_label), ) - def continue_to_exit(self, exitCode=0): - self.dap_server.request_continue() - stopped_events = self.dap_server.wait_for_stopped() + def continue_to_exit(self, exitCode=0, timeout=DEFAULT_TIMEOUT): + self.do_continue() + stopped_events = self.dap_server.wait_for_stopped(timeout) self.assertEqual( len(stopped_events), 1, "stopped_events = {}".format(stopped_events) ) @@ -330,27 +353,15 @@ def disassemble(self, threadId=None, frameIndex=None): def attach( self, - program=None, - pid=None, - waitFor=None, - trace=None, - initCommands=None, - preRunCommands=None, - stopCommands=None, - exitCommands=None, - attachCommands=None, - coreFile=None, + *, stopOnAttach=True, disconnectAutomatically=True, - terminateCommands=None, - postRunCommands=None, - sourceMap=None, sourceInitFile=False, expectFailure=False, - gdbRemotePort=None, - gdbRemoteHostname=None, sourceBreakpoints=None, functionBreakpoints=None, + timeout=DEFAULT_TIMEOUT, + **kwargs, ): """Build the default Makefile target, create the DAP debug adapter, and attach to the process. @@ -367,7 +378,7 @@ def cleanup(): self.addTearDownHook(cleanup) # Initialize and launch the program self.dap_server.request_initialize(sourceInitFile) - self.dap_server.wait_for_event("initialized") + self.dap_server.wait_for_event("initialized", timeout) # Set source breakpoints as part of the launch sequence. if sourceBreakpoints: @@ -389,64 +400,28 @@ def cleanup(): ) self.dap_server.request_configurationDone() - response = self.dap_server.request_attach( - program=program, - pid=pid, - waitFor=waitFor, - trace=trace, - initCommands=initCommands, - preRunCommands=preRunCommands, - stopCommands=stopCommands, - exitCommands=exitCommands, - attachCommands=attachCommands, - terminateCommands=terminateCommands, - coreFile=coreFile, - stopOnAttach=stopOnAttach, - postRunCommands=postRunCommands, - sourceMap=sourceMap, - gdbRemotePort=gdbRemotePort, - gdbRemoteHostname=gdbRemoteHostname, - ) + response = self.dap_server.request_attach(stopOnAttach=stopOnAttach, **kwargs) if expectFailure: return response if not (response and response["success"]): self.assertTrue( response["success"], "attach failed (%s)" % (response["message"]) ) + if stopOnAttach: + self.dap_server.wait_for_stopped(timeout) def launch( self, program=None, - args=None, - cwd=None, - env=None, - stopOnEntry=False, - disableASLR=False, - disableSTDIO=False, - shellExpandArguments=False, - trace=False, - initCommands=None, - preRunCommands=None, - stopCommands=None, - exitCommands=None, - terminateCommands=None, - sourcePath=None, - debuggerRoot=None, + *, sourceInitFile=False, - launchCommands=None, - sourceMap=None, disconnectAutomatically=True, - runInTerminal=False, - expectFailure=False, - postRunCommands=None, - enableAutoVariableSummaries=False, - displayExtendedBacktrace=False, - enableSyntheticChildDebugging=False, - commandEscapePrefix=None, - customFrameFormat=None, - customThreadFormat=None, sourceBreakpoints=None, functionBreakpoints=None, + expectFailure=False, + stopOnEntry=True, + timeout=DEFAULT_TIMEOUT, + **kwargs, ): """Sending launch request to dap""" @@ -462,7 +437,7 @@ def cleanup(): # Initialize and launch the program self.dap_server.request_initialize(sourceInitFile) - self.dap_server.wait_for_event("initialized") + self.dap_server.wait_for_event("initialized", timeout) # Set source breakpoints as part of the launch sequence. if sourceBreakpoints: @@ -487,76 +462,28 @@ def cleanup(): response = self.dap_server.request_launch( program, - args=args, - cwd=cwd, - env=env, stopOnEntry=stopOnEntry, - disableASLR=disableASLR, - disableSTDIO=disableSTDIO, - shellExpandArguments=shellExpandArguments, - trace=trace, - initCommands=initCommands, - preRunCommands=preRunCommands, - stopCommands=stopCommands, - exitCommands=exitCommands, - terminateCommands=terminateCommands, - sourcePath=sourcePath, - debuggerRoot=debuggerRoot, - launchCommands=launchCommands, - sourceMap=sourceMap, - runInTerminal=runInTerminal, - postRunCommands=postRunCommands, - enableAutoVariableSummaries=enableAutoVariableSummaries, - displayExtendedBacktrace=displayExtendedBacktrace, - enableSyntheticChildDebugging=enableSyntheticChildDebugging, - commandEscapePrefix=commandEscapePrefix, - customFrameFormat=customFrameFormat, - customThreadFormat=customThreadFormat, + **kwargs, ) if expectFailure: return response - if not (response and response["success"]): self.assertTrue( response["success"], "launch failed (%s)" % (response["body"]["error"]["format"]), ) + if stopOnEntry: + self.dap_server.wait_for_stopped(timeout) + return response def build_and_launch( self, program, - args=None, - cwd=None, - env=None, - stopOnEntry=False, - disableASLR=False, - disableSTDIO=False, - shellExpandArguments=False, - trace=False, - initCommands=None, - preRunCommands=None, - stopCommands=None, - exitCommands=None, - terminateCommands=None, - sourcePath=None, - debuggerRoot=None, - sourceInitFile=False, - runInTerminal=False, - disconnectAutomatically=True, - postRunCommands=None, - lldbDAPEnv=None, - enableAutoVariableSummaries=False, - displayExtendedBacktrace=False, - enableSyntheticChildDebugging=False, - commandEscapePrefix=None, - customFrameFormat=None, - customThreadFormat=None, - launchCommands=None, - expectFailure=False, - sourceBreakpoints=None, - functionBreakpoints=None, + *, + lldbDAPEnv: Optional[dict[str, str]] = None, + **kwargs, ): """Build the default Makefile target, create the DAP debug adapter, and launch the process. @@ -564,38 +491,7 @@ def build_and_launch( self.build_and_create_debug_adapter(lldbDAPEnv) self.assertTrue(os.path.exists(program), "executable must exist") - return self.launch( - program, - args, - cwd, - env, - stopOnEntry, - disableASLR, - disableSTDIO, - shellExpandArguments, - trace, - initCommands, - preRunCommands, - stopCommands, - exitCommands, - terminateCommands, - sourcePath, - debuggerRoot, - sourceInitFile, - runInTerminal=runInTerminal, - disconnectAutomatically=disconnectAutomatically, - postRunCommands=postRunCommands, - enableAutoVariableSummaries=enableAutoVariableSummaries, - enableSyntheticChildDebugging=enableSyntheticChildDebugging, - displayExtendedBacktrace=displayExtendedBacktrace, - commandEscapePrefix=commandEscapePrefix, - customFrameFormat=customFrameFormat, - customThreadFormat=customThreadFormat, - launchCommands=launchCommands, - expectFailure=expectFailure, - sourceBreakpoints=sourceBreakpoints, - functionBreakpoints=functionBreakpoints, - ) + return self.launch(program, **kwargs) def getBuiltinDebugServerTool(self): # Tries to find simulation/lldb-server/gdbserver tool path. diff --git a/lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py b/lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py index a9218d3c3dde3..55557e6e0030e 100644 --- a/lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py +++ b/lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py @@ -2,15 +2,11 @@ Test lldb-dap attach request """ -import dap_server from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil import lldbdap_testcase -import os -import shutil import subprocess -import tempfile import threading import time @@ -26,8 +22,6 @@ def spawn_and_wait(program, delay): class TestDAP_attach(lldbdap_testcase.DAPTestCaseBase): def set_and_hit_breakpoint(self, continueToExit=True): - self.dap_server.wait_for_stopped() - source = "main.c" breakpoint1_line = line_number(source, "// breakpoint 1") lines = [breakpoint1_line] @@ -36,7 +30,12 @@ def set_and_hit_breakpoint(self, continueToExit=True): self.assertEqual( len(breakpoint_ids), len(lines), "expect correct number of breakpoints" ) - self.continue_to_breakpoints(breakpoint_ids) + # Test binary will sleep for 10s, offset the breakpoint timeout + # accordingly. + timeout_offset = 10 + self.continue_to_breakpoints( + breakpoint_ids, timeout=timeout_offset + self.DEFAULT_TIMEOUT + ) if continueToExit: self.continue_to_exit() @@ -160,7 +159,7 @@ def test_commands(self): # Continue after launch and hit the "pause()" call and stop the target. # Get output from the console. This should contain both the # "stopCommands" that were run after we stop. - self.dap_server.request_continue() + self.do_continue() time.sleep(0.5) self.dap_server.request_pause() self.dap_server.wait_for_stopped() @@ -198,9 +197,6 @@ def test_attach_command_process_failures(self): ) @skipIfNetBSD # Hangs on NetBSD as well - @skipIf( - archs=["arm", "aarch64"] - ) # Example of a flaky run http://lab.llvm.org:8011/builders/lldb-aarch64-ubuntu/builds/5517/steps/test/logs/stdio def test_terminate_commands(self): """ Tests that the "terminateCommands", that can be passed during diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py index 8581f10cef22a..25f031db5cac5 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py @@ -60,7 +60,7 @@ def test_breakpoint_events(self): response = self.dap_server.request_setBreakpoints( main_source_path, [main_bp_line] ) - self.assertTrue(response) + self.assertTrue(response["success"]) breakpoints = response["body"]["breakpoints"] for breakpoint in breakpoints: main_bp_id = breakpoint["id"] @@ -72,7 +72,7 @@ def test_breakpoint_events(self): response = self.dap_server.request_setBreakpoints( foo_source_path, [foo_bp1_line] ) - self.assertTrue(response) + self.assertTrue(response["success"]) breakpoints = response["body"]["breakpoints"] for breakpoint in breakpoints: foo_bp_id = breakpoint["id"] @@ -81,9 +81,6 @@ def test_breakpoint_events(self): breakpoint["verified"], "expect foo breakpoint to not be verified" ) - # Make sure we're stopped. - self.dap_server.wait_for_stopped() - # Flush the breakpoint events. self.dap_server.wait_for_breakpoint_events(timeout=5) diff --git a/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py b/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py index 479a91208a66c..948c146d4da68 100644 --- a/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py +++ b/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py @@ -9,7 +9,7 @@ import lldbdap_testcase -class TestDAP_launch(lldbdap_testcase.DAPTestCaseBase): +class TestDAP_cancel(lldbdap_testcase.DAPTestCaseBase): def send_async_req(self, command: str, arguments={}) -> int: seq = self.dap_server.sequence self.dap_server.send_packet( @@ -45,14 +45,13 @@ def test_pending_request(self): """ program = self.getBuildArtifact("a.out") self.build_and_launch(program, stopOnEntry=True) - self.continue_to_next_stop() # Use a relatively short timeout since this is only to ensure the # following request is queued. blocking_seq = self.async_blocking_request(duration=1.0) # Use a longer timeout to ensure we catch if the request was interrupted # properly. - pending_seq = self.async_blocking_request(duration=self.timeoutval / 2) + pending_seq = self.async_blocking_request(duration=self.DEFAULT_TIMEOUT / 2) cancel_seq = self.async_cancel(requestId=pending_seq) blocking_resp = self.dap_server.recv_packet(filter_type=["response"]) @@ -78,12 +77,11 @@ def test_inflight_request(self): """ program = self.getBuildArtifact("a.out") self.build_and_launch(program, stopOnEntry=True) - self.continue_to_next_stop() - blocking_seq = self.async_blocking_request(duration=self.timeoutval / 2) + blocking_seq = self.async_blocking_request(duration=self.DEFAULT_TIMEOUT / 2) # Wait for the sleep to start to cancel the inflight request. self.collect_console( - timeout_secs=self.timeoutval, + timeout_secs=self.DEFAULT_TIMEOUT, pattern="starting sleep", ) cancel_seq = self.async_cancel(requestId=blocking_seq) diff --git a/lldb/test/API/tools/lldb-dap/commands/TestDAP_commands.py b/lldb/test/API/tools/lldb-dap/commands/TestDAP_commands.py index 223258fbdd3dc..ea6b2ea7f28ab 100644 --- a/lldb/test/API/tools/lldb-dap/commands/TestDAP_commands.py +++ b/lldb/test/API/tools/lldb-dap/commands/TestDAP_commands.py @@ -75,11 +75,12 @@ def test_command_directive_abort_on_error_attach_commands(self): ) command_abort_on_error = "settings set foo bar" program = self.build_and_create_debug_adapter_for_attach() - self.attach( - program, + resp = self.attach( + program=program, attachCommands=["?!" + command_quiet, "!" + command_abort_on_error], expectFailure=True, ) + self.assertFalse(resp["success"], "expected 'attach' failure") full_output = self.collect_console( timeout_secs=1.0, pattern=command_abort_on_error, diff --git a/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py b/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py index a94288c7a669e..75876c248f86c 100644 --- a/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py +++ b/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py @@ -43,12 +43,12 @@ def verify_completions(self, actual_list, expected_list, not_expected_list=[]): for not_expected_item in not_expected_list: self.assertNotIn(not_expected_item, actual_list) - def setup_debugee(self, stopOnEntry=False): + def setup_debuggee(self): program = self.getBuildArtifact("a.out") source = "main.cpp" self.build_and_launch( program, - stopOnEntry=stopOnEntry, + stopOnEntry=True, sourceBreakpoints=[ ( source, @@ -64,7 +64,7 @@ def test_command_completions(self): """ Tests completion requests for lldb commands, within "repl-mode=command" """ - self.setup_debugee() + self.setup_debuggee() self.continue_to_next_stop() res = self.dap_server.request_evaluate( @@ -143,7 +143,7 @@ def test_variable_completions(self): """ Tests completion requests in "repl-mode=variable" """ - self.setup_debugee() + self.setup_debuggee() self.continue_to_next_stop() res = self.dap_server.request_evaluate( @@ -241,7 +241,7 @@ def test_auto_completions(self): """ Tests completion requests in "repl-mode=auto" """ - self.setup_debugee(stopOnEntry=True) + self.setup_debuggee() res = self.dap_server.request_evaluate( "`lldb-dap repl-mode auto", context="repl" diff --git a/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py b/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py index 0b428994e7fba..1f810afdbb667 100644 --- a/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py +++ b/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py @@ -177,7 +177,7 @@ def test_diagnositcs(self): ) diagnostics = self.collect_important( - timeout_secs=self.timeoutval, pattern="minidump file" + timeout_secs=self.DEFAULT_TIMEOUT, pattern="minidump file" ) self.assertIn( diff --git a/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py b/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py index 1896acea15a99..e678c5ee77fdc 100644 --- a/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py +++ b/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py @@ -2,7 +2,6 @@ Test lldb-dap coreFile attaching """ - import dap_server from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * @@ -19,7 +18,7 @@ def test_core_file(self): core_file = os.path.join(current_dir, "linux-x86_64.core") self.create_debug_adapter() - self.attach(exe_file, coreFile=core_file) + self.attach(program=exe_file, coreFile=core_file) expected_frames = [ { @@ -51,7 +50,8 @@ def test_core_file(self): self.assertEqual(self.get_stackFrames(), expected_frames) # Resuming should have no effect and keep the process stopped - self.continue_to_next_stop() + resp = self.dap_server.request_continue() + self.assertFalse(resp["success"]) self.assertEqual(self.get_stackFrames(), expected_frames) self.dap_server.request_next(threadId=32259) @@ -67,7 +67,7 @@ def test_core_file_source_mapping_array(self): self.create_debug_adapter() source_map = [["/home/labath/test", current_dir]] - self.attach(exe_file, coreFile=core_file, sourceMap=source_map) + self.attach(program=exe_file, coreFile=core_file, sourceMap=source_map) self.assertIn(current_dir, self.get_stackFrames()[0]["source"]["path"]) @@ -81,6 +81,6 @@ def test_core_file_source_mapping_object(self): self.create_debug_adapter() source_map = {"/home/labath/test": current_dir} - self.attach(exe_file, coreFile=core_file, sourceMap=source_map) + self.attach(program=exe_file, coreFile=core_file, sourceMap=source_map) self.assertIn(current_dir, self.get_stackFrames()[0]["source"]["path"]) diff --git a/lldb/test/API/tools/lldb-dap/exception/TestDAP_exception.py b/lldb/test/API/tools/lldb-dap/exception/TestDAP_exception.py index ec7387dabb0c2..f044bcae41892 100644 --- a/lldb/test/API/tools/lldb-dap/exception/TestDAP_exception.py +++ b/lldb/test/API/tools/lldb-dap/exception/TestDAP_exception.py @@ -16,6 +16,7 @@ def test_stopped_description(self): """ program = self.getBuildArtifact("a.out") self.build_and_launch(program) + self.do_continue() self.assertTrue(self.verify_stop_exception_info("signal SIGABRT")) exceptionInfo = self.get_exceptionInfo() diff --git a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py index 7c85f05c1ba45..0063954791fd5 100644 --- a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py +++ b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py @@ -75,9 +75,7 @@ def test_termination(self): self.dap_server.request_disconnect() # Wait until the underlying lldb-dap process dies. - self.dap_server.process.wait( - timeout=lldbdap_testcase.DAPTestCaseBase.timeoutval - ) + self.dap_server.process.wait(timeout=self.DEFAULT_TIMEOUT) # Check the return code self.assertEqual(self.dap_server.process.poll(), 0) @@ -90,15 +88,16 @@ def test_stopOnEntry(self): program = self.getBuildArtifact("a.out") self.build_and_launch(program, stopOnEntry=True) - stopped_events = self.dap_server.wait_for_stopped() - for stopped_event in stopped_events: - if "body" in stopped_event: - body = stopped_event["body"] - if "reason" in body: - reason = body["reason"] - self.assertNotEqual( - reason, "breakpoint", 'verify stop isn\'t "main" breakpoint' - ) + self.assertTrue( + len(self.dap_server.thread_stop_reasons) > 0, + "expected stopped event during launch", + ) + for _, body in self.dap_server.thread_stop_reasons.items(): + if "reason" in body: + reason = body["reason"] + self.assertNotEqual( + reason, "breakpoint", 'verify stop isn\'t "main" breakpoint' + ) @skipIfWindows def test_cwd(self): @@ -393,14 +392,14 @@ def test_commands(self): # Get output from the console. This should contain both the # "stopCommands" that were run after the first breakpoint was hit self.continue_to_breakpoints(breakpoint_ids) - output = self.get_console(timeout=lldbdap_testcase.DAPTestCaseBase.timeoutval) + output = self.get_console(timeout=self.DEFAULT_TIMEOUT) self.verify_commands("stopCommands", output, stopCommands) # Continue again and hit the second breakpoint. # Get output from the console. This should contain both the # "stopCommands" that were run after the second breakpoint was hit self.continue_to_breakpoints(breakpoint_ids) - output = self.get_console(timeout=lldbdap_testcase.DAPTestCaseBase.timeoutval) + output = self.get_console(timeout=self.DEFAULT_TIMEOUT) self.verify_commands("stopCommands", output, stopCommands) # Continue until the program exits @@ -462,21 +461,21 @@ def test_extra_launch_commands(self): self.verify_commands("launchCommands", output, launchCommands) # Verify the "stopCommands" here self.continue_to_next_stop() - output = self.get_console(timeout=lldbdap_testcase.DAPTestCaseBase.timeoutval) + output = self.get_console(timeout=self.DEFAULT_TIMEOUT) self.verify_commands("stopCommands", output, stopCommands) # Continue and hit the second breakpoint. # Get output from the console. This should contain both the # "stopCommands" that were run after the first breakpoint was hit self.continue_to_next_stop() - output = self.get_console(timeout=lldbdap_testcase.DAPTestCaseBase.timeoutval) + output = self.get_console(timeout=self.DEFAULT_TIMEOUT) self.verify_commands("stopCommands", output, stopCommands) # Continue until the program exits self.continue_to_exit() # Get output from the console. This should contain both the # "exitCommands" that were run after the second breakpoint was hit - output = self.get_console(timeout=lldbdap_testcase.DAPTestCaseBase.timeoutval) + output = self.get_console(timeout=self.DEFAULT_TIMEOUT) self.verify_commands("exitCommands", output, exitCommands) def test_failing_launch_commands(self): @@ -531,7 +530,7 @@ def test_terminate_commands(self): terminateCommands = ["expr 4+2"] self.launch( - program=program, + program, stopOnEntry=True, terminateCommands=terminateCommands, disconnectAutomatically=False, diff --git a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py index 3fc0f752ee39e..b333efd7bfb1f 100644 --- a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py +++ b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py @@ -14,7 +14,7 @@ class TestDAP_module(lldbdap_testcase.DAPTestCaseBase): def run_test(self, symbol_basename, expect_debug_info_size): program_basename = "a.out.stripped" program = self.getBuildArtifact(program_basename) - self.build_and_launch(program) + self.build_and_launch(program, stopOnEntry=True) functions = ["foo"] breakpoint_ids = self.set_function_breakpoints(functions) self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint") @@ -108,7 +108,7 @@ def test_modules_dsym(self): @skipIfWindows def test_compile_units(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program) + self.build_and_launch(program, stopOnEntry=True) source = "main.cpp" main_source_path = self.getSourcePath(source) breakpoint1_line = line_number(source, "// breakpoint 1") diff --git a/lldb/test/API/tools/lldb-dap/output/TestDAP_output.py b/lldb/test/API/tools/lldb-dap/output/TestDAP_output.py index 49131ad9ecb17..0425b55a5e552 100644 --- a/lldb/test/API/tools/lldb-dap/output/TestDAP_output.py +++ b/lldb/test/API/tools/lldb-dap/output/TestDAP_output.py @@ -37,14 +37,14 @@ def test_output(self): # Disconnecting from the server to ensure any pending IO is flushed. self.dap_server.request_disconnect() - output += self.get_stdout(timeout=lldbdap_testcase.DAPTestCaseBase.timeoutval) + output += self.get_stdout(timeout=self.DEFAULT_TIMEOUT) self.assertTrue(output and len(output) > 0, "expect program stdout") self.assertIn( "abcdefghi\r\nhello world\r\nfinally\0\0", output, "full stdout not found in: " + repr(output), ) - console = self.get_console(timeout=self.timeoutval) + console = self.get_console(timeout=self.DEFAULT_TIMEOUT) self.assertTrue(console and len(console) > 0, "expect dap messages") self.assertIn( "out\0\0\r\nerr\0\0\r\n", console, f"full console message not found" diff --git a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py index 5f95c7bfb1556..8681b31e8eb1b 100644 --- a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py +++ b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py @@ -22,9 +22,8 @@ def test_basic_functionality(self): [bp_A, bp_B] = self.set_source_breakpoints("main.c", [line_A, line_B]) # Verify we hit A, then B. - self.verify_breakpoint_hit([bp_A]) - self.dap_server.request_continue() - self.verify_breakpoint_hit([bp_B]) + self.continue_to_breakpoints([bp_A]) + self.continue_to_breakpoints([bp_B]) # Make sure i has been modified from its initial value of 0. self.assertEqual( @@ -34,8 +33,9 @@ def test_basic_functionality(self): ) # Restart then check we stop back at A and program state has been reset. - self.dap_server.request_restart() - self.verify_breakpoint_hit([bp_A]) + resp = self.dap_server.request_restart() + self.assertTrue(resp["success"]) + self.continue_to_breakpoints([bp_A]) self.assertEqual( int(self.dap_server.get_local_variable_value("i")), 0, @@ -50,27 +50,26 @@ def test_stopOnEntry(self): program = self.getBuildArtifact("a.out") self.build_and_launch(program, stopOnEntry=True) [bp_main] = self.set_function_breakpoints(["main"]) - self.dap_server.request_configurationDone() - # Once the "configuration done" event is sent, we should get a stopped # event immediately because of stopOnEntry. - stopped_events = self.dap_server.wait_for_stopped() - for stopped_event in stopped_events: - if "body" in stopped_event: - body = stopped_event["body"] - if "reason" in body: - reason = body["reason"] - self.assertNotEqual( - reason, "breakpoint", 'verify stop isn\'t "main" breakpoint' - ) + self.assertTrue( + len(self.dap_server.thread_stop_reasons) > 0, + "expected stopped event during launch", + ) + for _, body in self.dap_server.thread_stop_reasons.items(): + if "reason" in body: + reason = body["reason"] + self.assertNotEqual( + reason, "breakpoint", 'verify stop isn\'t "main" breakpoint' + ) # Then, if we continue, we should hit the breakpoint at main. - self.dap_server.request_continue() - self.verify_breakpoint_hit([bp_main]) + self.continue_to_breakpoints([bp_main]) # Restart and check that we still get a stopped event before reaching # main. - self.dap_server.request_restart() + resp = self.dap_server.request_restart() + self.assertTrue(resp["success"]) stopped_events = self.dap_server.wait_for_stopped() for stopped_event in stopped_events: if "body" in stopped_event: @@ -96,8 +95,7 @@ def test_arguments(self): [bp_A] = self.set_source_breakpoints("main.c", [line_A]) # Verify we hit A, then B. - self.dap_server.request_configurationDone() - self.verify_breakpoint_hit([bp_A]) + self.continue_to_breakpoints([bp_A]) # We don't set any arguments in the initial launch request, so argc # should be 1. @@ -109,7 +107,7 @@ def test_arguments(self): # Restart with some extra 'args' and check that the new argc reflects # the updated launch config. - self.dap_server.request_restart( + resp = self.dap_server.request_restart( restartArguments={ "arguments": { "program": program, @@ -117,6 +115,7 @@ def test_arguments(self): } } ) + self.assertTrue(resp["success"]) self.verify_breakpoint_hit([bp_A]) self.assertEqual( int(self.dap_server.get_local_variable_value("argc")), diff --git a/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py b/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py index 7e28a5af4331c..33e038408fa34 100644 --- a/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py +++ b/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py @@ -2,7 +2,6 @@ Test stop hooks """ - from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * import lldbdap_testcase @@ -17,10 +16,6 @@ def test_stop_hooks_before_run(self): program = self.getBuildArtifact("a.out") preRunCommands = ["target stop-hook add -o help"] self.build_and_launch(program, stopOnEntry=True, preRunCommands=preRunCommands) - - # The first stop is on entry. - self.dap_server.wait_for_stopped() - breakpoint_ids = self.set_function_breakpoints(["main"]) # This request hangs if the race happens, because, in that case, the # command interpreter is in synchronous mode while lldb-dap expects diff --git a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py index 296e4911f4052..340be0b39010d 100644 --- a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py +++ b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py @@ -116,7 +116,7 @@ def darwin_dwarf_missing_obj(self, initCommands): self.create_debug_adapter() self.assertTrue(os.path.exists(program), "executable must exist") - self.launch(program=program, initCommands=initCommands) + self.launch(program, initCommands=initCommands) functions = ["main"] breakpoint_ids = self.set_function_breakpoints(functions) diff --git a/lldb/tools/lldb-dap/DAPError.cpp b/lldb/tools/lldb-dap/DAPError.cpp index dcb955af0345f..60347d577f821 100644 --- a/lldb/tools/lldb-dap/DAPError.cpp +++ b/lldb/tools/lldb-dap/DAPError.cpp @@ -8,6 +8,7 @@ #include "DAPError.h" #include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" #include namespace lldb_dap { @@ -26,4 +27,12 @@ std::error_code DAPError::convertToErrorCode() const { return llvm::inconvertibleErrorCode(); } +char NotStoppedError::ID; + +void NotStoppedError::log(llvm::raw_ostream &OS) const { OS << "not stopped"; } + +std::error_code NotStoppedError::convertToErrorCode() const { + return llvm::inconvertibleErrorCode(); +} + } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/DAPError.h b/lldb/tools/lldb-dap/DAPError.h index 564651b1f587d..4c94bdd6ac3d6 100644 --- a/lldb/tools/lldb-dap/DAPError.h +++ b/lldb/tools/lldb-dap/DAPError.h @@ -13,7 +13,7 @@ namespace lldb_dap { -/// An Error that is reported as a DAP Error Message, which may be presented to +/// An error that is reported as a DAP Error Message, which may be presented to /// the user. class DAPError : public llvm::ErrorInfo { public: @@ -40,4 +40,13 @@ class DAPError : public llvm::ErrorInfo { std::optional m_url_label; }; +/// An error that indicates the current request handler cannot execute because +/// the process is not stopped. +class NotStoppedError : public llvm::ErrorInfo { +public: + static char ID; + void log(llvm::raw_ostream &OS) const override; + std::error_code convertToErrorCode() const override; +}; + } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/ContinueRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ContinueRequestHandler.cpp index ca4c9141eca38..361c86421cf1b 100644 --- a/lldb/tools/lldb-dap/Handler/ContinueRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/ContinueRequestHandler.cpp @@ -31,6 +31,9 @@ ContinueRequestHandler::Run(const ContinueArguments &args) const { SBProcess process = dap.target.GetProcess(); SBError error; + if (!SBDebugger::StateIsStoppedState(process.GetState())) + return make_error(); + if (args.singleThread) dap.GetLLDBThread(args.threadId).Resume(error); else @@ -40,7 +43,7 @@ ContinueRequestHandler::Run(const ContinueArguments &args) const { return ToError(error); ContinueResponseBody body; - body.allThreadsContinued = args.singleThread; + body.allThreadsContinued = !args.singleThread; return body; } diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index eaebaf6619bbd..383f9e24a729a 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -106,11 +106,13 @@ class RequestHandler : public BaseRequestHandler { DAP_LOG(dap.log, "({0}) malformed request {1}, expected arguments but got none", dap.transport.GetClientName(), request.command); - response.success = false; - response.message = llvm::formatv("arguments required for command '{0}' " - "but none received", - request.command) - .str(); + HandleErrorResponse( + llvm::make_error( + llvm::formatv("arguments required for command '{0}' " + "but none received", + request.command) + .str()), + response); dap.Send(response); return; } @@ -123,26 +125,21 @@ class RequestHandler : public BaseRequestHandler { OS << "invalid arguments for request '" << request.command << "': " << llvm::toString(root.getError()) << "\n"; root.printErrorContext(*request.arguments, OS); - - response.success = false; - response.body = ToResponse(llvm::make_error(parse_failure)); - + HandleErrorResponse(llvm::make_error(parse_failure), response); dap.Send(response); return; } if constexpr (std::is_same_v) { if (llvm::Error err = Run(arguments)) { - response.success = false; - response.body = ToResponse(std::move(err)); + HandleErrorResponse(std::move(err), response); } else { response.success = true; } } else { Resp body = Run(arguments); if (llvm::Error err = body.takeError()) { - response.success = false; - response.body = ToResponse(std::move(err)); + HandleErrorResponse(std::move(err), response); } else { response.success = true; response.body = std::move(*body); @@ -172,26 +169,36 @@ class RequestHandler : public BaseRequestHandler { /// error. virtual void PostRun() const {}; - protocol::ErrorResponseBody ToResponse(llvm::Error err) const { - protocol::ErrorMessage error_message; - // Default to showing the user errors unless otherwise specified by a - // DAPError. - error_message.showUser = true; - error_message.sendTelemetry = false; - if (llvm::Error unhandled = llvm::handleErrors( - std::move(err), [&](const DAPError &E) -> llvm::Error { - error_message.format = E.getMessage(); - error_message.showUser = E.getShowUser(); - error_message.id = E.convertToErrorCode().value(); - error_message.url = E.getURL(); - error_message.urlLabel = E.getURLLabel(); - return llvm::Error::success(); - })) { - error_message.format = llvm::toString(std::move(unhandled)); - } - protocol::ErrorResponseBody body; - body.error = error_message; - return body; + void HandleErrorResponse(llvm::Error err, + protocol::Response &response) const { + response.success = false; + llvm::handleAllErrors( + std::move(err), + [&](const NotStoppedError &err) { + response.message = lldb_dap::protocol::eResponseMessageNotStopped; + }, + [&](const DAPError &err) { + protocol::ErrorMessage error_message; + error_message.sendTelemetry = false; + error_message.format = err.getMessage(); + error_message.showUser = err.getShowUser(); + error_message.id = err.convertToErrorCode().value(); + error_message.url = err.getURL(); + error_message.urlLabel = err.getURLLabel(); + protocol::ErrorResponseBody body; + body.error = error_message; + response.body = body; + }, + [&](const llvm::ErrorInfoBase &err) { + protocol::ErrorMessage error_message; + error_message.showUser = true; + error_message.sendTelemetry = false; + error_message.format = err.message(); + error_message.id = err.convertToErrorCode().value(); + protocol::ErrorResponseBody body; + body.error = error_message; + response.body = body; + }); } }; From lldb-commits at lists.llvm.org Fri May 16 08:47:08 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 08:47:08 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adding additional asserts to unit tests. (PR #140107) In-Reply-To: Message-ID: <68275dfc.620a0220.17f7a1.1a57@mx.google.com> https://github.com/ashgti closed https://github.com/llvm/llvm-project/pull/140107 From lldb-commits at lists.llvm.org Fri May 16 08:57:26 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Fri, 16 May 2025 08:57:26 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Basic implementation of a deferred request. (PR #140260) In-Reply-To: Message-ID: <68276066.a70a0220.3aef75.253e@mx.google.com> https://github.com/JDevlieghere commented: I like the idea of making the request handlers responsible for telling us whether they should be deferred compared to the allow-list I implemented. That's definitely an improvement. What I don't like is how this introduces more statefulness, especially in the request handlers. The queueing/deferring logic isn't trivial and I would strongly prefer if we could keep it centralized as much as possible. With this PR we end up with both a separate queue and a method that makes the `Run` operation behaves differently depending on the global DAP state (i.e. if we've send the configuration request). Would it be possible to have the RequestHandlers advertise whether or not they should be deferred until the configuration is done (e.g. `DeferredUntilConfigurationDone`), and keep the latter an implementation detail of the DAP class? And strictly handle deferring at the queue level? PS: Small nit, but your PR is titled "Basic implementation of a deferred request." which isn't accurate because deferred requests are already implemented. A better title would be "Change the way we defer requests" or something similar. https://github.com/llvm/llvm-project/pull/140260 From lldb-commits at lists.llvm.org Fri May 16 09:09:54 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 09:09:54 -0700 (PDT) Subject: [Lldb-commits] [lldb] c72c0b2 - Fix race condition during iteration through modules (#139283) (#139862) Message-ID: <68276352.170a0220.72df3.2287@mx.google.com> Author: nd Date: 2025-05-16T09:09:50-07:00 New Revision: c72c0b298c13ebc4d374e84b8ea20f8ca4f5ace2 URL: https://github.com/llvm/llvm-project/commit/c72c0b298c13ebc4d374e84b8ea20f8ca4f5ace2 DIFF: https://github.com/llvm/llvm-project/commit/c72c0b298c13ebc4d374e84b8ea20f8ca4f5ace2.diff LOG: Fix race condition during iteration through modules (#139283) (#139862) Use the locking iterator to ensure module don't change during iteration. Added: Modified: lldb/source/Target/Target.cpp Removed: ################################################################################ diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 7f61f8689fb95..9660fc97970b0 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -1511,8 +1511,7 @@ bool Target::IgnoreWatchpointByID(lldb::watch_id_t watch_id, ModuleSP Target::GetExecutableModule() { // search for the first executable in the module list - for (size_t i = 0; i < m_images.GetSize(); ++i) { - ModuleSP module_sp = m_images.GetModuleAtIndex(i); + for (ModuleSP module_sp : m_images.Modules()) { lldb_private::ObjectFile *obj = module_sp->GetObjectFile(); if (obj == nullptr) continue; From lldb-commits at lists.llvm.org Fri May 16 09:09:57 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Fri, 16 May 2025 09:09:57 -0700 (PDT) Subject: [Lldb-commits] [lldb] Fix race condition during iteration through modules (#139283) (PR #139862) In-Reply-To: Message-ID: <68276355.170a0220.3a786b.32a6@mx.google.com> https://github.com/JDevlieghere closed https://github.com/llvm/llvm-project/pull/139862 From lldb-commits at lists.llvm.org Fri May 16 09:10:15 2025 From: lldb-commits at lists.llvm.org (Ilia Kuklin via lldb-commits) Date: Fri, 16 May 2025 09:10:15 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <68276367.170a0220.d5550.33a6@mx.google.com> ================ @@ -111,7 +111,42 @@ ASTNodeUP DILParser::ParseUnaryExpression() { llvm_unreachable("invalid token kind"); } } - return ParsePrimaryExpression(); + return ParsePostfixExpression(); +} + +// Parse a postfix_expression. +// +// postfix_expression: +// primary_expression +// postfix_expression "[" integer_literal "]" +// +ASTNodeUP DILParser::ParsePostfixExpression() { + ASTNodeUP lhs = ParsePrimaryExpression(); + while (CurToken().Is(Token::l_square)) { + uint32_t loc = CurToken().GetLocation(); + Token token = CurToken(); + switch (token.GetKind()) { + case Token::l_square: { + m_dil_lexer.Advance(); + auto rhs = ParseIntegerConstant(); ---------------- kuilpd wrote: I see, thank you! https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Fri May 16 09:10:16 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 09:10:16 -0700 (PDT) Subject: [Lldb-commits] [lldb] Fix race condition during iteration through modules (#139283) (PR #139862) In-Reply-To: Message-ID: <68276368.170a0220.2d0568.1c71@mx.google.com> github-actions[bot] wrote: @nd Congratulations on having your first Pull Request (PR) merged into the LLVM Project! Your changes will be combined with recent changes from other authors, then tested by our [build bots](https://lab.llvm.org/buildbot/). If there is a problem with a build, you may receive a report in an email or a comment on this PR. Please check whether problems have been caused by your change specifically, as the builds can include changes from many authors. It is not uncommon for your change to be included in a build that fails due to someone else's changes, or infrastructure issues. How to do this, and the rest of the post-merge process, is covered in detail [here](https://llvm.org/docs/MyFirstTypoFix.html#myfirsttypofix-issues-after-landing-your-pr). If your change does cause a problem, it may be reverted, or you can revert it yourself. This is a normal part of [LLVM development](https://llvm.org/docs/DeveloperPolicy.html#patch-reversion-policy). You can fix your changes and open a new PR to merge them again. If you don't get any reports, no action is required from you. Your changes are working as expected, well done! https://github.com/llvm/llvm-project/pull/139862 From lldb-commits at lists.llvm.org Fri May 16 09:10:31 2025 From: lldb-commits at lists.llvm.org (Ilia Kuklin via lldb-commits) Date: Fri, 16 May 2025 09:10:31 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <68276377.170a0220.103500.3582@mx.google.com> https://github.com/kuilpd updated https://github.com/llvm/llvm-project/pull/138551 Rate limit · GitHub

Whoa there!

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

From lldb-commits at lists.llvm.org Fri May 16 09:13:13 2025 From: lldb-commits at lists.llvm.org (Ilia Kuklin via lldb-commits) Date: Fri, 16 May 2025 09:13:13 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add array subscription and integer parsing to DIL (PR #138551) In-Reply-To: Message-ID: <68276419.630a0220.e5cdf.6944@mx.google.com> ================ @@ -272,4 +272,67 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +llvm::Expected +Interpreter::Visit(const ArraySubscriptNode *node) { + auto lhs_or_err = Evaluate(node->GetBase()); + if (!lhs_or_err) { + return lhs_or_err; + } + lldb::ValueObjectSP base = *lhs_or_err; + const llvm::APInt *index = node->GetIndex(); + + Status error; + if (base->GetCompilerType().IsReferenceType()) { + base = base->Dereference(error); + if (error.Fail()) + return error.ToError(); + } + + // Check to see if 'base' has a synthetic value; if so, try using that. + uint64_t child_idx = index->getZExtValue(); + if (base->HasSyntheticValue()) { + lldb::ValueObjectSP synthetic = base->GetSyntheticValue(); + if (synthetic && synthetic != base) { + uint32_t num_children = synthetic->GetNumChildrenIgnoringErrors(); ---------------- kuilpd wrote: > Is it possible that some (simple) data formatter implements GetChildAtIndex as return foo without checking whether the index argument is in range? One thing I can add that I noticed: that code worked when I tried it from console lldb, but didn't work on the same executable and input string when called from Python tests. I'm not sure why. I changed the call to `GetNumChildren`, I think I'd prefer a vector telling me that I'm out of bounds instead of returning 0 like it's a correct value from the vector. https://github.com/llvm/llvm-project/pull/138551 From lldb-commits at lists.llvm.org Fri May 16 09:23:39 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 09:23:39 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Listen for broadcast classes. (PR #140142) In-Reply-To: Message-ID: <6827668b.170a0220.154d9.2182@mx.google.com> ashgti wrote: > Is it possible to delay _setting_ the breakpoint until we know what the target is? Or will that be a problem because attach/launchCommands will already resume the process? Could we require that the target is created inside `preRunCommands` or `initCommands`? Previously, we would handle the `launch`/`attach` request when it arrived, which meant we'd have a target configured by the time the `setBreakpoint` request was called. Also previously, we would leave the process in a stopped state until the `configurationDone` request was sent. #138219 adjusted that to delay handling the `launch`/`attach` until we get the configuration done. https://discourse.llvm.org/t/reliability-of-the-lldb-dap-tests/86125 has some background on that change. During the startup flow we do need to reply to the `setBreakpoint` requests before VSCode will send the `configurationDone`. We could just mark the breakpoints as unverified and not 'really' set them until we finish launching. That could also work around this issue. > Can we use the selected target until we've decided on the dap target? I guess that still leaves the possibility that the launch commands create multiple targets and that you temporarily see events belonging to the wrong target before another target was selected, but I'm not sure how to avoid that. Unless there's a way to queue up events? I'd need to look at the code in more detail to figure out how that works exactly (or ask @jimingham). Another possible way to handle this would be to iterate over the known breakpoints after the `attachCommands`/`launchCommands` have finished and check if we need to update the breakpoint state. For reference, our launch flow we use is roughly: ```jsonc { "type": "lldb-dap", "request": "launch", "name": "...", "initCommands": [ "command source config/lldbinit" // loads python scripts with additional helpers ], "launchCommands": [ "!launch --device bazel-bin/path/to/ios_app.ipa" ], "preLaunchTask": "bazel build //path/to:ios_app" }, ``` The python script is doing roughly: * unzipping the ipa * running `simctl install` / `devicectl install` * `debugger.CreateTarget('', '', '', True)` * `simctl launch --wait-for-debugger` / `devicectl device process launch --start-stopped` * `debugger.GetSelectedTarget().AttachToProcessWithID()` https://github.com/llvm/llvm-project/pull/140142 From lldb-commits at lists.llvm.org Fri May 16 09:25:07 2025 From: lldb-commits at lists.llvm.org (Jacob Lalonde via lldb-commits) Date: Fri, 16 May 2025 09:25:07 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB][Progress-On-Dap] Have indeterminate progress actually send events. (PR #140162) In-Reply-To: Message-ID: <682766e3.630a0220.3c230f.753f@mx.google.com> ================ @@ -77,16 +77,19 @@ ProgressEvent::Create(uint64_t progress_id, std::optional message, if (event.GetEventType() == progressStart && event.GetEventName().empty()) return std::nullopt; - if (prev_event && prev_event->EqualsForIDE(event)) + if (prev_event && prev_event->EqualsForIDE(event, total)) return std::nullopt; return event; } -bool ProgressEvent::EqualsForIDE(const ProgressEvent &other) const { +bool ProgressEvent::EqualsForIDE(const ProgressEvent &other, uint64_t total) const { return m_progress_id == other.m_progress_id && - m_event_type == other.m_event_type && - m_percentage == other.m_percentage; + m_event_type == other.m_event_type && + // If we check the percentage of a non-deterministic event ---------------- Jlalond wrote: You're correct, but then we'd be comparing if `null_opt == null_opt`, and no further updates would be sent. I overlooked this when adding the total, we should short circuit and ignore the percentage if percentage is a null opt. https://github.com/llvm/llvm-project/pull/140162 From lldb-commits at lists.llvm.org Fri May 16 09:39:05 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 09:39:05 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB][Progress-On-Dap] Have indeterminate progress actually send events. (PR #140162) In-Reply-To: Message-ID: <68276a29.050a0220.108903.3dc1@mx.google.com> ================ @@ -77,16 +77,19 @@ ProgressEvent::Create(uint64_t progress_id, std::optional message, if (event.GetEventType() == progressStart && event.GetEventName().empty()) return std::nullopt; - if (prev_event && prev_event->EqualsForIDE(event)) + if (prev_event && prev_event->EqualsForIDE(event, total)) return std::nullopt; return event; } -bool ProgressEvent::EqualsForIDE(const ProgressEvent &other) const { +bool ProgressEvent::EqualsForIDE(const ProgressEvent &other, uint64_t total) const { return m_progress_id == other.m_progress_id && - m_event_type == other.m_event_type && - m_percentage == other.m_percentage; + m_event_type == other.m_event_type && + // If we check the percentage of a non-deterministic event ---------------- ashgti wrote: But won't they have different event types if its changed? For a non-determinitic progress event, it should only go from `m_event_type == progressStart` to `m_event_type == progressEnd`, right? If we have 2 starts or 2 ends that feels like the logic got mixed up somewhere else, right? https://github.com/llvm/llvm-project/pull/140162 From lldb-commits at lists.llvm.org Fri May 16 09:54:18 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 09:54:18 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Listen for broadcast classes. (PR #140142) In-Reply-To: Message-ID: <68276dba.a70a0220.248a06.4013@mx.google.com> ashgti wrote: Okay, to summarize my previous comment, I think we could address this in the following ways: 1. Listen for the broadcast class instead of a specific broadcaster. The downside here is we may see events for targets/processes we're not directly interested in. 1. In the setBreakpoint (and friends) functions, delay actually setting the breakpoint until after configuration. The downside here is the added complexity to our startup flow. 1. After `launchCommands`/`attachCommands`, check the existing breakpoints and update the state. The downside here is ensuring we've correctly checked all stateful values after the launch is complete. https://github.com/llvm/llvm-project/pull/140142 From lldb-commits at lists.llvm.org Fri May 16 10:31:15 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Fri, 16 May 2025 10:31:15 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Basic implementation of a deferred request. (PR #140260) In-Reply-To: Message-ID: <68277663.050a0220.30f7ac.588f@mx.google.com> da-viper wrote: > Would it be possible to have the RequestHandlers advertise whether or not they should be deferred until the configuration is done (e.g. DeferredUntilConfigurationDone), and keep the latter an implementation detail of the DAP class? And strictly handle deferring at the queue level? Yes it can, > What I don't like is how this introduces more statefulness, especially in the request handlers. The queueing/deferring logic isn't trivial and I would strongly prefer if we could keep it centralized as much as possible. With this PR we end up with both a separate queue and a method that makes the Run operation behaves differently depending on the global DAP state (i.e. if we've send the configuration request). The plan is to partially resolve the request and then completing the request later on. for example. with the launch argument, the new method will be `optional DeferUntilConfig( const Arguments &arguments, bool &defer_request)` ```cpp std::optional LaunchRequestHandler::DeferUntilConfig( const LaunchRequestArguments &arguments, bool &defer_request) const { // setups the target and initcommands. if (LaunchResponse err = PreLaunch(arguments)) { return err; } defer_request = !dap.configuration_done; return std::nullopt; } ``` since this it is then deferred it will then complete the remaining request after the configuration is done. like so ```cpp Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const { if (Error err = dap.RunPreRunCommands()) return err; if (Error err = LaunchProcess(arguments)) return err; dap.RunPostRunCommands(); return Error::success(); } ``` The could potentially fix the breakpoints problem and also launch after configuration. Not 100% sure this is the best way hence why I have not included the commit. https://github.com/llvm/llvm-project/pull/140260 From lldb-commits at lists.llvm.org Fri May 16 11:05:34 2025 From: lldb-commits at lists.llvm.org (Jacob Lalonde via lldb-commits) Date: Fri, 16 May 2025 11:05:34 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB][Progress-On-Dap] Have indeterminate progress actually send events. (PR #140162) In-Reply-To: Message-ID: <68277e6e.170a0220.33cc7b.50cc@mx.google.com> ================ @@ -77,16 +77,19 @@ ProgressEvent::Create(uint64_t progress_id, std::optional message, if (event.GetEventType() == progressStart && event.GetEventName().empty()) return std::nullopt; - if (prev_event && prev_event->EqualsForIDE(event)) + if (prev_event && prev_event->EqualsForIDE(event, total)) return std::nullopt; return event; } -bool ProgressEvent::EqualsForIDE(const ProgressEvent &other) const { +bool ProgressEvent::EqualsForIDE(const ProgressEvent &other, uint64_t total) const { return m_progress_id == other.m_progress_id && - m_event_type == other.m_event_type && - m_percentage == other.m_percentage; + m_event_type == other.m_event_type && + // If we check the percentage of a non-deterministic event ---------------- Jlalond wrote: First, let me apologize for being overly brief in my explanation. You're correct @ashgti, but now imagine all the updates. Let's say we're indexing dwarf, you'll get the start, *the first update* and then the end. As an extreme hypothetical, if this takes 30 minutes you will have 0 progress actually sent to the progress bar in VSCode resulting in what appears to be a hang of LLDB. So, for non-deterministic events we want to update for every time window. DAP limits to 250 ms, which I think is fine. I might need to change the equals check now that I spell this out but I hope this explains the intent! https://github.com/llvm/llvm-project/pull/140162 From lldb-commits at lists.llvm.org Fri May 16 12:07:16 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 12:07:16 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adjusting startup flow to better handle async operations. (PR #140299) Message-ID: https://github.com/ashgti created https://github.com/llvm/llvm-project/pull/140299 This introduces an `AsyncRequestHandler` and partially reverse the changes from ba29e60f9a2222bd5e883579bb78db13fc5a7588 in that the `launch` and `attach` commands now run when we receive them. We wait to send the reply until we get the `configurationDone` request. >From 59aadc0f2b61a39563269329d10c553f7965c70b Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 16 May 2025 12:03:50 -0700 Subject: [PATCH] [lldb-dap] Adjusting startup flow to better handle async operations. This introduces an `AsyncRequestHandler` and partially reverse the changes from ba29e60f9a2222bd5e883579bb78db13fc5a7588 in that the `launch` and `attach` commands now run when we receive them. We wait to send the reply until we get the `configurationDone` request. --- lldb/tools/lldb-dap/DAP.cpp | 49 ++--- lldb/tools/lldb-dap/DAP.h | 22 ++- lldb/tools/lldb-dap/EventHelper.cpp | 2 +- .../lldb-dap/Handler/AttachRequestHandler.cpp | 69 +++---- .../lldb-dap/Handler/LaunchRequestHandler.cpp | 61 +++---- .../tools/lldb-dap/Handler/RequestHandler.cpp | 31 ++++ lldb/tools/lldb-dap/Handler/RequestHandler.h | 168 +++++++++++------- 7 files changed, 241 insertions(+), 161 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 56a0c38b00037..416661e98c21f 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -120,11 +120,12 @@ DAP::DAP(Log *log, const ReplMode default_repl_mode, : log(log), transport(transport), broadcaster("lldb-dap"), exception_breakpoints(), focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false), - restarting_process_id(LLDB_INVALID_PROCESS_ID), configuration_done(false), + restarting_process_id(LLDB_INVALID_PROCESS_ID), waiting_for_run_in_terminal(false), progress_event_reporter( [&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }), - reverse_request_seq(0), repl_mode(default_repl_mode) { + reverse_request_seq(0), repl_mode(default_repl_mode), + m_configuration_done(false) { configuration.preInitCommands = std::move(pre_init_commands); RegisterRequests(); } @@ -916,20 +917,10 @@ llvm::Error DAP::Loop() { return errWrapper; } - // The launch sequence is special and we need to carefully handle - // packets in the right order. Until we've handled configurationDone, - bool add_to_pending_queue = false; - if (const protocol::Request *req = - std::get_if(&*next)) { - llvm::StringRef command = req->command; - if (command == "disconnect") - disconnecting = true; - if (!configuration_done) - add_to_pending_queue = - command != "initialize" && command != "configurationDone" && - command != "disconnect" && !command.ends_with("Breakpoints"); - } + std::get_if(&*next); + req && req->command == "disconnect") + disconnecting = true; const std::optional cancel_args = getArgumentsIfRequest(*next, "cancel"); @@ -956,8 +947,7 @@ llvm::Error DAP::Loop() { { std::lock_guard guard(m_queue_mutex); - auto &queue = add_to_pending_queue ? m_pending_queue : m_queue; - queue.push_back(std::move(*next)); + m_queue.push_back(std::move(*next)); } m_queue_cv.notify_one(); } @@ -1255,14 +1245,25 @@ void DAP::SetConfiguration(const protocol::Configuration &config, SetThreadFormat(*configuration.customThreadFormat); } +bool DAP::GetConfigurationDone() { + std::lock_guard guard(m_configuration_done_mutex); + return m_configuration_done; +} + void DAP::SetConfigurationDone() { - { - std::lock_guard guard(m_queue_mutex); - std::copy(m_pending_queue.begin(), m_pending_queue.end(), - std::front_inserter(m_queue)); - configuration_done = true; - } - m_queue_cv.notify_all(); + std::lock_guard guard(m_configuration_done_mutex); + m_configuration_done = true; + for (auto &cb : m_configuration_done_callbacks) + cb(); + m_configuration_done_callbacks.clear(); +} + +void DAP::OnConfigurationDone(llvm::unique_function &&callback) { + std::lock_guard guard(m_configuration_done_mutex); + if (m_configuration_done) + callback(); + else + m_configuration_done_callbacks.emplace_back(std::move(callback)); } void DAP::SetFrameFormat(llvm::StringRef format) { diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c1a1130b1e59f..4d170ba4ec920 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -187,7 +187,6 @@ struct DAP { // shutting down the entire adapter. When we're restarting, we keep the id of // the old process here so we can detect this case and keep running. lldb::pid_t restarting_process_id; - bool configuration_done; bool waiting_for_run_in_terminal; ProgressEventReporter progress_event_reporter; // Keep track of the last stop thread index IDs as threads won't go away @@ -257,14 +256,26 @@ struct DAP { /// Configures the debug adapter for launching/attaching. void SetConfiguration(const protocol::Configuration &confing, bool is_attach); + /// Returns true if the debug session has received the `configurationDone` + /// request. + bool GetConfigurationDone(); + + /// Marks that the debug session has received the `configurationDone` request. void SetConfigurationDone(); + /// Registers a callback that is fired after `configurationDone` is received. + /// + /// NOTE: If `configurationDone` has already been received, the callback will + /// be invoked immediately. + void OnConfigurationDone(llvm::unique_function &&callback); + /// Configure source maps based on the current `DAPConfiguration`. void ConfigureSourceMaps(); /// Serialize the JSON value into a string and send the JSON packet to the /// "out" stream. void SendJSON(const llvm::json::Value &json); + /// Send the given message to the client void Send(const protocol::Message &message); @@ -336,7 +347,7 @@ struct DAP { lldb::SBTarget CreateTarget(lldb::SBError &error); /// Set given target object as a current target for lldb-dap and start - /// listeing for its breakpoint events. + /// listening for its breakpoint events. void SetTarget(const lldb::SBTarget target); bool HandleObject(const protocol::Message &M); @@ -377,7 +388,7 @@ struct DAP { }); } - /// The set of capablities supported by this adapter. + /// The set of capabilities supported by this adapter. protocol::Capabilities GetCapabilities(); /// Debuggee will continue from stopped state. @@ -444,13 +455,16 @@ struct DAP { /// Queue for all incoming messages. std::deque m_queue; - std::deque m_pending_queue; std::mutex m_queue_mutex; std::condition_variable m_queue_cv; std::mutex m_cancelled_requests_mutex; llvm::SmallSet m_cancelled_requests; + std::mutex m_configuration_done_mutex; + bool m_configuration_done; + std::vector> m_configuration_done_callbacks; + std::mutex m_active_request_mutex; const protocol::Request *m_active_request; }; diff --git a/lldb/tools/lldb-dap/EventHelper.cpp b/lldb/tools/lldb-dap/EventHelper.cpp index ed2d8700c26b0..e62f1d61a3d22 100644 --- a/lldb/tools/lldb-dap/EventHelper.cpp +++ b/lldb/tools/lldb-dap/EventHelper.cpp @@ -222,7 +222,7 @@ void SendContinuedEvent(DAP &dap) { // If the focus thread is not set then we haven't reported any thread status // to the client, so nothing to report. - if (!dap.configuration_done || dap.focus_tid == LLDB_INVALID_THREAD_ID) { + if (!dap.GetConfigurationDone() || dap.focus_tid == LLDB_INVALID_THREAD_ID) { return; } diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp index 0293ffbd0c922..c4f1ad084b4e7 100644 --- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp @@ -28,21 +28,22 @@ namespace lldb_dap { /// /// Since attaching is debugger/runtime specific, the arguments for this request /// are not part of this specification. -Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { +void AttachRequestHandler::Run(const AttachRequestArguments &args, + Reply reply) const { // Validate that we have a well formed attach request. if (args.attachCommands.empty() && args.coreFile.empty() && args.configuration.program.empty() && args.pid == LLDB_INVALID_PROCESS_ID && args.gdbRemotePort == LLDB_DAP_INVALID_PORT) - return make_error( + return reply(make_error( "expected one of 'pid', 'program', 'attachCommands', " - "'coreFile' or 'gdb-remote-port' to be specified"); + "'coreFile' or 'gdb-remote-port' to be specified")); // Check if we have mutually exclusive arguments. if ((args.pid != LLDB_INVALID_PROCESS_ID) && (args.gdbRemotePort != LLDB_DAP_INVALID_PORT)) - return make_error( - "'pid' and 'gdb-remote-port' are mutually exclusive"); + return reply(make_error( + "'pid' and 'gdb-remote-port' are mutually exclusive")); dap.SetConfiguration(args.configuration, /*is_attach=*/true); if (!args.coreFile.empty()) @@ -59,20 +60,20 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { // Run any initialize LLDB commands the user specified in the launch.json if (llvm::Error err = dap.RunInitCommands()) - return err; + return reply(std::move(err)); dap.ConfigureSourceMaps(); lldb::SBError error; lldb::SBTarget target = dap.CreateTarget(error); if (error.Fail()) - return ToError(error); + return reply(ToError(error)); dap.SetTarget(target); // Run any pre run LLDB commands the user specified in the launch.json if (Error err = dap.RunPreRunCommands()) - return err; + return reply(std::move(err)); if ((args.pid == LLDB_INVALID_PROCESS_ID || args.gdbRemotePort == LLDB_DAP_INVALID_PORT) && @@ -94,14 +95,14 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { // user that their command failed or the debugger is in an unexpected // state. if (llvm::Error err = dap.RunAttachCommands(args.attachCommands)) - return err; + return reply(std::move(err)); dap.target = dap.debugger.GetSelectedTarget(); // Validate the attachCommand results. if (!dap.target.GetProcess().IsValid()) - return make_error( - "attachCommands failed to attach to a process"); + return reply(make_error( + "attachCommands failed to attach to a process")); } else if (!args.coreFile.empty()) { dap.target.LoadCore(args.coreFile.data(), error); } else if (args.gdbRemotePort != LLDB_DAP_INVALID_PORT) { @@ -129,35 +130,35 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { // Make sure the process is attached and stopped. error = dap.WaitForProcessToStop(args.configuration.timeout); if (error.Fail()) - return ToError(error); + return reply(ToError(error)); if (args.coreFile.empty() && !dap.target.GetProcess().IsValid()) - return make_error("failed to attach to process"); + return reply(make_error("failed to attach to process")); dap.RunPostRunCommands(); - return Error::success(); -} + dap.OnConfigurationDone([&, reply = std::move(reply)]() { + reply(Error::success()); + + if (!dap.target.GetProcess().IsValid()) + return; + + // Clients can request a baseline of currently existing threads after + // we acknowledge the configurationDone request. + // Client requests the baseline of currently existing threads after + // a successful or attach by sending a 'threads' request + // right after receiving the configurationDone response. + // Obtain the list of threads before we resume the process + dap.initial_thread_list = + GetThreads(dap.target.GetProcess(), dap.thread_format); + + SendProcessEvent(dap, Attach); -void AttachRequestHandler::PostRun() const { - if (!dap.target.GetProcess().IsValid()) - return; - - // Clients can request a baseline of currently existing threads after - // we acknowledge the configurationDone request. - // Client requests the baseline of currently existing threads after - // a successful or attach by sending a 'threads' request - // right after receiving the configurationDone response. - // Obtain the list of threads before we resume the process - dap.initial_thread_list = - GetThreads(dap.target.GetProcess(), dap.thread_format); - - SendProcessEvent(dap, Attach); - - if (dap.stop_at_entry) - SendThreadStoppedEvent(dap); - else - dap.target.GetProcess().Continue(); + if (dap.stop_at_entry) + SendThreadStoppedEvent(dap); + else + dap.target.GetProcess().Continue(); + }); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp index 22d1a090187d8..d963f62dee4f4 100644 --- a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp @@ -21,11 +21,12 @@ using namespace lldb_dap::protocol; namespace lldb_dap { /// Launch request; value of command field is 'launch'. -Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const { +void LaunchRequestHandler::Run(const LaunchRequestArguments &arguments, + Reply reply) const { // Validate that we have a well formed launch request. if (!arguments.launchCommands.empty() && arguments.runInTerminal) - return make_error( - "'launchCommands' and 'runInTerminal' are mutually exclusive"); + return reply(make_error( + "'launchCommands' and 'runInTerminal' are mutually exclusive")); dap.SetConfiguration(arguments.configuration, /*is_attach=*/false); dap.last_launch_request = arguments; @@ -43,49 +44,49 @@ Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const { // This is run before target is created, so commands can't do anything with // the targets - preRunCommands are run with the target. if (Error err = dap.RunInitCommands()) - return err; + return reply(std::move(err)); dap.ConfigureSourceMaps(); lldb::SBError error; lldb::SBTarget target = dap.CreateTarget(error); if (error.Fail()) - return ToError(error); + return reply(ToError(error)); dap.SetTarget(target); // Run any pre run LLDB commands the user specified in the launch.json if (Error err = dap.RunPreRunCommands()) - return err; + return reply(std::move(err)); if (Error err = LaunchProcess(arguments)) - return err; + return reply(std::move(err)); dap.RunPostRunCommands(); - return Error::success(); -} - -void LaunchRequestHandler::PostRun() const { - if (!dap.target.GetProcess().IsValid()) - return; - - // Clients can request a baseline of currently existing threads after - // we acknowledge the configurationDone request. - // Client requests the baseline of currently existing threads after - // a successful or attach by sending a 'threads' request - // right after receiving the configurationDone response. - // Obtain the list of threads before we resume the process - dap.initial_thread_list = - GetThreads(dap.target.GetProcess(), dap.thread_format); - - // Attach happens when launching with runInTerminal. - SendProcessEvent(dap, dap.is_attach ? Attach : Launch); - - if (dap.stop_at_entry) - SendThreadStoppedEvent(dap); - else - dap.target.GetProcess().Continue(); + dap.OnConfigurationDone([&, reply = std::move(reply)]() { + reply(Error::success()); + + if (!dap.target.GetProcess().IsValid()) + return; + + // Clients can request a baseline of currently existing threads after + // we acknowledge the configurationDone request. + // Client requests the baseline of currently existing threads after + // a successful or attach by sending a 'threads' request + // right after receiving the configurationDone response. + // Obtain the list of threads before we resume the process + dap.initial_thread_list = + GetThreads(dap.target.GetProcess(), dap.thread_format); + + // Attach happens when launching with runInTerminal. + SendProcessEvent(dap, dap.is_attach ? Attach : Launch); + + if (dap.stop_at_entry) + SendThreadStoppedEvent(dap); + else + dap.target.GetProcess().Continue(); + }); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp index 93bc80a38e29d..063f613711f61 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp @@ -126,6 +126,37 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) { error.GetCString()); } +void HandleErrorResponse(llvm::Error err, protocol::Response &response) { + response.success = false; + llvm::handleAllErrors( + std::move(err), + [&](const NotStoppedError &err) { + response.message = lldb_dap::protocol::eResponseMessageNotStopped; + }, + [&](const DAPError &err) { + protocol::ErrorMessage error_message; + error_message.sendTelemetry = false; + error_message.format = err.getMessage(); + error_message.showUser = err.getShowUser(); + error_message.id = err.convertToErrorCode().value(); + error_message.url = err.getURL(); + error_message.urlLabel = err.getURLLabel(); + protocol::ErrorResponseBody body; + body.error = error_message; + response.body = body; + }, + [&](const llvm::ErrorInfoBase &err) { + protocol::ErrorMessage error_message; + error_message.showUser = true; + error_message.sendTelemetry = false; + error_message.format = err.message(); + error_message.id = err.convertToErrorCode().value(); + protocol::ErrorResponseBody body; + body.error = error_message; + response.body = body; + }); +} + void BaseRequestHandler::Run(const Request &request) { // If this request was cancelled, send a cancelled response. if (dap.IsCancelled(request)) { diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 383f9e24a729a..f7902592b572b 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -32,6 +32,35 @@ inline constexpr bool is_optional_v = is_optional::value; namespace lldb_dap { struct DAP; +void HandleErrorResponse(llvm::Error err, protocol::Response &response); +template +llvm::Expected parseArgs(const protocol::Request &request) { + protocol::Response response; + response.request_seq = request.seq; + response.command = request.command; + + if (!is_optional_v && !request.arguments) { + return llvm::make_error( + llvm::formatv("arguments required for command '{0}' " + "but none received", + request.command) + .str()); + } + + Args arguments; + llvm::json::Path::Root root("arguments"); + if (request.arguments && !fromJSON(*request.arguments, arguments, root)) { + std::string parse_failure; + llvm::raw_string_ostream OS(parse_failure); + OS << "invalid arguments for request '" << request.command + << "': " << llvm::toString(root.getError()) << "\n"; + root.printErrorContext(*request.arguments, OS); + return llvm::make_error(parse_failure); + } + + return arguments; +} + /// Base class for request handlers. Do not extend this directly: Extend /// the RequestHandler template subclass instead. class BaseRequestHandler { @@ -102,42 +131,21 @@ class RequestHandler : public BaseRequestHandler { response.request_seq = request.seq; response.command = request.command; - if (!is_optional_v && !request.arguments) { - DAP_LOG(dap.log, - "({0}) malformed request {1}, expected arguments but got none", - dap.transport.GetClientName(), request.command); - HandleErrorResponse( - llvm::make_error( - llvm::formatv("arguments required for command '{0}' " - "but none received", - request.command) - .str()), - response); - dap.Send(response); - return; - } - - Args arguments; - llvm::json::Path::Root root("arguments"); - if (request.arguments && !fromJSON(*request.arguments, arguments, root)) { - std::string parse_failure; - llvm::raw_string_ostream OS(parse_failure); - OS << "invalid arguments for request '" << request.command - << "': " << llvm::toString(root.getError()) << "\n"; - root.printErrorContext(*request.arguments, OS); - HandleErrorResponse(llvm::make_error(parse_failure), response); + llvm::Expected arguments = parseArgs(request); + if (llvm::Error err = arguments.takeError()) { + HandleErrorResponse(std::move(err), response); dap.Send(response); return; } if constexpr (std::is_same_v) { - if (llvm::Error err = Run(arguments)) { + if (llvm::Error err = Run(*arguments)) { HandleErrorResponse(std::move(err), response); } else { response.success = true; } } else { - Resp body = Run(arguments); + Resp body = Run(*arguments); if (llvm::Error err = body.takeError()) { HandleErrorResponse(std::move(err), response); } else { @@ -168,48 +176,73 @@ class RequestHandler : public BaseRequestHandler { /// *NOTE*: PostRun will be invoked even if the `Run` operation returned an /// error. virtual void PostRun() const {}; +}; - void HandleErrorResponse(llvm::Error err, - protocol::Response &response) const { - response.success = false; - llvm::handleAllErrors( - std::move(err), - [&](const NotStoppedError &err) { - response.message = lldb_dap::protocol::eResponseMessageNotStopped; - }, - [&](const DAPError &err) { - protocol::ErrorMessage error_message; - error_message.sendTelemetry = false; - error_message.format = err.getMessage(); - error_message.showUser = err.getShowUser(); - error_message.id = err.convertToErrorCode().value(); - error_message.url = err.getURL(); - error_message.urlLabel = err.getURLLabel(); - protocol::ErrorResponseBody body; - body.error = error_message; - response.body = body; - }, - [&](const llvm::ErrorInfoBase &err) { - protocol::ErrorMessage error_message; - error_message.showUser = true; - error_message.sendTelemetry = false; - error_message.format = err.message(); - error_message.id = err.convertToErrorCode().value(); - protocol::ErrorResponseBody body; - body.error = error_message; - response.body = body; - }); - } +/// A Reply is a void function that accepts a reply to an async request. +template using Reply = llvm::unique_function; + +/// Base class for handling DAP requests. Handlers should declare their +/// arguments and response body types like: +/// +/// class MyRequestHandler : public RequestHandler { +/// .... +/// }; +template +class AsyncRequestHandler : public BaseRequestHandler { + using BaseRequestHandler::BaseRequestHandler; + + void operator()(const protocol::Request &request) const override { + llvm::Expected arguments = parseArgs(request); + if (llvm::Error err = arguments.takeError()) { + protocol::Response response; + response.request_seq = request.seq; + response.command = request.command; + HandleErrorResponse(std::move(err), response); + dap.Send(response); + return; + } + + Run(*arguments, [&, request = std::move(request)](Resp body) { + protocol::Response response; + response.request_seq = request.seq; + response.command = request.command; + if constexpr (std::is_same_v) { + if (body) { + HandleErrorResponse(std::move(body), response); + } else { + response.success = true; + } + } else { + if (llvm::Error err = body.takeError()) { + HandleErrorResponse(std::move(err), response); + } else { + response.success = true; + response.body = std::move(*body); + } + } + + // Mark the request as 'cancelled' if the debugger was interrupted while + // evaluating this handler. + if (dap.debugger.InterruptRequested()) { + response.success = false; + response.message = protocol::eResponseMessageCancelled; + response.body = std::nullopt; + } + dap.Send(response); + }); + }; + + virtual void Run(const Args &, Reply) const = 0; }; class AttachRequestHandler - : public RequestHandler { + : public AsyncRequestHandler { public: - using RequestHandler::RequestHandler; + using AsyncRequestHandler::AsyncRequestHandler; static llvm::StringLiteral GetCommand() { return "attach"; } - llvm::Error Run(const protocol::AttachRequestArguments &args) const override; - void PostRun() const override; + void Run(const protocol::AttachRequestArguments &args, + Reply reply) const override; }; class BreakpointLocationsRequestHandler @@ -301,14 +334,13 @@ class InitializeRequestHandler }; class LaunchRequestHandler - : public RequestHandler { + : public AsyncRequestHandler { public: - using RequestHandler::RequestHandler; + using AsyncRequestHandler::AsyncRequestHandler; static llvm::StringLiteral GetCommand() { return "launch"; } - llvm::Error - Run(const protocol::LaunchRequestArguments &arguments) const override; - void PostRun() const override; + void Run(const protocol::LaunchRequestArguments &arguments, + Reply) const override; }; class RestartRequestHandler : public LegacyRequestHandler { From lldb-commits at lists.llvm.org Fri May 16 12:08:42 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 12:08:42 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adjusting startup flow to better handle async operations. (PR #140299) In-Reply-To: Message-ID: <68278d3a.a70a0220.1fec6a.62fe@mx.google.com> ashgti wrote: @JDevlieghere @da-viper I think this may work to resolve https://github.com/llvm/llvm-project/issues/140154 and the underlying issue I saw in #140142 without needing to change our broadcaster. Leaving as a draft for now, but all the tests are passing with this change. https://github.com/llvm/llvm-project/pull/140299 From lldb-commits at lists.llvm.org Fri May 16 12:18:26 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Fri, 16 May 2025 12:18:26 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adjusting startup flow to better handle async operations. (PR #140299) In-Reply-To: Message-ID: <68278f82.620a0220.16777b.7055@mx.google.com> da-viper wrote: @ashgti please could you rebase the branch as there is some risv commit that failed on the CI, will test it over the weekend. https://github.com/llvm/llvm-project/pull/140299 From lldb-commits at lists.llvm.org Fri May 16 12:19:09 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 12:19:09 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adjusting startup flow to better handle async operations. (PR #140299) In-Reply-To: Message-ID: <68278fad.050a0220.142de5.7176@mx.google.com> https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/140299 >From 59aadc0f2b61a39563269329d10c553f7965c70b Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 16 May 2025 12:03:50 -0700 Subject: [PATCH] [lldb-dap] Adjusting startup flow to better handle async operations. This introduces an `AsyncRequestHandler` and partially reverse the changes from ba29e60f9a2222bd5e883579bb78db13fc5a7588 in that the `launch` and `attach` commands now run when we receive them. We wait to send the reply until we get the `configurationDone` request. --- lldb/tools/lldb-dap/DAP.cpp | 49 ++--- lldb/tools/lldb-dap/DAP.h | 22 ++- lldb/tools/lldb-dap/EventHelper.cpp | 2 +- .../lldb-dap/Handler/AttachRequestHandler.cpp | 69 +++---- .../lldb-dap/Handler/LaunchRequestHandler.cpp | 61 +++---- .../tools/lldb-dap/Handler/RequestHandler.cpp | 31 ++++ lldb/tools/lldb-dap/Handler/RequestHandler.h | 168 +++++++++++------- 7 files changed, 241 insertions(+), 161 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 56a0c38b00037..416661e98c21f 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -120,11 +120,12 @@ DAP::DAP(Log *log, const ReplMode default_repl_mode, : log(log), transport(transport), broadcaster("lldb-dap"), exception_breakpoints(), focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false), - restarting_process_id(LLDB_INVALID_PROCESS_ID), configuration_done(false), + restarting_process_id(LLDB_INVALID_PROCESS_ID), waiting_for_run_in_terminal(false), progress_event_reporter( [&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }), - reverse_request_seq(0), repl_mode(default_repl_mode) { + reverse_request_seq(0), repl_mode(default_repl_mode), + m_configuration_done(false) { configuration.preInitCommands = std::move(pre_init_commands); RegisterRequests(); } @@ -916,20 +917,10 @@ llvm::Error DAP::Loop() { return errWrapper; } - // The launch sequence is special and we need to carefully handle - // packets in the right order. Until we've handled configurationDone, - bool add_to_pending_queue = false; - if (const protocol::Request *req = - std::get_if(&*next)) { - llvm::StringRef command = req->command; - if (command == "disconnect") - disconnecting = true; - if (!configuration_done) - add_to_pending_queue = - command != "initialize" && command != "configurationDone" && - command != "disconnect" && !command.ends_with("Breakpoints"); - } + std::get_if(&*next); + req && req->command == "disconnect") + disconnecting = true; const std::optional cancel_args = getArgumentsIfRequest(*next, "cancel"); @@ -956,8 +947,7 @@ llvm::Error DAP::Loop() { { std::lock_guard guard(m_queue_mutex); - auto &queue = add_to_pending_queue ? m_pending_queue : m_queue; - queue.push_back(std::move(*next)); + m_queue.push_back(std::move(*next)); } m_queue_cv.notify_one(); } @@ -1255,14 +1245,25 @@ void DAP::SetConfiguration(const protocol::Configuration &config, SetThreadFormat(*configuration.customThreadFormat); } +bool DAP::GetConfigurationDone() { + std::lock_guard guard(m_configuration_done_mutex); + return m_configuration_done; +} + void DAP::SetConfigurationDone() { - { - std::lock_guard guard(m_queue_mutex); - std::copy(m_pending_queue.begin(), m_pending_queue.end(), - std::front_inserter(m_queue)); - configuration_done = true; - } - m_queue_cv.notify_all(); + std::lock_guard guard(m_configuration_done_mutex); + m_configuration_done = true; + for (auto &cb : m_configuration_done_callbacks) + cb(); + m_configuration_done_callbacks.clear(); +} + +void DAP::OnConfigurationDone(llvm::unique_function &&callback) { + std::lock_guard guard(m_configuration_done_mutex); + if (m_configuration_done) + callback(); + else + m_configuration_done_callbacks.emplace_back(std::move(callback)); } void DAP::SetFrameFormat(llvm::StringRef format) { diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c1a1130b1e59f..4d170ba4ec920 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -187,7 +187,6 @@ struct DAP { // shutting down the entire adapter. When we're restarting, we keep the id of // the old process here so we can detect this case and keep running. lldb::pid_t restarting_process_id; - bool configuration_done; bool waiting_for_run_in_terminal; ProgressEventReporter progress_event_reporter; // Keep track of the last stop thread index IDs as threads won't go away @@ -257,14 +256,26 @@ struct DAP { /// Configures the debug adapter for launching/attaching. void SetConfiguration(const protocol::Configuration &confing, bool is_attach); + /// Returns true if the debug session has received the `configurationDone` + /// request. + bool GetConfigurationDone(); + + /// Marks that the debug session has received the `configurationDone` request. void SetConfigurationDone(); + /// Registers a callback that is fired after `configurationDone` is received. + /// + /// NOTE: If `configurationDone` has already been received, the callback will + /// be invoked immediately. + void OnConfigurationDone(llvm::unique_function &&callback); + /// Configure source maps based on the current `DAPConfiguration`. void ConfigureSourceMaps(); /// Serialize the JSON value into a string and send the JSON packet to the /// "out" stream. void SendJSON(const llvm::json::Value &json); + /// Send the given message to the client void Send(const protocol::Message &message); @@ -336,7 +347,7 @@ struct DAP { lldb::SBTarget CreateTarget(lldb::SBError &error); /// Set given target object as a current target for lldb-dap and start - /// listeing for its breakpoint events. + /// listening for its breakpoint events. void SetTarget(const lldb::SBTarget target); bool HandleObject(const protocol::Message &M); @@ -377,7 +388,7 @@ struct DAP { }); } - /// The set of capablities supported by this adapter. + /// The set of capabilities supported by this adapter. protocol::Capabilities GetCapabilities(); /// Debuggee will continue from stopped state. @@ -444,13 +455,16 @@ struct DAP { /// Queue for all incoming messages. std::deque m_queue; - std::deque m_pending_queue; std::mutex m_queue_mutex; std::condition_variable m_queue_cv; std::mutex m_cancelled_requests_mutex; llvm::SmallSet m_cancelled_requests; + std::mutex m_configuration_done_mutex; + bool m_configuration_done; + std::vector> m_configuration_done_callbacks; + std::mutex m_active_request_mutex; const protocol::Request *m_active_request; }; diff --git a/lldb/tools/lldb-dap/EventHelper.cpp b/lldb/tools/lldb-dap/EventHelper.cpp index ed2d8700c26b0..e62f1d61a3d22 100644 --- a/lldb/tools/lldb-dap/EventHelper.cpp +++ b/lldb/tools/lldb-dap/EventHelper.cpp @@ -222,7 +222,7 @@ void SendContinuedEvent(DAP &dap) { // If the focus thread is not set then we haven't reported any thread status // to the client, so nothing to report. - if (!dap.configuration_done || dap.focus_tid == LLDB_INVALID_THREAD_ID) { + if (!dap.GetConfigurationDone() || dap.focus_tid == LLDB_INVALID_THREAD_ID) { return; } diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp index 0293ffbd0c922..c4f1ad084b4e7 100644 --- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp @@ -28,21 +28,22 @@ namespace lldb_dap { /// /// Since attaching is debugger/runtime specific, the arguments for this request /// are not part of this specification. -Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { +void AttachRequestHandler::Run(const AttachRequestArguments &args, + Reply reply) const { // Validate that we have a well formed attach request. if (args.attachCommands.empty() && args.coreFile.empty() && args.configuration.program.empty() && args.pid == LLDB_INVALID_PROCESS_ID && args.gdbRemotePort == LLDB_DAP_INVALID_PORT) - return make_error( + return reply(make_error( "expected one of 'pid', 'program', 'attachCommands', " - "'coreFile' or 'gdb-remote-port' to be specified"); + "'coreFile' or 'gdb-remote-port' to be specified")); // Check if we have mutually exclusive arguments. if ((args.pid != LLDB_INVALID_PROCESS_ID) && (args.gdbRemotePort != LLDB_DAP_INVALID_PORT)) - return make_error( - "'pid' and 'gdb-remote-port' are mutually exclusive"); + return reply(make_error( + "'pid' and 'gdb-remote-port' are mutually exclusive")); dap.SetConfiguration(args.configuration, /*is_attach=*/true); if (!args.coreFile.empty()) @@ -59,20 +60,20 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { // Run any initialize LLDB commands the user specified in the launch.json if (llvm::Error err = dap.RunInitCommands()) - return err; + return reply(std::move(err)); dap.ConfigureSourceMaps(); lldb::SBError error; lldb::SBTarget target = dap.CreateTarget(error); if (error.Fail()) - return ToError(error); + return reply(ToError(error)); dap.SetTarget(target); // Run any pre run LLDB commands the user specified in the launch.json if (Error err = dap.RunPreRunCommands()) - return err; + return reply(std::move(err)); if ((args.pid == LLDB_INVALID_PROCESS_ID || args.gdbRemotePort == LLDB_DAP_INVALID_PORT) && @@ -94,14 +95,14 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { // user that their command failed or the debugger is in an unexpected // state. if (llvm::Error err = dap.RunAttachCommands(args.attachCommands)) - return err; + return reply(std::move(err)); dap.target = dap.debugger.GetSelectedTarget(); // Validate the attachCommand results. if (!dap.target.GetProcess().IsValid()) - return make_error( - "attachCommands failed to attach to a process"); + return reply(make_error( + "attachCommands failed to attach to a process")); } else if (!args.coreFile.empty()) { dap.target.LoadCore(args.coreFile.data(), error); } else if (args.gdbRemotePort != LLDB_DAP_INVALID_PORT) { @@ -129,35 +130,35 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { // Make sure the process is attached and stopped. error = dap.WaitForProcessToStop(args.configuration.timeout); if (error.Fail()) - return ToError(error); + return reply(ToError(error)); if (args.coreFile.empty() && !dap.target.GetProcess().IsValid()) - return make_error("failed to attach to process"); + return reply(make_error("failed to attach to process")); dap.RunPostRunCommands(); - return Error::success(); -} + dap.OnConfigurationDone([&, reply = std::move(reply)]() { + reply(Error::success()); + + if (!dap.target.GetProcess().IsValid()) + return; + + // Clients can request a baseline of currently existing threads after + // we acknowledge the configurationDone request. + // Client requests the baseline of currently existing threads after + // a successful or attach by sending a 'threads' request + // right after receiving the configurationDone response. + // Obtain the list of threads before we resume the process + dap.initial_thread_list = + GetThreads(dap.target.GetProcess(), dap.thread_format); + + SendProcessEvent(dap, Attach); -void AttachRequestHandler::PostRun() const { - if (!dap.target.GetProcess().IsValid()) - return; - - // Clients can request a baseline of currently existing threads after - // we acknowledge the configurationDone request. - // Client requests the baseline of currently existing threads after - // a successful or attach by sending a 'threads' request - // right after receiving the configurationDone response. - // Obtain the list of threads before we resume the process - dap.initial_thread_list = - GetThreads(dap.target.GetProcess(), dap.thread_format); - - SendProcessEvent(dap, Attach); - - if (dap.stop_at_entry) - SendThreadStoppedEvent(dap); - else - dap.target.GetProcess().Continue(); + if (dap.stop_at_entry) + SendThreadStoppedEvent(dap); + else + dap.target.GetProcess().Continue(); + }); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp index 22d1a090187d8..d963f62dee4f4 100644 --- a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp @@ -21,11 +21,12 @@ using namespace lldb_dap::protocol; namespace lldb_dap { /// Launch request; value of command field is 'launch'. -Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const { +void LaunchRequestHandler::Run(const LaunchRequestArguments &arguments, + Reply reply) const { // Validate that we have a well formed launch request. if (!arguments.launchCommands.empty() && arguments.runInTerminal) - return make_error( - "'launchCommands' and 'runInTerminal' are mutually exclusive"); + return reply(make_error( + "'launchCommands' and 'runInTerminal' are mutually exclusive")); dap.SetConfiguration(arguments.configuration, /*is_attach=*/false); dap.last_launch_request = arguments; @@ -43,49 +44,49 @@ Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const { // This is run before target is created, so commands can't do anything with // the targets - preRunCommands are run with the target. if (Error err = dap.RunInitCommands()) - return err; + return reply(std::move(err)); dap.ConfigureSourceMaps(); lldb::SBError error; lldb::SBTarget target = dap.CreateTarget(error); if (error.Fail()) - return ToError(error); + return reply(ToError(error)); dap.SetTarget(target); // Run any pre run LLDB commands the user specified in the launch.json if (Error err = dap.RunPreRunCommands()) - return err; + return reply(std::move(err)); if (Error err = LaunchProcess(arguments)) - return err; + return reply(std::move(err)); dap.RunPostRunCommands(); - return Error::success(); -} - -void LaunchRequestHandler::PostRun() const { - if (!dap.target.GetProcess().IsValid()) - return; - - // Clients can request a baseline of currently existing threads after - // we acknowledge the configurationDone request. - // Client requests the baseline of currently existing threads after - // a successful or attach by sending a 'threads' request - // right after receiving the configurationDone response. - // Obtain the list of threads before we resume the process - dap.initial_thread_list = - GetThreads(dap.target.GetProcess(), dap.thread_format); - - // Attach happens when launching with runInTerminal. - SendProcessEvent(dap, dap.is_attach ? Attach : Launch); - - if (dap.stop_at_entry) - SendThreadStoppedEvent(dap); - else - dap.target.GetProcess().Continue(); + dap.OnConfigurationDone([&, reply = std::move(reply)]() { + reply(Error::success()); + + if (!dap.target.GetProcess().IsValid()) + return; + + // Clients can request a baseline of currently existing threads after + // we acknowledge the configurationDone request. + // Client requests the baseline of currently existing threads after + // a successful or attach by sending a 'threads' request + // right after receiving the configurationDone response. + // Obtain the list of threads before we resume the process + dap.initial_thread_list = + GetThreads(dap.target.GetProcess(), dap.thread_format); + + // Attach happens when launching with runInTerminal. + SendProcessEvent(dap, dap.is_attach ? Attach : Launch); + + if (dap.stop_at_entry) + SendThreadStoppedEvent(dap); + else + dap.target.GetProcess().Continue(); + }); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp index 93bc80a38e29d..063f613711f61 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp @@ -126,6 +126,37 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) { error.GetCString()); } +void HandleErrorResponse(llvm::Error err, protocol::Response &response) { + response.success = false; + llvm::handleAllErrors( + std::move(err), + [&](const NotStoppedError &err) { + response.message = lldb_dap::protocol::eResponseMessageNotStopped; + }, + [&](const DAPError &err) { + protocol::ErrorMessage error_message; + error_message.sendTelemetry = false; + error_message.format = err.getMessage(); + error_message.showUser = err.getShowUser(); + error_message.id = err.convertToErrorCode().value(); + error_message.url = err.getURL(); + error_message.urlLabel = err.getURLLabel(); + protocol::ErrorResponseBody body; + body.error = error_message; + response.body = body; + }, + [&](const llvm::ErrorInfoBase &err) { + protocol::ErrorMessage error_message; + error_message.showUser = true; + error_message.sendTelemetry = false; + error_message.format = err.message(); + error_message.id = err.convertToErrorCode().value(); + protocol::ErrorResponseBody body; + body.error = error_message; + response.body = body; + }); +} + void BaseRequestHandler::Run(const Request &request) { // If this request was cancelled, send a cancelled response. if (dap.IsCancelled(request)) { diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 383f9e24a729a..f7902592b572b 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -32,6 +32,35 @@ inline constexpr bool is_optional_v = is_optional::value; namespace lldb_dap { struct DAP; +void HandleErrorResponse(llvm::Error err, protocol::Response &response); +template +llvm::Expected parseArgs(const protocol::Request &request) { + protocol::Response response; + response.request_seq = request.seq; + response.command = request.command; + + if (!is_optional_v && !request.arguments) { + return llvm::make_error( + llvm::formatv("arguments required for command '{0}' " + "but none received", + request.command) + .str()); + } + + Args arguments; + llvm::json::Path::Root root("arguments"); + if (request.arguments && !fromJSON(*request.arguments, arguments, root)) { + std::string parse_failure; + llvm::raw_string_ostream OS(parse_failure); + OS << "invalid arguments for request '" << request.command + << "': " << llvm::toString(root.getError()) << "\n"; + root.printErrorContext(*request.arguments, OS); + return llvm::make_error(parse_failure); + } + + return arguments; +} + /// Base class for request handlers. Do not extend this directly: Extend /// the RequestHandler template subclass instead. class BaseRequestHandler { @@ -102,42 +131,21 @@ class RequestHandler : public BaseRequestHandler { response.request_seq = request.seq; response.command = request.command; - if (!is_optional_v && !request.arguments) { - DAP_LOG(dap.log, - "({0}) malformed request {1}, expected arguments but got none", - dap.transport.GetClientName(), request.command); - HandleErrorResponse( - llvm::make_error( - llvm::formatv("arguments required for command '{0}' " - "but none received", - request.command) - .str()), - response); - dap.Send(response); - return; - } - - Args arguments; - llvm::json::Path::Root root("arguments"); - if (request.arguments && !fromJSON(*request.arguments, arguments, root)) { - std::string parse_failure; - llvm::raw_string_ostream OS(parse_failure); - OS << "invalid arguments for request '" << request.command - << "': " << llvm::toString(root.getError()) << "\n"; - root.printErrorContext(*request.arguments, OS); - HandleErrorResponse(llvm::make_error(parse_failure), response); + llvm::Expected arguments = parseArgs(request); + if (llvm::Error err = arguments.takeError()) { + HandleErrorResponse(std::move(err), response); dap.Send(response); return; } if constexpr (std::is_same_v) { - if (llvm::Error err = Run(arguments)) { + if (llvm::Error err = Run(*arguments)) { HandleErrorResponse(std::move(err), response); } else { response.success = true; } } else { - Resp body = Run(arguments); + Resp body = Run(*arguments); if (llvm::Error err = body.takeError()) { HandleErrorResponse(std::move(err), response); } else { @@ -168,48 +176,73 @@ class RequestHandler : public BaseRequestHandler { /// *NOTE*: PostRun will be invoked even if the `Run` operation returned an /// error. virtual void PostRun() const {}; +}; - void HandleErrorResponse(llvm::Error err, - protocol::Response &response) const { - response.success = false; - llvm::handleAllErrors( - std::move(err), - [&](const NotStoppedError &err) { - response.message = lldb_dap::protocol::eResponseMessageNotStopped; - }, - [&](const DAPError &err) { - protocol::ErrorMessage error_message; - error_message.sendTelemetry = false; - error_message.format = err.getMessage(); - error_message.showUser = err.getShowUser(); - error_message.id = err.convertToErrorCode().value(); - error_message.url = err.getURL(); - error_message.urlLabel = err.getURLLabel(); - protocol::ErrorResponseBody body; - body.error = error_message; - response.body = body; - }, - [&](const llvm::ErrorInfoBase &err) { - protocol::ErrorMessage error_message; - error_message.showUser = true; - error_message.sendTelemetry = false; - error_message.format = err.message(); - error_message.id = err.convertToErrorCode().value(); - protocol::ErrorResponseBody body; - body.error = error_message; - response.body = body; - }); - } +/// A Reply is a void function that accepts a reply to an async request. +template using Reply = llvm::unique_function; + +/// Base class for handling DAP requests. Handlers should declare their +/// arguments and response body types like: +/// +/// class MyRequestHandler : public RequestHandler { +/// .... +/// }; +template +class AsyncRequestHandler : public BaseRequestHandler { + using BaseRequestHandler::BaseRequestHandler; + + void operator()(const protocol::Request &request) const override { + llvm::Expected arguments = parseArgs(request); + if (llvm::Error err = arguments.takeError()) { + protocol::Response response; + response.request_seq = request.seq; + response.command = request.command; + HandleErrorResponse(std::move(err), response); + dap.Send(response); + return; + } + + Run(*arguments, [&, request = std::move(request)](Resp body) { + protocol::Response response; + response.request_seq = request.seq; + response.command = request.command; + if constexpr (std::is_same_v) { + if (body) { + HandleErrorResponse(std::move(body), response); + } else { + response.success = true; + } + } else { + if (llvm::Error err = body.takeError()) { + HandleErrorResponse(std::move(err), response); + } else { + response.success = true; + response.body = std::move(*body); + } + } + + // Mark the request as 'cancelled' if the debugger was interrupted while + // evaluating this handler. + if (dap.debugger.InterruptRequested()) { + response.success = false; + response.message = protocol::eResponseMessageCancelled; + response.body = std::nullopt; + } + dap.Send(response); + }); + }; + + virtual void Run(const Args &, Reply) const = 0; }; class AttachRequestHandler - : public RequestHandler { + : public AsyncRequestHandler { public: - using RequestHandler::RequestHandler; + using AsyncRequestHandler::AsyncRequestHandler; static llvm::StringLiteral GetCommand() { return "attach"; } - llvm::Error Run(const protocol::AttachRequestArguments &args) const override; - void PostRun() const override; + void Run(const protocol::AttachRequestArguments &args, + Reply reply) const override; }; class BreakpointLocationsRequestHandler @@ -301,14 +334,13 @@ class InitializeRequestHandler }; class LaunchRequestHandler - : public RequestHandler { + : public AsyncRequestHandler { public: - using RequestHandler::RequestHandler; + using AsyncRequestHandler::AsyncRequestHandler; static llvm::StringLiteral GetCommand() { return "launch"; } - llvm::Error - Run(const protocol::LaunchRequestArguments &arguments) const override; - void PostRun() const override; + void Run(const protocol::LaunchRequestArguments &arguments, + Reply) const override; }; class RestartRequestHandler : public LegacyRequestHandler { From lldb-commits at lists.llvm.org Fri May 16 12:22:02 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 12:22:02 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adjusting startup flow to better handle async operations. (PR #140299) In-Reply-To: Message-ID: <6827905a.170a0220.9532a.59a9@mx.google.com> https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/140299 >From 59aadc0f2b61a39563269329d10c553f7965c70b Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 16 May 2025 12:03:50 -0700 Subject: [PATCH 1/2] [lldb-dap] Adjusting startup flow to better handle async operations. This introduces an `AsyncRequestHandler` and partially reverse the changes from ba29e60f9a2222bd5e883579bb78db13fc5a7588 in that the `launch` and `attach` commands now run when we receive them. We wait to send the reply until we get the `configurationDone` request. --- lldb/tools/lldb-dap/DAP.cpp | 49 ++--- lldb/tools/lldb-dap/DAP.h | 22 ++- lldb/tools/lldb-dap/EventHelper.cpp | 2 +- .../lldb-dap/Handler/AttachRequestHandler.cpp | 69 +++---- .../lldb-dap/Handler/LaunchRequestHandler.cpp | 61 +++---- .../tools/lldb-dap/Handler/RequestHandler.cpp | 31 ++++ lldb/tools/lldb-dap/Handler/RequestHandler.h | 168 +++++++++++------- 7 files changed, 241 insertions(+), 161 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 56a0c38b00037..416661e98c21f 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -120,11 +120,12 @@ DAP::DAP(Log *log, const ReplMode default_repl_mode, : log(log), transport(transport), broadcaster("lldb-dap"), exception_breakpoints(), focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false), - restarting_process_id(LLDB_INVALID_PROCESS_ID), configuration_done(false), + restarting_process_id(LLDB_INVALID_PROCESS_ID), waiting_for_run_in_terminal(false), progress_event_reporter( [&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }), - reverse_request_seq(0), repl_mode(default_repl_mode) { + reverse_request_seq(0), repl_mode(default_repl_mode), + m_configuration_done(false) { configuration.preInitCommands = std::move(pre_init_commands); RegisterRequests(); } @@ -916,20 +917,10 @@ llvm::Error DAP::Loop() { return errWrapper; } - // The launch sequence is special and we need to carefully handle - // packets in the right order. Until we've handled configurationDone, - bool add_to_pending_queue = false; - if (const protocol::Request *req = - std::get_if(&*next)) { - llvm::StringRef command = req->command; - if (command == "disconnect") - disconnecting = true; - if (!configuration_done) - add_to_pending_queue = - command != "initialize" && command != "configurationDone" && - command != "disconnect" && !command.ends_with("Breakpoints"); - } + std::get_if(&*next); + req && req->command == "disconnect") + disconnecting = true; const std::optional cancel_args = getArgumentsIfRequest(*next, "cancel"); @@ -956,8 +947,7 @@ llvm::Error DAP::Loop() { { std::lock_guard guard(m_queue_mutex); - auto &queue = add_to_pending_queue ? m_pending_queue : m_queue; - queue.push_back(std::move(*next)); + m_queue.push_back(std::move(*next)); } m_queue_cv.notify_one(); } @@ -1255,14 +1245,25 @@ void DAP::SetConfiguration(const protocol::Configuration &config, SetThreadFormat(*configuration.customThreadFormat); } +bool DAP::GetConfigurationDone() { + std::lock_guard guard(m_configuration_done_mutex); + return m_configuration_done; +} + void DAP::SetConfigurationDone() { - { - std::lock_guard guard(m_queue_mutex); - std::copy(m_pending_queue.begin(), m_pending_queue.end(), - std::front_inserter(m_queue)); - configuration_done = true; - } - m_queue_cv.notify_all(); + std::lock_guard guard(m_configuration_done_mutex); + m_configuration_done = true; + for (auto &cb : m_configuration_done_callbacks) + cb(); + m_configuration_done_callbacks.clear(); +} + +void DAP::OnConfigurationDone(llvm::unique_function &&callback) { + std::lock_guard guard(m_configuration_done_mutex); + if (m_configuration_done) + callback(); + else + m_configuration_done_callbacks.emplace_back(std::move(callback)); } void DAP::SetFrameFormat(llvm::StringRef format) { diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c1a1130b1e59f..4d170ba4ec920 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -187,7 +187,6 @@ struct DAP { // shutting down the entire adapter. When we're restarting, we keep the id of // the old process here so we can detect this case and keep running. lldb::pid_t restarting_process_id; - bool configuration_done; bool waiting_for_run_in_terminal; ProgressEventReporter progress_event_reporter; // Keep track of the last stop thread index IDs as threads won't go away @@ -257,14 +256,26 @@ struct DAP { /// Configures the debug adapter for launching/attaching. void SetConfiguration(const protocol::Configuration &confing, bool is_attach); + /// Returns true if the debug session has received the `configurationDone` + /// request. + bool GetConfigurationDone(); + + /// Marks that the debug session has received the `configurationDone` request. void SetConfigurationDone(); + /// Registers a callback that is fired after `configurationDone` is received. + /// + /// NOTE: If `configurationDone` has already been received, the callback will + /// be invoked immediately. + void OnConfigurationDone(llvm::unique_function &&callback); + /// Configure source maps based on the current `DAPConfiguration`. void ConfigureSourceMaps(); /// Serialize the JSON value into a string and send the JSON packet to the /// "out" stream. void SendJSON(const llvm::json::Value &json); + /// Send the given message to the client void Send(const protocol::Message &message); @@ -336,7 +347,7 @@ struct DAP { lldb::SBTarget CreateTarget(lldb::SBError &error); /// Set given target object as a current target for lldb-dap and start - /// listeing for its breakpoint events. + /// listening for its breakpoint events. void SetTarget(const lldb::SBTarget target); bool HandleObject(const protocol::Message &M); @@ -377,7 +388,7 @@ struct DAP { }); } - /// The set of capablities supported by this adapter. + /// The set of capabilities supported by this adapter. protocol::Capabilities GetCapabilities(); /// Debuggee will continue from stopped state. @@ -444,13 +455,16 @@ struct DAP { /// Queue for all incoming messages. std::deque m_queue; - std::deque m_pending_queue; std::mutex m_queue_mutex; std::condition_variable m_queue_cv; std::mutex m_cancelled_requests_mutex; llvm::SmallSet m_cancelled_requests; + std::mutex m_configuration_done_mutex; + bool m_configuration_done; + std::vector> m_configuration_done_callbacks; + std::mutex m_active_request_mutex; const protocol::Request *m_active_request; }; diff --git a/lldb/tools/lldb-dap/EventHelper.cpp b/lldb/tools/lldb-dap/EventHelper.cpp index ed2d8700c26b0..e62f1d61a3d22 100644 --- a/lldb/tools/lldb-dap/EventHelper.cpp +++ b/lldb/tools/lldb-dap/EventHelper.cpp @@ -222,7 +222,7 @@ void SendContinuedEvent(DAP &dap) { // If the focus thread is not set then we haven't reported any thread status // to the client, so nothing to report. - if (!dap.configuration_done || dap.focus_tid == LLDB_INVALID_THREAD_ID) { + if (!dap.GetConfigurationDone() || dap.focus_tid == LLDB_INVALID_THREAD_ID) { return; } diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp index 0293ffbd0c922..c4f1ad084b4e7 100644 --- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp @@ -28,21 +28,22 @@ namespace lldb_dap { /// /// Since attaching is debugger/runtime specific, the arguments for this request /// are not part of this specification. -Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { +void AttachRequestHandler::Run(const AttachRequestArguments &args, + Reply reply) const { // Validate that we have a well formed attach request. if (args.attachCommands.empty() && args.coreFile.empty() && args.configuration.program.empty() && args.pid == LLDB_INVALID_PROCESS_ID && args.gdbRemotePort == LLDB_DAP_INVALID_PORT) - return make_error( + return reply(make_error( "expected one of 'pid', 'program', 'attachCommands', " - "'coreFile' or 'gdb-remote-port' to be specified"); + "'coreFile' or 'gdb-remote-port' to be specified")); // Check if we have mutually exclusive arguments. if ((args.pid != LLDB_INVALID_PROCESS_ID) && (args.gdbRemotePort != LLDB_DAP_INVALID_PORT)) - return make_error( - "'pid' and 'gdb-remote-port' are mutually exclusive"); + return reply(make_error( + "'pid' and 'gdb-remote-port' are mutually exclusive")); dap.SetConfiguration(args.configuration, /*is_attach=*/true); if (!args.coreFile.empty()) @@ -59,20 +60,20 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { // Run any initialize LLDB commands the user specified in the launch.json if (llvm::Error err = dap.RunInitCommands()) - return err; + return reply(std::move(err)); dap.ConfigureSourceMaps(); lldb::SBError error; lldb::SBTarget target = dap.CreateTarget(error); if (error.Fail()) - return ToError(error); + return reply(ToError(error)); dap.SetTarget(target); // Run any pre run LLDB commands the user specified in the launch.json if (Error err = dap.RunPreRunCommands()) - return err; + return reply(std::move(err)); if ((args.pid == LLDB_INVALID_PROCESS_ID || args.gdbRemotePort == LLDB_DAP_INVALID_PORT) && @@ -94,14 +95,14 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { // user that their command failed or the debugger is in an unexpected // state. if (llvm::Error err = dap.RunAttachCommands(args.attachCommands)) - return err; + return reply(std::move(err)); dap.target = dap.debugger.GetSelectedTarget(); // Validate the attachCommand results. if (!dap.target.GetProcess().IsValid()) - return make_error( - "attachCommands failed to attach to a process"); + return reply(make_error( + "attachCommands failed to attach to a process")); } else if (!args.coreFile.empty()) { dap.target.LoadCore(args.coreFile.data(), error); } else if (args.gdbRemotePort != LLDB_DAP_INVALID_PORT) { @@ -129,35 +130,35 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { // Make sure the process is attached and stopped. error = dap.WaitForProcessToStop(args.configuration.timeout); if (error.Fail()) - return ToError(error); + return reply(ToError(error)); if (args.coreFile.empty() && !dap.target.GetProcess().IsValid()) - return make_error("failed to attach to process"); + return reply(make_error("failed to attach to process")); dap.RunPostRunCommands(); - return Error::success(); -} + dap.OnConfigurationDone([&, reply = std::move(reply)]() { + reply(Error::success()); + + if (!dap.target.GetProcess().IsValid()) + return; + + // Clients can request a baseline of currently existing threads after + // we acknowledge the configurationDone request. + // Client requests the baseline of currently existing threads after + // a successful or attach by sending a 'threads' request + // right after receiving the configurationDone response. + // Obtain the list of threads before we resume the process + dap.initial_thread_list = + GetThreads(dap.target.GetProcess(), dap.thread_format); + + SendProcessEvent(dap, Attach); -void AttachRequestHandler::PostRun() const { - if (!dap.target.GetProcess().IsValid()) - return; - - // Clients can request a baseline of currently existing threads after - // we acknowledge the configurationDone request. - // Client requests the baseline of currently existing threads after - // a successful or attach by sending a 'threads' request - // right after receiving the configurationDone response. - // Obtain the list of threads before we resume the process - dap.initial_thread_list = - GetThreads(dap.target.GetProcess(), dap.thread_format); - - SendProcessEvent(dap, Attach); - - if (dap.stop_at_entry) - SendThreadStoppedEvent(dap); - else - dap.target.GetProcess().Continue(); + if (dap.stop_at_entry) + SendThreadStoppedEvent(dap); + else + dap.target.GetProcess().Continue(); + }); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp index 22d1a090187d8..d963f62dee4f4 100644 --- a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp @@ -21,11 +21,12 @@ using namespace lldb_dap::protocol; namespace lldb_dap { /// Launch request; value of command field is 'launch'. -Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const { +void LaunchRequestHandler::Run(const LaunchRequestArguments &arguments, + Reply reply) const { // Validate that we have a well formed launch request. if (!arguments.launchCommands.empty() && arguments.runInTerminal) - return make_error( - "'launchCommands' and 'runInTerminal' are mutually exclusive"); + return reply(make_error( + "'launchCommands' and 'runInTerminal' are mutually exclusive")); dap.SetConfiguration(arguments.configuration, /*is_attach=*/false); dap.last_launch_request = arguments; @@ -43,49 +44,49 @@ Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const { // This is run before target is created, so commands can't do anything with // the targets - preRunCommands are run with the target. if (Error err = dap.RunInitCommands()) - return err; + return reply(std::move(err)); dap.ConfigureSourceMaps(); lldb::SBError error; lldb::SBTarget target = dap.CreateTarget(error); if (error.Fail()) - return ToError(error); + return reply(ToError(error)); dap.SetTarget(target); // Run any pre run LLDB commands the user specified in the launch.json if (Error err = dap.RunPreRunCommands()) - return err; + return reply(std::move(err)); if (Error err = LaunchProcess(arguments)) - return err; + return reply(std::move(err)); dap.RunPostRunCommands(); - return Error::success(); -} - -void LaunchRequestHandler::PostRun() const { - if (!dap.target.GetProcess().IsValid()) - return; - - // Clients can request a baseline of currently existing threads after - // we acknowledge the configurationDone request. - // Client requests the baseline of currently existing threads after - // a successful or attach by sending a 'threads' request - // right after receiving the configurationDone response. - // Obtain the list of threads before we resume the process - dap.initial_thread_list = - GetThreads(dap.target.GetProcess(), dap.thread_format); - - // Attach happens when launching with runInTerminal. - SendProcessEvent(dap, dap.is_attach ? Attach : Launch); - - if (dap.stop_at_entry) - SendThreadStoppedEvent(dap); - else - dap.target.GetProcess().Continue(); + dap.OnConfigurationDone([&, reply = std::move(reply)]() { + reply(Error::success()); + + if (!dap.target.GetProcess().IsValid()) + return; + + // Clients can request a baseline of currently existing threads after + // we acknowledge the configurationDone request. + // Client requests the baseline of currently existing threads after + // a successful or attach by sending a 'threads' request + // right after receiving the configurationDone response. + // Obtain the list of threads before we resume the process + dap.initial_thread_list = + GetThreads(dap.target.GetProcess(), dap.thread_format); + + // Attach happens when launching with runInTerminal. + SendProcessEvent(dap, dap.is_attach ? Attach : Launch); + + if (dap.stop_at_entry) + SendThreadStoppedEvent(dap); + else + dap.target.GetProcess().Continue(); + }); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp index 93bc80a38e29d..063f613711f61 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp @@ -126,6 +126,37 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) { error.GetCString()); } +void HandleErrorResponse(llvm::Error err, protocol::Response &response) { + response.success = false; + llvm::handleAllErrors( + std::move(err), + [&](const NotStoppedError &err) { + response.message = lldb_dap::protocol::eResponseMessageNotStopped; + }, + [&](const DAPError &err) { + protocol::ErrorMessage error_message; + error_message.sendTelemetry = false; + error_message.format = err.getMessage(); + error_message.showUser = err.getShowUser(); + error_message.id = err.convertToErrorCode().value(); + error_message.url = err.getURL(); + error_message.urlLabel = err.getURLLabel(); + protocol::ErrorResponseBody body; + body.error = error_message; + response.body = body; + }, + [&](const llvm::ErrorInfoBase &err) { + protocol::ErrorMessage error_message; + error_message.showUser = true; + error_message.sendTelemetry = false; + error_message.format = err.message(); + error_message.id = err.convertToErrorCode().value(); + protocol::ErrorResponseBody body; + body.error = error_message; + response.body = body; + }); +} + void BaseRequestHandler::Run(const Request &request) { // If this request was cancelled, send a cancelled response. if (dap.IsCancelled(request)) { diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 383f9e24a729a..f7902592b572b 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -32,6 +32,35 @@ inline constexpr bool is_optional_v = is_optional::value; namespace lldb_dap { struct DAP; +void HandleErrorResponse(llvm::Error err, protocol::Response &response); +template +llvm::Expected parseArgs(const protocol::Request &request) { + protocol::Response response; + response.request_seq = request.seq; + response.command = request.command; + + if (!is_optional_v && !request.arguments) { + return llvm::make_error( + llvm::formatv("arguments required for command '{0}' " + "but none received", + request.command) + .str()); + } + + Args arguments; + llvm::json::Path::Root root("arguments"); + if (request.arguments && !fromJSON(*request.arguments, arguments, root)) { + std::string parse_failure; + llvm::raw_string_ostream OS(parse_failure); + OS << "invalid arguments for request '" << request.command + << "': " << llvm::toString(root.getError()) << "\n"; + root.printErrorContext(*request.arguments, OS); + return llvm::make_error(parse_failure); + } + + return arguments; +} + /// Base class for request handlers. Do not extend this directly: Extend /// the RequestHandler template subclass instead. class BaseRequestHandler { @@ -102,42 +131,21 @@ class RequestHandler : public BaseRequestHandler { response.request_seq = request.seq; response.command = request.command; - if (!is_optional_v && !request.arguments) { - DAP_LOG(dap.log, - "({0}) malformed request {1}, expected arguments but got none", - dap.transport.GetClientName(), request.command); - HandleErrorResponse( - llvm::make_error( - llvm::formatv("arguments required for command '{0}' " - "but none received", - request.command) - .str()), - response); - dap.Send(response); - return; - } - - Args arguments; - llvm::json::Path::Root root("arguments"); - if (request.arguments && !fromJSON(*request.arguments, arguments, root)) { - std::string parse_failure; - llvm::raw_string_ostream OS(parse_failure); - OS << "invalid arguments for request '" << request.command - << "': " << llvm::toString(root.getError()) << "\n"; - root.printErrorContext(*request.arguments, OS); - HandleErrorResponse(llvm::make_error(parse_failure), response); + llvm::Expected arguments = parseArgs(request); + if (llvm::Error err = arguments.takeError()) { + HandleErrorResponse(std::move(err), response); dap.Send(response); return; } if constexpr (std::is_same_v) { - if (llvm::Error err = Run(arguments)) { + if (llvm::Error err = Run(*arguments)) { HandleErrorResponse(std::move(err), response); } else { response.success = true; } } else { - Resp body = Run(arguments); + Resp body = Run(*arguments); if (llvm::Error err = body.takeError()) { HandleErrorResponse(std::move(err), response); } else { @@ -168,48 +176,73 @@ class RequestHandler : public BaseRequestHandler { /// *NOTE*: PostRun will be invoked even if the `Run` operation returned an /// error. virtual void PostRun() const {}; +}; - void HandleErrorResponse(llvm::Error err, - protocol::Response &response) const { - response.success = false; - llvm::handleAllErrors( - std::move(err), - [&](const NotStoppedError &err) { - response.message = lldb_dap::protocol::eResponseMessageNotStopped; - }, - [&](const DAPError &err) { - protocol::ErrorMessage error_message; - error_message.sendTelemetry = false; - error_message.format = err.getMessage(); - error_message.showUser = err.getShowUser(); - error_message.id = err.convertToErrorCode().value(); - error_message.url = err.getURL(); - error_message.urlLabel = err.getURLLabel(); - protocol::ErrorResponseBody body; - body.error = error_message; - response.body = body; - }, - [&](const llvm::ErrorInfoBase &err) { - protocol::ErrorMessage error_message; - error_message.showUser = true; - error_message.sendTelemetry = false; - error_message.format = err.message(); - error_message.id = err.convertToErrorCode().value(); - protocol::ErrorResponseBody body; - body.error = error_message; - response.body = body; - }); - } +/// A Reply is a void function that accepts a reply to an async request. +template using Reply = llvm::unique_function; + +/// Base class for handling DAP requests. Handlers should declare their +/// arguments and response body types like: +/// +/// class MyRequestHandler : public RequestHandler { +/// .... +/// }; +template +class AsyncRequestHandler : public BaseRequestHandler { + using BaseRequestHandler::BaseRequestHandler; + + void operator()(const protocol::Request &request) const override { + llvm::Expected arguments = parseArgs(request); + if (llvm::Error err = arguments.takeError()) { + protocol::Response response; + response.request_seq = request.seq; + response.command = request.command; + HandleErrorResponse(std::move(err), response); + dap.Send(response); + return; + } + + Run(*arguments, [&, request = std::move(request)](Resp body) { + protocol::Response response; + response.request_seq = request.seq; + response.command = request.command; + if constexpr (std::is_same_v) { + if (body) { + HandleErrorResponse(std::move(body), response); + } else { + response.success = true; + } + } else { + if (llvm::Error err = body.takeError()) { + HandleErrorResponse(std::move(err), response); + } else { + response.success = true; + response.body = std::move(*body); + } + } + + // Mark the request as 'cancelled' if the debugger was interrupted while + // evaluating this handler. + if (dap.debugger.InterruptRequested()) { + response.success = false; + response.message = protocol::eResponseMessageCancelled; + response.body = std::nullopt; + } + dap.Send(response); + }); + }; + + virtual void Run(const Args &, Reply) const = 0; }; class AttachRequestHandler - : public RequestHandler { + : public AsyncRequestHandler { public: - using RequestHandler::RequestHandler; + using AsyncRequestHandler::AsyncRequestHandler; static llvm::StringLiteral GetCommand() { return "attach"; } - llvm::Error Run(const protocol::AttachRequestArguments &args) const override; - void PostRun() const override; + void Run(const protocol::AttachRequestArguments &args, + Reply reply) const override; }; class BreakpointLocationsRequestHandler @@ -301,14 +334,13 @@ class InitializeRequestHandler }; class LaunchRequestHandler - : public RequestHandler { + : public AsyncRequestHandler { public: - using RequestHandler::RequestHandler; + using AsyncRequestHandler::AsyncRequestHandler; static llvm::StringLiteral GetCommand() { return "launch"; } - llvm::Error - Run(const protocol::LaunchRequestArguments &arguments) const override; - void PostRun() const override; + void Run(const protocol::LaunchRequestArguments &arguments, + Reply) const override; }; class RestartRequestHandler : public LegacyRequestHandler { >From c62e0ec5644e32308c8e6d805fd7fb0d5598440c Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 16 May 2025 12:21:32 -0700 Subject: [PATCH 2/2] Consistently using `SetTarget` and adding an additional check before sending the `attach`/`launch` reply. --- lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp | 11 +++++++---- lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp | 7 ++++--- lldb/tools/lldb-dap/Handler/RequestHandler.cpp | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp index c4f1ad084b4e7..3c87ad7d9eb8d 100644 --- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp @@ -97,7 +97,9 @@ void AttachRequestHandler::Run(const AttachRequestArguments &args, if (llvm::Error err = dap.RunAttachCommands(args.attachCommands)) return reply(std::move(err)); - dap.target = dap.debugger.GetSelectedTarget(); + // The custom commands might have created a new target so we should use + // the selected target after these commands are run. + dap.SetTarget(dap.debugger.GetSelectedTarget()); // Validate the attachCommand results. if (!dap.target.GetProcess().IsValid()) @@ -138,10 +140,11 @@ void AttachRequestHandler::Run(const AttachRequestArguments &args, dap.RunPostRunCommands(); dap.OnConfigurationDone([&, reply = std::move(reply)]() { - reply(Error::success()); - + // Ensure we have a valid process still, otherwise a run command may have + // left us in a bad state. if (!dap.target.GetProcess().IsValid()) - return; + return reply(make_error("invalid process")); + reply(Error::success()); // Clients can request a baseline of currently existing threads after // we acknowledge the configurationDone request. diff --git a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp index d963f62dee4f4..daf2f96c96995 100644 --- a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp @@ -65,10 +65,11 @@ void LaunchRequestHandler::Run(const LaunchRequestArguments &arguments, dap.RunPostRunCommands(); dap.OnConfigurationDone([&, reply = std::move(reply)]() { - reply(Error::success()); - + // Ensure we have a valid process still, otherwise a run command may have + // left us in a bad state. if (!dap.target.GetProcess().IsValid()) - return; + return reply(make_error("invalid process")); + reply(Error::success()); // Clients can request a baseline of currently existing threads after // we acknowledge the configurationDone request. diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp index 063f613711f61..dc71bd5606a3f 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp @@ -240,7 +240,7 @@ llvm::Error BaseRequestHandler::LaunchProcess( // The custom commands might have created a new target so we should use // the selected target after these commands are run. - dap.target = dap.debugger.GetSelectedTarget(); + dap.SetTarget(dap.debugger.GetSelectedTarget()); } } From lldb-commits at lists.llvm.org Fri May 16 12:30:27 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 12:30:27 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adjusting startup flow to better handle async operations. (PR #140299) In-Reply-To: Message-ID: <68279253.170a0220.19d562.58b6@mx.google.com> https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/140299 >From 59aadc0f2b61a39563269329d10c553f7965c70b Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 16 May 2025 12:03:50 -0700 Subject: [PATCH 1/3] [lldb-dap] Adjusting startup flow to better handle async operations. This introduces an `AsyncRequestHandler` and partially reverse the changes from ba29e60f9a2222bd5e883579bb78db13fc5a7588 in that the `launch` and `attach` commands now run when we receive them. We wait to send the reply until we get the `configurationDone` request. --- lldb/tools/lldb-dap/DAP.cpp | 49 ++--- lldb/tools/lldb-dap/DAP.h | 22 ++- lldb/tools/lldb-dap/EventHelper.cpp | 2 +- .../lldb-dap/Handler/AttachRequestHandler.cpp | 69 +++---- .../lldb-dap/Handler/LaunchRequestHandler.cpp | 61 +++---- .../tools/lldb-dap/Handler/RequestHandler.cpp | 31 ++++ lldb/tools/lldb-dap/Handler/RequestHandler.h | 168 +++++++++++------- 7 files changed, 241 insertions(+), 161 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 56a0c38b00037..416661e98c21f 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -120,11 +120,12 @@ DAP::DAP(Log *log, const ReplMode default_repl_mode, : log(log), transport(transport), broadcaster("lldb-dap"), exception_breakpoints(), focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false), - restarting_process_id(LLDB_INVALID_PROCESS_ID), configuration_done(false), + restarting_process_id(LLDB_INVALID_PROCESS_ID), waiting_for_run_in_terminal(false), progress_event_reporter( [&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }), - reverse_request_seq(0), repl_mode(default_repl_mode) { + reverse_request_seq(0), repl_mode(default_repl_mode), + m_configuration_done(false) { configuration.preInitCommands = std::move(pre_init_commands); RegisterRequests(); } @@ -916,20 +917,10 @@ llvm::Error DAP::Loop() { return errWrapper; } - // The launch sequence is special and we need to carefully handle - // packets in the right order. Until we've handled configurationDone, - bool add_to_pending_queue = false; - if (const protocol::Request *req = - std::get_if(&*next)) { - llvm::StringRef command = req->command; - if (command == "disconnect") - disconnecting = true; - if (!configuration_done) - add_to_pending_queue = - command != "initialize" && command != "configurationDone" && - command != "disconnect" && !command.ends_with("Breakpoints"); - } + std::get_if(&*next); + req && req->command == "disconnect") + disconnecting = true; const std::optional cancel_args = getArgumentsIfRequest(*next, "cancel"); @@ -956,8 +947,7 @@ llvm::Error DAP::Loop() { { std::lock_guard guard(m_queue_mutex); - auto &queue = add_to_pending_queue ? m_pending_queue : m_queue; - queue.push_back(std::move(*next)); + m_queue.push_back(std::move(*next)); } m_queue_cv.notify_one(); } @@ -1255,14 +1245,25 @@ void DAP::SetConfiguration(const protocol::Configuration &config, SetThreadFormat(*configuration.customThreadFormat); } +bool DAP::GetConfigurationDone() { + std::lock_guard guard(m_configuration_done_mutex); + return m_configuration_done; +} + void DAP::SetConfigurationDone() { - { - std::lock_guard guard(m_queue_mutex); - std::copy(m_pending_queue.begin(), m_pending_queue.end(), - std::front_inserter(m_queue)); - configuration_done = true; - } - m_queue_cv.notify_all(); + std::lock_guard guard(m_configuration_done_mutex); + m_configuration_done = true; + for (auto &cb : m_configuration_done_callbacks) + cb(); + m_configuration_done_callbacks.clear(); +} + +void DAP::OnConfigurationDone(llvm::unique_function &&callback) { + std::lock_guard guard(m_configuration_done_mutex); + if (m_configuration_done) + callback(); + else + m_configuration_done_callbacks.emplace_back(std::move(callback)); } void DAP::SetFrameFormat(llvm::StringRef format) { diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c1a1130b1e59f..4d170ba4ec920 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -187,7 +187,6 @@ struct DAP { // shutting down the entire adapter. When we're restarting, we keep the id of // the old process here so we can detect this case and keep running. lldb::pid_t restarting_process_id; - bool configuration_done; bool waiting_for_run_in_terminal; ProgressEventReporter progress_event_reporter; // Keep track of the last stop thread index IDs as threads won't go away @@ -257,14 +256,26 @@ struct DAP { /// Configures the debug adapter for launching/attaching. void SetConfiguration(const protocol::Configuration &confing, bool is_attach); + /// Returns true if the debug session has received the `configurationDone` + /// request. + bool GetConfigurationDone(); + + /// Marks that the debug session has received the `configurationDone` request. void SetConfigurationDone(); + /// Registers a callback that is fired after `configurationDone` is received. + /// + /// NOTE: If `configurationDone` has already been received, the callback will + /// be invoked immediately. + void OnConfigurationDone(llvm::unique_function &&callback); + /// Configure source maps based on the current `DAPConfiguration`. void ConfigureSourceMaps(); /// Serialize the JSON value into a string and send the JSON packet to the /// "out" stream. void SendJSON(const llvm::json::Value &json); + /// Send the given message to the client void Send(const protocol::Message &message); @@ -336,7 +347,7 @@ struct DAP { lldb::SBTarget CreateTarget(lldb::SBError &error); /// Set given target object as a current target for lldb-dap and start - /// listeing for its breakpoint events. + /// listening for its breakpoint events. void SetTarget(const lldb::SBTarget target); bool HandleObject(const protocol::Message &M); @@ -377,7 +388,7 @@ struct DAP { }); } - /// The set of capablities supported by this adapter. + /// The set of capabilities supported by this adapter. protocol::Capabilities GetCapabilities(); /// Debuggee will continue from stopped state. @@ -444,13 +455,16 @@ struct DAP { /// Queue for all incoming messages. std::deque m_queue; - std::deque m_pending_queue; std::mutex m_queue_mutex; std::condition_variable m_queue_cv; std::mutex m_cancelled_requests_mutex; llvm::SmallSet m_cancelled_requests; + std::mutex m_configuration_done_mutex; + bool m_configuration_done; + std::vector> m_configuration_done_callbacks; + std::mutex m_active_request_mutex; const protocol::Request *m_active_request; }; diff --git a/lldb/tools/lldb-dap/EventHelper.cpp b/lldb/tools/lldb-dap/EventHelper.cpp index ed2d8700c26b0..e62f1d61a3d22 100644 --- a/lldb/tools/lldb-dap/EventHelper.cpp +++ b/lldb/tools/lldb-dap/EventHelper.cpp @@ -222,7 +222,7 @@ void SendContinuedEvent(DAP &dap) { // If the focus thread is not set then we haven't reported any thread status // to the client, so nothing to report. - if (!dap.configuration_done || dap.focus_tid == LLDB_INVALID_THREAD_ID) { + if (!dap.GetConfigurationDone() || dap.focus_tid == LLDB_INVALID_THREAD_ID) { return; } diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp index 0293ffbd0c922..c4f1ad084b4e7 100644 --- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp @@ -28,21 +28,22 @@ namespace lldb_dap { /// /// Since attaching is debugger/runtime specific, the arguments for this request /// are not part of this specification. -Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { +void AttachRequestHandler::Run(const AttachRequestArguments &args, + Reply reply) const { // Validate that we have a well formed attach request. if (args.attachCommands.empty() && args.coreFile.empty() && args.configuration.program.empty() && args.pid == LLDB_INVALID_PROCESS_ID && args.gdbRemotePort == LLDB_DAP_INVALID_PORT) - return make_error( + return reply(make_error( "expected one of 'pid', 'program', 'attachCommands', " - "'coreFile' or 'gdb-remote-port' to be specified"); + "'coreFile' or 'gdb-remote-port' to be specified")); // Check if we have mutually exclusive arguments. if ((args.pid != LLDB_INVALID_PROCESS_ID) && (args.gdbRemotePort != LLDB_DAP_INVALID_PORT)) - return make_error( - "'pid' and 'gdb-remote-port' are mutually exclusive"); + return reply(make_error( + "'pid' and 'gdb-remote-port' are mutually exclusive")); dap.SetConfiguration(args.configuration, /*is_attach=*/true); if (!args.coreFile.empty()) @@ -59,20 +60,20 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { // Run any initialize LLDB commands the user specified in the launch.json if (llvm::Error err = dap.RunInitCommands()) - return err; + return reply(std::move(err)); dap.ConfigureSourceMaps(); lldb::SBError error; lldb::SBTarget target = dap.CreateTarget(error); if (error.Fail()) - return ToError(error); + return reply(ToError(error)); dap.SetTarget(target); // Run any pre run LLDB commands the user specified in the launch.json if (Error err = dap.RunPreRunCommands()) - return err; + return reply(std::move(err)); if ((args.pid == LLDB_INVALID_PROCESS_ID || args.gdbRemotePort == LLDB_DAP_INVALID_PORT) && @@ -94,14 +95,14 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { // user that their command failed or the debugger is in an unexpected // state. if (llvm::Error err = dap.RunAttachCommands(args.attachCommands)) - return err; + return reply(std::move(err)); dap.target = dap.debugger.GetSelectedTarget(); // Validate the attachCommand results. if (!dap.target.GetProcess().IsValid()) - return make_error( - "attachCommands failed to attach to a process"); + return reply(make_error( + "attachCommands failed to attach to a process")); } else if (!args.coreFile.empty()) { dap.target.LoadCore(args.coreFile.data(), error); } else if (args.gdbRemotePort != LLDB_DAP_INVALID_PORT) { @@ -129,35 +130,35 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { // Make sure the process is attached and stopped. error = dap.WaitForProcessToStop(args.configuration.timeout); if (error.Fail()) - return ToError(error); + return reply(ToError(error)); if (args.coreFile.empty() && !dap.target.GetProcess().IsValid()) - return make_error("failed to attach to process"); + return reply(make_error("failed to attach to process")); dap.RunPostRunCommands(); - return Error::success(); -} + dap.OnConfigurationDone([&, reply = std::move(reply)]() { + reply(Error::success()); + + if (!dap.target.GetProcess().IsValid()) + return; + + // Clients can request a baseline of currently existing threads after + // we acknowledge the configurationDone request. + // Client requests the baseline of currently existing threads after + // a successful or attach by sending a 'threads' request + // right after receiving the configurationDone response. + // Obtain the list of threads before we resume the process + dap.initial_thread_list = + GetThreads(dap.target.GetProcess(), dap.thread_format); + + SendProcessEvent(dap, Attach); -void AttachRequestHandler::PostRun() const { - if (!dap.target.GetProcess().IsValid()) - return; - - // Clients can request a baseline of currently existing threads after - // we acknowledge the configurationDone request. - // Client requests the baseline of currently existing threads after - // a successful or attach by sending a 'threads' request - // right after receiving the configurationDone response. - // Obtain the list of threads before we resume the process - dap.initial_thread_list = - GetThreads(dap.target.GetProcess(), dap.thread_format); - - SendProcessEvent(dap, Attach); - - if (dap.stop_at_entry) - SendThreadStoppedEvent(dap); - else - dap.target.GetProcess().Continue(); + if (dap.stop_at_entry) + SendThreadStoppedEvent(dap); + else + dap.target.GetProcess().Continue(); + }); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp index 22d1a090187d8..d963f62dee4f4 100644 --- a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp @@ -21,11 +21,12 @@ using namespace lldb_dap::protocol; namespace lldb_dap { /// Launch request; value of command field is 'launch'. -Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const { +void LaunchRequestHandler::Run(const LaunchRequestArguments &arguments, + Reply reply) const { // Validate that we have a well formed launch request. if (!arguments.launchCommands.empty() && arguments.runInTerminal) - return make_error( - "'launchCommands' and 'runInTerminal' are mutually exclusive"); + return reply(make_error( + "'launchCommands' and 'runInTerminal' are mutually exclusive")); dap.SetConfiguration(arguments.configuration, /*is_attach=*/false); dap.last_launch_request = arguments; @@ -43,49 +44,49 @@ Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const { // This is run before target is created, so commands can't do anything with // the targets - preRunCommands are run with the target. if (Error err = dap.RunInitCommands()) - return err; + return reply(std::move(err)); dap.ConfigureSourceMaps(); lldb::SBError error; lldb::SBTarget target = dap.CreateTarget(error); if (error.Fail()) - return ToError(error); + return reply(ToError(error)); dap.SetTarget(target); // Run any pre run LLDB commands the user specified in the launch.json if (Error err = dap.RunPreRunCommands()) - return err; + return reply(std::move(err)); if (Error err = LaunchProcess(arguments)) - return err; + return reply(std::move(err)); dap.RunPostRunCommands(); - return Error::success(); -} - -void LaunchRequestHandler::PostRun() const { - if (!dap.target.GetProcess().IsValid()) - return; - - // Clients can request a baseline of currently existing threads after - // we acknowledge the configurationDone request. - // Client requests the baseline of currently existing threads after - // a successful or attach by sending a 'threads' request - // right after receiving the configurationDone response. - // Obtain the list of threads before we resume the process - dap.initial_thread_list = - GetThreads(dap.target.GetProcess(), dap.thread_format); - - // Attach happens when launching with runInTerminal. - SendProcessEvent(dap, dap.is_attach ? Attach : Launch); - - if (dap.stop_at_entry) - SendThreadStoppedEvent(dap); - else - dap.target.GetProcess().Continue(); + dap.OnConfigurationDone([&, reply = std::move(reply)]() { + reply(Error::success()); + + if (!dap.target.GetProcess().IsValid()) + return; + + // Clients can request a baseline of currently existing threads after + // we acknowledge the configurationDone request. + // Client requests the baseline of currently existing threads after + // a successful or attach by sending a 'threads' request + // right after receiving the configurationDone response. + // Obtain the list of threads before we resume the process + dap.initial_thread_list = + GetThreads(dap.target.GetProcess(), dap.thread_format); + + // Attach happens when launching with runInTerminal. + SendProcessEvent(dap, dap.is_attach ? Attach : Launch); + + if (dap.stop_at_entry) + SendThreadStoppedEvent(dap); + else + dap.target.GetProcess().Continue(); + }); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp index 93bc80a38e29d..063f613711f61 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp @@ -126,6 +126,37 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) { error.GetCString()); } +void HandleErrorResponse(llvm::Error err, protocol::Response &response) { + response.success = false; + llvm::handleAllErrors( + std::move(err), + [&](const NotStoppedError &err) { + response.message = lldb_dap::protocol::eResponseMessageNotStopped; + }, + [&](const DAPError &err) { + protocol::ErrorMessage error_message; + error_message.sendTelemetry = false; + error_message.format = err.getMessage(); + error_message.showUser = err.getShowUser(); + error_message.id = err.convertToErrorCode().value(); + error_message.url = err.getURL(); + error_message.urlLabel = err.getURLLabel(); + protocol::ErrorResponseBody body; + body.error = error_message; + response.body = body; + }, + [&](const llvm::ErrorInfoBase &err) { + protocol::ErrorMessage error_message; + error_message.showUser = true; + error_message.sendTelemetry = false; + error_message.format = err.message(); + error_message.id = err.convertToErrorCode().value(); + protocol::ErrorResponseBody body; + body.error = error_message; + response.body = body; + }); +} + void BaseRequestHandler::Run(const Request &request) { // If this request was cancelled, send a cancelled response. if (dap.IsCancelled(request)) { diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 383f9e24a729a..f7902592b572b 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -32,6 +32,35 @@ inline constexpr bool is_optional_v = is_optional::value; namespace lldb_dap { struct DAP; +void HandleErrorResponse(llvm::Error err, protocol::Response &response); +template +llvm::Expected parseArgs(const protocol::Request &request) { + protocol::Response response; + response.request_seq = request.seq; + response.command = request.command; + + if (!is_optional_v && !request.arguments) { + return llvm::make_error( + llvm::formatv("arguments required for command '{0}' " + "but none received", + request.command) + .str()); + } + + Args arguments; + llvm::json::Path::Root root("arguments"); + if (request.arguments && !fromJSON(*request.arguments, arguments, root)) { + std::string parse_failure; + llvm::raw_string_ostream OS(parse_failure); + OS << "invalid arguments for request '" << request.command + << "': " << llvm::toString(root.getError()) << "\n"; + root.printErrorContext(*request.arguments, OS); + return llvm::make_error(parse_failure); + } + + return arguments; +} + /// Base class for request handlers. Do not extend this directly: Extend /// the RequestHandler template subclass instead. class BaseRequestHandler { @@ -102,42 +131,21 @@ class RequestHandler : public BaseRequestHandler { response.request_seq = request.seq; response.command = request.command; - if (!is_optional_v && !request.arguments) { - DAP_LOG(dap.log, - "({0}) malformed request {1}, expected arguments but got none", - dap.transport.GetClientName(), request.command); - HandleErrorResponse( - llvm::make_error( - llvm::formatv("arguments required for command '{0}' " - "but none received", - request.command) - .str()), - response); - dap.Send(response); - return; - } - - Args arguments; - llvm::json::Path::Root root("arguments"); - if (request.arguments && !fromJSON(*request.arguments, arguments, root)) { - std::string parse_failure; - llvm::raw_string_ostream OS(parse_failure); - OS << "invalid arguments for request '" << request.command - << "': " << llvm::toString(root.getError()) << "\n"; - root.printErrorContext(*request.arguments, OS); - HandleErrorResponse(llvm::make_error(parse_failure), response); + llvm::Expected arguments = parseArgs(request); + if (llvm::Error err = arguments.takeError()) { + HandleErrorResponse(std::move(err), response); dap.Send(response); return; } if constexpr (std::is_same_v) { - if (llvm::Error err = Run(arguments)) { + if (llvm::Error err = Run(*arguments)) { HandleErrorResponse(std::move(err), response); } else { response.success = true; } } else { - Resp body = Run(arguments); + Resp body = Run(*arguments); if (llvm::Error err = body.takeError()) { HandleErrorResponse(std::move(err), response); } else { @@ -168,48 +176,73 @@ class RequestHandler : public BaseRequestHandler { /// *NOTE*: PostRun will be invoked even if the `Run` operation returned an /// error. virtual void PostRun() const {}; +}; - void HandleErrorResponse(llvm::Error err, - protocol::Response &response) const { - response.success = false; - llvm::handleAllErrors( - std::move(err), - [&](const NotStoppedError &err) { - response.message = lldb_dap::protocol::eResponseMessageNotStopped; - }, - [&](const DAPError &err) { - protocol::ErrorMessage error_message; - error_message.sendTelemetry = false; - error_message.format = err.getMessage(); - error_message.showUser = err.getShowUser(); - error_message.id = err.convertToErrorCode().value(); - error_message.url = err.getURL(); - error_message.urlLabel = err.getURLLabel(); - protocol::ErrorResponseBody body; - body.error = error_message; - response.body = body; - }, - [&](const llvm::ErrorInfoBase &err) { - protocol::ErrorMessage error_message; - error_message.showUser = true; - error_message.sendTelemetry = false; - error_message.format = err.message(); - error_message.id = err.convertToErrorCode().value(); - protocol::ErrorResponseBody body; - body.error = error_message; - response.body = body; - }); - } +/// A Reply is a void function that accepts a reply to an async request. +template using Reply = llvm::unique_function; + +/// Base class for handling DAP requests. Handlers should declare their +/// arguments and response body types like: +/// +/// class MyRequestHandler : public RequestHandler { +/// .... +/// }; +template +class AsyncRequestHandler : public BaseRequestHandler { + using BaseRequestHandler::BaseRequestHandler; + + void operator()(const protocol::Request &request) const override { + llvm::Expected arguments = parseArgs(request); + if (llvm::Error err = arguments.takeError()) { + protocol::Response response; + response.request_seq = request.seq; + response.command = request.command; + HandleErrorResponse(std::move(err), response); + dap.Send(response); + return; + } + + Run(*arguments, [&, request = std::move(request)](Resp body) { + protocol::Response response; + response.request_seq = request.seq; + response.command = request.command; + if constexpr (std::is_same_v) { + if (body) { + HandleErrorResponse(std::move(body), response); + } else { + response.success = true; + } + } else { + if (llvm::Error err = body.takeError()) { + HandleErrorResponse(std::move(err), response); + } else { + response.success = true; + response.body = std::move(*body); + } + } + + // Mark the request as 'cancelled' if the debugger was interrupted while + // evaluating this handler. + if (dap.debugger.InterruptRequested()) { + response.success = false; + response.message = protocol::eResponseMessageCancelled; + response.body = std::nullopt; + } + dap.Send(response); + }); + }; + + virtual void Run(const Args &, Reply) const = 0; }; class AttachRequestHandler - : public RequestHandler { + : public AsyncRequestHandler { public: - using RequestHandler::RequestHandler; + using AsyncRequestHandler::AsyncRequestHandler; static llvm::StringLiteral GetCommand() { return "attach"; } - llvm::Error Run(const protocol::AttachRequestArguments &args) const override; - void PostRun() const override; + void Run(const protocol::AttachRequestArguments &args, + Reply reply) const override; }; class BreakpointLocationsRequestHandler @@ -301,14 +334,13 @@ class InitializeRequestHandler }; class LaunchRequestHandler - : public RequestHandler { + : public AsyncRequestHandler { public: - using RequestHandler::RequestHandler; + using AsyncRequestHandler::AsyncRequestHandler; static llvm::StringLiteral GetCommand() { return "launch"; } - llvm::Error - Run(const protocol::LaunchRequestArguments &arguments) const override; - void PostRun() const override; + void Run(const protocol::LaunchRequestArguments &arguments, + Reply) const override; }; class RestartRequestHandler : public LegacyRequestHandler { >From c62e0ec5644e32308c8e6d805fd7fb0d5598440c Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 16 May 2025 12:21:32 -0700 Subject: [PATCH 2/3] Consistently using `SetTarget` and adding an additional check before sending the `attach`/`launch` reply. --- lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp | 11 +++++++---- lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp | 7 ++++--- lldb/tools/lldb-dap/Handler/RequestHandler.cpp | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp index c4f1ad084b4e7..3c87ad7d9eb8d 100644 --- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp @@ -97,7 +97,9 @@ void AttachRequestHandler::Run(const AttachRequestArguments &args, if (llvm::Error err = dap.RunAttachCommands(args.attachCommands)) return reply(std::move(err)); - dap.target = dap.debugger.GetSelectedTarget(); + // The custom commands might have created a new target so we should use + // the selected target after these commands are run. + dap.SetTarget(dap.debugger.GetSelectedTarget()); // Validate the attachCommand results. if (!dap.target.GetProcess().IsValid()) @@ -138,10 +140,11 @@ void AttachRequestHandler::Run(const AttachRequestArguments &args, dap.RunPostRunCommands(); dap.OnConfigurationDone([&, reply = std::move(reply)]() { - reply(Error::success()); - + // Ensure we have a valid process still, otherwise a run command may have + // left us in a bad state. if (!dap.target.GetProcess().IsValid()) - return; + return reply(make_error("invalid process")); + reply(Error::success()); // Clients can request a baseline of currently existing threads after // we acknowledge the configurationDone request. diff --git a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp index d963f62dee4f4..daf2f96c96995 100644 --- a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp @@ -65,10 +65,11 @@ void LaunchRequestHandler::Run(const LaunchRequestArguments &arguments, dap.RunPostRunCommands(); dap.OnConfigurationDone([&, reply = std::move(reply)]() { - reply(Error::success()); - + // Ensure we have a valid process still, otherwise a run command may have + // left us in a bad state. if (!dap.target.GetProcess().IsValid()) - return; + return reply(make_error("invalid process")); + reply(Error::success()); // Clients can request a baseline of currently existing threads after // we acknowledge the configurationDone request. diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp index 063f613711f61..dc71bd5606a3f 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp @@ -240,7 +240,7 @@ llvm::Error BaseRequestHandler::LaunchProcess( // The custom commands might have created a new target so we should use // the selected target after these commands are run. - dap.target = dap.debugger.GetSelectedTarget(); + dap.SetTarget(dap.debugger.GetSelectedTarget()); } } >From 1aae1b8585d5fb9be875380ed2f219e15d48f6e8 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 16 May 2025 12:29:54 -0700 Subject: [PATCH 3/3] Updating the doc comments on `AsyncRequestHandler`. --- lldb/tools/lldb-dap/Handler/RequestHandler.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index f7902592b572b..0cf7b2838f5ec 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -181,10 +181,10 @@ class RequestHandler : public BaseRequestHandler { /// A Reply is a void function that accepts a reply to an async request. template using Reply = llvm::unique_function; -/// Base class for handling DAP requests. Handlers should declare their -/// arguments and response body types like: +/// Base class for handling DAP requests asynchronously. Handlers should declare +/// their arguments and response body types like: /// -/// class MyRequestHandler : public RequestHandler { +/// class MyRequestHandler : public AsyncRequestHandler { /// .... /// }; template @@ -232,6 +232,9 @@ class AsyncRequestHandler : public BaseRequestHandler { }); }; + /// Run the request handler. The reply callback is expected to be invoked only + /// once and may be moved to be handled at a later time. Returning from the + /// `Run` call will unblock handling the next request. virtual void Run(const Args &, Reply) const = 0; }; From lldb-commits at lists.llvm.org Fri May 16 13:58:59 2025 From: lldb-commits at lists.llvm.org (Zequan Wu via lldb-commits) Date: Fri, 16 May 2025 13:58:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][Formatters] Add --pointer-match-depth option to `type summary add` command. (PR #138209) In-Reply-To: Message-ID: <6827a713.170a0220.bf09.5b4d@mx.google.com> https://github.com/ZequanWu updated https://github.com/llvm/llvm-project/pull/138209 >From dcb5b2596267d908dea1474164a1fadf1cd23aef Mon Sep 17 00:00:00 2001 From: Zequan Wu Date: Thu, 1 May 2025 14:51:24 -0700 Subject: [PATCH 1/5] [lldb][Formatters] Add --pointer-match-depth option to "type summary add" command. --- lldb/include/lldb/API/SBTypeSummary.h | 4 + .../lldb/DataFormatters/FormatClasses.h | 10 +- .../lldb/DataFormatters/FormatManager.h | 3 +- .../lldb/DataFormatters/FormattersContainer.h | 8 +- lldb/include/lldb/DataFormatters/TypeFormat.h | 5 + .../include/lldb/DataFormatters/TypeSummary.h | 17 ++- .../lldb/DataFormatters/TypeSynthetic.h | 5 + lldb/source/API/SBTypeSummary.cpp | 16 +++ lldb/source/Commands/CommandObjectType.cpp | 27 +++-- lldb/source/Commands/Options.td | 4 + lldb/source/DataFormatters/FormatManager.cpp | 40 ++++--- .../source/DataFormatters/TypeCategoryMap.cpp | 5 +- lldb/source/DataFormatters/TypeSummary.cpp | 37 ++++--- .../data-formatter-ptr-matching/Makefile | 4 + .../TestDataFormatterPtrMatching.py | 101 ++++++++++++++++++ .../data-formatter-ptr-matching/main.cpp | 32 ++++++ 16 files changed, 266 insertions(+), 52 deletions(-) create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/Makefile create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/main.cpp diff --git a/lldb/include/lldb/API/SBTypeSummary.h b/lldb/include/lldb/API/SBTypeSummary.h index 40fa146b4e31b..b6869e53a39e7 100644 --- a/lldb/include/lldb/API/SBTypeSummary.h +++ b/lldb/include/lldb/API/SBTypeSummary.h @@ -109,6 +109,10 @@ class SBTypeSummary { void SetFunctionCode(const char *data); + uint32_t GetPtrMatchDepth(); + + void SetPtrMatchDepth(uint32_t ptr_match_depth); + uint32_t GetOptions(); void SetOptions(uint32_t); diff --git a/lldb/include/lldb/DataFormatters/FormatClasses.h b/lldb/include/lldb/DataFormatters/FormatClasses.h index a6bc3a3542536..89d74649ecc64 100644 --- a/lldb/include/lldb/DataFormatters/FormatClasses.h +++ b/lldb/include/lldb/DataFormatters/FormatClasses.h @@ -76,9 +76,10 @@ class FormattersMatchCandidate { FormattersMatchCandidate(ConstString name, ScriptInterpreter *script_interpreter, TypeImpl type, - Flags flags) + Flags flags, uint32_t ptr_stripped_depth = 0) : m_type_name(name), m_script_interpreter(script_interpreter), - m_type(type), m_flags(flags) {} + m_type(type), m_flags(flags), m_ptr_stripped_depth(ptr_stripped_depth) { + } ~FormattersMatchCandidate() = default; @@ -96,6 +97,8 @@ class FormattersMatchCandidate { bool DidStripTypedef() const { return m_flags.stripped_typedef; } + uint32_t GetPtrStrippedDepth() const { return m_ptr_stripped_depth; } + template bool IsMatch(const std::shared_ptr &formatter_sp) const { if (!formatter_sp) @@ -104,6 +107,8 @@ class FormattersMatchCandidate { return false; if (formatter_sp->SkipsPointers() && DidStripPointer()) return false; + if (formatter_sp->GetPtrMatchDepth() < GetPtrStrippedDepth()) + return false; if (formatter_sp->SkipsReferences() && DidStripReference()) return false; return true; @@ -116,6 +121,7 @@ class FormattersMatchCandidate { ScriptInterpreter *m_script_interpreter; TypeImpl m_type; Flags m_flags; + uint32_t m_ptr_stripped_depth; }; typedef std::vector FormattersMatchVector; diff --git a/lldb/include/lldb/DataFormatters/FormatManager.h b/lldb/include/lldb/DataFormatters/FormatManager.h index db2fe99c44caf..9e24f7b722407 100644 --- a/lldb/include/lldb/DataFormatters/FormatManager.h +++ b/lldb/include/lldb/DataFormatters/FormatManager.h @@ -180,7 +180,8 @@ class FormatManager : public IFormatChangeListener { lldb::DynamicValueType use_dynamic, FormattersMatchVector &entries, FormattersMatchCandidate::Flags current_flags, - bool root_level = false); + bool root_level = false, + uint32_t ptr_stripped_depth = 0); std::atomic m_last_revision; FormatCache m_format_cache; diff --git a/lldb/include/lldb/DataFormatters/FormattersContainer.h b/lldb/include/lldb/DataFormatters/FormattersContainer.h index 7898621fd18af..f7465fc65538d 100644 --- a/lldb/include/lldb/DataFormatters/FormattersContainer.h +++ b/lldb/include/lldb/DataFormatters/FormattersContainer.h @@ -193,12 +193,10 @@ template class FormattersContainer { bool Get(const FormattersMatchVector &candidates, ValueSP &entry) { for (const FormattersMatchCandidate &candidate : candidates) { if (Get(candidate, entry)) { - if (candidate.IsMatch(entry) == false) { - entry.reset(); - continue; - } else { + if (candidate.IsMatch(entry)) return true; - } + entry.reset(); + continue; } } return false; diff --git a/lldb/include/lldb/DataFormatters/TypeFormat.h b/lldb/include/lldb/DataFormatters/TypeFormat.h index 63d4765bdf270..d242f9083d608 100644 --- a/lldb/include/lldb/DataFormatters/TypeFormat.h +++ b/lldb/include/lldb/DataFormatters/TypeFormat.h @@ -133,6 +133,10 @@ class TypeFormatImpl { void SetOptions(uint32_t value) { m_flags.SetValue(value); } + uint32_t GetPtrMatchDepth() { return m_ptr_match_depth; } + + void SetPtrMatchDepth(uint32_t value) { m_ptr_match_depth = value; } + uint32_t &GetRevision() { return m_my_revision; } enum class Type { eTypeUnknown, eTypeFormat, eTypeEnum }; @@ -150,6 +154,7 @@ class TypeFormatImpl { protected: Flags m_flags; uint32_t m_my_revision = 0; + uint32_t m_ptr_match_depth = 1; private: TypeFormatImpl(const TypeFormatImpl &) = delete; diff --git a/lldb/include/lldb/DataFormatters/TypeSummary.h b/lldb/include/lldb/DataFormatters/TypeSummary.h index f4d5563516ecb..589f68c2ce314 100644 --- a/lldb/include/lldb/DataFormatters/TypeSummary.h +++ b/lldb/include/lldb/DataFormatters/TypeSummary.h @@ -253,6 +253,10 @@ class TypeSummaryImpl { void SetOptions(uint32_t value) { m_flags.SetValue(value); } + uint32_t GetPtrMatchDepth() { return m_ptr_match_depth; } + + void SetPtrMatchDepth(uint32_t value) { m_ptr_match_depth = value; } + // we are using a ValueObject* instead of a ValueObjectSP because we do not // need to hold on to this for extended periods of time and we trust the // ValueObject to stay around for as long as it is required for us to @@ -278,10 +282,12 @@ class TypeSummaryImpl { uint32_t m_my_revision = 0; Flags m_flags; - TypeSummaryImpl(Kind kind, const TypeSummaryImpl::Flags &flags); + TypeSummaryImpl(Kind kind, const TypeSummaryImpl::Flags &flags, + uint32_t ptr_match_depth = 1); private: Kind m_kind; + uint32_t m_ptr_match_depth = 1; TypeSummaryImpl(const TypeSummaryImpl &) = delete; const TypeSummaryImpl &operator=(const TypeSummaryImpl &) = delete; }; @@ -292,7 +298,8 @@ struct StringSummaryFormat : public TypeSummaryImpl { FormatEntity::Entry m_format; Status m_error; - StringSummaryFormat(const TypeSummaryImpl::Flags &flags, const char *f); + StringSummaryFormat(const TypeSummaryImpl::Flags &flags, const char *f, + uint32_t ptr_match_depth = 1); ~StringSummaryFormat() override = default; @@ -328,7 +335,8 @@ struct CXXFunctionSummaryFormat : public TypeSummaryImpl { std::string m_description; CXXFunctionSummaryFormat(const TypeSummaryImpl::Flags &flags, Callback impl, - const char *description); + const char *description, + uint32_t ptr_match_depth = 1); ~CXXFunctionSummaryFormat() override = default; @@ -373,7 +381,8 @@ struct ScriptSummaryFormat : public TypeSummaryImpl { ScriptSummaryFormat(const TypeSummaryImpl::Flags &flags, const char *function_name, - const char *python_script = nullptr); + const char *python_script = nullptr, + uint32_t ptr_match_depth = 1); ~ScriptSummaryFormat() override = default; diff --git a/lldb/include/lldb/DataFormatters/TypeSynthetic.h b/lldb/include/lldb/DataFormatters/TypeSynthetic.h index c8d7d15588065..37f02fb8f7ce5 100644 --- a/lldb/include/lldb/DataFormatters/TypeSynthetic.h +++ b/lldb/include/lldb/DataFormatters/TypeSynthetic.h @@ -273,9 +273,14 @@ class SyntheticChildren { uint32_t &GetRevision() { return m_my_revision; } + uint32_t GetPtrMatchDepth() { return m_ptr_match_depth; } + + void SetPtrMatchDepth(uint32_t value) { m_ptr_match_depth = value; } + protected: uint32_t m_my_revision = 0; Flags m_flags; + uint32_t m_ptr_match_depth = 1; private: SyntheticChildren(const SyntheticChildren &) = delete; diff --git a/lldb/source/API/SBTypeSummary.cpp b/lldb/source/API/SBTypeSummary.cpp index 856ee0ed3175b..d7acb0670018a 100644 --- a/lldb/source/API/SBTypeSummary.cpp +++ b/lldb/source/API/SBTypeSummary.cpp @@ -230,6 +230,22 @@ const char *SBTypeSummary::GetData() { return nullptr; } +uint32_t SBTypeSummary::GetPtrMatchDepth() { + LLDB_INSTRUMENT_VA(this); + + if (!IsValid()) + return 0; + return m_opaque_sp->GetPtrMatchDepth(); +} + +void SBTypeSummary::SetPtrMatchDepth(uint32_t ptr_match_depth) { + LLDB_INSTRUMENT_VA(this); + + if (!IsValid()) + return; + return m_opaque_sp->SetPtrMatchDepth(ptr_match_depth); +} + uint32_t SBTypeSummary::GetOptions() { LLDB_INSTRUMENT_VA(this); diff --git a/lldb/source/Commands/CommandObjectType.cpp b/lldb/source/Commands/CommandObjectType.cpp index 41630b61c2f0e..19cd3ff2972e9 100644 --- a/lldb/source/Commands/CommandObjectType.cpp +++ b/lldb/source/Commands/CommandObjectType.cpp @@ -51,12 +51,13 @@ class ScriptAddOptions { FormatterMatchType m_match_type; ConstString m_name; std::string m_category; + uint32_t m_ptr_match_depth; ScriptAddOptions(const TypeSummaryImpl::Flags &flags, FormatterMatchType match_type, ConstString name, - std::string catg) + std::string catg, uint32_t m_ptr_match_depth) : m_flags(flags), m_match_type(match_type), m_name(name), - m_category(catg) {} + m_category(catg), m_ptr_match_depth(m_ptr_match_depth) {} typedef std::shared_ptr SharedPointer; }; @@ -146,6 +147,7 @@ class CommandObjectTypeSummaryAdd : public CommandObjectParsed, std::string m_python_function; bool m_is_add_script = false; std::string m_category; + uint32_t m_ptr_match_depth = 1; }; CommandOptions m_options; @@ -211,7 +213,7 @@ class CommandObjectTypeSummaryAdd : public CommandObjectParsed, TypeSummaryImplSP script_format; script_format = std::make_shared( options->m_flags, funct_name_str.c_str(), - lines.CopyList(" ").c_str()); + lines.CopyList(" ").c_str(), options->m_ptr_match_depth); Status error; @@ -1178,6 +1180,13 @@ Status CommandObjectTypeSummaryAdd::CommandOptions::SetOptionValue( case 'p': m_flags.SetSkipPointers(true); break; + case 'd': + if (option_arg.getAsInteger(0, m_ptr_match_depth)) { + error = Status::FromErrorStringWithFormat( + "invalid integer value for option '%c': %s", short_option, + option_arg.data()); + } + break; case 'r': m_flags.SetSkipReferences(true); break; @@ -1266,7 +1275,8 @@ bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary( (" " + m_options.m_python_function + "(valobj,internal_dict)"); script_format = std::make_shared( - m_options.m_flags, funct_name, code.c_str()); + m_options.m_flags, funct_name, code.c_str(), + m_options.m_ptr_match_depth); ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); @@ -1300,12 +1310,13 @@ bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary( std::string code = " " + m_options.m_python_script; script_format = std::make_shared( - m_options.m_flags, funct_name_str.c_str(), code.c_str()); + m_options.m_flags, funct_name_str.c_str(), code.c_str(), + m_options.m_ptr_match_depth); } else { // Use an IOHandler to grab Python code from the user auto options = std::make_unique( m_options.m_flags, m_options.m_match_type, m_options.m_name, - m_options.m_category); + m_options.m_category, m_options.m_ptr_match_depth); for (auto &entry : command.entries()) { if (entry.ref().empty()) { @@ -1380,8 +1391,8 @@ bool CommandObjectTypeSummaryAdd::Execute_StringSummary( return false; } - std::unique_ptr string_format( - new StringSummaryFormat(m_options.m_flags, format_cstr)); + std::unique_ptr string_format(new StringSummaryFormat( + m_options.m_flags, format_cstr, m_options.m_ptr_match_depth)); if (!string_format) { result.AppendError("summary creation failed"); return false; diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index 53864ff29327d..9dd7467b4269c 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -1240,6 +1240,10 @@ let Command = "type summary add" in { Desc<"Don't show the value, just show the summary, for this type.">; def type_summary_add_skip_pointers : Option<"skip-pointers", "p">, Desc<"Don't use this format for pointers-to-type objects.">; + def type_summary_add_pointer_match_depth : Option<"pointer-match-depth", "d">, + Arg<"UnsignedInteger">, + Desc<"Specify the maximum pointer depth that this format can be apply to " + "(default to 1). It's only effective when --skip-pointers is not set.">; def type_summary_add_skip_references : Option<"skip-references", "r">, Desc<"Don't use this format for references-to-type objects.">; def type_summary_add_regex : Option<"regex", "x">, diff --git a/lldb/source/DataFormatters/FormatManager.cpp b/lldb/source/DataFormatters/FormatManager.cpp index 3b891cecb1c8b..122f2304ead24 100644 --- a/lldb/source/DataFormatters/FormatManager.cpp +++ b/lldb/source/DataFormatters/FormatManager.cpp @@ -174,7 +174,8 @@ void FormatManager::DisableAllCategories() { void FormatManager::GetPossibleMatches( ValueObject &valobj, CompilerType compiler_type, lldb::DynamicValueType use_dynamic, FormattersMatchVector &entries, - FormattersMatchCandidate::Flags current_flags, bool root_level) { + FormattersMatchCandidate::Flags current_flags, bool root_level, + uint32_t ptr_stripped_depth) { compiler_type = compiler_type.GetTypeForFormatters(); ConstString type_name(compiler_type.GetTypeName()); // A ValueObject that couldn't be made correctly won't necessarily have a @@ -190,46 +191,51 @@ void FormatManager::GetPossibleMatches( sstring.Printf("%s:%d", type_name.AsCString(), valobj.GetBitfieldBitSize()); ConstString bitfieldname(sstring.GetString()); entries.push_back({bitfieldname, script_interpreter, - TypeImpl(compiler_type), current_flags}); + TypeImpl(compiler_type), current_flags, + ptr_stripped_depth}); } if (!compiler_type.IsMeaninglessWithoutDynamicResolution()) { entries.push_back({type_name, script_interpreter, TypeImpl(compiler_type), - current_flags}); + current_flags, ptr_stripped_depth}); ConstString display_type_name(compiler_type.GetTypeName()); if (display_type_name != type_name) entries.push_back({display_type_name, script_interpreter, - TypeImpl(compiler_type), current_flags}); + TypeImpl(compiler_type), current_flags, + ptr_stripped_depth}); } for (bool is_rvalue_ref = true, j = true; j && compiler_type.IsReferenceType(nullptr, &is_rvalue_ref); j = false) { CompilerType non_ref_type = compiler_type.GetNonReferenceType(); GetPossibleMatches(valobj, non_ref_type, use_dynamic, entries, - current_flags.WithStrippedReference()); + current_flags.WithStrippedReference(), root_level, + ptr_stripped_depth); if (non_ref_type.IsTypedefType()) { CompilerType deffed_referenced_type = non_ref_type.GetTypedefedType(); deffed_referenced_type = is_rvalue_ref ? deffed_referenced_type.GetRValueReferenceType() : deffed_referenced_type.GetLValueReferenceType(); // this is not exactly the usual meaning of stripping typedefs - GetPossibleMatches( - valobj, deffed_referenced_type, - use_dynamic, entries, current_flags.WithStrippedTypedef()); + GetPossibleMatches(valobj, deffed_referenced_type, use_dynamic, entries, + current_flags.WithStrippedTypedef(), root_level, + ptr_stripped_depth); } } if (compiler_type.IsPointerType()) { CompilerType non_ptr_type = compiler_type.GetPointeeType(); GetPossibleMatches(valobj, non_ptr_type, use_dynamic, entries, - current_flags.WithStrippedPointer()); + current_flags.WithStrippedPointer(), root_level, + ptr_stripped_depth + 1); if (non_ptr_type.IsTypedefType()) { CompilerType deffed_pointed_type = non_ptr_type.GetTypedefedType().GetPointerType(); // this is not exactly the usual meaning of stripping typedefs GetPossibleMatches(valobj, deffed_pointed_type, use_dynamic, entries, - current_flags.WithStrippedTypedef()); + current_flags.WithStrippedTypedef(), root_level, + ptr_stripped_depth + 1); } } @@ -246,9 +252,9 @@ void FormatManager::GetPossibleMatches( CompilerType deffed_array_type = element_type.GetTypedefedType().GetArrayType(array_size); // this is not exactly the usual meaning of stripping typedefs - GetPossibleMatches( - valobj, deffed_array_type, - use_dynamic, entries, current_flags.WithStrippedTypedef()); + GetPossibleMatches(valobj, deffed_array_type, use_dynamic, entries, + current_flags.WithStrippedTypedef(), root_level, + ptr_stripped_depth); } } @@ -266,7 +272,8 @@ void FormatManager::GetPossibleMatches( if (compiler_type.IsTypedefType()) { CompilerType deffed_type = compiler_type.GetTypedefedType(); GetPossibleMatches(valobj, deffed_type, use_dynamic, entries, - current_flags.WithStrippedTypedef()); + current_flags.WithStrippedTypedef(), root_level, + ptr_stripped_depth); } if (root_level) { @@ -281,7 +288,8 @@ void FormatManager::GetPossibleMatches( if (unqual_compiler_ast_type.GetOpaqueQualType() != compiler_type.GetOpaqueQualType()) GetPossibleMatches(valobj, unqual_compiler_ast_type, use_dynamic, - entries, current_flags); + entries, current_flags, root_level, + ptr_stripped_depth); } while (false); // if all else fails, go to static type @@ -290,7 +298,7 @@ void FormatManager::GetPossibleMatches( if (static_value_sp) GetPossibleMatches(*static_value_sp.get(), static_value_sp->GetCompilerType(), use_dynamic, - entries, current_flags, true); + entries, current_flags, true, ptr_stripped_depth); } } } diff --git a/lldb/source/DataFormatters/TypeCategoryMap.cpp b/lldb/source/DataFormatters/TypeCategoryMap.cpp index ce2cf369b5be5..8682e4b7435e4 100644 --- a/lldb/source/DataFormatters/TypeCategoryMap.cpp +++ b/lldb/source/DataFormatters/TypeCategoryMap.cpp @@ -185,12 +185,13 @@ void TypeCategoryMap::Get(FormattersMatchData &match_data, ImplSP &retval) { for (auto match : match_data.GetMatchesVector()) { LLDB_LOGF( log, - "[%s] candidate match = %s %s %s %s", + "[%s] candidate match = %s %s %s %s ptr-stripped-depth=%u", __FUNCTION__, match.GetTypeName().GetCString(), match.DidStripPointer() ? "strip-pointers" : "no-strip-pointers", match.DidStripReference() ? "strip-reference" : "no-strip-reference", - match.DidStripTypedef() ? "strip-typedef" : "no-strip-typedef"); + match.DidStripTypedef() ? "strip-typedef" : "no-strip-typedef", + match.GetPtrStrippedDepth()); } } diff --git a/lldb/source/DataFormatters/TypeSummary.cpp b/lldb/source/DataFormatters/TypeSummary.cpp index 18bf81aedf2cb..6aa290698cd12 100644 --- a/lldb/source/DataFormatters/TypeSummary.cpp +++ b/lldb/source/DataFormatters/TypeSummary.cpp @@ -43,8 +43,9 @@ TypeSummaryOptions::SetCapping(lldb::TypeSummaryCapping cap) { return *this; } -TypeSummaryImpl::TypeSummaryImpl(Kind kind, const TypeSummaryImpl::Flags &flags) - : m_flags(flags), m_kind(kind) {} +TypeSummaryImpl::TypeSummaryImpl(Kind kind, const TypeSummaryImpl::Flags &flags, + uint32_t ptr_match_depth) + : m_flags(flags), m_kind(kind), m_ptr_match_depth(ptr_match_depth) {} std::string TypeSummaryImpl::GetSummaryKindName() { switch (m_kind) { @@ -63,8 +64,10 @@ std::string TypeSummaryImpl::GetSummaryKindName() { } StringSummaryFormat::StringSummaryFormat(const TypeSummaryImpl::Flags &flags, - const char *format_cstr) - : TypeSummaryImpl(Kind::eSummaryString, flags), m_format_str() { + const char *format_cstr, + uint32_t ptr_match_depth) + : TypeSummaryImpl(Kind::eSummaryString, flags, ptr_match_depth), + m_format_str() { SetSummaryString(format_cstr); } @@ -117,7 +120,7 @@ bool StringSummaryFormat::FormatObject(ValueObject *valobj, std::string &retval, std::string StringSummaryFormat::GetDescription() { StreamString sstr; - sstr.Printf("`%s`%s%s%s%s%s%s%s%s%s", m_format_str.c_str(), + sstr.Printf("`%s`%s%s%s%s%s%s%s%s%s ptr-match-depth=%u", m_format_str.c_str(), m_error.Fail() ? " error: " : "", m_error.Fail() ? m_error.AsCString() : "", Cascades() ? "" : " (not cascading)", @@ -126,15 +129,17 @@ std::string StringSummaryFormat::GetDescription() { IsOneLiner() ? " (one-line printout)" : "", SkipsPointers() ? " (skip pointers)" : "", SkipsReferences() ? " (skip references)" : "", - HideNames(nullptr) ? " (hide member names)" : ""); + HideNames(nullptr) ? " (hide member names)" : "", + GetPtrMatchDepth()); return std::string(sstr.GetString()); } std::string StringSummaryFormat::GetName() { return m_format_str; } CXXFunctionSummaryFormat::CXXFunctionSummaryFormat( - const TypeSummaryImpl::Flags &flags, Callback impl, const char *description) - : TypeSummaryImpl(Kind::eCallback, flags), m_impl(impl), + const TypeSummaryImpl::Flags &flags, Callback impl, const char *description, + uint32_t ptr_match_depth) + : TypeSummaryImpl(Kind::eCallback, flags, ptr_match_depth), m_impl(impl), m_description(description ? description : "") {} bool CXXFunctionSummaryFormat::FormatObject(ValueObject *valobj, @@ -150,14 +155,15 @@ bool CXXFunctionSummaryFormat::FormatObject(ValueObject *valobj, std::string CXXFunctionSummaryFormat::GetDescription() { StreamString sstr; - sstr.Printf("%s%s%s%s%s%s%s %s", Cascades() ? "" : " (not cascading)", + sstr.Printf("%s%s%s%s%s%s%s ptr-match-depth=%u %s", + Cascades() ? "" : " (not cascading)", !DoesPrintChildren(nullptr) ? "" : " (show children)", !DoesPrintValue(nullptr) ? " (hide value)" : "", IsOneLiner() ? " (one-line printout)" : "", SkipsPointers() ? " (skip pointers)" : "", SkipsReferences() ? " (skip references)" : "", HideNames(nullptr) ? " (hide member names)" : "", - m_description.c_str()); + GetPtrMatchDepth(), m_description.c_str()); return std::string(sstr.GetString()); } @@ -165,8 +171,9 @@ std::string CXXFunctionSummaryFormat::GetName() { return m_description; } ScriptSummaryFormat::ScriptSummaryFormat(const TypeSummaryImpl::Flags &flags, const char *function_name, - const char *python_script) - : TypeSummaryImpl(Kind::eScript, flags), m_function_name(), + const char *python_script, + uint32_t ptr_match_depth) + : TypeSummaryImpl(Kind::eScript, flags, ptr_match_depth), m_function_name(), m_python_script(), m_script_function_sp() { // Take preference in the python script name over the function name. if (function_name) { @@ -211,13 +218,15 @@ bool ScriptSummaryFormat::FormatObject(ValueObject *valobj, std::string &retval, std::string ScriptSummaryFormat::GetDescription() { StreamString sstr; - sstr.Printf("%s%s%s%s%s%s%s\n ", Cascades() ? "" : " (not cascading)", + sstr.Printf("%s%s%s%s%s%s%s ptr-match-depth=%u\n ", + Cascades() ? "" : " (not cascading)", !DoesPrintChildren(nullptr) ? "" : " (show children)", !DoesPrintValue(nullptr) ? " (hide value)" : "", IsOneLiner() ? " (one-line printout)" : "", SkipsPointers() ? " (skip pointers)" : "", SkipsReferences() ? " (skip references)" : "", - HideNames(nullptr) ? " (hide member names)" : ""); + HideNames(nullptr) ? " (hide member names)" : "", + GetPtrMatchDepth()); if (m_python_script.empty()) { if (m_function_name.empty()) { sstr.PutCString("no backing script"); diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/Makefile new file mode 100644 index 0000000000000..a149c7f81bfab --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/Makefile @@ -0,0 +1,4 @@ +CXX_SOURCES := main.cpp + +CXXFLAGS_EXTRAS := -O0 +include Makefile.rules diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py new file mode 100644 index 0000000000000..f960526466076 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py @@ -0,0 +1,101 @@ +""" +Test lldb data formatter subsystem. +""" + +import os +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class PtrMatchingDataFormatterTestCase(TestBase): + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + # Find the line number to break at. + self.line = line_number("main.cpp", "// Set break point at this line.") + + def test_summary_with_command(self): + """Test "type summary add" command line option "--pointer-match-depth".""" + self.build() + self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET) + + lldbutil.run_break_set_by_file_and_line( + self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True + ) + + self.runCmd("run", RUN_SUCCEEDED) + + # This is the function to remove the custom formats in order to have a + # clean slate for the next test case. + def cleanup(): + self.runCmd("type format clear", check=False) + self.runCmd("type summary clear", check=False) + + # Execute the cleanup function during test case tear down. + self.addTearDownHook(cleanup) + + # By default, --pointer-match-depth is 1. + self.runCmd('type summary add --cascade true -s "MyInt" "Int"') + self.expect("frame variable", patterns=[ + r".* i = MyInt\n", + r".* i_p = 0x.* MyInt\n", + r".* i_pp = 0x[0-9a-f]+\n", + r".* i_ppp = 0x[0-9a-f]+\n", + r".* f = MyInt\n", + r".* f_p = 0x[0-9a-f]+ MyInt\n", + r".* f_pp = 0x[0-9a-f]+\n", + r".* f_ppp = 0x[0-9a-f]+\n", + r".* fp = 0x[0-9a-f]+ MyInt\n", + r".* fp_p = 0x[0-9a-f]+\n", + r".* fp_pp = 0x[0-9a-f]+\n", + r".* b = MyInt\n", + r".* b_p = 0x[0-9a-f]+ MyInt\n", + r".* b_pp = 0x[0-9a-f]+\n", + r".* bp = 0x[0-9a-f]+ MyInt\n", + r".* bp_p = 0x[0-9a-f]+\n", + r".* bp_pp = 0x[0-9a-f]+\n", + ]) + + self.runCmd('type summary delete "Int"') + self.runCmd( + 'type summary add --cascade true --pointer-match-depth 2 -s "MyInt" "Int"') + self.expect("frame variable", patterns=[ + r".* i = MyInt\n", + r".* i_p = 0x.* MyInt\n", + r".* i_pp = 0x[0-9a-f]+ MyInt\n", + r".* i_ppp = 0x[0-9a-f]+\n", + r".* f = MyInt\n", + r".* f_p = 0x[0-9a-f]+ MyInt\n", + r".* f_pp = 0x[0-9a-f]+ MyInt\n", + r".* f_ppp = 0x[0-9a-f]+\n", + r".* fp = 0x[0-9a-f]+ MyInt\n", + r".* fp_p = 0x[0-9a-f]+ MyInt\n", + r".* fp_pp = 0x[0-9a-f]+\n", + r".* b = MyInt\n", + r".* b_p = 0x[0-9a-f]+ MyInt\n", + r".* b_pp = 0x[0-9a-f]+ MyInt\n", + r".* bp = 0x[0-9a-f]+ MyInt\n", + r".* bp_p = 0x[0-9a-f]+ MyInt\n", + r".* bp_pp = 0x[0-9a-f]+\n", + ]) + + self.runCmd('type summary delete "Int"') + self.runCmd( + 'type summary add --cascade true --pointer-match-depth 2 -s "MyFoo" "Foo"') + self.expect("frame variable", patterns=[ + r".* f = MyFoo\n", + r".* f_p = 0x[0-9a-f]+ MyFoo\n", + r".* f_pp = 0x[0-9a-f]+ MyFoo\n", + r".* f_ppp = 0x[0-9a-f]+\n", + r".* fp = 0x[0-9a-f]+\n", + r".* fp_p = 0x[0-9a-f]+\n", + r".* fp_pp = 0x[0-9a-f]+\n", + r".* b = MyFoo\n", + r".* b_p = 0x[0-9a-f]+ MyFoo\n", + r".* b_pp = 0x[0-9a-f]+ MyFoo\n", + r".* bp = 0x[0-9a-f]+ MyFoo\n", + r".* bp_p = 0x[0-9a-f]+ MyFoo\n", + r".* bp_pp = 0x[0-9a-f]+\n", + ]) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/main.cpp new file mode 100644 index 0000000000000..5fafae53d1c21 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/main.cpp @@ -0,0 +1,32 @@ +struct Int { + int i; +}; +typedef Int Foo; +typedef Int* FooP; +typedef Foo Bar; +typedef Foo* BarP; + +int main() { + Int i = {42}; + Int* i_p = &i; + Int** i_pp = &i_p; + Int*** i_ppp = &i_pp; + + Foo f = i; + Foo* f_p = &f; + Foo** f_pp = &f_p; + Foo*** f_ppp = &f_pp; + + FooP fp = f_p; + FooP* fp_p = &fp; + FooP** fp_pp = &fp_p; + + Bar b = i; + Bar* b_p = &b; + Bar** b_pp = &b_p; + + BarP bp = b_p; + BarP* bp_p = &bp; + BarP** bp_pp = &bp_p; + return 0; // Set break point at this line. +} >From 91619c0322bc542da14123f173a3c6b34d412feb Mon Sep 17 00:00:00 2001 From: Zequan Wu Date: Fri, 2 May 2025 11:52:38 -0700 Subject: [PATCH 2/5] address comments --- lldb/docs/use/variable.rst | 10 ++ lldb/source/API/SBTypeSummary.cpp | 2 +- .../source/DataFormatters/TypeCategoryMap.cpp | 8 +- .../TestDataFormatterPtrMatching.py | 109 ++++++++++-------- .../data-formatter-ptr-matching/main.cpp | 28 ++--- 5 files changed, 86 insertions(+), 71 deletions(-) diff --git a/lldb/docs/use/variable.rst b/lldb/docs/use/variable.rst index 3ad71cb93c51d..d6b8b78f01ebe 100644 --- a/lldb/docs/use/variable.rst +++ b/lldb/docs/use/variable.rst @@ -366,6 +366,16 @@ The command to obtain the output shown in the example is: Initially, we will focus on summary strings, and then describe the Python binding mechanism. +Summary Format Matching On Pointers +---------------------- + +When a summary format is registered for a type ``T``, lldb will apply this +format to both ``T`` and ``T*``. -p options could prevent lldb from using this +format to type ``T*``. When -p options is not given, users can use the -d option +to specify how many layer of pointers can be dereferenced at most when matching +the format of type ``T`` (default to 1). It should be noted that the value +object passed to the summary format won't dereferenced at all. + Summary Strings --------------- diff --git a/lldb/source/API/SBTypeSummary.cpp b/lldb/source/API/SBTypeSummary.cpp index d7acb0670018a..58ec068ab9600 100644 --- a/lldb/source/API/SBTypeSummary.cpp +++ b/lldb/source/API/SBTypeSummary.cpp @@ -232,7 +232,7 @@ const char *SBTypeSummary::GetData() { uint32_t SBTypeSummary::GetPtrMatchDepth() { LLDB_INSTRUMENT_VA(this); - + if (!IsValid()) return 0; return m_opaque_sp->GetPtrMatchDepth(); diff --git a/lldb/source/DataFormatters/TypeCategoryMap.cpp b/lldb/source/DataFormatters/TypeCategoryMap.cpp index 8682e4b7435e4..81b7e1f2b7d49 100644 --- a/lldb/source/DataFormatters/TypeCategoryMap.cpp +++ b/lldb/source/DataFormatters/TypeCategoryMap.cpp @@ -184,14 +184,12 @@ void TypeCategoryMap::Get(FormattersMatchData &match_data, ImplSP &retval) { if (log) { for (auto match : match_data.GetMatchesVector()) { LLDB_LOGF( - log, - "[%s] candidate match = %s %s %s %s ptr-stripped-depth=%u", - __FUNCTION__, - match.GetTypeName().GetCString(), + log, "[%s] candidate match = %s %s %s %s ptr-stripped-depth=%u", + __FUNCTION__, match.GetTypeName().GetCString(), match.DidStripPointer() ? "strip-pointers" : "no-strip-pointers", match.DidStripReference() ? "strip-reference" : "no-strip-reference", match.DidStripTypedef() ? "strip-typedef" : "no-strip-typedef", - match.GetPtrStrippedDepth()); + match.GetPtrStrippingDepth()); } } diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py index f960526466076..8de712a749578 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py @@ -38,64 +38,71 @@ def cleanup(): # By default, --pointer-match-depth is 1. self.runCmd('type summary add --cascade true -s "MyInt" "Int"') - self.expect("frame variable", patterns=[ - r".* i = MyInt\n", - r".* i_p = 0x.* MyInt\n", - r".* i_pp = 0x[0-9a-f]+\n", - r".* i_ppp = 0x[0-9a-f]+\n", - r".* f = MyInt\n", - r".* f_p = 0x[0-9a-f]+ MyInt\n", - r".* f_pp = 0x[0-9a-f]+\n", - r".* f_ppp = 0x[0-9a-f]+\n", - r".* fp = 0x[0-9a-f]+ MyInt\n", - r".* fp_p = 0x[0-9a-f]+\n", - r".* fp_pp = 0x[0-9a-f]+\n", - r".* b = MyInt\n", - r".* b_p = 0x[0-9a-f]+ MyInt\n", - r".* b_pp = 0x[0-9a-f]+\n", - r".* bp = 0x[0-9a-f]+ MyInt\n", - r".* bp_p = 0x[0-9a-f]+\n", - r".* bp_pp = 0x[0-9a-f]+\n", + self.expect( + "frame variable", + patterns=[ + r".* i = MyInt\n", + r".* i_p = 0x.* MyInt\n", + r".* i_pp = 0x[0-9a-f]+\n", + r".* i_ppp = 0x[0-9a-f]+\n", + r".* f = MyInt\n", + r".* f_p = 0x[0-9a-f]+ MyInt\n", + r".* f_pp = 0x[0-9a-f]+\n", + r".* f_ppp = 0x[0-9a-f]+\n", + r".* fp = 0x[0-9a-f]+ MyInt\n", + r".* fp_p = 0x[0-9a-f]+\n", + r".* fp_pp = 0x[0-9a-f]+\n", + r".* b = MyInt\n", + r".* b_p = 0x[0-9a-f]+ MyInt\n", + r".* b_pp = 0x[0-9a-f]+\n", + r".* bp = 0x[0-9a-f]+ MyInt\n", + r".* bp_p = 0x[0-9a-f]+\n", + r".* bp_pp = 0x[0-9a-f]+\n", ]) self.runCmd('type summary delete "Int"') self.runCmd( 'type summary add --cascade true --pointer-match-depth 2 -s "MyInt" "Int"') - self.expect("frame variable", patterns=[ - r".* i = MyInt\n", - r".* i_p = 0x.* MyInt\n", - r".* i_pp = 0x[0-9a-f]+ MyInt\n", - r".* i_ppp = 0x[0-9a-f]+\n", - r".* f = MyInt\n", - r".* f_p = 0x[0-9a-f]+ MyInt\n", - r".* f_pp = 0x[0-9a-f]+ MyInt\n", - r".* f_ppp = 0x[0-9a-f]+\n", - r".* fp = 0x[0-9a-f]+ MyInt\n", - r".* fp_p = 0x[0-9a-f]+ MyInt\n", - r".* fp_pp = 0x[0-9a-f]+\n", - r".* b = MyInt\n", - r".* b_p = 0x[0-9a-f]+ MyInt\n", - r".* b_pp = 0x[0-9a-f]+ MyInt\n", - r".* bp = 0x[0-9a-f]+ MyInt\n", - r".* bp_p = 0x[0-9a-f]+ MyInt\n", - r".* bp_pp = 0x[0-9a-f]+\n", + self.expect( + "frame variable", + patterns=[ + r".* i = MyInt\n", + r".* i_p = 0x.* MyInt\n", + r".* i_pp = 0x[0-9a-f]+ MyInt\n", + r".* i_ppp = 0x[0-9a-f]+\n", + r".* f = MyInt\n", + r".* f_p = 0x[0-9a-f]+ MyInt\n", + r".* f_pp = 0x[0-9a-f]+ MyInt\n", + r".* f_ppp = 0x[0-9a-f]+\n", + r".* fp = 0x[0-9a-f]+ MyInt\n", + r".* fp_p = 0x[0-9a-f]+ MyInt\n", + r".* fp_pp = 0x[0-9a-f]+\n", + r".* b = MyInt\n", + r".* b_p = 0x[0-9a-f]+ MyInt\n", + r".* b_pp = 0x[0-9a-f]+ MyInt\n", + r".* bp = 0x[0-9a-f]+ MyInt\n", + r".* bp_p = 0x[0-9a-f]+ MyInt\n", + r".* bp_pp = 0x[0-9a-f]+\n", ]) self.runCmd('type summary delete "Int"') self.runCmd( - 'type summary add --cascade true --pointer-match-depth 2 -s "MyFoo" "Foo"') - self.expect("frame variable", patterns=[ - r".* f = MyFoo\n", - r".* f_p = 0x[0-9a-f]+ MyFoo\n", - r".* f_pp = 0x[0-9a-f]+ MyFoo\n", - r".* f_ppp = 0x[0-9a-f]+\n", - r".* fp = 0x[0-9a-f]+\n", - r".* fp_p = 0x[0-9a-f]+\n", - r".* fp_pp = 0x[0-9a-f]+\n", - r".* b = MyFoo\n", - r".* b_p = 0x[0-9a-f]+ MyFoo\n", - r".* b_pp = 0x[0-9a-f]+ MyFoo\n", - r".* bp = 0x[0-9a-f]+ MyFoo\n", - r".* bp_p = 0x[0-9a-f]+ MyFoo\n", - r".* bp_pp = 0x[0-9a-f]+\n", + 'type summary add --cascade true --pointer-match-depth 2 -s "MyFoo" "Foo"' + ) + self.expect( + "frame variable", + patterns=[ + r".* f = MyFoo\n", + r".* f_p = 0x[0-9a-f]+ MyFoo\n", + r".* f_pp = 0x[0-9a-f]+ MyFoo\n", + r".* f_ppp = 0x[0-9a-f]+\n", + r".* fp = 0x[0-9a-f]+\n", + r".* fp_p = 0x[0-9a-f]+\n", + r".* fp_pp = 0x[0-9a-f]+\n", + r".* b = MyFoo\n", + r".* b_p = 0x[0-9a-f]+ MyFoo\n", + r".* b_pp = 0x[0-9a-f]+ MyFoo\n", + r".* bp = 0x[0-9a-f]+ MyFoo\n", + r".* bp_p = 0x[0-9a-f]+ MyFoo\n", + r".* bp_pp = 0x[0-9a-f]+\n", ]) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/main.cpp index 5fafae53d1c21..2d8c7193b959c 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/main.cpp @@ -2,31 +2,31 @@ struct Int { int i; }; typedef Int Foo; -typedef Int* FooP; +typedef Int *FooP; typedef Foo Bar; -typedef Foo* BarP; +typedef Foo *BarP; int main() { Int i = {42}; - Int* i_p = &i; - Int** i_pp = &i_p; - Int*** i_ppp = &i_pp; + Int *i_p = &i; + Int **i_pp = &i_p; + Int ***i_ppp = &i_pp; Foo f = i; - Foo* f_p = &f; - Foo** f_pp = &f_p; - Foo*** f_ppp = &f_pp; + Foo *f_p = &f; + Foo **f_pp = &f_p; + Foo ***f_ppp = &f_pp; FooP fp = f_p; - FooP* fp_p = &fp; - FooP** fp_pp = &fp_p; + FooP *fp_p = &fp; + FooP **fp_pp = &fp_p; Bar b = i; - Bar* b_p = &b; - Bar** b_pp = &b_p; + Bar *b_p = &b; + Bar **b_pp = &b_p; BarP bp = b_p; - BarP* bp_p = &bp; - BarP** bp_pp = &bp_p; + BarP *bp_p = &bp; + BarP **bp_pp = &bp_p; return 0; // Set break point at this line. } >From 022526721fcf7d917626d004467f121e7cf33a3c Mon Sep 17 00:00:00 2001 From: Zequan Wu Date: Fri, 2 May 2025 13:41:24 -0700 Subject: [PATCH 3/5] format --- .../TestDataFormatterPtrMatching.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py index 8de712a749578..ebefe87e913a3 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py @@ -58,11 +58,13 @@ def cleanup(): r".* bp = 0x[0-9a-f]+ MyInt\n", r".* bp_p = 0x[0-9a-f]+\n", r".* bp_pp = 0x[0-9a-f]+\n", - ]) + ], + ) self.runCmd('type summary delete "Int"') self.runCmd( - 'type summary add --cascade true --pointer-match-depth 2 -s "MyInt" "Int"') + 'type summary add --cascade true --pointer-match-depth 2 -s "MyInt" "Int"' + ) self.expect( "frame variable", patterns=[ @@ -83,7 +85,8 @@ def cleanup(): r".* bp = 0x[0-9a-f]+ MyInt\n", r".* bp_p = 0x[0-9a-f]+ MyInt\n", r".* bp_pp = 0x[0-9a-f]+\n", - ]) + ], + ) self.runCmd('type summary delete "Int"') self.runCmd( @@ -105,4 +108,5 @@ def cleanup(): r".* bp = 0x[0-9a-f]+ MyFoo\n", r".* bp_p = 0x[0-9a-f]+ MyFoo\n", r".* bp_pp = 0x[0-9a-f]+\n", - ]) + ], + ) >From d6ca5bc643ee2be77febbde219fcfd011f855483 Mon Sep 17 00:00:00 2001 From: Zequan Wu Date: Fri, 2 May 2025 15:26:10 -0700 Subject: [PATCH 4/5] fix name --- lldb/source/DataFormatters/TypeCategoryMap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/DataFormatters/TypeCategoryMap.cpp b/lldb/source/DataFormatters/TypeCategoryMap.cpp index 81b7e1f2b7d49..c318e1d2d1354 100644 --- a/lldb/source/DataFormatters/TypeCategoryMap.cpp +++ b/lldb/source/DataFormatters/TypeCategoryMap.cpp @@ -189,7 +189,7 @@ void TypeCategoryMap::Get(FormattersMatchData &match_data, ImplSP &retval) { match.DidStripPointer() ? "strip-pointers" : "no-strip-pointers", match.DidStripReference() ? "strip-reference" : "no-strip-reference", match.DidStripTypedef() ? "strip-typedef" : "no-strip-typedef", - match.GetPtrStrippingDepth()); + match.GetPtrStrippedDepth()); } } >From 1ed7fdc90da535d6ddc570431d0003d4021f6e97 Mon Sep 17 00:00:00 2001 From: Zequan Wu Date: Fri, 16 May 2025 13:58:43 -0700 Subject: [PATCH 5/5] rephrase doc --- lldb/docs/use/variable.rst | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lldb/docs/use/variable.rst b/lldb/docs/use/variable.rst index d6b8b78f01ebe..7a4c562c5bd41 100644 --- a/lldb/docs/use/variable.rst +++ b/lldb/docs/use/variable.rst @@ -369,12 +369,16 @@ binding mechanism. Summary Format Matching On Pointers ---------------------- -When a summary format is registered for a type ``T``, lldb will apply this -format to both ``T`` and ``T*``. -p options could prevent lldb from using this -format to type ``T*``. When -p options is not given, users can use the -d option -to specify how many layer of pointers can be dereferenced at most when matching -the format of type ``T`` (default to 1). It should be noted that the value -object passed to the summary format won't dereferenced at all. +A summary formatter for a type ``T`` might or might not be appropriate to use +for pointers to that type. If the formatter is only appropriate for the type and +not its pointers, use the ``-p`` option to restrict it to match SBValues of type +``T``. If you want the formatter to also match pointers to the type, you can use +the ``-d`` option to specify how many pointer layers the formatter should match. +The default value is 1, so if you don't specify ``-p`` or ``-d``, your formatter +will be used on SBValues of type ``T`` and ``T*``. If you want to also match +``T**`` set ``-d`` to 2, etc. In all cases, the SBValue passed to the summary +formatter will be the matched ValueObject. lldb doesn't dereference the matched +value down to the SBValue of type ``T`` before passing it to your formatter. Summary Strings --------------- From lldb-commits at lists.llvm.org Fri May 16 15:25:15 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Fri, 16 May 2025 15:25:15 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adjusting startup flow to better handle async operations. (PR #140299) In-Reply-To: Message-ID: <6827bb4b.050a0220.2c82d9.67ed@mx.google.com> JDevlieghere wrote: I haven't looked at the code yet. I was re-reading the launch sequence part of the spec [1] to make sure this still complies, and I believe it does because the spec talks about _responding_ to the request, not about _handling_ it. > After the response to configurationDone is sent, the debug adapter may respond to the launch or attach request, and then the debug session has started. That said, does this actually solve the underlying problems? We know that VS Code sends the launch and attach request before configuration done. It's equally valid to not do that, and do things the way they're shown in the sequence diagram, where you set breakpoints, then configuration done, then launch or attach. Won't that still hit the same problem? [1] https://microsoft.github.io/debug-adapter-protocol/overview https://github.com/llvm/llvm-project/pull/140299 From lldb-commits at lists.llvm.org Fri May 16 15:45:06 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 15:45:06 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adjusting startup flow to better handle async operations. (PR #140299) In-Reply-To: Message-ID: <6827bff2.630a0220.3cb728.a08d@mx.google.com> ashgti wrote: > That said, does this actually solve the underlying problems? We know that VS Code sends the launch and attach request before configuration done. It's equally valid to not do that, and do things the way they're shown in the sequence diagram, where you set breakpoints, then configuration done, then launch or attach. Won't that still hit the same problem? I think there are 2 specific problems that we have after ba29e60f9a2222bd5e883579bb78db13fc5a7588. 1. The pending request filter is somewhat fragile and for @da-viper use case of implementing support for [supportsDataBreakpointBytes](https://microsoft.github.io/debug-adapter-protocol//specification.html#Requests_DataBreakpointInfo) they're running into issues trying to respond to the `dataBreakpointInfo` request without access to a valid target but by not responding to the request, we're not getting `configurationDone`. 2. With the new launch flow, we're setting breakpoints before we've created a target, which is why I'm seeing us missing breakpoint events now when we used to not miss with `launchCommands`. As for the sequence, the flow has 2 parallel tracks that are independently triggered. The overall flow is: * After capabilities are returned from the initialize request trigger the `request launch` or `request attach` * After adapter sends `event initialized`, trigger the `setBreakpoints`, `setFunctionBreakpoints`, `setExceptionBreakpoints `, `setDataBreakpoints`, etc. followed by `configurationDone`. We're actually triggering the configuration flow by sending `event initialized` so we can adjust when that happens. Per the spec: > the debug adapter is expected to send an [initialized](https://microsoft.github.io/debug-adapter-protocol/specification#Events_Initialized) event to the development tool to announce that it is ready to accept configuration requests. With this approach a debug adapter does not have to implement a buffering strategy for configuration information. Maybe we should look at moving the `initialized` event to after we've responded to the `launch`/`attach` commands instead of buffering or making them async. https://github.com/llvm/llvm-project/pull/140299 From lldb-commits at lists.llvm.org Fri May 16 15:52:58 2025 From: lldb-commits at lists.llvm.org (Jacob Lalonde via lldb-commits) Date: Fri, 16 May 2025 15:52:58 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB][ELF Core] Support all the Generic (Negative) SI Codes. (PR #140150) In-Reply-To: Message-ID: <6827c1ca.170a0220.2c2147.63cf@mx.google.com> https://github.com/Jlalond updated https://github.com/llvm/llvm-project/pull/140150 >From 86ec6c076b9cf8e7afeb7d6bb0e334434f6e0d9e Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Thu, 15 May 2025 13:57:11 -0700 Subject: [PATCH 1/7] Update ThreadElfCore --- lldb/include/lldb/Target/UnixSignals.h | 6 ++++-- .../Plugins/Process/Utility/LinuxSignals.cpp | 17 ++++++++++++++--- .../Plugins/Process/elf-core/ThreadElfCore.cpp | 10 +++++++--- .../Plugins/Process/elf-core/ThreadElfCore.h | 6 ++++++ lldb/source/Target/UnixSignals.cpp | 9 +++++++-- 5 files changed, 38 insertions(+), 10 deletions(-) diff --git a/lldb/include/lldb/Target/UnixSignals.h b/lldb/include/lldb/Target/UnixSignals.h index b3605ccefddbe..a1807d69f329b 100644 --- a/lldb/include/lldb/Target/UnixSignals.h +++ b/lldb/include/lldb/Target/UnixSignals.h @@ -36,7 +36,9 @@ class UnixSignals { std::optional code = std::nullopt, std::optional addr = std::nullopt, std::optional lower = std::nullopt, - std::optional upper = std::nullopt) const; + std::optional upper = std::nullopt, + std::optional pid = std::nullopt, + std::optional uid = std::nullopt) const; bool SignalIsValid(int32_t signo) const; @@ -105,7 +107,7 @@ class UnixSignals { llvm::StringRef description, llvm::StringRef alias = llvm::StringRef()); - enum SignalCodePrintOption { None, Address, Bounds }; + enum SignalCodePrintOption { None, Address, Bounds, Sender }; // Instead of calling this directly, use a ADD_SIGCODE macro to get compile // time checks when on the native platform. diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index 9c4fe55147a28..25d4e4609bbb8 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -38,6 +38,17 @@ #define ADD_SIGCODE(signal_name, signal_value, code_name, code_value, ...) \ AddSignalCode(signal_value, code_value, __VA_ARGS__) #endif /* if defined(__linux__) && !defined(__mips__) */ +// See siginfo.h in the Linux Kernel, these codes can be sent for any signal. +#define ADD_LINUX_SIGNAL(signo, name, ...) \ + AddSignal(signo, name, __VA_ARGS__); \ + ADD_SIGCODE(signo, signo, SI_QUEUE, -1, "sent by sigqueue"); \ + ADD_SIGCODE(signo, signo, SI_TIMER, -2, "sent by timer expiration"); \ + ADD_SIGCODE(signo, signo, SI_MESGQ, -3, "sent by real time mesq state change"); \ + ADD_SIGCODE(signo, signo, SI_ASYNCIO, -4, "sent by AIO completion"); \ + ADD_SIGCODE(signo, signo, SI_SIGIO, -5, "sent by queued SIGIO"); \ + ADD_SIGCODE(signo, signo, SI_TKILL, -6, "sent by tkill system call"); \ + ADD_SIGCODE(signo, signo, SI_DETHREAD, -7, "sent by execve() killing subsidiary threads"); \ + ADD_SIGCODE(signo, signo, SI_ASYNCNL, -60, "sent by glibc async name lookup completion"); using namespace lldb_private; @@ -46,9 +57,9 @@ LinuxSignals::LinuxSignals() : UnixSignals() { Reset(); } void LinuxSignals::Reset() { m_signals.clear(); // clang-format off - // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION - // ====== ============== ======== ====== ====== =================================================== - AddSignal(1, "SIGHUP", false, true, true, "hangup"); + // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION + // ====== ============== ======== ====== ====== =================================================== + ADD_LINUX_SIGNAL(1, "SIGHUP", false, true, true, "hangup"); AddSignal(2, "SIGINT", true, true, true, "interrupt"); AddSignal(3, "SIGQUIT", false, true, true, "quit"); diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index a0cd0ee5025bd..267879a473463 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -584,9 +584,13 @@ Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, // 64b ELF have a 4 byte pad. if (data.GetAddressByteSize() == 8) offset += 4; - // Not every stop signal has a valid address, but that will get resolved in - // the unix_signals.GetSignalDescription() call below. - if (unix_signals.GetShouldStop(si_signo)) { + + if (si_code < 0) { + sigfault.kill._pid = data.GetU32(&offset); + sigfault.kill._uid = data.GetU32(&offset); + } else if (unix_signals.GetShouldStop(si_signo)) { + // Not every stop signal has a valid address, but that will get resolved in + // the unix_signals.GetSignalDescription() call below. // Instead of memcpy we call all these individually as the extractor will // handle endianness for us. sigfault.si_addr = data.GetAddress(&offset); diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h index 6f8d41351a6bf..2cbf794c2b5b1 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -96,6 +96,12 @@ struct ELFLinuxSigInfo { /* used when si_code=SEGV_PKUERR */ uint32_t _pkey; } bounds; + + // We need this for all the generic signals. + struct { + uint32_t _pid; /* sender's pid */ + uint32_t _uid; /* sender's uid */ + } _kill; } sigfault; enum SigInfoNoteType : uint8_t { eUnspecified, eNT_SIGINFO }; diff --git a/lldb/source/Target/UnixSignals.cpp b/lldb/source/Target/UnixSignals.cpp index da661003925c7..a5dbfd029410a 100644 --- a/lldb/source/Target/UnixSignals.cpp +++ b/lldb/source/Target/UnixSignals.cpp @@ -141,7 +141,9 @@ std::string UnixSignals::GetSignalDescription(int32_t signo, std::optional code, std::optional addr, std::optional lower, - std::optional upper) const { + std::optional upper, + std::optional pid, + std::optional uid) const { std::string str; collection::const_iterator pos = m_signals.find(signo); @@ -180,6 +182,10 @@ UnixSignals::GetSignalDescription(int32_t signo, std::optional code, strm << sc.m_description.str(); break; + case SignalCodePrintOption::Sender: + if (pid && uid) + strm << " (sender pid=" << *pid << ", uid=" << *uid << ")"; + break; } str += strm.str(); } @@ -397,4 +403,3 @@ bool UnixSignals::ResetSignal(int32_t signo, bool reset_stop, (*elem).second.Reset(reset_stop, reset_notify, reset_suppress); return true; } - >From 6d8a30cc38816f661cd3126613987ccbde39ab05 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Thu, 15 May 2025 14:33:15 -0700 Subject: [PATCH 2/7] Add sender option to LinuxSignals.cpp --- .../Plugins/Process/Utility/LinuxSignals.cpp | 142 +++++++++--------- .../Process/elf-core/ThreadElfCore.cpp | 32 ++-- .../Plugins/Process/elf-core/ThreadElfCore.h | 44 +++--- 3 files changed, 111 insertions(+), 107 deletions(-) diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index 25d4e4609bbb8..da0abf5a1f471 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -41,14 +41,14 @@ // See siginfo.h in the Linux Kernel, these codes can be sent for any signal. #define ADD_LINUX_SIGNAL(signo, name, ...) \ AddSignal(signo, name, __VA_ARGS__); \ - ADD_SIGCODE(signo, signo, SI_QUEUE, -1, "sent by sigqueue"); \ - ADD_SIGCODE(signo, signo, SI_TIMER, -2, "sent by timer expiration"); \ - ADD_SIGCODE(signo, signo, SI_MESGQ, -3, "sent by real time mesq state change"); \ - ADD_SIGCODE(signo, signo, SI_ASYNCIO, -4, "sent by AIO completion"); \ - ADD_SIGCODE(signo, signo, SI_SIGIO, -5, "sent by queued SIGIO"); \ - ADD_SIGCODE(signo, signo, SI_TKILL, -6, "sent by tkill system call"); \ - ADD_SIGCODE(signo, signo, SI_DETHREAD, -7, "sent by execve() killing subsidiary threads"); \ - ADD_SIGCODE(signo, signo, SI_ASYNCNL, -60, "sent by glibc async name lookup completion"); + ADD_SIGCODE(signo, signo, SI_QUEUE, -1, "sent by sigqueue", SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_TIMER, -2, "sent by timer expiration", SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_MESGQ, -3, "sent by real time mesq state change", SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_ASYNCIO, -4, "sent by AIO completion", SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_SIGIO, -5, "sent by queued SIGIO", SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_TKILL, -6, "sent by tkill system call", SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_DETHREAD, -7, "sent by execve() killing subsidiary threads", SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_ASYNCNL, -60, "sent by glibc async name lookup completion", SignalCodePrintOption::Sender); using namespace lldb_private; @@ -60,10 +60,10 @@ void LinuxSignals::Reset() { // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION // ====== ============== ======== ====== ====== =================================================== ADD_LINUX_SIGNAL(1, "SIGHUP", false, true, true, "hangup"); - AddSignal(2, "SIGINT", true, true, true, "interrupt"); - AddSignal(3, "SIGQUIT", false, true, true, "quit"); + ADD_LINUX_SIGNAL(2, "SIGINT", true, true, true, "interrupt"); + ADD_LINUX_SIGNAL(3, "SIGQUIT", false, true, true, "quit"); - AddSignal(4, "SIGILL", false, true, true, "illegal instruction"); + ADD_LINUX_SIGNAL(4, "SIGILL", false, true, true, "illegal instruction"); ADD_SIGCODE(SIGILL, 4, ILL_ILLOPC, 1, "illegal opcode"); ADD_SIGCODE(SIGILL, 4, ILL_ILLOPN, 2, "illegal operand"); ADD_SIGCODE(SIGILL, 4, ILL_ILLADR, 3, "illegal addressing mode"); @@ -73,15 +73,15 @@ void LinuxSignals::Reset() { ADD_SIGCODE(SIGILL, 4, ILL_COPROC, 7, "coprocessor error"); ADD_SIGCODE(SIGILL, 4, ILL_BADSTK, 8, "internal stack error"); - AddSignal(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)"); - AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT"); + ADD_LINUX_SIGNAL(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)"); + ADD_LINUX_SIGNAL(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT"); - AddSignal(7, "SIGBUS", false, true, true, "bus error"); + ADD_LINUX_SIGNAL(7, "SIGBUS", false, true, true, "bus error"); ADD_SIGCODE(SIGBUS, 7, BUS_ADRALN, 1, "illegal alignment"); ADD_SIGCODE(SIGBUS, 7, BUS_ADRERR, 2, "illegal address"); ADD_SIGCODE(SIGBUS, 7, BUS_OBJERR, 3, "hardware error"); - AddSignal(8, "SIGFPE", false, true, true, "floating point exception"); + ADD_LINUX_SIGNAL(8, "SIGFPE", false, true, true, "floating point exception"); ADD_SIGCODE(SIGFPE, 8, FPE_INTDIV, 1, "integer divide by zero"); ADD_SIGCODE(SIGFPE, 8, FPE_INTOVF, 2, "integer overflow"); ADD_SIGCODE(SIGFPE, 8, FPE_FLTDIV, 3, "floating point divide by zero"); @@ -91,10 +91,10 @@ void LinuxSignals::Reset() { ADD_SIGCODE(SIGFPE, 8, FPE_FLTINV, 7, "floating point invalid operation"); ADD_SIGCODE(SIGFPE, 8, FPE_FLTSUB, 8, "subscript out of range"); - AddSignal(9, "SIGKILL", false, true, true, "kill"); - AddSignal(10, "SIGUSR1", false, true, true, "user defined signal 1"); + ADD_LINUX_SIGNAL(9, "SIGKILL", false, true, true, "kill"); + ADD_LINUX_SIGNAL(10, "SIGUSR1", false, true, true, "user defined signal 1"); - AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation"); + ADD_LINUX_SIGNAL(11, "SIGSEGV", false, true, true, "segmentation violation"); ADD_SIGCODE(SIGSEGV, 11, SEGV_MAPERR, 1, "address not mapped to object", SignalCodePrintOption::Address); ADD_SIGCODE(SIGSEGV, 11, SEGV_ACCERR, 2, "invalid permissions for mapped object", SignalCodePrintOption::Address); ADD_SIGCODE(SIGSEGV, 11, SEGV_BNDERR, 3, "failed address bounds checks", SignalCodePrintOption::Bounds); @@ -105,58 +105,58 @@ void LinuxSignals::Reset() { // codes. One way to get this is via unaligned SIMD loads. Treat it as invalid address. ADD_SIGCODE(SIGSEGV, 11, SI_KERNEL, 0x80, "invalid address", SignalCodePrintOption::Address); - AddSignal(12, "SIGUSR2", false, true, true, "user defined signal 2"); - AddSignal(13, "SIGPIPE", false, true, true, "write to pipe with reading end closed"); - AddSignal(14, "SIGALRM", false, false, false, "alarm"); - AddSignal(15, "SIGTERM", false, true, true, "termination requested"); - AddSignal(16, "SIGSTKFLT", false, true, true, "stack fault"); - AddSignal(17, "SIGCHLD", false, false, true, "child status has changed", "SIGCLD"); - AddSignal(18, "SIGCONT", false, false, true, "process continue"); - AddSignal(19, "SIGSTOP", true, true, true, "process stop"); - AddSignal(20, "SIGTSTP", false, true, true, "tty stop"); - AddSignal(21, "SIGTTIN", false, true, true, "background tty read"); - AddSignal(22, "SIGTTOU", false, true, true, "background tty write"); - AddSignal(23, "SIGURG", false, true, true, "urgent data on socket"); - AddSignal(24, "SIGXCPU", false, true, true, "CPU resource exceeded"); - AddSignal(25, "SIGXFSZ", false, true, true, "file size limit exceeded"); - AddSignal(26, "SIGVTALRM", false, true, true, "virtual time alarm"); - AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm"); - AddSignal(28, "SIGWINCH", false, true, true, "window size changes"); - AddSignal(29, "SIGIO", false, true, true, "input/output ready/Pollable event", "SIGPOLL"); - AddSignal(30, "SIGPWR", false, true, true, "power failure"); - AddSignal(31, "SIGSYS", false, true, true, "invalid system call"); - AddSignal(32, "SIG32", false, false, false, "threading library internal signal 1"); - AddSignal(33, "SIG33", false, false, false, "threading library internal signal 2"); - AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0"); - AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1"); - AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2"); - AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3"); - AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4"); - AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5"); - AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6"); - AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7"); - AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8"); - AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9"); - AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10"); - AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11"); - AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12"); - AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13"); - AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14"); - AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15"); - AddSignal(50, "SIGRTMAX-14", false, false, false, "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output - AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17"); - AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18"); - AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19"); - AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20"); - AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21"); - AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22"); - AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23"); - AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24"); - AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25"); - AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26"); - AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27"); - AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28"); - AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29"); - AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30"); + ADD_LINUX_SIGNAL(12, "SIGUSR2", false, true, true, "user defined signal 2"); + ADD_LINUX_SIGNAL(13, "SIGPIPE", false, true, true, "write to pipe with reading end closed"); + ADD_LINUX_SIGNAL(14, "SIGALRM", false, false, false, "alarm"); + ADD_LINUX_SIGNAL(15, "SIGTERM", false, true, true, "termination requested"); + ADD_LINUX_SIGNAL(16, "SIGSTKFLT", false, true, true, "stack fault"); + ADD_LINUX_SIGNAL(17, "SIGCHLD", false, false, true, "child status has changed", "SIGCLD"); + ADD_LINUX_SIGNAL(18, "SIGCONT", false, false, true, "process continue"); + ADD_LINUX_SIGNAL(19, "SIGSTOP", true, true, true, "process stop"); + ADD_LINUX_SIGNAL(20, "SIGTSTP", false, true, true, "tty stop"); + ADD_LINUX_SIGNAL(21, "SIGTTIN", false, true, true, "background tty read"); + ADD_LINUX_SIGNAL(22, "SIGTTOU", false, true, true, "background tty write"); + ADD_LINUX_SIGNAL(23, "SIGURG", false, true, true, "urgent data on socket"); + ADD_LINUX_SIGNAL(24, "SIGXCPU", false, true, true, "CPU resource exceeded"); + ADD_LINUX_SIGNAL(25, "SIGXFSZ", false, true, true, "file size limit exceeded"); + ADD_LINUX_SIGNAL(26, "SIGVTALRM", false, true, true, "virtual time alarm"); + ADD_LINUX_SIGNAL(27, "SIGPROF", false, false, false, "profiling time alarm"); + ADD_LINUX_SIGNAL(28, "SIGWINCH", false, true, true, "window size changes"); + ADD_LINUX_SIGNAL(29, "SIGIO", false, true, true, "input/output ready/Pollable event", "SIGPOLL"); + ADD_LINUX_SIGNAL(30, "SIGPWR", false, true, true, "power failure"); + ADD_LINUX_SIGNAL(31, "SIGSYS", false, true, true, "invalid system call"); + ADD_LINUX_SIGNAL(32, "SIG32", false, false, false, "threading library internal signal 1"); + ADD_LINUX_SIGNAL(33, "SIG33", false, false, false, "threading library internal signal 2"); + ADD_LINUX_SIGNAL(34, "SIGRTMIN", false, false, false, "real time signal 0"); + ADD_LINUX_SIGNAL(35, "SIGRTMIN+1", false, false, false, "real time signal 1"); + ADD_LINUX_SIGNAL(36, "SIGRTMIN+2", false, false, false, "real time signal 2"); + ADD_LINUX_SIGNAL(37, "SIGRTMIN+3", false, false, false, "real time signal 3"); + ADD_LINUX_SIGNAL(38, "SIGRTMIN+4", false, false, false, "real time signal 4"); + ADD_LINUX_SIGNAL(39, "SIGRTMIN+5", false, false, false, "real time signal 5"); + ADD_LINUX_SIGNAL(40, "SIGRTMIN+6", false, false, false, "real time signal 6"); + ADD_LINUX_SIGNAL(41, "SIGRTMIN+7", false, false, false, "real time signal 7"); + ADD_LINUX_SIGNAL(42, "SIGRTMIN+8", false, false, false, "real time signal 8"); + ADD_LINUX_SIGNAL(43, "SIGRTMIN+9", false, false, false, "real time signal 9"); + ADD_LINUX_SIGNAL(44, "SIGRTMIN+10", false, false, false, "real time signal 10"); + ADD_LINUX_SIGNAL(45, "SIGRTMIN+11", false, false, false, "real time signal 11"); + ADD_LINUX_SIGNAL(46, "SIGRTMIN+12", false, false, false, "real time signal 12"); + ADD_LINUX_SIGNAL(47, "SIGRTMIN+13", false, false, false, "real time signal 13"); + ADD_LINUX_SIGNAL(48, "SIGRTMIN+14", false, false, false, "real time signal 14"); + ADD_LINUX_SIGNAL(49, "SIGRTMIN+15", false, false, false, "real time signal 15"); + ADD_LINUX_SIGNAL(50, "SIGRTMAX-14", false, false, false, "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output + ADD_LINUX_SIGNAL(51, "SIGRTMAX-13", false, false, false, "real time signal 17"); + ADD_LINUX_SIGNAL(52, "SIGRTMAX-12", false, false, false, "real time signal 18"); + ADD_LINUX_SIGNAL(53, "SIGRTMAX-11", false, false, false, "real time signal 19"); + ADD_LINUX_SIGNAL(54, "SIGRTMAX-10", false, false, false, "real time signal 20"); + ADD_LINUX_SIGNAL(55, "SIGRTMAX-9", false, false, false, "real time signal 21"); + ADD_LINUX_SIGNAL(56, "SIGRTMAX-8", false, false, false, "real time signal 22"); + ADD_LINUX_SIGNAL(57, "SIGRTMAX-7", false, false, false, "real time signal 23"); + ADD_LINUX_SIGNAL(58, "SIGRTMAX-6", false, false, false, "real time signal 24"); + ADD_LINUX_SIGNAL(59, "SIGRTMAX-5", false, false, false, "real time signal 25"); + ADD_LINUX_SIGNAL(60, "SIGRTMAX-4", false, false, false, "real time signal 26"); + ADD_LINUX_SIGNAL(61, "SIGRTMAX-3", false, false, false, "real time signal 27"); + ADD_LINUX_SIGNAL(62, "SIGRTMAX-2", false, false, false, "real time signal 28"); + ADD_LINUX_SIGNAL(63, "SIGRTMAX-1", false, false, false, "real time signal 29"); + ADD_LINUX_SIGNAL(64, "SIGRTMAX", false, false, false, "real time signal 30"); // clang-format on } diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index 267879a473463..ce0f65cd9f14c 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -586,24 +586,24 @@ Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, offset += 4; if (si_code < 0) { - sigfault.kill._pid = data.GetU32(&offset); - sigfault.kill._uid = data.GetU32(&offset); + sifields.kill.pid = data.GetU32(&offset); + sifields.kill.uid = data.GetU32(&offset); } else if (unix_signals.GetShouldStop(si_signo)) { // Not every stop signal has a valid address, but that will get resolved in // the unix_signals.GetSignalDescription() call below. // Instead of memcpy we call all these individually as the extractor will // handle endianness for us. - sigfault.si_addr = data.GetAddress(&offset); - sigfault.si_addr_lsb = data.GetU16(&offset); - if (data.GetByteSize() - offset >= sizeof(sigfault.bounds)) { - sigfault.bounds._addr_bnd._lower = data.GetAddress(&offset); - sigfault.bounds._addr_bnd._upper = data.GetAddress(&offset); - sigfault.bounds._pkey = data.GetU32(&offset); + sifields.sigfault.si_addr = data.GetAddress(&offset); + sifields.sigfault.si_addr_lsb = data.GetU16(&offset); + if (data.GetByteSize() - offset >= sizeof(sifields.sigfault.bounds)) { + sifields.sigfault.bounds._addr_bnd._lower = data.GetAddress(&offset); + sifields.sigfault.bounds._addr_bnd._upper = data.GetAddress(&offset); + sifields.sigfault.bounds._pkey = data.GetU32(&offset); } else { // Set these to 0 so we don't use bogus data for the description. - sigfault.bounds._addr_bnd._lower = 0; - sigfault.bounds._addr_bnd._upper = 0; - sigfault.bounds._pkey = 0; + sifields.sigfault.bounds._addr_bnd._lower = 0; + sifields.sigfault.bounds._addr_bnd._upper = 0; + sifields.sigfault.bounds._pkey = 0; } } @@ -613,13 +613,15 @@ Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, std::string ELFLinuxSigInfo::GetDescription( const lldb_private::UnixSignals &unix_signals) const { if (unix_signals.GetShouldStop(si_signo) && note_type == eNT_SIGINFO) { - if (sigfault.bounds._addr_bnd._upper != 0) + if (si_code < 0) + return unix_signals.GetSignalDescription(si_signo, si_code, std::nullopt, std::nullopt, std::nullopt, sifields.kill.pid, sifields.kill.uid); + else if (sifields.sigfault.bounds._addr_bnd._upper != 0) return unix_signals.GetSignalDescription( - si_signo, si_code, sigfault.si_addr, sigfault.bounds._addr_bnd._lower, - sigfault.bounds._addr_bnd._upper); + si_signo, si_code, sifields.sigfault.si_addr, sifields.sigfault.bounds._addr_bnd._lower, + sifields.sigfault.bounds._addr_bnd._upper); else return unix_signals.GetSignalDescription(si_signo, si_code, - sigfault.si_addr); + sifields.sigfault.si_addr); } // This looks weird, but there is an existing pattern where we don't pass a diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h index 2cbf794c2b5b1..2c254b4b522e9 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -82,27 +82,29 @@ struct ELFLinuxSigInfo { int32_t si_signo; // Order matters for the first 3. int32_t si_errno; int32_t si_code; - // Copied from siginfo_t so we don't have to include signal.h on non 'Nix - // builds. Slight modifications to ensure no 32b vs 64b differences. - struct alignas(8) { - lldb::addr_t si_addr; /* faulting insn/memory ref. */ - int16_t si_addr_lsb; /* Valid LSB of the reported address. */ - union { - /* used when si_code=SEGV_BNDERR */ - struct { - lldb::addr_t _lower; - lldb::addr_t _upper; - } _addr_bnd; - /* used when si_code=SEGV_PKUERR */ - uint32_t _pkey; - } bounds; - - // We need this for all the generic signals. - struct { - uint32_t _pid; /* sender's pid */ - uint32_t _uid; /* sender's uid */ - } _kill; - } sigfault; + union alignas(8) { + struct alignas(8) { + uint32_t pid; /* sender's pid */ + uint32_t uid; /* sender's uid */ + } kill; + // Copied from siginfo_t so we don't have to include signal.h on non 'Nix + // builds. Slight modifications to ensure no 32b vs 64b differences. + struct alignas(8) { + lldb::addr_t si_addr; /* faulting insn/memory ref. */ + int16_t si_addr_lsb; /* Valid LSB of the reported address. */ + union { + /* used when si_code=SEGV_BNDERR */ + struct { + lldb::addr_t _lower; + lldb::addr_t _upper; + } _addr_bnd; + /* used when si_code=SEGV_PKUERR */ + uint32_t _pkey; + } bounds; + + // We need this for all the generic signals. + } sigfault; + } sifields; enum SigInfoNoteType : uint8_t { eUnspecified, eNT_SIGINFO }; SigInfoNoteType note_type; >From 9e352e71666628c7e81f520e8619779cc7a6e150 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Thu, 15 May 2025 14:46:40 -0700 Subject: [PATCH 3/7] Add test for sender case --- lldb/unittests/Signals/UnixSignalsTest.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lldb/unittests/Signals/UnixSignalsTest.cpp b/lldb/unittests/Signals/UnixSignalsTest.cpp index 9a7d9afc2b185..825cc5ea6a782 100644 --- a/lldb/unittests/Signals/UnixSignalsTest.cpp +++ b/lldb/unittests/Signals/UnixSignalsTest.cpp @@ -27,6 +27,7 @@ class TestSignals : public UnixSignals { AddSignalCode(16, 2, "SIG16 with a fault address", SignalCodePrintOption::Address); AddSignalCode(16, 3, "bounds violation", SignalCodePrintOption::Bounds); + AddSignalCode(16, -6, "sent by tkill system call", SignalCodePrintOption::Sender); } }; @@ -124,6 +125,10 @@ TEST(UnixSignalsTest, GetAsString) { // No address given just print the code description. ASSERT_EQ("SIG16: SIG16 with a fault address", signals.GetSignalDescription(16, 2)); + // TKill, but with no sender + ASSERT_EQ("SIG16: sent by tkill system call", signals.GetSignalDescription(16, -6, 0xCAFEF00D)); + // TKill, but with no sender + ASSERT_EQ("SIG16: sent by tkill system call (sender pid=912, uid=99)", signals.GetSignalDescription(16, -6, 0xCAFEF00D, std::nullopt, std::nullopt, 912, 99)); const char *expected = "SIG16: bounds violation"; // Must pass all needed info to get full output. >From 1a1b9fa48bead59a15291a58814e363cd4412f55 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Thu, 15 May 2025 15:03:32 -0700 Subject: [PATCH 4/7] run GCF --- .../Plugins/Process/Utility/LinuxSignals.cpp | 31 +++++++++++++------ .../Process/elf-core/ThreadElfCore.cpp | 17 +++++----- .../Plugins/Process/elf-core/ThreadElfCore.h | 4 +-- lldb/source/Target/UnixSignals.cpp | 12 +++---- lldb/unittests/Signals/UnixSignalsTest.cpp | 10 ++++-- 5 files changed, 45 insertions(+), 29 deletions(-) diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index da0abf5a1f471..76c32e376eb4b 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -39,16 +39,27 @@ AddSignalCode(signal_value, code_value, __VA_ARGS__) #endif /* if defined(__linux__) && !defined(__mips__) */ // See siginfo.h in the Linux Kernel, these codes can be sent for any signal. -#define ADD_LINUX_SIGNAL(signo, name, ...) \ - AddSignal(signo, name, __VA_ARGS__); \ - ADD_SIGCODE(signo, signo, SI_QUEUE, -1, "sent by sigqueue", SignalCodePrintOption::Sender); \ - ADD_SIGCODE(signo, signo, SI_TIMER, -2, "sent by timer expiration", SignalCodePrintOption::Sender); \ - ADD_SIGCODE(signo, signo, SI_MESGQ, -3, "sent by real time mesq state change", SignalCodePrintOption::Sender); \ - ADD_SIGCODE(signo, signo, SI_ASYNCIO, -4, "sent by AIO completion", SignalCodePrintOption::Sender); \ - ADD_SIGCODE(signo, signo, SI_SIGIO, -5, "sent by queued SIGIO", SignalCodePrintOption::Sender); \ - ADD_SIGCODE(signo, signo, SI_TKILL, -6, "sent by tkill system call", SignalCodePrintOption::Sender); \ - ADD_SIGCODE(signo, signo, SI_DETHREAD, -7, "sent by execve() killing subsidiary threads", SignalCodePrintOption::Sender); \ - ADD_SIGCODE(signo, signo, SI_ASYNCNL, -60, "sent by glibc async name lookup completion", SignalCodePrintOption::Sender); +#define ADD_LINUX_SIGNAL(signo, name, ...) \ + AddSignal(signo, name, __VA_ARGS__); \ + ADD_SIGCODE(signo, signo, SI_QUEUE, -1, "sent by sigqueue", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_TIMER, -2, "sent by timer expiration", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_MESGQ, -3, \ + "sent by real time mesq state change", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_ASYNCIO, -4, "sent by AIO completion", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_SIGIO, -5, "sent by queued SIGIO", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_TKILL, -6, "sent by tkill system call", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_DETHREAD, -7, \ + "sent by execve() killing subsidiary threads", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_ASYNCNL, -60, \ + "sent by glibc async name lookup completion", \ + SignalCodePrintOption::Sender); using namespace lldb_private; diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index ce0f65cd9f14c..907e009bc7b80 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -585,10 +585,10 @@ Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, if (data.GetAddressByteSize() == 8) offset += 4; - if (si_code < 0) { - sifields.kill.pid = data.GetU32(&offset); - sifields.kill.uid = data.GetU32(&offset); - } else if (unix_signals.GetShouldStop(si_signo)) { + if (si_code < 0) { + sifields.kill.pid = data.GetU32(&offset); + sifields.kill.uid = data.GetU32(&offset); + } else if (unix_signals.GetShouldStop(si_signo)) { // Not every stop signal has a valid address, but that will get resolved in // the unix_signals.GetSignalDescription() call below. // Instead of memcpy we call all these individually as the extractor will @@ -614,14 +614,17 @@ std::string ELFLinuxSigInfo::GetDescription( const lldb_private::UnixSignals &unix_signals) const { if (unix_signals.GetShouldStop(si_signo) && note_type == eNT_SIGINFO) { if (si_code < 0) - return unix_signals.GetSignalDescription(si_signo, si_code, std::nullopt, std::nullopt, std::nullopt, sifields.kill.pid, sifields.kill.uid); + return unix_signals.GetSignalDescription( + si_signo, si_code, std::nullopt, std::nullopt, std::nullopt, + sifields.kill.pid, sifields.kill.uid); else if (sifields.sigfault.bounds._addr_bnd._upper != 0) return unix_signals.GetSignalDescription( - si_signo, si_code, sifields.sigfault.si_addr, sifields.sigfault.bounds._addr_bnd._lower, + si_signo, si_code, sifields.sigfault.si_addr, + sifields.sigfault.bounds._addr_bnd._lower, sifields.sigfault.bounds._addr_bnd._upper); else return unix_signals.GetSignalDescription(si_signo, si_code, - sifields.sigfault.si_addr); + sifields.sigfault.si_addr); } // This looks weird, but there is an existing pattern where we don't pass a diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h index 2c254b4b522e9..40434543b7bb2 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -84,8 +84,8 @@ struct ELFLinuxSigInfo { int32_t si_code; union alignas(8) { struct alignas(8) { - uint32_t pid; /* sender's pid */ - uint32_t uid; /* sender's uid */ + uint32_t pid; /* sender's pid */ + uint32_t uid; /* sender's uid */ } kill; // Copied from siginfo_t so we don't have to include signal.h on non 'Nix // builds. Slight modifications to ensure no 32b vs 64b differences. diff --git a/lldb/source/Target/UnixSignals.cpp b/lldb/source/Target/UnixSignals.cpp index a5dbfd029410a..6113c6648817c 100644 --- a/lldb/source/Target/UnixSignals.cpp +++ b/lldb/source/Target/UnixSignals.cpp @@ -137,13 +137,11 @@ llvm::StringRef UnixSignals::GetSignalAsStringRef(int32_t signo) const { return pos->second.m_name; } -std::string -UnixSignals::GetSignalDescription(int32_t signo, std::optional code, - std::optional addr, - std::optional lower, - std::optional upper, - std::optional pid, - std::optional uid) const { +std::string UnixSignals::GetSignalDescription( + int32_t signo, std::optional code, + std::optional addr, std::optional lower, + std::optional upper, std::optional pid, + std::optional uid) const { std::string str; collection::const_iterator pos = m_signals.find(signo); diff --git a/lldb/unittests/Signals/UnixSignalsTest.cpp b/lldb/unittests/Signals/UnixSignalsTest.cpp index 825cc5ea6a782..582e441556067 100644 --- a/lldb/unittests/Signals/UnixSignalsTest.cpp +++ b/lldb/unittests/Signals/UnixSignalsTest.cpp @@ -27,7 +27,8 @@ class TestSignals : public UnixSignals { AddSignalCode(16, 2, "SIG16 with a fault address", SignalCodePrintOption::Address); AddSignalCode(16, 3, "bounds violation", SignalCodePrintOption::Bounds); - AddSignalCode(16, -6, "sent by tkill system call", SignalCodePrintOption::Sender); + AddSignalCode(16, -6, "sent by tkill system call", + SignalCodePrintOption::Sender); } }; @@ -126,9 +127,12 @@ TEST(UnixSignalsTest, GetAsString) { ASSERT_EQ("SIG16: SIG16 with a fault address", signals.GetSignalDescription(16, 2)); // TKill, but with no sender - ASSERT_EQ("SIG16: sent by tkill system call", signals.GetSignalDescription(16, -6, 0xCAFEF00D)); + ASSERT_EQ("SIG16: sent by tkill system call", + signals.GetSignalDescription(16, -6, 0xCAFEF00D)); // TKill, but with no sender - ASSERT_EQ("SIG16: sent by tkill system call (sender pid=912, uid=99)", signals.GetSignalDescription(16, -6, 0xCAFEF00D, std::nullopt, std::nullopt, 912, 99)); + ASSERT_EQ("SIG16: sent by tkill system call (sender pid=912, uid=99)", + signals.GetSignalDescription(16, -6, 0xCAFEF00D, std::nullopt, + std::nullopt, 912, 99)); const char *expected = "SIG16: bounds violation"; // Must pass all needed info to get full output. >From d8c2a04859e7c10617c15eacc02a303d66b83121 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Fri, 16 May 2025 14:56:06 -0700 Subject: [PATCH 5/7] Reconfigure the parsing to get the bytes and convert to value object, then parse that in thlinux signals --- lldb/include/lldb/Target/UnixSignals.h | 3 + .../Plugins/Process/Utility/LinuxSignals.cpp | 42 ++++++ .../Plugins/Process/Utility/LinuxSignals.h | 2 + .../Process/elf-core/ProcessElfCore.cpp | 19 ++- .../Process/elf-core/ThreadElfCore.cpp | 129 +++++------------- .../Plugins/Process/elf-core/ThreadElfCore.h | 69 ++-------- 6 files changed, 105 insertions(+), 159 deletions(-) diff --git a/lldb/include/lldb/Target/UnixSignals.h b/lldb/include/lldb/Target/UnixSignals.h index a1807d69f329b..9ae4048ed683d 100644 --- a/lldb/include/lldb/Target/UnixSignals.h +++ b/lldb/include/lldb/Target/UnixSignals.h @@ -15,6 +15,7 @@ #include #include "lldb/lldb-private.h" +#include "lldb/ValueObject/ValueObject.h" #include "llvm/Support/JSON.h" namespace lldb_private { @@ -31,6 +32,8 @@ class UnixSignals { llvm::StringRef GetSignalAsStringRef(int32_t signo) const; + virtual std::string GetSignalDescriptionFromSiginfo(lldb::ValueObjectSP siginfo_sp) const { return ""; }; + std::string GetSignalDescription(int32_t signo, std::optional code = std::nullopt, diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index 76c32e376eb4b..392675a265f5d 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -171,3 +171,45 @@ void LinuxSignals::Reset() { ADD_LINUX_SIGNAL(64, "SIGRTMAX", false, false, false, "real time signal 30"); // clang-format on } + +std::string LinuxSignals::GetSignalDescriptionFromSiginfo(lldb::ValueObjectSP siginfo_sp) const { + if (!siginfo_sp) + return ""; + + int code = siginfo_sp->GetChildMemberWithName("si_code")->GetValueAsSigned(0); + int signo = siginfo_sp->GetChildMemberWithName("si_signo")->GetValueAsSigned(-1); + // si_code = 0 is SI_NOINFO, we just want the description with nothing important + if (code == 0) + return GetSignalDescription(signo, code); + + lldb::ValueObjectSP sifields = siginfo_sp->GetChildMemberWithName("_sifields"); + // The negative si_codes are special and mean this signal was sent from user space + // not the kernel. These take precedence because they break some of the invariants + // around kernel sent signals. Such as SIGSEGV won't have an address. + if (code < 0) { + lldb::ValueObjectSP sikill = sifields->GetChildMemberWithName("_kill"); + uint32_t pid = sikill->GetChildMemberWithName("_pid")->GetValueAsUnsigned(-1); + uint32_t uid = sikill->GetChildMemberWithName("_uid")->GetValueAsUnsigned(-1); + return GetSignalDescription(signo, code, std::nullopt, std::nullopt, std::nullopt, pid, uid); + } + + switch (signo) { + case SIGILL: + case SIGFPE: + case SIGBUS: { + lldb::ValueObjectSP sigfault = sifields->GetChildMemberWithName("_sigfault"); + lldb::addr_t addr = sigfault->GetChildMemberWithName("_addr")->GetValueAsUnsigned(-1); + return GetSignalDescription(signo, code, addr); + } + case SIGSEGV: { + lldb::ValueObjectSP sigfault = sifields->GetChildMemberWithName("_sigfault"); + lldb::addr_t addr = sigfault->GetChildMemberWithName("_addr")->GetValueAsUnsigned(-1); + lldb::ValueObjectSP bounds = sigfault->GetChildMemberWithName("_addr_bnd"); + lldb::addr_t lower = bounds->GetChildMemberWithName("_lower")->GetValueAsUnsigned(-1); + lldb::addr_t upper = bounds->GetChildMemberWithName("_upper")->GetValueAsUnsigned(-1); + return GetSignalDescription(signo, code, addr, lower, upper); + } + default: + return GetSignalDescription(signo, code); + } +} diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.h b/lldb/source/Plugins/Process/Utility/LinuxSignals.h index 32c4744a96d04..414cfd531388f 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.h +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.h @@ -18,6 +18,8 @@ class LinuxSignals : public UnixSignals { public: LinuxSignals(); + std::string GetSignalDescriptionFromSiginfo(lldb::ValueObjectSP siginfo_sp) const override; + private: void Reset() override; }; diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 6635b15b669f1..dc3e9616dc9c0 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -232,7 +232,7 @@ Status ProcessElfCore::DoLoadCore() { bool prstatus_signal_found = false; // Check we found a signal in a SIGINFO note. for (const auto &thread_data : m_thread_data) { - if (thread_data.siginfo.si_signo != 0) + if (!thread_data.siginfo_bytes.empty()) siginfo_signal_found = true; if (thread_data.prstatus_sig != 0) prstatus_signal_found = true; @@ -242,10 +242,10 @@ Status ProcessElfCore::DoLoadCore() { // PRSTATUS note. if (prstatus_signal_found) { for (auto &thread_data : m_thread_data) - thread_data.siginfo.si_signo = thread_data.prstatus_sig; + thread_data.signo = thread_data.prstatus_sig; } else if (m_thread_data.size() > 0) { // If all else fails force the first thread to be SIGSTOP - m_thread_data.begin()->siginfo.si_signo = + m_thread_data.begin()->signo = GetUnixSignals()->GetSignalNumberFromName("SIGSTOP"); } } @@ -506,7 +506,7 @@ static void ParseFreeBSDPrStatus(ThreadData &thread_data, else offset += 16; - thread_data.siginfo.si_signo = data.GetU32(&offset); // pr_cursig + thread_data.signo = data.GetU32(&offset); // pr_cursig thread_data.tid = data.GetU32(&offset); // pr_pid if (lp64) offset += 4; @@ -589,7 +589,7 @@ static void ParseOpenBSDProcInfo(ThreadData &thread_data, return; offset += 4; - thread_data.siginfo.si_signo = data.GetU32(&offset); + thread_data.signo = data.GetU32(&offset); } llvm::Expected> @@ -827,7 +827,7 @@ llvm::Error ProcessElfCore::parseNetBSDNotes(llvm::ArrayRef notes) { // Signal targeted at the whole process. if (siglwp == 0) { for (auto &data : m_thread_data) - data.siginfo.si_signo = signo; + data.signo = signo; } // Signal destined for a particular LWP. else { @@ -835,7 +835,7 @@ llvm::Error ProcessElfCore::parseNetBSDNotes(llvm::ArrayRef notes) { for (auto &data : m_thread_data) { if (data.tid == siglwp) { - data.siginfo.si_signo = signo; + data.signo = signo; passed = true; break; } @@ -938,12 +938,9 @@ llvm::Error ProcessElfCore::parseLinuxNotes(llvm::ArrayRef notes) { break; } case ELF::NT_SIGINFO: { - const lldb_private::UnixSignals &unix_signals = *GetUnixSignals(); - ELFLinuxSigInfo siginfo; - Status status = siginfo.Parse(note.data, arch, unix_signals); + Status status = ELFLinuxSigInfo::Parse(note.data, arch, GetTarget().GetPlatform(), thread_data); if (status.Fail()) return status.ToError(); - thread_data.siginfo = siginfo; break; } case ELF::NT_FILE: { diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index 907e009bc7b80..766b9b6d331fb 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -52,7 +52,7 @@ using namespace lldb_private; ThreadElfCore::ThreadElfCore(Process &process, const ThreadData &td) : Thread(process, td.tid), m_thread_name(td.name), m_thread_reg_ctx_sp(), m_gpregset_data(td.gpregset), m_notes(td.notes), - m_siginfo(std::move(td.siginfo)) {} + m_siginfo_bytes(std::move(td.siginfo_bytes)), m_signo(td.signo) {} ThreadElfCore::~ThreadElfCore() { DestroyThread(); } @@ -243,6 +243,14 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { return reg_ctx_sp; } +llvm::Expected> ThreadElfCore::GetSiginfo(size_t max_size) const { + if (m_siginfo_bytes.empty()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "no siginfo note"); + + return llvm::MemoryBuffer::getMemBufferCopy(m_siginfo_bytes, "siginfo note bytes"); +} + bool ThreadElfCore::CalculateStopInfo() { ProcessSP process_sp(GetProcess()); if (!process_sp) @@ -252,15 +260,17 @@ bool ThreadElfCore::CalculateStopInfo() { if (!unix_signals_sp) return false; - const char *sig_description; - std::string description = m_siginfo.GetDescription(*unix_signals_sp); - if (description.empty()) - sig_description = nullptr; - else - sig_description = description.c_str(); - - SetStopInfo(StopInfo::CreateStopReasonWithSignal( - *this, m_siginfo.si_signo, sig_description, m_siginfo.si_code)); + lldb::ValueObjectSP siginfo = GetSiginfoValue(); + if (!siginfo || !siginfo->GetValueIsValid()) { + std::string description = unix_signals_sp->GetSignalDescription(m_signo, 0); + SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, m_signo, description.c_str(), 0)); + } else { + std::string description = unix_signals_sp->GetSignalDescriptionFromSiginfo(siginfo); + uint32_t signo = siginfo->GetChildMemberWithName("si_signo")->GetValueAsUnsigned(-1); + uint32_t code = siginfo->GetChildMemberWithName("si_code")->GetValueAsUnsigned(0); + SetStopInfo(StopInfo::CreateStopReasonWithSignal( + *this, signo, description.c_str(), code)); + } SetStopInfo(m_stop_info_sp); return true; @@ -544,91 +554,22 @@ ELFLinuxPrPsInfo::Populate(const lldb_private::ProcessInstanceInfo &info, return prpsinfo; } -// Parse SIGINFO from NOTE entry -ELFLinuxSigInfo::ELFLinuxSigInfo() { memset(this, 0, sizeof(ELFLinuxSigInfo)); } +Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, const lldb::PlatformSP platform_sp, ThreadData &thread_data) { + if (!platform_sp) + return Status::FromErrorString("No platform for arch."); + CompilerType type = platform_sp->GetSiginfoType(arch.GetTriple()); + if (!type.IsValid()) + return Status::FromErrorString("no siginfo_t for platform."); -size_t ELFLinuxSigInfo::GetSize(const lldb_private::ArchSpec &arch) { - if (arch.IsMIPS()) - return sizeof(ELFLinuxSigInfo); - switch (arch.GetCore()) { - case lldb_private::ArchSpec::eCore_x86_64_x86_64: - return sizeof(ELFLinuxSigInfo); - case lldb_private::ArchSpec::eCore_s390x_generic: - case lldb_private::ArchSpec::eCore_x86_32_i386: - case lldb_private::ArchSpec::eCore_x86_32_i486: - return 12; - default: - return 0; - } -} + auto type_size_or_err = type.GetByteSize(nullptr); + if (!type_size_or_err) + return Status::FromError(type_size_or_err.takeError()); -Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, - const lldb_private::UnixSignals &unix_signals) { - Status error; - uint64_t size = GetSize(arch); - if (size > data.GetByteSize()) { - error = Status::FromErrorStringWithFormat( - "NT_SIGINFO size should be %zu, but the remaining bytes are: %" PRIu64, - GetSize(arch), data.GetByteSize()); - return error; - } - - // Set that we've parsed the siginfo from a SIGINFO note. - note_type = eNT_SIGINFO; - // Parsing from a 32 bit ELF core file, and populating/reusing the structure - // properly, because the struct is for the 64 bit version - offset_t offset = 0; - si_signo = data.GetU32(&offset); - si_errno = data.GetU32(&offset); - si_code = data.GetU32(&offset); - // 64b ELF have a 4 byte pad. - if (data.GetAddressByteSize() == 8) - offset += 4; - - if (si_code < 0) { - sifields.kill.pid = data.GetU32(&offset); - sifields.kill.uid = data.GetU32(&offset); - } else if (unix_signals.GetShouldStop(si_signo)) { - // Not every stop signal has a valid address, but that will get resolved in - // the unix_signals.GetSignalDescription() call below. - // Instead of memcpy we call all these individually as the extractor will - // handle endianness for us. - sifields.sigfault.si_addr = data.GetAddress(&offset); - sifields.sigfault.si_addr_lsb = data.GetU16(&offset); - if (data.GetByteSize() - offset >= sizeof(sifields.sigfault.bounds)) { - sifields.sigfault.bounds._addr_bnd._lower = data.GetAddress(&offset); - sifields.sigfault.bounds._addr_bnd._upper = data.GetAddress(&offset); - sifields.sigfault.bounds._pkey = data.GetU32(&offset); - } else { - // Set these to 0 so we don't use bogus data for the description. - sifields.sigfault.bounds._addr_bnd._lower = 0; - sifields.sigfault.bounds._addr_bnd._upper = 0; - sifields.sigfault.bounds._pkey = 0; - } - } - - return error; -} - -std::string ELFLinuxSigInfo::GetDescription( - const lldb_private::UnixSignals &unix_signals) const { - if (unix_signals.GetShouldStop(si_signo) && note_type == eNT_SIGINFO) { - if (si_code < 0) - return unix_signals.GetSignalDescription( - si_signo, si_code, std::nullopt, std::nullopt, std::nullopt, - sifields.kill.pid, sifields.kill.uid); - else if (sifields.sigfault.bounds._addr_bnd._upper != 0) - return unix_signals.GetSignalDescription( - si_signo, si_code, sifields.sigfault.si_addr, - sifields.sigfault.bounds._addr_bnd._lower, - sifields.sigfault.bounds._addr_bnd._upper); - else - return unix_signals.GetSignalDescription(si_signo, si_code, - sifields.sigfault.si_addr); - } + if (data.GetByteSize() < *type_size_or_err) + return Status::FromErrorString("siginfo note byte size smaller than siginfo_t for platform."); - // This looks weird, but there is an existing pattern where we don't pass a - // description to keep up with that, we return empty here, and then the above - // function will set the description whether or not this is empty. - return std::string(); + lldb::offset_t offset = 0; + const char *bytes = static_cast(data.GetData(&offset, *type_size_or_err)); + thread_data.siginfo_bytes = llvm::StringRef(bytes, *type_size_or_err); + return Status(); } diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h index 40434543b7bb2..413719a1a26f4 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -12,6 +12,8 @@ #include "Plugins/Process/elf-core/RegisterUtilities.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataExtractor.h" +#include "lldb/ValueObject/ValueObject.h" +#include "lldb/Target/Platform.h" #include "llvm/ADT/DenseMap.h" #include #include @@ -77,57 +79,14 @@ struct ELFLinuxPrStatus { static_assert(sizeof(ELFLinuxPrStatus) == 112, "sizeof ELFLinuxPrStatus is not correct!"); -struct ELFLinuxSigInfo { - - int32_t si_signo; // Order matters for the first 3. - int32_t si_errno; - int32_t si_code; - union alignas(8) { - struct alignas(8) { - uint32_t pid; /* sender's pid */ - uint32_t uid; /* sender's uid */ - } kill; - // Copied from siginfo_t so we don't have to include signal.h on non 'Nix - // builds. Slight modifications to ensure no 32b vs 64b differences. - struct alignas(8) { - lldb::addr_t si_addr; /* faulting insn/memory ref. */ - int16_t si_addr_lsb; /* Valid LSB of the reported address. */ - union { - /* used when si_code=SEGV_BNDERR */ - struct { - lldb::addr_t _lower; - lldb::addr_t _upper; - } _addr_bnd; - /* used when si_code=SEGV_PKUERR */ - uint32_t _pkey; - } bounds; - - // We need this for all the generic signals. - } sigfault; - } sifields; - - enum SigInfoNoteType : uint8_t { eUnspecified, eNT_SIGINFO }; - SigInfoNoteType note_type; - - ELFLinuxSigInfo(); - - lldb_private::Status Parse(const lldb_private::DataExtractor &data, - const lldb_private::ArchSpec &arch, - const lldb_private::UnixSignals &unix_signals); - - std::string - GetDescription(const lldb_private::UnixSignals &unix_signals) const; - - // Return the bytesize of the structure - // 64 bit - just sizeof - // 32 bit - hardcoded because we are reusing the struct, but some of the - // members are smaller - - // so the layout is not the same - static size_t GetSize(const lldb_private::ArchSpec &arch); +class ELFLinuxSigInfo { +public: + static lldb_private::Status Parse(const lldb_private::DataExtractor &data, + const lldb_private::ArchSpec &arch, + const lldb::PlatformSP platform_sp, + ThreadData &thread_data); }; -static_assert(sizeof(ELFLinuxSigInfo) == 56, - "sizeof ELFLinuxSigInfo is not correct!"); // PRPSINFO structure's size differs based on architecture. // This is the layout in the x86-64 arch case. @@ -176,8 +135,9 @@ struct ThreadData { std::vector notes; lldb::tid_t tid; std::string name; - ELFLinuxSigInfo siginfo; - int prstatus_sig = 0; + llvm::StringRef siginfo_bytes; + int prstatus_sig; + int signo; }; class ThreadElfCore : public lldb_private::Thread { @@ -208,8 +168,7 @@ class ThreadElfCore : public lldb_private::Thread { m_thread_name.clear(); } - void CreateStopFromSigInfo(const ELFLinuxSigInfo &siginfo, - const lldb_private::UnixSignals &unix_signals); + llvm::Expected> GetSiginfo(size_t max_size) const override; protected: // Member variables. @@ -218,7 +177,9 @@ class ThreadElfCore : public lldb_private::Thread { lldb_private::DataExtractor m_gpregset_data; std::vector m_notes; - ELFLinuxSigInfo m_siginfo; + llvm::StringRef m_siginfo_bytes; + // Only used if no siginfo note. + int m_signo; bool CalculateStopInfo() override; }; >From f2b2f8d37029b8172eac844dc2f812d46556d2c8 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Fri, 16 May 2025 15:52:19 -0700 Subject: [PATCH 6/7] Refactor from testing, discovered that the compiler type generated signal differs from the linux definition --- .../Plugins/Process/Utility/LinuxSignals.cpp | 11 ++++++----- .../Plugins/Process/elf-core/ThreadElfCore.h | 19 ++++++++++--------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index 392675a265f5d..aef1b3f1d0a12 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -188,8 +188,8 @@ std::string LinuxSignals::GetSignalDescriptionFromSiginfo(lldb::ValueObjectSP si // around kernel sent signals. Such as SIGSEGV won't have an address. if (code < 0) { lldb::ValueObjectSP sikill = sifields->GetChildMemberWithName("_kill"); - uint32_t pid = sikill->GetChildMemberWithName("_pid")->GetValueAsUnsigned(-1); - uint32_t uid = sikill->GetChildMemberWithName("_uid")->GetValueAsUnsigned(-1); + uint32_t pid = sikill->GetChildMemberWithName("si_pid")->GetValueAsUnsigned(-1); + uint32_t uid = sikill->GetChildMemberWithName("si_uid")->GetValueAsUnsigned(-1); return GetSignalDescription(signo, code, std::nullopt, std::nullopt, std::nullopt, pid, uid); } @@ -198,13 +198,14 @@ std::string LinuxSignals::GetSignalDescriptionFromSiginfo(lldb::ValueObjectSP si case SIGFPE: case SIGBUS: { lldb::ValueObjectSP sigfault = sifields->GetChildMemberWithName("_sigfault"); - lldb::addr_t addr = sigfault->GetChildMemberWithName("_addr")->GetValueAsUnsigned(-1); + lldb::addr_t addr = sigfault->GetChildMemberWithName("si_addr")->GetValueAsUnsigned(-1); return GetSignalDescription(signo, code, addr); } case SIGSEGV: { lldb::ValueObjectSP sigfault = sifields->GetChildMemberWithName("_sigfault"); - lldb::addr_t addr = sigfault->GetChildMemberWithName("_addr")->GetValueAsUnsigned(-1); - lldb::ValueObjectSP bounds = sigfault->GetChildMemberWithName("_addr_bnd"); + lldb::addr_t addr = sigfault->GetChildMemberWithName("si_addr")->GetValueAsUnsigned(-1); + + lldb::ValueObjectSP bounds = sigfault->GetChildMemberWithName("_bounds")->GetChildMemberWithName("_addr_bnd"); lldb::addr_t lower = bounds->GetChildMemberWithName("_lower")->GetValueAsUnsigned(-1); lldb::addr_t upper = bounds->GetChildMemberWithName("_upper")->GetValueAsUnsigned(-1); return GetSignalDescription(signo, code, addr, lower, upper); diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h index 413719a1a26f4..8b5e593528125 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -79,6 +79,16 @@ struct ELFLinuxPrStatus { static_assert(sizeof(ELFLinuxPrStatus) == 112, "sizeof ELFLinuxPrStatus is not correct!"); +struct ThreadData { + lldb_private::DataExtractor gpregset; + std::vector notes; + lldb::tid_t tid; + std::string name; + llvm::StringRef siginfo_bytes; + int prstatus_sig; + int signo; +}; + class ELFLinuxSigInfo { public: static lldb_private::Status Parse(const lldb_private::DataExtractor &data, @@ -130,15 +140,6 @@ struct ELFLinuxPrPsInfo { static_assert(sizeof(ELFLinuxPrPsInfo) == 136, "sizeof ELFLinuxPrPsInfo is not correct!"); -struct ThreadData { - lldb_private::DataExtractor gpregset; - std::vector notes; - lldb::tid_t tid; - std::string name; - llvm::StringRef siginfo_bytes; - int prstatus_sig; - int signo; -}; class ThreadElfCore : public lldb_private::Thread { public: >From 12e725417075b09739da786417dac3898e7d4a35 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Fri, 16 May 2025 15:52:41 -0700 Subject: [PATCH 7/7] Run GCF --- lldb/include/lldb/Target/UnixSignals.h | 7 +- .../Plugins/Process/Utility/LinuxSignals.cpp | 72 +++++++++++-------- .../Plugins/Process/Utility/LinuxSignals.h | 3 +- .../Process/elf-core/ProcessElfCore.cpp | 3 +- .../Process/elf-core/ThreadElfCore.cpp | 32 ++++++--- .../Plugins/Process/elf-core/ThreadElfCore.h | 7 +- 6 files changed, 77 insertions(+), 47 deletions(-) diff --git a/lldb/include/lldb/Target/UnixSignals.h b/lldb/include/lldb/Target/UnixSignals.h index 9ae4048ed683d..53b718e917d25 100644 --- a/lldb/include/lldb/Target/UnixSignals.h +++ b/lldb/include/lldb/Target/UnixSignals.h @@ -14,8 +14,8 @@ #include #include -#include "lldb/lldb-private.h" #include "lldb/ValueObject/ValueObject.h" +#include "lldb/lldb-private.h" #include "llvm/Support/JSON.h" namespace lldb_private { @@ -32,7 +32,10 @@ class UnixSignals { llvm::StringRef GetSignalAsStringRef(int32_t signo) const; - virtual std::string GetSignalDescriptionFromSiginfo(lldb::ValueObjectSP siginfo_sp) const { return ""; }; + virtual std::string + GetSignalDescriptionFromSiginfo(lldb::ValueObjectSP siginfo_sp) const { + return ""; + }; std::string GetSignalDescription(int32_t signo, diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index aef1b3f1d0a12..06b8423000026 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -172,45 +172,61 @@ void LinuxSignals::Reset() { // clang-format on } -std::string LinuxSignals::GetSignalDescriptionFromSiginfo(lldb::ValueObjectSP siginfo_sp) const { +std::string LinuxSignals::GetSignalDescriptionFromSiginfo( + lldb::ValueObjectSP siginfo_sp) const { if (!siginfo_sp) return ""; int code = siginfo_sp->GetChildMemberWithName("si_code")->GetValueAsSigned(0); - int signo = siginfo_sp->GetChildMemberWithName("si_signo")->GetValueAsSigned(-1); - // si_code = 0 is SI_NOINFO, we just want the description with nothing important + int signo = + siginfo_sp->GetChildMemberWithName("si_signo")->GetValueAsSigned(-1); + // si_code = 0 is SI_NOINFO, we just want the description with nothing + // important if (code == 0) return GetSignalDescription(signo, code); - lldb::ValueObjectSP sifields = siginfo_sp->GetChildMemberWithName("_sifields"); - // The negative si_codes are special and mean this signal was sent from user space - // not the kernel. These take precedence because they break some of the invariants - // around kernel sent signals. Such as SIGSEGV won't have an address. + lldb::ValueObjectSP sifields = + siginfo_sp->GetChildMemberWithName("_sifields"); + // The negative si_codes are special and mean this signal was sent from user + // space not the kernel. These take precedence because they break some of the + // invariants around kernel sent signals. Such as SIGSEGV won't have an + // address. if (code < 0) { lldb::ValueObjectSP sikill = sifields->GetChildMemberWithName("_kill"); - uint32_t pid = sikill->GetChildMemberWithName("si_pid")->GetValueAsUnsigned(-1); - uint32_t uid = sikill->GetChildMemberWithName("si_uid")->GetValueAsUnsigned(-1); - return GetSignalDescription(signo, code, std::nullopt, std::nullopt, std::nullopt, pid, uid); + uint32_t pid = + sikill->GetChildMemberWithName("si_pid")->GetValueAsUnsigned(-1); + uint32_t uid = + sikill->GetChildMemberWithName("si_uid")->GetValueAsUnsigned(-1); + return GetSignalDescription(signo, code, std::nullopt, std::nullopt, + std::nullopt, pid, uid); } switch (signo) { - case SIGILL: - case SIGFPE: - case SIGBUS: { - lldb::ValueObjectSP sigfault = sifields->GetChildMemberWithName("_sigfault"); - lldb::addr_t addr = sigfault->GetChildMemberWithName("si_addr")->GetValueAsUnsigned(-1); - return GetSignalDescription(signo, code, addr); - } - case SIGSEGV: { - lldb::ValueObjectSP sigfault = sifields->GetChildMemberWithName("_sigfault"); - lldb::addr_t addr = sigfault->GetChildMemberWithName("si_addr")->GetValueAsUnsigned(-1); - - lldb::ValueObjectSP bounds = sigfault->GetChildMemberWithName("_bounds")->GetChildMemberWithName("_addr_bnd"); - lldb::addr_t lower = bounds->GetChildMemberWithName("_lower")->GetValueAsUnsigned(-1); - lldb::addr_t upper = bounds->GetChildMemberWithName("_upper")->GetValueAsUnsigned(-1); - return GetSignalDescription(signo, code, addr, lower, upper); - } - default: - return GetSignalDescription(signo, code); + case SIGILL: + case SIGFPE: + case SIGBUS: { + lldb::ValueObjectSP sigfault = + sifields->GetChildMemberWithName("_sigfault"); + lldb::addr_t addr = + sigfault->GetChildMemberWithName("si_addr")->GetValueAsUnsigned(-1); + return GetSignalDescription(signo, code, addr); + } + case SIGSEGV: { + lldb::ValueObjectSP sigfault = + sifields->GetChildMemberWithName("_sigfault"); + lldb::addr_t addr = + sigfault->GetChildMemberWithName("si_addr")->GetValueAsUnsigned(-1); + + lldb::ValueObjectSP bounds = + sigfault->GetChildMemberWithName("_bounds")->GetChildMemberWithName( + "_addr_bnd"); + lldb::addr_t lower = + bounds->GetChildMemberWithName("_lower")->GetValueAsUnsigned(-1); + lldb::addr_t upper = + bounds->GetChildMemberWithName("_upper")->GetValueAsUnsigned(-1); + return GetSignalDescription(signo, code, addr, lower, upper); + } + default: + return GetSignalDescription(signo, code); } } diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.h b/lldb/source/Plugins/Process/Utility/LinuxSignals.h index 414cfd531388f..fab8e4d0526a4 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.h +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.h @@ -18,7 +18,8 @@ class LinuxSignals : public UnixSignals { public: LinuxSignals(); - std::string GetSignalDescriptionFromSiginfo(lldb::ValueObjectSP siginfo_sp) const override; + std::string GetSignalDescriptionFromSiginfo( + lldb::ValueObjectSP siginfo_sp) const override; private: void Reset() override; diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index dc3e9616dc9c0..eda30c9c6f82b 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -938,7 +938,8 @@ llvm::Error ProcessElfCore::parseLinuxNotes(llvm::ArrayRef notes) { break; } case ELF::NT_SIGINFO: { - Status status = ELFLinuxSigInfo::Parse(note.data, arch, GetTarget().GetPlatform(), thread_data); + Status status = ELFLinuxSigInfo::Parse( + note.data, arch, GetTarget().GetPlatform(), thread_data); if (status.Fail()) return status.ToError(); break; diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index 766b9b6d331fb..32948d6b0de9e 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -243,12 +243,14 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { return reg_ctx_sp; } -llvm::Expected> ThreadElfCore::GetSiginfo(size_t max_size) const { +llvm::Expected> +ThreadElfCore::GetSiginfo(size_t max_size) const { if (m_siginfo_bytes.empty()) return llvm::createStringError(llvm::inconvertibleErrorCode(), - "no siginfo note"); + "no siginfo note"); - return llvm::MemoryBuffer::getMemBufferCopy(m_siginfo_bytes, "siginfo note bytes"); + return llvm::MemoryBuffer::getMemBufferCopy(m_siginfo_bytes, + "siginfo note bytes"); } bool ThreadElfCore::CalculateStopInfo() { @@ -263,13 +265,17 @@ bool ThreadElfCore::CalculateStopInfo() { lldb::ValueObjectSP siginfo = GetSiginfoValue(); if (!siginfo || !siginfo->GetValueIsValid()) { std::string description = unix_signals_sp->GetSignalDescription(m_signo, 0); - SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, m_signo, description.c_str(), 0)); + SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, m_signo, + description.c_str(), 0)); } else { - std::string description = unix_signals_sp->GetSignalDescriptionFromSiginfo(siginfo); - uint32_t signo = siginfo->GetChildMemberWithName("si_signo")->GetValueAsUnsigned(-1); - uint32_t code = siginfo->GetChildMemberWithName("si_code")->GetValueAsUnsigned(0); + std::string description = + unix_signals_sp->GetSignalDescriptionFromSiginfo(siginfo); + uint32_t signo = + siginfo->GetChildMemberWithName("si_signo")->GetValueAsUnsigned(-1); + uint32_t code = + siginfo->GetChildMemberWithName("si_code")->GetValueAsUnsigned(0); SetStopInfo(StopInfo::CreateStopReasonWithSignal( - *this, signo, description.c_str(), code)); + *this, signo, description.c_str(), code)); } SetStopInfo(m_stop_info_sp); @@ -554,7 +560,9 @@ ELFLinuxPrPsInfo::Populate(const lldb_private::ProcessInstanceInfo &info, return prpsinfo; } -Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, const lldb::PlatformSP platform_sp, ThreadData &thread_data) { +Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, + const lldb::PlatformSP platform_sp, + ThreadData &thread_data) { if (!platform_sp) return Status::FromErrorString("No platform for arch."); CompilerType type = platform_sp->GetSiginfoType(arch.GetTriple()); @@ -566,10 +574,12 @@ Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, c return Status::FromError(type_size_or_err.takeError()); if (data.GetByteSize() < *type_size_or_err) - return Status::FromErrorString("siginfo note byte size smaller than siginfo_t for platform."); + return Status::FromErrorString( + "siginfo note byte size smaller than siginfo_t for platform."); lldb::offset_t offset = 0; - const char *bytes = static_cast(data.GetData(&offset, *type_size_or_err)); + const char *bytes = + static_cast(data.GetData(&offset, *type_size_or_err)); thread_data.siginfo_bytes = llvm::StringRef(bytes, *type_size_or_err); return Status(); } diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h index 8b5e593528125..2ab9b90f9cc17 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -10,10 +10,10 @@ #define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_THREADELFCORE_H #include "Plugins/Process/elf-core/RegisterUtilities.h" +#include "lldb/Target/Platform.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/ValueObject/ValueObject.h" -#include "lldb/Target/Platform.h" #include "llvm/ADT/DenseMap.h" #include #include @@ -97,7 +97,6 @@ class ELFLinuxSigInfo { ThreadData &thread_data); }; - // PRPSINFO structure's size differs based on architecture. // This is the layout in the x86-64 arch case. // In the i386 case we parse it manually and fill it again @@ -140,7 +139,6 @@ struct ELFLinuxPrPsInfo { static_assert(sizeof(ELFLinuxPrPsInfo) == 136, "sizeof ELFLinuxPrPsInfo is not correct!"); - class ThreadElfCore : public lldb_private::Thread { public: ThreadElfCore(lldb_private::Process &process, const ThreadData &td); @@ -169,7 +167,8 @@ class ThreadElfCore : public lldb_private::Thread { m_thread_name.clear(); } - llvm::Expected> GetSiginfo(size_t max_size) const override; + llvm::Expected> + GetSiginfo(size_t max_size) const override; protected: // Member variables. From lldb-commits at lists.llvm.org Fri May 16 15:56:10 2025 From: lldb-commits at lists.llvm.org (Jacob Lalonde via lldb-commits) Date: Fri, 16 May 2025 15:56:10 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB][ELF Core] Support all the Generic (Negative) SI Codes. (PR #140150) In-Reply-To: Message-ID: <6827c28a.170a0220.99b17.69b7@mx.google.com> Jlalond wrote: @labath I refactored to the best of my ability the signal parsing. Thankfully even getting `thread siginfo` working. However I'm unhappy with how I'm handling the ValueObject in the Linux Signals, I couldn't find an easy way to make this into some generic siginfo linux type, so I'm directly accessing members. While it's good I made a better way of doing this, I feel this is worse in terms of safety due to having to explore the ValueObject hierarchy. Any advice here? Secondly, while testing I found the layout in the valueobject differs to the `siginfo_t` on my machine in some subtle ways. Even if the Core was generated on my machine. https://github.com/llvm/llvm-project/pull/140150 From lldb-commits at lists.llvm.org Fri May 16 16:42:21 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Fri, 16 May 2025 16:42:21 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adjusting startup flow to better handle async operations. (PR #140299) In-Reply-To: Message-ID: <6827cd5d.050a0220.3be236.77ea@mx.google.com> JDevlieghere wrote: Thanks for the summary and especially calling out that the launch and the configuration tracks are happening _in parallel_, I hadn't realized that until now. That explains what the "PAR" stands for in the sequence diagram... Things make a lot more sense now :-) Alright, yeah in that case I see how we can avoid both problems by handling the launch and attach, halting the process, doing the configuration and then sending the response. https://github.com/llvm/llvm-project/pull/140299 From lldb-commits at lists.llvm.org Fri May 16 16:50:25 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Fri, 16 May 2025 16:50:25 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adjusting startup flow to better handle async operations. (PR #140299) In-Reply-To: Message-ID: <6827cf41.a70a0220.33a4eb.6af2@mx.google.com> JDevlieghere wrote: One more thing that comes to mind: how confident are we that all existing clients send the launch/attach in parallel with the configuration requests? If we implement what you suggest, we risk a potential deadlock when a client waits for the launch/attach to complete before sending configuration requests or inversely, if the client waits for the initialized event before sending the launch/attach. https://github.com/llvm/llvm-project/pull/140299 From lldb-commits at lists.llvm.org Fri May 16 18:08:43 2025 From: lldb-commits at lists.llvm.org (Kazu Hirata via lldb-commits) Date: Fri, 16 May 2025 18:08:43 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Avoid creating temporary instances of std::string (NFC) (PR #140325) Message-ID: https://github.com/kazutakahirata created https://github.com/llvm/llvm-project/pull/140325 EmplaceSafeString accepts StringRef for the last parameter, str, and then internally creates a copy of str via StringRef::str or llvm::json::fixUTF8, so caller do not need to create their own temporary instances of std::string. >From efaef78da4a3cdb62db966f79692414c07a172c1 Mon Sep 17 00:00:00 2001 From: Kazu Hirata Date: Fri, 16 May 2025 17:59:35 -0700 Subject: [PATCH] [lldb-dap] Avoid creating temporary instances of std::string (NFC) EmplaceSafeString accepts StringRef for the last parameter, str, and then internally creates a copy of str via StringRef::str or llvm::json::fixUTF8, so caller do not need to create their own temporary instances of std::string. --- lldb/tools/lldb-dap/EventHelper.cpp | 2 +- lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp | 2 +- lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp | 2 +- lldb/tools/lldb-dap/JSONUtils.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lldb/tools/lldb-dap/EventHelper.cpp b/lldb/tools/lldb-dap/EventHelper.cpp index ed2d8700c26b0..c698084836e2f 100644 --- a/lldb/tools/lldb-dap/EventHelper.cpp +++ b/lldb/tools/lldb-dap/EventHelper.cpp @@ -93,7 +93,7 @@ void SendProcessEvent(DAP &dap, LaunchMethod launch_method) { exe_fspec.GetPath(exe_path, sizeof(exe_path)); llvm::json::Object event(CreateEventObject("process")); llvm::json::Object body; - EmplaceSafeString(body, "name", std::string(exe_path)); + EmplaceSafeString(body, "name", exe_path); const auto pid = dap.target.GetProcess().GetProcessID(); body.try_emplace("systemProcessId", (int64_t)pid); body.try_emplace("isLocalProcess", true); diff --git a/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp index 5ce133c33b7e1..e1556846dff19 100644 --- a/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp @@ -205,7 +205,7 @@ void EvaluateRequestHandler::operator()( lldb::SBError error = value.GetError(); const char *error_cstr = error.GetCString(); if (error_cstr && error_cstr[0]) - EmplaceSafeString(response, "message", std::string(error_cstr)); + EmplaceSafeString(response, "message", error_cstr); else EmplaceSafeString(response, "message", "evaluate failed"); } else { diff --git a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp index 924ea63ed1593..c1c2adb32a510 100644 --- a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp @@ -136,7 +136,7 @@ void ExceptionInfoRequestHandler::operator()( if (!ObjectContainsKey(body, "description")) { char description[1024]; if (thread.GetStopDescription(description, sizeof(description))) { - EmplaceSafeString(body, "description", std::string(description)); + EmplaceSafeString(body, "description", description); } } body.try_emplace("breakMode", "always"); diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index a8bd672583a5d..714947a4d3b9c 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -905,7 +905,7 @@ llvm::json::Value CreateThreadStopped(DAP &dap, lldb::SBThread &thread, if (!ObjectContainsKey(body, "description")) { char description[1024]; if (thread.GetStopDescription(description, sizeof(description))) { - EmplaceSafeString(body, "description", std::string(description)); + EmplaceSafeString(body, "description", description); } } // "threadCausedFocus" is used in tests to validate breaking behavior. From lldb-commits at lists.llvm.org Fri May 16 18:09:15 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 18:09:15 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Avoid creating temporary instances of std::string (NFC) (PR #140325) In-Reply-To: Message-ID: <6827e1bb.630a0220.3cd12.adc8@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Kazu Hirata (kazutakahirata)
Changes EmplaceSafeString accepts StringRef for the last parameter, str, and then internally creates a copy of str via StringRef::str or llvm::json::fixUTF8, so caller do not need to create their own temporary instances of std::string. --- Full diff: https://github.com/llvm/llvm-project/pull/140325.diff 4 Files Affected: - (modified) lldb/tools/lldb-dap/EventHelper.cpp (+1-1) - (modified) lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp (+1-1) - (modified) lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp (+1-1) - (modified) lldb/tools/lldb-dap/JSONUtils.cpp (+1-1) ``````````diff diff --git a/lldb/tools/lldb-dap/EventHelper.cpp b/lldb/tools/lldb-dap/EventHelper.cpp index ed2d8700c26b0..c698084836e2f 100644 --- a/lldb/tools/lldb-dap/EventHelper.cpp +++ b/lldb/tools/lldb-dap/EventHelper.cpp @@ -93,7 +93,7 @@ void SendProcessEvent(DAP &dap, LaunchMethod launch_method) { exe_fspec.GetPath(exe_path, sizeof(exe_path)); llvm::json::Object event(CreateEventObject("process")); llvm::json::Object body; - EmplaceSafeString(body, "name", std::string(exe_path)); + EmplaceSafeString(body, "name", exe_path); const auto pid = dap.target.GetProcess().GetProcessID(); body.try_emplace("systemProcessId", (int64_t)pid); body.try_emplace("isLocalProcess", true); diff --git a/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp index 5ce133c33b7e1..e1556846dff19 100644 --- a/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp @@ -205,7 +205,7 @@ void EvaluateRequestHandler::operator()( lldb::SBError error = value.GetError(); const char *error_cstr = error.GetCString(); if (error_cstr && error_cstr[0]) - EmplaceSafeString(response, "message", std::string(error_cstr)); + EmplaceSafeString(response, "message", error_cstr); else EmplaceSafeString(response, "message", "evaluate failed"); } else { diff --git a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp index 924ea63ed1593..c1c2adb32a510 100644 --- a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp @@ -136,7 +136,7 @@ void ExceptionInfoRequestHandler::operator()( if (!ObjectContainsKey(body, "description")) { char description[1024]; if (thread.GetStopDescription(description, sizeof(description))) { - EmplaceSafeString(body, "description", std::string(description)); + EmplaceSafeString(body, "description", description); } } body.try_emplace("breakMode", "always"); diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index a8bd672583a5d..714947a4d3b9c 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -905,7 +905,7 @@ llvm::json::Value CreateThreadStopped(DAP &dap, lldb::SBThread &thread, if (!ObjectContainsKey(body, "description")) { char description[1024]; if (thread.GetStopDescription(description, sizeof(description))) { - EmplaceSafeString(body, "description", std::string(description)); + EmplaceSafeString(body, "description", description); } } // "threadCausedFocus" is used in tests to validate breaking behavior. ``````````
https://github.com/llvm/llvm-project/pull/140325 From lldb-commits at lists.llvm.org Fri May 16 18:09:49 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Fri, 16 May 2025 18:09:49 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Avoid creating temporary instances of std::string (NFC) (PR #140325) In-Reply-To: Message-ID: <6827e1dd.170a0220.2b9185.6522@mx.google.com> https://github.com/JDevlieghere approved this pull request. https://github.com/llvm/llvm-project/pull/140325 From lldb-commits at lists.llvm.org Fri May 16 18:16:00 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Fri, 16 May 2025 18:16:00 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adjusting startup flow to better handle async operations. (PR #140299) In-Reply-To: Message-ID: <6827e350.170a0220.15d084.6778@mx.google.com> JDevlieghere wrote: I also found this diagram which covers both cases I had in mind: https://github.com/microsoft/vscode/issues/4902#issuecomment-368583522 https://github.com/llvm/llvm-project/pull/140299 From lldb-commits at lists.llvm.org Fri May 16 18:47:19 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Fri, 16 May 2025 18:47:19 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adjusting startup flow to better handle async operations. (PR #140299) In-Reply-To: Message-ID: <6827eaa7.170a0220.375382.69d6@mx.google.com> JDevlieghere wrote: I took a look at the code and I think the approach looks good. I wonder if there's an opportunity to make this slightly more generic to avoid (1) having to change the interface (i.e. keep returning an `llvm::Error`) and (2) defer the error response so there's no divergence between when we send a success and failure response. That would require doing the checking of the async condition (for async requests) as well as executing the callback (if we don't yet have an error) at the layer above it. I don't know how much that complicates things or if that's worth it (do we expect to use this anywhere else?) in which case feel free to ignore this. https://github.com/llvm/llvm-project/pull/140299 From lldb-commits at lists.llvm.org Fri May 16 18:47:52 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 18:47:52 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Take two at refactoring the startup sequence. (PR #140331) Message-ID: https://github.com/ashgti created https://github.com/llvm/llvm-project/pull/140331 This is more straight forward refactor of the startup sequence that reverts parts of ba29e60f9a2222bd5e883579bb78db13fc5a7588. Unlike my previous attempt, I ended up removing the pending request queue and not including an `AsyncReqeustHandler` because I don't think we actually need that at the moment. The key is that during the startup flow there are 2 parallel operations happening in the DAP that have different triggers. * The `initialize` request is sent and once the response is received the `launch` or `attach` is sent. * When the `initialized` event is recieved the `setBreakpionts` and other config requests are made followed by the `configurationDone` event. I moved the `initialized` event back to happen in the `PostRun` of the `launch` or `attach` request handlers. This ensures that we have a valid target by the time the configuration calls are made. I added also added a few extra validations that to the `configurationeDone` handler to ensure we're in an expected state. I've also fixed up the tests to match the new flow. With the other additional test fixes in 087a5d2ec7897cd99d3787820711fec76a8e1792 I think we've narrowed down the main source of test instability that motivated the startup sequence change. >From 71c7830f569c0b13045ad4b0301973e606a2f06e Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 16 May 2025 18:35:28 -0700 Subject: [PATCH] [lldb-dap] Take two at refactoring the startup sequence. This is more straight forward refactor of the startup sequence that reverts parts of ba29e60f9a2222bd5e883579bb78db13fc5a7588. Unlike my previous attempt, I ended up removing the pending request queue and not including an `AsyncReqeustHandler` because I don't think we actually need that at the moment. The key is that during the startup flow there are 2 parallel operations happening in the DAP that have different triggers. * The `initialize` request is sent and once the response is received the `launch` or `attach` is sent. * When the `initialized` event is recieved the `setBreakpionts` and other config requests are made followed by the `configurationDone` event. I moved the `initialized` event back to happen in the `PostRun` of the `launch` or `attach` request handlers. This ensures that we have a valid target by the time the configuration calls are made. I added also added a few extra validations that to the `configurationeDone` handler to ensure we're in an expected state. I've also fixed up the tests to match the new flow. With the other additional test fixes in 087a5d2ec7897cd99d3787820711fec76a8e1792 I think we've narrowed down the main source of test instability that motivated the startup sequence change. --- .../test/tools/lldb-dap/dap_server.py | 24 +++--- .../test/tools/lldb-dap/lldbdap_testcase.py | 70 +--------------- .../TestDAP_breakpointEvents.py | 2 +- .../tools/lldb-dap/cancel/TestDAP_cancel.py | 4 +- .../completions/TestDAP_completions.py | 17 ++-- .../tools/lldb-dap/console/TestDAP_console.py | 13 +-- .../console/TestDAP_redirection_to_console.py | 4 +- .../lldb-dap/coreFile/TestDAP_coreFile.py | 1 + .../lldb-dap/evaluate/TestDAP_evaluate.py | 1 - .../tools/lldb-dap/launch/TestDAP_launch.py | 3 +- .../module-event/TestDAP_module_event.py | 2 +- .../tools/lldb-dap/module/TestDAP_module.py | 4 +- .../repl-mode/TestDAP_repl_mode_detection.py | 2 +- .../tools/lldb-dap/restart/TestDAP_restart.py | 5 +- .../lldb-dap/send-event/TestDAP_sendEvent.py | 3 +- .../lldb-dap/stackTrace/TestDAP_stackTrace.py | 2 +- .../TestDAP_stackTraceDisassemblyDisplay.py | 2 +- .../startDebugging/TestDAP_startDebugging.py | 2 +- .../lldb-dap/stop-hooks/TestDAP_stop_hooks.py | 2 +- .../tools/lldb-dap/threads/TestDAP_threads.py | 5 +- .../children/TestDAP_variables_children.py | 5 +- lldb/tools/lldb-dap/DAP.cpp | 29 +------ lldb/tools/lldb-dap/DAP.h | 1 - .../lldb-dap/Handler/AttachRequestHandler.cpp | 19 +---- .../ConfigurationDoneRequestHandler.cpp | 82 ++++++++++--------- .../Handler/InitializeRequestHandler.cpp | 4 - .../lldb-dap/Handler/LaunchRequestHandler.cpp | 20 +---- lldb/tools/lldb-dap/Handler/RequestHandler.h | 62 ++++++++------ lldb/tools/lldb-dap/Protocol/ProtocolBase.h | 3 + .../lldb-dap/Protocol/ProtocolRequests.h | 7 ++ 30 files changed, 150 insertions(+), 250 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index d3589e78b6bc7..70fd0b0c419db 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -133,6 +133,7 @@ def __init__( self.output_condition = threading.Condition() self.output: dict[str, list[str]] = {} self.configuration_done_sent = False + self.initialized = False self.frame_scopes = {} self.init_commands = init_commands self.disassembled_instructions = {} @@ -235,6 +236,8 @@ def _handle_recv_packet(self, packet: Optional[ProtocolMessage]) -> bool: self.output_condition.release() # no need to add 'output' event packets to our packets list return keepGoing + elif event == "initialized": + self.initialized = True elif event == "process": # When a new process is attached or launched, remember the # details that are available in the body of the event @@ -602,7 +605,7 @@ def request_attach( exitCommands: Optional[list[str]] = None, terminateCommands: Optional[list[str]] = None, coreFile: Optional[str] = None, - stopOnAttach=True, + stopOnEntry=False, sourceMap: Optional[Union[list[tuple[str, str]], dict[str, str]]] = None, gdbRemotePort: Optional[int] = None, gdbRemoteHostname: Optional[str] = None, @@ -629,8 +632,8 @@ def request_attach( args_dict["attachCommands"] = attachCommands if coreFile: args_dict["coreFile"] = coreFile - if stopOnAttach: - args_dict["stopOnEntry"] = stopOnAttach + if stopOnEntry: + args_dict["stopOnEntry"] = stopOnEntry if postRunCommands: args_dict["postRunCommands"] = postRunCommands if sourceMap: @@ -640,11 +643,7 @@ def request_attach( if gdbRemoteHostname is not None: args_dict["gdb-remote-hostname"] = gdbRemoteHostname command_dict = {"command": "attach", "type": "request", "arguments": args_dict} - response = self.send_recv(command_dict) - - if response["success"]: - self.wait_for_event("process") - return response + return self.send_recv(command_dict) def request_breakpointLocations( self, file_path, line, end_line=None, column=None, end_column=None @@ -677,6 +676,7 @@ def request_configurationDone(self): response = self.send_recv(command_dict) if response: self.configuration_done_sent = True + self.request_threads() return response def _process_stopped(self): @@ -824,7 +824,7 @@ def request_launch( args: Optional[list[str]] = None, cwd: Optional[str] = None, env: Optional[dict[str, str]] = None, - stopOnEntry=True, + stopOnEntry=False, disableASLR=True, disableSTDIO=False, shellExpandArguments=False, @@ -894,11 +894,7 @@ def request_launch( if commandEscapePrefix is not None: args_dict["commandEscapePrefix"] = commandEscapePrefix command_dict = {"command": "launch", "type": "request", "arguments": args_dict} - response = self.send_recv(command_dict) - - if response["success"]: - self.wait_for_event("process") - return response + return self.send_recv(command_dict) def request_next(self, threadId, granularity="statement"): if self.exit_status is not None: diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index d7cf8e2864324..afdc746ed0d0d 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -56,7 +56,7 @@ def set_source_breakpoints(self, source_path, lines, data=None): It contains optional location/hitCondition/logMessage parameters. """ response = self.dap_server.request_setBreakpoints(source_path, lines, data) - if response is None: + if response is None or not response["success"]: return [] breakpoints = response["body"]["breakpoints"] breakpoint_ids = [] @@ -354,13 +354,9 @@ def disassemble(self, threadId=None, frameIndex=None): def attach( self, *, - stopOnAttach=True, disconnectAutomatically=True, sourceInitFile=False, expectFailure=False, - sourceBreakpoints=None, - functionBreakpoints=None, - timeout=DEFAULT_TIMEOUT, **kwargs, ): """Build the default Makefile target, create the DAP debug adapter, @@ -378,37 +374,13 @@ def cleanup(): self.addTearDownHook(cleanup) # Initialize and launch the program self.dap_server.request_initialize(sourceInitFile) - self.dap_server.wait_for_event("initialized", timeout) - - # Set source breakpoints as part of the launch sequence. - if sourceBreakpoints: - for source_path, lines in sourceBreakpoints: - response = self.dap_server.request_setBreakpoints(source_path, lines) - self.assertTrue( - response["success"], - "setBreakpoints failed (%s)" % (response), - ) - - # Set function breakpoints as part of the launch sequence. - if functionBreakpoints: - response = self.dap_server.request_setFunctionBreakpoints( - functionBreakpoints - ) - self.assertTrue( - response["success"], - "setFunctionBreakpoint failed (%s)" % (response), - ) - - self.dap_server.request_configurationDone() - response = self.dap_server.request_attach(stopOnAttach=stopOnAttach, **kwargs) + response = self.dap_server.request_attach(**kwargs) if expectFailure: return response if not (response and response["success"]): self.assertTrue( response["success"], "attach failed (%s)" % (response["message"]) ) - if stopOnAttach: - self.dap_server.wait_for_stopped(timeout) def launch( self, @@ -416,11 +388,7 @@ def launch( *, sourceInitFile=False, disconnectAutomatically=True, - sourceBreakpoints=None, - functionBreakpoints=None, expectFailure=False, - stopOnEntry=True, - timeout=DEFAULT_TIMEOUT, **kwargs, ): """Sending launch request to dap""" @@ -437,35 +405,7 @@ def cleanup(): # Initialize and launch the program self.dap_server.request_initialize(sourceInitFile) - self.dap_server.wait_for_event("initialized", timeout) - - # Set source breakpoints as part of the launch sequence. - if sourceBreakpoints: - for source_path, lines in sourceBreakpoints: - response = self.dap_server.request_setBreakpoints(source_path, lines) - self.assertTrue( - response["success"], - "setBreakpoints failed (%s)" % (response), - ) - - # Set function breakpoints as part of the launch sequence. - if functionBreakpoints: - response = self.dap_server.request_setFunctionBreakpoints( - functionBreakpoints - ) - self.assertTrue( - response["success"], - "setFunctionBreakpoint failed (%s)" % (response), - ) - - self.dap_server.request_configurationDone() - - response = self.dap_server.request_launch( - program, - stopOnEntry=stopOnEntry, - **kwargs, - ) - + response = self.dap_server.request_launch(program, **kwargs) if expectFailure: return response if not (response and response["success"]): @@ -473,10 +413,6 @@ def cleanup(): response["success"], "launch failed (%s)" % (response["body"]["error"]["format"]), ) - if stopOnEntry: - self.dap_server.wait_for_stopped(timeout) - - return response def build_and_launch( self, diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py index 25f031db5cac5..d46fc31d797da 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py @@ -52,7 +52,7 @@ def test_breakpoint_events(self): # breakpoint events for these breakpoints but not for ones that are not # set via the command interpreter. bp_command = "breakpoint set --file foo.cpp --line %u" % (foo_bp2_line) - self.build_and_launch(program, stopOnEntry=True, preRunCommands=[bp_command]) + self.build_and_launch(program, preRunCommands=[bp_command]) main_bp_id = 0 foo_bp_id = 0 # Set breakpoints and verify that they got set correctly diff --git a/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py b/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py index 948c146d4da68..824ed8fe3bb97 100644 --- a/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py +++ b/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py @@ -44,7 +44,7 @@ def test_pending_request(self): Tests cancelling a pending request. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) # Use a relatively short timeout since this is only to ensure the # following request is queued. @@ -76,7 +76,7 @@ def test_inflight_request(self): Tests cancelling an inflight request. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) blocking_seq = self.async_blocking_request(duration=self.DEFAULT_TIMEOUT / 2) # Wait for the sleep to start to cancel the inflight request. diff --git a/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py b/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py index 75876c248f86c..04897acfcf85d 100644 --- a/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py +++ b/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py @@ -46,17 +46,12 @@ def verify_completions(self, actual_list, expected_list, not_expected_list=[]): def setup_debuggee(self): program = self.getBuildArtifact("a.out") source = "main.cpp" - self.build_and_launch( - program, - stopOnEntry=True, - sourceBreakpoints=[ - ( - source, - [ - line_number(source, "// breakpoint 1"), - line_number(source, "// breakpoint 2"), - ], - ), + self.build_and_launch(program) + self.set_source_breakpoints( + source, + [ + line_number(source, "// breakpoint 1"), + line_number(source, "// breakpoint 2"), ], ) diff --git a/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py b/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py index 1f810afdbb667..7b4d1adbb2071 100644 --- a/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py +++ b/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py @@ -53,7 +53,7 @@ def test_scopes_variables_setVariable_evaluate(self): character. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") lines = [breakpoint1_line] @@ -66,6 +66,7 @@ def test_scopes_variables_setVariable_evaluate(self): # Cause a "scopes" to be sent for frame zero which should update the # selected thread and frame to frame 0. self.dap_server.get_local_variables(frameIndex=0) + # Verify frame #0 is selected in the command interpreter by running # the "frame select" command with no frame index which will print the # currently selected frame. @@ -74,15 +75,15 @@ def test_scopes_variables_setVariable_evaluate(self): # Cause a "scopes" to be sent for frame one which should update the # selected thread and frame to frame 1. self.dap_server.get_local_variables(frameIndex=1) + # Verify frame #1 is selected in the command interpreter by running # the "frame select" command with no frame index which will print the # currently selected frame. - self.check_lldb_command("frame select", "frame #1", "frame 1 is selected") def test_custom_escape_prefix(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="::") + self.build_and_launch(program, commandEscapePrefix="::") source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line]) @@ -97,7 +98,7 @@ def test_custom_escape_prefix(self): def test_empty_escape_prefix(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="") + self.build_and_launch(program, commandEscapePrefix="") source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line]) @@ -114,7 +115,7 @@ def test_empty_escape_prefix(self): def test_exit_status_message_sigterm(self): source = "main.cpp" program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="") + self.build_and_launch(program, commandEscapePrefix="") breakpoint1_line = line_number(source, "// breakpoint 1") breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line]) self.continue_to_breakpoints(breakpoint_ids) @@ -168,7 +169,7 @@ def test_exit_status_message_ok(self): def test_diagnositcs(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) core = self.getBuildArtifact("minidump.core") self.yaml2obj("minidump.yaml", core) diff --git a/lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py b/lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py index 23500bd6fe586..e367c327d4295 100644 --- a/lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py +++ b/lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py @@ -16,9 +16,7 @@ def test(self): """ program = self.getBuildArtifact("a.out") self.build_and_launch( - program, - stopOnEntry=True, - lldbDAPEnv={"LLDB_DAP_TEST_STDOUT_STDERR_REDIRECTION": ""}, + program, lldbDAPEnv={"LLDB_DAP_TEST_STDOUT_STDERR_REDIRECTION": ""} ) source = "main.cpp" diff --git a/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py b/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py index e678c5ee77fdc..db43dbaf515cf 100644 --- a/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py +++ b/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py @@ -19,6 +19,7 @@ def test_core_file(self): self.create_debug_adapter() self.attach(program=exe_file, coreFile=core_file) + self.dap_server.request_configurationDone() expected_frames = [ { diff --git a/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py b/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py index 372a9bb75e007..2166e88151986 100644 --- a/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py +++ b/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py @@ -43,7 +43,6 @@ def run_test_evaluate_expressions( self.build_and_launch( program, enableAutoVariableSummaries=enableAutoVariableSummaries, - stopOnEntry=True, ) source = "main.cpp" self.set_source_breakpoints( diff --git a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py index 0063954791fd5..d769ac51096b8 100644 --- a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py +++ b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py @@ -87,7 +87,8 @@ def test_stopOnEntry(self): """ program = self.getBuildArtifact("a.out") self.build_and_launch(program, stopOnEntry=True) - + self.dap_server.request_configurationDone() + self.dap_server.wait_for_stopped() self.assertTrue( len(self.dap_server.thread_stop_reasons) > 0, "expected stopped event during launch", diff --git a/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py b/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py index 19de35b60a3ef..1ef2f2a8235a4 100644 --- a/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py +++ b/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py @@ -10,7 +10,7 @@ class TestDAP_module_event(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_module_event(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") diff --git a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py index b333efd7bfb1f..3fc0f752ee39e 100644 --- a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py +++ b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py @@ -14,7 +14,7 @@ class TestDAP_module(lldbdap_testcase.DAPTestCaseBase): def run_test(self, symbol_basename, expect_debug_info_size): program_basename = "a.out.stripped" program = self.getBuildArtifact(program_basename) - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) functions = ["foo"] breakpoint_ids = self.set_function_breakpoints(functions) self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint") @@ -108,7 +108,7 @@ def test_modules_dsym(self): @skipIfWindows def test_compile_units(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.cpp" main_source_path = self.getSourcePath(source) breakpoint1_line = line_number(source, "// breakpoint 1") diff --git a/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py b/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py index 81edcdf4bd0f9..c6f59949d668e 100644 --- a/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py +++ b/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py @@ -20,7 +20,7 @@ def assertEvaluate(self, expression, regex): def test_completions(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") diff --git a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py index 8681b31e8eb1b..83faf276852f8 100644 --- a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py +++ b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py @@ -35,7 +35,7 @@ def test_basic_functionality(self): # Restart then check we stop back at A and program state has been reset. resp = self.dap_server.request_restart() self.assertTrue(resp["success"]) - self.continue_to_breakpoints([bp_A]) + self.verify_breakpoint_hit([bp_A]) self.assertEqual( int(self.dap_server.get_local_variable_value("i")), 0, @@ -50,6 +50,9 @@ def test_stopOnEntry(self): program = self.getBuildArtifact("a.out") self.build_and_launch(program, stopOnEntry=True) [bp_main] = self.set_function_breakpoints(["main"]) + + self.dap_server.request_configurationDone() + self.dap_server.wait_for_stopped() # Once the "configuration done" event is sent, we should get a stopped # event immediately because of stopOnEntry. self.assertTrue( diff --git a/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py b/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py index 3e015186d4b81..a01845669666f 100644 --- a/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py +++ b/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py @@ -24,7 +24,6 @@ def test_send_event(self): } self.build_and_launch( program, - sourceBreakpoints=[(source, [breakpoint_line])], stopCommands=[ "lldb-dap send-event my-custom-event-no-body", "lldb-dap send-event my-custom-event '{}'".format( @@ -32,6 +31,8 @@ def test_send_event(self): ), ], ) + self.set_source_breakpoints(source, [breakpoint_line]) + self.continue_to_next_stop() custom_event = self.dap_server.wait_for_event( filter=["my-custom-event-no-body"] diff --git a/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py b/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py index 9c6f1d42feda2..abd469274ffd4 100644 --- a/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py +++ b/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py @@ -61,7 +61,7 @@ def test_stackTrace(self): Tests the 'stackTrace' packet and all its variants. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.c" self.source_path = os.path.join(os.getcwd(), source) self.recurse_end = line_number(source, "recurse end") diff --git a/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py b/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py index 963d711978534..08c225b3cada4 100644 --- a/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py +++ b/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py @@ -37,7 +37,7 @@ def build_and_run_until_breakpoint(self): breakpoint_line = line_number(other_source_file, "// Break here") program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="") + self.build_and_launch(program, commandEscapePrefix="") breakpoint_ids = self.set_source_breakpoints( other_source_file, [breakpoint_line] diff --git a/lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py b/lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py index e37cd36d7f283..b487257b6414d 100644 --- a/lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py +++ b/lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py @@ -15,7 +15,7 @@ def test_startDebugging(self): """ program = self.getBuildArtifact("a.out") source = "main.c" - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) breakpoint_line = line_number(source, "// breakpoint") diff --git a/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py b/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py index 33e038408fa34..d630e1d14c3a0 100644 --- a/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py +++ b/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py @@ -15,7 +15,7 @@ def test_stop_hooks_before_run(self): """ program = self.getBuildArtifact("a.out") preRunCommands = ["target stop-hook add -o help"] - self.build_and_launch(program, stopOnEntry=True, preRunCommands=preRunCommands) + self.build_and_launch(program, preRunCommands=preRunCommands) breakpoint_ids = self.set_function_breakpoints(["main"]) # This request hangs if the race happens, because, in that case, the # command interpreter is in synchronous mode while lldb-dap expects diff --git a/lldb/test/API/tools/lldb-dap/threads/TestDAP_threads.py b/lldb/test/API/tools/lldb-dap/threads/TestDAP_threads.py index 6edb4b8e2a816..a4658da58ac94 100644 --- a/lldb/test/API/tools/lldb-dap/threads/TestDAP_threads.py +++ b/lldb/test/API/tools/lldb-dap/threads/TestDAP_threads.py @@ -50,7 +50,9 @@ def test_thread_format(self): """ program = self.getBuildArtifact("a.out") self.build_and_launch( - program, customThreadFormat="This is thread index #${thread.index}" + program, + customThreadFormat="This is thread index #${thread.index}", + stopCommands=["thread list"], ) source = "main.c" breakpoint_line = line_number(source, "// break here") @@ -63,5 +65,6 @@ def test_thread_format(self): self.continue_to_breakpoints(breakpoint_ids) # We are stopped at the second thread threads = self.dap_server.get_threads() + print("got thread", threads) self.assertEqual(threads[0]["name"], "This is thread index #1") self.assertEqual(threads[1]["name"], "This is thread index #2") diff --git a/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py b/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py index eb09649f387d7..75e75c4ad7c69 100644 --- a/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py +++ b/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py @@ -13,14 +13,11 @@ def test_get_num_children(self): program = self.getBuildArtifact("a.out") self.build_and_launch( program, - stopOnEntry=True, preRunCommands=[ "command script import '%s'" % self.getSourcePath("formatter.py") ], ) source = "main.cpp" - breakpoint1_line = line_number(source, "// break here") - breakpoint_ids = self.set_source_breakpoints( source, [line_number(source, "// break here")] ) @@ -47,7 +44,7 @@ def test_return_variable_with_children(self): Test the stepping out of a function with return value show the children correctly """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) function_name = "test_return_variable_with_children" breakpoint_ids = self.set_function_breakpoints([function_name]) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 56a0c38b00037..0d5eba6c40961 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -916,20 +916,10 @@ llvm::Error DAP::Loop() { return errWrapper; } - // The launch sequence is special and we need to carefully handle - // packets in the right order. Until we've handled configurationDone, - bool add_to_pending_queue = false; - if (const protocol::Request *req = - std::get_if(&*next)) { - llvm::StringRef command = req->command; - if (command == "disconnect") - disconnecting = true; - if (!configuration_done) - add_to_pending_queue = - command != "initialize" && command != "configurationDone" && - command != "disconnect" && !command.ends_with("Breakpoints"); - } + std::get_if(&*next); + req && req->arguments == "disconnect") + disconnecting = true; const std::optional cancel_args = getArgumentsIfRequest(*next, "cancel"); @@ -956,8 +946,7 @@ llvm::Error DAP::Loop() { { std::lock_guard guard(m_queue_mutex); - auto &queue = add_to_pending_queue ? m_pending_queue : m_queue; - queue.push_back(std::move(*next)); + m_queue.push_back(std::move(*next)); } m_queue_cv.notify_one(); } @@ -1255,16 +1244,6 @@ void DAP::SetConfiguration(const protocol::Configuration &config, SetThreadFormat(*configuration.customThreadFormat); } -void DAP::SetConfigurationDone() { - { - std::lock_guard guard(m_queue_mutex); - std::copy(m_pending_queue.begin(), m_pending_queue.end(), - std::front_inserter(m_queue)); - configuration_done = true; - } - m_queue_cv.notify_all(); -} - void DAP::SetFrameFormat(llvm::StringRef format) { lldb::SBError error; frame_format = lldb::SBFormat(format.str().c_str(), error); diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c1a1130b1e59f..8f24c6cf82924 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -444,7 +444,6 @@ struct DAP { /// Queue for all incoming messages. std::deque m_queue; - std::deque m_pending_queue; std::mutex m_queue_mutex; std::condition_variable m_queue_cv; diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp index 0293ffbd0c922..371349a26866e 100644 --- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp @@ -140,24 +140,7 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { } void AttachRequestHandler::PostRun() const { - if (!dap.target.GetProcess().IsValid()) - return; - - // Clients can request a baseline of currently existing threads after - // we acknowledge the configurationDone request. - // Client requests the baseline of currently existing threads after - // a successful or attach by sending a 'threads' request - // right after receiving the configurationDone response. - // Obtain the list of threads before we resume the process - dap.initial_thread_list = - GetThreads(dap.target.GetProcess(), dap.thread_format); - - SendProcessEvent(dap, Attach); - - if (dap.stop_at_entry) - SendThreadStoppedEvent(dap); - else - dap.target.GetProcess().Continue(); + dap.SendJSON(CreateEventObject("initialized")); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp index 802c28d7b8904..1281857ef4b60 100644 --- a/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp @@ -9,49 +9,53 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" +#include "lldb/API/SBDebugger.h" + +using namespace llvm; +using namespace lldb_dap::protocol; namespace lldb_dap { -// "ConfigurationDoneRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "ConfigurationDone request; value of command field -// is 'configurationDone'.\nThe client of the debug protocol must -// send this request at the end of the sequence of configuration -// requests (which was started by the InitializedEvent).", -// "properties": { -// "command": { -// "type": "string", -// "enum": [ "configurationDone" ] -// }, -// "arguments": { -// "$ref": "#/definitions/ConfigurationDoneArguments" -// } -// }, -// "required": [ "command" ] -// }] -// }, -// "ConfigurationDoneArguments": { -// "type": "object", -// "description": "Arguments for 'configurationDone' request.\nThe -// configurationDone request has no standardized attributes." -// }, -// "ConfigurationDoneResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to 'configurationDone' request. This is -// just an acknowledgement, so no body field is required." -// }] -// }, - -void ConfigurationDoneRequestHandler::operator()( - const llvm::json::Object &request) const { - dap.SetConfigurationDone(); - - llvm::json::Object response; - FillResponse(request, response); - dap.SendJSON(llvm::json::Value(std::move(response))); +/// This request indicates that the client has finished initialization of the +/// debug adapter. +/// +/// So it is the last request in the sequence of configuration requests (which +/// was started by the `initialized` event). +/// +/// Clients should only call this request if the corresponding capability +/// `supportsConfigurationDoneRequest` is true. +llvm::Error +ConfigurationDoneRequestHandler::Run(const ConfigurationDoneArguments &) const { + dap.configuration_done = true; + + // Ensure any command scripts did not leave us in an unexpected state. + lldb::SBProcess process = dap.target.GetProcess(); + if (!process.IsValid() || + !lldb::SBDebugger::StateIsStoppedState(process.GetState())) + return make_error( + "Expected process to be stopped.\r\n\r\nProcess is in an unexpected " + "state and may have missed an initial configuration. Please check that " + "any debugger command scripts are not resuming the process during the " + "launch sequence."); + + // Clients can request a baseline of currently existing threads after + // we acknowledge the configurationDone request. + // Client requests the baseline of currently existing threads after + // a successful or attach by sending a 'threads' request + // right after receiving the configurationDone response. + // Obtain the list of threads before we resume the process + dap.initial_thread_list = GetThreads(process, dap.thread_format); + + SendProcessEvent(dap, dap.is_attach ? Attach : Launch); + + if (dap.stop_at_entry) + SendThreadStoppedEvent(dap); + else + process.Continue(); + + return Error::success(); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp index b64987746b3d5..0a178406b5a69 100644 --- a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp @@ -78,7 +78,3 @@ llvm::Expected InitializeRequestHandler::Run( return dap.GetCapabilities(); } - -void InitializeRequestHandler::PostRun() const { - dap.SendJSON(CreateEventObject("initialized")); -} diff --git a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp index 22d1a090187d8..1d7b4b7009462 100644 --- a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp @@ -67,25 +67,7 @@ Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const { } void LaunchRequestHandler::PostRun() const { - if (!dap.target.GetProcess().IsValid()) - return; - - // Clients can request a baseline of currently existing threads after - // we acknowledge the configurationDone request. - // Client requests the baseline of currently existing threads after - // a successful or attach by sending a 'threads' request - // right after receiving the configurationDone response. - // Obtain the list of threads before we resume the process - dap.initial_thread_list = - GetThreads(dap.target.GetProcess(), dap.thread_format); - - // Attach happens when launching with runInTerminal. - SendProcessEvent(dap, dap.is_attach ? Attach : Launch); - - if (dap.stop_at_entry) - SendThreadStoppedEvent(dap); - else - dap.target.GetProcess().Continue(); + dap.SendJSON(CreateEventObject("initialized")); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 383f9e24a729a..cbcff179ed9d1 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -21,6 +21,7 @@ #include "llvm/Support/JSON.h" #include #include +#include template struct is_optional : std::false_type {}; @@ -87,6 +88,34 @@ class LegacyRequestHandler : public BaseRequestHandler { } }; +template +llvm::Expected parseArgs(const protocol::Request &request) { + if (!is_optional_v && !request.arguments) + return llvm::make_error( + llvm::formatv("arguments required for command '{0}' " + "but none received", + request.command) + .str()); + + Args arguments; + llvm::json::Path::Root root("arguments"); + if (request.arguments && !fromJSON(*request.arguments, arguments, root)) { + std::string parse_failure; + llvm::raw_string_ostream OS(parse_failure); + OS << "invalid arguments for request '" << request.command + << "': " << llvm::toString(root.getError()) << "\n"; + root.printErrorContext(*request.arguments, OS); + return llvm::make_error(parse_failure); + } + + return arguments; +} +template <> +inline llvm::Expected +parseArgs(const protocol::Request &request) { + return std::nullopt; +} + /// Base class for handling DAP requests. Handlers should declare their /// arguments and response body types like: /// @@ -102,10 +131,8 @@ class RequestHandler : public BaseRequestHandler { response.request_seq = request.seq; response.command = request.command; - if (!is_optional_v && !request.arguments) { - DAP_LOG(dap.log, - "({0}) malformed request {1}, expected arguments but got none", - dap.transport.GetClientName(), request.command); + llvm::Expected arguments = parseArgs(request); + if (!arguments) { HandleErrorResponse( llvm::make_error( llvm::formatv("arguments required for command '{0}' " @@ -117,27 +144,14 @@ class RequestHandler : public BaseRequestHandler { return; } - Args arguments; - llvm::json::Path::Root root("arguments"); - if (request.arguments && !fromJSON(*request.arguments, arguments, root)) { - std::string parse_failure; - llvm::raw_string_ostream OS(parse_failure); - OS << "invalid arguments for request '" << request.command - << "': " << llvm::toString(root.getError()) << "\n"; - root.printErrorContext(*request.arguments, OS); - HandleErrorResponse(llvm::make_error(parse_failure), response); - dap.Send(response); - return; - } - if constexpr (std::is_same_v) { - if (llvm::Error err = Run(arguments)) { + if (llvm::Error err = Run(*arguments)) { HandleErrorResponse(std::move(err), response); } else { response.success = true; } } else { - Resp body = Run(arguments); + Resp body = Run(*arguments); if (llvm::Error err = body.takeError()) { HandleErrorResponse(std::move(err), response); } else { @@ -246,14 +260,17 @@ class ContinueRequestHandler Run(const protocol::ContinueArguments &args) const override; }; -class ConfigurationDoneRequestHandler : public LegacyRequestHandler { +class ConfigurationDoneRequestHandler + : public RequestHandler { public: - using LegacyRequestHandler::LegacyRequestHandler; + using RequestHandler::RequestHandler; static llvm::StringLiteral GetCommand() { return "configurationDone"; } FeatureSet GetSupportedFeatures() const override { return {protocol::eAdapterFeatureConfigurationDoneRequest}; } - void operator()(const llvm::json::Object &request) const override; + protocol::ConfigurationDoneResponse + Run(const protocol::ConfigurationDoneArguments &) const override; }; class DisconnectRequestHandler @@ -297,7 +314,6 @@ class InitializeRequestHandler static llvm::StringLiteral GetCommand() { return "initialize"; } llvm::Expected Run(const protocol::InitializeRequestArguments &args) const override; - void PostRun() const override; }; class LaunchRequestHandler diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h index bad0e886d94d2..1cb9cb13dd0da 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h @@ -148,6 +148,9 @@ struct ErrorResponseBody { }; llvm::json::Value toJSON(const ErrorResponseBody &); +/// This is a placehold for requests with an empty, null or undefined arguments. +using EmptyArguments = std::optional; + /// This is just an acknowledgement, so no body field is required. using VoidResponse = llvm::Error; diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index 4e08b4728453b..b421c631344de 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -370,6 +370,13 @@ struct ContinueResponseBody { }; llvm::json::Value toJSON(const ContinueResponseBody &); +/// Arguments for `configurationDone` request. +using ConfigurationDoneArguments = EmptyArguments; + +/// Response to `configurationDone` request. This is just an acknowledgement, so +/// no body field is required. +using ConfigurationDoneResponse = VoidResponse; + /// Arguments for `setVariable` request. struct SetVariableArguments { /// The reference of the variable container. The `variablesReference` must From lldb-commits at lists.llvm.org Fri May 16 18:50:11 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 18:50:11 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adjusting startup flow to better handle async operations. (PR #140299) In-Reply-To: Message-ID: <6827eb53.170a0220.1d6dfd.0986@mx.google.com> ashgti wrote: I think #140331 is a cleaner way to solve this without the need for an `AsyncRequestHandler`. We may still want the `AsyncRequestHandler` in the future, but at least for now, I think we can avoid its added complexity. https://github.com/llvm/llvm-project/pull/140299 From lldb-commits at lists.llvm.org Fri May 16 18:55:52 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 18:55:52 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Take two at refactoring the startup sequence. (PR #140331) In-Reply-To: Message-ID: <6827eca8.a70a0220.274e86.6df5@mx.google.com> https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/140331 >From 5c77f71128e01db1a3926d0de06f2d4d55cb80e0 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 16 May 2025 18:35:28 -0700 Subject: [PATCH] [lldb-dap] Take two at refactoring the startup sequence. This is more straight forward refactor of the startup sequence that reverts parts of ba29e60f9a2222bd5e883579bb78db13fc5a7588. Unlike my previous attempt, I ended up removing the pending request queue and not including an `AsyncReqeustHandler` because I don't think we actually need that at the moment. The key is that during the startup flow there are 2 parallel operations happening in the DAP that have different triggers. * The `initialize` request is sent and once the response is received the `launch` or `attach` is sent. * When the `initialized` event is recieved the `setBreakpionts` and other config requests are made followed by the `configurationDone` event. I moved the `initialized` event back to happen in the `PostRun` of the `launch` or `attach` request handlers. This ensures that we have a valid target by the time the configuration calls are made. I added also added a few extra validations that to the `configurationeDone` handler to ensure we're in an expected state. I've also fixed up the tests to match the new flow. With the other additional test fixes in 087a5d2ec7897cd99d3787820711fec76a8e1792 I think we've narrowed down the main source of test instability that motivated the startup sequence change. --- .../test/tools/lldb-dap/dap_server.py | 24 +++--- .../test/tools/lldb-dap/lldbdap_testcase.py | 70 +--------------- .../TestDAP_breakpointEvents.py | 2 +- .../tools/lldb-dap/cancel/TestDAP_cancel.py | 4 +- .../completions/TestDAP_completions.py | 17 ++-- .../tools/lldb-dap/console/TestDAP_console.py | 13 +-- .../console/TestDAP_redirection_to_console.py | 4 +- .../lldb-dap/coreFile/TestDAP_coreFile.py | 1 + .../lldb-dap/evaluate/TestDAP_evaluate.py | 1 - .../tools/lldb-dap/launch/TestDAP_launch.py | 4 +- .../module-event/TestDAP_module_event.py | 2 +- .../tools/lldb-dap/module/TestDAP_module.py | 4 +- .../repl-mode/TestDAP_repl_mode_detection.py | 2 +- .../tools/lldb-dap/restart/TestDAP_restart.py | 5 +- .../lldb-dap/send-event/TestDAP_sendEvent.py | 3 +- .../lldb-dap/stackTrace/TestDAP_stackTrace.py | 2 +- .../TestDAP_stackTraceDisassemblyDisplay.py | 2 +- .../startDebugging/TestDAP_startDebugging.py | 2 +- .../lldb-dap/stop-hooks/TestDAP_stop_hooks.py | 2 +- .../tools/lldb-dap/threads/TestDAP_threads.py | 5 +- .../children/TestDAP_variables_children.py | 5 +- lldb/tools/lldb-dap/DAP.cpp | 29 +------ lldb/tools/lldb-dap/DAP.h | 1 - .../lldb-dap/Handler/AttachRequestHandler.cpp | 19 +---- .../ConfigurationDoneRequestHandler.cpp | 82 ++++++++++--------- .../Handler/InitializeRequestHandler.cpp | 4 - .../lldb-dap/Handler/LaunchRequestHandler.cpp | 20 +---- lldb/tools/lldb-dap/Handler/RequestHandler.h | 62 ++++++++------ lldb/tools/lldb-dap/Protocol/ProtocolBase.h | 3 + .../lldb-dap/Protocol/ProtocolRequests.h | 7 ++ 30 files changed, 150 insertions(+), 251 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index d3589e78b6bc7..70fd0b0c419db 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -133,6 +133,7 @@ def __init__( self.output_condition = threading.Condition() self.output: dict[str, list[str]] = {} self.configuration_done_sent = False + self.initialized = False self.frame_scopes = {} self.init_commands = init_commands self.disassembled_instructions = {} @@ -235,6 +236,8 @@ def _handle_recv_packet(self, packet: Optional[ProtocolMessage]) -> bool: self.output_condition.release() # no need to add 'output' event packets to our packets list return keepGoing + elif event == "initialized": + self.initialized = True elif event == "process": # When a new process is attached or launched, remember the # details that are available in the body of the event @@ -602,7 +605,7 @@ def request_attach( exitCommands: Optional[list[str]] = None, terminateCommands: Optional[list[str]] = None, coreFile: Optional[str] = None, - stopOnAttach=True, + stopOnEntry=False, sourceMap: Optional[Union[list[tuple[str, str]], dict[str, str]]] = None, gdbRemotePort: Optional[int] = None, gdbRemoteHostname: Optional[str] = None, @@ -629,8 +632,8 @@ def request_attach( args_dict["attachCommands"] = attachCommands if coreFile: args_dict["coreFile"] = coreFile - if stopOnAttach: - args_dict["stopOnEntry"] = stopOnAttach + if stopOnEntry: + args_dict["stopOnEntry"] = stopOnEntry if postRunCommands: args_dict["postRunCommands"] = postRunCommands if sourceMap: @@ -640,11 +643,7 @@ def request_attach( if gdbRemoteHostname is not None: args_dict["gdb-remote-hostname"] = gdbRemoteHostname command_dict = {"command": "attach", "type": "request", "arguments": args_dict} - response = self.send_recv(command_dict) - - if response["success"]: - self.wait_for_event("process") - return response + return self.send_recv(command_dict) def request_breakpointLocations( self, file_path, line, end_line=None, column=None, end_column=None @@ -677,6 +676,7 @@ def request_configurationDone(self): response = self.send_recv(command_dict) if response: self.configuration_done_sent = True + self.request_threads() return response def _process_stopped(self): @@ -824,7 +824,7 @@ def request_launch( args: Optional[list[str]] = None, cwd: Optional[str] = None, env: Optional[dict[str, str]] = None, - stopOnEntry=True, + stopOnEntry=False, disableASLR=True, disableSTDIO=False, shellExpandArguments=False, @@ -894,11 +894,7 @@ def request_launch( if commandEscapePrefix is not None: args_dict["commandEscapePrefix"] = commandEscapePrefix command_dict = {"command": "launch", "type": "request", "arguments": args_dict} - response = self.send_recv(command_dict) - - if response["success"]: - self.wait_for_event("process") - return response + return self.send_recv(command_dict) def request_next(self, threadId, granularity="statement"): if self.exit_status is not None: diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index d7cf8e2864324..afdc746ed0d0d 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -56,7 +56,7 @@ def set_source_breakpoints(self, source_path, lines, data=None): It contains optional location/hitCondition/logMessage parameters. """ response = self.dap_server.request_setBreakpoints(source_path, lines, data) - if response is None: + if response is None or not response["success"]: return [] breakpoints = response["body"]["breakpoints"] breakpoint_ids = [] @@ -354,13 +354,9 @@ def disassemble(self, threadId=None, frameIndex=None): def attach( self, *, - stopOnAttach=True, disconnectAutomatically=True, sourceInitFile=False, expectFailure=False, - sourceBreakpoints=None, - functionBreakpoints=None, - timeout=DEFAULT_TIMEOUT, **kwargs, ): """Build the default Makefile target, create the DAP debug adapter, @@ -378,37 +374,13 @@ def cleanup(): self.addTearDownHook(cleanup) # Initialize and launch the program self.dap_server.request_initialize(sourceInitFile) - self.dap_server.wait_for_event("initialized", timeout) - - # Set source breakpoints as part of the launch sequence. - if sourceBreakpoints: - for source_path, lines in sourceBreakpoints: - response = self.dap_server.request_setBreakpoints(source_path, lines) - self.assertTrue( - response["success"], - "setBreakpoints failed (%s)" % (response), - ) - - # Set function breakpoints as part of the launch sequence. - if functionBreakpoints: - response = self.dap_server.request_setFunctionBreakpoints( - functionBreakpoints - ) - self.assertTrue( - response["success"], - "setFunctionBreakpoint failed (%s)" % (response), - ) - - self.dap_server.request_configurationDone() - response = self.dap_server.request_attach(stopOnAttach=stopOnAttach, **kwargs) + response = self.dap_server.request_attach(**kwargs) if expectFailure: return response if not (response and response["success"]): self.assertTrue( response["success"], "attach failed (%s)" % (response["message"]) ) - if stopOnAttach: - self.dap_server.wait_for_stopped(timeout) def launch( self, @@ -416,11 +388,7 @@ def launch( *, sourceInitFile=False, disconnectAutomatically=True, - sourceBreakpoints=None, - functionBreakpoints=None, expectFailure=False, - stopOnEntry=True, - timeout=DEFAULT_TIMEOUT, **kwargs, ): """Sending launch request to dap""" @@ -437,35 +405,7 @@ def cleanup(): # Initialize and launch the program self.dap_server.request_initialize(sourceInitFile) - self.dap_server.wait_for_event("initialized", timeout) - - # Set source breakpoints as part of the launch sequence. - if sourceBreakpoints: - for source_path, lines in sourceBreakpoints: - response = self.dap_server.request_setBreakpoints(source_path, lines) - self.assertTrue( - response["success"], - "setBreakpoints failed (%s)" % (response), - ) - - # Set function breakpoints as part of the launch sequence. - if functionBreakpoints: - response = self.dap_server.request_setFunctionBreakpoints( - functionBreakpoints - ) - self.assertTrue( - response["success"], - "setFunctionBreakpoint failed (%s)" % (response), - ) - - self.dap_server.request_configurationDone() - - response = self.dap_server.request_launch( - program, - stopOnEntry=stopOnEntry, - **kwargs, - ) - + response = self.dap_server.request_launch(program, **kwargs) if expectFailure: return response if not (response and response["success"]): @@ -473,10 +413,6 @@ def cleanup(): response["success"], "launch failed (%s)" % (response["body"]["error"]["format"]), ) - if stopOnEntry: - self.dap_server.wait_for_stopped(timeout) - - return response def build_and_launch( self, diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py index 25f031db5cac5..d46fc31d797da 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py @@ -52,7 +52,7 @@ def test_breakpoint_events(self): # breakpoint events for these breakpoints but not for ones that are not # set via the command interpreter. bp_command = "breakpoint set --file foo.cpp --line %u" % (foo_bp2_line) - self.build_and_launch(program, stopOnEntry=True, preRunCommands=[bp_command]) + self.build_and_launch(program, preRunCommands=[bp_command]) main_bp_id = 0 foo_bp_id = 0 # Set breakpoints and verify that they got set correctly diff --git a/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py b/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py index 948c146d4da68..824ed8fe3bb97 100644 --- a/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py +++ b/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py @@ -44,7 +44,7 @@ def test_pending_request(self): Tests cancelling a pending request. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) # Use a relatively short timeout since this is only to ensure the # following request is queued. @@ -76,7 +76,7 @@ def test_inflight_request(self): Tests cancelling an inflight request. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) blocking_seq = self.async_blocking_request(duration=self.DEFAULT_TIMEOUT / 2) # Wait for the sleep to start to cancel the inflight request. diff --git a/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py b/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py index 75876c248f86c..04897acfcf85d 100644 --- a/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py +++ b/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py @@ -46,17 +46,12 @@ def verify_completions(self, actual_list, expected_list, not_expected_list=[]): def setup_debuggee(self): program = self.getBuildArtifact("a.out") source = "main.cpp" - self.build_and_launch( - program, - stopOnEntry=True, - sourceBreakpoints=[ - ( - source, - [ - line_number(source, "// breakpoint 1"), - line_number(source, "// breakpoint 2"), - ], - ), + self.build_and_launch(program) + self.set_source_breakpoints( + source, + [ + line_number(source, "// breakpoint 1"), + line_number(source, "// breakpoint 2"), ], ) diff --git a/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py b/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py index 1f810afdbb667..7b4d1adbb2071 100644 --- a/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py +++ b/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py @@ -53,7 +53,7 @@ def test_scopes_variables_setVariable_evaluate(self): character. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") lines = [breakpoint1_line] @@ -66,6 +66,7 @@ def test_scopes_variables_setVariable_evaluate(self): # Cause a "scopes" to be sent for frame zero which should update the # selected thread and frame to frame 0. self.dap_server.get_local_variables(frameIndex=0) + # Verify frame #0 is selected in the command interpreter by running # the "frame select" command with no frame index which will print the # currently selected frame. @@ -74,15 +75,15 @@ def test_scopes_variables_setVariable_evaluate(self): # Cause a "scopes" to be sent for frame one which should update the # selected thread and frame to frame 1. self.dap_server.get_local_variables(frameIndex=1) + # Verify frame #1 is selected in the command interpreter by running # the "frame select" command with no frame index which will print the # currently selected frame. - self.check_lldb_command("frame select", "frame #1", "frame 1 is selected") def test_custom_escape_prefix(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="::") + self.build_and_launch(program, commandEscapePrefix="::") source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line]) @@ -97,7 +98,7 @@ def test_custom_escape_prefix(self): def test_empty_escape_prefix(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="") + self.build_and_launch(program, commandEscapePrefix="") source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line]) @@ -114,7 +115,7 @@ def test_empty_escape_prefix(self): def test_exit_status_message_sigterm(self): source = "main.cpp" program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="") + self.build_and_launch(program, commandEscapePrefix="") breakpoint1_line = line_number(source, "// breakpoint 1") breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line]) self.continue_to_breakpoints(breakpoint_ids) @@ -168,7 +169,7 @@ def test_exit_status_message_ok(self): def test_diagnositcs(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) core = self.getBuildArtifact("minidump.core") self.yaml2obj("minidump.yaml", core) diff --git a/lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py b/lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py index 23500bd6fe586..e367c327d4295 100644 --- a/lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py +++ b/lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py @@ -16,9 +16,7 @@ def test(self): """ program = self.getBuildArtifact("a.out") self.build_and_launch( - program, - stopOnEntry=True, - lldbDAPEnv={"LLDB_DAP_TEST_STDOUT_STDERR_REDIRECTION": ""}, + program, lldbDAPEnv={"LLDB_DAP_TEST_STDOUT_STDERR_REDIRECTION": ""} ) source = "main.cpp" diff --git a/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py b/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py index e678c5ee77fdc..db43dbaf515cf 100644 --- a/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py +++ b/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py @@ -19,6 +19,7 @@ def test_core_file(self): self.create_debug_adapter() self.attach(program=exe_file, coreFile=core_file) + self.dap_server.request_configurationDone() expected_frames = [ { diff --git a/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py b/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py index 372a9bb75e007..2166e88151986 100644 --- a/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py +++ b/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py @@ -43,7 +43,6 @@ def run_test_evaluate_expressions( self.build_and_launch( program, enableAutoVariableSummaries=enableAutoVariableSummaries, - stopOnEntry=True, ) source = "main.cpp" self.set_source_breakpoints( diff --git a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py index 0063954791fd5..8805ce50e6a21 100644 --- a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py +++ b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py @@ -87,7 +87,8 @@ def test_stopOnEntry(self): """ program = self.getBuildArtifact("a.out") self.build_and_launch(program, stopOnEntry=True) - + self.dap_server.request_configurationDone() + self.dap_server.wait_for_stopped() self.assertTrue( len(self.dap_server.thread_stop_reasons) > 0, "expected stopped event during launch", @@ -357,7 +358,6 @@ def test_commands(self): terminateCommands = ["expr 4+2"] self.build_and_launch( program, - stopOnEntry=True, initCommands=initCommands, preRunCommands=preRunCommands, postRunCommands=postRunCommands, diff --git a/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py b/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py index 19de35b60a3ef..1ef2f2a8235a4 100644 --- a/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py +++ b/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py @@ -10,7 +10,7 @@ class TestDAP_module_event(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_module_event(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") diff --git a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py index b333efd7bfb1f..3fc0f752ee39e 100644 --- a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py +++ b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py @@ -14,7 +14,7 @@ class TestDAP_module(lldbdap_testcase.DAPTestCaseBase): def run_test(self, symbol_basename, expect_debug_info_size): program_basename = "a.out.stripped" program = self.getBuildArtifact(program_basename) - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) functions = ["foo"] breakpoint_ids = self.set_function_breakpoints(functions) self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint") @@ -108,7 +108,7 @@ def test_modules_dsym(self): @skipIfWindows def test_compile_units(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.cpp" main_source_path = self.getSourcePath(source) breakpoint1_line = line_number(source, "// breakpoint 1") diff --git a/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py b/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py index 81edcdf4bd0f9..c6f59949d668e 100644 --- a/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py +++ b/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py @@ -20,7 +20,7 @@ def assertEvaluate(self, expression, regex): def test_completions(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") diff --git a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py index 8681b31e8eb1b..83faf276852f8 100644 --- a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py +++ b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py @@ -35,7 +35,7 @@ def test_basic_functionality(self): # Restart then check we stop back at A and program state has been reset. resp = self.dap_server.request_restart() self.assertTrue(resp["success"]) - self.continue_to_breakpoints([bp_A]) + self.verify_breakpoint_hit([bp_A]) self.assertEqual( int(self.dap_server.get_local_variable_value("i")), 0, @@ -50,6 +50,9 @@ def test_stopOnEntry(self): program = self.getBuildArtifact("a.out") self.build_and_launch(program, stopOnEntry=True) [bp_main] = self.set_function_breakpoints(["main"]) + + self.dap_server.request_configurationDone() + self.dap_server.wait_for_stopped() # Once the "configuration done" event is sent, we should get a stopped # event immediately because of stopOnEntry. self.assertTrue( diff --git a/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py b/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py index 3e015186d4b81..a01845669666f 100644 --- a/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py +++ b/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py @@ -24,7 +24,6 @@ def test_send_event(self): } self.build_and_launch( program, - sourceBreakpoints=[(source, [breakpoint_line])], stopCommands=[ "lldb-dap send-event my-custom-event-no-body", "lldb-dap send-event my-custom-event '{}'".format( @@ -32,6 +31,8 @@ def test_send_event(self): ), ], ) + self.set_source_breakpoints(source, [breakpoint_line]) + self.continue_to_next_stop() custom_event = self.dap_server.wait_for_event( filter=["my-custom-event-no-body"] diff --git a/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py b/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py index 9c6f1d42feda2..abd469274ffd4 100644 --- a/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py +++ b/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py @@ -61,7 +61,7 @@ def test_stackTrace(self): Tests the 'stackTrace' packet and all its variants. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.c" self.source_path = os.path.join(os.getcwd(), source) self.recurse_end = line_number(source, "recurse end") diff --git a/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py b/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py index 963d711978534..08c225b3cada4 100644 --- a/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py +++ b/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py @@ -37,7 +37,7 @@ def build_and_run_until_breakpoint(self): breakpoint_line = line_number(other_source_file, "// Break here") program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="") + self.build_and_launch(program, commandEscapePrefix="") breakpoint_ids = self.set_source_breakpoints( other_source_file, [breakpoint_line] diff --git a/lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py b/lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py index e37cd36d7f283..b487257b6414d 100644 --- a/lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py +++ b/lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py @@ -15,7 +15,7 @@ def test_startDebugging(self): """ program = self.getBuildArtifact("a.out") source = "main.c" - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) breakpoint_line = line_number(source, "// breakpoint") diff --git a/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py b/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py index 33e038408fa34..d630e1d14c3a0 100644 --- a/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py +++ b/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py @@ -15,7 +15,7 @@ def test_stop_hooks_before_run(self): """ program = self.getBuildArtifact("a.out") preRunCommands = ["target stop-hook add -o help"] - self.build_and_launch(program, stopOnEntry=True, preRunCommands=preRunCommands) + self.build_and_launch(program, preRunCommands=preRunCommands) breakpoint_ids = self.set_function_breakpoints(["main"]) # This request hangs if the race happens, because, in that case, the # command interpreter is in synchronous mode while lldb-dap expects diff --git a/lldb/test/API/tools/lldb-dap/threads/TestDAP_threads.py b/lldb/test/API/tools/lldb-dap/threads/TestDAP_threads.py index 6edb4b8e2a816..a4658da58ac94 100644 --- a/lldb/test/API/tools/lldb-dap/threads/TestDAP_threads.py +++ b/lldb/test/API/tools/lldb-dap/threads/TestDAP_threads.py @@ -50,7 +50,9 @@ def test_thread_format(self): """ program = self.getBuildArtifact("a.out") self.build_and_launch( - program, customThreadFormat="This is thread index #${thread.index}" + program, + customThreadFormat="This is thread index #${thread.index}", + stopCommands=["thread list"], ) source = "main.c" breakpoint_line = line_number(source, "// break here") @@ -63,5 +65,6 @@ def test_thread_format(self): self.continue_to_breakpoints(breakpoint_ids) # We are stopped at the second thread threads = self.dap_server.get_threads() + print("got thread", threads) self.assertEqual(threads[0]["name"], "This is thread index #1") self.assertEqual(threads[1]["name"], "This is thread index #2") diff --git a/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py b/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py index eb09649f387d7..75e75c4ad7c69 100644 --- a/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py +++ b/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py @@ -13,14 +13,11 @@ def test_get_num_children(self): program = self.getBuildArtifact("a.out") self.build_and_launch( program, - stopOnEntry=True, preRunCommands=[ "command script import '%s'" % self.getSourcePath("formatter.py") ], ) source = "main.cpp" - breakpoint1_line = line_number(source, "// break here") - breakpoint_ids = self.set_source_breakpoints( source, [line_number(source, "// break here")] ) @@ -47,7 +44,7 @@ def test_return_variable_with_children(self): Test the stepping out of a function with return value show the children correctly """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) function_name = "test_return_variable_with_children" breakpoint_ids = self.set_function_breakpoints([function_name]) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 56a0c38b00037..0d5eba6c40961 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -916,20 +916,10 @@ llvm::Error DAP::Loop() { return errWrapper; } - // The launch sequence is special and we need to carefully handle - // packets in the right order. Until we've handled configurationDone, - bool add_to_pending_queue = false; - if (const protocol::Request *req = - std::get_if(&*next)) { - llvm::StringRef command = req->command; - if (command == "disconnect") - disconnecting = true; - if (!configuration_done) - add_to_pending_queue = - command != "initialize" && command != "configurationDone" && - command != "disconnect" && !command.ends_with("Breakpoints"); - } + std::get_if(&*next); + req && req->arguments == "disconnect") + disconnecting = true; const std::optional cancel_args = getArgumentsIfRequest(*next, "cancel"); @@ -956,8 +946,7 @@ llvm::Error DAP::Loop() { { std::lock_guard guard(m_queue_mutex); - auto &queue = add_to_pending_queue ? m_pending_queue : m_queue; - queue.push_back(std::move(*next)); + m_queue.push_back(std::move(*next)); } m_queue_cv.notify_one(); } @@ -1255,16 +1244,6 @@ void DAP::SetConfiguration(const protocol::Configuration &config, SetThreadFormat(*configuration.customThreadFormat); } -void DAP::SetConfigurationDone() { - { - std::lock_guard guard(m_queue_mutex); - std::copy(m_pending_queue.begin(), m_pending_queue.end(), - std::front_inserter(m_queue)); - configuration_done = true; - } - m_queue_cv.notify_all(); -} - void DAP::SetFrameFormat(llvm::StringRef format) { lldb::SBError error; frame_format = lldb::SBFormat(format.str().c_str(), error); diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c1a1130b1e59f..8f24c6cf82924 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -444,7 +444,6 @@ struct DAP { /// Queue for all incoming messages. std::deque m_queue; - std::deque m_pending_queue; std::mutex m_queue_mutex; std::condition_variable m_queue_cv; diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp index 0293ffbd0c922..371349a26866e 100644 --- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp @@ -140,24 +140,7 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { } void AttachRequestHandler::PostRun() const { - if (!dap.target.GetProcess().IsValid()) - return; - - // Clients can request a baseline of currently existing threads after - // we acknowledge the configurationDone request. - // Client requests the baseline of currently existing threads after - // a successful or attach by sending a 'threads' request - // right after receiving the configurationDone response. - // Obtain the list of threads before we resume the process - dap.initial_thread_list = - GetThreads(dap.target.GetProcess(), dap.thread_format); - - SendProcessEvent(dap, Attach); - - if (dap.stop_at_entry) - SendThreadStoppedEvent(dap); - else - dap.target.GetProcess().Continue(); + dap.SendJSON(CreateEventObject("initialized")); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp index 802c28d7b8904..1281857ef4b60 100644 --- a/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp @@ -9,49 +9,53 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" +#include "lldb/API/SBDebugger.h" + +using namespace llvm; +using namespace lldb_dap::protocol; namespace lldb_dap { -// "ConfigurationDoneRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "ConfigurationDone request; value of command field -// is 'configurationDone'.\nThe client of the debug protocol must -// send this request at the end of the sequence of configuration -// requests (which was started by the InitializedEvent).", -// "properties": { -// "command": { -// "type": "string", -// "enum": [ "configurationDone" ] -// }, -// "arguments": { -// "$ref": "#/definitions/ConfigurationDoneArguments" -// } -// }, -// "required": [ "command" ] -// }] -// }, -// "ConfigurationDoneArguments": { -// "type": "object", -// "description": "Arguments for 'configurationDone' request.\nThe -// configurationDone request has no standardized attributes." -// }, -// "ConfigurationDoneResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to 'configurationDone' request. This is -// just an acknowledgement, so no body field is required." -// }] -// }, - -void ConfigurationDoneRequestHandler::operator()( - const llvm::json::Object &request) const { - dap.SetConfigurationDone(); - - llvm::json::Object response; - FillResponse(request, response); - dap.SendJSON(llvm::json::Value(std::move(response))); +/// This request indicates that the client has finished initialization of the +/// debug adapter. +/// +/// So it is the last request in the sequence of configuration requests (which +/// was started by the `initialized` event). +/// +/// Clients should only call this request if the corresponding capability +/// `supportsConfigurationDoneRequest` is true. +llvm::Error +ConfigurationDoneRequestHandler::Run(const ConfigurationDoneArguments &) const { + dap.configuration_done = true; + + // Ensure any command scripts did not leave us in an unexpected state. + lldb::SBProcess process = dap.target.GetProcess(); + if (!process.IsValid() || + !lldb::SBDebugger::StateIsStoppedState(process.GetState())) + return make_error( + "Expected process to be stopped.\r\n\r\nProcess is in an unexpected " + "state and may have missed an initial configuration. Please check that " + "any debugger command scripts are not resuming the process during the " + "launch sequence."); + + // Clients can request a baseline of currently existing threads after + // we acknowledge the configurationDone request. + // Client requests the baseline of currently existing threads after + // a successful or attach by sending a 'threads' request + // right after receiving the configurationDone response. + // Obtain the list of threads before we resume the process + dap.initial_thread_list = GetThreads(process, dap.thread_format); + + SendProcessEvent(dap, dap.is_attach ? Attach : Launch); + + if (dap.stop_at_entry) + SendThreadStoppedEvent(dap); + else + process.Continue(); + + return Error::success(); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp index b64987746b3d5..0a178406b5a69 100644 --- a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp @@ -78,7 +78,3 @@ llvm::Expected InitializeRequestHandler::Run( return dap.GetCapabilities(); } - -void InitializeRequestHandler::PostRun() const { - dap.SendJSON(CreateEventObject("initialized")); -} diff --git a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp index 22d1a090187d8..1d7b4b7009462 100644 --- a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp @@ -67,25 +67,7 @@ Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const { } void LaunchRequestHandler::PostRun() const { - if (!dap.target.GetProcess().IsValid()) - return; - - // Clients can request a baseline of currently existing threads after - // we acknowledge the configurationDone request. - // Client requests the baseline of currently existing threads after - // a successful or attach by sending a 'threads' request - // right after receiving the configurationDone response. - // Obtain the list of threads before we resume the process - dap.initial_thread_list = - GetThreads(dap.target.GetProcess(), dap.thread_format); - - // Attach happens when launching with runInTerminal. - SendProcessEvent(dap, dap.is_attach ? Attach : Launch); - - if (dap.stop_at_entry) - SendThreadStoppedEvent(dap); - else - dap.target.GetProcess().Continue(); + dap.SendJSON(CreateEventObject("initialized")); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 383f9e24a729a..cbcff179ed9d1 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -21,6 +21,7 @@ #include "llvm/Support/JSON.h" #include #include +#include template struct is_optional : std::false_type {}; @@ -87,6 +88,34 @@ class LegacyRequestHandler : public BaseRequestHandler { } }; +template +llvm::Expected parseArgs(const protocol::Request &request) { + if (!is_optional_v && !request.arguments) + return llvm::make_error( + llvm::formatv("arguments required for command '{0}' " + "but none received", + request.command) + .str()); + + Args arguments; + llvm::json::Path::Root root("arguments"); + if (request.arguments && !fromJSON(*request.arguments, arguments, root)) { + std::string parse_failure; + llvm::raw_string_ostream OS(parse_failure); + OS << "invalid arguments for request '" << request.command + << "': " << llvm::toString(root.getError()) << "\n"; + root.printErrorContext(*request.arguments, OS); + return llvm::make_error(parse_failure); + } + + return arguments; +} +template <> +inline llvm::Expected +parseArgs(const protocol::Request &request) { + return std::nullopt; +} + /// Base class for handling DAP requests. Handlers should declare their /// arguments and response body types like: /// @@ -102,10 +131,8 @@ class RequestHandler : public BaseRequestHandler { response.request_seq = request.seq; response.command = request.command; - if (!is_optional_v && !request.arguments) { - DAP_LOG(dap.log, - "({0}) malformed request {1}, expected arguments but got none", - dap.transport.GetClientName(), request.command); + llvm::Expected arguments = parseArgs(request); + if (!arguments) { HandleErrorResponse( llvm::make_error( llvm::formatv("arguments required for command '{0}' " @@ -117,27 +144,14 @@ class RequestHandler : public BaseRequestHandler { return; } - Args arguments; - llvm::json::Path::Root root("arguments"); - if (request.arguments && !fromJSON(*request.arguments, arguments, root)) { - std::string parse_failure; - llvm::raw_string_ostream OS(parse_failure); - OS << "invalid arguments for request '" << request.command - << "': " << llvm::toString(root.getError()) << "\n"; - root.printErrorContext(*request.arguments, OS); - HandleErrorResponse(llvm::make_error(parse_failure), response); - dap.Send(response); - return; - } - if constexpr (std::is_same_v) { - if (llvm::Error err = Run(arguments)) { + if (llvm::Error err = Run(*arguments)) { HandleErrorResponse(std::move(err), response); } else { response.success = true; } } else { - Resp body = Run(arguments); + Resp body = Run(*arguments); if (llvm::Error err = body.takeError()) { HandleErrorResponse(std::move(err), response); } else { @@ -246,14 +260,17 @@ class ContinueRequestHandler Run(const protocol::ContinueArguments &args) const override; }; -class ConfigurationDoneRequestHandler : public LegacyRequestHandler { +class ConfigurationDoneRequestHandler + : public RequestHandler { public: - using LegacyRequestHandler::LegacyRequestHandler; + using RequestHandler::RequestHandler; static llvm::StringLiteral GetCommand() { return "configurationDone"; } FeatureSet GetSupportedFeatures() const override { return {protocol::eAdapterFeatureConfigurationDoneRequest}; } - void operator()(const llvm::json::Object &request) const override; + protocol::ConfigurationDoneResponse + Run(const protocol::ConfigurationDoneArguments &) const override; }; class DisconnectRequestHandler @@ -297,7 +314,6 @@ class InitializeRequestHandler static llvm::StringLiteral GetCommand() { return "initialize"; } llvm::Expected Run(const protocol::InitializeRequestArguments &args) const override; - void PostRun() const override; }; class LaunchRequestHandler diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h index bad0e886d94d2..1cb9cb13dd0da 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h @@ -148,6 +148,9 @@ struct ErrorResponseBody { }; llvm::json::Value toJSON(const ErrorResponseBody &); +/// This is a placehold for requests with an empty, null or undefined arguments. +using EmptyArguments = std::optional; + /// This is just an acknowledgement, so no body field is required. using VoidResponse = llvm::Error; diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index 4e08b4728453b..b421c631344de 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -370,6 +370,13 @@ struct ContinueResponseBody { }; llvm::json::Value toJSON(const ContinueResponseBody &); +/// Arguments for `configurationDone` request. +using ConfigurationDoneArguments = EmptyArguments; + +/// Response to `configurationDone` request. This is just an acknowledgement, so +/// no body field is required. +using ConfigurationDoneResponse = VoidResponse; + /// Arguments for `setVariable` request. struct SetVariableArguments { /// The reference of the variable container. The `variablesReference` must From lldb-commits at lists.llvm.org Fri May 16 18:57:12 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 18:57:12 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Take two at refactoring the startup sequence. (PR #140331) In-Reply-To: Message-ID: <6827ecf8.050a0220.f4538.75e3@mx.google.com> ashgti wrote: @da-viper I think this version may be a bit cleaner for https://github.com/llvm/llvm-project/issues/140154, let me know if that works for you https://github.com/llvm/llvm-project/pull/140331 From lldb-commits at lists.llvm.org Fri May 16 18:57:21 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 18:57:21 -0700 (PDT) Subject: [Lldb-commits] [lldb] Update python.rst (PR #140333) Message-ID: https://github.com/LauraElanorJones created https://github.com/llvm/llvm-project/pull/140333 Fix code block formatting in section "The Decision Point Breakpoint Commands" >From 7d235fe77df46cfe2525cbed2a9944a6f208a613 Mon Sep 17 00:00:00 2001 From: LauraElanorJones <164247463+LauraElanorJones at users.noreply.github.com> Date: Fri, 16 May 2025 18:49:02 -0700 Subject: [PATCH] Update python.rst Fix code block formatting in section "The Decision Point Breakpoint Commands" --- lldb/docs/use/python.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lldb/docs/use/python.rst b/lldb/docs/use/python.rst index d9c29d95708c1..3a919f2a8cdb1 100644 --- a/lldb/docs/use/python.rst +++ b/lldb/docs/use/python.rst @@ -330,9 +330,12 @@ decision to go right: process.Continue() else: print "Here is the problem; going right, should go left!" - Just as a reminder, LLDB is going to take this script and wrap it up in a function, like this: +Just as a reminder, LLDB is going to take this script and wrap it up in a function, like this: + +:: + def some_unique_and_obscure_function_name (frame, bp_loc): global path if path[0] == 'R': From lldb-commits at lists.llvm.org Fri May 16 18:57:39 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 18:57:39 -0700 (PDT) Subject: [Lldb-commits] [lldb] Update python.rst (PR #140333) In-Reply-To: Message-ID: <6827ed13.630a0220.103036.a8e6@mx.google.com> github-actions[bot] wrote: Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using `@` followed by their GitHub username. If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the [LLVM GitHub User Guide](https://llvm.org/docs/GitHub.html). You can also ask questions in a comment on this PR, on the [LLVM Discord](https://discord.com/invite/xS7Z362) or on the [forums](https://discourse.llvm.org/). https://github.com/llvm/llvm-project/pull/140333 From lldb-commits at lists.llvm.org Fri May 16 18:57:47 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 18:57:47 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Adjusting startup flow to better handle async operations. (PR #140299) In-Reply-To: Message-ID: <6827ed1b.170a0220.e7b5b.48ee@mx.google.com> https://github.com/ashgti closed https://github.com/llvm/llvm-project/pull/140299 From lldb-commits at lists.llvm.org Fri May 16 18:58:18 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 18:58:18 -0700 (PDT) Subject: [Lldb-commits] [lldb] Update python.rst (PR #140333) In-Reply-To: Message-ID: <6827ed3a.170a0220.160907.6a92@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: None (LauraElanorJones)
Changes Fix code block formatting in section "The Decision Point Breakpoint Commands" --- Full diff: https://github.com/llvm/llvm-project/pull/140333.diff 1 Files Affected: - (modified) lldb/docs/use/python.rst (+4-1) ``````````diff diff --git a/lldb/docs/use/python.rst b/lldb/docs/use/python.rst index d9c29d95708c1..3a919f2a8cdb1 100644 --- a/lldb/docs/use/python.rst +++ b/lldb/docs/use/python.rst @@ -330,9 +330,12 @@ decision to go right: process.Continue() else: print "Here is the problem; going right, should go left!" - Just as a reminder, LLDB is going to take this script and wrap it up in a function, like this: +Just as a reminder, LLDB is going to take this script and wrap it up in a function, like this: + +:: + def some_unique_and_obscure_function_name (frame, bp_loc): global path if path[0] == 'R': ``````````
https://github.com/llvm/llvm-project/pull/140333 From lldb-commits at lists.llvm.org Fri May 16 18:59:28 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 18:59:28 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Listen for broadcast classes. (PR #140142) In-Reply-To: Message-ID: <6827ed80.170a0220.18eeef.68ef@mx.google.com> ashgti wrote: #140331 will also fix this underlying issue. I think its a better approach to fix this without having to listen for all events. https://github.com/llvm/llvm-project/pull/140142 From lldb-commits at lists.llvm.org Fri May 16 19:03:02 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Fri, 16 May 2025 19:03:02 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Take two at refactoring the startup sequence. (PR #140331) In-Reply-To: Message-ID: <6827ee56.170a0220.103927.652a@mx.google.com> https://github.com/JDevlieghere approved this pull request. I think you can move this out of draft. I'm thoroughly convinced that my first stab at this is wrong. The code LGTM and I like that we don't have to launch everything with `stopOnEntry`. The only thing I don't like is that the configurationDone is now once again implicit. In a future PR, I'd love to move the tests to a model where we specify that explicitly after doing the breakpoints (and automatically catch cases where someone forgets, like your PR from earlier this week). I'm happy to sign myself up to do that work. https://github.com/llvm/llvm-project/pull/140331 From lldb-commits at lists.llvm.org Fri May 16 19:03:20 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Fri, 16 May 2025 19:03:20 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Take two at refactoring the startup sequence. (PR #140331) In-Reply-To: Message-ID: <6827ee68.630a0220.1f0250.aa31@mx.google.com> https://github.com/JDevlieghere edited https://github.com/llvm/llvm-project/pull/140331 From lldb-commits at lists.llvm.org Fri May 16 19:04:36 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 19:04:36 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Take two at refactoring the startup sequence. (PR #140331) In-Reply-To: Message-ID: <6827eeb4.170a0220.2798aa.682b@mx.google.com> https://github.com/ashgti ready_for_review https://github.com/llvm/llvm-project/pull/140331 From lldb-commits at lists.llvm.org Fri May 16 19:05:14 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 19:05:14 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Take two at refactoring the startup sequence. (PR #140331) In-Reply-To: Message-ID: <6827eeda.a70a0220.6ab5f.79c7@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: John Harrison (ashgti)
Changes This is more straight forward refactor of the startup sequence that reverts parts of ba29e60f9a2222bd5e883579bb78db13fc5a7588. Unlike my previous attempt, I ended up removing the pending request queue and not including an `AsyncReqeustHandler` because I don't think we actually need that at the moment. The key is that during the startup flow there are 2 parallel operations happening in the DAP that have different triggers. * The `initialize` request is sent and once the response is received the `launch` or `attach` is sent. * When the `initialized` event is recieved the `setBreakpionts` and other config requests are made followed by the `configurationDone` event. I moved the `initialized` event back to happen in the `PostRun` of the `launch` or `attach` request handlers. This ensures that we have a valid target by the time the configuration calls are made. I added also added a few extra validations that to the `configurationeDone` handler to ensure we're in an expected state. I've also fixed up the tests to match the new flow. With the other additional test fixes in 087a5d2ec7897cd99d3787820711fec76a8e1792 I think we've narrowed down the main source of test instability that motivated the startup sequence change. --- Patch is 42.82 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/140331.diff 30 Files Affected: - (modified) lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py (+10-14) - (modified) lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py (+3-67) - (modified) lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py (+1-1) - (modified) lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py (+2-2) - (modified) lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py (+6-11) - (modified) lldb/test/API/tools/lldb-dap/console/TestDAP_console.py (+7-6) - (modified) lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py (+1-3) - (modified) lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py (+1) - (modified) lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py (-1) - (modified) lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py (+2-2) - (modified) lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py (+1-1) - (modified) lldb/test/API/tools/lldb-dap/module/TestDAP_module.py (+2-2) - (modified) lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py (+1-1) - (modified) lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py (+4-1) - (modified) lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py (+2-1) - (modified) lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py (+1-1) - (modified) lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py (+1-1) - (modified) lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py (+1-1) - (modified) lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py (+1-1) - (modified) lldb/test/API/tools/lldb-dap/threads/TestDAP_threads.py (+4-1) - (modified) lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py (+1-4) - (modified) lldb/tools/lldb-dap/DAP.cpp (+4-25) - (modified) lldb/tools/lldb-dap/DAP.h (-1) - (modified) lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp (+1-18) - (modified) lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp (+43-39) - (modified) lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp (-4) - (modified) lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp (+1-19) - (modified) lldb/tools/lldb-dap/Handler/RequestHandler.h (+39-23) - (modified) lldb/tools/lldb-dap/Protocol/ProtocolBase.h (+3) - (modified) lldb/tools/lldb-dap/Protocol/ProtocolRequests.h (+7) ``````````diff diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index d3589e78b6bc7..70fd0b0c419db 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -133,6 +133,7 @@ def __init__( self.output_condition = threading.Condition() self.output: dict[str, list[str]] = {} self.configuration_done_sent = False + self.initialized = False self.frame_scopes = {} self.init_commands = init_commands self.disassembled_instructions = {} @@ -235,6 +236,8 @@ def _handle_recv_packet(self, packet: Optional[ProtocolMessage]) -> bool: self.output_condition.release() # no need to add 'output' event packets to our packets list return keepGoing + elif event == "initialized": + self.initialized = True elif event == "process": # When a new process is attached or launched, remember the # details that are available in the body of the event @@ -602,7 +605,7 @@ def request_attach( exitCommands: Optional[list[str]] = None, terminateCommands: Optional[list[str]] = None, coreFile: Optional[str] = None, - stopOnAttach=True, + stopOnEntry=False, sourceMap: Optional[Union[list[tuple[str, str]], dict[str, str]]] = None, gdbRemotePort: Optional[int] = None, gdbRemoteHostname: Optional[str] = None, @@ -629,8 +632,8 @@ def request_attach( args_dict["attachCommands"] = attachCommands if coreFile: args_dict["coreFile"] = coreFile - if stopOnAttach: - args_dict["stopOnEntry"] = stopOnAttach + if stopOnEntry: + args_dict["stopOnEntry"] = stopOnEntry if postRunCommands: args_dict["postRunCommands"] = postRunCommands if sourceMap: @@ -640,11 +643,7 @@ def request_attach( if gdbRemoteHostname is not None: args_dict["gdb-remote-hostname"] = gdbRemoteHostname command_dict = {"command": "attach", "type": "request", "arguments": args_dict} - response = self.send_recv(command_dict) - - if response["success"]: - self.wait_for_event("process") - return response + return self.send_recv(command_dict) def request_breakpointLocations( self, file_path, line, end_line=None, column=None, end_column=None @@ -677,6 +676,7 @@ def request_configurationDone(self): response = self.send_recv(command_dict) if response: self.configuration_done_sent = True + self.request_threads() return response def _process_stopped(self): @@ -824,7 +824,7 @@ def request_launch( args: Optional[list[str]] = None, cwd: Optional[str] = None, env: Optional[dict[str, str]] = None, - stopOnEntry=True, + stopOnEntry=False, disableASLR=True, disableSTDIO=False, shellExpandArguments=False, @@ -894,11 +894,7 @@ def request_launch( if commandEscapePrefix is not None: args_dict["commandEscapePrefix"] = commandEscapePrefix command_dict = {"command": "launch", "type": "request", "arguments": args_dict} - response = self.send_recv(command_dict) - - if response["success"]: - self.wait_for_event("process") - return response + return self.send_recv(command_dict) def request_next(self, threadId, granularity="statement"): if self.exit_status is not None: diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index d7cf8e2864324..afdc746ed0d0d 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -56,7 +56,7 @@ def set_source_breakpoints(self, source_path, lines, data=None): It contains optional location/hitCondition/logMessage parameters. """ response = self.dap_server.request_setBreakpoints(source_path, lines, data) - if response is None: + if response is None or not response["success"]: return [] breakpoints = response["body"]["breakpoints"] breakpoint_ids = [] @@ -354,13 +354,9 @@ def disassemble(self, threadId=None, frameIndex=None): def attach( self, *, - stopOnAttach=True, disconnectAutomatically=True, sourceInitFile=False, expectFailure=False, - sourceBreakpoints=None, - functionBreakpoints=None, - timeout=DEFAULT_TIMEOUT, **kwargs, ): """Build the default Makefile target, create the DAP debug adapter, @@ -378,37 +374,13 @@ def cleanup(): self.addTearDownHook(cleanup) # Initialize and launch the program self.dap_server.request_initialize(sourceInitFile) - self.dap_server.wait_for_event("initialized", timeout) - - # Set source breakpoints as part of the launch sequence. - if sourceBreakpoints: - for source_path, lines in sourceBreakpoints: - response = self.dap_server.request_setBreakpoints(source_path, lines) - self.assertTrue( - response["success"], - "setBreakpoints failed (%s)" % (response), - ) - - # Set function breakpoints as part of the launch sequence. - if functionBreakpoints: - response = self.dap_server.request_setFunctionBreakpoints( - functionBreakpoints - ) - self.assertTrue( - response["success"], - "setFunctionBreakpoint failed (%s)" % (response), - ) - - self.dap_server.request_configurationDone() - response = self.dap_server.request_attach(stopOnAttach=stopOnAttach, **kwargs) + response = self.dap_server.request_attach(**kwargs) if expectFailure: return response if not (response and response["success"]): self.assertTrue( response["success"], "attach failed (%s)" % (response["message"]) ) - if stopOnAttach: - self.dap_server.wait_for_stopped(timeout) def launch( self, @@ -416,11 +388,7 @@ def launch( *, sourceInitFile=False, disconnectAutomatically=True, - sourceBreakpoints=None, - functionBreakpoints=None, expectFailure=False, - stopOnEntry=True, - timeout=DEFAULT_TIMEOUT, **kwargs, ): """Sending launch request to dap""" @@ -437,35 +405,7 @@ def cleanup(): # Initialize and launch the program self.dap_server.request_initialize(sourceInitFile) - self.dap_server.wait_for_event("initialized", timeout) - - # Set source breakpoints as part of the launch sequence. - if sourceBreakpoints: - for source_path, lines in sourceBreakpoints: - response = self.dap_server.request_setBreakpoints(source_path, lines) - self.assertTrue( - response["success"], - "setBreakpoints failed (%s)" % (response), - ) - - # Set function breakpoints as part of the launch sequence. - if functionBreakpoints: - response = self.dap_server.request_setFunctionBreakpoints( - functionBreakpoints - ) - self.assertTrue( - response["success"], - "setFunctionBreakpoint failed (%s)" % (response), - ) - - self.dap_server.request_configurationDone() - - response = self.dap_server.request_launch( - program, - stopOnEntry=stopOnEntry, - **kwargs, - ) - + response = self.dap_server.request_launch(program, **kwargs) if expectFailure: return response if not (response and response["success"]): @@ -473,10 +413,6 @@ def cleanup(): response["success"], "launch failed (%s)" % (response["body"]["error"]["format"]), ) - if stopOnEntry: - self.dap_server.wait_for_stopped(timeout) - - return response def build_and_launch( self, diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py index 25f031db5cac5..d46fc31d797da 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py @@ -52,7 +52,7 @@ def test_breakpoint_events(self): # breakpoint events for these breakpoints but not for ones that are not # set via the command interpreter. bp_command = "breakpoint set --file foo.cpp --line %u" % (foo_bp2_line) - self.build_and_launch(program, stopOnEntry=True, preRunCommands=[bp_command]) + self.build_and_launch(program, preRunCommands=[bp_command]) main_bp_id = 0 foo_bp_id = 0 # Set breakpoints and verify that they got set correctly diff --git a/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py b/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py index 948c146d4da68..824ed8fe3bb97 100644 --- a/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py +++ b/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py @@ -44,7 +44,7 @@ def test_pending_request(self): Tests cancelling a pending request. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) # Use a relatively short timeout since this is only to ensure the # following request is queued. @@ -76,7 +76,7 @@ def test_inflight_request(self): Tests cancelling an inflight request. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) blocking_seq = self.async_blocking_request(duration=self.DEFAULT_TIMEOUT / 2) # Wait for the sleep to start to cancel the inflight request. diff --git a/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py b/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py index 75876c248f86c..04897acfcf85d 100644 --- a/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py +++ b/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py @@ -46,17 +46,12 @@ def verify_completions(self, actual_list, expected_list, not_expected_list=[]): def setup_debuggee(self): program = self.getBuildArtifact("a.out") source = "main.cpp" - self.build_and_launch( - program, - stopOnEntry=True, - sourceBreakpoints=[ - ( - source, - [ - line_number(source, "// breakpoint 1"), - line_number(source, "// breakpoint 2"), - ], - ), + self.build_and_launch(program) + self.set_source_breakpoints( + source, + [ + line_number(source, "// breakpoint 1"), + line_number(source, "// breakpoint 2"), ], ) diff --git a/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py b/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py index 1f810afdbb667..7b4d1adbb2071 100644 --- a/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py +++ b/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py @@ -53,7 +53,7 @@ def test_scopes_variables_setVariable_evaluate(self): character. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") lines = [breakpoint1_line] @@ -66,6 +66,7 @@ def test_scopes_variables_setVariable_evaluate(self): # Cause a "scopes" to be sent for frame zero which should update the # selected thread and frame to frame 0. self.dap_server.get_local_variables(frameIndex=0) + # Verify frame #0 is selected in the command interpreter by running # the "frame select" command with no frame index which will print the # currently selected frame. @@ -74,15 +75,15 @@ def test_scopes_variables_setVariable_evaluate(self): # Cause a "scopes" to be sent for frame one which should update the # selected thread and frame to frame 1. self.dap_server.get_local_variables(frameIndex=1) + # Verify frame #1 is selected in the command interpreter by running # the "frame select" command with no frame index which will print the # currently selected frame. - self.check_lldb_command("frame select", "frame #1", "frame 1 is selected") def test_custom_escape_prefix(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="::") + self.build_and_launch(program, commandEscapePrefix="::") source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line]) @@ -97,7 +98,7 @@ def test_custom_escape_prefix(self): def test_empty_escape_prefix(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="") + self.build_and_launch(program, commandEscapePrefix="") source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line]) @@ -114,7 +115,7 @@ def test_empty_escape_prefix(self): def test_exit_status_message_sigterm(self): source = "main.cpp" program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="") + self.build_and_launch(program, commandEscapePrefix="") breakpoint1_line = line_number(source, "// breakpoint 1") breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line]) self.continue_to_breakpoints(breakpoint_ids) @@ -168,7 +169,7 @@ def test_exit_status_message_ok(self): def test_diagnositcs(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) core = self.getBuildArtifact("minidump.core") self.yaml2obj("minidump.yaml", core) diff --git a/lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py b/lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py index 23500bd6fe586..e367c327d4295 100644 --- a/lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py +++ b/lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py @@ -16,9 +16,7 @@ def test(self): """ program = self.getBuildArtifact("a.out") self.build_and_launch( - program, - stopOnEntry=True, - lldbDAPEnv={"LLDB_DAP_TEST_STDOUT_STDERR_REDIRECTION": ""}, + program, lldbDAPEnv={"LLDB_DAP_TEST_STDOUT_STDERR_REDIRECTION": ""} ) source = "main.cpp" diff --git a/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py b/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py index e678c5ee77fdc..db43dbaf515cf 100644 --- a/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py +++ b/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py @@ -19,6 +19,7 @@ def test_core_file(self): self.create_debug_adapter() self.attach(program=exe_file, coreFile=core_file) + self.dap_server.request_configurationDone() expected_frames = [ { diff --git a/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py b/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py index 372a9bb75e007..2166e88151986 100644 --- a/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py +++ b/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py @@ -43,7 +43,6 @@ def run_test_evaluate_expressions( self.build_and_launch( program, enableAutoVariableSummaries=enableAutoVariableSummaries, - stopOnEntry=True, ) source = "main.cpp" self.set_source_breakpoints( diff --git a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py index 0063954791fd5..8805ce50e6a21 100644 --- a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py +++ b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py @@ -87,7 +87,8 @@ def test_stopOnEntry(self): """ program = self.getBuildArtifact("a.out") self.build_and_launch(program, stopOnEntry=True) - + self.dap_server.request_configurationDone() + self.dap_server.wait_for_stopped() self.assertTrue( len(self.dap_server.thread_stop_reasons) > 0, "expected stopped event during launch", @@ -357,7 +358,6 @@ def test_commands(self): terminateCommands = ["expr 4+2"] self.build_and_launch( program, - stopOnEntry=True, initCommands=initCommands, preRunCommands=preRunCommands, postRunCommands=postRunCommands, diff --git a/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py b/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py index 19de35b60a3ef..1ef2f2a8235a4 100644 --- a/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py +++ b/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py @@ -10,7 +10,7 @@ class TestDAP_module_event(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_module_event(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") diff --git a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py index b333efd7bfb1f..3fc0f752ee39e 100644 --- a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py +++ b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py @@ -14,7 +14,7 @@ class TestDAP_module(lldbdap_testcase.DAPTestCaseBase): def run_test(self, symbol_basename, expect_debug_info_size): program_basename = "a.out.stripped" program = self.getBuildArtifact(program_basename) - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) functions = ["foo"] breakpoint_ids = self.set_function_breakpoints(functions) self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint") @@ -108,7 +108,7 @@ def test_modules_dsym(self): @skipIfWindows def test_compile_units(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.cpp" main_source_path = self.getSourcePath(source) breakpoint1_line = line_number(source, "// breakpoint 1") diff --git a/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py b/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py index 81edcdf4bd0f9..c6f59949d668e 100644 --- a/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py +++ b/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py @@ -20,7 +20,7 @@ def assertEvaluate(self, expression, regex): def test_completions(self): program = self.getBuildArtifact("a.out") - self.build_and_lau... [truncated] ``````````
https://github.com/llvm/llvm-project/pull/140331 From lldb-commits at lists.llvm.org Fri May 16 19:06:09 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 19:06:09 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Take two at refactoring the startup sequence. (PR #140331) In-Reply-To: Message-ID: <6827ef11.a70a0220.13c1b8.731a@mx.google.com> ashgti wrote: Looks like all the tests are passing on linux and for me locally as well. > The only thing I don't like is that the configurationDone is now once again implicit. In a future PR, I'd love to move the tests to a model where we specify that explicitly after doing the breakpoints (and automatically catch cases where someone forgets, like your PR from earlier this week). I'm happy to sign myself up to do that work. That sounds great! I think that would help clean up the tests a bit by making it a bit more explicit about when they're done configuring things. https://github.com/llvm/llvm-project/pull/140331 From lldb-commits at lists.llvm.org Fri May 16 19:09:39 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 19:09:39 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Take two at refactoring the startup sequence. (PR #140331) In-Reply-To: Message-ID: <6827efe3.a70a0220.125144.8418@mx.google.com> https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/140331 >From 5c77f71128e01db1a3926d0de06f2d4d55cb80e0 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 16 May 2025 18:35:28 -0700 Subject: [PATCH 1/2] [lldb-dap] Take two at refactoring the startup sequence. This is more straight forward refactor of the startup sequence that reverts parts of ba29e60f9a2222bd5e883579bb78db13fc5a7588. Unlike my previous attempt, I ended up removing the pending request queue and not including an `AsyncReqeustHandler` because I don't think we actually need that at the moment. The key is that during the startup flow there are 2 parallel operations happening in the DAP that have different triggers. * The `initialize` request is sent and once the response is received the `launch` or `attach` is sent. * When the `initialized` event is recieved the `setBreakpionts` and other config requests are made followed by the `configurationDone` event. I moved the `initialized` event back to happen in the `PostRun` of the `launch` or `attach` request handlers. This ensures that we have a valid target by the time the configuration calls are made. I added also added a few extra validations that to the `configurationeDone` handler to ensure we're in an expected state. I've also fixed up the tests to match the new flow. With the other additional test fixes in 087a5d2ec7897cd99d3787820711fec76a8e1792 I think we've narrowed down the main source of test instability that motivated the startup sequence change. --- .../test/tools/lldb-dap/dap_server.py | 24 +++--- .../test/tools/lldb-dap/lldbdap_testcase.py | 70 +--------------- .../TestDAP_breakpointEvents.py | 2 +- .../tools/lldb-dap/cancel/TestDAP_cancel.py | 4 +- .../completions/TestDAP_completions.py | 17 ++-- .../tools/lldb-dap/console/TestDAP_console.py | 13 +-- .../console/TestDAP_redirection_to_console.py | 4 +- .../lldb-dap/coreFile/TestDAP_coreFile.py | 1 + .../lldb-dap/evaluate/TestDAP_evaluate.py | 1 - .../tools/lldb-dap/launch/TestDAP_launch.py | 4 +- .../module-event/TestDAP_module_event.py | 2 +- .../tools/lldb-dap/module/TestDAP_module.py | 4 +- .../repl-mode/TestDAP_repl_mode_detection.py | 2 +- .../tools/lldb-dap/restart/TestDAP_restart.py | 5 +- .../lldb-dap/send-event/TestDAP_sendEvent.py | 3 +- .../lldb-dap/stackTrace/TestDAP_stackTrace.py | 2 +- .../TestDAP_stackTraceDisassemblyDisplay.py | 2 +- .../startDebugging/TestDAP_startDebugging.py | 2 +- .../lldb-dap/stop-hooks/TestDAP_stop_hooks.py | 2 +- .../tools/lldb-dap/threads/TestDAP_threads.py | 5 +- .../children/TestDAP_variables_children.py | 5 +- lldb/tools/lldb-dap/DAP.cpp | 29 +------ lldb/tools/lldb-dap/DAP.h | 1 - .../lldb-dap/Handler/AttachRequestHandler.cpp | 19 +---- .../ConfigurationDoneRequestHandler.cpp | 82 ++++++++++--------- .../Handler/InitializeRequestHandler.cpp | 4 - .../lldb-dap/Handler/LaunchRequestHandler.cpp | 20 +---- lldb/tools/lldb-dap/Handler/RequestHandler.h | 62 ++++++++------ lldb/tools/lldb-dap/Protocol/ProtocolBase.h | 3 + .../lldb-dap/Protocol/ProtocolRequests.h | 7 ++ 30 files changed, 150 insertions(+), 251 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index d3589e78b6bc7..70fd0b0c419db 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -133,6 +133,7 @@ def __init__( self.output_condition = threading.Condition() self.output: dict[str, list[str]] = {} self.configuration_done_sent = False + self.initialized = False self.frame_scopes = {} self.init_commands = init_commands self.disassembled_instructions = {} @@ -235,6 +236,8 @@ def _handle_recv_packet(self, packet: Optional[ProtocolMessage]) -> bool: self.output_condition.release() # no need to add 'output' event packets to our packets list return keepGoing + elif event == "initialized": + self.initialized = True elif event == "process": # When a new process is attached or launched, remember the # details that are available in the body of the event @@ -602,7 +605,7 @@ def request_attach( exitCommands: Optional[list[str]] = None, terminateCommands: Optional[list[str]] = None, coreFile: Optional[str] = None, - stopOnAttach=True, + stopOnEntry=False, sourceMap: Optional[Union[list[tuple[str, str]], dict[str, str]]] = None, gdbRemotePort: Optional[int] = None, gdbRemoteHostname: Optional[str] = None, @@ -629,8 +632,8 @@ def request_attach( args_dict["attachCommands"] = attachCommands if coreFile: args_dict["coreFile"] = coreFile - if stopOnAttach: - args_dict["stopOnEntry"] = stopOnAttach + if stopOnEntry: + args_dict["stopOnEntry"] = stopOnEntry if postRunCommands: args_dict["postRunCommands"] = postRunCommands if sourceMap: @@ -640,11 +643,7 @@ def request_attach( if gdbRemoteHostname is not None: args_dict["gdb-remote-hostname"] = gdbRemoteHostname command_dict = {"command": "attach", "type": "request", "arguments": args_dict} - response = self.send_recv(command_dict) - - if response["success"]: - self.wait_for_event("process") - return response + return self.send_recv(command_dict) def request_breakpointLocations( self, file_path, line, end_line=None, column=None, end_column=None @@ -677,6 +676,7 @@ def request_configurationDone(self): response = self.send_recv(command_dict) if response: self.configuration_done_sent = True + self.request_threads() return response def _process_stopped(self): @@ -824,7 +824,7 @@ def request_launch( args: Optional[list[str]] = None, cwd: Optional[str] = None, env: Optional[dict[str, str]] = None, - stopOnEntry=True, + stopOnEntry=False, disableASLR=True, disableSTDIO=False, shellExpandArguments=False, @@ -894,11 +894,7 @@ def request_launch( if commandEscapePrefix is not None: args_dict["commandEscapePrefix"] = commandEscapePrefix command_dict = {"command": "launch", "type": "request", "arguments": args_dict} - response = self.send_recv(command_dict) - - if response["success"]: - self.wait_for_event("process") - return response + return self.send_recv(command_dict) def request_next(self, threadId, granularity="statement"): if self.exit_status is not None: diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index d7cf8e2864324..afdc746ed0d0d 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -56,7 +56,7 @@ def set_source_breakpoints(self, source_path, lines, data=None): It contains optional location/hitCondition/logMessage parameters. """ response = self.dap_server.request_setBreakpoints(source_path, lines, data) - if response is None: + if response is None or not response["success"]: return [] breakpoints = response["body"]["breakpoints"] breakpoint_ids = [] @@ -354,13 +354,9 @@ def disassemble(self, threadId=None, frameIndex=None): def attach( self, *, - stopOnAttach=True, disconnectAutomatically=True, sourceInitFile=False, expectFailure=False, - sourceBreakpoints=None, - functionBreakpoints=None, - timeout=DEFAULT_TIMEOUT, **kwargs, ): """Build the default Makefile target, create the DAP debug adapter, @@ -378,37 +374,13 @@ def cleanup(): self.addTearDownHook(cleanup) # Initialize and launch the program self.dap_server.request_initialize(sourceInitFile) - self.dap_server.wait_for_event("initialized", timeout) - - # Set source breakpoints as part of the launch sequence. - if sourceBreakpoints: - for source_path, lines in sourceBreakpoints: - response = self.dap_server.request_setBreakpoints(source_path, lines) - self.assertTrue( - response["success"], - "setBreakpoints failed (%s)" % (response), - ) - - # Set function breakpoints as part of the launch sequence. - if functionBreakpoints: - response = self.dap_server.request_setFunctionBreakpoints( - functionBreakpoints - ) - self.assertTrue( - response["success"], - "setFunctionBreakpoint failed (%s)" % (response), - ) - - self.dap_server.request_configurationDone() - response = self.dap_server.request_attach(stopOnAttach=stopOnAttach, **kwargs) + response = self.dap_server.request_attach(**kwargs) if expectFailure: return response if not (response and response["success"]): self.assertTrue( response["success"], "attach failed (%s)" % (response["message"]) ) - if stopOnAttach: - self.dap_server.wait_for_stopped(timeout) def launch( self, @@ -416,11 +388,7 @@ def launch( *, sourceInitFile=False, disconnectAutomatically=True, - sourceBreakpoints=None, - functionBreakpoints=None, expectFailure=False, - stopOnEntry=True, - timeout=DEFAULT_TIMEOUT, **kwargs, ): """Sending launch request to dap""" @@ -437,35 +405,7 @@ def cleanup(): # Initialize and launch the program self.dap_server.request_initialize(sourceInitFile) - self.dap_server.wait_for_event("initialized", timeout) - - # Set source breakpoints as part of the launch sequence. - if sourceBreakpoints: - for source_path, lines in sourceBreakpoints: - response = self.dap_server.request_setBreakpoints(source_path, lines) - self.assertTrue( - response["success"], - "setBreakpoints failed (%s)" % (response), - ) - - # Set function breakpoints as part of the launch sequence. - if functionBreakpoints: - response = self.dap_server.request_setFunctionBreakpoints( - functionBreakpoints - ) - self.assertTrue( - response["success"], - "setFunctionBreakpoint failed (%s)" % (response), - ) - - self.dap_server.request_configurationDone() - - response = self.dap_server.request_launch( - program, - stopOnEntry=stopOnEntry, - **kwargs, - ) - + response = self.dap_server.request_launch(program, **kwargs) if expectFailure: return response if not (response and response["success"]): @@ -473,10 +413,6 @@ def cleanup(): response["success"], "launch failed (%s)" % (response["body"]["error"]["format"]), ) - if stopOnEntry: - self.dap_server.wait_for_stopped(timeout) - - return response def build_and_launch( self, diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py index 25f031db5cac5..d46fc31d797da 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py @@ -52,7 +52,7 @@ def test_breakpoint_events(self): # breakpoint events for these breakpoints but not for ones that are not # set via the command interpreter. bp_command = "breakpoint set --file foo.cpp --line %u" % (foo_bp2_line) - self.build_and_launch(program, stopOnEntry=True, preRunCommands=[bp_command]) + self.build_and_launch(program, preRunCommands=[bp_command]) main_bp_id = 0 foo_bp_id = 0 # Set breakpoints and verify that they got set correctly diff --git a/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py b/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py index 948c146d4da68..824ed8fe3bb97 100644 --- a/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py +++ b/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py @@ -44,7 +44,7 @@ def test_pending_request(self): Tests cancelling a pending request. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) # Use a relatively short timeout since this is only to ensure the # following request is queued. @@ -76,7 +76,7 @@ def test_inflight_request(self): Tests cancelling an inflight request. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) blocking_seq = self.async_blocking_request(duration=self.DEFAULT_TIMEOUT / 2) # Wait for the sleep to start to cancel the inflight request. diff --git a/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py b/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py index 75876c248f86c..04897acfcf85d 100644 --- a/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py +++ b/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py @@ -46,17 +46,12 @@ def verify_completions(self, actual_list, expected_list, not_expected_list=[]): def setup_debuggee(self): program = self.getBuildArtifact("a.out") source = "main.cpp" - self.build_and_launch( - program, - stopOnEntry=True, - sourceBreakpoints=[ - ( - source, - [ - line_number(source, "// breakpoint 1"), - line_number(source, "// breakpoint 2"), - ], - ), + self.build_and_launch(program) + self.set_source_breakpoints( + source, + [ + line_number(source, "// breakpoint 1"), + line_number(source, "// breakpoint 2"), ], ) diff --git a/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py b/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py index 1f810afdbb667..7b4d1adbb2071 100644 --- a/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py +++ b/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py @@ -53,7 +53,7 @@ def test_scopes_variables_setVariable_evaluate(self): character. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") lines = [breakpoint1_line] @@ -66,6 +66,7 @@ def test_scopes_variables_setVariable_evaluate(self): # Cause a "scopes" to be sent for frame zero which should update the # selected thread and frame to frame 0. self.dap_server.get_local_variables(frameIndex=0) + # Verify frame #0 is selected in the command interpreter by running # the "frame select" command with no frame index which will print the # currently selected frame. @@ -74,15 +75,15 @@ def test_scopes_variables_setVariable_evaluate(self): # Cause a "scopes" to be sent for frame one which should update the # selected thread and frame to frame 1. self.dap_server.get_local_variables(frameIndex=1) + # Verify frame #1 is selected in the command interpreter by running # the "frame select" command with no frame index which will print the # currently selected frame. - self.check_lldb_command("frame select", "frame #1", "frame 1 is selected") def test_custom_escape_prefix(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="::") + self.build_and_launch(program, commandEscapePrefix="::") source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line]) @@ -97,7 +98,7 @@ def test_custom_escape_prefix(self): def test_empty_escape_prefix(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="") + self.build_and_launch(program, commandEscapePrefix="") source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line]) @@ -114,7 +115,7 @@ def test_empty_escape_prefix(self): def test_exit_status_message_sigterm(self): source = "main.cpp" program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="") + self.build_and_launch(program, commandEscapePrefix="") breakpoint1_line = line_number(source, "// breakpoint 1") breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line]) self.continue_to_breakpoints(breakpoint_ids) @@ -168,7 +169,7 @@ def test_exit_status_message_ok(self): def test_diagnositcs(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) core = self.getBuildArtifact("minidump.core") self.yaml2obj("minidump.yaml", core) diff --git a/lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py b/lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py index 23500bd6fe586..e367c327d4295 100644 --- a/lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py +++ b/lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py @@ -16,9 +16,7 @@ def test(self): """ program = self.getBuildArtifact("a.out") self.build_and_launch( - program, - stopOnEntry=True, - lldbDAPEnv={"LLDB_DAP_TEST_STDOUT_STDERR_REDIRECTION": ""}, + program, lldbDAPEnv={"LLDB_DAP_TEST_STDOUT_STDERR_REDIRECTION": ""} ) source = "main.cpp" diff --git a/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py b/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py index e678c5ee77fdc..db43dbaf515cf 100644 --- a/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py +++ b/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py @@ -19,6 +19,7 @@ def test_core_file(self): self.create_debug_adapter() self.attach(program=exe_file, coreFile=core_file) + self.dap_server.request_configurationDone() expected_frames = [ { diff --git a/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py b/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py index 372a9bb75e007..2166e88151986 100644 --- a/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py +++ b/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py @@ -43,7 +43,6 @@ def run_test_evaluate_expressions( self.build_and_launch( program, enableAutoVariableSummaries=enableAutoVariableSummaries, - stopOnEntry=True, ) source = "main.cpp" self.set_source_breakpoints( diff --git a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py index 0063954791fd5..8805ce50e6a21 100644 --- a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py +++ b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py @@ -87,7 +87,8 @@ def test_stopOnEntry(self): """ program = self.getBuildArtifact("a.out") self.build_and_launch(program, stopOnEntry=True) - + self.dap_server.request_configurationDone() + self.dap_server.wait_for_stopped() self.assertTrue( len(self.dap_server.thread_stop_reasons) > 0, "expected stopped event during launch", @@ -357,7 +358,6 @@ def test_commands(self): terminateCommands = ["expr 4+2"] self.build_and_launch( program, - stopOnEntry=True, initCommands=initCommands, preRunCommands=preRunCommands, postRunCommands=postRunCommands, diff --git a/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py b/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py index 19de35b60a3ef..1ef2f2a8235a4 100644 --- a/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py +++ b/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py @@ -10,7 +10,7 @@ class TestDAP_module_event(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_module_event(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") diff --git a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py index b333efd7bfb1f..3fc0f752ee39e 100644 --- a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py +++ b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py @@ -14,7 +14,7 @@ class TestDAP_module(lldbdap_testcase.DAPTestCaseBase): def run_test(self, symbol_basename, expect_debug_info_size): program_basename = "a.out.stripped" program = self.getBuildArtifact(program_basename) - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) functions = ["foo"] breakpoint_ids = self.set_function_breakpoints(functions) self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint") @@ -108,7 +108,7 @@ def test_modules_dsym(self): @skipIfWindows def test_compile_units(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.cpp" main_source_path = self.getSourcePath(source) breakpoint1_line = line_number(source, "// breakpoint 1") diff --git a/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py b/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py index 81edcdf4bd0f9..c6f59949d668e 100644 --- a/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py +++ b/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py @@ -20,7 +20,7 @@ def assertEvaluate(self, expression, regex): def test_completions(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") diff --git a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py index 8681b31e8eb1b..83faf276852f8 100644 --- a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py +++ b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py @@ -35,7 +35,7 @@ def test_basic_functionality(self): # Restart then check we stop back at A and program state has been reset. resp = self.dap_server.request_restart() self.assertTrue(resp["success"]) - self.continue_to_breakpoints([bp_A]) + self.verify_breakpoint_hit([bp_A]) self.assertEqual( int(self.dap_server.get_local_variable_value("i")), 0, @@ -50,6 +50,9 @@ def test_stopOnEntry(self): program = self.getBuildArtifact("a.out") self.build_and_launch(program, stopOnEntry=True) [bp_main] = self.set_function_breakpoints(["main"]) + + self.dap_server.request_configurationDone() + self.dap_server.wait_for_stopped() # Once the "configuration done" event is sent, we should get a stopped # event immediately because of stopOnEntry. self.assertTrue( diff --git a/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py b/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py index 3e015186d4b81..a01845669666f 100644 --- a/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py +++ b/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py @@ -24,7 +24,6 @@ def test_send_event(self): } self.build_and_launch( program, - sourceBreakpoints=[(source, [breakpoint_line])], stopCommands=[ "lldb-dap send-event my-custom-event-no-body", "lldb-dap send-event my-custom-event '{}'".format( @@ -32,6 +31,8 @@ def test_send_event(self): ), ], ) + self.set_source_breakpoints(source, [breakpoint_line]) + self.continue_to_next_stop() custom_event = self.dap_server.wait_for_event( filter=["my-custom-event-no-body"] diff --git a/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py b/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py index 9c6f1d42feda2..abd469274ffd4 100644 --- a/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py +++ b/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py @@ -61,7 +61,7 @@ def test_stackTrace(self): Tests the 'stackTrace' packet and all its variants. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.c" self.source_path = os.path.join(os.getcwd(), source) self.recurse_end = line_number(source, "recurse end") diff --git a/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py b/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py index 963d711978534..08c225b3cada4 100644 --- a/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py +++ b/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py @@ -37,7 +37,7 @@ def build_and_run_until_breakpoint(self): breakpoint_line = line_number(other_source_file, "// Break here") program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="") + self.build_and_launch(program, commandEscapePrefix="") breakpoint_ids = self.set_source_breakpoints( other_source_file, [breakpoint_line] diff --git a/lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py b/lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py index e37cd36d7f283..b487257b6414d 100644 --- a/lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py +++ b/lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py @@ -15,7 +15,7 @@ def test_startDebugging(self): """ program = self.getBuildArtifact("a.out") source = "main.c" - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) breakpoint_line = line_number(source, "// breakpoint") diff --git a/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py b/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py index 33e038408fa34..d630e1d14c3a0 100644 --- a/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py +++ b/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py @@ -15,7 +15,7 @@ def test_stop_hooks_before_run(self): """ program = self.getBuildArtifact("a.out") preRunCommands = ["target stop-hook add -o help"] - self.build_and_launch(program, stopOnEntry=True, preRunCommands=preRunCommands) + self.build_and_launch(program, preRunCommands=preRunCommands) breakpoint_ids = self.set_function_breakpoints(["main"]) # This request hangs if the race happens, because, in that case, the # command interpreter is in synchronous mode while lldb-dap expects diff --git a/lldb/test/API/tools/lldb-dap/threads/TestDAP_threads.py b/lldb/test/API/tools/lldb-dap/threads/TestDAP_threads.py index 6edb4b8e2a816..a4658da58ac94 100644 --- a/lldb/test/API/tools/lldb-dap/threads/TestDAP_threads.py +++ b/lldb/test/API/tools/lldb-dap/threads/TestDAP_threads.py @@ -50,7 +50,9 @@ def test_thread_format(self): """ program = self.getBuildArtifact("a.out") self.build_and_launch( - program, customThreadFormat="This is thread index #${thread.index}" + program, + customThreadFormat="This is thread index #${thread.index}", + stopCommands=["thread list"], ) source = "main.c" breakpoint_line = line_number(source, "// break here") @@ -63,5 +65,6 @@ def test_thread_format(self): self.continue_to_breakpoints(breakpoint_ids) # We are stopped at the second thread threads = self.dap_server.get_threads() + print("got thread", threads) self.assertEqual(threads[0]["name"], "This is thread index #1") self.assertEqual(threads[1]["name"], "This is thread index #2") diff --git a/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py b/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py index eb09649f387d7..75e75c4ad7c69 100644 --- a/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py +++ b/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py @@ -13,14 +13,11 @@ def test_get_num_children(self): program = self.getBuildArtifact("a.out") self.build_and_launch( program, - stopOnEntry=True, preRunCommands=[ "command script import '%s'" % self.getSourcePath("formatter.py") ], ) source = "main.cpp" - breakpoint1_line = line_number(source, "// break here") - breakpoint_ids = self.set_source_breakpoints( source, [line_number(source, "// break here")] ) @@ -47,7 +44,7 @@ def test_return_variable_with_children(self): Test the stepping out of a function with return value show the children correctly """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) function_name = "test_return_variable_with_children" breakpoint_ids = self.set_function_breakpoints([function_name]) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 56a0c38b00037..0d5eba6c40961 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -916,20 +916,10 @@ llvm::Error DAP::Loop() { return errWrapper; } - // The launch sequence is special and we need to carefully handle - // packets in the right order. Until we've handled configurationDone, - bool add_to_pending_queue = false; - if (const protocol::Request *req = - std::get_if(&*next)) { - llvm::StringRef command = req->command; - if (command == "disconnect") - disconnecting = true; - if (!configuration_done) - add_to_pending_queue = - command != "initialize" && command != "configurationDone" && - command != "disconnect" && !command.ends_with("Breakpoints"); - } + std::get_if(&*next); + req && req->arguments == "disconnect") + disconnecting = true; const std::optional cancel_args = getArgumentsIfRequest(*next, "cancel"); @@ -956,8 +946,7 @@ llvm::Error DAP::Loop() { { std::lock_guard guard(m_queue_mutex); - auto &queue = add_to_pending_queue ? m_pending_queue : m_queue; - queue.push_back(std::move(*next)); + m_queue.push_back(std::move(*next)); } m_queue_cv.notify_one(); } @@ -1255,16 +1244,6 @@ void DAP::SetConfiguration(const protocol::Configuration &config, SetThreadFormat(*configuration.customThreadFormat); } -void DAP::SetConfigurationDone() { - { - std::lock_guard guard(m_queue_mutex); - std::copy(m_pending_queue.begin(), m_pending_queue.end(), - std::front_inserter(m_queue)); - configuration_done = true; - } - m_queue_cv.notify_all(); -} - void DAP::SetFrameFormat(llvm::StringRef format) { lldb::SBError error; frame_format = lldb::SBFormat(format.str().c_str(), error); diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c1a1130b1e59f..8f24c6cf82924 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -444,7 +444,6 @@ struct DAP { /// Queue for all incoming messages. std::deque m_queue; - std::deque m_pending_queue; std::mutex m_queue_mutex; std::condition_variable m_queue_cv; diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp index 0293ffbd0c922..371349a26866e 100644 --- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp @@ -140,24 +140,7 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { } void AttachRequestHandler::PostRun() const { - if (!dap.target.GetProcess().IsValid()) - return; - - // Clients can request a baseline of currently existing threads after - // we acknowledge the configurationDone request. - // Client requests the baseline of currently existing threads after - // a successful or attach by sending a 'threads' request - // right after receiving the configurationDone response. - // Obtain the list of threads before we resume the process - dap.initial_thread_list = - GetThreads(dap.target.GetProcess(), dap.thread_format); - - SendProcessEvent(dap, Attach); - - if (dap.stop_at_entry) - SendThreadStoppedEvent(dap); - else - dap.target.GetProcess().Continue(); + dap.SendJSON(CreateEventObject("initialized")); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp index 802c28d7b8904..1281857ef4b60 100644 --- a/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp @@ -9,49 +9,53 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" +#include "lldb/API/SBDebugger.h" + +using namespace llvm; +using namespace lldb_dap::protocol; namespace lldb_dap { -// "ConfigurationDoneRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "ConfigurationDone request; value of command field -// is 'configurationDone'.\nThe client of the debug protocol must -// send this request at the end of the sequence of configuration -// requests (which was started by the InitializedEvent).", -// "properties": { -// "command": { -// "type": "string", -// "enum": [ "configurationDone" ] -// }, -// "arguments": { -// "$ref": "#/definitions/ConfigurationDoneArguments" -// } -// }, -// "required": [ "command" ] -// }] -// }, -// "ConfigurationDoneArguments": { -// "type": "object", -// "description": "Arguments for 'configurationDone' request.\nThe -// configurationDone request has no standardized attributes." -// }, -// "ConfigurationDoneResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to 'configurationDone' request. This is -// just an acknowledgement, so no body field is required." -// }] -// }, - -void ConfigurationDoneRequestHandler::operator()( - const llvm::json::Object &request) const { - dap.SetConfigurationDone(); - - llvm::json::Object response; - FillResponse(request, response); - dap.SendJSON(llvm::json::Value(std::move(response))); +/// This request indicates that the client has finished initialization of the +/// debug adapter. +/// +/// So it is the last request in the sequence of configuration requests (which +/// was started by the `initialized` event). +/// +/// Clients should only call this request if the corresponding capability +/// `supportsConfigurationDoneRequest` is true. +llvm::Error +ConfigurationDoneRequestHandler::Run(const ConfigurationDoneArguments &) const { + dap.configuration_done = true; + + // Ensure any command scripts did not leave us in an unexpected state. + lldb::SBProcess process = dap.target.GetProcess(); + if (!process.IsValid() || + !lldb::SBDebugger::StateIsStoppedState(process.GetState())) + return make_error( + "Expected process to be stopped.\r\n\r\nProcess is in an unexpected " + "state and may have missed an initial configuration. Please check that " + "any debugger command scripts are not resuming the process during the " + "launch sequence."); + + // Clients can request a baseline of currently existing threads after + // we acknowledge the configurationDone request. + // Client requests the baseline of currently existing threads after + // a successful or attach by sending a 'threads' request + // right after receiving the configurationDone response. + // Obtain the list of threads before we resume the process + dap.initial_thread_list = GetThreads(process, dap.thread_format); + + SendProcessEvent(dap, dap.is_attach ? Attach : Launch); + + if (dap.stop_at_entry) + SendThreadStoppedEvent(dap); + else + process.Continue(); + + return Error::success(); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp index b64987746b3d5..0a178406b5a69 100644 --- a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp @@ -78,7 +78,3 @@ llvm::Expected InitializeRequestHandler::Run( return dap.GetCapabilities(); } - -void InitializeRequestHandler::PostRun() const { - dap.SendJSON(CreateEventObject("initialized")); -} diff --git a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp index 22d1a090187d8..1d7b4b7009462 100644 --- a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp @@ -67,25 +67,7 @@ Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const { } void LaunchRequestHandler::PostRun() const { - if (!dap.target.GetProcess().IsValid()) - return; - - // Clients can request a baseline of currently existing threads after - // we acknowledge the configurationDone request. - // Client requests the baseline of currently existing threads after - // a successful or attach by sending a 'threads' request - // right after receiving the configurationDone response. - // Obtain the list of threads before we resume the process - dap.initial_thread_list = - GetThreads(dap.target.GetProcess(), dap.thread_format); - - // Attach happens when launching with runInTerminal. - SendProcessEvent(dap, dap.is_attach ? Attach : Launch); - - if (dap.stop_at_entry) - SendThreadStoppedEvent(dap); - else - dap.target.GetProcess().Continue(); + dap.SendJSON(CreateEventObject("initialized")); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 383f9e24a729a..cbcff179ed9d1 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -21,6 +21,7 @@ #include "llvm/Support/JSON.h" #include #include +#include template struct is_optional : std::false_type {}; @@ -87,6 +88,34 @@ class LegacyRequestHandler : public BaseRequestHandler { } }; +template +llvm::Expected parseArgs(const protocol::Request &request) { + if (!is_optional_v && !request.arguments) + return llvm::make_error( + llvm::formatv("arguments required for command '{0}' " + "but none received", + request.command) + .str()); + + Args arguments; + llvm::json::Path::Root root("arguments"); + if (request.arguments && !fromJSON(*request.arguments, arguments, root)) { + std::string parse_failure; + llvm::raw_string_ostream OS(parse_failure); + OS << "invalid arguments for request '" << request.command + << "': " << llvm::toString(root.getError()) << "\n"; + root.printErrorContext(*request.arguments, OS); + return llvm::make_error(parse_failure); + } + + return arguments; +} +template <> +inline llvm::Expected +parseArgs(const protocol::Request &request) { + return std::nullopt; +} + /// Base class for handling DAP requests. Handlers should declare their /// arguments and response body types like: /// @@ -102,10 +131,8 @@ class RequestHandler : public BaseRequestHandler { response.request_seq = request.seq; response.command = request.command; - if (!is_optional_v && !request.arguments) { - DAP_LOG(dap.log, - "({0}) malformed request {1}, expected arguments but got none", - dap.transport.GetClientName(), request.command); + llvm::Expected arguments = parseArgs(request); + if (!arguments) { HandleErrorResponse( llvm::make_error( llvm::formatv("arguments required for command '{0}' " @@ -117,27 +144,14 @@ class RequestHandler : public BaseRequestHandler { return; } - Args arguments; - llvm::json::Path::Root root("arguments"); - if (request.arguments && !fromJSON(*request.arguments, arguments, root)) { - std::string parse_failure; - llvm::raw_string_ostream OS(parse_failure); - OS << "invalid arguments for request '" << request.command - << "': " << llvm::toString(root.getError()) << "\n"; - root.printErrorContext(*request.arguments, OS); - HandleErrorResponse(llvm::make_error(parse_failure), response); - dap.Send(response); - return; - } - if constexpr (std::is_same_v) { - if (llvm::Error err = Run(arguments)) { + if (llvm::Error err = Run(*arguments)) { HandleErrorResponse(std::move(err), response); } else { response.success = true; } } else { - Resp body = Run(arguments); + Resp body = Run(*arguments); if (llvm::Error err = body.takeError()) { HandleErrorResponse(std::move(err), response); } else { @@ -246,14 +260,17 @@ class ContinueRequestHandler Run(const protocol::ContinueArguments &args) const override; }; -class ConfigurationDoneRequestHandler : public LegacyRequestHandler { +class ConfigurationDoneRequestHandler + : public RequestHandler { public: - using LegacyRequestHandler::LegacyRequestHandler; + using RequestHandler::RequestHandler; static llvm::StringLiteral GetCommand() { return "configurationDone"; } FeatureSet GetSupportedFeatures() const override { return {protocol::eAdapterFeatureConfigurationDoneRequest}; } - void operator()(const llvm::json::Object &request) const override; + protocol::ConfigurationDoneResponse + Run(const protocol::ConfigurationDoneArguments &) const override; }; class DisconnectRequestHandler @@ -297,7 +314,6 @@ class InitializeRequestHandler static llvm::StringLiteral GetCommand() { return "initialize"; } llvm::Expected Run(const protocol::InitializeRequestArguments &args) const override; - void PostRun() const override; }; class LaunchRequestHandler diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h index bad0e886d94d2..1cb9cb13dd0da 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h @@ -148,6 +148,9 @@ struct ErrorResponseBody { }; llvm::json::Value toJSON(const ErrorResponseBody &); +/// This is a placehold for requests with an empty, null or undefined arguments. +using EmptyArguments = std::optional; + /// This is just an acknowledgement, so no body field is required. using VoidResponse = llvm::Error; diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index 4e08b4728453b..b421c631344de 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -370,6 +370,13 @@ struct ContinueResponseBody { }; llvm::json::Value toJSON(const ContinueResponseBody &); +/// Arguments for `configurationDone` request. +using ConfigurationDoneArguments = EmptyArguments; + +/// Response to `configurationDone` request. This is just an acknowledgement, so +/// no body field is required. +using ConfigurationDoneResponse = VoidResponse; + /// Arguments for `setVariable` request. struct SetVariableArguments { /// The reference of the variable container. The `variablesReference` must >From 0e3748b33d09009334c8f3a676dd86beb4f6ffb2 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 16 May 2025 19:09:19 -0700 Subject: [PATCH 2/2] Correct the error handling when parseArgs fails in `RequestHandler`. --- lldb/tools/lldb-dap/Handler/RequestHandler.h | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index cbcff179ed9d1..e6bccfe12f402 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -132,14 +132,8 @@ class RequestHandler : public BaseRequestHandler { response.command = request.command; llvm::Expected arguments = parseArgs(request); - if (!arguments) { - HandleErrorResponse( - llvm::make_error( - llvm::formatv("arguments required for command '{0}' " - "but none received", - request.command) - .str()), - response); + if (llvm::Error err = arguments.takeError()) { + HandleErrorResponse(std::move(err), response); dap.Send(response); return; } From lldb-commits at lists.llvm.org Fri May 16 19:15:24 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Fri, 16 May 2025 19:15:24 -0700 (PDT) Subject: [Lldb-commits] [lldb] Update python.rst (PR #140333) In-Reply-To: Message-ID: <6827f13c.050a0220.d7bd1.719a@mx.google.com> https://github.com/JDevlieghere approved this pull request. https://github.com/llvm/llvm-project/pull/140333 From lldb-commits at lists.llvm.org Fri May 16 19:16:08 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Fri, 16 May 2025 19:16:08 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Take two at refactoring the startup sequence. (PR #140331) In-Reply-To: Message-ID: <6827f168.170a0220.3433c.68bb@mx.google.com> JDevlieghere wrote: > Looks like all the tests are passing on linux and for me locally on macOS as well. All the macOS tests are passing for me as well. https://github.com/llvm/llvm-project/pull/140331 From lldb-commits at lists.llvm.org Fri May 16 19:17:07 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 19:17:07 -0700 (PDT) Subject: [Lldb-commits] [lldb] 9178a17 - Update python.rst (#140333) Message-ID: <6827f1a3.170a0220.3d34f1.34e2@mx.google.com> Author: LauraElanorJones Date: 2025-05-16T19:17:03-07:00 New Revision: 9178a1720667807aa46dcfc3069bad7e8fef5f2e URL: https://github.com/llvm/llvm-project/commit/9178a1720667807aa46dcfc3069bad7e8fef5f2e DIFF: https://github.com/llvm/llvm-project/commit/9178a1720667807aa46dcfc3069bad7e8fef5f2e.diff LOG: Update python.rst (#140333) Fix code block formatting in section "The Decision Point Breakpoint Commands" Added: Modified: lldb/docs/use/python.rst Removed: ################################################################################ diff --git a/lldb/docs/use/python.rst b/lldb/docs/use/python.rst index d9c29d95708c1..3a919f2a8cdb1 100644 --- a/lldb/docs/use/python.rst +++ b/lldb/docs/use/python.rst @@ -330,9 +330,12 @@ decision to go right: process.Continue() else: print "Here is the problem; going right, should go left!" - Just as a reminder, LLDB is going to take this script and wrap it up in a function, like this: +Just as a reminder, LLDB is going to take this script and wrap it up in a function, like this: + +:: + def some_unique_and_obscure_function_name (frame, bp_loc): global path if path[0] == 'R': From lldb-commits at lists.llvm.org Fri May 16 19:17:09 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Fri, 16 May 2025 19:17:09 -0700 (PDT) Subject: [Lldb-commits] [lldb] Update python.rst (PR #140333) In-Reply-To: Message-ID: <6827f1a5.a70a0220.27a4c6.8011@mx.google.com> https://github.com/JDevlieghere closed https://github.com/llvm/llvm-project/pull/140333 From lldb-commits at lists.llvm.org Fri May 16 19:17:28 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 19:17:28 -0700 (PDT) Subject: [Lldb-commits] [lldb] Update python.rst (PR #140333) In-Reply-To: Message-ID: <6827f1b8.a70a0220.2a028.425b@mx.google.com> github-actions[bot] wrote: @LauraElanorJones Congratulations on having your first Pull Request (PR) merged into the LLVM Project! Your changes will be combined with recent changes from other authors, then tested by our [build bots](https://lab.llvm.org/buildbot/). If there is a problem with a build, you may receive a report in an email or a comment on this PR. Please check whether problems have been caused by your change specifically, as the builds can include changes from many authors. It is not uncommon for your change to be included in a build that fails due to someone else's changes, or infrastructure issues. How to do this, and the rest of the post-merge process, is covered in detail [here](https://llvm.org/docs/MyFirstTypoFix.html#myfirsttypofix-issues-after-landing-your-pr). If your change does cause a problem, it may be reverted, or you can revert it yourself. This is a normal part of [LLVM development](https://llvm.org/docs/DeveloperPolicy.html#patch-reversion-policy). You can fix your changes and open a new PR to merge them again. If you don't get any reports, no action is required from you. Your changes are working as expected, well done! https://github.com/llvm/llvm-project/pull/140333 From lldb-commits at lists.llvm.org Fri May 16 19:18:24 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 19:18:24 -0700 (PDT) Subject: [Lldb-commits] [lldb] Update python.rst (PR #140333) In-Reply-To: Message-ID: <6827f1f0.170a0220.245487.9662@mx.google.com> github-actions[bot] wrote: ⚠️ We detected that you are using a GitHub private e-mail address to contribute to the repo.
Please turn off [Keep my email addresses private](https://github.com/settings/emails) setting in your account.
See [LLVM Discourse](https://discourse.llvm.org/t/hidden-emails-on-github-should-we-do-something-about-it) for more information. https://github.com/llvm/llvm-project/pull/140333 From lldb-commits at lists.llvm.org Fri May 16 19:28:37 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 19:28:37 -0700 (PDT) Subject: [Lldb-commits] [lldb] 0e0b501 - [lldb-dap] Take two at refactoring the startup sequence. (#140331) Message-ID: <6827f455.170a0220.12518c.6b74@mx.google.com> Author: John Harrison Date: 2025-05-16T19:28:34-07:00 New Revision: 0e0b501bf53677105b539fa4f84cbfb76c46f74d URL: https://github.com/llvm/llvm-project/commit/0e0b501bf53677105b539fa4f84cbfb76c46f74d DIFF: https://github.com/llvm/llvm-project/commit/0e0b501bf53677105b539fa4f84cbfb76c46f74d.diff LOG: [lldb-dap] Take two at refactoring the startup sequence. (#140331) This is more straight forward refactor of the startup sequence that reverts parts of ba29e60f9a2222bd5e883579bb78db13fc5a7588. Unlike my previous attempt, I ended up removing the pending request queue and not including an `AsyncReqeustHandler` because I don't think we actually need that at the moment. The key is that during the startup flow there are 2 parallel operations happening in the DAP that have different triggers. * The `initialize` request is sent and once the response is received the `launch` or `attach` is sent. * When the `initialized` event is recieved the `setBreakpionts` and other config requests are made followed by the `configurationDone` event. I moved the `initialized` event back to happen in the `PostRun` of the `launch` or `attach` request handlers. This ensures that we have a valid target by the time the configuration calls are made. I added also added a few extra validations that to the `configurationeDone` handler to ensure we're in an expected state. I've also fixed up the tests to match the new flow. With the other additional test fixes in 087a5d2ec7897cd99d3787820711fec76a8e1792 I think we've narrowed down the main source of test instability that motivated the startup sequence change. Added: Modified: lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py lldb/test/API/tools/lldb-dap/console/TestDAP_console.py lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py lldb/test/API/tools/lldb-dap/module/TestDAP_module.py lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py lldb/test/API/tools/lldb-dap/threads/TestDAP_threads.py lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py lldb/tools/lldb-dap/DAP.cpp lldb/tools/lldb-dap/DAP.h lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp lldb/tools/lldb-dap/Handler/RequestHandler.h lldb/tools/lldb-dap/Protocol/ProtocolBase.h lldb/tools/lldb-dap/Protocol/ProtocolRequests.h Removed: ################################################################################ diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index d3589e78b6bc7..70fd0b0c419db 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -133,6 +133,7 @@ def __init__( self.output_condition = threading.Condition() self.output: dict[str, list[str]] = {} self.configuration_done_sent = False + self.initialized = False self.frame_scopes = {} self.init_commands = init_commands self.disassembled_instructions = {} @@ -235,6 +236,8 @@ def _handle_recv_packet(self, packet: Optional[ProtocolMessage]) -> bool: self.output_condition.release() # no need to add 'output' event packets to our packets list return keepGoing + elif event == "initialized": + self.initialized = True elif event == "process": # When a new process is attached or launched, remember the # details that are available in the body of the event @@ -602,7 +605,7 @@ def request_attach( exitCommands: Optional[list[str]] = None, terminateCommands: Optional[list[str]] = None, coreFile: Optional[str] = None, - stopOnAttach=True, + stopOnEntry=False, sourceMap: Optional[Union[list[tuple[str, str]], dict[str, str]]] = None, gdbRemotePort: Optional[int] = None, gdbRemoteHostname: Optional[str] = None, @@ -629,8 +632,8 @@ def request_attach( args_dict["attachCommands"] = attachCommands if coreFile: args_dict["coreFile"] = coreFile - if stopOnAttach: - args_dict["stopOnEntry"] = stopOnAttach + if stopOnEntry: + args_dict["stopOnEntry"] = stopOnEntry if postRunCommands: args_dict["postRunCommands"] = postRunCommands if sourceMap: @@ -640,11 +643,7 @@ def request_attach( if gdbRemoteHostname is not None: args_dict["gdb-remote-hostname"] = gdbRemoteHostname command_dict = {"command": "attach", "type": "request", "arguments": args_dict} - response = self.send_recv(command_dict) - - if response["success"]: - self.wait_for_event("process") - return response + return self.send_recv(command_dict) def request_breakpointLocations( self, file_path, line, end_line=None, column=None, end_column=None @@ -677,6 +676,7 @@ def request_configurationDone(self): response = self.send_recv(command_dict) if response: self.configuration_done_sent = True + self.request_threads() return response def _process_stopped(self): @@ -824,7 +824,7 @@ def request_launch( args: Optional[list[str]] = None, cwd: Optional[str] = None, env: Optional[dict[str, str]] = None, - stopOnEntry=True, + stopOnEntry=False, disableASLR=True, disableSTDIO=False, shellExpandArguments=False, @@ -894,11 +894,7 @@ def request_launch( if commandEscapePrefix is not None: args_dict["commandEscapePrefix"] = commandEscapePrefix command_dict = {"command": "launch", "type": "request", "arguments": args_dict} - response = self.send_recv(command_dict) - - if response["success"]: - self.wait_for_event("process") - return response + return self.send_recv(command_dict) def request_next(self, threadId, granularity="statement"): if self.exit_status is not None: diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index d7cf8e2864324..afdc746ed0d0d 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -56,7 +56,7 @@ def set_source_breakpoints(self, source_path, lines, data=None): It contains optional location/hitCondition/logMessage parameters. """ response = self.dap_server.request_setBreakpoints(source_path, lines, data) - if response is None: + if response is None or not response["success"]: return [] breakpoints = response["body"]["breakpoints"] breakpoint_ids = [] @@ -354,13 +354,9 @@ def disassemble(self, threadId=None, frameIndex=None): def attach( self, *, - stopOnAttach=True, disconnectAutomatically=True, sourceInitFile=False, expectFailure=False, - sourceBreakpoints=None, - functionBreakpoints=None, - timeout=DEFAULT_TIMEOUT, **kwargs, ): """Build the default Makefile target, create the DAP debug adapter, @@ -378,37 +374,13 @@ def cleanup(): self.addTearDownHook(cleanup) # Initialize and launch the program self.dap_server.request_initialize(sourceInitFile) - self.dap_server.wait_for_event("initialized", timeout) - - # Set source breakpoints as part of the launch sequence. - if sourceBreakpoints: - for source_path, lines in sourceBreakpoints: - response = self.dap_server.request_setBreakpoints(source_path, lines) - self.assertTrue( - response["success"], - "setBreakpoints failed (%s)" % (response), - ) - - # Set function breakpoints as part of the launch sequence. - if functionBreakpoints: - response = self.dap_server.request_setFunctionBreakpoints( - functionBreakpoints - ) - self.assertTrue( - response["success"], - "setFunctionBreakpoint failed (%s)" % (response), - ) - - self.dap_server.request_configurationDone() - response = self.dap_server.request_attach(stopOnAttach=stopOnAttach, **kwargs) + response = self.dap_server.request_attach(**kwargs) if expectFailure: return response if not (response and response["success"]): self.assertTrue( response["success"], "attach failed (%s)" % (response["message"]) ) - if stopOnAttach: - self.dap_server.wait_for_stopped(timeout) def launch( self, @@ -416,11 +388,7 @@ def launch( *, sourceInitFile=False, disconnectAutomatically=True, - sourceBreakpoints=None, - functionBreakpoints=None, expectFailure=False, - stopOnEntry=True, - timeout=DEFAULT_TIMEOUT, **kwargs, ): """Sending launch request to dap""" @@ -437,35 +405,7 @@ def cleanup(): # Initialize and launch the program self.dap_server.request_initialize(sourceInitFile) - self.dap_server.wait_for_event("initialized", timeout) - - # Set source breakpoints as part of the launch sequence. - if sourceBreakpoints: - for source_path, lines in sourceBreakpoints: - response = self.dap_server.request_setBreakpoints(source_path, lines) - self.assertTrue( - response["success"], - "setBreakpoints failed (%s)" % (response), - ) - - # Set function breakpoints as part of the launch sequence. - if functionBreakpoints: - response = self.dap_server.request_setFunctionBreakpoints( - functionBreakpoints - ) - self.assertTrue( - response["success"], - "setFunctionBreakpoint failed (%s)" % (response), - ) - - self.dap_server.request_configurationDone() - - response = self.dap_server.request_launch( - program, - stopOnEntry=stopOnEntry, - **kwargs, - ) - + response = self.dap_server.request_launch(program, **kwargs) if expectFailure: return response if not (response and response["success"]): @@ -473,10 +413,6 @@ def cleanup(): response["success"], "launch failed (%s)" % (response["body"]["error"]["format"]), ) - if stopOnEntry: - self.dap_server.wait_for_stopped(timeout) - - return response def build_and_launch( self, diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py index 25f031db5cac5..d46fc31d797da 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py @@ -52,7 +52,7 @@ def test_breakpoint_events(self): # breakpoint events for these breakpoints but not for ones that are not # set via the command interpreter. bp_command = "breakpoint set --file foo.cpp --line %u" % (foo_bp2_line) - self.build_and_launch(program, stopOnEntry=True, preRunCommands=[bp_command]) + self.build_and_launch(program, preRunCommands=[bp_command]) main_bp_id = 0 foo_bp_id = 0 # Set breakpoints and verify that they got set correctly diff --git a/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py b/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py index 948c146d4da68..824ed8fe3bb97 100644 --- a/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py +++ b/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py @@ -44,7 +44,7 @@ def test_pending_request(self): Tests cancelling a pending request. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) # Use a relatively short timeout since this is only to ensure the # following request is queued. @@ -76,7 +76,7 @@ def test_inflight_request(self): Tests cancelling an inflight request. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) blocking_seq = self.async_blocking_request(duration=self.DEFAULT_TIMEOUT / 2) # Wait for the sleep to start to cancel the inflight request. diff --git a/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py b/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py index 75876c248f86c..04897acfcf85d 100644 --- a/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py +++ b/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py @@ -46,17 +46,12 @@ def verify_completions(self, actual_list, expected_list, not_expected_list=[]): def setup_debuggee(self): program = self.getBuildArtifact("a.out") source = "main.cpp" - self.build_and_launch( - program, - stopOnEntry=True, - sourceBreakpoints=[ - ( - source, - [ - line_number(source, "// breakpoint 1"), - line_number(source, "// breakpoint 2"), - ], - ), + self.build_and_launch(program) + self.set_source_breakpoints( + source, + [ + line_number(source, "// breakpoint 1"), + line_number(source, "// breakpoint 2"), ], ) diff --git a/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py b/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py index 1f810afdbb667..7b4d1adbb2071 100644 --- a/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py +++ b/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py @@ -53,7 +53,7 @@ def test_scopes_variables_setVariable_evaluate(self): character. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") lines = [breakpoint1_line] @@ -66,6 +66,7 @@ def test_scopes_variables_setVariable_evaluate(self): # Cause a "scopes" to be sent for frame zero which should update the # selected thread and frame to frame 0. self.dap_server.get_local_variables(frameIndex=0) + # Verify frame #0 is selected in the command interpreter by running # the "frame select" command with no frame index which will print the # currently selected frame. @@ -74,15 +75,15 @@ def test_scopes_variables_setVariable_evaluate(self): # Cause a "scopes" to be sent for frame one which should update the # selected thread and frame to frame 1. self.dap_server.get_local_variables(frameIndex=1) + # Verify frame #1 is selected in the command interpreter by running # the "frame select" command with no frame index which will print the # currently selected frame. - self.check_lldb_command("frame select", "frame #1", "frame 1 is selected") def test_custom_escape_prefix(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="::") + self.build_and_launch(program, commandEscapePrefix="::") source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line]) @@ -97,7 +98,7 @@ def test_custom_escape_prefix(self): def test_empty_escape_prefix(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="") + self.build_and_launch(program, commandEscapePrefix="") source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line]) @@ -114,7 +115,7 @@ def test_empty_escape_prefix(self): def test_exit_status_message_sigterm(self): source = "main.cpp" program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="") + self.build_and_launch(program, commandEscapePrefix="") breakpoint1_line = line_number(source, "// breakpoint 1") breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line]) self.continue_to_breakpoints(breakpoint_ids) @@ -168,7 +169,7 @@ def test_exit_status_message_ok(self): def test_diagnositcs(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) core = self.getBuildArtifact("minidump.core") self.yaml2obj("minidump.yaml", core) diff --git a/lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py b/lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py index 23500bd6fe586..e367c327d4295 100644 --- a/lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py +++ b/lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py @@ -16,9 +16,7 @@ def test(self): """ program = self.getBuildArtifact("a.out") self.build_and_launch( - program, - stopOnEntry=True, - lldbDAPEnv={"LLDB_DAP_TEST_STDOUT_STDERR_REDIRECTION": ""}, + program, lldbDAPEnv={"LLDB_DAP_TEST_STDOUT_STDERR_REDIRECTION": ""} ) source = "main.cpp" diff --git a/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py b/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py index e678c5ee77fdc..db43dbaf515cf 100644 --- a/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py +++ b/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py @@ -19,6 +19,7 @@ def test_core_file(self): self.create_debug_adapter() self.attach(program=exe_file, coreFile=core_file) + self.dap_server.request_configurationDone() expected_frames = [ { diff --git a/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py b/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py index 372a9bb75e007..2166e88151986 100644 --- a/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py +++ b/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py @@ -43,7 +43,6 @@ def run_test_evaluate_expressions( self.build_and_launch( program, enableAutoVariableSummaries=enableAutoVariableSummaries, - stopOnEntry=True, ) source = "main.cpp" self.set_source_breakpoints( diff --git a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py index 0063954791fd5..8805ce50e6a21 100644 --- a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py +++ b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py @@ -87,7 +87,8 @@ def test_stopOnEntry(self): """ program = self.getBuildArtifact("a.out") self.build_and_launch(program, stopOnEntry=True) - + self.dap_server.request_configurationDone() + self.dap_server.wait_for_stopped() self.assertTrue( len(self.dap_server.thread_stop_reasons) > 0, "expected stopped event during launch", @@ -357,7 +358,6 @@ def test_commands(self): terminateCommands = ["expr 4+2"] self.build_and_launch( program, - stopOnEntry=True, initCommands=initCommands, preRunCommands=preRunCommands, postRunCommands=postRunCommands, diff --git a/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py b/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py index 19de35b60a3ef..1ef2f2a8235a4 100644 --- a/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py +++ b/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py @@ -10,7 +10,7 @@ class TestDAP_module_event(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_module_event(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") diff --git a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py index b333efd7bfb1f..3fc0f752ee39e 100644 --- a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py +++ b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py @@ -14,7 +14,7 @@ class TestDAP_module(lldbdap_testcase.DAPTestCaseBase): def run_test(self, symbol_basename, expect_debug_info_size): program_basename = "a.out.stripped" program = self.getBuildArtifact(program_basename) - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) functions = ["foo"] breakpoint_ids = self.set_function_breakpoints(functions) self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint") @@ -108,7 +108,7 @@ def test_modules_dsym(self): @skipIfWindows def test_compile_units(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.cpp" main_source_path = self.getSourcePath(source) breakpoint1_line = line_number(source, "// breakpoint 1") diff --git a/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py b/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py index 81edcdf4bd0f9..c6f59949d668e 100644 --- a/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py +++ b/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py @@ -20,7 +20,7 @@ def assertEvaluate(self, expression, regex): def test_completions(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.cpp" breakpoint1_line = line_number(source, "// breakpoint 1") diff --git a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py index 8681b31e8eb1b..83faf276852f8 100644 --- a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py +++ b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py @@ -35,7 +35,7 @@ def test_basic_functionality(self): # Restart then check we stop back at A and program state has been reset. resp = self.dap_server.request_restart() self.assertTrue(resp["success"]) - self.continue_to_breakpoints([bp_A]) + self.verify_breakpoint_hit([bp_A]) self.assertEqual( int(self.dap_server.get_local_variable_value("i")), 0, @@ -50,6 +50,9 @@ def test_stopOnEntry(self): program = self.getBuildArtifact("a.out") self.build_and_launch(program, stopOnEntry=True) [bp_main] = self.set_function_breakpoints(["main"]) + + self.dap_server.request_configurationDone() + self.dap_server.wait_for_stopped() # Once the "configuration done" event is sent, we should get a stopped # event immediately because of stopOnEntry. self.assertTrue( diff --git a/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py b/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py index 3e015186d4b81..a01845669666f 100644 --- a/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py +++ b/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py @@ -24,7 +24,6 @@ def test_send_event(self): } self.build_and_launch( program, - sourceBreakpoints=[(source, [breakpoint_line])], stopCommands=[ "lldb-dap send-event my-custom-event-no-body", "lldb-dap send-event my-custom-event '{}'".format( @@ -32,6 +31,8 @@ def test_send_event(self): ), ], ) + self.set_source_breakpoints(source, [breakpoint_line]) + self.continue_to_next_stop() custom_event = self.dap_server.wait_for_event( filter=["my-custom-event-no-body"] diff --git a/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py b/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py index 9c6f1d42feda2..abd469274ffd4 100644 --- a/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py +++ b/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py @@ -61,7 +61,7 @@ def test_stackTrace(self): Tests the 'stackTrace' packet and all its variants. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) source = "main.c" self.source_path = os.path.join(os.getcwd(), source) self.recurse_end = line_number(source, "recurse end") diff --git a/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py b/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py index 963d711978534..08c225b3cada4 100644 --- a/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py +++ b/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py @@ -37,7 +37,7 @@ def build_and_run_until_breakpoint(self): breakpoint_line = line_number(other_source_file, "// Break here") program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="") + self.build_and_launch(program, commandEscapePrefix="") breakpoint_ids = self.set_source_breakpoints( other_source_file, [breakpoint_line] diff --git a/lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py b/lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py index e37cd36d7f283..b487257b6414d 100644 --- a/lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py +++ b/lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py @@ -15,7 +15,7 @@ def test_startDebugging(self): """ program = self.getBuildArtifact("a.out") source = "main.c" - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) breakpoint_line = line_number(source, "// breakpoint") diff --git a/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py b/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py index 33e038408fa34..d630e1d14c3a0 100644 --- a/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py +++ b/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py @@ -15,7 +15,7 @@ def test_stop_hooks_before_run(self): """ program = self.getBuildArtifact("a.out") preRunCommands = ["target stop-hook add -o help"] - self.build_and_launch(program, stopOnEntry=True, preRunCommands=preRunCommands) + self.build_and_launch(program, preRunCommands=preRunCommands) breakpoint_ids = self.set_function_breakpoints(["main"]) # This request hangs if the race happens, because, in that case, the # command interpreter is in synchronous mode while lldb-dap expects diff --git a/lldb/test/API/tools/lldb-dap/threads/TestDAP_threads.py b/lldb/test/API/tools/lldb-dap/threads/TestDAP_threads.py index 6edb4b8e2a816..a4658da58ac94 100644 --- a/lldb/test/API/tools/lldb-dap/threads/TestDAP_threads.py +++ b/lldb/test/API/tools/lldb-dap/threads/TestDAP_threads.py @@ -50,7 +50,9 @@ def test_thread_format(self): """ program = self.getBuildArtifact("a.out") self.build_and_launch( - program, customThreadFormat="This is thread index #${thread.index}" + program, + customThreadFormat="This is thread index #${thread.index}", + stopCommands=["thread list"], ) source = "main.c" breakpoint_line = line_number(source, "// break here") @@ -63,5 +65,6 @@ def test_thread_format(self): self.continue_to_breakpoints(breakpoint_ids) # We are stopped at the second thread threads = self.dap_server.get_threads() + print("got thread", threads) self.assertEqual(threads[0]["name"], "This is thread index #1") self.assertEqual(threads[1]["name"], "This is thread index #2") diff --git a/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py b/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py index eb09649f387d7..75e75c4ad7c69 100644 --- a/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py +++ b/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py @@ -13,14 +13,11 @@ def test_get_num_children(self): program = self.getBuildArtifact("a.out") self.build_and_launch( program, - stopOnEntry=True, preRunCommands=[ "command script import '%s'" % self.getSourcePath("formatter.py") ], ) source = "main.cpp" - breakpoint1_line = line_number(source, "// break here") - breakpoint_ids = self.set_source_breakpoints( source, [line_number(source, "// break here")] ) @@ -47,7 +44,7 @@ def test_return_variable_with_children(self): Test the stepping out of a function with return value show the children correctly """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program, stopOnEntry=True) + self.build_and_launch(program) function_name = "test_return_variable_with_children" breakpoint_ids = self.set_function_breakpoints([function_name]) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 56a0c38b00037..0d5eba6c40961 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -916,20 +916,10 @@ llvm::Error DAP::Loop() { return errWrapper; } - // The launch sequence is special and we need to carefully handle - // packets in the right order. Until we've handled configurationDone, - bool add_to_pending_queue = false; - if (const protocol::Request *req = - std::get_if(&*next)) { - llvm::StringRef command = req->command; - if (command == "disconnect") - disconnecting = true; - if (!configuration_done) - add_to_pending_queue = - command != "initialize" && command != "configurationDone" && - command != "disconnect" && !command.ends_with("Breakpoints"); - } + std::get_if(&*next); + req && req->arguments == "disconnect") + disconnecting = true; const std::optional cancel_args = getArgumentsIfRequest(*next, "cancel"); @@ -956,8 +946,7 @@ llvm::Error DAP::Loop() { { std::lock_guard guard(m_queue_mutex); - auto &queue = add_to_pending_queue ? m_pending_queue : m_queue; - queue.push_back(std::move(*next)); + m_queue.push_back(std::move(*next)); } m_queue_cv.notify_one(); } @@ -1255,16 +1244,6 @@ void DAP::SetConfiguration(const protocol::Configuration &config, SetThreadFormat(*configuration.customThreadFormat); } -void DAP::SetConfigurationDone() { - { - std::lock_guard guard(m_queue_mutex); - std::copy(m_pending_queue.begin(), m_pending_queue.end(), - std::front_inserter(m_queue)); - configuration_done = true; - } - m_queue_cv.notify_all(); -} - void DAP::SetFrameFormat(llvm::StringRef format) { lldb::SBError error; frame_format = lldb::SBFormat(format.str().c_str(), error); diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c1a1130b1e59f..8f24c6cf82924 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -444,7 +444,6 @@ struct DAP { /// Queue for all incoming messages. std::deque m_queue; - std::deque m_pending_queue; std::mutex m_queue_mutex; std::condition_variable m_queue_cv; diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp index 0293ffbd0c922..371349a26866e 100644 --- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp @@ -140,24 +140,7 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { } void AttachRequestHandler::PostRun() const { - if (!dap.target.GetProcess().IsValid()) - return; - - // Clients can request a baseline of currently existing threads after - // we acknowledge the configurationDone request. - // Client requests the baseline of currently existing threads after - // a successful or attach by sending a 'threads' request - // right after receiving the configurationDone response. - // Obtain the list of threads before we resume the process - dap.initial_thread_list = - GetThreads(dap.target.GetProcess(), dap.thread_format); - - SendProcessEvent(dap, Attach); - - if (dap.stop_at_entry) - SendThreadStoppedEvent(dap); - else - dap.target.GetProcess().Continue(); + dap.SendJSON(CreateEventObject("initialized")); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp index 802c28d7b8904..1281857ef4b60 100644 --- a/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp @@ -9,49 +9,53 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" +#include "lldb/API/SBDebugger.h" + +using namespace llvm; +using namespace lldb_dap::protocol; namespace lldb_dap { -// "ConfigurationDoneRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "ConfigurationDone request; value of command field -// is 'configurationDone'.\nThe client of the debug protocol must -// send this request at the end of the sequence of configuration -// requests (which was started by the InitializedEvent).", -// "properties": { -// "command": { -// "type": "string", -// "enum": [ "configurationDone" ] -// }, -// "arguments": { -// "$ref": "#/definitions/ConfigurationDoneArguments" -// } -// }, -// "required": [ "command" ] -// }] -// }, -// "ConfigurationDoneArguments": { -// "type": "object", -// "description": "Arguments for 'configurationDone' request.\nThe -// configurationDone request has no standardized attributes." -// }, -// "ConfigurationDoneResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to 'configurationDone' request. This is -// just an acknowledgement, so no body field is required." -// }] -// }, - -void ConfigurationDoneRequestHandler::operator()( - const llvm::json::Object &request) const { - dap.SetConfigurationDone(); - - llvm::json::Object response; - FillResponse(request, response); - dap.SendJSON(llvm::json::Value(std::move(response))); +/// This request indicates that the client has finished initialization of the +/// debug adapter. +/// +/// So it is the last request in the sequence of configuration requests (which +/// was started by the `initialized` event). +/// +/// Clients should only call this request if the corresponding capability +/// `supportsConfigurationDoneRequest` is true. +llvm::Error +ConfigurationDoneRequestHandler::Run(const ConfigurationDoneArguments &) const { + dap.configuration_done = true; + + // Ensure any command scripts did not leave us in an unexpected state. + lldb::SBProcess process = dap.target.GetProcess(); + if (!process.IsValid() || + !lldb::SBDebugger::StateIsStoppedState(process.GetState())) + return make_error( + "Expected process to be stopped.\r\n\r\nProcess is in an unexpected " + "state and may have missed an initial configuration. Please check that " + "any debugger command scripts are not resuming the process during the " + "launch sequence."); + + // Clients can request a baseline of currently existing threads after + // we acknowledge the configurationDone request. + // Client requests the baseline of currently existing threads after + // a successful or attach by sending a 'threads' request + // right after receiving the configurationDone response. + // Obtain the list of threads before we resume the process + dap.initial_thread_list = GetThreads(process, dap.thread_format); + + SendProcessEvent(dap, dap.is_attach ? Attach : Launch); + + if (dap.stop_at_entry) + SendThreadStoppedEvent(dap); + else + process.Continue(); + + return Error::success(); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp index b64987746b3d5..0a178406b5a69 100644 --- a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp @@ -78,7 +78,3 @@ llvm::Expected InitializeRequestHandler::Run( return dap.GetCapabilities(); } - -void InitializeRequestHandler::PostRun() const { - dap.SendJSON(CreateEventObject("initialized")); -} diff --git a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp index 22d1a090187d8..1d7b4b7009462 100644 --- a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp @@ -67,25 +67,7 @@ Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const { } void LaunchRequestHandler::PostRun() const { - if (!dap.target.GetProcess().IsValid()) - return; - - // Clients can request a baseline of currently existing threads after - // we acknowledge the configurationDone request. - // Client requests the baseline of currently existing threads after - // a successful or attach by sending a 'threads' request - // right after receiving the configurationDone response. - // Obtain the list of threads before we resume the process - dap.initial_thread_list = - GetThreads(dap.target.GetProcess(), dap.thread_format); - - // Attach happens when launching with runInTerminal. - SendProcessEvent(dap, dap.is_attach ? Attach : Launch); - - if (dap.stop_at_entry) - SendThreadStoppedEvent(dap); - else - dap.target.GetProcess().Continue(); + dap.SendJSON(CreateEventObject("initialized")); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 383f9e24a729a..e6bccfe12f402 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -21,6 +21,7 @@ #include "llvm/Support/JSON.h" #include #include +#include template struct is_optional : std::false_type {}; @@ -87,6 +88,34 @@ class LegacyRequestHandler : public BaseRequestHandler { } }; +template +llvm::Expected parseArgs(const protocol::Request &request) { + if (!is_optional_v && !request.arguments) + return llvm::make_error( + llvm::formatv("arguments required for command '{0}' " + "but none received", + request.command) + .str()); + + Args arguments; + llvm::json::Path::Root root("arguments"); + if (request.arguments && !fromJSON(*request.arguments, arguments, root)) { + std::string parse_failure; + llvm::raw_string_ostream OS(parse_failure); + OS << "invalid arguments for request '" << request.command + << "': " << llvm::toString(root.getError()) << "\n"; + root.printErrorContext(*request.arguments, OS); + return llvm::make_error(parse_failure); + } + + return arguments; +} +template <> +inline llvm::Expected +parseArgs(const protocol::Request &request) { + return std::nullopt; +} + /// Base class for handling DAP requests. Handlers should declare their /// arguments and response body types like: /// @@ -102,42 +131,21 @@ class RequestHandler : public BaseRequestHandler { response.request_seq = request.seq; response.command = request.command; - if (!is_optional_v && !request.arguments) { - DAP_LOG(dap.log, - "({0}) malformed request {1}, expected arguments but got none", - dap.transport.GetClientName(), request.command); - HandleErrorResponse( - llvm::make_error( - llvm::formatv("arguments required for command '{0}' " - "but none received", - request.command) - .str()), - response); - dap.Send(response); - return; - } - - Args arguments; - llvm::json::Path::Root root("arguments"); - if (request.arguments && !fromJSON(*request.arguments, arguments, root)) { - std::string parse_failure; - llvm::raw_string_ostream OS(parse_failure); - OS << "invalid arguments for request '" << request.command - << "': " << llvm::toString(root.getError()) << "\n"; - root.printErrorContext(*request.arguments, OS); - HandleErrorResponse(llvm::make_error(parse_failure), response); + llvm::Expected arguments = parseArgs(request); + if (llvm::Error err = arguments.takeError()) { + HandleErrorResponse(std::move(err), response); dap.Send(response); return; } if constexpr (std::is_same_v) { - if (llvm::Error err = Run(arguments)) { + if (llvm::Error err = Run(*arguments)) { HandleErrorResponse(std::move(err), response); } else { response.success = true; } } else { - Resp body = Run(arguments); + Resp body = Run(*arguments); if (llvm::Error err = body.takeError()) { HandleErrorResponse(std::move(err), response); } else { @@ -246,14 +254,17 @@ class ContinueRequestHandler Run(const protocol::ContinueArguments &args) const override; }; -class ConfigurationDoneRequestHandler : public LegacyRequestHandler { +class ConfigurationDoneRequestHandler + : public RequestHandler { public: - using LegacyRequestHandler::LegacyRequestHandler; + using RequestHandler::RequestHandler; static llvm::StringLiteral GetCommand() { return "configurationDone"; } FeatureSet GetSupportedFeatures() const override { return {protocol::eAdapterFeatureConfigurationDoneRequest}; } - void operator()(const llvm::json::Object &request) const override; + protocol::ConfigurationDoneResponse + Run(const protocol::ConfigurationDoneArguments &) const override; }; class DisconnectRequestHandler @@ -297,7 +308,6 @@ class InitializeRequestHandler static llvm::StringLiteral GetCommand() { return "initialize"; } llvm::Expected Run(const protocol::InitializeRequestArguments &args) const override; - void PostRun() const override; }; class LaunchRequestHandler diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h index bad0e886d94d2..1cb9cb13dd0da 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h @@ -148,6 +148,9 @@ struct ErrorResponseBody { }; llvm::json::Value toJSON(const ErrorResponseBody &); +/// This is a placehold for requests with an empty, null or undefined arguments. +using EmptyArguments = std::optional; + /// This is just an acknowledgement, so no body field is required. using VoidResponse = llvm::Error; diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index 4e08b4728453b..b421c631344de 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -370,6 +370,13 @@ struct ContinueResponseBody { }; llvm::json::Value toJSON(const ContinueResponseBody &); +/// Arguments for `configurationDone` request. +using ConfigurationDoneArguments = EmptyArguments; + +/// Response to `configurationDone` request. This is just an acknowledgement, so +/// no body field is required. +using ConfigurationDoneResponse = VoidResponse; + /// Arguments for `setVariable` request. struct SetVariableArguments { /// The reference of the variable container. The `variablesReference` must From lldb-commits at lists.llvm.org Fri May 16 19:28:40 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Fri, 16 May 2025 19:28:40 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Take two at refactoring the startup sequence. (PR #140331) In-Reply-To: Message-ID: <6827f458.170a0220.177fd1.690d@mx.google.com> https://github.com/ashgti closed https://github.com/llvm/llvm-project/pull/140331 From lldb-commits at lists.llvm.org Fri May 16 20:02:16 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 20:02:16 -0700 (PDT) Subject: [Lldb-commits] [lldb] dfac044 - [lldb-dap] Avoid creating temporary instances of std::string (NFC) (#140325) Message-ID: <6827fc38.050a0220.1ccc17.80d3@mx.google.com> Author: Kazu Hirata Date: 2025-05-16T20:02:13-07:00 New Revision: dfac0445d0813abe2260ffdc9eeb23671cefd812 URL: https://github.com/llvm/llvm-project/commit/dfac0445d0813abe2260ffdc9eeb23671cefd812 DIFF: https://github.com/llvm/llvm-project/commit/dfac0445d0813abe2260ffdc9eeb23671cefd812.diff LOG: [lldb-dap] Avoid creating temporary instances of std::string (NFC) (#140325) EmplaceSafeString accepts StringRef for the last parameter, str, and then internally creates a copy of str via StringRef::str or llvm::json::fixUTF8, so caller do not need to create their own temporary instances of std::string. Added: Modified: lldb/tools/lldb-dap/EventHelper.cpp lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp lldb/tools/lldb-dap/JSONUtils.cpp Removed: ################################################################################ diff --git a/lldb/tools/lldb-dap/EventHelper.cpp b/lldb/tools/lldb-dap/EventHelper.cpp index ed2d8700c26b0..c698084836e2f 100644 --- a/lldb/tools/lldb-dap/EventHelper.cpp +++ b/lldb/tools/lldb-dap/EventHelper.cpp @@ -93,7 +93,7 @@ void SendProcessEvent(DAP &dap, LaunchMethod launch_method) { exe_fspec.GetPath(exe_path, sizeof(exe_path)); llvm::json::Object event(CreateEventObject("process")); llvm::json::Object body; - EmplaceSafeString(body, "name", std::string(exe_path)); + EmplaceSafeString(body, "name", exe_path); const auto pid = dap.target.GetProcess().GetProcessID(); body.try_emplace("systemProcessId", (int64_t)pid); body.try_emplace("isLocalProcess", true); diff --git a/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp index 5ce133c33b7e1..e1556846dff19 100644 --- a/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp @@ -205,7 +205,7 @@ void EvaluateRequestHandler::operator()( lldb::SBError error = value.GetError(); const char *error_cstr = error.GetCString(); if (error_cstr && error_cstr[0]) - EmplaceSafeString(response, "message", std::string(error_cstr)); + EmplaceSafeString(response, "message", error_cstr); else EmplaceSafeString(response, "message", "evaluate failed"); } else { diff --git a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp index 924ea63ed1593..c1c2adb32a510 100644 --- a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp @@ -136,7 +136,7 @@ void ExceptionInfoRequestHandler::operator()( if (!ObjectContainsKey(body, "description")) { char description[1024]; if (thread.GetStopDescription(description, sizeof(description))) { - EmplaceSafeString(body, "description", std::string(description)); + EmplaceSafeString(body, "description", description); } } body.try_emplace("breakMode", "always"); diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index a8bd672583a5d..714947a4d3b9c 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -905,7 +905,7 @@ llvm::json::Value CreateThreadStopped(DAP &dap, lldb::SBThread &thread, if (!ObjectContainsKey(body, "description")) { char description[1024]; if (thread.GetStopDescription(description, sizeof(description))) { - EmplaceSafeString(body, "description", std::string(description)); + EmplaceSafeString(body, "description", description); } } // "threadCausedFocus" is used in tests to validate breaking behavior. From lldb-commits at lists.llvm.org Fri May 16 20:02:19 2025 From: lldb-commits at lists.llvm.org (Kazu Hirata via lldb-commits) Date: Fri, 16 May 2025 20:02:19 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Avoid creating temporary instances of std::string (NFC) (PR #140325) In-Reply-To: Message-ID: <6827fc3b.a70a0220.34a194.71dc@mx.google.com> https://github.com/kazutakahirata closed https://github.com/llvm/llvm-project/pull/140325 From lldb-commits at lists.llvm.org Fri May 16 20:31:02 2025 From: lldb-commits at lists.llvm.org (Kazu Hirata via lldb-commits) Date: Fri, 16 May 2025 20:31:02 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use llvm::replace (NFC) (PR #140343) Message-ID: https://github.com/kazutakahirata created https://github.com/llvm/llvm-project/pull/140343 None >From e0f9312651d1e884547bf44b44dd2c6b8ff09ff6 Mon Sep 17 00:00:00 2001 From: Kazu Hirata Date: Fri, 16 May 2025 20:07:05 -0700 Subject: [PATCH] [lldb] Use llvm::replace (NFC) --- lldb/source/Interpreter/CommandInterpreter.cpp | 4 ++-- .../ExpressionParser/Clang/ClangExpressionSourceCode.cpp | 4 ++-- lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp | 9 +++------ lldb/source/Utility/FileSpec.cpp | 4 ++-- lldb/utils/TableGen/LLDBOptionDefEmitter.cpp | 2 +- lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp | 4 ++-- 6 files changed, 12 insertions(+), 15 deletions(-) diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index eb4741feb0aa5..34749d890bf03 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -3346,9 +3346,9 @@ bool CommandInterpreter::SaveTranscript( CommandReturnObject &result, std::optional output_file) { if (output_file == std::nullopt || output_file->empty()) { std::string now = llvm::to_string(std::chrono::system_clock::now()); - std::replace(now.begin(), now.end(), ' ', '_'); + llvm::replace(now, ' ', '_'); // Can't have file name with colons on Windows - std::replace(now.begin(), now.end(), ':', '-'); + llvm::replace(now, ':', '-'); const std::string file_name = "lldb_session_" + now + ".log"; FileSpec save_location = GetSaveSessionDirectory(); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp index 3b601726388d6..1feeeb64aa9e5 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp @@ -251,8 +251,8 @@ TokenVerifier::TokenVerifier(std::string body) { // We only care about tokens and not their original source locations. If we // move the whole expression to only be in one line we can simplify the // following code that extracts the token contents. - std::replace(body.begin(), body.end(), '\n', ' '); - std::replace(body.begin(), body.end(), '\r', ' '); + llvm::replace(body, '\n', ' '); + llvm::replace(body, '\r', ' '); FileSystemOptions file_opts; FileManager file_mgr(file_opts, diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index 3c3a0aa992d9c..262a7dc731713 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -237,12 +237,9 @@ FileSpecList PlatformDarwin::LocateExecutableScriptingResources( // ScriptInterpreter. For now, we just replace dots with // underscores, but if we ever support anything other than // Python we will need to rework this - std::replace(module_basename.begin(), module_basename.end(), '.', - '_'); - std::replace(module_basename.begin(), module_basename.end(), ' ', - '_'); - std::replace(module_basename.begin(), module_basename.end(), '-', - '_'); + llvm::replace(module_basename, '.', '_'); + llvm::replace(module_basename, ' ', '_'); + llvm::replace(module_basename, '-', '_'); ScriptInterpreter *script_interpreter = target->GetDebugger().GetScriptInterpreter(); if (script_interpreter && diff --git a/lldb/source/Utility/FileSpec.cpp b/lldb/source/Utility/FileSpec.cpp index bb2b8647342b8..69d921643da2a 100644 --- a/lldb/source/Utility/FileSpec.cpp +++ b/lldb/source/Utility/FileSpec.cpp @@ -60,7 +60,7 @@ void Denormalize(llvm::SmallVectorImpl &path, FileSpec::Style style) { if (PathStyleIsPosix(style)) return; - std::replace(path.begin(), path.end(), '/', '\\'); + llvm::replace(path, '/', '\\'); } } // end anonymous namespace @@ -186,7 +186,7 @@ void FileSpec::SetFile(llvm::StringRef pathname, Style style) { // Normalize back slashes to forward slashes if (m_style == Style::windows) - std::replace(resolved.begin(), resolved.end(), '\\', '/'); + llvm::replace(resolved, '\\', '/'); if (resolved.empty()) { // If we have no path after normalization set the path to the current diff --git a/lldb/utils/TableGen/LLDBOptionDefEmitter.cpp b/lldb/utils/TableGen/LLDBOptionDefEmitter.cpp index 735489c0e56a4..2507910d8a97a 100644 --- a/lldb/utils/TableGen/LLDBOptionDefEmitter.cpp +++ b/lldb/utils/TableGen/LLDBOptionDefEmitter.cpp @@ -150,7 +150,7 @@ static void emitOptions(std::string Command, ArrayRef Records, std::vector Options(Records.begin(), Records.end()); std::string ID = Command; - std::replace(ID.begin(), ID.end(), ' ', '_'); + llvm::replace(ID, ' ', '_'); // Generate the macro that the user needs to define before including the // *.inc file. std::string NeededMacro = "LLDB_OPTIONS_" + ID; diff --git a/lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp b/lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp index 8df87fda9f775..1d4495f9281b2 100644 --- a/lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp +++ b/lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp @@ -131,7 +131,7 @@ static void emityProperties(std::string PropertyName, // Generate the macro that the user needs to define before including the // *.inc file. std::string NeededMacro = "LLDB_PROPERTIES_" + PropertyName; - std::replace(NeededMacro.begin(), NeededMacro.end(), ' ', '_'); + llvm::replace(NeededMacro, ' ', '_'); // All options are in one file, so we need put them behind macros and ask the // user to define the macro for the options that are needed. @@ -154,7 +154,7 @@ static void emitPropertyEnum(std::string PropertyName, // Generate the macro that the user needs to define before including the // *.inc file. std::string NeededMacro = "LLDB_PROPERTIES_" + PropertyName; - std::replace(NeededMacro.begin(), NeededMacro.end(), ' ', '_'); + llvm::replace(NeededMacro, ' ', '_'); // All options are in one file, so we need put them behind macros and ask the // user to define the macro for the options that are needed. From lldb-commits at lists.llvm.org Fri May 16 20:31:33 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Fri, 16 May 2025 20:31:33 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use llvm::replace (NFC) (PR #140343) In-Reply-To: Message-ID: <68280315.170a0220.297121.3247@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Kazu Hirata (kazutakahirata)
Changes --- Full diff: https://github.com/llvm/llvm-project/pull/140343.diff 6 Files Affected: - (modified) lldb/source/Interpreter/CommandInterpreter.cpp (+2-2) - (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp (+2-2) - (modified) lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp (+3-6) - (modified) lldb/source/Utility/FileSpec.cpp (+2-2) - (modified) lldb/utils/TableGen/LLDBOptionDefEmitter.cpp (+1-1) - (modified) lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp (+2-2) ``````````diff diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index eb4741feb0aa5..34749d890bf03 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -3346,9 +3346,9 @@ bool CommandInterpreter::SaveTranscript( CommandReturnObject &result, std::optional output_file) { if (output_file == std::nullopt || output_file->empty()) { std::string now = llvm::to_string(std::chrono::system_clock::now()); - std::replace(now.begin(), now.end(), ' ', '_'); + llvm::replace(now, ' ', '_'); // Can't have file name with colons on Windows - std::replace(now.begin(), now.end(), ':', '-'); + llvm::replace(now, ':', '-'); const std::string file_name = "lldb_session_" + now + ".log"; FileSpec save_location = GetSaveSessionDirectory(); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp index 3b601726388d6..1feeeb64aa9e5 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp @@ -251,8 +251,8 @@ TokenVerifier::TokenVerifier(std::string body) { // We only care about tokens and not their original source locations. If we // move the whole expression to only be in one line we can simplify the // following code that extracts the token contents. - std::replace(body.begin(), body.end(), '\n', ' '); - std::replace(body.begin(), body.end(), '\r', ' '); + llvm::replace(body, '\n', ' '); + llvm::replace(body, '\r', ' '); FileSystemOptions file_opts; FileManager file_mgr(file_opts, diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index 3c3a0aa992d9c..262a7dc731713 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -237,12 +237,9 @@ FileSpecList PlatformDarwin::LocateExecutableScriptingResources( // ScriptInterpreter. For now, we just replace dots with // underscores, but if we ever support anything other than // Python we will need to rework this - std::replace(module_basename.begin(), module_basename.end(), '.', - '_'); - std::replace(module_basename.begin(), module_basename.end(), ' ', - '_'); - std::replace(module_basename.begin(), module_basename.end(), '-', - '_'); + llvm::replace(module_basename, '.', '_'); + llvm::replace(module_basename, ' ', '_'); + llvm::replace(module_basename, '-', '_'); ScriptInterpreter *script_interpreter = target->GetDebugger().GetScriptInterpreter(); if (script_interpreter && diff --git a/lldb/source/Utility/FileSpec.cpp b/lldb/source/Utility/FileSpec.cpp index bb2b8647342b8..69d921643da2a 100644 --- a/lldb/source/Utility/FileSpec.cpp +++ b/lldb/source/Utility/FileSpec.cpp @@ -60,7 +60,7 @@ void Denormalize(llvm::SmallVectorImpl &path, FileSpec::Style style) { if (PathStyleIsPosix(style)) return; - std::replace(path.begin(), path.end(), '/', '\\'); + llvm::replace(path, '/', '\\'); } } // end anonymous namespace @@ -186,7 +186,7 @@ void FileSpec::SetFile(llvm::StringRef pathname, Style style) { // Normalize back slashes to forward slashes if (m_style == Style::windows) - std::replace(resolved.begin(), resolved.end(), '\\', '/'); + llvm::replace(resolved, '\\', '/'); if (resolved.empty()) { // If we have no path after normalization set the path to the current diff --git a/lldb/utils/TableGen/LLDBOptionDefEmitter.cpp b/lldb/utils/TableGen/LLDBOptionDefEmitter.cpp index 735489c0e56a4..2507910d8a97a 100644 --- a/lldb/utils/TableGen/LLDBOptionDefEmitter.cpp +++ b/lldb/utils/TableGen/LLDBOptionDefEmitter.cpp @@ -150,7 +150,7 @@ static void emitOptions(std::string Command, ArrayRef Records, std::vector Options(Records.begin(), Records.end()); std::string ID = Command; - std::replace(ID.begin(), ID.end(), ' ', '_'); + llvm::replace(ID, ' ', '_'); // Generate the macro that the user needs to define before including the // *.inc file. std::string NeededMacro = "LLDB_OPTIONS_" + ID; diff --git a/lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp b/lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp index 8df87fda9f775..1d4495f9281b2 100644 --- a/lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp +++ b/lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp @@ -131,7 +131,7 @@ static void emityProperties(std::string PropertyName, // Generate the macro that the user needs to define before including the // *.inc file. std::string NeededMacro = "LLDB_PROPERTIES_" + PropertyName; - std::replace(NeededMacro.begin(), NeededMacro.end(), ' ', '_'); + llvm::replace(NeededMacro, ' ', '_'); // All options are in one file, so we need put them behind macros and ask the // user to define the macro for the options that are needed. @@ -154,7 +154,7 @@ static void emitPropertyEnum(std::string PropertyName, // Generate the macro that the user needs to define before including the // *.inc file. std::string NeededMacro = "LLDB_PROPERTIES_" + PropertyName; - std::replace(NeededMacro.begin(), NeededMacro.end(), ' ', '_'); + llvm::replace(NeededMacro, ' ', '_'); // All options are in one file, so we need put them behind macros and ask the // user to define the macro for the options that are needed. ``````````
https://github.com/llvm/llvm-project/pull/140343 From lldb-commits at lists.llvm.org Sat May 17 07:51:14 2025 From: lldb-commits at lists.llvm.org (Tim Gymnich via lldb-commits) Date: Sat, 17 May 2025 07:51:14 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use llvm::replace (NFC) (PR #140343) In-Reply-To: Message-ID: <6828a262.170a0220.ca4a8.84eb@mx.google.com> https://github.com/tgymnich approved this pull request. https://github.com/llvm/llvm-project/pull/140343 From lldb-commits at lists.llvm.org Sat May 17 09:09:13 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sat, 17 May 2025 09:09:13 -0700 (PDT) Subject: [Lldb-commits] [lldb] 68e4f60 - [lldb] Use llvm::replace (NFC) (#140343) Message-ID: <6828b4a9.050a0220.18cc90.2f31@mx.google.com> Author: Kazu Hirata Date: 2025-05-17T09:09:10-07:00 New Revision: 68e4f6090b369c14da8c6ef1f614664b9e0427e1 URL: https://github.com/llvm/llvm-project/commit/68e4f6090b369c14da8c6ef1f614664b9e0427e1 DIFF: https://github.com/llvm/llvm-project/commit/68e4f6090b369c14da8c6ef1f614664b9e0427e1.diff LOG: [lldb] Use llvm::replace (NFC) (#140343) Added: Modified: lldb/source/Interpreter/CommandInterpreter.cpp lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp lldb/source/Utility/FileSpec.cpp lldb/utils/TableGen/LLDBOptionDefEmitter.cpp lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp Removed: ################################################################################ diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index eb4741feb0aa5..34749d890bf03 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -3346,9 +3346,9 @@ bool CommandInterpreter::SaveTranscript( CommandReturnObject &result, std::optional output_file) { if (output_file == std::nullopt || output_file->empty()) { std::string now = llvm::to_string(std::chrono::system_clock::now()); - std::replace(now.begin(), now.end(), ' ', '_'); + llvm::replace(now, ' ', '_'); // Can't have file name with colons on Windows - std::replace(now.begin(), now.end(), ':', '-'); + llvm::replace(now, ':', '-'); const std::string file_name = "lldb_session_" + now + ".log"; FileSpec save_location = GetSaveSessionDirectory(); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp index 3b601726388d6..1feeeb64aa9e5 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp @@ -251,8 +251,8 @@ TokenVerifier::TokenVerifier(std::string body) { // We only care about tokens and not their original source locations. If we // move the whole expression to only be in one line we can simplify the // following code that extracts the token contents. - std::replace(body.begin(), body.end(), '\n', ' '); - std::replace(body.begin(), body.end(), '\r', ' '); + llvm::replace(body, '\n', ' '); + llvm::replace(body, '\r', ' '); FileSystemOptions file_opts; FileManager file_mgr(file_opts, diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index 3c3a0aa992d9c..262a7dc731713 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -237,12 +237,9 @@ FileSpecList PlatformDarwin::LocateExecutableScriptingResources( // ScriptInterpreter. For now, we just replace dots with // underscores, but if we ever support anything other than // Python we will need to rework this - std::replace(module_basename.begin(), module_basename.end(), '.', - '_'); - std::replace(module_basename.begin(), module_basename.end(), ' ', - '_'); - std::replace(module_basename.begin(), module_basename.end(), '-', - '_'); + llvm::replace(module_basename, '.', '_'); + llvm::replace(module_basename, ' ', '_'); + llvm::replace(module_basename, '-', '_'); ScriptInterpreter *script_interpreter = target->GetDebugger().GetScriptInterpreter(); if (script_interpreter && diff --git a/lldb/source/Utility/FileSpec.cpp b/lldb/source/Utility/FileSpec.cpp index bb2b8647342b8..69d921643da2a 100644 --- a/lldb/source/Utility/FileSpec.cpp +++ b/lldb/source/Utility/FileSpec.cpp @@ -60,7 +60,7 @@ void Denormalize(llvm::SmallVectorImpl &path, FileSpec::Style style) { if (PathStyleIsPosix(style)) return; - std::replace(path.begin(), path.end(), '/', '\\'); + llvm::replace(path, '/', '\\'); } } // end anonymous namespace @@ -186,7 +186,7 @@ void FileSpec::SetFile(llvm::StringRef pathname, Style style) { // Normalize back slashes to forward slashes if (m_style == Style::windows) - std::replace(resolved.begin(), resolved.end(), '\\', '/'); + llvm::replace(resolved, '\\', '/'); if (resolved.empty()) { // If we have no path after normalization set the path to the current diff --git a/lldb/utils/TableGen/LLDBOptionDefEmitter.cpp b/lldb/utils/TableGen/LLDBOptionDefEmitter.cpp index 735489c0e56a4..2507910d8a97a 100644 --- a/lldb/utils/TableGen/LLDBOptionDefEmitter.cpp +++ b/lldb/utils/TableGen/LLDBOptionDefEmitter.cpp @@ -150,7 +150,7 @@ static void emitOptions(std::string Command, ArrayRef Records, std::vector Options(Records.begin(), Records.end()); std::string ID = Command; - std::replace(ID.begin(), ID.end(), ' ', '_'); + llvm::replace(ID, ' ', '_'); // Generate the macro that the user needs to define before including the // *.inc file. std::string NeededMacro = "LLDB_OPTIONS_" + ID; diff --git a/lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp b/lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp index 8df87fda9f775..1d4495f9281b2 100644 --- a/lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp +++ b/lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp @@ -131,7 +131,7 @@ static void emityProperties(std::string PropertyName, // Generate the macro that the user needs to define before including the // *.inc file. std::string NeededMacro = "LLDB_PROPERTIES_" + PropertyName; - std::replace(NeededMacro.begin(), NeededMacro.end(), ' ', '_'); + llvm::replace(NeededMacro, ' ', '_'); // All options are in one file, so we need put them behind macros and ask the // user to define the macro for the options that are needed. @@ -154,7 +154,7 @@ static void emitPropertyEnum(std::string PropertyName, // Generate the macro that the user needs to define before including the // *.inc file. std::string NeededMacro = "LLDB_PROPERTIES_" + PropertyName; - std::replace(NeededMacro.begin(), NeededMacro.end(), ' ', '_'); + llvm::replace(NeededMacro, ' ', '_'); // All options are in one file, so we need put them behind macros and ask the // user to define the macro for the options that are needed. From lldb-commits at lists.llvm.org Sat May 17 09:09:16 2025 From: lldb-commits at lists.llvm.org (Kazu Hirata via lldb-commits) Date: Sat, 17 May 2025 09:09:16 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use llvm::replace (NFC) (PR #140343) In-Reply-To: Message-ID: <6828b4ac.050a0220.138398.910b@mx.google.com> https://github.com/kazutakahirata closed https://github.com/llvm/llvm-project/pull/140343 From lldb-commits at lists.llvm.org Sat May 17 11:20:32 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sat, 17 May 2025 11:20:32 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Member variable cleanup in DAP.{cpp, h} (NFC) (PR #140390) Message-ID: https://github.com/JDevlieghere created https://github.com/llvm/llvm-project/pull/140390 - Use in-class member initialization to simplify the constructor. - Remove unimplemented SetConfigurationDone. - Consistently use Doxygen-style comments. >From c546c86ac849f316cdddd9b31b881e92d8683aa5 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Sat, 17 May 2025 11:17:41 -0700 Subject: [PATCH] [lldb-dap] Member variable cleanup in DAP.{cpp,h} (NFC) - Use in-class member initialization to simplify the constructor. - Remove unimplemented SetConfigurationDone. - Consistently use Doxygen-style comments. --- lldb/tools/lldb-dap/DAP.cpp | 6 +--- lldb/tools/lldb-dap/DAP.h | 60 ++++++++++++++++++++++++------------- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 0d5eba6c40961..d813cdb0b9074 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -118,13 +118,9 @@ llvm::StringRef DAP::debug_adapter_path = ""; DAP::DAP(Log *log, const ReplMode default_repl_mode, std::vector pre_init_commands, Transport &transport) : log(log), transport(transport), broadcaster("lldb-dap"), - exception_breakpoints(), focus_tid(LLDB_INVALID_THREAD_ID), - stop_at_entry(false), is_attach(false), - restarting_process_id(LLDB_INVALID_PROCESS_ID), configuration_done(false), - waiting_for_run_in_terminal(false), progress_event_reporter( [&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }), - reverse_request_seq(0), repl_mode(default_repl_mode) { + repl_mode(default_repl_mode) { configuration.preInitCommands = std::move(pre_init_commands); RegisterRequests(); } diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 8f24c6cf82924..975e2b290e1f9 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -162,10 +162,16 @@ struct DAP { lldb::SBFile in; OutputRedirector out; OutputRedirector err; + /// Configuration specified by the launch or attach commands. protocol::Configuration configuration; + + /// The debugger instance for this DAP session. lldb::SBDebugger debugger; + + /// The target instance for this DAP session. lldb::SBTarget target; + Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; @@ -173,39 +179,53 @@ struct DAP { InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; llvm::once_flag init_exception_breakpoints_flag; - // Map step in target id to list of function targets that user can choose. + + /// Map step in target id to list of function targets that user can choose. llvm::DenseMap step_in_targets; - // A copy of the last LaunchRequest so we can reuse its arguments if we get a - // RestartRequest. Restarting an AttachRequest is not supported. + + /// A copy of the last LaunchRequest so we can reuse its arguments if we get a + /// RestartRequest. Restarting an AttachRequest is not supported. std::optional last_launch_request; - lldb::tid_t focus_tid; + + /// The focused thread for this DAP session. + lldb::tid_t focus_tid = LLDB_INVALID_THREAD_ID; + bool disconnecting = false; llvm::once_flag terminated_event_flag; - bool stop_at_entry; - bool is_attach; - // The process event thread normally responds to process exited events by - // shutting down the entire adapter. When we're restarting, we keep the id of - // the old process here so we can detect this case and keep running. - lldb::pid_t restarting_process_id; + bool stop_at_entry = false; + bool is_attach = false; + + /// The process event thread normally responds to process exited events by + /// shutting down the entire adapter. When we're restarting, we keep the id of + /// the old process here so we can detect this case and keep running. + lldb::pid_t restarting_process_id = LLDB_INVALID_PROCESS_ID; + + /// Whether we have received the ConfigurationDone request, indicating that + /// the client has finished initialization of the debug adapter. bool configuration_done; - bool waiting_for_run_in_terminal; + + bool waiting_for_run_in_terminal = false; ProgressEventReporter progress_event_reporter; - // Keep track of the last stop thread index IDs as threads won't go away - // unless we send a "thread" event to indicate the thread exited. + + /// Keep track of the last stop thread index IDs as threads won't go away + /// unless we send a "thread" event to indicate the thread exited. llvm::DenseSet thread_ids; - uint32_t reverse_request_seq; + + uint32_t reverse_request_seq = 0; std::mutex call_mutex; llvm::SmallDenseMap> inflight_reverse_requests; ReplMode repl_mode; lldb::SBFormat frame_format; lldb::SBFormat thread_format; - // This is used to allow request_evaluate to handle empty expressions - // (ie the user pressed 'return' and expects the previous expression to - // repeat). If the previous expression was a command, this string will be - // empty; if the previous expression was a variable expression, this string - // will contain that expression. + + /// This is used to allow request_evaluate to handle empty expressions + /// (ie the user pressed 'return' and expects the previous expression to + /// repeat). If the previous expression was a command, this string will be + /// empty; if the previous expression was a variable expression, this string + /// will contain that expression. std::string last_nonempty_var_expression; + /// The set of features supported by the connected client. llvm::DenseSet clientFeatures; @@ -257,8 +277,6 @@ struct DAP { /// Configures the debug adapter for launching/attaching. void SetConfiguration(const protocol::Configuration &confing, bool is_attach); - void SetConfigurationDone(); - /// Configure source maps based on the current `DAPConfiguration`. void ConfigureSourceMaps(); From lldb-commits at lists.llvm.org Sat May 17 11:21:07 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sat, 17 May 2025 11:21:07 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Member variable cleanup in DAP.{cpp, h} (NFC) (PR #140390) In-Reply-To: Message-ID: <6828d393.a70a0220.043c.9c6b@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Jonas Devlieghere (JDevlieghere)
Changes - Use in-class member initialization to simplify the constructor. - Remove unimplemented SetConfigurationDone. - Consistently use Doxygen-style comments. --- Full diff: https://github.com/llvm/llvm-project/pull/140390.diff 2 Files Affected: - (modified) lldb/tools/lldb-dap/DAP.cpp (+1-5) - (modified) lldb/tools/lldb-dap/DAP.h (+39-21) ``````````diff diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 0d5eba6c40961..d813cdb0b9074 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -118,13 +118,9 @@ llvm::StringRef DAP::debug_adapter_path = ""; DAP::DAP(Log *log, const ReplMode default_repl_mode, std::vector pre_init_commands, Transport &transport) : log(log), transport(transport), broadcaster("lldb-dap"), - exception_breakpoints(), focus_tid(LLDB_INVALID_THREAD_ID), - stop_at_entry(false), is_attach(false), - restarting_process_id(LLDB_INVALID_PROCESS_ID), configuration_done(false), - waiting_for_run_in_terminal(false), progress_event_reporter( [&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }), - reverse_request_seq(0), repl_mode(default_repl_mode) { + repl_mode(default_repl_mode) { configuration.preInitCommands = std::move(pre_init_commands); RegisterRequests(); } diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 8f24c6cf82924..975e2b290e1f9 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -162,10 +162,16 @@ struct DAP { lldb::SBFile in; OutputRedirector out; OutputRedirector err; + /// Configuration specified by the launch or attach commands. protocol::Configuration configuration; + + /// The debugger instance for this DAP session. lldb::SBDebugger debugger; + + /// The target instance for this DAP session. lldb::SBTarget target; + Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; @@ -173,39 +179,53 @@ struct DAP { InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; llvm::once_flag init_exception_breakpoints_flag; - // Map step in target id to list of function targets that user can choose. + + /// Map step in target id to list of function targets that user can choose. llvm::DenseMap step_in_targets; - // A copy of the last LaunchRequest so we can reuse its arguments if we get a - // RestartRequest. Restarting an AttachRequest is not supported. + + /// A copy of the last LaunchRequest so we can reuse its arguments if we get a + /// RestartRequest. Restarting an AttachRequest is not supported. std::optional last_launch_request; - lldb::tid_t focus_tid; + + /// The focused thread for this DAP session. + lldb::tid_t focus_tid = LLDB_INVALID_THREAD_ID; + bool disconnecting = false; llvm::once_flag terminated_event_flag; - bool stop_at_entry; - bool is_attach; - // The process event thread normally responds to process exited events by - // shutting down the entire adapter. When we're restarting, we keep the id of - // the old process here so we can detect this case and keep running. - lldb::pid_t restarting_process_id; + bool stop_at_entry = false; + bool is_attach = false; + + /// The process event thread normally responds to process exited events by + /// shutting down the entire adapter. When we're restarting, we keep the id of + /// the old process here so we can detect this case and keep running. + lldb::pid_t restarting_process_id = LLDB_INVALID_PROCESS_ID; + + /// Whether we have received the ConfigurationDone request, indicating that + /// the client has finished initialization of the debug adapter. bool configuration_done; - bool waiting_for_run_in_terminal; + + bool waiting_for_run_in_terminal = false; ProgressEventReporter progress_event_reporter; - // Keep track of the last stop thread index IDs as threads won't go away - // unless we send a "thread" event to indicate the thread exited. + + /// Keep track of the last stop thread index IDs as threads won't go away + /// unless we send a "thread" event to indicate the thread exited. llvm::DenseSet thread_ids; - uint32_t reverse_request_seq; + + uint32_t reverse_request_seq = 0; std::mutex call_mutex; llvm::SmallDenseMap> inflight_reverse_requests; ReplMode repl_mode; lldb::SBFormat frame_format; lldb::SBFormat thread_format; - // This is used to allow request_evaluate to handle empty expressions - // (ie the user pressed 'return' and expects the previous expression to - // repeat). If the previous expression was a command, this string will be - // empty; if the previous expression was a variable expression, this string - // will contain that expression. + + /// This is used to allow request_evaluate to handle empty expressions + /// (ie the user pressed 'return' and expects the previous expression to + /// repeat). If the previous expression was a command, this string will be + /// empty; if the previous expression was a variable expression, this string + /// will contain that expression. std::string last_nonempty_var_expression; + /// The set of features supported by the connected client. llvm::DenseSet clientFeatures; @@ -257,8 +277,6 @@ struct DAP { /// Configures the debug adapter for launching/attaching. void SetConfiguration(const protocol::Configuration &confing, bool is_attach); - void SetConfigurationDone(); - /// Configure source maps based on the current `DAPConfiguration`. void ConfigureSourceMaps(); ``````````
https://github.com/llvm/llvm-project/pull/140390 From lldb-commits at lists.llvm.org Sat May 17 11:38:34 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sat, 17 May 2025 11:38:34 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Move the Variables struct into its own file (NFC) (PR #140393) Message-ID: https://github.com/JDevlieghere created https://github.com/llvm/llvm-project/pull/140393 Move the Variables struct out of DAP.h and into its own file to reduce the complexity of the latter. This PR also makes the members that are implementation details private. >From 82cd419423f74777e248743534f2da48ae6b72c9 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Sat, 17 May 2025 11:34:48 -0700 Subject: [PATCH] [lldb-dap] Move the Variables struct into its own file (NFC) Move the Variables struct out of DAP.h and into its own file to reduce the complexity of the latter. This PR also makes the members that are implementation details private. --- lldb/tools/lldb-dap/CMakeLists.txt | 1 + lldb/tools/lldb-dap/DAP.cpp | 93 ------------------------- lldb/tools/lldb-dap/DAP.h | 51 +------------- lldb/tools/lldb-dap/Variables.cpp | 105 +++++++++++++++++++++++++++++ lldb/tools/lldb-dap/Variables.h | 71 +++++++++++++++++++ 5 files changed, 178 insertions(+), 143 deletions(-) create mode 100644 lldb/tools/lldb-dap/Variables.cpp create mode 100644 lldb/tools/lldb-dap/Variables.h diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 5dedee8a87f41..f8e81eaff8606 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -23,6 +23,7 @@ add_lldb_library(lldbDAP RunInTerminal.cpp SourceBreakpoint.cpp Transport.cpp + Variables.cpp Watchpoint.cpp Handler/ResponseHandler.cpp diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 0d5eba6c40961..af46838f5671c 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1021,45 +1021,6 @@ lldb::SBError DAP::WaitForProcessToStop(std::chrono::seconds seconds) { return error; } -void Variables::Clear() { - locals.Clear(); - globals.Clear(); - registers.Clear(); - referenced_variables.clear(); -} - -int64_t Variables::GetNewVariableReference(bool is_permanent) { - if (is_permanent) - return next_permanent_var_ref++; - return next_temporary_var_ref++; -} - -bool Variables::IsPermanentVariableReference(int64_t var_ref) { - return var_ref >= PermanentVariableStartIndex; -} - -lldb::SBValue Variables::GetVariable(int64_t var_ref) const { - if (IsPermanentVariableReference(var_ref)) { - auto pos = referenced_permanent_variables.find(var_ref); - if (pos != referenced_permanent_variables.end()) - return pos->second; - } else { - auto pos = referenced_variables.find(var_ref); - if (pos != referenced_variables.end()) - return pos->second; - } - return lldb::SBValue(); -} - -int64_t Variables::InsertVariable(lldb::SBValue variable, bool is_permanent) { - int64_t var_ref = GetNewVariableReference(is_permanent); - if (is_permanent) - referenced_permanent_variables.insert(std::make_pair(var_ref, variable)); - else - referenced_variables.insert(std::make_pair(var_ref, variable)); - return var_ref; -} - bool StartDebuggingRequestHandler::DoExecute( lldb::SBDebugger debugger, char **command, lldb::SBCommandReturnObject &result) { @@ -1296,60 +1257,6 @@ DAP::GetInstructionBPFromStopReason(lldb::SBThread &thread) { return inst_bp; } -lldb::SBValueList *Variables::GetTopLevelScope(int64_t variablesReference) { - switch (variablesReference) { - case VARREF_LOCALS: - return &locals; - case VARREF_GLOBALS: - return &globals; - case VARREF_REGS: - return ®isters; - default: - return nullptr; - } -} - -lldb::SBValue Variables::FindVariable(uint64_t variablesReference, - llvm::StringRef name) { - lldb::SBValue variable; - if (lldb::SBValueList *top_scope = GetTopLevelScope(variablesReference)) { - bool is_duplicated_variable_name = name.contains(" @"); - // variablesReference is one of our scopes, not an actual variable it is - // asking for a variable in locals or globals or registers - int64_t end_idx = top_scope->GetSize(); - // Searching backward so that we choose the variable in closest scope - // among variables of the same name. - for (int64_t i = end_idx - 1; i >= 0; --i) { - lldb::SBValue curr_variable = top_scope->GetValueAtIndex(i); - std::string variable_name = CreateUniqueVariableNameForDisplay( - curr_variable, is_duplicated_variable_name); - if (variable_name == name) { - variable = curr_variable; - break; - } - } - } else { - // This is not under the globals or locals scope, so there are no - // duplicated names. - - // We have a named item within an actual variable so we need to find it - // withing the container variable by name. - lldb::SBValue container = GetVariable(variablesReference); - variable = container.GetChildMemberWithName(name.data()); - if (!variable.IsValid()) { - if (name.starts_with("[")) { - llvm::StringRef index_str(name.drop_front(1)); - uint64_t index = 0; - if (!index_str.consumeInteger(0, index)) { - if (index_str == "]") - variable = container.GetChildAtIndex(index); - } - } - } - } - return variable; -} - protocol::Capabilities DAP::GetCapabilities() { protocol::Capabilities capabilities; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 8f24c6cf82924..033203309b4c6 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -20,6 +20,7 @@ #include "Protocol/ProtocolTypes.h" #include "SourceBreakpoint.h" #include "Transport.h" +#include "Variables.h" #include "lldb/API/SBBroadcaster.h" #include "lldb/API/SBCommandInterpreter.h" #include "lldb/API/SBDebugger.h" @@ -30,8 +31,6 @@ #include "lldb/API/SBMutex.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" -#include "lldb/API/SBValue.h" -#include "lldb/API/SBValueList.h" #include "lldb/lldb-types.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" @@ -52,10 +51,6 @@ #include #include -#define VARREF_LOCALS (int64_t)1 -#define VARREF_GLOBALS (int64_t)2 -#define VARREF_REGS (int64_t)3 -#define VARREF_FIRST_VAR_IDX (int64_t)4 #define NO_TYPENAME "" namespace lldb_dap { @@ -88,50 +83,6 @@ enum class PacketStatus { enum class ReplMode { Variable = 0, Command, Auto }; -struct Variables { - /// Variable_reference start index of permanent expandable variable. - static constexpr int64_t PermanentVariableStartIndex = (1ll << 32); - - lldb::SBValueList locals; - lldb::SBValueList globals; - lldb::SBValueList registers; - - int64_t next_temporary_var_ref{VARREF_FIRST_VAR_IDX}; - int64_t next_permanent_var_ref{PermanentVariableStartIndex}; - - /// Variables that are alive in this stop state. - /// Will be cleared when debuggee resumes. - llvm::DenseMap referenced_variables; - /// Variables that persist across entire debug session. - /// These are the variables evaluated from debug console REPL. - llvm::DenseMap referenced_permanent_variables; - - /// Check if \p var_ref points to a variable that should persist for the - /// entire duration of the debug session, e.g. repl expandable variables - static bool IsPermanentVariableReference(int64_t var_ref); - - /// \return a new variableReference. - /// Specify is_permanent as true for variable that should persist entire - /// debug session. - int64_t GetNewVariableReference(bool is_permanent); - - /// \return the expandable variable corresponding with variableReference - /// value of \p value. - /// If \p var_ref is invalid an empty SBValue is returned. - lldb::SBValue GetVariable(int64_t var_ref) const; - - /// Insert a new \p variable. - /// \return variableReference assigned to this expandable variable. - int64_t InsertVariable(lldb::SBValue variable, bool is_permanent); - - lldb::SBValueList *GetTopLevelScope(int64_t variablesReference); - - lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef name); - - /// Clear all scope variables and non-permanent expandable variables. - void Clear(); -}; - struct StartDebuggingRequestHandler : public lldb::SBCommandPluginInterface { DAP &dap; explicit StartDebuggingRequestHandler(DAP &d) : dap(d) {}; diff --git a/lldb/tools/lldb-dap/Variables.cpp b/lldb/tools/lldb-dap/Variables.cpp new file mode 100644 index 0000000000000..777e3183d8c0d --- /dev/null +++ b/lldb/tools/lldb-dap/Variables.cpp @@ -0,0 +1,105 @@ +//===-- Variables.cpp ---------------------------------------------------*-===// +// +// 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 "Variables.h" +#include "JSONUtils.h" + +using namespace lldb_dap; + +lldb::SBValueList *Variables::GetTopLevelScope(int64_t variablesReference) { + switch (variablesReference) { + case VARREF_LOCALS: + return &locals; + case VARREF_GLOBALS: + return &globals; + case VARREF_REGS: + return ®isters; + default: + return nullptr; + } +} + +void Variables::Clear() { + locals.Clear(); + globals.Clear(); + registers.Clear(); + m_referencedvariables.clear(); +} + +int64_t Variables::GetNewVariableReference(bool is_permanent) { + if (is_permanent) + return m_next_permanent_var_ref++; + return m_next_temporary_var_ref++; +} + +bool Variables::IsPermanentVariableReference(int64_t var_ref) { + return var_ref >= PermanentVariableStartIndex; +} + +lldb::SBValue Variables::GetVariable(int64_t var_ref) const { + if (IsPermanentVariableReference(var_ref)) { + auto pos = m_referencedpermanent_variables.find(var_ref); + if (pos != m_referencedpermanent_variables.end()) + return pos->second; + } else { + auto pos = m_referencedvariables.find(var_ref); + if (pos != m_referencedvariables.end()) + return pos->second; + } + return lldb::SBValue(); +} + +int64_t Variables::InsertVariable(lldb::SBValue variable, bool is_permanent) { + int64_t var_ref = GetNewVariableReference(is_permanent); + if (is_permanent) + m_referencedpermanent_variables.insert(std::make_pair(var_ref, variable)); + else + m_referencedvariables.insert(std::make_pair(var_ref, variable)); + return var_ref; +} + +lldb::SBValue Variables::FindVariable(uint64_t variablesReference, + llvm::StringRef name) { + lldb::SBValue variable; + if (lldb::SBValueList *top_scope = GetTopLevelScope(variablesReference)) { + bool is_duplicated_variable_name = name.contains(" @"); + // variablesReference is one of our scopes, not an actual variable it is + // asking for a variable in locals or globals or registers + int64_t end_idx = top_scope->GetSize(); + // Searching backward so that we choose the variable in closest scope + // among variables of the same name. + for (int64_t i = end_idx - 1; i >= 0; --i) { + lldb::SBValue curr_variable = top_scope->GetValueAtIndex(i); + std::string variable_name = CreateUniqueVariableNameForDisplay( + curr_variable, is_duplicated_variable_name); + if (variable_name == name) { + variable = curr_variable; + break; + } + } + } else { + // This is not under the globals or locals scope, so there are no + // duplicated names. + + // We have a named item within an actual variable so we need to find it + // withing the container variable by name. + lldb::SBValue container = GetVariable(variablesReference); + variable = container.GetChildMemberWithName(name.data()); + if (!variable.IsValid()) { + if (name.starts_with("[")) { + llvm::StringRef index_str(name.drop_front(1)); + uint64_t index = 0; + if (!index_str.consumeInteger(0, index)) { + if (index_str == "]") + variable = container.GetChildAtIndex(index); + } + } + } + } + return variable; +} diff --git a/lldb/tools/lldb-dap/Variables.h b/lldb/tools/lldb-dap/Variables.h new file mode 100644 index 0000000000000..0ed84b36aef99 --- /dev/null +++ b/lldb/tools/lldb-dap/Variables.h @@ -0,0 +1,71 @@ +//===-- Variables.h -----------------------------------------------------*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TOOLS_LLDB_DAP_VARIABLES_H +#define LLDB_TOOLS_LLDB_DAP_VARIABLES_H + +#include "lldb/API/SBValue.h" +#include "lldb/API/SBValueList.h" +#include "llvm/ADT/DenseMap.h" + +#define VARREF_FIRST_VAR_IDX (int64_t)4 +#define VARREF_LOCALS (int64_t)1 +#define VARREF_GLOBALS (int64_t)2 +#define VARREF_REGS (int64_t)3 + +namespace lldb_dap { + +struct Variables { + lldb::SBValueList locals; + lldb::SBValueList globals; + lldb::SBValueList registers; + + /// Check if \p var_ref points to a variable that should persist for the + /// entire duration of the debug session, e.g. repl expandable variables + static bool IsPermanentVariableReference(int64_t var_ref); + + /// \return a new variableReference. + /// Specify is_permanent as true for variable that should persist entire + /// debug session. + int64_t GetNewVariableReference(bool is_permanent); + + /// \return the expandable variable corresponding with variableReference + /// value of \p value. + /// If \p var_ref is invalid an empty SBValue is returned. + lldb::SBValue GetVariable(int64_t var_ref) const; + + /// Insert a new \p variable. + /// \return variableReference assigned to this expandable variable. + int64_t InsertVariable(lldb::SBValue variable, bool is_permanent); + + lldb::SBValueList *GetTopLevelScope(int64_t variablesReference); + + lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef name); + + /// Clear all scope variables and non-permanent expandable variables. + void Clear(); + +private: + /// Variable_reference start index of permanent expandable variable. + static constexpr int64_t PermanentVariableStartIndex = (1ll << 32); + + /// Variables that are alive in this stop state. + /// Will be cleared when debuggee resumes. + llvm::DenseMap m_referencedvariables; + + /// Variables that persist across entire debug session. + /// These are the variables evaluated from debug console REPL. + llvm::DenseMap m_referencedpermanent_variables; + + int64_t m_next_temporary_var_ref{VARREF_FIRST_VAR_IDX}; + int64_t m_next_permanent_var_ref{PermanentVariableStartIndex}; +}; + +} // namespace lldb_dap + +#endif From lldb-commits at lists.llvm.org Sat May 17 11:39:10 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sat, 17 May 2025 11:39:10 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Move the Variables struct into its own file (NFC) (PR #140393) In-Reply-To: Message-ID: <6828d7ce.170a0220.12fd9c.8b61@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Jonas Devlieghere (JDevlieghere)
Changes Move the Variables struct out of DAP.h and into its own file to reduce the complexity of the latter. This PR also makes the members that are implementation details private. --- Full diff: https://github.com/llvm/llvm-project/pull/140393.diff 5 Files Affected: - (modified) lldb/tools/lldb-dap/CMakeLists.txt (+1) - (modified) lldb/tools/lldb-dap/DAP.cpp (-93) - (modified) lldb/tools/lldb-dap/DAP.h (+1-50) - (added) lldb/tools/lldb-dap/Variables.cpp (+105) - (added) lldb/tools/lldb-dap/Variables.h (+71) ``````````diff diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 5dedee8a87f41..f8e81eaff8606 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -23,6 +23,7 @@ add_lldb_library(lldbDAP RunInTerminal.cpp SourceBreakpoint.cpp Transport.cpp + Variables.cpp Watchpoint.cpp Handler/ResponseHandler.cpp diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 0d5eba6c40961..af46838f5671c 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1021,45 +1021,6 @@ lldb::SBError DAP::WaitForProcessToStop(std::chrono::seconds seconds) { return error; } -void Variables::Clear() { - locals.Clear(); - globals.Clear(); - registers.Clear(); - referenced_variables.clear(); -} - -int64_t Variables::GetNewVariableReference(bool is_permanent) { - if (is_permanent) - return next_permanent_var_ref++; - return next_temporary_var_ref++; -} - -bool Variables::IsPermanentVariableReference(int64_t var_ref) { - return var_ref >= PermanentVariableStartIndex; -} - -lldb::SBValue Variables::GetVariable(int64_t var_ref) const { - if (IsPermanentVariableReference(var_ref)) { - auto pos = referenced_permanent_variables.find(var_ref); - if (pos != referenced_permanent_variables.end()) - return pos->second; - } else { - auto pos = referenced_variables.find(var_ref); - if (pos != referenced_variables.end()) - return pos->second; - } - return lldb::SBValue(); -} - -int64_t Variables::InsertVariable(lldb::SBValue variable, bool is_permanent) { - int64_t var_ref = GetNewVariableReference(is_permanent); - if (is_permanent) - referenced_permanent_variables.insert(std::make_pair(var_ref, variable)); - else - referenced_variables.insert(std::make_pair(var_ref, variable)); - return var_ref; -} - bool StartDebuggingRequestHandler::DoExecute( lldb::SBDebugger debugger, char **command, lldb::SBCommandReturnObject &result) { @@ -1296,60 +1257,6 @@ DAP::GetInstructionBPFromStopReason(lldb::SBThread &thread) { return inst_bp; } -lldb::SBValueList *Variables::GetTopLevelScope(int64_t variablesReference) { - switch (variablesReference) { - case VARREF_LOCALS: - return &locals; - case VARREF_GLOBALS: - return &globals; - case VARREF_REGS: - return ®isters; - default: - return nullptr; - } -} - -lldb::SBValue Variables::FindVariable(uint64_t variablesReference, - llvm::StringRef name) { - lldb::SBValue variable; - if (lldb::SBValueList *top_scope = GetTopLevelScope(variablesReference)) { - bool is_duplicated_variable_name = name.contains(" @"); - // variablesReference is one of our scopes, not an actual variable it is - // asking for a variable in locals or globals or registers - int64_t end_idx = top_scope->GetSize(); - // Searching backward so that we choose the variable in closest scope - // among variables of the same name. - for (int64_t i = end_idx - 1; i >= 0; --i) { - lldb::SBValue curr_variable = top_scope->GetValueAtIndex(i); - std::string variable_name = CreateUniqueVariableNameForDisplay( - curr_variable, is_duplicated_variable_name); - if (variable_name == name) { - variable = curr_variable; - break; - } - } - } else { - // This is not under the globals or locals scope, so there are no - // duplicated names. - - // We have a named item within an actual variable so we need to find it - // withing the container variable by name. - lldb::SBValue container = GetVariable(variablesReference); - variable = container.GetChildMemberWithName(name.data()); - if (!variable.IsValid()) { - if (name.starts_with("[")) { - llvm::StringRef index_str(name.drop_front(1)); - uint64_t index = 0; - if (!index_str.consumeInteger(0, index)) { - if (index_str == "]") - variable = container.GetChildAtIndex(index); - } - } - } - } - return variable; -} - protocol::Capabilities DAP::GetCapabilities() { protocol::Capabilities capabilities; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 8f24c6cf82924..033203309b4c6 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -20,6 +20,7 @@ #include "Protocol/ProtocolTypes.h" #include "SourceBreakpoint.h" #include "Transport.h" +#include "Variables.h" #include "lldb/API/SBBroadcaster.h" #include "lldb/API/SBCommandInterpreter.h" #include "lldb/API/SBDebugger.h" @@ -30,8 +31,6 @@ #include "lldb/API/SBMutex.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" -#include "lldb/API/SBValue.h" -#include "lldb/API/SBValueList.h" #include "lldb/lldb-types.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" @@ -52,10 +51,6 @@ #include #include -#define VARREF_LOCALS (int64_t)1 -#define VARREF_GLOBALS (int64_t)2 -#define VARREF_REGS (int64_t)3 -#define VARREF_FIRST_VAR_IDX (int64_t)4 #define NO_TYPENAME "" namespace lldb_dap { @@ -88,50 +83,6 @@ enum class PacketStatus { enum class ReplMode { Variable = 0, Command, Auto }; -struct Variables { - /// Variable_reference start index of permanent expandable variable. - static constexpr int64_t PermanentVariableStartIndex = (1ll << 32); - - lldb::SBValueList locals; - lldb::SBValueList globals; - lldb::SBValueList registers; - - int64_t next_temporary_var_ref{VARREF_FIRST_VAR_IDX}; - int64_t next_permanent_var_ref{PermanentVariableStartIndex}; - - /// Variables that are alive in this stop state. - /// Will be cleared when debuggee resumes. - llvm::DenseMap referenced_variables; - /// Variables that persist across entire debug session. - /// These are the variables evaluated from debug console REPL. - llvm::DenseMap referenced_permanent_variables; - - /// Check if \p var_ref points to a variable that should persist for the - /// entire duration of the debug session, e.g. repl expandable variables - static bool IsPermanentVariableReference(int64_t var_ref); - - /// \return a new variableReference. - /// Specify is_permanent as true for variable that should persist entire - /// debug session. - int64_t GetNewVariableReference(bool is_permanent); - - /// \return the expandable variable corresponding with variableReference - /// value of \p value. - /// If \p var_ref is invalid an empty SBValue is returned. - lldb::SBValue GetVariable(int64_t var_ref) const; - - /// Insert a new \p variable. - /// \return variableReference assigned to this expandable variable. - int64_t InsertVariable(lldb::SBValue variable, bool is_permanent); - - lldb::SBValueList *GetTopLevelScope(int64_t variablesReference); - - lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef name); - - /// Clear all scope variables and non-permanent expandable variables. - void Clear(); -}; - struct StartDebuggingRequestHandler : public lldb::SBCommandPluginInterface { DAP &dap; explicit StartDebuggingRequestHandler(DAP &d) : dap(d) {}; diff --git a/lldb/tools/lldb-dap/Variables.cpp b/lldb/tools/lldb-dap/Variables.cpp new file mode 100644 index 0000000000000..777e3183d8c0d --- /dev/null +++ b/lldb/tools/lldb-dap/Variables.cpp @@ -0,0 +1,105 @@ +//===-- Variables.cpp ---------------------------------------------------*-===// +// +// 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 "Variables.h" +#include "JSONUtils.h" + +using namespace lldb_dap; + +lldb::SBValueList *Variables::GetTopLevelScope(int64_t variablesReference) { + switch (variablesReference) { + case VARREF_LOCALS: + return &locals; + case VARREF_GLOBALS: + return &globals; + case VARREF_REGS: + return ®isters; + default: + return nullptr; + } +} + +void Variables::Clear() { + locals.Clear(); + globals.Clear(); + registers.Clear(); + m_referencedvariables.clear(); +} + +int64_t Variables::GetNewVariableReference(bool is_permanent) { + if (is_permanent) + return m_next_permanent_var_ref++; + return m_next_temporary_var_ref++; +} + +bool Variables::IsPermanentVariableReference(int64_t var_ref) { + return var_ref >= PermanentVariableStartIndex; +} + +lldb::SBValue Variables::GetVariable(int64_t var_ref) const { + if (IsPermanentVariableReference(var_ref)) { + auto pos = m_referencedpermanent_variables.find(var_ref); + if (pos != m_referencedpermanent_variables.end()) + return pos->second; + } else { + auto pos = m_referencedvariables.find(var_ref); + if (pos != m_referencedvariables.end()) + return pos->second; + } + return lldb::SBValue(); +} + +int64_t Variables::InsertVariable(lldb::SBValue variable, bool is_permanent) { + int64_t var_ref = GetNewVariableReference(is_permanent); + if (is_permanent) + m_referencedpermanent_variables.insert(std::make_pair(var_ref, variable)); + else + m_referencedvariables.insert(std::make_pair(var_ref, variable)); + return var_ref; +} + +lldb::SBValue Variables::FindVariable(uint64_t variablesReference, + llvm::StringRef name) { + lldb::SBValue variable; + if (lldb::SBValueList *top_scope = GetTopLevelScope(variablesReference)) { + bool is_duplicated_variable_name = name.contains(" @"); + // variablesReference is one of our scopes, not an actual variable it is + // asking for a variable in locals or globals or registers + int64_t end_idx = top_scope->GetSize(); + // Searching backward so that we choose the variable in closest scope + // among variables of the same name. + for (int64_t i = end_idx - 1; i >= 0; --i) { + lldb::SBValue curr_variable = top_scope->GetValueAtIndex(i); + std::string variable_name = CreateUniqueVariableNameForDisplay( + curr_variable, is_duplicated_variable_name); + if (variable_name == name) { + variable = curr_variable; + break; + } + } + } else { + // This is not under the globals or locals scope, so there are no + // duplicated names. + + // We have a named item within an actual variable so we need to find it + // withing the container variable by name. + lldb::SBValue container = GetVariable(variablesReference); + variable = container.GetChildMemberWithName(name.data()); + if (!variable.IsValid()) { + if (name.starts_with("[")) { + llvm::StringRef index_str(name.drop_front(1)); + uint64_t index = 0; + if (!index_str.consumeInteger(0, index)) { + if (index_str == "]") + variable = container.GetChildAtIndex(index); + } + } + } + } + return variable; +} diff --git a/lldb/tools/lldb-dap/Variables.h b/lldb/tools/lldb-dap/Variables.h new file mode 100644 index 0000000000000..0ed84b36aef99 --- /dev/null +++ b/lldb/tools/lldb-dap/Variables.h @@ -0,0 +1,71 @@ +//===-- Variables.h -----------------------------------------------------*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TOOLS_LLDB_DAP_VARIABLES_H +#define LLDB_TOOLS_LLDB_DAP_VARIABLES_H + +#include "lldb/API/SBValue.h" +#include "lldb/API/SBValueList.h" +#include "llvm/ADT/DenseMap.h" + +#define VARREF_FIRST_VAR_IDX (int64_t)4 +#define VARREF_LOCALS (int64_t)1 +#define VARREF_GLOBALS (int64_t)2 +#define VARREF_REGS (int64_t)3 + +namespace lldb_dap { + +struct Variables { + lldb::SBValueList locals; + lldb::SBValueList globals; + lldb::SBValueList registers; + + /// Check if \p var_ref points to a variable that should persist for the + /// entire duration of the debug session, e.g. repl expandable variables + static bool IsPermanentVariableReference(int64_t var_ref); + + /// \return a new variableReference. + /// Specify is_permanent as true for variable that should persist entire + /// debug session. + int64_t GetNewVariableReference(bool is_permanent); + + /// \return the expandable variable corresponding with variableReference + /// value of \p value. + /// If \p var_ref is invalid an empty SBValue is returned. + lldb::SBValue GetVariable(int64_t var_ref) const; + + /// Insert a new \p variable. + /// \return variableReference assigned to this expandable variable. + int64_t InsertVariable(lldb::SBValue variable, bool is_permanent); + + lldb::SBValueList *GetTopLevelScope(int64_t variablesReference); + + lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef name); + + /// Clear all scope variables and non-permanent expandable variables. + void Clear(); + +private: + /// Variable_reference start index of permanent expandable variable. + static constexpr int64_t PermanentVariableStartIndex = (1ll << 32); + + /// Variables that are alive in this stop state. + /// Will be cleared when debuggee resumes. + llvm::DenseMap m_referencedvariables; + + /// Variables that persist across entire debug session. + /// These are the variables evaluated from debug console REPL. + llvm::DenseMap m_referencedpermanent_variables; + + int64_t m_next_temporary_var_ref{VARREF_FIRST_VAR_IDX}; + int64_t m_next_permanent_var_ref{PermanentVariableStartIndex}; +}; + +} // namespace lldb_dap + +#endif ``````````
https://github.com/llvm/llvm-project/pull/140393 From lldb-commits at lists.llvm.org Sat May 17 11:59:01 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sat, 17 May 2025 11:59:01 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Move the Variables struct into its own file (NFC) (PR #140393) In-Reply-To: Message-ID: <6828dc75.170a0220.152f6e.8a2d@mx.google.com> https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/140393 >From 82cd419423f74777e248743534f2da48ae6b72c9 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Sat, 17 May 2025 11:34:48 -0700 Subject: [PATCH 1/2] [lldb-dap] Move the Variables struct into its own file (NFC) Move the Variables struct out of DAP.h and into its own file to reduce the complexity of the latter. This PR also makes the members that are implementation details private. --- lldb/tools/lldb-dap/CMakeLists.txt | 1 + lldb/tools/lldb-dap/DAP.cpp | 93 ------------------------- lldb/tools/lldb-dap/DAP.h | 51 +------------- lldb/tools/lldb-dap/Variables.cpp | 105 +++++++++++++++++++++++++++++ lldb/tools/lldb-dap/Variables.h | 71 +++++++++++++++++++ 5 files changed, 178 insertions(+), 143 deletions(-) create mode 100644 lldb/tools/lldb-dap/Variables.cpp create mode 100644 lldb/tools/lldb-dap/Variables.h diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 5dedee8a87f41..f8e81eaff8606 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -23,6 +23,7 @@ add_lldb_library(lldbDAP RunInTerminal.cpp SourceBreakpoint.cpp Transport.cpp + Variables.cpp Watchpoint.cpp Handler/ResponseHandler.cpp diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 0d5eba6c40961..af46838f5671c 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1021,45 +1021,6 @@ lldb::SBError DAP::WaitForProcessToStop(std::chrono::seconds seconds) { return error; } -void Variables::Clear() { - locals.Clear(); - globals.Clear(); - registers.Clear(); - referenced_variables.clear(); -} - -int64_t Variables::GetNewVariableReference(bool is_permanent) { - if (is_permanent) - return next_permanent_var_ref++; - return next_temporary_var_ref++; -} - -bool Variables::IsPermanentVariableReference(int64_t var_ref) { - return var_ref >= PermanentVariableStartIndex; -} - -lldb::SBValue Variables::GetVariable(int64_t var_ref) const { - if (IsPermanentVariableReference(var_ref)) { - auto pos = referenced_permanent_variables.find(var_ref); - if (pos != referenced_permanent_variables.end()) - return pos->second; - } else { - auto pos = referenced_variables.find(var_ref); - if (pos != referenced_variables.end()) - return pos->second; - } - return lldb::SBValue(); -} - -int64_t Variables::InsertVariable(lldb::SBValue variable, bool is_permanent) { - int64_t var_ref = GetNewVariableReference(is_permanent); - if (is_permanent) - referenced_permanent_variables.insert(std::make_pair(var_ref, variable)); - else - referenced_variables.insert(std::make_pair(var_ref, variable)); - return var_ref; -} - bool StartDebuggingRequestHandler::DoExecute( lldb::SBDebugger debugger, char **command, lldb::SBCommandReturnObject &result) { @@ -1296,60 +1257,6 @@ DAP::GetInstructionBPFromStopReason(lldb::SBThread &thread) { return inst_bp; } -lldb::SBValueList *Variables::GetTopLevelScope(int64_t variablesReference) { - switch (variablesReference) { - case VARREF_LOCALS: - return &locals; - case VARREF_GLOBALS: - return &globals; - case VARREF_REGS: - return ®isters; - default: - return nullptr; - } -} - -lldb::SBValue Variables::FindVariable(uint64_t variablesReference, - llvm::StringRef name) { - lldb::SBValue variable; - if (lldb::SBValueList *top_scope = GetTopLevelScope(variablesReference)) { - bool is_duplicated_variable_name = name.contains(" @"); - // variablesReference is one of our scopes, not an actual variable it is - // asking for a variable in locals or globals or registers - int64_t end_idx = top_scope->GetSize(); - // Searching backward so that we choose the variable in closest scope - // among variables of the same name. - for (int64_t i = end_idx - 1; i >= 0; --i) { - lldb::SBValue curr_variable = top_scope->GetValueAtIndex(i); - std::string variable_name = CreateUniqueVariableNameForDisplay( - curr_variable, is_duplicated_variable_name); - if (variable_name == name) { - variable = curr_variable; - break; - } - } - } else { - // This is not under the globals or locals scope, so there are no - // duplicated names. - - // We have a named item within an actual variable so we need to find it - // withing the container variable by name. - lldb::SBValue container = GetVariable(variablesReference); - variable = container.GetChildMemberWithName(name.data()); - if (!variable.IsValid()) { - if (name.starts_with("[")) { - llvm::StringRef index_str(name.drop_front(1)); - uint64_t index = 0; - if (!index_str.consumeInteger(0, index)) { - if (index_str == "]") - variable = container.GetChildAtIndex(index); - } - } - } - } - return variable; -} - protocol::Capabilities DAP::GetCapabilities() { protocol::Capabilities capabilities; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 8f24c6cf82924..033203309b4c6 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -20,6 +20,7 @@ #include "Protocol/ProtocolTypes.h" #include "SourceBreakpoint.h" #include "Transport.h" +#include "Variables.h" #include "lldb/API/SBBroadcaster.h" #include "lldb/API/SBCommandInterpreter.h" #include "lldb/API/SBDebugger.h" @@ -30,8 +31,6 @@ #include "lldb/API/SBMutex.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" -#include "lldb/API/SBValue.h" -#include "lldb/API/SBValueList.h" #include "lldb/lldb-types.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" @@ -52,10 +51,6 @@ #include #include -#define VARREF_LOCALS (int64_t)1 -#define VARREF_GLOBALS (int64_t)2 -#define VARREF_REGS (int64_t)3 -#define VARREF_FIRST_VAR_IDX (int64_t)4 #define NO_TYPENAME "" namespace lldb_dap { @@ -88,50 +83,6 @@ enum class PacketStatus { enum class ReplMode { Variable = 0, Command, Auto }; -struct Variables { - /// Variable_reference start index of permanent expandable variable. - static constexpr int64_t PermanentVariableStartIndex = (1ll << 32); - - lldb::SBValueList locals; - lldb::SBValueList globals; - lldb::SBValueList registers; - - int64_t next_temporary_var_ref{VARREF_FIRST_VAR_IDX}; - int64_t next_permanent_var_ref{PermanentVariableStartIndex}; - - /// Variables that are alive in this stop state. - /// Will be cleared when debuggee resumes. - llvm::DenseMap referenced_variables; - /// Variables that persist across entire debug session. - /// These are the variables evaluated from debug console REPL. - llvm::DenseMap referenced_permanent_variables; - - /// Check if \p var_ref points to a variable that should persist for the - /// entire duration of the debug session, e.g. repl expandable variables - static bool IsPermanentVariableReference(int64_t var_ref); - - /// \return a new variableReference. - /// Specify is_permanent as true for variable that should persist entire - /// debug session. - int64_t GetNewVariableReference(bool is_permanent); - - /// \return the expandable variable corresponding with variableReference - /// value of \p value. - /// If \p var_ref is invalid an empty SBValue is returned. - lldb::SBValue GetVariable(int64_t var_ref) const; - - /// Insert a new \p variable. - /// \return variableReference assigned to this expandable variable. - int64_t InsertVariable(lldb::SBValue variable, bool is_permanent); - - lldb::SBValueList *GetTopLevelScope(int64_t variablesReference); - - lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef name); - - /// Clear all scope variables and non-permanent expandable variables. - void Clear(); -}; - struct StartDebuggingRequestHandler : public lldb::SBCommandPluginInterface { DAP &dap; explicit StartDebuggingRequestHandler(DAP &d) : dap(d) {}; diff --git a/lldb/tools/lldb-dap/Variables.cpp b/lldb/tools/lldb-dap/Variables.cpp new file mode 100644 index 0000000000000..777e3183d8c0d --- /dev/null +++ b/lldb/tools/lldb-dap/Variables.cpp @@ -0,0 +1,105 @@ +//===-- Variables.cpp ---------------------------------------------------*-===// +// +// 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 "Variables.h" +#include "JSONUtils.h" + +using namespace lldb_dap; + +lldb::SBValueList *Variables::GetTopLevelScope(int64_t variablesReference) { + switch (variablesReference) { + case VARREF_LOCALS: + return &locals; + case VARREF_GLOBALS: + return &globals; + case VARREF_REGS: + return ®isters; + default: + return nullptr; + } +} + +void Variables::Clear() { + locals.Clear(); + globals.Clear(); + registers.Clear(); + m_referencedvariables.clear(); +} + +int64_t Variables::GetNewVariableReference(bool is_permanent) { + if (is_permanent) + return m_next_permanent_var_ref++; + return m_next_temporary_var_ref++; +} + +bool Variables::IsPermanentVariableReference(int64_t var_ref) { + return var_ref >= PermanentVariableStartIndex; +} + +lldb::SBValue Variables::GetVariable(int64_t var_ref) const { + if (IsPermanentVariableReference(var_ref)) { + auto pos = m_referencedpermanent_variables.find(var_ref); + if (pos != m_referencedpermanent_variables.end()) + return pos->second; + } else { + auto pos = m_referencedvariables.find(var_ref); + if (pos != m_referencedvariables.end()) + return pos->second; + } + return lldb::SBValue(); +} + +int64_t Variables::InsertVariable(lldb::SBValue variable, bool is_permanent) { + int64_t var_ref = GetNewVariableReference(is_permanent); + if (is_permanent) + m_referencedpermanent_variables.insert(std::make_pair(var_ref, variable)); + else + m_referencedvariables.insert(std::make_pair(var_ref, variable)); + return var_ref; +} + +lldb::SBValue Variables::FindVariable(uint64_t variablesReference, + llvm::StringRef name) { + lldb::SBValue variable; + if (lldb::SBValueList *top_scope = GetTopLevelScope(variablesReference)) { + bool is_duplicated_variable_name = name.contains(" @"); + // variablesReference is one of our scopes, not an actual variable it is + // asking for a variable in locals or globals or registers + int64_t end_idx = top_scope->GetSize(); + // Searching backward so that we choose the variable in closest scope + // among variables of the same name. + for (int64_t i = end_idx - 1; i >= 0; --i) { + lldb::SBValue curr_variable = top_scope->GetValueAtIndex(i); + std::string variable_name = CreateUniqueVariableNameForDisplay( + curr_variable, is_duplicated_variable_name); + if (variable_name == name) { + variable = curr_variable; + break; + } + } + } else { + // This is not under the globals or locals scope, so there are no + // duplicated names. + + // We have a named item within an actual variable so we need to find it + // withing the container variable by name. + lldb::SBValue container = GetVariable(variablesReference); + variable = container.GetChildMemberWithName(name.data()); + if (!variable.IsValid()) { + if (name.starts_with("[")) { + llvm::StringRef index_str(name.drop_front(1)); + uint64_t index = 0; + if (!index_str.consumeInteger(0, index)) { + if (index_str == "]") + variable = container.GetChildAtIndex(index); + } + } + } + } + return variable; +} diff --git a/lldb/tools/lldb-dap/Variables.h b/lldb/tools/lldb-dap/Variables.h new file mode 100644 index 0000000000000..0ed84b36aef99 --- /dev/null +++ b/lldb/tools/lldb-dap/Variables.h @@ -0,0 +1,71 @@ +//===-- Variables.h -----------------------------------------------------*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TOOLS_LLDB_DAP_VARIABLES_H +#define LLDB_TOOLS_LLDB_DAP_VARIABLES_H + +#include "lldb/API/SBValue.h" +#include "lldb/API/SBValueList.h" +#include "llvm/ADT/DenseMap.h" + +#define VARREF_FIRST_VAR_IDX (int64_t)4 +#define VARREF_LOCALS (int64_t)1 +#define VARREF_GLOBALS (int64_t)2 +#define VARREF_REGS (int64_t)3 + +namespace lldb_dap { + +struct Variables { + lldb::SBValueList locals; + lldb::SBValueList globals; + lldb::SBValueList registers; + + /// Check if \p var_ref points to a variable that should persist for the + /// entire duration of the debug session, e.g. repl expandable variables + static bool IsPermanentVariableReference(int64_t var_ref); + + /// \return a new variableReference. + /// Specify is_permanent as true for variable that should persist entire + /// debug session. + int64_t GetNewVariableReference(bool is_permanent); + + /// \return the expandable variable corresponding with variableReference + /// value of \p value. + /// If \p var_ref is invalid an empty SBValue is returned. + lldb::SBValue GetVariable(int64_t var_ref) const; + + /// Insert a new \p variable. + /// \return variableReference assigned to this expandable variable. + int64_t InsertVariable(lldb::SBValue variable, bool is_permanent); + + lldb::SBValueList *GetTopLevelScope(int64_t variablesReference); + + lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef name); + + /// Clear all scope variables and non-permanent expandable variables. + void Clear(); + +private: + /// Variable_reference start index of permanent expandable variable. + static constexpr int64_t PermanentVariableStartIndex = (1ll << 32); + + /// Variables that are alive in this stop state. + /// Will be cleared when debuggee resumes. + llvm::DenseMap m_referencedvariables; + + /// Variables that persist across entire debug session. + /// These are the variables evaluated from debug console REPL. + llvm::DenseMap m_referencedpermanent_variables; + + int64_t m_next_temporary_var_ref{VARREF_FIRST_VAR_IDX}; + int64_t m_next_permanent_var_ref{PermanentVariableStartIndex}; +}; + +} // namespace lldb_dap + +#endif >From 62d94ae00b12006aacae7108f67a3b944fd97bdf Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Sat, 17 May 2025 11:58:48 -0700 Subject: [PATCH 2/2] Add Variables unit tests --- lldb/unittests/DAP/CMakeLists.txt | 1 + lldb/unittests/DAP/VariablesTest.cpp | 84 ++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 lldb/unittests/DAP/VariablesTest.cpp diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index af7d11e2e95e2..429a12e9fb505 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -6,6 +6,7 @@ add_lldb_unittest(DAPTests ProtocolTypesTest.cpp TestBase.cpp TransportTest.cpp + VariablesTest.cpp LINK_LIBS lldbDAP diff --git a/lldb/unittests/DAP/VariablesTest.cpp b/lldb/unittests/DAP/VariablesTest.cpp new file mode 100644 index 0000000000000..1ee98c0d1f8e0 --- /dev/null +++ b/lldb/unittests/DAP/VariablesTest.cpp @@ -0,0 +1,84 @@ +//===-- VariablesTest.cpp -------------------------------------------------===// +// +// 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 "Variables.h" +#include "lldb/API/SBValue.h" +#include "lldb/API/SBValueList.h" +#include "gtest/gtest.h" + +using namespace lldb_dap; + +class VariablesTest : public ::testing::Test { +protected: + Variables vars; +}; + +TEST_F(VariablesTest, GetNewVariableReference_UniqueAndRanges) { + const int64_t temp1 = vars.GetNewVariableReference(false); + const int64_t temp2 = vars.GetNewVariableReference(false); + const int64_t perm1 = vars.GetNewVariableReference(true); + const int64_t perm2 = vars.GetNewVariableReference(true); + + EXPECT_NE(temp1, temp2); + EXPECT_NE(perm1, perm2); + EXPECT_LT(temp1, perm1); + EXPECT_LT(temp2, perm1); +} + +TEST_F(VariablesTest, InsertAndGetVariable_Temporary) { + lldb::SBValue dummy; + const int64_t ref = vars.InsertVariable(dummy, false); + lldb::SBValue out = vars.GetVariable(ref); + + EXPECT_TRUE(out.IsValid() == dummy.IsValid()); +} + +TEST_F(VariablesTest, InsertAndGetVariable_Permanent) { + lldb::SBValue dummy; + const int64_t ref = vars.InsertVariable(dummy, true); + lldb::SBValue out = vars.GetVariable(ref); + + EXPECT_TRUE(out.IsValid() == dummy.IsValid()); +} + +TEST_F(VariablesTest, IsPermanentVariableReference) { + const int64_t perm = vars.GetNewVariableReference(true); + const int64_t temp = vars.GetNewVariableReference(false); + + EXPECT_TRUE(Variables::IsPermanentVariableReference(perm)); + EXPECT_FALSE(Variables::IsPermanentVariableReference(temp)); +} + +TEST_F(VariablesTest, Clear_RemovesTemporaryKeepsPermanent) { + lldb::SBValue dummy; + const int64_t temp = vars.InsertVariable(dummy, false); + const int64_t perm = vars.InsertVariable(dummy, true); + vars.Clear(); + + EXPECT_FALSE(vars.GetVariable(temp).IsValid()); + EXPECT_TRUE(vars.GetVariable(perm).IsValid() == dummy.IsValid()); +} + +TEST_F(VariablesTest, GetTopLevelScope_ReturnsCorrectScope) { + vars.locals.Append(lldb::SBValue()); + vars.globals.Append(lldb::SBValue()); + vars.registers.Append(lldb::SBValue()); + + EXPECT_EQ(vars.GetTopLevelScope(VARREF_LOCALS), &vars.locals); + EXPECT_EQ(vars.GetTopLevelScope(VARREF_GLOBALS), &vars.globals); + EXPECT_EQ(vars.GetTopLevelScope(VARREF_REGS), &vars.registers); + EXPECT_EQ(vars.GetTopLevelScope(9999), nullptr); +} + +TEST_F(VariablesTest, FindVariable_LocalsByName) { + lldb::SBValue dummy; + vars.locals.Append(dummy); + lldb::SBValue found = vars.FindVariable(VARREF_LOCALS, ""); + + EXPECT_TRUE(found.IsValid() == dummy.IsValid()); +} From lldb-commits at lists.llvm.org Sat May 17 11:59:21 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sat, 17 May 2025 11:59:21 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Move the Variables struct into its own file (PR #140393) In-Reply-To: Message-ID: <6828dc89.630a0220.183fc2.e192@mx.google.com> https://github.com/JDevlieghere edited https://github.com/llvm/llvm-project/pull/140393 From lldb-commits at lists.llvm.org Sat May 17 11:59:38 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sat, 17 May 2025 11:59:38 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Move the Variables struct into its own file (PR #140393) In-Reply-To: Message-ID: <6828dc9a.050a0220.312130.976a@mx.google.com> https://github.com/JDevlieghere edited https://github.com/llvm/llvm-project/pull/140393 From lldb-commits at lists.llvm.org Sat May 17 12:03:32 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sat, 17 May 2025 12:03:32 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Move the Variables struct into its own file (PR #140393) In-Reply-To: Message-ID: <6828dd84.170a0220.5dd41.15c1@mx.google.com> https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/140393 >From 82cd419423f74777e248743534f2da48ae6b72c9 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Sat, 17 May 2025 11:34:48 -0700 Subject: [PATCH 1/3] [lldb-dap] Move the Variables struct into its own file (NFC) Move the Variables struct out of DAP.h and into its own file to reduce the complexity of the latter. This PR also makes the members that are implementation details private. --- lldb/tools/lldb-dap/CMakeLists.txt | 1 + lldb/tools/lldb-dap/DAP.cpp | 93 ------------------------- lldb/tools/lldb-dap/DAP.h | 51 +------------- lldb/tools/lldb-dap/Variables.cpp | 105 +++++++++++++++++++++++++++++ lldb/tools/lldb-dap/Variables.h | 71 +++++++++++++++++++ 5 files changed, 178 insertions(+), 143 deletions(-) create mode 100644 lldb/tools/lldb-dap/Variables.cpp create mode 100644 lldb/tools/lldb-dap/Variables.h diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 5dedee8a87f41..f8e81eaff8606 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -23,6 +23,7 @@ add_lldb_library(lldbDAP RunInTerminal.cpp SourceBreakpoint.cpp Transport.cpp + Variables.cpp Watchpoint.cpp Handler/ResponseHandler.cpp diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 0d5eba6c40961..af46838f5671c 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1021,45 +1021,6 @@ lldb::SBError DAP::WaitForProcessToStop(std::chrono::seconds seconds) { return error; } -void Variables::Clear() { - locals.Clear(); - globals.Clear(); - registers.Clear(); - referenced_variables.clear(); -} - -int64_t Variables::GetNewVariableReference(bool is_permanent) { - if (is_permanent) - return next_permanent_var_ref++; - return next_temporary_var_ref++; -} - -bool Variables::IsPermanentVariableReference(int64_t var_ref) { - return var_ref >= PermanentVariableStartIndex; -} - -lldb::SBValue Variables::GetVariable(int64_t var_ref) const { - if (IsPermanentVariableReference(var_ref)) { - auto pos = referenced_permanent_variables.find(var_ref); - if (pos != referenced_permanent_variables.end()) - return pos->second; - } else { - auto pos = referenced_variables.find(var_ref); - if (pos != referenced_variables.end()) - return pos->second; - } - return lldb::SBValue(); -} - -int64_t Variables::InsertVariable(lldb::SBValue variable, bool is_permanent) { - int64_t var_ref = GetNewVariableReference(is_permanent); - if (is_permanent) - referenced_permanent_variables.insert(std::make_pair(var_ref, variable)); - else - referenced_variables.insert(std::make_pair(var_ref, variable)); - return var_ref; -} - bool StartDebuggingRequestHandler::DoExecute( lldb::SBDebugger debugger, char **command, lldb::SBCommandReturnObject &result) { @@ -1296,60 +1257,6 @@ DAP::GetInstructionBPFromStopReason(lldb::SBThread &thread) { return inst_bp; } -lldb::SBValueList *Variables::GetTopLevelScope(int64_t variablesReference) { - switch (variablesReference) { - case VARREF_LOCALS: - return &locals; - case VARREF_GLOBALS: - return &globals; - case VARREF_REGS: - return ®isters; - default: - return nullptr; - } -} - -lldb::SBValue Variables::FindVariable(uint64_t variablesReference, - llvm::StringRef name) { - lldb::SBValue variable; - if (lldb::SBValueList *top_scope = GetTopLevelScope(variablesReference)) { - bool is_duplicated_variable_name = name.contains(" @"); - // variablesReference is one of our scopes, not an actual variable it is - // asking for a variable in locals or globals or registers - int64_t end_idx = top_scope->GetSize(); - // Searching backward so that we choose the variable in closest scope - // among variables of the same name. - for (int64_t i = end_idx - 1; i >= 0; --i) { - lldb::SBValue curr_variable = top_scope->GetValueAtIndex(i); - std::string variable_name = CreateUniqueVariableNameForDisplay( - curr_variable, is_duplicated_variable_name); - if (variable_name == name) { - variable = curr_variable; - break; - } - } - } else { - // This is not under the globals or locals scope, so there are no - // duplicated names. - - // We have a named item within an actual variable so we need to find it - // withing the container variable by name. - lldb::SBValue container = GetVariable(variablesReference); - variable = container.GetChildMemberWithName(name.data()); - if (!variable.IsValid()) { - if (name.starts_with("[")) { - llvm::StringRef index_str(name.drop_front(1)); - uint64_t index = 0; - if (!index_str.consumeInteger(0, index)) { - if (index_str == "]") - variable = container.GetChildAtIndex(index); - } - } - } - } - return variable; -} - protocol::Capabilities DAP::GetCapabilities() { protocol::Capabilities capabilities; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 8f24c6cf82924..033203309b4c6 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -20,6 +20,7 @@ #include "Protocol/ProtocolTypes.h" #include "SourceBreakpoint.h" #include "Transport.h" +#include "Variables.h" #include "lldb/API/SBBroadcaster.h" #include "lldb/API/SBCommandInterpreter.h" #include "lldb/API/SBDebugger.h" @@ -30,8 +31,6 @@ #include "lldb/API/SBMutex.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" -#include "lldb/API/SBValue.h" -#include "lldb/API/SBValueList.h" #include "lldb/lldb-types.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" @@ -52,10 +51,6 @@ #include #include -#define VARREF_LOCALS (int64_t)1 -#define VARREF_GLOBALS (int64_t)2 -#define VARREF_REGS (int64_t)3 -#define VARREF_FIRST_VAR_IDX (int64_t)4 #define NO_TYPENAME "" namespace lldb_dap { @@ -88,50 +83,6 @@ enum class PacketStatus { enum class ReplMode { Variable = 0, Command, Auto }; -struct Variables { - /// Variable_reference start index of permanent expandable variable. - static constexpr int64_t PermanentVariableStartIndex = (1ll << 32); - - lldb::SBValueList locals; - lldb::SBValueList globals; - lldb::SBValueList registers; - - int64_t next_temporary_var_ref{VARREF_FIRST_VAR_IDX}; - int64_t next_permanent_var_ref{PermanentVariableStartIndex}; - - /// Variables that are alive in this stop state. - /// Will be cleared when debuggee resumes. - llvm::DenseMap referenced_variables; - /// Variables that persist across entire debug session. - /// These are the variables evaluated from debug console REPL. - llvm::DenseMap referenced_permanent_variables; - - /// Check if \p var_ref points to a variable that should persist for the - /// entire duration of the debug session, e.g. repl expandable variables - static bool IsPermanentVariableReference(int64_t var_ref); - - /// \return a new variableReference. - /// Specify is_permanent as true for variable that should persist entire - /// debug session. - int64_t GetNewVariableReference(bool is_permanent); - - /// \return the expandable variable corresponding with variableReference - /// value of \p value. - /// If \p var_ref is invalid an empty SBValue is returned. - lldb::SBValue GetVariable(int64_t var_ref) const; - - /// Insert a new \p variable. - /// \return variableReference assigned to this expandable variable. - int64_t InsertVariable(lldb::SBValue variable, bool is_permanent); - - lldb::SBValueList *GetTopLevelScope(int64_t variablesReference); - - lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef name); - - /// Clear all scope variables and non-permanent expandable variables. - void Clear(); -}; - struct StartDebuggingRequestHandler : public lldb::SBCommandPluginInterface { DAP &dap; explicit StartDebuggingRequestHandler(DAP &d) : dap(d) {}; diff --git a/lldb/tools/lldb-dap/Variables.cpp b/lldb/tools/lldb-dap/Variables.cpp new file mode 100644 index 0000000000000..777e3183d8c0d --- /dev/null +++ b/lldb/tools/lldb-dap/Variables.cpp @@ -0,0 +1,105 @@ +//===-- Variables.cpp ---------------------------------------------------*-===// +// +// 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 "Variables.h" +#include "JSONUtils.h" + +using namespace lldb_dap; + +lldb::SBValueList *Variables::GetTopLevelScope(int64_t variablesReference) { + switch (variablesReference) { + case VARREF_LOCALS: + return &locals; + case VARREF_GLOBALS: + return &globals; + case VARREF_REGS: + return ®isters; + default: + return nullptr; + } +} + +void Variables::Clear() { + locals.Clear(); + globals.Clear(); + registers.Clear(); + m_referencedvariables.clear(); +} + +int64_t Variables::GetNewVariableReference(bool is_permanent) { + if (is_permanent) + return m_next_permanent_var_ref++; + return m_next_temporary_var_ref++; +} + +bool Variables::IsPermanentVariableReference(int64_t var_ref) { + return var_ref >= PermanentVariableStartIndex; +} + +lldb::SBValue Variables::GetVariable(int64_t var_ref) const { + if (IsPermanentVariableReference(var_ref)) { + auto pos = m_referencedpermanent_variables.find(var_ref); + if (pos != m_referencedpermanent_variables.end()) + return pos->second; + } else { + auto pos = m_referencedvariables.find(var_ref); + if (pos != m_referencedvariables.end()) + return pos->second; + } + return lldb::SBValue(); +} + +int64_t Variables::InsertVariable(lldb::SBValue variable, bool is_permanent) { + int64_t var_ref = GetNewVariableReference(is_permanent); + if (is_permanent) + m_referencedpermanent_variables.insert(std::make_pair(var_ref, variable)); + else + m_referencedvariables.insert(std::make_pair(var_ref, variable)); + return var_ref; +} + +lldb::SBValue Variables::FindVariable(uint64_t variablesReference, + llvm::StringRef name) { + lldb::SBValue variable; + if (lldb::SBValueList *top_scope = GetTopLevelScope(variablesReference)) { + bool is_duplicated_variable_name = name.contains(" @"); + // variablesReference is one of our scopes, not an actual variable it is + // asking for a variable in locals or globals or registers + int64_t end_idx = top_scope->GetSize(); + // Searching backward so that we choose the variable in closest scope + // among variables of the same name. + for (int64_t i = end_idx - 1; i >= 0; --i) { + lldb::SBValue curr_variable = top_scope->GetValueAtIndex(i); + std::string variable_name = CreateUniqueVariableNameForDisplay( + curr_variable, is_duplicated_variable_name); + if (variable_name == name) { + variable = curr_variable; + break; + } + } + } else { + // This is not under the globals or locals scope, so there are no + // duplicated names. + + // We have a named item within an actual variable so we need to find it + // withing the container variable by name. + lldb::SBValue container = GetVariable(variablesReference); + variable = container.GetChildMemberWithName(name.data()); + if (!variable.IsValid()) { + if (name.starts_with("[")) { + llvm::StringRef index_str(name.drop_front(1)); + uint64_t index = 0; + if (!index_str.consumeInteger(0, index)) { + if (index_str == "]") + variable = container.GetChildAtIndex(index); + } + } + } + } + return variable; +} diff --git a/lldb/tools/lldb-dap/Variables.h b/lldb/tools/lldb-dap/Variables.h new file mode 100644 index 0000000000000..0ed84b36aef99 --- /dev/null +++ b/lldb/tools/lldb-dap/Variables.h @@ -0,0 +1,71 @@ +//===-- Variables.h -----------------------------------------------------*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TOOLS_LLDB_DAP_VARIABLES_H +#define LLDB_TOOLS_LLDB_DAP_VARIABLES_H + +#include "lldb/API/SBValue.h" +#include "lldb/API/SBValueList.h" +#include "llvm/ADT/DenseMap.h" + +#define VARREF_FIRST_VAR_IDX (int64_t)4 +#define VARREF_LOCALS (int64_t)1 +#define VARREF_GLOBALS (int64_t)2 +#define VARREF_REGS (int64_t)3 + +namespace lldb_dap { + +struct Variables { + lldb::SBValueList locals; + lldb::SBValueList globals; + lldb::SBValueList registers; + + /// Check if \p var_ref points to a variable that should persist for the + /// entire duration of the debug session, e.g. repl expandable variables + static bool IsPermanentVariableReference(int64_t var_ref); + + /// \return a new variableReference. + /// Specify is_permanent as true for variable that should persist entire + /// debug session. + int64_t GetNewVariableReference(bool is_permanent); + + /// \return the expandable variable corresponding with variableReference + /// value of \p value. + /// If \p var_ref is invalid an empty SBValue is returned. + lldb::SBValue GetVariable(int64_t var_ref) const; + + /// Insert a new \p variable. + /// \return variableReference assigned to this expandable variable. + int64_t InsertVariable(lldb::SBValue variable, bool is_permanent); + + lldb::SBValueList *GetTopLevelScope(int64_t variablesReference); + + lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef name); + + /// Clear all scope variables and non-permanent expandable variables. + void Clear(); + +private: + /// Variable_reference start index of permanent expandable variable. + static constexpr int64_t PermanentVariableStartIndex = (1ll << 32); + + /// Variables that are alive in this stop state. + /// Will be cleared when debuggee resumes. + llvm::DenseMap m_referencedvariables; + + /// Variables that persist across entire debug session. + /// These are the variables evaluated from debug console REPL. + llvm::DenseMap m_referencedpermanent_variables; + + int64_t m_next_temporary_var_ref{VARREF_FIRST_VAR_IDX}; + int64_t m_next_permanent_var_ref{PermanentVariableStartIndex}; +}; + +} // namespace lldb_dap + +#endif >From 62d94ae00b12006aacae7108f67a3b944fd97bdf Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Sat, 17 May 2025 11:58:48 -0700 Subject: [PATCH 2/3] Add Variables unit tests --- lldb/unittests/DAP/CMakeLists.txt | 1 + lldb/unittests/DAP/VariablesTest.cpp | 84 ++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 lldb/unittests/DAP/VariablesTest.cpp diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index af7d11e2e95e2..429a12e9fb505 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -6,6 +6,7 @@ add_lldb_unittest(DAPTests ProtocolTypesTest.cpp TestBase.cpp TransportTest.cpp + VariablesTest.cpp LINK_LIBS lldbDAP diff --git a/lldb/unittests/DAP/VariablesTest.cpp b/lldb/unittests/DAP/VariablesTest.cpp new file mode 100644 index 0000000000000..1ee98c0d1f8e0 --- /dev/null +++ b/lldb/unittests/DAP/VariablesTest.cpp @@ -0,0 +1,84 @@ +//===-- VariablesTest.cpp -------------------------------------------------===// +// +// 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 "Variables.h" +#include "lldb/API/SBValue.h" +#include "lldb/API/SBValueList.h" +#include "gtest/gtest.h" + +using namespace lldb_dap; + +class VariablesTest : public ::testing::Test { +protected: + Variables vars; +}; + +TEST_F(VariablesTest, GetNewVariableReference_UniqueAndRanges) { + const int64_t temp1 = vars.GetNewVariableReference(false); + const int64_t temp2 = vars.GetNewVariableReference(false); + const int64_t perm1 = vars.GetNewVariableReference(true); + const int64_t perm2 = vars.GetNewVariableReference(true); + + EXPECT_NE(temp1, temp2); + EXPECT_NE(perm1, perm2); + EXPECT_LT(temp1, perm1); + EXPECT_LT(temp2, perm1); +} + +TEST_F(VariablesTest, InsertAndGetVariable_Temporary) { + lldb::SBValue dummy; + const int64_t ref = vars.InsertVariable(dummy, false); + lldb::SBValue out = vars.GetVariable(ref); + + EXPECT_TRUE(out.IsValid() == dummy.IsValid()); +} + +TEST_F(VariablesTest, InsertAndGetVariable_Permanent) { + lldb::SBValue dummy; + const int64_t ref = vars.InsertVariable(dummy, true); + lldb::SBValue out = vars.GetVariable(ref); + + EXPECT_TRUE(out.IsValid() == dummy.IsValid()); +} + +TEST_F(VariablesTest, IsPermanentVariableReference) { + const int64_t perm = vars.GetNewVariableReference(true); + const int64_t temp = vars.GetNewVariableReference(false); + + EXPECT_TRUE(Variables::IsPermanentVariableReference(perm)); + EXPECT_FALSE(Variables::IsPermanentVariableReference(temp)); +} + +TEST_F(VariablesTest, Clear_RemovesTemporaryKeepsPermanent) { + lldb::SBValue dummy; + const int64_t temp = vars.InsertVariable(dummy, false); + const int64_t perm = vars.InsertVariable(dummy, true); + vars.Clear(); + + EXPECT_FALSE(vars.GetVariable(temp).IsValid()); + EXPECT_TRUE(vars.GetVariable(perm).IsValid() == dummy.IsValid()); +} + +TEST_F(VariablesTest, GetTopLevelScope_ReturnsCorrectScope) { + vars.locals.Append(lldb::SBValue()); + vars.globals.Append(lldb::SBValue()); + vars.registers.Append(lldb::SBValue()); + + EXPECT_EQ(vars.GetTopLevelScope(VARREF_LOCALS), &vars.locals); + EXPECT_EQ(vars.GetTopLevelScope(VARREF_GLOBALS), &vars.globals); + EXPECT_EQ(vars.GetTopLevelScope(VARREF_REGS), &vars.registers); + EXPECT_EQ(vars.GetTopLevelScope(9999), nullptr); +} + +TEST_F(VariablesTest, FindVariable_LocalsByName) { + lldb::SBValue dummy; + vars.locals.Append(dummy); + lldb::SBValue found = vars.FindVariable(VARREF_LOCALS, ""); + + EXPECT_TRUE(found.IsValid() == dummy.IsValid()); +} >From e3f677bd7b03ccd089731c6c6f0177bf990cd347 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Sat, 17 May 2025 12:03:18 -0700 Subject: [PATCH 3/3] Improve test readability --- lldb/unittests/DAP/VariablesTest.cpp | 29 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/lldb/unittests/DAP/VariablesTest.cpp b/lldb/unittests/DAP/VariablesTest.cpp index 1ee98c0d1f8e0..6b14fc6c3945d 100644 --- a/lldb/unittests/DAP/VariablesTest.cpp +++ b/lldb/unittests/DAP/VariablesTest.cpp @@ -15,14 +15,15 @@ using namespace lldb_dap; class VariablesTest : public ::testing::Test { protected: + enum : bool { Permanent = true, Temporary = false }; Variables vars; }; TEST_F(VariablesTest, GetNewVariableReference_UniqueAndRanges) { - const int64_t temp1 = vars.GetNewVariableReference(false); - const int64_t temp2 = vars.GetNewVariableReference(false); - const int64_t perm1 = vars.GetNewVariableReference(true); - const int64_t perm2 = vars.GetNewVariableReference(true); + const int64_t temp1 = vars.GetNewVariableReference(Temporary); + const int64_t temp2 = vars.GetNewVariableReference(Temporary); + const int64_t perm1 = vars.GetNewVariableReference(Permanent); + const int64_t perm2 = vars.GetNewVariableReference(Permanent); EXPECT_NE(temp1, temp2); EXPECT_NE(perm1, perm2); @@ -32,23 +33,23 @@ TEST_F(VariablesTest, GetNewVariableReference_UniqueAndRanges) { TEST_F(VariablesTest, InsertAndGetVariable_Temporary) { lldb::SBValue dummy; - const int64_t ref = vars.InsertVariable(dummy, false); + const int64_t ref = vars.InsertVariable(dummy, Temporary); lldb::SBValue out = vars.GetVariable(ref); - EXPECT_TRUE(out.IsValid() == dummy.IsValid()); + EXPECT_EQ(out.IsValid(), dummy.IsValid()); } TEST_F(VariablesTest, InsertAndGetVariable_Permanent) { lldb::SBValue dummy; - const int64_t ref = vars.InsertVariable(dummy, true); + const int64_t ref = vars.InsertVariable(dummy, Permanent); lldb::SBValue out = vars.GetVariable(ref); - EXPECT_TRUE(out.IsValid() == dummy.IsValid()); + EXPECT_EQ(out.IsValid(), dummy.IsValid()); } TEST_F(VariablesTest, IsPermanentVariableReference) { - const int64_t perm = vars.GetNewVariableReference(true); - const int64_t temp = vars.GetNewVariableReference(false); + const int64_t perm = vars.GetNewVariableReference(Permanent); + const int64_t temp = vars.GetNewVariableReference(Temporary); EXPECT_TRUE(Variables::IsPermanentVariableReference(perm)); EXPECT_FALSE(Variables::IsPermanentVariableReference(temp)); @@ -56,12 +57,12 @@ TEST_F(VariablesTest, IsPermanentVariableReference) { TEST_F(VariablesTest, Clear_RemovesTemporaryKeepsPermanent) { lldb::SBValue dummy; - const int64_t temp = vars.InsertVariable(dummy, false); - const int64_t perm = vars.InsertVariable(dummy, true); + const int64_t temp = vars.InsertVariable(dummy, Temporary); + const int64_t perm = vars.InsertVariable(dummy, Permanent); vars.Clear(); EXPECT_FALSE(vars.GetVariable(temp).IsValid()); - EXPECT_TRUE(vars.GetVariable(perm).IsValid() == dummy.IsValid()); + EXPECT_EQ(vars.GetVariable(perm).IsValid(), dummy.IsValid()); } TEST_F(VariablesTest, GetTopLevelScope_ReturnsCorrectScope) { @@ -80,5 +81,5 @@ TEST_F(VariablesTest, FindVariable_LocalsByName) { vars.locals.Append(dummy); lldb::SBValue found = vars.FindVariable(VARREF_LOCALS, ""); - EXPECT_TRUE(found.IsValid() == dummy.IsValid()); + EXPECT_EQ(found.IsValid(), dummy.IsValid()); } From lldb-commits at lists.llvm.org Sat May 17 12:24:27 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sat, 17 May 2025 12:24:27 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Move the command plugins out of the DAP header (PR #140396) Message-ID: https://github.com/JDevlieghere created https://github.com/llvm/llvm-project/pull/140396 Move the command plugins out of the DAP header and into their file. This PR also renames the classes from "RequestHandler" to "Command". Although they are implemented in terms of sending requests, they are not "handlers". >From 2b1f57010f2377a588867c509afb921cd0ccdd71 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Sat, 17 May 2025 12:20:15 -0700 Subject: [PATCH] [lldb-dap] Move the command plugins out of the DAP header Move the command plugins out of the DAP header and into their file. This PR also renames the classes from "RequestHandler" to "Command". Although they are implemented in terms of sending requests, they are not "handlers". --- lldb/tools/lldb-dap/CMakeLists.txt | 1 + lldb/tools/lldb-dap/CommandPlugins.cpp | 163 ++++++++++++++++++ lldb/tools/lldb-dap/CommandPlugins.h | 40 +++++ lldb/tools/lldb-dap/DAP.cpp | 153 ---------------- lldb/tools/lldb-dap/DAP.h | 21 --- .../Handler/InitializeRequestHandler.cpp | 7 +- 6 files changed, 208 insertions(+), 177 deletions(-) create mode 100644 lldb/tools/lldb-dap/CommandPlugins.cpp create mode 100644 lldb/tools/lldb-dap/CommandPlugins.h diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 5dedee8a87f41..97cdf23484ea0 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -8,6 +8,7 @@ add_public_tablegen_target(LLDBDAPOptionsTableGen) add_lldb_library(lldbDAP Breakpoint.cpp BreakpointBase.cpp + CommandPlugins.cpp DAP.cpp DAPError.cpp DAPLog.cpp diff --git a/lldb/tools/lldb-dap/CommandPlugins.cpp b/lldb/tools/lldb-dap/CommandPlugins.cpp new file mode 100644 index 0000000000000..4e7aa029e0f22 --- /dev/null +++ b/lldb/tools/lldb-dap/CommandPlugins.cpp @@ -0,0 +1,163 @@ +//===-- CommandPlugins.cpp ------------------------------------------------===// +// +// 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 "CommandPlugins.h" +#include "Handler/ResponseHandler.h" +#include "JSONUtils.h" +#include "lldb/API/SBStream.h" + +using namespace lldb_dap; + +bool StartDebuggingCommand::DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) { + // Command format like: `start-debugging ` + if (!command) { + result.SetError("Invalid use of start-debugging, expected format " + "`start-debugging `."); + return false; + } + + if (!command[0] || llvm::StringRef(command[0]).empty()) { + result.SetError("start-debugging request type missing."); + return false; + } + + if (!command[1] || llvm::StringRef(command[1]).empty()) { + result.SetError("start-debugging debug configuration missing."); + return false; + } + + llvm::StringRef request{command[0]}; + std::string raw_configuration{command[1]}; + + llvm::Expected configuration = + llvm::json::parse(raw_configuration); + + if (!configuration) { + llvm::Error err = configuration.takeError(); + std::string msg = "Failed to parse json configuration: " + + llvm::toString(std::move(err)) + "\n\n" + + raw_configuration; + result.SetError(msg.c_str()); + return false; + } + + dap.SendReverseRequest( + "startDebugging", + llvm::json::Object{{"request", request}, + {"configuration", std::move(*configuration)}}); + + result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); + + return true; +} + +bool ReplModeCommand::DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) { + // Command format like: `repl-mode ?` + // If a new mode is not specified report the current mode. + if (!command || llvm::StringRef(command[0]).empty()) { + std::string mode; + switch (dap.repl_mode) { + case ReplMode::Variable: + mode = "variable"; + break; + case ReplMode::Command: + mode = "command"; + break; + case ReplMode::Auto: + mode = "auto"; + break; + } + + result.Printf("lldb-dap repl-mode %s.\n", mode.c_str()); + result.SetStatus(lldb::eReturnStatusSuccessFinishResult); + + return true; + } + + llvm::StringRef new_mode{command[0]}; + + if (new_mode == "variable") { + dap.repl_mode = ReplMode::Variable; + } else if (new_mode == "command") { + dap.repl_mode = ReplMode::Command; + } else if (new_mode == "auto") { + dap.repl_mode = ReplMode::Auto; + } else { + lldb::SBStream error_message; + error_message.Printf("Invalid repl-mode '%s'. Expected one of 'variable', " + "'command' or 'auto'.\n", + new_mode.data()); + result.SetError(error_message.GetData()); + return false; + } + + result.Printf("lldb-dap repl-mode %s set.\n", new_mode.data()); + result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); + return true; +} + +/// Sends a DAP event with an optional body. +/// +/// https://code.visualstudio.com/api/references/vscode-api#debug.onDidReceiveDebugSessionCustomEvent +bool SendEventCommand::DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) { + // Command format like: `send-event ?` + if (!command || !command[0] || llvm::StringRef(command[0]).empty()) { + result.SetError("Not enough arguments found, expected format " + "`lldb-dap send-event ?`."); + return false; + } + + llvm::StringRef name{command[0]}; + // Events that are stateful and should be handled by lldb-dap internally. + const std::array internal_events{"breakpoint", "capabilities", "continued", + "exited", "initialize", "loadedSource", + "module", "process", "stopped", + "terminated", "thread"}; + if (llvm::is_contained(internal_events, name)) { + std::string msg = + llvm::formatv("Invalid use of lldb-dap send-event, event \"{0}\" " + "should be handled by lldb-dap internally.", + name) + .str(); + result.SetError(msg.c_str()); + return false; + } + + llvm::json::Object event(CreateEventObject(name)); + + if (command[1] && !llvm::StringRef(command[1]).empty()) { + // See if we have unused arguments. + if (command[2]) { + result.SetError( + "Additional arguments found, expected `lldb-dap send-event " + " ?`."); + return false; + } + + llvm::StringRef raw_body{command[1]}; + + llvm::Expected body = llvm::json::parse(raw_body); + + if (!body) { + llvm::Error err = body.takeError(); + std::string msg = "Failed to parse custom event body: " + + llvm::toString(std::move(err)); + result.SetError(msg.c_str()); + return false; + } + + event.try_emplace("body", std::move(*body)); + } + + dap.SendJSON(llvm::json::Value(std::move(event))); + result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); + return true; +} diff --git a/lldb/tools/lldb-dap/CommandPlugins.h b/lldb/tools/lldb-dap/CommandPlugins.h new file mode 100644 index 0000000000000..011c7fd2da2a1 --- /dev/null +++ b/lldb/tools/lldb-dap/CommandPlugins.h @@ -0,0 +1,40 @@ +//===-- CommandPlugins.h --------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TOOLS_LLDB_DAP_COMMANDPLUGINS_H +#define LLDB_TOOLS_LLDB_DAP_COMMANDPLUGINS_H + +#include "DAP.h" +#include "lldb/API/SBCommandInterpreter.h" + +namespace lldb_dap { + +struct StartDebuggingCommand : public lldb::SBCommandPluginInterface { + DAP &dap; + explicit StartDebuggingCommand(DAP &d) : dap(d) {}; + bool DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) override; +}; + +struct ReplModeCommand : public lldb::SBCommandPluginInterface { + DAP &dap; + explicit ReplModeCommand(DAP &d) : dap(d) {}; + bool DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) override; +}; + +struct SendEventCommand : public lldb::SBCommandPluginInterface { + DAP &dap; + explicit SendEventCommand(DAP &d) : dap(d) {}; + bool DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) override; +}; + +} // namespace lldb_dap + +#endif diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 0d5eba6c40961..a24d63c9ae97f 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1060,159 +1060,6 @@ int64_t Variables::InsertVariable(lldb::SBValue variable, bool is_permanent) { return var_ref; } -bool StartDebuggingRequestHandler::DoExecute( - lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) { - // Command format like: `start-debugging ` - if (!command) { - result.SetError("Invalid use of start-debugging, expected format " - "`start-debugging `."); - return false; - } - - if (!command[0] || llvm::StringRef(command[0]).empty()) { - result.SetError("start-debugging request type missing."); - return false; - } - - if (!command[1] || llvm::StringRef(command[1]).empty()) { - result.SetError("start-debugging debug configuration missing."); - return false; - } - - llvm::StringRef request{command[0]}; - std::string raw_configuration{command[1]}; - - llvm::Expected configuration = - llvm::json::parse(raw_configuration); - - if (!configuration) { - llvm::Error err = configuration.takeError(); - std::string msg = "Failed to parse json configuration: " + - llvm::toString(std::move(err)) + "\n\n" + - raw_configuration; - result.SetError(msg.c_str()); - return false; - } - - dap.SendReverseRequest( - "startDebugging", - llvm::json::Object{{"request", request}, - {"configuration", std::move(*configuration)}}); - - result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); - - return true; -} - -bool ReplModeRequestHandler::DoExecute(lldb::SBDebugger debugger, - char **command, - lldb::SBCommandReturnObject &result) { - // Command format like: `repl-mode ?` - // If a new mode is not specified report the current mode. - if (!command || llvm::StringRef(command[0]).empty()) { - std::string mode; - switch (dap.repl_mode) { - case ReplMode::Variable: - mode = "variable"; - break; - case ReplMode::Command: - mode = "command"; - break; - case ReplMode::Auto: - mode = "auto"; - break; - } - - result.Printf("lldb-dap repl-mode %s.\n", mode.c_str()); - result.SetStatus(lldb::eReturnStatusSuccessFinishResult); - - return true; - } - - llvm::StringRef new_mode{command[0]}; - - if (new_mode == "variable") { - dap.repl_mode = ReplMode::Variable; - } else if (new_mode == "command") { - dap.repl_mode = ReplMode::Command; - } else if (new_mode == "auto") { - dap.repl_mode = ReplMode::Auto; - } else { - lldb::SBStream error_message; - error_message.Printf("Invalid repl-mode '%s'. Expected one of 'variable', " - "'command' or 'auto'.\n", - new_mode.data()); - result.SetError(error_message.GetData()); - return false; - } - - result.Printf("lldb-dap repl-mode %s set.\n", new_mode.data()); - result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); - return true; -} - -// Sends a DAP event with an optional body. -// -// See -// https://code.visualstudio.com/api/references/vscode-api#debug.onDidReceiveDebugSessionCustomEvent -bool SendEventRequestHandler::DoExecute(lldb::SBDebugger debugger, - char **command, - lldb::SBCommandReturnObject &result) { - // Command format like: `send-event ?` - if (!command || !command[0] || llvm::StringRef(command[0]).empty()) { - result.SetError("Not enough arguments found, expected format " - "`lldb-dap send-event ?`."); - return false; - } - - llvm::StringRef name{command[0]}; - // Events that are stateful and should be handled by lldb-dap internally. - const std::array internal_events{"breakpoint", "capabilities", "continued", - "exited", "initialize", "loadedSource", - "module", "process", "stopped", - "terminated", "thread"}; - if (llvm::is_contained(internal_events, name)) { - std::string msg = - llvm::formatv("Invalid use of lldb-dap send-event, event \"{0}\" " - "should be handled by lldb-dap internally.", - name) - .str(); - result.SetError(msg.c_str()); - return false; - } - - llvm::json::Object event(CreateEventObject(name)); - - if (command[1] && !llvm::StringRef(command[1]).empty()) { - // See if we have unused arguments. - if (command[2]) { - result.SetError( - "Additional arguments found, expected `lldb-dap send-event " - " ?`."); - return false; - } - - llvm::StringRef raw_body{command[1]}; - - llvm::Expected body = llvm::json::parse(raw_body); - - if (!body) { - llvm::Error err = body.takeError(); - std::string msg = "Failed to parse custom event body: " + - llvm::toString(std::move(err)); - result.SetError(msg.c_str()); - return false; - } - - event.try_emplace("body", std::move(*body)); - } - - dap.SendJSON(llvm::json::Value(std::move(event))); - result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); - return true; -} - void DAP::ConfigureSourceMaps() { if (configuration.sourceMap.empty() && configuration.sourcePath.empty()) return; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 8f24c6cf82924..990a02889fef3 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -132,27 +132,6 @@ struct Variables { void Clear(); }; -struct StartDebuggingRequestHandler : public lldb::SBCommandPluginInterface { - DAP &dap; - explicit StartDebuggingRequestHandler(DAP &d) : dap(d) {}; - bool DoExecute(lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) override; -}; - -struct ReplModeRequestHandler : public lldb::SBCommandPluginInterface { - DAP &dap; - explicit ReplModeRequestHandler(DAP &d) : dap(d) {}; - bool DoExecute(lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) override; -}; - -struct SendEventRequestHandler : public lldb::SBCommandPluginInterface { - DAP &dap; - explicit SendEventRequestHandler(DAP &d) : dap(d) {}; - bool DoExecute(lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) override; -}; - struct DAP { /// Path to the lldb-dap binary itself. static llvm::StringRef debug_adapter_path; diff --git a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp index 0a178406b5a69..dcd02d61ca4f4 100644 --- a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "CommandPlugins.h" #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" @@ -59,14 +60,14 @@ llvm::Expected InitializeRequestHandler::Run( if (arguments.supportedFeatures.contains( eClientFeatureStartDebuggingRequest)) { cmd.AddCommand( - "start-debugging", new StartDebuggingRequestHandler(dap), + "start-debugging", new StartDebuggingCommand(dap), "Sends a startDebugging request from the debug adapter to the client " "to start a child debug session of the same type as the caller."); } cmd.AddCommand( - "repl-mode", new ReplModeRequestHandler(dap), + "repl-mode", new ReplModeCommand(dap), "Get or set the repl behavior of lldb-dap evaluation requests."); - cmd.AddCommand("send-event", new SendEventRequestHandler(dap), + cmd.AddCommand("send-event", new SendEventCommand(dap), "Sends an DAP event to the client."); if (arguments.supportedFeatures.contains(eClientFeatureProgressReporting)) From lldb-commits at lists.llvm.org Sat May 17 12:25:01 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sat, 17 May 2025 12:25:01 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Move the command plugins out of the DAP header (PR #140396) In-Reply-To: Message-ID: <6828e28d.050a0220.140010.9c7d@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Jonas Devlieghere (JDevlieghere)
Changes Move the command plugins out of the DAP header and into their file. This PR also renames the classes from "RequestHandler" to "Command". Although they are implemented in terms of sending requests, they are not "handlers". --- Full diff: https://github.com/llvm/llvm-project/pull/140396.diff 6 Files Affected: - (modified) lldb/tools/lldb-dap/CMakeLists.txt (+1) - (added) lldb/tools/lldb-dap/CommandPlugins.cpp (+163) - (added) lldb/tools/lldb-dap/CommandPlugins.h (+40) - (modified) lldb/tools/lldb-dap/DAP.cpp (-153) - (modified) lldb/tools/lldb-dap/DAP.h (-21) - (modified) lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp (+4-3) ``````````diff diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 5dedee8a87f41..97cdf23484ea0 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -8,6 +8,7 @@ add_public_tablegen_target(LLDBDAPOptionsTableGen) add_lldb_library(lldbDAP Breakpoint.cpp BreakpointBase.cpp + CommandPlugins.cpp DAP.cpp DAPError.cpp DAPLog.cpp diff --git a/lldb/tools/lldb-dap/CommandPlugins.cpp b/lldb/tools/lldb-dap/CommandPlugins.cpp new file mode 100644 index 0000000000000..4e7aa029e0f22 --- /dev/null +++ b/lldb/tools/lldb-dap/CommandPlugins.cpp @@ -0,0 +1,163 @@ +//===-- CommandPlugins.cpp ------------------------------------------------===// +// +// 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 "CommandPlugins.h" +#include "Handler/ResponseHandler.h" +#include "JSONUtils.h" +#include "lldb/API/SBStream.h" + +using namespace lldb_dap; + +bool StartDebuggingCommand::DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) { + // Command format like: `start-debugging ` + if (!command) { + result.SetError("Invalid use of start-debugging, expected format " + "`start-debugging `."); + return false; + } + + if (!command[0] || llvm::StringRef(command[0]).empty()) { + result.SetError("start-debugging request type missing."); + return false; + } + + if (!command[1] || llvm::StringRef(command[1]).empty()) { + result.SetError("start-debugging debug configuration missing."); + return false; + } + + llvm::StringRef request{command[0]}; + std::string raw_configuration{command[1]}; + + llvm::Expected configuration = + llvm::json::parse(raw_configuration); + + if (!configuration) { + llvm::Error err = configuration.takeError(); + std::string msg = "Failed to parse json configuration: " + + llvm::toString(std::move(err)) + "\n\n" + + raw_configuration; + result.SetError(msg.c_str()); + return false; + } + + dap.SendReverseRequest( + "startDebugging", + llvm::json::Object{{"request", request}, + {"configuration", std::move(*configuration)}}); + + result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); + + return true; +} + +bool ReplModeCommand::DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) { + // Command format like: `repl-mode ?` + // If a new mode is not specified report the current mode. + if (!command || llvm::StringRef(command[0]).empty()) { + std::string mode; + switch (dap.repl_mode) { + case ReplMode::Variable: + mode = "variable"; + break; + case ReplMode::Command: + mode = "command"; + break; + case ReplMode::Auto: + mode = "auto"; + break; + } + + result.Printf("lldb-dap repl-mode %s.\n", mode.c_str()); + result.SetStatus(lldb::eReturnStatusSuccessFinishResult); + + return true; + } + + llvm::StringRef new_mode{command[0]}; + + if (new_mode == "variable") { + dap.repl_mode = ReplMode::Variable; + } else if (new_mode == "command") { + dap.repl_mode = ReplMode::Command; + } else if (new_mode == "auto") { + dap.repl_mode = ReplMode::Auto; + } else { + lldb::SBStream error_message; + error_message.Printf("Invalid repl-mode '%s'. Expected one of 'variable', " + "'command' or 'auto'.\n", + new_mode.data()); + result.SetError(error_message.GetData()); + return false; + } + + result.Printf("lldb-dap repl-mode %s set.\n", new_mode.data()); + result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); + return true; +} + +/// Sends a DAP event with an optional body. +/// +/// https://code.visualstudio.com/api/references/vscode-api#debug.onDidReceiveDebugSessionCustomEvent +bool SendEventCommand::DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) { + // Command format like: `send-event ?` + if (!command || !command[0] || llvm::StringRef(command[0]).empty()) { + result.SetError("Not enough arguments found, expected format " + "`lldb-dap send-event ?`."); + return false; + } + + llvm::StringRef name{command[0]}; + // Events that are stateful and should be handled by lldb-dap internally. + const std::array internal_events{"breakpoint", "capabilities", "continued", + "exited", "initialize", "loadedSource", + "module", "process", "stopped", + "terminated", "thread"}; + if (llvm::is_contained(internal_events, name)) { + std::string msg = + llvm::formatv("Invalid use of lldb-dap send-event, event \"{0}\" " + "should be handled by lldb-dap internally.", + name) + .str(); + result.SetError(msg.c_str()); + return false; + } + + llvm::json::Object event(CreateEventObject(name)); + + if (command[1] && !llvm::StringRef(command[1]).empty()) { + // See if we have unused arguments. + if (command[2]) { + result.SetError( + "Additional arguments found, expected `lldb-dap send-event " + " ?`."); + return false; + } + + llvm::StringRef raw_body{command[1]}; + + llvm::Expected body = llvm::json::parse(raw_body); + + if (!body) { + llvm::Error err = body.takeError(); + std::string msg = "Failed to parse custom event body: " + + llvm::toString(std::move(err)); + result.SetError(msg.c_str()); + return false; + } + + event.try_emplace("body", std::move(*body)); + } + + dap.SendJSON(llvm::json::Value(std::move(event))); + result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); + return true; +} diff --git a/lldb/tools/lldb-dap/CommandPlugins.h b/lldb/tools/lldb-dap/CommandPlugins.h new file mode 100644 index 0000000000000..011c7fd2da2a1 --- /dev/null +++ b/lldb/tools/lldb-dap/CommandPlugins.h @@ -0,0 +1,40 @@ +//===-- CommandPlugins.h --------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TOOLS_LLDB_DAP_COMMANDPLUGINS_H +#define LLDB_TOOLS_LLDB_DAP_COMMANDPLUGINS_H + +#include "DAP.h" +#include "lldb/API/SBCommandInterpreter.h" + +namespace lldb_dap { + +struct StartDebuggingCommand : public lldb::SBCommandPluginInterface { + DAP &dap; + explicit StartDebuggingCommand(DAP &d) : dap(d) {}; + bool DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) override; +}; + +struct ReplModeCommand : public lldb::SBCommandPluginInterface { + DAP &dap; + explicit ReplModeCommand(DAP &d) : dap(d) {}; + bool DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) override; +}; + +struct SendEventCommand : public lldb::SBCommandPluginInterface { + DAP &dap; + explicit SendEventCommand(DAP &d) : dap(d) {}; + bool DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) override; +}; + +} // namespace lldb_dap + +#endif diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 0d5eba6c40961..a24d63c9ae97f 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1060,159 +1060,6 @@ int64_t Variables::InsertVariable(lldb::SBValue variable, bool is_permanent) { return var_ref; } -bool StartDebuggingRequestHandler::DoExecute( - lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) { - // Command format like: `start-debugging ` - if (!command) { - result.SetError("Invalid use of start-debugging, expected format " - "`start-debugging `."); - return false; - } - - if (!command[0] || llvm::StringRef(command[0]).empty()) { - result.SetError("start-debugging request type missing."); - return false; - } - - if (!command[1] || llvm::StringRef(command[1]).empty()) { - result.SetError("start-debugging debug configuration missing."); - return false; - } - - llvm::StringRef request{command[0]}; - std::string raw_configuration{command[1]}; - - llvm::Expected configuration = - llvm::json::parse(raw_configuration); - - if (!configuration) { - llvm::Error err = configuration.takeError(); - std::string msg = "Failed to parse json configuration: " + - llvm::toString(std::move(err)) + "\n\n" + - raw_configuration; - result.SetError(msg.c_str()); - return false; - } - - dap.SendReverseRequest( - "startDebugging", - llvm::json::Object{{"request", request}, - {"configuration", std::move(*configuration)}}); - - result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); - - return true; -} - -bool ReplModeRequestHandler::DoExecute(lldb::SBDebugger debugger, - char **command, - lldb::SBCommandReturnObject &result) { - // Command format like: `repl-mode ?` - // If a new mode is not specified report the current mode. - if (!command || llvm::StringRef(command[0]).empty()) { - std::string mode; - switch (dap.repl_mode) { - case ReplMode::Variable: - mode = "variable"; - break; - case ReplMode::Command: - mode = "command"; - break; - case ReplMode::Auto: - mode = "auto"; - break; - } - - result.Printf("lldb-dap repl-mode %s.\n", mode.c_str()); - result.SetStatus(lldb::eReturnStatusSuccessFinishResult); - - return true; - } - - llvm::StringRef new_mode{command[0]}; - - if (new_mode == "variable") { - dap.repl_mode = ReplMode::Variable; - } else if (new_mode == "command") { - dap.repl_mode = ReplMode::Command; - } else if (new_mode == "auto") { - dap.repl_mode = ReplMode::Auto; - } else { - lldb::SBStream error_message; - error_message.Printf("Invalid repl-mode '%s'. Expected one of 'variable', " - "'command' or 'auto'.\n", - new_mode.data()); - result.SetError(error_message.GetData()); - return false; - } - - result.Printf("lldb-dap repl-mode %s set.\n", new_mode.data()); - result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); - return true; -} - -// Sends a DAP event with an optional body. -// -// See -// https://code.visualstudio.com/api/references/vscode-api#debug.onDidReceiveDebugSessionCustomEvent -bool SendEventRequestHandler::DoExecute(lldb::SBDebugger debugger, - char **command, - lldb::SBCommandReturnObject &result) { - // Command format like: `send-event ?` - if (!command || !command[0] || llvm::StringRef(command[0]).empty()) { - result.SetError("Not enough arguments found, expected format " - "`lldb-dap send-event ?`."); - return false; - } - - llvm::StringRef name{command[0]}; - // Events that are stateful and should be handled by lldb-dap internally. - const std::array internal_events{"breakpoint", "capabilities", "continued", - "exited", "initialize", "loadedSource", - "module", "process", "stopped", - "terminated", "thread"}; - if (llvm::is_contained(internal_events, name)) { - std::string msg = - llvm::formatv("Invalid use of lldb-dap send-event, event \"{0}\" " - "should be handled by lldb-dap internally.", - name) - .str(); - result.SetError(msg.c_str()); - return false; - } - - llvm::json::Object event(CreateEventObject(name)); - - if (command[1] && !llvm::StringRef(command[1]).empty()) { - // See if we have unused arguments. - if (command[2]) { - result.SetError( - "Additional arguments found, expected `lldb-dap send-event " - " ?`."); - return false; - } - - llvm::StringRef raw_body{command[1]}; - - llvm::Expected body = llvm::json::parse(raw_body); - - if (!body) { - llvm::Error err = body.takeError(); - std::string msg = "Failed to parse custom event body: " + - llvm::toString(std::move(err)); - result.SetError(msg.c_str()); - return false; - } - - event.try_emplace("body", std::move(*body)); - } - - dap.SendJSON(llvm::json::Value(std::move(event))); - result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); - return true; -} - void DAP::ConfigureSourceMaps() { if (configuration.sourceMap.empty() && configuration.sourcePath.empty()) return; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 8f24c6cf82924..990a02889fef3 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -132,27 +132,6 @@ struct Variables { void Clear(); }; -struct StartDebuggingRequestHandler : public lldb::SBCommandPluginInterface { - DAP &dap; - explicit StartDebuggingRequestHandler(DAP &d) : dap(d) {}; - bool DoExecute(lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) override; -}; - -struct ReplModeRequestHandler : public lldb::SBCommandPluginInterface { - DAP &dap; - explicit ReplModeRequestHandler(DAP &d) : dap(d) {}; - bool DoExecute(lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) override; -}; - -struct SendEventRequestHandler : public lldb::SBCommandPluginInterface { - DAP &dap; - explicit SendEventRequestHandler(DAP &d) : dap(d) {}; - bool DoExecute(lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) override; -}; - struct DAP { /// Path to the lldb-dap binary itself. static llvm::StringRef debug_adapter_path; diff --git a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp index 0a178406b5a69..dcd02d61ca4f4 100644 --- a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "CommandPlugins.h" #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" @@ -59,14 +60,14 @@ llvm::Expected InitializeRequestHandler::Run( if (arguments.supportedFeatures.contains( eClientFeatureStartDebuggingRequest)) { cmd.AddCommand( - "start-debugging", new StartDebuggingRequestHandler(dap), + "start-debugging", new StartDebuggingCommand(dap), "Sends a startDebugging request from the debug adapter to the client " "to start a child debug session of the same type as the caller."); } cmd.AddCommand( - "repl-mode", new ReplModeRequestHandler(dap), + "repl-mode", new ReplModeCommand(dap), "Get or set the repl behavior of lldb-dap evaluation requests."); - cmd.AddCommand("send-event", new SendEventRequestHandler(dap), + cmd.AddCommand("send-event", new SendEventCommand(dap), "Sends an DAP event to the client."); if (arguments.supportedFeatures.contains(eClientFeatureProgressReporting)) ``````````
https://github.com/llvm/llvm-project/pull/140396 From lldb-commits at lists.llvm.org Sat May 17 12:59:10 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sat, 17 May 2025 12:59:10 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add field member operators to DIL (PR #138093) In-Reply-To: Message-ID: <6828ea8e.a70a0220.42a85.a0ea@mx.google.com> https://github.com/cmtice updated https://github.com/llvm/llvm-project/pull/138093 >From fe9ac0fa05bb43ea718214746f0ea9b7eefc929a Mon Sep 17 00:00:00 2001 From: Caroline Tice Date: Thu, 1 May 2025 00:05:57 -0700 Subject: [PATCH 1/4] [LLDB] Add field member operators to DIL Add the arrow and period operators, allowing DIL to find and access member fields. --- lldb/docs/dil-expr-lang.ebnf | 10 +- lldb/include/lldb/ValueObject/DILAST.h | 26 +++ lldb/include/lldb/ValueObject/DILEval.h | 8 + lldb/include/lldb/ValueObject/DILLexer.h | 2 + lldb/include/lldb/ValueObject/DILParser.h | 1 + lldb/source/ValueObject/DILAST.cpp | 4 + lldb/source/ValueObject/DILEval.cpp | 200 ++++++++++++++++++ lldb/source/ValueObject/DILLexer.cpp | 9 +- lldb/source/ValueObject/DILParser.cpp | 27 ++- .../frame/var-dil/basics/MemberOf/Makefile | 3 + .../MemberOf/TestFrameVarDILMemberOf.py | 47 ++++ .../frame/var-dil/basics/MemberOf/main.cpp | 59 ++++++ .../basics/MemberOfAnonymousMember/Makefile | 3 + .../TestFrameVarDILMemberOfAnonymousMember.py | 62 ++++++ .../basics/MemberOfAnonymousMember/main.cpp | 74 +++++++ .../basics/MemberOfInheritance/Makefile | 3 + .../TestFrameVarDILMemberOfInheritance.py | 49 +++++ .../basics/MemberOfInheritance/main.cpp | 87 ++++++++ 18 files changed, 666 insertions(+), 8 deletions(-) create mode 100644 lldb/test/API/commands/frame/var-dil/basics/MemberOf/Makefile create mode 100644 lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py create mode 100644 lldb/test/API/commands/frame/var-dil/basics/MemberOf/main.cpp create mode 100644 lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/Makefile create mode 100644 lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/TestFrameVarDILMemberOfAnonymousMember.py create mode 100644 lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/main.cpp create mode 100644 lldb/test/API/commands/frame/var-dil/basics/MemberOfInheritance/Makefile create mode 100644 lldb/test/API/commands/frame/var-dil/basics/MemberOfInheritance/TestFrameVarDILMemberOfInheritance.py create mode 100644 lldb/test/API/commands/frame/var-dil/basics/MemberOfInheritance/main.cpp diff --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf index c8bf4231b3e4a..580626862c005 100644 --- a/lldb/docs/dil-expr-lang.ebnf +++ b/lldb/docs/dil-expr-lang.ebnf @@ -5,13 +5,17 @@ expression = unary_expression ; -unary_expression = unary_operator expression - | primary_expression ; +unary_expression = postfix_expression + | unary_operator expression ; unary_operator = "*" | "&" ; +postfix_expresson = primary_expression + | postfix_expression "." id_expression + | postfix_expression "->" id_expression ; + primary_expression = id_expression - | "(" expression ")"; + | "(" expression ")" ; id_expression = unqualified_id | qualified_id diff --git a/lldb/include/lldb/ValueObject/DILAST.h b/lldb/include/lldb/ValueObject/DILAST.h index fe3827ef0516a..a74a12bd8be9d 100644 --- a/lldb/include/lldb/ValueObject/DILAST.h +++ b/lldb/include/lldb/ValueObject/DILAST.h @@ -20,6 +20,7 @@ namespace lldb_private::dil { enum class NodeKind { eErrorNode, eIdentifierNode, + eMemberOfNode, eUnaryOpNode, }; @@ -88,6 +89,29 @@ class IdentifierNode : public ASTNode { std::string m_name; }; +class MemberOfNode : public ASTNode { +public: + MemberOfNode(uint32_t location, ASTNodeUP base, bool is_arrow, + ConstString name) + : ASTNode(location, NodeKind::eMemberOfNode), m_base(std::move(base)), + m_is_arrow(is_arrow), m_field_name(name) { } + + llvm::Expected Accept(Visitor *v) const override; + + ASTNode *base() const { return m_base.get(); } + bool IsArrow() const { return m_is_arrow; } + ConstString FieldName() const { return m_field_name; } + + static bool classof(const ASTNode *node) { + return node->GetKind() == NodeKind::eMemberOfNode; + } + +private: + ASTNodeUP m_base; + bool m_is_arrow; + ConstString m_field_name; +}; + class UnaryOpNode : public ASTNode { public: UnaryOpNode(uint32_t location, UnaryOpKind kind, ASTNodeUP operand) @@ -118,6 +142,8 @@ class Visitor { virtual llvm::Expected Visit(const IdentifierNode *node) = 0; virtual llvm::Expected + Visit(const MemberOfNode *node) = 0; + virtual llvm::Expected Visit(const UnaryOpNode *node) = 0; }; diff --git a/lldb/include/lldb/ValueObject/DILEval.h b/lldb/include/lldb/ValueObject/DILEval.h index b1dd3fdb49739..053daffaa41f2 100644 --- a/lldb/include/lldb/ValueObject/DILEval.h +++ b/lldb/include/lldb/ValueObject/DILEval.h @@ -49,8 +49,16 @@ class Interpreter : Visitor { private: llvm::Expected Visit(const IdentifierNode *node) override; + llvm::Expected Visit(const MemberOfNode *node) override; llvm::Expected Visit(const UnaryOpNode *node) override; + lldb::ValueObjectSP EvaluateMemberOf(lldb::ValueObjectSP value, + const std::vector &path, + bool use_synthetic, bool is_dynamic); + + lldb::ValueObjectSP FindMemberWithName(lldb::ValueObjectSP base, + ConstString name, bool is_arrow); + // Used by the interpreter to create objects, perform casts, etc. lldb::TargetSP m_target; llvm::StringRef m_expr; diff --git a/lldb/include/lldb/ValueObject/DILLexer.h b/lldb/include/lldb/ValueObject/DILLexer.h index 3508b8b7a85c6..9475519a43d2a 100644 --- a/lldb/include/lldb/ValueObject/DILLexer.h +++ b/lldb/include/lldb/ValueObject/DILLexer.h @@ -25,10 +25,12 @@ class Token { public: enum Kind { amp, + arrow, coloncolon, eof, identifier, l_paren, + period, r_paren, star, }; diff --git a/lldb/include/lldb/ValueObject/DILParser.h b/lldb/include/lldb/ValueObject/DILParser.h index f5c00b1040ef4..c62f8908290f5 100644 --- a/lldb/include/lldb/ValueObject/DILParser.h +++ b/lldb/include/lldb/ValueObject/DILParser.h @@ -84,6 +84,7 @@ class DILParser { ASTNodeUP ParseExpression(); ASTNodeUP ParseUnaryExpression(); + ASTNodeUP ParsePostfixExpression(); ASTNodeUP ParsePrimaryExpression(); std::string ParseNestedNameSpecifier(); diff --git a/lldb/source/ValueObject/DILAST.cpp b/lldb/source/ValueObject/DILAST.cpp index ea847587501ee..2814d96b94e6e 100644 --- a/lldb/source/ValueObject/DILAST.cpp +++ b/lldb/source/ValueObject/DILAST.cpp @@ -19,6 +19,10 @@ llvm::Expected IdentifierNode::Accept(Visitor *v) const { return v->Visit(this); } +llvm::Expected MemberOfNode::Accept(Visitor *v) const { + return v->Visit(this); +} + llvm::Expected UnaryOpNode::Accept(Visitor *v) const { return v->Visit(this); } diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp index 15a66d4866305..1f1ad7161f42e 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -272,4 +272,204 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } +lldb::ValueObjectSP +Interpreter::EvaluateMemberOf(lldb::ValueObjectSP value, + const std::vector &path, + bool use_synthetic, bool is_dynamic) { + lldb::ValueObjectSP member_val_sp = value; + + lldb::DynamicValueType use_dynamic = + (!is_dynamic) ? lldb::eNoDynamicValues : lldb::eDynamicDontRunTarget; + // Walk the path from the base value to the value that contains the requested field. + for (uint32_t idx : path) { + member_val_sp = member_val_sp->GetChildAtIndex(idx, /*can_create*/ true); + } + // If that didn't work, try it with the dynamic value. + if (!member_val_sp && is_dynamic) { + lldb::ValueObjectSP dyn_val_sp = value->GetDynamicValue(use_dynamic); + if (dyn_val_sp) { + for (uint32_t idx : path) { + dyn_val_sp = dyn_val_sp->GetChildAtIndex(idx, true); + } + member_val_sp = dyn_val_sp; + } + } + assert(member_val_sp && "invalid ast: invalid member access"); + + return member_val_sp; +} + +static bool GetFieldIndex(CompilerType type, const std::string &name, + std::vector *idx_path) { + bool found = false; + uint32_t num_fields = type.GetNumFields(); + for (uint32_t i = 0; i < num_fields; ++i) { + uint64_t bit_offset = 0; + uint32_t bitfield_bit_size = 0; + bool is_bitfield = false; + std::string name_sstr; + CompilerType field_type(type.GetFieldAtIndex( + i, name_sstr, &bit_offset, &bitfield_bit_size, &is_bitfield)); + auto field_name = + name_sstr.length() == 0 ? std::optional() : name_sstr; + if (field_type.IsValid() && name_sstr == name) { + idx_path->push_back(i + type.GetNumberOfNonEmptyBaseClasses()); + found = true; + break; + } else if (field_type.IsAnonymousType()) { + found = GetFieldIndex(field_type, name, idx_path); + if (found) { + idx_path->push_back(i + type.GetNumberOfNonEmptyBaseClasses()); + break; + } + } + } + return found; +} + +static bool SearchBaseClassesForField(lldb::ValueObjectSP base_sp, + CompilerType base_type, + const std::string &name, + std::vector *idx_path, + bool use_synthetic, bool is_dynamic) { + bool found = false; + uint32_t num_non_empty_bases = 0; + uint32_t num_direct_bases = base_type.GetNumDirectBaseClasses(); + for (uint32_t i = 0; i < num_direct_bases; ++i) { + uint32_t bit_offset; + CompilerType base_class = + base_type.GetDirectBaseClassAtIndex(i, &bit_offset); + std::vector field_idx_path; + if (GetFieldIndex(base_class, name, &field_idx_path)) { + for (uint32_t j : field_idx_path) + idx_path->push_back(j + base_class.GetNumberOfNonEmptyBaseClasses()); + idx_path->push_back(i); + return true; + } + + found = SearchBaseClassesForField(base_sp, base_class, name, idx_path, + use_synthetic, is_dynamic); + if (found) { + idx_path->push_back(i); + return true; + } + + if (base_class.GetNumFields() > 0) + num_non_empty_bases += 1; + } + return false; +} + +lldb::ValueObjectSP Interpreter::FindMemberWithName(lldb::ValueObjectSP base, + ConstString name, + bool is_arrow) { + bool is_synthetic = false; + bool is_dynamic = true; + // See if GetChildMemberWithName works. + lldb::ValueObjectSP field_obj = + base->GetChildMemberWithName(name.GetStringRef()); + if (field_obj && field_obj->GetName() == name) + return field_obj; + + // Check for synthetic member. + lldb::ValueObjectSP child_sp = base->GetSyntheticValue(); + if (child_sp) { + is_synthetic = true; + field_obj = child_sp->GetChildMemberWithName(name); + if (field_obj && field_obj->GetName() == name) + return field_obj; + } + + // Check indices of immediate member fields of base's type. + CompilerType base_type = base->GetCompilerType(); + std::vector field_idx_path; + if (GetFieldIndex(base_type, name.GetString(), &field_idx_path)) { + std::reverse(field_idx_path.begin(), field_idx_path.end()); + // Traverse the path & verify the final object is correct. + field_obj = base; + for (uint32_t i : field_idx_path) + field_obj = field_obj->GetChildAtIndex(i, true); + if (field_obj && field_obj->GetName() == name) + return field_obj; + } + + // Go through base classes and look for field there. + std::vector base_class_idx_path; + bool found = + SearchBaseClassesForField(base, base_type, name.GetString(), + &base_class_idx_path, is_synthetic, is_dynamic); + if (found && !base_class_idx_path.empty()) { + std::reverse(base_class_idx_path.begin(), base_class_idx_path.end()); + field_obj = + EvaluateMemberOf(base, base_class_idx_path, is_synthetic, is_dynamic); + if (field_obj && field_obj->GetName() == name) + return field_obj; + } + + // Field not found. + return lldb::ValueObjectSP(); +} + +llvm::Expected +Interpreter::Visit(const MemberOfNode *node) { + Status error; + auto base_or_err = Evaluate(node->base()); + if (!base_or_err) { + return base_or_err; + } + lldb::ValueObjectSP base = *base_or_err; + + // Perform basic type checking. + CompilerType base_type = base->GetCompilerType(); + // When using an arrow, make sure the base is a pointer or array type. + // When using a period, make sure the base type is NOT a pointer type. + if (node->IsArrow() && !base_type.IsPointerType() && + !base_type.IsArrayType()) { + lldb::ValueObjectSP deref_sp = base->Dereference(error); + if (error.Success()) { + base = deref_sp; + base_type = deref_sp->GetCompilerType().GetPointerType(); + } else { + std::string errMsg = + llvm::formatv("member reference type {0} is not a pointer; " + "did you mean to use '.'?", + base_type.TypeDescription()); + return llvm::make_error( + m_expr, errMsg, node->GetLocation(), node->FieldName().GetLength()); + } + } else if (!node->IsArrow() && base_type.IsPointerType()) { + std::string errMsg = + llvm::formatv("member reference type {0} is a pointer; " + "did you mean to use '->'?", + base_type.TypeDescription()); + return llvm::make_error( + m_expr, errMsg, node->GetLocation(), node->FieldName().GetLength()); + } + + // User specified array->elem; need to get to element[0] to look for fields. + if (node->IsArrow() && base_type.IsArrayType()) + base = base->GetChildAtIndex(0); + + // Now look for the member with the specified name. + lldb::ValueObjectSP field_obj = + FindMemberWithName(base, node->FieldName(), node->IsArrow()); + if (field_obj) { + if (field_obj->GetCompilerType().IsReferenceType()) { + lldb::ValueObjectSP tmp_obj = field_obj->Dereference(error); + if (error.Fail()) + return error.ToError(); + return tmp_obj; + } + return field_obj; + } + + if (node->IsArrow() && base_type.IsPointerType()) + base_type = base_type.GetPointeeType(); + std::string errMsg = llvm::formatv( + "no member named '{0}' in {1}", node->FieldName().GetStringRef(), + base_type.GetFullyUnqualifiedType().TypeDescription()); + return llvm::make_error( + m_expr, errMsg, node->GetLocation(), node->FieldName().GetLength()); +} + } // namespace lldb_private::dil diff --git a/lldb/source/ValueObject/DILLexer.cpp b/lldb/source/ValueObject/DILLexer.cpp index b9c2e7971e3b4..1610b4e87d7fb 100644 --- a/lldb/source/ValueObject/DILLexer.cpp +++ b/lldb/source/ValueObject/DILLexer.cpp @@ -21,6 +21,8 @@ llvm::StringRef Token::GetTokenName(Kind kind) { switch (kind) { case Kind::amp: return "amp"; + case Kind::arrow: + return "arrow"; case Kind::coloncolon: return "coloncolon"; case Kind::eof: @@ -29,6 +31,8 @@ llvm::StringRef Token::GetTokenName(Kind kind) { return "identifier"; case Kind::l_paren: return "l_paren"; + case Kind::period: + return "period"; case Kind::r_paren: return "r_paren"; case Token::star: @@ -86,8 +90,9 @@ llvm::Expected DILLexer::Lex(llvm::StringRef expr, return Token(Token::identifier, maybe_word->str(), position); constexpr std::pair operators[] = { - {Token::amp, "&"}, {Token::coloncolon, "::"}, {Token::l_paren, "("}, - {Token::r_paren, ")"}, {Token::star, "*"}, + {Token::amp, "&"}, {Token::arrow, "->"}, {Token::coloncolon, "::"}, + {Token::l_paren, "("}, {Token::period, "."}, {Token::r_paren, ")"}, + {Token::star, "*"}, }; for (auto [kind, str] : operators) { if (remainder.consume_front(str)) diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp index 2c78eae8cf6bf..9c5bc71775fb2 100644 --- a/lldb/source/ValueObject/DILParser.cpp +++ b/lldb/source/ValueObject/DILParser.cpp @@ -79,15 +79,15 @@ ASTNodeUP DILParser::Run() { // Parse an expression. // // expression: -// primary_expression +// unary_expression // ASTNodeUP DILParser::ParseExpression() { return ParseUnaryExpression(); } // Parse an unary_expression. // // unary_expression: +// postfix_expression // unary_operator expression -// primary_expression // // unary_operator: // "&" @@ -111,7 +111,28 @@ ASTNodeUP DILParser::ParseUnaryExpression() { llvm_unreachable("invalid token kind"); } } - return ParsePrimaryExpression(); + return ParsePostfixExpression(); +} +// Parse a postfix_expression. +// +// postfix_expression: +// primary_expression +// postfix_expression "." id_expression +// postfix_expression "->" id_expression +// +ASTNodeUP DILParser::ParsePostfixExpression() { + ASTNodeUP lhs = ParsePrimaryExpression(); + while (CurToken().IsOneOf({Token::period, Token::arrow})) { + Token token = CurToken(); + m_dil_lexer.Advance(); + Token member_token = CurToken(); + std::string member_id = ParseIdExpression(); + lhs = std::make_unique(member_token.GetLocation(), + std::move(lhs), + token.GetKind() == Token::arrow, + ConstString(member_id)); + } + return lhs; } // Parse a primary_expression. diff --git a/lldb/test/API/commands/frame/var-dil/basics/MemberOf/Makefile b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/Makefile new file mode 100644 index 0000000000000..99998b20bcb05 --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py new file mode 100644 index 0000000000000..ff942c88bf183 --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py @@ -0,0 +1,47 @@ +""" +Make sure 'frame var' using DIL parser/evaultor works for local variables. +""" + +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +from lldbsuite.test import lldbutil + +import os +import shutil +import time + +class TestFrameVarDILMemberOf(TestBase): + # If your test case doesn't stress debug info, then + # set this to true. That way it won't be run once for + # each debug info format. + NO_DEBUG_INFO_TESTCASE = True + + def test_frame_var(self): + self.build() + lldbutil.run_to_source_breakpoint(self, "Set a breakpoint here", + lldb.SBFileSpec("main.cpp")) + + self.expect("settings set target.experimental.use-DIL true", + substrs=[""]) + self.expect_var_path("s.x", value="1") + self.expect_var_path("s.r", value="2") + self.expect_var_path("sr.x", value="1") + self.expect_var_path("sr.r", value="2") + self.expect_var_path("sp->x", value="1") + self.expect_var_path("sp->r", value="2") + self.expect_var_path("sarr->x", value="5"); + self.expect_var_path("sarr->r", value="2") + + self.expect("frame variable 'sp->foo'", error=True, + substrs=["no member named 'foo' in 'Sx'"]) + + self.expect("frame variable 'sp.x'", error=True, + substrs=["member reference type 'Sx *' is a " + "pointer; did you mean to use '->'"]) + self.expect("frame variable 'sarr.x'", error=True, + substrs=["no member named 'x' in 'Sx[2]'"]) + + # Test for record typedefs. + self.expect_var_path("sa.x", value="3") + self.expect_var_path("sa.y", value="'\\x04'") diff --git a/lldb/test/API/commands/frame/var-dil/basics/MemberOf/main.cpp b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/main.cpp new file mode 100644 index 0000000000000..dace888bef4dc --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/main.cpp @@ -0,0 +1,59 @@ +int +main(int argc, char**argv) +{ + int x = 2; + struct Sx { + int x; + int& r; + char y; + } s{1, x, 2}; + + Sx& sr = s; + Sx* sp = &s; + + Sx sarr[2] = {{5, x, 2}, {1, x, 3}}; + + using SxAlias = Sx; + SxAlias sa{3, x, 4}; + + return 0; // Set a breakpoint here +} + +/* + EXPECT_THAT(Eval("s.x"), IsEqual("1")); + EXPECT_THAT(Eval("s.r"), IsEqual("2")); + EXPECT_THAT(Eval("s.r + 1"), IsEqual("3")); + EXPECT_THAT(Eval("sr.x"), IsEqual("1")); + EXPECT_THAT(Eval("sr.r"), IsEqual("2")); + EXPECT_THAT(Eval("sr.r + 1"), IsEqual("3")); + EXPECT_THAT(Eval("sp->x"), IsEqual("1")); + EXPECT_THAT(Eval("sp->r"), IsEqual("2")); + EXPECT_THAT(Eval("sp->r + 1"), IsEqual("3")); + EXPECT_THAT(Eval("sarr->x"), IsEqual("5")); + EXPECT_THAT(Eval("sarr->r"), IsEqual("2")); + EXPECT_THAT(Eval("sarr->r + 1"), IsEqual("3")); + EXPECT_THAT(Eval("(sarr + 1)->x"), IsEqual("1")); + + EXPECT_THAT( + Eval("sp->4"), + IsError( + ":1:5: expected 'identifier', got: <'4' (numeric_constant)>\n" + "sp->4\n" + " ^")); + EXPECT_THAT(Eval("sp->foo"), IsError("no member named 'foo' in 'Sx'")); + EXPECT_THAT( + Eval("sp->r / (void*)0"), + IsError("invalid operands to binary expression ('int' and 'void *')")); + + EXPECT_THAT(Eval("sp.x"), IsError("member reference type 'Sx *' is a " + "pointer; did you mean to use '->'")); + EXPECT_THAT( + Eval("sarr.x"), + IsError( + "member reference base type 'Sx[2]' is not a structure or union")); + + // Test for record typedefs. + EXPECT_THAT(Eval("sa.x"), IsEqual("3")); + EXPECT_THAT(Eval("sa.y"), IsEqual("'\\x04'")); + +*/ diff --git a/lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/Makefile b/lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/Makefile new file mode 100644 index 0000000000000..99998b20bcb05 --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/TestFrameVarDILMemberOfAnonymousMember.py b/lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/TestFrameVarDILMemberOfAnonymousMember.py new file mode 100644 index 0000000000000..1bde4706da90f --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/TestFrameVarDILMemberOfAnonymousMember.py @@ -0,0 +1,62 @@ +""" +Make sure 'frame var' using DIL parser/evaultor works for local variables. +""" + +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +from lldbsuite.test import lldbutil + +import os +import shutil +import time + +class TestFrameVarDILMemberOfAnonymousMember(TestBase): + # If your test case doesn't stress debug info, then + # set this to true. That way it won't be run once for + # each debug info format. + NO_DEBUG_INFO_TESTCASE = True + + def test_frame_var(self): + self.build() + lldbutil.run_to_source_breakpoint(self, "Set a breakpoint here", + lldb.SBFileSpec("main.cpp")) + + self.expect("settings set target.experimental.use-DIL true", + substrs=[""]) + self.expect_var_path("a.x", value="1") + self.expect_var_path("a.y", value="2") + + self.expect("frame variable 'b.x'", error=True, + substrs=["no member named 'x' in 'B'"]) + #self.expect_var_path("b.y", value="0") + self.expect_var_path("b.z", value="3") + self.expect_var_path("b.w", value="4") + self.expect_var_path("b.a.x", value="1") + self.expect_var_path("b.a.y", value="2") + + self.expect_var_path("c.x", value="5") + self.expect_var_path("c.y", value="6") + + self.expect_var_path("d.x", value="7") + self.expect_var_path("d.y", value="8") + self.expect_var_path("d.z", value="9") + self.expect_var_path("d.w", value="10") + + self.expect("frame variable 'e.x'", error=True, + substrs=["no member named 'x' in 'E'"]) + self.expect("frame variable 'f.x'", error=True, + substrs=["no member named 'x' in 'F'"]) + self.expect_var_path("f.named_field.x", value="12") + + self.expect_var_path("unnamed_derived.y", value="2") + self.expect_var_path("unnamed_derived.z", value="13") + + self.expect("frame variable 'derb.x'", error=True, + substrs=["no member named 'x' in 'DerivedB'"]) + self.expect("frame variable 'derb.y'", error=True, + substrs=["no member named 'y' in 'DerivedB'"]) + self.expect_var_path("derb.w", value="14") + self.expect_var_path("derb.k", value="15") + self.expect_var_path("derb.a.x", value="1") + self.expect_var_path("derb.a.y", value="2") diff --git a/lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/main.cpp b/lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/main.cpp new file mode 100644 index 0000000000000..6237523ac6bf3 --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/main.cpp @@ -0,0 +1,74 @@ +int main(int argc, char** argv) +{ + struct A { + struct { + int x = 1; + }; + int y = 2; + } a; + + struct B { + // Anonymous struct inherits another struct. + struct : public A { + int z = 3; + }; + int w = 4; + A a; + } b; + + // Anonymous classes and unions. + struct C { + union { + int x = 5; + }; + class { + public: + int y = 6; + }; + } c; + + // Multiple levels of anonymous structs. + struct D { + struct { + struct { + int x = 7; + struct { + int y = 8; + }; + }; + int z = 9; + struct { + int w = 10; + }; + }; + } d; + + struct E { + struct IsNotAnon { + int x = 11; + }; + } e; + + struct F { + struct { + int x = 12; + } named_field; + } f; + + // Inherited unnamed struct without an enclosing parent class. + struct : public A { + struct { + int z = 13; + }; + } unnamed_derived; + + struct DerivedB : public B { + struct { + // `w` in anonymous struct overrides `w` from `B`. + int w = 14; + int k = 15; + }; + } derb; + + return 0; // Set a breakpoint here +} diff --git a/lldb/test/API/commands/frame/var-dil/basics/MemberOfInheritance/Makefile b/lldb/test/API/commands/frame/var-dil/basics/MemberOfInheritance/Makefile new file mode 100644 index 0000000000000..99998b20bcb05 --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/basics/MemberOfInheritance/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/commands/frame/var-dil/basics/MemberOfInheritance/TestFrameVarDILMemberOfInheritance.py b/lldb/test/API/commands/frame/var-dil/basics/MemberOfInheritance/TestFrameVarDILMemberOfInheritance.py new file mode 100644 index 0000000000000..c38ab5d30b238 --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/basics/MemberOfInheritance/TestFrameVarDILMemberOfInheritance.py @@ -0,0 +1,49 @@ +""" +Make sure 'frame var' using DIL parser/evaultor works for local variables. +""" + +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +from lldbsuite.test import lldbutil + +import os +import shutil +import time + +class TestFrameVarDILMemberOfInheritance(TestBase): + # If your test case doesn't stress debug info, then + # set this to true. That way it won't be run once for + # each debug info format. + NO_DEBUG_INFO_TESTCASE = True + + def test_frame_var(self): + self.build() + lldbutil.run_to_source_breakpoint(self, "Set a breakpoint here", + lldb.SBFileSpec("main.cpp")) + + self.expect("settings set target.experimental.use-DIL true", + substrs=[""]) + self.expect_var_path("a.a_", value="1") + self.expect_var_path("b.b_", value="2") + self.expect_var_path("c.a_", value="1") + self.expect_var_path("c.b_", value="2") + self.expect_var_path("c.c_", value="3") + self.expect_var_path("d.a_", value="1") + self.expect_var_path("d.b_", value="2") + self.expect_var_path("d.c_", value="3") + self.expect_var_path("d.d_", value="4") + self.expect_var_path("d.fa_.a_", value="5") + + self.expect_var_path("plugin.x", value="1") + self.expect_var_path("plugin.y", value="2") + + self.expect_var_path("engine.x", value="1") + self.expect_var_path("engine.y", value="2") + self.expect_var_path("engine.z", value="3") + + self.expect_var_path("parent_base->x", value="1") + self.expect_var_path("parent_base->y", value="2") + self.expect_var_path("parent->x", value="1") + self.expect_var_path("parent->y", value="2") + self.expect_var_path("parent->z", value="3") diff --git a/lldb/test/API/commands/frame/var-dil/basics/MemberOfInheritance/main.cpp b/lldb/test/API/commands/frame/var-dil/basics/MemberOfInheritance/main.cpp new file mode 100644 index 0000000000000..4d29af1b7f15b --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/basics/MemberOfInheritance/main.cpp @@ -0,0 +1,87 @@ +int main(int argc, char** argv) +{ + struct A { + int a_; + } a{1}; + + struct B { + int b_; + } b{2}; + + struct C : A, B { + int c_; + } c; + // } c{{1}, {2}, 3}; + c.a_ = 1; + c.b_ = 2; + c.c_ = 3; + + struct D : C { + int d_; + A fa_; + } d; + // } d{{{1}, {2}, 3}, 4, {5}}; + d.a_ = 1; + d.b_ = 2; + d.c_ = 3; + d.d_ = 4; + d.fa_.a_ = 5; + + // Virtual inheritance example. + struct Animal { + virtual ~Animal() = default; + int weight_; + }; + struct Mammal : virtual Animal {}; + struct WingedAnimal : virtual Animal {}; + struct Bat : Mammal, WingedAnimal { + } bat; + bat.weight_ = 10; + + // Empty bases example. + struct IPlugin { + virtual ~IPlugin() {} + }; + struct Plugin : public IPlugin { + int x; + int y; + }; + Plugin plugin; + plugin.x = 1; + plugin.y = 2; + + struct ObjectBase { + int x; + }; + struct Object : ObjectBase {}; + struct Engine : Object { + int y; + int z; + }; + + Engine engine; + engine.x = 1; + engine.y = 2; + engine.z = 3; + + // Empty multiple inheritance with empty base. + struct Base { + int x; + int y; + virtual void Do() = 0; + virtual ~Base() {} + }; + struct Mixin {}; + struct Parent : private Mixin, public Base { + int z; + virtual void Do(){}; + }; + Parent obj; + obj.x = 1; + obj.y = 2; + obj.z = 3; + Base* parent_base = &obj; + Parent* parent = &obj; + + return 0; // Set a breakpoint here +} >From b3bf9213cafb3bc8e5b333b37b83f9af294782f2 Mon Sep 17 00:00:00 2001 From: Caroline Tice Date: Wed, 7 May 2025 23:05:58 -0700 Subject: [PATCH 2/4] Remove special code for finding field members and rely entirely on ValueObject::GetChildMemberWithName. Also minor code cleanups requested by reviewer. --- lldb/include/lldb/ValueObject/DILAST.h | 12 +- lldb/include/lldb/ValueObject/DILEval.h | 7 - lldb/source/ValueObject/DILEval.cpp | 164 ++---------------------- lldb/source/ValueObject/DILParser.cpp | 7 +- 4 files changed, 22 insertions(+), 168 deletions(-) diff --git a/lldb/include/lldb/ValueObject/DILAST.h b/lldb/include/lldb/ValueObject/DILAST.h index a74a12bd8be9d..f3cda4fbece9b 100644 --- a/lldb/include/lldb/ValueObject/DILAST.h +++ b/lldb/include/lldb/ValueObject/DILAST.h @@ -92,15 +92,15 @@ class IdentifierNode : public ASTNode { class MemberOfNode : public ASTNode { public: MemberOfNode(uint32_t location, ASTNodeUP base, bool is_arrow, - ConstString name) + std::string name) : ASTNode(location, NodeKind::eMemberOfNode), m_base(std::move(base)), - m_is_arrow(is_arrow), m_field_name(name) { } + m_is_arrow(is_arrow), m_field_name(std::move(name)) {} llvm::Expected Accept(Visitor *v) const override; - ASTNode *base() const { return m_base.get(); } - bool IsArrow() const { return m_is_arrow; } - ConstString FieldName() const { return m_field_name; } + ASTNode *GetBase() const { return m_base.get(); } + bool GetIsArrow() const { return m_is_arrow; } + std::string GetFieldName() const { return m_field_name; } static bool classof(const ASTNode *node) { return node->GetKind() == NodeKind::eMemberOfNode; @@ -109,7 +109,7 @@ class MemberOfNode : public ASTNode { private: ASTNodeUP m_base; bool m_is_arrow; - ConstString m_field_name; + std::string m_field_name; }; class UnaryOpNode : public ASTNode { diff --git a/lldb/include/lldb/ValueObject/DILEval.h b/lldb/include/lldb/ValueObject/DILEval.h index 053daffaa41f2..04c21ab77b6b4 100644 --- a/lldb/include/lldb/ValueObject/DILEval.h +++ b/lldb/include/lldb/ValueObject/DILEval.h @@ -52,13 +52,6 @@ class Interpreter : Visitor { llvm::Expected Visit(const MemberOfNode *node) override; llvm::Expected Visit(const UnaryOpNode *node) override; - lldb::ValueObjectSP EvaluateMemberOf(lldb::ValueObjectSP value, - const std::vector &path, - bool use_synthetic, bool is_dynamic); - - lldb::ValueObjectSP FindMemberWithName(lldb::ValueObjectSP base, - ConstString name, bool is_arrow); - // Used by the interpreter to create objects, perform casts, etc. lldb::TargetSP m_target; llvm::StringRef m_expr; diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp index 1f1ad7161f42e..8630bdd0a4ed1 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -272,148 +272,10 @@ Interpreter::Visit(const UnaryOpNode *node) { m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); } -lldb::ValueObjectSP -Interpreter::EvaluateMemberOf(lldb::ValueObjectSP value, - const std::vector &path, - bool use_synthetic, bool is_dynamic) { - lldb::ValueObjectSP member_val_sp = value; - - lldb::DynamicValueType use_dynamic = - (!is_dynamic) ? lldb::eNoDynamicValues : lldb::eDynamicDontRunTarget; - // Walk the path from the base value to the value that contains the requested field. - for (uint32_t idx : path) { - member_val_sp = member_val_sp->GetChildAtIndex(idx, /*can_create*/ true); - } - // If that didn't work, try it with the dynamic value. - if (!member_val_sp && is_dynamic) { - lldb::ValueObjectSP dyn_val_sp = value->GetDynamicValue(use_dynamic); - if (dyn_val_sp) { - for (uint32_t idx : path) { - dyn_val_sp = dyn_val_sp->GetChildAtIndex(idx, true); - } - member_val_sp = dyn_val_sp; - } - } - assert(member_val_sp && "invalid ast: invalid member access"); - - return member_val_sp; -} - -static bool GetFieldIndex(CompilerType type, const std::string &name, - std::vector *idx_path) { - bool found = false; - uint32_t num_fields = type.GetNumFields(); - for (uint32_t i = 0; i < num_fields; ++i) { - uint64_t bit_offset = 0; - uint32_t bitfield_bit_size = 0; - bool is_bitfield = false; - std::string name_sstr; - CompilerType field_type(type.GetFieldAtIndex( - i, name_sstr, &bit_offset, &bitfield_bit_size, &is_bitfield)); - auto field_name = - name_sstr.length() == 0 ? std::optional() : name_sstr; - if (field_type.IsValid() && name_sstr == name) { - idx_path->push_back(i + type.GetNumberOfNonEmptyBaseClasses()); - found = true; - break; - } else if (field_type.IsAnonymousType()) { - found = GetFieldIndex(field_type, name, idx_path); - if (found) { - idx_path->push_back(i + type.GetNumberOfNonEmptyBaseClasses()); - break; - } - } - } - return found; -} - -static bool SearchBaseClassesForField(lldb::ValueObjectSP base_sp, - CompilerType base_type, - const std::string &name, - std::vector *idx_path, - bool use_synthetic, bool is_dynamic) { - bool found = false; - uint32_t num_non_empty_bases = 0; - uint32_t num_direct_bases = base_type.GetNumDirectBaseClasses(); - for (uint32_t i = 0; i < num_direct_bases; ++i) { - uint32_t bit_offset; - CompilerType base_class = - base_type.GetDirectBaseClassAtIndex(i, &bit_offset); - std::vector field_idx_path; - if (GetFieldIndex(base_class, name, &field_idx_path)) { - for (uint32_t j : field_idx_path) - idx_path->push_back(j + base_class.GetNumberOfNonEmptyBaseClasses()); - idx_path->push_back(i); - return true; - } - - found = SearchBaseClassesForField(base_sp, base_class, name, idx_path, - use_synthetic, is_dynamic); - if (found) { - idx_path->push_back(i); - return true; - } - - if (base_class.GetNumFields() > 0) - num_non_empty_bases += 1; - } - return false; -} - -lldb::ValueObjectSP Interpreter::FindMemberWithName(lldb::ValueObjectSP base, - ConstString name, - bool is_arrow) { - bool is_synthetic = false; - bool is_dynamic = true; - // See if GetChildMemberWithName works. - lldb::ValueObjectSP field_obj = - base->GetChildMemberWithName(name.GetStringRef()); - if (field_obj && field_obj->GetName() == name) - return field_obj; - - // Check for synthetic member. - lldb::ValueObjectSP child_sp = base->GetSyntheticValue(); - if (child_sp) { - is_synthetic = true; - field_obj = child_sp->GetChildMemberWithName(name); - if (field_obj && field_obj->GetName() == name) - return field_obj; - } - - // Check indices of immediate member fields of base's type. - CompilerType base_type = base->GetCompilerType(); - std::vector field_idx_path; - if (GetFieldIndex(base_type, name.GetString(), &field_idx_path)) { - std::reverse(field_idx_path.begin(), field_idx_path.end()); - // Traverse the path & verify the final object is correct. - field_obj = base; - for (uint32_t i : field_idx_path) - field_obj = field_obj->GetChildAtIndex(i, true); - if (field_obj && field_obj->GetName() == name) - return field_obj; - } - - // Go through base classes and look for field there. - std::vector base_class_idx_path; - bool found = - SearchBaseClassesForField(base, base_type, name.GetString(), - &base_class_idx_path, is_synthetic, is_dynamic); - if (found && !base_class_idx_path.empty()) { - std::reverse(base_class_idx_path.begin(), base_class_idx_path.end()); - field_obj = - EvaluateMemberOf(base, base_class_idx_path, is_synthetic, is_dynamic); - if (field_obj && field_obj->GetName() == name) - return field_obj; - } - - // Field not found. - return lldb::ValueObjectSP(); -} - llvm::Expected Interpreter::Visit(const MemberOfNode *node) { Status error; - auto base_or_err = Evaluate(node->base()); + auto base_or_err = Evaluate(node->GetBase()); if (!base_or_err) { return base_or_err; } @@ -423,7 +285,7 @@ Interpreter::Visit(const MemberOfNode *node) { CompilerType base_type = base->GetCompilerType(); // When using an arrow, make sure the base is a pointer or array type. // When using a period, make sure the base type is NOT a pointer type. - if (node->IsArrow() && !base_type.IsPointerType() && + if (node->GetIsArrow() && !base_type.IsPointerType() && !base_type.IsArrayType()) { lldb::ValueObjectSP deref_sp = base->Dereference(error); if (error.Success()) { @@ -435,25 +297,25 @@ Interpreter::Visit(const MemberOfNode *node) { "did you mean to use '.'?", base_type.TypeDescription()); return llvm::make_error( - m_expr, errMsg, node->GetLocation(), node->FieldName().GetLength()); + m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); } - } else if (!node->IsArrow() && base_type.IsPointerType()) { + } else if (!node->GetIsArrow() && base_type.IsPointerType()) { std::string errMsg = llvm::formatv("member reference type {0} is a pointer; " "did you mean to use '->'?", base_type.TypeDescription()); return llvm::make_error( - m_expr, errMsg, node->GetLocation(), node->FieldName().GetLength()); + m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); } // User specified array->elem; need to get to element[0] to look for fields. - if (node->IsArrow() && base_type.IsArrayType()) + if (node->GetIsArrow() && base_type.IsArrayType()) base = base->GetChildAtIndex(0); // Now look for the member with the specified name. lldb::ValueObjectSP field_obj = - FindMemberWithName(base, node->FieldName(), node->IsArrow()); - if (field_obj) { + base->GetChildMemberWithName(llvm::StringRef(node->GetFieldName())); + if (field_obj && field_obj->GetName().GetString() == node->GetFieldName()) { if (field_obj->GetCompilerType().IsReferenceType()) { lldb::ValueObjectSP tmp_obj = field_obj->Dereference(error); if (error.Fail()) @@ -463,13 +325,13 @@ Interpreter::Visit(const MemberOfNode *node) { return field_obj; } - if (node->IsArrow() && base_type.IsPointerType()) + if (node->GetIsArrow() && base_type.IsPointerType()) base_type = base_type.GetPointeeType(); - std::string errMsg = llvm::formatv( - "no member named '{0}' in {1}", node->FieldName().GetStringRef(), - base_type.GetFullyUnqualifiedType().TypeDescription()); + std::string errMsg = + llvm::formatv("no member named '{0}' in {1}", node->GetFieldName(), + base_type.GetFullyUnqualifiedType().TypeDescription()); return llvm::make_error( - m_expr, errMsg, node->GetLocation(), node->FieldName().GetLength()); + m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); } } // namespace lldb_private::dil diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp index 9c5bc71775fb2..b147ca61df73b 100644 --- a/lldb/source/ValueObject/DILParser.cpp +++ b/lldb/source/ValueObject/DILParser.cpp @@ -127,10 +127,9 @@ ASTNodeUP DILParser::ParsePostfixExpression() { m_dil_lexer.Advance(); Token member_token = CurToken(); std::string member_id = ParseIdExpression(); - lhs = std::make_unique(member_token.GetLocation(), - std::move(lhs), - token.GetKind() == Token::arrow, - ConstString(member_id)); + lhs = std::make_unique( + member_token.GetLocation(), std::move(lhs), + token.GetKind() == Token::arrow, member_id); } return lhs; } >From 4afffe9379ed90e1000c8c0c187eb2e703024d70 Mon Sep 17 00:00:00 2001 From: Caroline Tice Date: Mon, 12 May 2025 20:52:34 -0700 Subject: [PATCH 3/4] Minor code cleanups: - Formatting issues. - Update the evalution of MemberOf to NOT automatically deref references - Update tests to match. - Change GetFieldName to return a StringRef instead of a std::string. --- lldb/include/lldb/ValueObject/DILAST.h | 2 +- lldb/source/ValueObject/DILEval.cpp | 15 ++----- lldb/source/ValueObject/DILParser.cpp | 1 + .../MemberOf/TestFrameVarDILMemberOf.py | 8 ++-- .../frame/var-dil/basics/MemberOf/main.cpp | 39 ------------------- 5 files changed, 10 insertions(+), 55 deletions(-) diff --git a/lldb/include/lldb/ValueObject/DILAST.h b/lldb/include/lldb/ValueObject/DILAST.h index f3cda4fbece9b..8687316657ca9 100644 --- a/lldb/include/lldb/ValueObject/DILAST.h +++ b/lldb/include/lldb/ValueObject/DILAST.h @@ -100,7 +100,7 @@ class MemberOfNode : public ASTNode { ASTNode *GetBase() const { return m_base.get(); } bool GetIsArrow() const { return m_is_arrow; } - std::string GetFieldName() const { return m_field_name; } + llvm::StringRef GetFieldName() const { return llvm::StringRef(m_field_name); } static bool classof(const ASTNode *node) { return node->GetKind() == NodeKind::eMemberOfNode; diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp index 8630bdd0a4ed1..7eb7591a0a6b2 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -274,11 +274,9 @@ Interpreter::Visit(const UnaryOpNode *node) { llvm::Expected Interpreter::Visit(const MemberOfNode *node) { - Status error; auto base_or_err = Evaluate(node->GetBase()); - if (!base_or_err) { + if (!base_or_err) return base_or_err; - } lldb::ValueObjectSP base = *base_or_err; // Perform basic type checking. @@ -287,6 +285,7 @@ Interpreter::Visit(const MemberOfNode *node) { // When using a period, make sure the base type is NOT a pointer type. if (node->GetIsArrow() && !base_type.IsPointerType() && !base_type.IsArrayType()) { + Status error; lldb::ValueObjectSP deref_sp = base->Dereference(error); if (error.Success()) { base = deref_sp; @@ -314,14 +313,8 @@ Interpreter::Visit(const MemberOfNode *node) { // Now look for the member with the specified name. lldb::ValueObjectSP field_obj = - base->GetChildMemberWithName(llvm::StringRef(node->GetFieldName())); - if (field_obj && field_obj->GetName().GetString() == node->GetFieldName()) { - if (field_obj->GetCompilerType().IsReferenceType()) { - lldb::ValueObjectSP tmp_obj = field_obj->Dereference(error); - if (error.Fail()) - return error.ToError(); - return tmp_obj; - } + base->GetChildMemberWithName(node->GetFieldName()); + if (field_obj && field_obj->GetName() == node->GetFieldName()) { return field_obj; } diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp index b147ca61df73b..982fbf40e6b39 100644 --- a/lldb/source/ValueObject/DILParser.cpp +++ b/lldb/source/ValueObject/DILParser.cpp @@ -113,6 +113,7 @@ ASTNodeUP DILParser::ParseUnaryExpression() { } return ParsePostfixExpression(); } + // Parse a postfix_expression. // // postfix_expression: diff --git a/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py index ff942c88bf183..76918b872ce77 100644 --- a/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py +++ b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py @@ -25,13 +25,13 @@ def test_frame_var(self): self.expect("settings set target.experimental.use-DIL true", substrs=[""]) self.expect_var_path("s.x", value="1") - self.expect_var_path("s.r", value="2") + self.expect_var_path("s.r", type="int &") self.expect_var_path("sr.x", value="1") - self.expect_var_path("sr.r", value="2") + self.expect_var_path("sr.r", type="int &") self.expect_var_path("sp->x", value="1") - self.expect_var_path("sp->r", value="2") + self.expect_var_path("sp->r", type="int &") self.expect_var_path("sarr->x", value="5"); - self.expect_var_path("sarr->r", value="2") + self.expect_var_path("sarr->r", type="int &") self.expect("frame variable 'sp->foo'", error=True, substrs=["no member named 'foo' in 'Sx'"]) diff --git a/lldb/test/API/commands/frame/var-dil/basics/MemberOf/main.cpp b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/main.cpp index dace888bef4dc..b859c00917f0e 100644 --- a/lldb/test/API/commands/frame/var-dil/basics/MemberOf/main.cpp +++ b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/main.cpp @@ -18,42 +18,3 @@ main(int argc, char**argv) return 0; // Set a breakpoint here } - -/* - EXPECT_THAT(Eval("s.x"), IsEqual("1")); - EXPECT_THAT(Eval("s.r"), IsEqual("2")); - EXPECT_THAT(Eval("s.r + 1"), IsEqual("3")); - EXPECT_THAT(Eval("sr.x"), IsEqual("1")); - EXPECT_THAT(Eval("sr.r"), IsEqual("2")); - EXPECT_THAT(Eval("sr.r + 1"), IsEqual("3")); - EXPECT_THAT(Eval("sp->x"), IsEqual("1")); - EXPECT_THAT(Eval("sp->r"), IsEqual("2")); - EXPECT_THAT(Eval("sp->r + 1"), IsEqual("3")); - EXPECT_THAT(Eval("sarr->x"), IsEqual("5")); - EXPECT_THAT(Eval("sarr->r"), IsEqual("2")); - EXPECT_THAT(Eval("sarr->r + 1"), IsEqual("3")); - EXPECT_THAT(Eval("(sarr + 1)->x"), IsEqual("1")); - - EXPECT_THAT( - Eval("sp->4"), - IsError( - ":1:5: expected 'identifier', got: <'4' (numeric_constant)>\n" - "sp->4\n" - " ^")); - EXPECT_THAT(Eval("sp->foo"), IsError("no member named 'foo' in 'Sx'")); - EXPECT_THAT( - Eval("sp->r / (void*)0"), - IsError("invalid operands to binary expression ('int' and 'void *')")); - - EXPECT_THAT(Eval("sp.x"), IsError("member reference type 'Sx *' is a " - "pointer; did you mean to use '->'")); - EXPECT_THAT( - Eval("sarr.x"), - IsError( - "member reference base type 'Sx[2]' is not a structure or union")); - - // Test for record typedefs. - EXPECT_THAT(Eval("sa.x"), IsEqual("3")); - EXPECT_THAT(Eval("sa.y"), IsEqual("'\\x04'")); - -*/ >From a8eea48b2c63a4a7a4ac55feb9364fa3ff47dc1c Mon Sep 17 00:00:00 2001 From: Caroline Tice Date: Sat, 17 May 2025 12:58:11 -0700 Subject: [PATCH 4/4] - Remove code treating arrays as pointers. - Remove code that automatically dereferenced result. - Update member-of logic to more closely match current frame var implementation. --- lldb/include/lldb/ValueObject/DILAST.h | 17 ++- lldb/include/lldb/ValueObject/DILParser.h | 2 + lldb/source/ValueObject/DILEval.cpp | 117 +++++++++++++----- lldb/source/ValueObject/DILParser.cpp | 6 +- .../MemberOf/TestFrameVarDILMemberOf.py | 6 +- .../frame/var-dil/basics/MemberOf/main.cpp | 2 - 6 files changed, 109 insertions(+), 41 deletions(-) diff --git a/lldb/include/lldb/ValueObject/DILAST.h b/lldb/include/lldb/ValueObject/DILAST.h index 8687316657ca9..05d9ebd26a3b0 100644 --- a/lldb/include/lldb/ValueObject/DILAST.h +++ b/lldb/include/lldb/ValueObject/DILAST.h @@ -92,15 +92,24 @@ class IdentifierNode : public ASTNode { class MemberOfNode : public ASTNode { public: MemberOfNode(uint32_t location, ASTNodeUP base, bool is_arrow, - std::string name) + std::string name, lldb::DynamicValueType use_dynamic, + bool fragile_ivar, bool use_synth_child, + bool check_ptr_vs_member) : ASTNode(location, NodeKind::eMemberOfNode), m_base(std::move(base)), - m_is_arrow(is_arrow), m_field_name(std::move(name)) {} + m_is_arrow(is_arrow), m_field_name(std::move(name)), + m_use_dynamic(use_dynamic), m_fragile_ivar(fragile_ivar), + m_use_synth_child(use_synth_child), + m_check_ptr_vs_member(check_ptr_vs_member) {} llvm::Expected Accept(Visitor *v) const override; ASTNode *GetBase() const { return m_base.get(); } bool GetIsArrow() const { return m_is_arrow; } llvm::StringRef GetFieldName() const { return llvm::StringRef(m_field_name); } + bool GetCheckPtrVsMember() const { return m_check_ptr_vs_member; } + bool GetFragileIvar() const { return m_fragile_ivar; } + bool GetSynthChild() const { return m_use_synth_child; } + lldb::DynamicValueType GetUseDynamic() const { return m_use_dynamic; } static bool classof(const ASTNode *node) { return node->GetKind() == NodeKind::eMemberOfNode; @@ -110,6 +119,10 @@ class MemberOfNode : public ASTNode { ASTNodeUP m_base; bool m_is_arrow; std::string m_field_name; + lldb::DynamicValueType m_use_dynamic; + bool m_fragile_ivar; + bool m_use_synth_child; + bool m_check_ptr_vs_member; }; class UnaryOpNode : public ASTNode { diff --git a/lldb/include/lldb/ValueObject/DILParser.h b/lldb/include/lldb/ValueObject/DILParser.h index c62f8908290f5..bd152940d28f6 100644 --- a/lldb/include/lldb/ValueObject/DILParser.h +++ b/lldb/include/lldb/ValueObject/DILParser.h @@ -118,6 +118,8 @@ class DILParser { lldb::DynamicValueType m_use_dynamic; bool m_use_synthetic; + bool m_fragile_ivar; + bool m_check_ptr_vs_member; }; // class DILParser } // namespace lldb_private::dil diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp index 7eb7591a0a6b2..299916f69c041 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -278,47 +278,104 @@ Interpreter::Visit(const MemberOfNode *node) { if (!base_or_err) return base_or_err; lldb::ValueObjectSP base = *base_or_err; + bool check_ptr_vs_member = node->GetCheckPtrVsMember(); + bool fragile_ivar = node->GetFragileIvar(); + bool synth_child = node->GetSynthChild(); + lldb::DynamicValueType use_dynamic = node->GetUseDynamic(); + + // Perform some basic type & correctness checking. + if (node->GetIsArrow()) { + if (!fragile_ivar) { + // Make sure we aren't trying to deref an objective + // C ivar if this is not allowed + const uint32_t pointer_type_flags = + base->GetCompilerType().GetTypeInfo(nullptr); + if ((pointer_type_flags & lldb::eTypeIsObjC) && + (pointer_type_flags & lldb::eTypeIsPointer)) { + // This was an objective C object pointer and it was requested we + // skip any fragile ivars so return nothing here + return lldb::ValueObjectSP(); + } + } - // Perform basic type checking. - CompilerType base_type = base->GetCompilerType(); - // When using an arrow, make sure the base is a pointer or array type. - // When using a period, make sure the base type is NOT a pointer type. - if (node->GetIsArrow() && !base_type.IsPointerType() && - !base_type.IsArrayType()) { - Status error; - lldb::ValueObjectSP deref_sp = base->Dereference(error); - if (error.Success()) { - base = deref_sp; - base_type = deref_sp->GetCompilerType().GetPointerType(); - } else { - std::string errMsg = - llvm::formatv("member reference type {0} is not a pointer; " - "did you mean to use '.'?", - base_type.TypeDescription()); - return llvm::make_error( - m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); + // If we have a non-pointer type with a synthetic value then lets check + // if we have a synthetic dereference specified. + if (!base->IsPointerType() && base->HasSyntheticValue()) { + Status deref_error; + if (lldb::ValueObjectSP synth_deref_sp = + base->GetSyntheticValue()->Dereference(deref_error); + synth_deref_sp && deref_error.Success()) { + base = std::move(synth_deref_sp); + } + if (!base || deref_error.Fail()) { + std::string errMsg = llvm::formatv( + "Failed to dereference synthetic value: {0}", deref_error); + return llvm::make_error( + m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); + } + + // Some synthetic plug-ins fail to set the error in Dereference + if (!base) { + std::string errMsg = "Failed to dereference synthetic value"; + return llvm::make_error( + m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); + } } - } else if (!node->GetIsArrow() && base_type.IsPointerType()) { - std::string errMsg = - llvm::formatv("member reference type {0} is a pointer; " - "did you mean to use '->'?", - base_type.TypeDescription()); - return llvm::make_error( - m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); } - // User specified array->elem; need to get to element[0] to look for fields. - if (node->GetIsArrow() && base_type.IsArrayType()) - base = base->GetChildAtIndex(0); + if (check_ptr_vs_member) { + bool expr_is_ptr = node->GetIsArrow(); + bool base_is_ptr = base->IsPointerType(); + + if (expr_is_ptr != base_is_ptr) { + if (base_is_ptr) { + std::string errMsg = + llvm::formatv("member reference type {0} is a pointer; " + "did you mean to use '->'?", + base->GetCompilerType().TypeDescription()); + return llvm::make_error( + m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); + } else { + std::string errMsg = + llvm::formatv("member reference type {0} is not a pointer; " + "did you mean to use '.'?", + base->GetCompilerType().TypeDescription()); + return llvm::make_error( + m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); + } + } + } - // Now look for the member with the specified name. lldb::ValueObjectSP field_obj = base->GetChildMemberWithName(node->GetFieldName()); + if (!field_obj) { + if (synth_child) { + field_obj = base->GetSyntheticValue(); + if (field_obj) + field_obj = field_obj->GetChildMemberWithName(node->GetFieldName()); + } + + if (!synth_child || !field_obj) { + std::string errMsg = llvm::formatv( + "no member named '{0}' in {1}", node->GetFieldName(), + base->GetCompilerType().GetFullyUnqualifiedType().TypeDescription()); + return llvm::make_error( + m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); + } + } + if (field_obj && field_obj->GetName() == node->GetFieldName()) { + if (use_dynamic != lldb::eNoDynamicValues) { + lldb::ValueObjectSP dynamic_val_sp = + field_obj->GetDynamicValue(use_dynamic); + if (dynamic_val_sp) + field_obj = dynamic_val_sp; + } return field_obj; } - if (node->GetIsArrow() && base_type.IsPointerType()) + CompilerType base_type = base->GetCompilerType(); + if (node->GetIsArrow() && base->IsPointerType()) base_type = base_type.GetPointeeType(); std::string errMsg = llvm::formatv("no member named '{0}' in {1}", node->GetFieldName(), diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp index 982fbf40e6b39..5c0051dd3eb1d 100644 --- a/lldb/source/ValueObject/DILParser.cpp +++ b/lldb/source/ValueObject/DILParser.cpp @@ -66,7 +66,8 @@ DILParser::DILParser(llvm::StringRef dil_input_expr, DILLexer lexer, llvm::Error &error) : m_ctx_scope(frame_sp), m_input_expr(dil_input_expr), m_dil_lexer(std::move(lexer)), m_error(error), m_use_dynamic(use_dynamic), - m_use_synthetic(use_synthetic) {} + m_use_synthetic(use_synthetic), m_fragile_ivar(fragile_ivar), + m_check_ptr_vs_member(check_ptr_vs_member) {} ASTNodeUP DILParser::Run() { ASTNodeUP expr = ParseExpression(); @@ -130,7 +131,8 @@ ASTNodeUP DILParser::ParsePostfixExpression() { std::string member_id = ParseIdExpression(); lhs = std::make_unique( member_token.GetLocation(), std::move(lhs), - token.GetKind() == Token::arrow, member_id); + token.GetKind() == Token::arrow, member_id, UseDynamic(), + m_fragile_ivar, m_use_synthetic, m_check_ptr_vs_member); } return lhs; } diff --git a/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py index 76918b872ce77..bb16c1f82489d 100644 --- a/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py +++ b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py @@ -30,17 +30,13 @@ def test_frame_var(self): self.expect_var_path("sr.r", type="int &") self.expect_var_path("sp->x", value="1") self.expect_var_path("sp->r", type="int &") - self.expect_var_path("sarr->x", value="5"); - self.expect_var_path("sarr->r", type="int &") self.expect("frame variable 'sp->foo'", error=True, - substrs=["no member named 'foo' in 'Sx'"]) + substrs=["no member named 'foo' in 'Sx *'"]) self.expect("frame variable 'sp.x'", error=True, substrs=["member reference type 'Sx *' is a " "pointer; did you mean to use '->'"]) - self.expect("frame variable 'sarr.x'", error=True, - substrs=["no member named 'x' in 'Sx[2]'"]) # Test for record typedefs. self.expect_var_path("sa.x", value="3") diff --git a/lldb/test/API/commands/frame/var-dil/basics/MemberOf/main.cpp b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/main.cpp index b859c00917f0e..80e8c064b1701 100644 --- a/lldb/test/API/commands/frame/var-dil/basics/MemberOf/main.cpp +++ b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/main.cpp @@ -11,8 +11,6 @@ main(int argc, char**argv) Sx& sr = s; Sx* sp = &s; - Sx sarr[2] = {{5, x, 2}, {1, x, 3}}; - using SxAlias = Sx; SxAlias sa{3, x, 4}; From lldb-commits at lists.llvm.org Sat May 17 13:00:27 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sat, 17 May 2025 13:00:27 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB] Add field member operators to DIL (PR #138093) In-Reply-To: Message-ID: <6828eadb.170a0220.eb782.b0d4@mx.google.com> cmtice wrote: I believe I have addressed all the review comments so far. Please take another look. Thanks! https://github.com/llvm/llvm-project/pull/138093 From lldb-commits at lists.llvm.org Sat May 17 14:43:15 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sat, 17 May 2025 14:43:15 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <682902f3.620a0220.10aea4.ad1a@mx.google.com> https://github.com/eronnen updated https://github.com/llvm/llvm-project/pull/139969 >From a705fec9e42d209ff64be3588ca74567d4319361 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sat, 10 May 2025 20:45:17 +0200 Subject: [PATCH 1/5] support assembly in BreakpointLocationsRequestHandler --- .../breakpoint/TestDAP_setBreakpoints.py | 1 - .../TestDAP_setExceptionBreakpoints.py | 1 - .../TestDAP_setFunctionBreakpoints.py | 1 - lldb/tools/lldb-dap/DAP.h | 3 + .../Handler/BreakpointLocationsHandler.cpp | 77 +++++++++++++++---- lldb/tools/lldb-dap/Handler/RequestHandler.h | 11 +++ .../lldb-dap/Handler/SourceRequestHandler.cpp | 4 +- 7 files changed, 76 insertions(+), 22 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index aae1251b17c93..26df2573555df 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,7 +12,6 @@ import os - at skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py index 4dc8c5b3c7ded..92ac66cd44c5d 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setExceptionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_functionality(self): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index baaca4d974d5d..946595f639edc 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c1a1130b1e59f..587d15891530e 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -219,6 +219,9 @@ struct DAP { llvm::StringSet<> modules; /// @} + /// Number of lines of assembly code to show when no debug info is available. + uint32_t number_of_assembly_lines_for_nodebug = 32; + /// Creates a new DAP sessions. /// /// \param[in] log diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 2ac886c3a5d2c..9eea549d72b00 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "JSONUtils.h" +#include "LLDBUtils.h" #include "RequestHandler.h" #include @@ -19,19 +19,50 @@ namespace lldb_dap { llvm::Expected BreakpointLocationsRequestHandler::Run( const protocol::BreakpointLocationsArguments &args) const { - std::string path = args.source.path.value_or(""); uint32_t start_line = args.line; uint32_t start_column = args.column.value_or(LLDB_INVALID_COLUMN_NUMBER); uint32_t end_line = args.endLine.value_or(start_line); uint32_t end_column = args.endColumn.value_or(std::numeric_limits::max()); + // Find all relevant lines & columns + llvm::SmallVector, 8> locations; + if (args.source.sourceReference) { + AddAssemblyBreakpointLocations(locations, *args.source.sourceReference, + start_line, end_line); + } else { + std::string path = args.source.path.value_or(""); + AddSourceBreakpointLocations(locations, std::move(path), start_line, + start_column, end_line, end_column); + } + + // The line entries are sorted by addresses, but we must return the list + // ordered by line / column position. + std::sort(locations.begin(), locations.end()); + locations.erase(llvm::unique(locations), locations.end()); + + std::vector breakpoint_locations; + for (auto &l : locations) { + protocol::BreakpointLocation lc; + lc.line = l.first; + lc.column = l.second; + breakpoint_locations.push_back(std::move(lc)); + } + + return protocol::BreakpointLocationsResponseBody{ + /*breakpoints=*/std::move(breakpoint_locations)}; +} + +template +void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const { + lldb::SBFileSpec file_spec(path.c_str(), true); lldb::SBSymbolContextList compile_units = dap.target.FindCompileUnits(file_spec); - // Find all relevant lines & columns - llvm::SmallVector, 8> locations; for (uint32_t c_idx = 0, c_limit = compile_units.GetSize(); c_idx < c_limit; ++c_idx) { const lldb::SBCompileUnit &compile_unit = @@ -71,22 +102,34 @@ BreakpointLocationsRequestHandler::Run( locations.emplace_back(line, column); } } +} - // The line entries are sorted by addresses, but we must return the list - // ordered by line / column position. - std::sort(locations.begin(), locations.end()); - locations.erase(llvm::unique(locations), locations.end()); +template +void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { + lldb::SBProcess process = dap.target.GetProcess(); + lldb::SBThread thread = + process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); + lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - std::vector breakpoint_locations; - for (auto &l : locations) { - protocol::BreakpointLocation lc; - lc.line = l.first; - lc.column = l.second; - breakpoint_locations.push_back(std::move(lc)); - } + if (!frame.IsValid()) + return; - return protocol::BreakpointLocationsResponseBody{ - /*breakpoints=*/std::move(breakpoint_locations)}; + lldb::SBSymbol symbol = frame.GetSymbol(); + if (symbol.IsValid()) { + lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); + } + } else { + for (uint32_t i = start_line - 1; + i < dap.number_of_assembly_lines_for_nodebug && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); + } + } } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 383f9e24a729a..34f2423e01f60 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -16,6 +16,7 @@ #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/JSON.h" @@ -224,6 +225,16 @@ class BreakpointLocationsRequestHandler } llvm::Expected Run(const protocol::BreakpointLocationsArguments &args) const override; + + template + void AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const; + template + void AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const; }; class CompletionsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp index 0ddd87881a164..fb396a3dc8862 100644 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp @@ -52,8 +52,8 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { insts.GetDescription(stream, exe_ctx); } else { // No valid symbol, just return the disassembly. - lldb::SBInstructionList insts = - dap.target.ReadInstructions(frame.GetPCAddress(), 32); + lldb::SBInstructionList insts = dap.target.ReadInstructions( + frame.GetPCAddress(), dap.number_of_assembly_lines_for_nodebug); insts.GetDescription(stream, exe_ctx); } >From 9e305534dae0d0e21d827cc3e4bb4d302dcaab23 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 11 May 2025 19:49:03 +0200 Subject: [PATCH 2/5] support assembly in SetBreakpointsRequestHandler --- lldb/tools/lldb-dap/DAP.h | 1 + .../Handler/BreakpointLocationsHandler.cpp | 20 ++--- lldb/tools/lldb-dap/Handler/RequestHandler.h | 9 ++ .../Handler/SetBreakpointsRequestHandler.cpp | 90 ++++++++++++++++++- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 22 +++++ lldb/tools/lldb-dap/SourceBreakpoint.h | 1 + 6 files changed, 127 insertions(+), 16 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 587d15891530e..0bc9063e1266f 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -169,6 +169,7 @@ struct DAP { Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; + llvm::DenseMap assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 9eea549d72b00..be02c47056310 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -117,18 +117,14 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( return; lldb::SBSymbol symbol = frame.GetSymbol(); - if (symbol.IsValid()) { - lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); - ++i) { - locations.emplace_back(i, 0); - } - } else { - for (uint32_t i = start_line - 1; - i < dap.number_of_assembly_lines_for_nodebug && i < (end_line - 1); - ++i) { - locations.emplace_back(i, 0); - } + if (!symbol.IsValid()) + return; + + // start_line is relative to the symbol's start address + lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); } } diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 34f2423e01f60..ddd01ffe33823 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -379,6 +379,15 @@ class SetBreakpointsRequestHandler } llvm::Expected Run(const protocol::SetBreakpointsArguments &args) const override; + + std::vector SetSourceBreakpoints( + const std::string &path, + const std::optional> &breakpoints) + const; + std::vector SetAssemblyBreakpoints( + int64_t sourceReference, + const std::optional> &breakpoints) + const; }; class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 86e090b66afe9..71f9e5578ef08 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -9,8 +9,11 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" +#include +#include #include namespace lldb_dap { @@ -23,15 +26,30 @@ llvm::Expected SetBreakpointsRequestHandler::Run( const protocol::SetBreakpointsArguments &args) const { const auto &source = args.source; - const auto path = source.path.value_or(""); + std::vector response_breakpoints; + if (source.sourceReference) + response_breakpoints = SetAssemblyBreakpoints( + source.sourceReference.value(), args.breakpoints); + else if (source.path) + response_breakpoints = + SetSourceBreakpoints(source.path.value(), args.breakpoints); + + return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; +} + +std::vector +SetBreakpointsRequestHandler::SetSourceBreakpoints( + const std::string &path, + const std::optional> &breakpoints) + const { std::vector response_breakpoints; // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; // "breakpoints" may be unset, in which case we treat it the same as being set // to an empty array. - if (args.breakpoints) { - for (const auto &bp : *args.breakpoints) { + if (breakpoints) { + for (const auto &bp : *breakpoints) { SourceBreakpoint src_bp(dap, bp); std::pair bp_pos(src_bp.GetLine(), src_bp.GetColumn()); @@ -73,7 +91,71 @@ SetBreakpointsRequestHandler::Run( } } - return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; + return response_breakpoints; +} + +std::vector +SetBreakpointsRequestHandler::SetAssemblyBreakpoints( + int64_t sourceReference, + const std::optional> &breakpoints) + const { + std::vector response_breakpoints; + + lldb::SBProcess process = dap.target.GetProcess(); + lldb::SBThread thread = + process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); + lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); + + if (!frame.IsValid()) + return response_breakpoints; + + lldb::SBSymbol symbol = frame.GetSymbol(); + if (!symbol.IsValid()) + return response_breakpoints; // Not yet supporting breakpoints in assembly + // without a valid symbol + + SourceBreakpointMap request_bps; + if (breakpoints) { + for (const auto &bp : *breakpoints) { + SourceBreakpoint src_bp(dap, bp); + std::pair bp_pos(src_bp.GetLine(), 0); + request_bps.try_emplace(bp_pos, src_bp); + const auto [iv, inserted] = + dap.assembly_breakpoints[sourceReference].try_emplace(bp_pos, src_bp); + // We check if this breakpoint already exists to update it + if (inserted) + iv->getSecond().SetBreakpoint(symbol); + else + iv->getSecond().UpdateBreakpoint(src_bp); + + protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); + protocol::Source source; + source.sourceReference = sourceReference; + source.name = symbol.GetName(); + response_bp.source = std::move(source); + + if (!response_bp.line) + response_bp.line = src_bp.GetLine(); + if (!response_bp.column) + response_bp.column = src_bp.GetColumn(); + response_breakpoints.push_back(response_bp); + } + } + + // Delete existing breakpoints for this sourceReference that are not in the + // request_bps set. + auto old_src_bp_pos = dap.assembly_breakpoints.find(sourceReference); + if (old_src_bp_pos != dap.assembly_breakpoints.end()) { + for (auto &old_bp : old_src_bp_pos->second) { + auto request_pos = request_bps.find(old_bp.first); + if (request_pos == request_bps.end()) { + dap.target.BreakpointDelete(old_bp.second.GetID()); + old_src_bp_pos->second.erase(old_bp.first); + } + } + } + + return response_breakpoints; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 4581c995b4260..938b8fb8bcdda 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -13,7 +13,9 @@ #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBFileSpecList.h" #include "lldb/API/SBFrame.h" +#include "lldb/API/SBInstruction.h" #include "lldb/API/SBMutex.h" +#include "lldb/API/SBSymbol.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" #include "lldb/API/SBValue.h" @@ -45,6 +47,26 @@ void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) { Breakpoint::SetBreakpoint(); } +void SourceBreakpoint::SetBreakpoint(lldb::SBSymbol &symbol) { + lldb::SBMutex lock = m_dap.GetAPIMutex(); + std::lock_guard guard(lock); + + if (m_line == 0) + return; + + lldb::SBInstructionList inst_list = + m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); + if (inst_list.GetSize() < m_line) + return; + lldb::SBAddress address = + inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + + m_bp = m_dap.target.BreakpointCreateBySBAddress(address); + if (!m_log_message.empty()) + SetLogMessage(); + Breakpoint::SetBreakpoint(); +} + void SourceBreakpoint::UpdateBreakpoint(const SourceBreakpoint &request_bp) { if (m_log_message != request_bp.m_log_message) { m_log_message = request_bp.m_log_message; diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h index 5b15296f861c5..8589800e50983 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.h +++ b/lldb/tools/lldb-dap/SourceBreakpoint.h @@ -26,6 +26,7 @@ class SourceBreakpoint : public Breakpoint { // Set this breakpoint in LLDB as a new breakpoint void SetBreakpoint(const llvm::StringRef source_path); + void SetBreakpoint(lldb::SBSymbol &symbol); void UpdateBreakpoint(const SourceBreakpoint &request_bp); void SetLogMessage(); >From cb47dbc97fbbc1e2db9bd9c8989dcce425c796ee Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Wed, 14 May 2025 23:51:41 +0200 Subject: [PATCH 3/5] fix resolving of assembly source breakpoints --- lldb/tools/lldb-dap/Breakpoint.cpp | 45 ++++++++++++++++--- lldb/tools/lldb-dap/DAP.h | 3 +- .../Handler/BreakpointLocationsHandler.cpp | 4 +- lldb/tools/lldb-dap/Handler/RequestHandler.h | 4 +- .../Handler/SetBreakpointsRequestHandler.cpp | 30 ++++++------- lldb/tools/lldb-dap/package-lock.json | 4 +- lldb/tools/lldb-dap/package.json | 5 ++- 7 files changed, 63 insertions(+), 32 deletions(-) diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 26d633d1d172e..87fcd15b0a568 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -9,10 +9,12 @@ #include "Breakpoint.h" #include "DAP.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "lldb/API/SBAddress.h" #include "lldb/API/SBBreakpointLocation.h" #include "lldb/API/SBLineEntry.h" #include "lldb/API/SBMutex.h" +#include "lldb/lldb-enumerations.h" #include "llvm/ADT/StringExtras.h" #include #include @@ -63,14 +65,43 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { std::string formatted_addr = "0x" + llvm::utohexstr(bp_addr.GetLoadAddress(m_bp.GetTarget())); breakpoint.instructionReference = formatted_addr; + + lldb::StopDisassemblyType stop_disassembly_display = + GetStopDisassemblyDisplay(m_dap.debugger); auto line_entry = bp_addr.GetLineEntry(); - const auto line = line_entry.GetLine(); - if (line != UINT32_MAX) - breakpoint.line = line; - const auto column = line_entry.GetColumn(); - if (column != 0) - breakpoint.column = column; - breakpoint.source = CreateSource(line_entry); + if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) { + const auto line = line_entry.GetLine(); + if (line != UINT32_MAX) + breakpoint.line = line; + const auto column = line_entry.GetColumn(); + if (column != 0) + breakpoint.column = column; + breakpoint.source = CreateSource(line_entry); + } else { + // Breakpoint made by assembly + auto symbol_context = bp_addr.GetSymbolContext( + lldb::eSymbolContextSymbol | lldb::eSymbolContextModule); + if (symbol_context.IsValid()) { + auto symbol = symbol_context.GetSymbol(); + breakpoint.line = + m_bp.GetTarget() + .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) + .GetSize() + + 1; + protocol::Source source; + source.name = symbol.GetName(); + + auto module = symbol_context.GetModule(); + if (module.IsValid()) { + std::string path = module.GetFileSpec().GetDirectory(); + path += "/"; + path += module.GetFileSpec().GetFilename(); + source.path = std::move(path); + } + + breakpoint.source = std::move(source); + } + } } return breakpoint; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 0bc9063e1266f..54b233077f0c3 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -169,7 +169,8 @@ struct DAP { Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; - llvm::DenseMap assembly_breakpoints; + llvm::DenseMap> + assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index be02c47056310..06ada47a6f27f 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -122,9 +122,9 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( // start_line is relative to the symbol's start address lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i <= (end_line - 1); ++i) { - locations.emplace_back(i, 0); + locations.emplace_back(i, 1); } } diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index ddd01ffe33823..fec304979995e 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -381,11 +381,11 @@ class SetBreakpointsRequestHandler Run(const protocol::SetBreakpointsArguments &args) const override; std::vector SetSourceBreakpoints( - const std::string &path, + const protocol::Source &source, const std::optional> &breakpoints) const; std::vector SetAssemblyBreakpoints( - int64_t sourceReference, + const protocol::Source &source, const std::optional> &breakpoints) const; }; diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 71f9e5578ef08..4fefd8b440c7d 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -28,21 +28,20 @@ SetBreakpointsRequestHandler::Run( const auto &source = args.source; std::vector response_breakpoints; if (source.sourceReference) - response_breakpoints = SetAssemblyBreakpoints( - source.sourceReference.value(), args.breakpoints); + response_breakpoints = SetAssemblyBreakpoints(source, args.breakpoints); else if (source.path) - response_breakpoints = - SetSourceBreakpoints(source.path.value(), args.breakpoints); + response_breakpoints = SetSourceBreakpoints(source, args.breakpoints); return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; } std::vector SetBreakpointsRequestHandler::SetSourceBreakpoints( - const std::string &path, + const protocol::Source &source, const std::optional> &breakpoints) const { std::vector response_breakpoints; + std::string path = source.path.value_or(""); // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; @@ -96,10 +95,11 @@ SetBreakpointsRequestHandler::SetSourceBreakpoints( std::vector SetBreakpointsRequestHandler::SetAssemblyBreakpoints( - int64_t sourceReference, + const protocol::Source &source, const std::optional> &breakpoints) const { std::vector response_breakpoints; + int64_t sourceReference = source.sourceReference.value_or(0); lldb::SBProcess process = dap.target.GetProcess(); lldb::SBThread thread = @@ -114,14 +114,14 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( return response_breakpoints; // Not yet supporting breakpoints in assembly // without a valid symbol - SourceBreakpointMap request_bps; + llvm::DenseMap request_bps; if (breakpoints) { for (const auto &bp : *breakpoints) { SourceBreakpoint src_bp(dap, bp); - std::pair bp_pos(src_bp.GetLine(), 0); - request_bps.try_emplace(bp_pos, src_bp); + request_bps.try_emplace(src_bp.GetLine(), src_bp); const auto [iv, inserted] = - dap.assembly_breakpoints[sourceReference].try_emplace(bp_pos, src_bp); + dap.assembly_breakpoints[sourceReference].try_emplace( + src_bp.GetLine(), src_bp); // We check if this breakpoint already exists to update it if (inserted) iv->getSecond().SetBreakpoint(symbol); @@ -129,15 +129,11 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( iv->getSecond().UpdateBreakpoint(src_bp); protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - protocol::Source source; - source.sourceReference = sourceReference; - source.name = symbol.GetName(); - response_bp.source = std::move(source); - + response_bp.source = source; if (!response_bp.line) response_bp.line = src_bp.GetLine(); - if (!response_bp.column) - response_bp.column = src_bp.GetColumn(); + if (bp.column) + response_bp.column = *bp.column; response_breakpoints.push_back(response_bp); } } diff --git a/lldb/tools/lldb-dap/package-lock.json b/lldb/tools/lldb-dap/package-lock.json index 0a2b9e764067e..af90a9573aee6 100644 --- a/lldb/tools/lldb-dap/package-lock.json +++ b/lldb/tools/lldb-dap/package-lock.json @@ -1,12 +1,12 @@ { "name": "lldb-dap", - "version": "0.2.13", + "version": "0.2.14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lldb-dap", - "version": "0.2.13", + "version": "0.2.14", "license": "Apache 2.0 License with LLVM exceptions", "devDependencies": { "@types/node": "^18.19.41", diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index d5ca604798799..73e70cd961f4f 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -1,7 +1,7 @@ { "name": "lldb-dap", "displayName": "LLDB DAP", - "version": "0.2.13", + "version": "0.2.14", "publisher": "llvm-vs-code-extensions", "homepage": "https://lldb.llvm.org", "description": "Debugging with LLDB in Visual Studio Code", @@ -265,6 +265,9 @@ ] }, "breakpoints": [ + { + "language": "lldb.disassembly" + }, { "language": "ada" }, >From 6e1135deac7c1a58a85fc6f25a032d4c61e09d66 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Thu, 15 May 2025 00:36:10 +0200 Subject: [PATCH 4/5] remove include --- lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 4fefd8b440c7d..d69da5bd02c1e 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -12,8 +12,6 @@ #include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" -#include -#include #include namespace lldb_dap { >From 3807a12724feb3fb2dc9b46db20611e8813cb77b Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sat, 17 May 2025 21:05:27 +0200 Subject: [PATCH 5/5] use load address as sourceReference --- lldb/include/lldb/API/SBFileSpec.h | 3 + lldb/source/API/SBFileSpec.cpp | 8 ++ lldb/tools/lldb-dap/Breakpoint.cpp | 18 +---- .../Handler/BreakpointLocationsHandler.cpp | 11 +-- .../Handler/SetBreakpointsRequestHandler.cpp | 11 +-- .../lldb-dap/Handler/SourceRequestHandler.cpp | 18 ++--- lldb/tools/lldb-dap/JSONUtils.cpp | 75 +++++++++++++------ lldb/tools/lldb-dap/JSONUtils.h | 14 ++++ 8 files changed, 96 insertions(+), 62 deletions(-) diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index 36641843aabeb..303cb7d712cbf 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -10,6 +10,7 @@ #define LLDB_API_SBFILESPEC_H #include "lldb/API/SBDefines.h" +#include "lldb/API/SBStream.h" namespace lldb { @@ -53,6 +54,8 @@ class LLDB_API SBFileSpec { uint32_t GetPath(char *dst_path, size_t dst_len) const; + bool GetPath(lldb::SBStream &dst_path) const; + static int ResolvePath(const char *src_path, char *dst_path, size_t dst_len); bool GetDescription(lldb::SBStream &description) const; diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp index a7df9afc4b8eb..cb44dac1d4fcc 100644 --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -19,6 +19,7 @@ #include #include +#include using namespace lldb; using namespace lldb_private; @@ -147,6 +148,13 @@ uint32_t SBFileSpec::GetPath(char *dst_path, size_t dst_len) const { return result; } +bool SBFileSpec::GetPath(SBStream &dst_path) const { + LLDB_INSTRUMENT_VA(this, dst_path); + + std::string path = m_opaque_up->GetPath(); + return dst_path->PutCString(path.c_str()) > 0; +} + const lldb_private::FileSpec *SBFileSpec::operator->() const { return m_opaque_up.get(); } diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 87fcd15b0a568..a54a34e0f936d 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -79,27 +79,15 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { breakpoint.source = CreateSource(line_entry); } else { // Breakpoint made by assembly - auto symbol_context = bp_addr.GetSymbolContext( - lldb::eSymbolContextSymbol | lldb::eSymbolContextModule); - if (symbol_context.IsValid()) { - auto symbol = symbol_context.GetSymbol(); + auto symbol = bp_addr.GetSymbol(); + if (symbol.IsValid()) { breakpoint.line = m_bp.GetTarget() .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) .GetSize() + 1; - protocol::Source source; - source.name = symbol.GetName(); - auto module = symbol_context.GetModule(); - if (module.IsValid()) { - std::string path = module.GetFileSpec().GetDirectory(); - path += "/"; - path += module.GetFileSpec().GetFilename(); - source.path = std::move(path); - } - - breakpoint.source = std::move(source); + breakpoint.source = CreateAssemblySource(m_dap.target, bp_addr); } } } diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 06ada47a6f27f..c4d658caeee2d 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "LLDBUtils.h" #include "RequestHandler.h" #include @@ -108,15 +107,11 @@ template void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( llvm::SmallVector, N> &locations, int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { - lldb::SBProcess process = dap.target.GetProcess(); - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - - if (!frame.IsValid()) + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) return; - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) return; diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index d69da5bd02c1e..7b401f06e9a85 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -9,7 +9,6 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" -#include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" #include @@ -99,15 +98,11 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( std::vector response_breakpoints; int64_t sourceReference = source.sourceReference.value_or(0); - lldb::SBProcess process = dap.target.GetProcess(); - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - - if (!frame.IsValid()) + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) return response_breakpoints; - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) return response_breakpoints; // Not yet supporting breakpoints in assembly // without a valid symbol diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp index fb396a3dc8862..9249e2aa6fef7 100644 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp @@ -11,6 +11,7 @@ #include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" +#include "lldb/API/SBAddress.h" #include "lldb/API/SBExecutionContext.h" #include "lldb/API/SBFrame.h" #include "lldb/API/SBInstructionList.h" @@ -19,6 +20,7 @@ #include "lldb/API/SBSymbol.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" +#include "lldb/lldb-types.h" #include "llvm/Support/Error.h" namespace lldb_dap { @@ -34,18 +36,14 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { return llvm::make_error( "invalid arguments, expected source.sourceReference to be set"); - lldb::SBProcess process = dap.target.GetProcess(); - // Upper 32 bits is the thread index ID - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(source)); - // Lower 32 bits is the frame index - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(source)); - if (!frame.IsValid()) + lldb::SBAddress address(source, dap.target); + if (!address.IsValid()) return llvm::make_error("source not found"); + lldb::SBSymbol symbol = address.GetSymbol(); + lldb::SBStream stream; - lldb::SBExecutionContext exe_ctx(frame); - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBExecutionContext exe_ctx(dap.target); if (symbol.IsValid()) { lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); @@ -53,7 +51,7 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { } else { // No valid symbol, just return the disassembly. lldb::SBInstructionList insts = dap.target.ReadInstructions( - frame.GetPCAddress(), dap.number_of_assembly_lines_for_nodebug); + address, dap.number_of_assembly_lines_for_nodebug); insts.GetDescription(stream, exe_ctx); } diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index a8bd672583a5d..54e45cfc3319c 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -490,6 +490,13 @@ CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp) { return filter; } +static std::string GetLoadAddressString(const lldb::addr_t addr) { + std::string result; + llvm::raw_string_ostream os(result); + os << llvm::format_hex(addr, 18); + return result; +} + protocol::Source CreateSource(const lldb::SBFileSpec &file) { protocol::Source source; if (file.IsValid()) { @@ -516,6 +523,43 @@ protocol::Source CreateSource(llvm::StringRef source_path) { return source; } +protocol::Source CreateAssemblySource(const lldb::SBTarget &target, + lldb::SBAddress &address) { + protocol::Source source; + + auto symbol = address.GetSymbol(); + std::string name; + if (symbol.IsValid()) { + source.sourceReference = symbol.GetStartAddress().GetLoadAddress(target); + name = symbol.GetName(); + } else { + const auto load_addr = address.GetLoadAddress(target); + source.sourceReference = load_addr; + name = GetLoadAddressString(load_addr); + } + + lldb::SBModule module = address.GetModule(); + if (module.IsValid()) { + lldb::SBFileSpec file_spec = module.GetFileSpec(); + if (file_spec.IsValid()) { + lldb::SBStream module_path; + if (file_spec.GetPath(module_path)) { + std::string path = module_path.GetData(); + source.path = path + '`' + name; + } + } + } + + source.name = std::move(name); + + // Mark the source as deemphasized since users will only be able to view + // assembly for these frames. + source.presentationHint = + protocol::Source::PresentationHint::eSourcePresentationHintDeemphasize; + + return source; +} + bool ShouldDisplayAssemblySource( const lldb::SBLineEntry &line_entry, lldb::StopDisassemblyType stop_disassembly_display) { @@ -619,12 +663,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, frame_name = name; } - if (frame_name.empty()) { + if (frame_name.empty()) // If the function name is unavailable, display the pc address as a 16-digit // hex string, e.g. "0x0000000000012345" - llvm::raw_string_ostream os(frame_name); - os << llvm::format_hex(frame.GetPC(), 18); - } + frame_name = GetLoadAddressString(frame.GetPC()); // We only include `[opt]` if a custom frame format is not specified. if (!format && frame.GetFunction().GetIsOptimized()) @@ -641,17 +683,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, } else if (frame.GetSymbol().IsValid()) { // If no source is associated with the frame, use the DAPFrameID to track // the 'source' and generate assembly. - llvm::json::Object source; - EmplaceSafeString(source, "name", frame_name); - char buf[PATH_MAX] = {0}; - size_t size = frame.GetModule().GetFileSpec().GetPath(buf, PATH_MAX); - EmplaceSafeString(source, "path", - std::string(buf, size) + '`' + frame_name); - source.try_emplace("sourceReference", MakeDAPFrameID(frame)); - // Mark the source as deemphasized since users will only be able to view - // assembly for these frames. - EmplaceSafeString(source, "presentationHint", "deemphasize"); - object.try_emplace("source", std::move(source)); + auto frame_address = frame.GetPCAddress(); + object.try_emplace("source", CreateAssemblySource( + frame.GetThread().GetProcess().GetTarget(), + frame_address)); // Calculate the line of the current PC from the start of the current // symbol. @@ -665,12 +700,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, object.try_emplace("column", 1); } else { // No valid line entry or symbol. - llvm::json::Object source; - EmplaceSafeString(source, "name", frame_name); - source.try_emplace("sourceReference", MakeDAPFrameID(frame)); - EmplaceSafeString(source, "presentationHint", "deemphasize"); - object.try_emplace("source", std::move(source)); - + auto frame_address = frame.GetPCAddress(); + object.try_emplace("source", CreateAssemblySource( + frame.GetThread().GetProcess().GetTarget(), + frame_address)); object.try_emplace("line", 1); object.try_emplace("column", 1); } diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h index 783f291338d8c..ac9b39739104f 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -269,6 +269,20 @@ protocol::Source CreateSource(const lldb::SBLineEntry &line_entry); /// definition outlined by Microsoft. protocol::Source CreateSource(llvm::StringRef source_path); +/// Create a "Source" object for a given frame, using its assembly for source. +/// +/// \param[in] target +/// The relevant target. +/// +/// \param[in] address +/// The address to use when creating the "Source" object. +/// +/// \return +/// A "Source" JSON object that follows the formal JSON +/// definition outlined by Microsoft. +protocol::Source CreateAssemblySource(const lldb::SBTarget &target, + lldb::SBAddress &address); + /// Return true if the given line entry should be displayed as assembly. /// /// \param[in] line_entry From lldb-commits at lists.llvm.org Sat May 17 14:52:16 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sat, 17 May 2025 14:52:16 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68290510.170a0220.1340e5.93af@mx.google.com> https://github.com/eronnen edited https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sat May 17 14:59:26 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sat, 17 May 2025 14:59:26 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <682906be.170a0220.38baf2.8f87@mx.google.com> https://github.com/eronnen edited https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sat May 17 17:25:54 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sat, 17 May 2025 17:25:54 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68292912.170a0220.2fe732.5dce@mx.google.com> https://github.com/eronnen updated https://github.com/llvm/llvm-project/pull/139969 >From a705fec9e42d209ff64be3588ca74567d4319361 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sat, 10 May 2025 20:45:17 +0200 Subject: [PATCH 1/6] support assembly in BreakpointLocationsRequestHandler --- .../breakpoint/TestDAP_setBreakpoints.py | 1 - .../TestDAP_setExceptionBreakpoints.py | 1 - .../TestDAP_setFunctionBreakpoints.py | 1 - lldb/tools/lldb-dap/DAP.h | 3 + .../Handler/BreakpointLocationsHandler.cpp | 77 +++++++++++++++---- lldb/tools/lldb-dap/Handler/RequestHandler.h | 11 +++ .../lldb-dap/Handler/SourceRequestHandler.cpp | 4 +- 7 files changed, 76 insertions(+), 22 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index aae1251b17c93..26df2573555df 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,7 +12,6 @@ import os - at skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py index 4dc8c5b3c7ded..92ac66cd44c5d 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setExceptionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_functionality(self): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index baaca4d974d5d..946595f639edc 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c1a1130b1e59f..587d15891530e 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -219,6 +219,9 @@ struct DAP { llvm::StringSet<> modules; /// @} + /// Number of lines of assembly code to show when no debug info is available. + uint32_t number_of_assembly_lines_for_nodebug = 32; + /// Creates a new DAP sessions. /// /// \param[in] log diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 2ac886c3a5d2c..9eea549d72b00 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "JSONUtils.h" +#include "LLDBUtils.h" #include "RequestHandler.h" #include @@ -19,19 +19,50 @@ namespace lldb_dap { llvm::Expected BreakpointLocationsRequestHandler::Run( const protocol::BreakpointLocationsArguments &args) const { - std::string path = args.source.path.value_or(""); uint32_t start_line = args.line; uint32_t start_column = args.column.value_or(LLDB_INVALID_COLUMN_NUMBER); uint32_t end_line = args.endLine.value_or(start_line); uint32_t end_column = args.endColumn.value_or(std::numeric_limits::max()); + // Find all relevant lines & columns + llvm::SmallVector, 8> locations; + if (args.source.sourceReference) { + AddAssemblyBreakpointLocations(locations, *args.source.sourceReference, + start_line, end_line); + } else { + std::string path = args.source.path.value_or(""); + AddSourceBreakpointLocations(locations, std::move(path), start_line, + start_column, end_line, end_column); + } + + // The line entries are sorted by addresses, but we must return the list + // ordered by line / column position. + std::sort(locations.begin(), locations.end()); + locations.erase(llvm::unique(locations), locations.end()); + + std::vector breakpoint_locations; + for (auto &l : locations) { + protocol::BreakpointLocation lc; + lc.line = l.first; + lc.column = l.second; + breakpoint_locations.push_back(std::move(lc)); + } + + return protocol::BreakpointLocationsResponseBody{ + /*breakpoints=*/std::move(breakpoint_locations)}; +} + +template +void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const { + lldb::SBFileSpec file_spec(path.c_str(), true); lldb::SBSymbolContextList compile_units = dap.target.FindCompileUnits(file_spec); - // Find all relevant lines & columns - llvm::SmallVector, 8> locations; for (uint32_t c_idx = 0, c_limit = compile_units.GetSize(); c_idx < c_limit; ++c_idx) { const lldb::SBCompileUnit &compile_unit = @@ -71,22 +102,34 @@ BreakpointLocationsRequestHandler::Run( locations.emplace_back(line, column); } } +} - // The line entries are sorted by addresses, but we must return the list - // ordered by line / column position. - std::sort(locations.begin(), locations.end()); - locations.erase(llvm::unique(locations), locations.end()); +template +void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { + lldb::SBProcess process = dap.target.GetProcess(); + lldb::SBThread thread = + process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); + lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - std::vector breakpoint_locations; - for (auto &l : locations) { - protocol::BreakpointLocation lc; - lc.line = l.first; - lc.column = l.second; - breakpoint_locations.push_back(std::move(lc)); - } + if (!frame.IsValid()) + return; - return protocol::BreakpointLocationsResponseBody{ - /*breakpoints=*/std::move(breakpoint_locations)}; + lldb::SBSymbol symbol = frame.GetSymbol(); + if (symbol.IsValid()) { + lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); + } + } else { + for (uint32_t i = start_line - 1; + i < dap.number_of_assembly_lines_for_nodebug && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); + } + } } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 383f9e24a729a..34f2423e01f60 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -16,6 +16,7 @@ #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/JSON.h" @@ -224,6 +225,16 @@ class BreakpointLocationsRequestHandler } llvm::Expected Run(const protocol::BreakpointLocationsArguments &args) const override; + + template + void AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const; + template + void AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const; }; class CompletionsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp index 0ddd87881a164..fb396a3dc8862 100644 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp @@ -52,8 +52,8 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { insts.GetDescription(stream, exe_ctx); } else { // No valid symbol, just return the disassembly. - lldb::SBInstructionList insts = - dap.target.ReadInstructions(frame.GetPCAddress(), 32); + lldb::SBInstructionList insts = dap.target.ReadInstructions( + frame.GetPCAddress(), dap.number_of_assembly_lines_for_nodebug); insts.GetDescription(stream, exe_ctx); } >From 9e305534dae0d0e21d827cc3e4bb4d302dcaab23 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 11 May 2025 19:49:03 +0200 Subject: [PATCH 2/6] support assembly in SetBreakpointsRequestHandler --- lldb/tools/lldb-dap/DAP.h | 1 + .../Handler/BreakpointLocationsHandler.cpp | 20 ++--- lldb/tools/lldb-dap/Handler/RequestHandler.h | 9 ++ .../Handler/SetBreakpointsRequestHandler.cpp | 90 ++++++++++++++++++- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 22 +++++ lldb/tools/lldb-dap/SourceBreakpoint.h | 1 + 6 files changed, 127 insertions(+), 16 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 587d15891530e..0bc9063e1266f 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -169,6 +169,7 @@ struct DAP { Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; + llvm::DenseMap assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 9eea549d72b00..be02c47056310 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -117,18 +117,14 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( return; lldb::SBSymbol symbol = frame.GetSymbol(); - if (symbol.IsValid()) { - lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); - ++i) { - locations.emplace_back(i, 0); - } - } else { - for (uint32_t i = start_line - 1; - i < dap.number_of_assembly_lines_for_nodebug && i < (end_line - 1); - ++i) { - locations.emplace_back(i, 0); - } + if (!symbol.IsValid()) + return; + + // start_line is relative to the symbol's start address + lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); } } diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 34f2423e01f60..ddd01ffe33823 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -379,6 +379,15 @@ class SetBreakpointsRequestHandler } llvm::Expected Run(const protocol::SetBreakpointsArguments &args) const override; + + std::vector SetSourceBreakpoints( + const std::string &path, + const std::optional> &breakpoints) + const; + std::vector SetAssemblyBreakpoints( + int64_t sourceReference, + const std::optional> &breakpoints) + const; }; class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 86e090b66afe9..71f9e5578ef08 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -9,8 +9,11 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" +#include +#include #include namespace lldb_dap { @@ -23,15 +26,30 @@ llvm::Expected SetBreakpointsRequestHandler::Run( const protocol::SetBreakpointsArguments &args) const { const auto &source = args.source; - const auto path = source.path.value_or(""); + std::vector response_breakpoints; + if (source.sourceReference) + response_breakpoints = SetAssemblyBreakpoints( + source.sourceReference.value(), args.breakpoints); + else if (source.path) + response_breakpoints = + SetSourceBreakpoints(source.path.value(), args.breakpoints); + + return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; +} + +std::vector +SetBreakpointsRequestHandler::SetSourceBreakpoints( + const std::string &path, + const std::optional> &breakpoints) + const { std::vector response_breakpoints; // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; // "breakpoints" may be unset, in which case we treat it the same as being set // to an empty array. - if (args.breakpoints) { - for (const auto &bp : *args.breakpoints) { + if (breakpoints) { + for (const auto &bp : *breakpoints) { SourceBreakpoint src_bp(dap, bp); std::pair bp_pos(src_bp.GetLine(), src_bp.GetColumn()); @@ -73,7 +91,71 @@ SetBreakpointsRequestHandler::Run( } } - return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; + return response_breakpoints; +} + +std::vector +SetBreakpointsRequestHandler::SetAssemblyBreakpoints( + int64_t sourceReference, + const std::optional> &breakpoints) + const { + std::vector response_breakpoints; + + lldb::SBProcess process = dap.target.GetProcess(); + lldb::SBThread thread = + process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); + lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); + + if (!frame.IsValid()) + return response_breakpoints; + + lldb::SBSymbol symbol = frame.GetSymbol(); + if (!symbol.IsValid()) + return response_breakpoints; // Not yet supporting breakpoints in assembly + // without a valid symbol + + SourceBreakpointMap request_bps; + if (breakpoints) { + for (const auto &bp : *breakpoints) { + SourceBreakpoint src_bp(dap, bp); + std::pair bp_pos(src_bp.GetLine(), 0); + request_bps.try_emplace(bp_pos, src_bp); + const auto [iv, inserted] = + dap.assembly_breakpoints[sourceReference].try_emplace(bp_pos, src_bp); + // We check if this breakpoint already exists to update it + if (inserted) + iv->getSecond().SetBreakpoint(symbol); + else + iv->getSecond().UpdateBreakpoint(src_bp); + + protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); + protocol::Source source; + source.sourceReference = sourceReference; + source.name = symbol.GetName(); + response_bp.source = std::move(source); + + if (!response_bp.line) + response_bp.line = src_bp.GetLine(); + if (!response_bp.column) + response_bp.column = src_bp.GetColumn(); + response_breakpoints.push_back(response_bp); + } + } + + // Delete existing breakpoints for this sourceReference that are not in the + // request_bps set. + auto old_src_bp_pos = dap.assembly_breakpoints.find(sourceReference); + if (old_src_bp_pos != dap.assembly_breakpoints.end()) { + for (auto &old_bp : old_src_bp_pos->second) { + auto request_pos = request_bps.find(old_bp.first); + if (request_pos == request_bps.end()) { + dap.target.BreakpointDelete(old_bp.second.GetID()); + old_src_bp_pos->second.erase(old_bp.first); + } + } + } + + return response_breakpoints; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 4581c995b4260..938b8fb8bcdda 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -13,7 +13,9 @@ #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBFileSpecList.h" #include "lldb/API/SBFrame.h" +#include "lldb/API/SBInstruction.h" #include "lldb/API/SBMutex.h" +#include "lldb/API/SBSymbol.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" #include "lldb/API/SBValue.h" @@ -45,6 +47,26 @@ void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) { Breakpoint::SetBreakpoint(); } +void SourceBreakpoint::SetBreakpoint(lldb::SBSymbol &symbol) { + lldb::SBMutex lock = m_dap.GetAPIMutex(); + std::lock_guard guard(lock); + + if (m_line == 0) + return; + + lldb::SBInstructionList inst_list = + m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); + if (inst_list.GetSize() < m_line) + return; + lldb::SBAddress address = + inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + + m_bp = m_dap.target.BreakpointCreateBySBAddress(address); + if (!m_log_message.empty()) + SetLogMessage(); + Breakpoint::SetBreakpoint(); +} + void SourceBreakpoint::UpdateBreakpoint(const SourceBreakpoint &request_bp) { if (m_log_message != request_bp.m_log_message) { m_log_message = request_bp.m_log_message; diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h index 5b15296f861c5..8589800e50983 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.h +++ b/lldb/tools/lldb-dap/SourceBreakpoint.h @@ -26,6 +26,7 @@ class SourceBreakpoint : public Breakpoint { // Set this breakpoint in LLDB as a new breakpoint void SetBreakpoint(const llvm::StringRef source_path); + void SetBreakpoint(lldb::SBSymbol &symbol); void UpdateBreakpoint(const SourceBreakpoint &request_bp); void SetLogMessage(); >From cb47dbc97fbbc1e2db9bd9c8989dcce425c796ee Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Wed, 14 May 2025 23:51:41 +0200 Subject: [PATCH 3/6] fix resolving of assembly source breakpoints --- lldb/tools/lldb-dap/Breakpoint.cpp | 45 ++++++++++++++++--- lldb/tools/lldb-dap/DAP.h | 3 +- .../Handler/BreakpointLocationsHandler.cpp | 4 +- lldb/tools/lldb-dap/Handler/RequestHandler.h | 4 +- .../Handler/SetBreakpointsRequestHandler.cpp | 30 ++++++------- lldb/tools/lldb-dap/package-lock.json | 4 +- lldb/tools/lldb-dap/package.json | 5 ++- 7 files changed, 63 insertions(+), 32 deletions(-) diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 26d633d1d172e..87fcd15b0a568 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -9,10 +9,12 @@ #include "Breakpoint.h" #include "DAP.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "lldb/API/SBAddress.h" #include "lldb/API/SBBreakpointLocation.h" #include "lldb/API/SBLineEntry.h" #include "lldb/API/SBMutex.h" +#include "lldb/lldb-enumerations.h" #include "llvm/ADT/StringExtras.h" #include #include @@ -63,14 +65,43 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { std::string formatted_addr = "0x" + llvm::utohexstr(bp_addr.GetLoadAddress(m_bp.GetTarget())); breakpoint.instructionReference = formatted_addr; + + lldb::StopDisassemblyType stop_disassembly_display = + GetStopDisassemblyDisplay(m_dap.debugger); auto line_entry = bp_addr.GetLineEntry(); - const auto line = line_entry.GetLine(); - if (line != UINT32_MAX) - breakpoint.line = line; - const auto column = line_entry.GetColumn(); - if (column != 0) - breakpoint.column = column; - breakpoint.source = CreateSource(line_entry); + if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) { + const auto line = line_entry.GetLine(); + if (line != UINT32_MAX) + breakpoint.line = line; + const auto column = line_entry.GetColumn(); + if (column != 0) + breakpoint.column = column; + breakpoint.source = CreateSource(line_entry); + } else { + // Breakpoint made by assembly + auto symbol_context = bp_addr.GetSymbolContext( + lldb::eSymbolContextSymbol | lldb::eSymbolContextModule); + if (symbol_context.IsValid()) { + auto symbol = symbol_context.GetSymbol(); + breakpoint.line = + m_bp.GetTarget() + .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) + .GetSize() + + 1; + protocol::Source source; + source.name = symbol.GetName(); + + auto module = symbol_context.GetModule(); + if (module.IsValid()) { + std::string path = module.GetFileSpec().GetDirectory(); + path += "/"; + path += module.GetFileSpec().GetFilename(); + source.path = std::move(path); + } + + breakpoint.source = std::move(source); + } + } } return breakpoint; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 0bc9063e1266f..54b233077f0c3 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -169,7 +169,8 @@ struct DAP { Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; - llvm::DenseMap assembly_breakpoints; + llvm::DenseMap> + assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index be02c47056310..06ada47a6f27f 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -122,9 +122,9 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( // start_line is relative to the symbol's start address lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i <= (end_line - 1); ++i) { - locations.emplace_back(i, 0); + locations.emplace_back(i, 1); } } diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index ddd01ffe33823..fec304979995e 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -381,11 +381,11 @@ class SetBreakpointsRequestHandler Run(const protocol::SetBreakpointsArguments &args) const override; std::vector SetSourceBreakpoints( - const std::string &path, + const protocol::Source &source, const std::optional> &breakpoints) const; std::vector SetAssemblyBreakpoints( - int64_t sourceReference, + const protocol::Source &source, const std::optional> &breakpoints) const; }; diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 71f9e5578ef08..4fefd8b440c7d 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -28,21 +28,20 @@ SetBreakpointsRequestHandler::Run( const auto &source = args.source; std::vector response_breakpoints; if (source.sourceReference) - response_breakpoints = SetAssemblyBreakpoints( - source.sourceReference.value(), args.breakpoints); + response_breakpoints = SetAssemblyBreakpoints(source, args.breakpoints); else if (source.path) - response_breakpoints = - SetSourceBreakpoints(source.path.value(), args.breakpoints); + response_breakpoints = SetSourceBreakpoints(source, args.breakpoints); return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; } std::vector SetBreakpointsRequestHandler::SetSourceBreakpoints( - const std::string &path, + const protocol::Source &source, const std::optional> &breakpoints) const { std::vector response_breakpoints; + std::string path = source.path.value_or(""); // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; @@ -96,10 +95,11 @@ SetBreakpointsRequestHandler::SetSourceBreakpoints( std::vector SetBreakpointsRequestHandler::SetAssemblyBreakpoints( - int64_t sourceReference, + const protocol::Source &source, const std::optional> &breakpoints) const { std::vector response_breakpoints; + int64_t sourceReference = source.sourceReference.value_or(0); lldb::SBProcess process = dap.target.GetProcess(); lldb::SBThread thread = @@ -114,14 +114,14 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( return response_breakpoints; // Not yet supporting breakpoints in assembly // without a valid symbol - SourceBreakpointMap request_bps; + llvm::DenseMap request_bps; if (breakpoints) { for (const auto &bp : *breakpoints) { SourceBreakpoint src_bp(dap, bp); - std::pair bp_pos(src_bp.GetLine(), 0); - request_bps.try_emplace(bp_pos, src_bp); + request_bps.try_emplace(src_bp.GetLine(), src_bp); const auto [iv, inserted] = - dap.assembly_breakpoints[sourceReference].try_emplace(bp_pos, src_bp); + dap.assembly_breakpoints[sourceReference].try_emplace( + src_bp.GetLine(), src_bp); // We check if this breakpoint already exists to update it if (inserted) iv->getSecond().SetBreakpoint(symbol); @@ -129,15 +129,11 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( iv->getSecond().UpdateBreakpoint(src_bp); protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - protocol::Source source; - source.sourceReference = sourceReference; - source.name = symbol.GetName(); - response_bp.source = std::move(source); - + response_bp.source = source; if (!response_bp.line) response_bp.line = src_bp.GetLine(); - if (!response_bp.column) - response_bp.column = src_bp.GetColumn(); + if (bp.column) + response_bp.column = *bp.column; response_breakpoints.push_back(response_bp); } } diff --git a/lldb/tools/lldb-dap/package-lock.json b/lldb/tools/lldb-dap/package-lock.json index 0a2b9e764067e..af90a9573aee6 100644 --- a/lldb/tools/lldb-dap/package-lock.json +++ b/lldb/tools/lldb-dap/package-lock.json @@ -1,12 +1,12 @@ { "name": "lldb-dap", - "version": "0.2.13", + "version": "0.2.14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lldb-dap", - "version": "0.2.13", + "version": "0.2.14", "license": "Apache 2.0 License with LLVM exceptions", "devDependencies": { "@types/node": "^18.19.41", diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index d5ca604798799..73e70cd961f4f 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -1,7 +1,7 @@ { "name": "lldb-dap", "displayName": "LLDB DAP", - "version": "0.2.13", + "version": "0.2.14", "publisher": "llvm-vs-code-extensions", "homepage": "https://lldb.llvm.org", "description": "Debugging with LLDB in Visual Studio Code", @@ -265,6 +265,9 @@ ] }, "breakpoints": [ + { + "language": "lldb.disassembly" + }, { "language": "ada" }, >From 6e1135deac7c1a58a85fc6f25a032d4c61e09d66 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Thu, 15 May 2025 00:36:10 +0200 Subject: [PATCH 4/6] remove include --- lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 4fefd8b440c7d..d69da5bd02c1e 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -12,8 +12,6 @@ #include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" -#include -#include #include namespace lldb_dap { >From 3807a12724feb3fb2dc9b46db20611e8813cb77b Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sat, 17 May 2025 21:05:27 +0200 Subject: [PATCH 5/6] use load address as sourceReference --- lldb/include/lldb/API/SBFileSpec.h | 3 + lldb/source/API/SBFileSpec.cpp | 8 ++ lldb/tools/lldb-dap/Breakpoint.cpp | 18 +---- .../Handler/BreakpointLocationsHandler.cpp | 11 +-- .../Handler/SetBreakpointsRequestHandler.cpp | 11 +-- .../lldb-dap/Handler/SourceRequestHandler.cpp | 18 ++--- lldb/tools/lldb-dap/JSONUtils.cpp | 75 +++++++++++++------ lldb/tools/lldb-dap/JSONUtils.h | 14 ++++ 8 files changed, 96 insertions(+), 62 deletions(-) diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index 36641843aabeb..303cb7d712cbf 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -10,6 +10,7 @@ #define LLDB_API_SBFILESPEC_H #include "lldb/API/SBDefines.h" +#include "lldb/API/SBStream.h" namespace lldb { @@ -53,6 +54,8 @@ class LLDB_API SBFileSpec { uint32_t GetPath(char *dst_path, size_t dst_len) const; + bool GetPath(lldb::SBStream &dst_path) const; + static int ResolvePath(const char *src_path, char *dst_path, size_t dst_len); bool GetDescription(lldb::SBStream &description) const; diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp index a7df9afc4b8eb..cb44dac1d4fcc 100644 --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -19,6 +19,7 @@ #include #include +#include using namespace lldb; using namespace lldb_private; @@ -147,6 +148,13 @@ uint32_t SBFileSpec::GetPath(char *dst_path, size_t dst_len) const { return result; } +bool SBFileSpec::GetPath(SBStream &dst_path) const { + LLDB_INSTRUMENT_VA(this, dst_path); + + std::string path = m_opaque_up->GetPath(); + return dst_path->PutCString(path.c_str()) > 0; +} + const lldb_private::FileSpec *SBFileSpec::operator->() const { return m_opaque_up.get(); } diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 87fcd15b0a568..a54a34e0f936d 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -79,27 +79,15 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { breakpoint.source = CreateSource(line_entry); } else { // Breakpoint made by assembly - auto symbol_context = bp_addr.GetSymbolContext( - lldb::eSymbolContextSymbol | lldb::eSymbolContextModule); - if (symbol_context.IsValid()) { - auto symbol = symbol_context.GetSymbol(); + auto symbol = bp_addr.GetSymbol(); + if (symbol.IsValid()) { breakpoint.line = m_bp.GetTarget() .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) .GetSize() + 1; - protocol::Source source; - source.name = symbol.GetName(); - auto module = symbol_context.GetModule(); - if (module.IsValid()) { - std::string path = module.GetFileSpec().GetDirectory(); - path += "/"; - path += module.GetFileSpec().GetFilename(); - source.path = std::move(path); - } - - breakpoint.source = std::move(source); + breakpoint.source = CreateAssemblySource(m_dap.target, bp_addr); } } } diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 06ada47a6f27f..c4d658caeee2d 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "LLDBUtils.h" #include "RequestHandler.h" #include @@ -108,15 +107,11 @@ template void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( llvm::SmallVector, N> &locations, int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { - lldb::SBProcess process = dap.target.GetProcess(); - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - - if (!frame.IsValid()) + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) return; - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) return; diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index d69da5bd02c1e..7b401f06e9a85 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -9,7 +9,6 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" -#include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" #include @@ -99,15 +98,11 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( std::vector response_breakpoints; int64_t sourceReference = source.sourceReference.value_or(0); - lldb::SBProcess process = dap.target.GetProcess(); - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - - if (!frame.IsValid()) + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) return response_breakpoints; - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) return response_breakpoints; // Not yet supporting breakpoints in assembly // without a valid symbol diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp index fb396a3dc8862..9249e2aa6fef7 100644 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp @@ -11,6 +11,7 @@ #include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" +#include "lldb/API/SBAddress.h" #include "lldb/API/SBExecutionContext.h" #include "lldb/API/SBFrame.h" #include "lldb/API/SBInstructionList.h" @@ -19,6 +20,7 @@ #include "lldb/API/SBSymbol.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" +#include "lldb/lldb-types.h" #include "llvm/Support/Error.h" namespace lldb_dap { @@ -34,18 +36,14 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { return llvm::make_error( "invalid arguments, expected source.sourceReference to be set"); - lldb::SBProcess process = dap.target.GetProcess(); - // Upper 32 bits is the thread index ID - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(source)); - // Lower 32 bits is the frame index - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(source)); - if (!frame.IsValid()) + lldb::SBAddress address(source, dap.target); + if (!address.IsValid()) return llvm::make_error("source not found"); + lldb::SBSymbol symbol = address.GetSymbol(); + lldb::SBStream stream; - lldb::SBExecutionContext exe_ctx(frame); - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBExecutionContext exe_ctx(dap.target); if (symbol.IsValid()) { lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); @@ -53,7 +51,7 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { } else { // No valid symbol, just return the disassembly. lldb::SBInstructionList insts = dap.target.ReadInstructions( - frame.GetPCAddress(), dap.number_of_assembly_lines_for_nodebug); + address, dap.number_of_assembly_lines_for_nodebug); insts.GetDescription(stream, exe_ctx); } diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index a8bd672583a5d..54e45cfc3319c 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -490,6 +490,13 @@ CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp) { return filter; } +static std::string GetLoadAddressString(const lldb::addr_t addr) { + std::string result; + llvm::raw_string_ostream os(result); + os << llvm::format_hex(addr, 18); + return result; +} + protocol::Source CreateSource(const lldb::SBFileSpec &file) { protocol::Source source; if (file.IsValid()) { @@ -516,6 +523,43 @@ protocol::Source CreateSource(llvm::StringRef source_path) { return source; } +protocol::Source CreateAssemblySource(const lldb::SBTarget &target, + lldb::SBAddress &address) { + protocol::Source source; + + auto symbol = address.GetSymbol(); + std::string name; + if (symbol.IsValid()) { + source.sourceReference = symbol.GetStartAddress().GetLoadAddress(target); + name = symbol.GetName(); + } else { + const auto load_addr = address.GetLoadAddress(target); + source.sourceReference = load_addr; + name = GetLoadAddressString(load_addr); + } + + lldb::SBModule module = address.GetModule(); + if (module.IsValid()) { + lldb::SBFileSpec file_spec = module.GetFileSpec(); + if (file_spec.IsValid()) { + lldb::SBStream module_path; + if (file_spec.GetPath(module_path)) { + std::string path = module_path.GetData(); + source.path = path + '`' + name; + } + } + } + + source.name = std::move(name); + + // Mark the source as deemphasized since users will only be able to view + // assembly for these frames. + source.presentationHint = + protocol::Source::PresentationHint::eSourcePresentationHintDeemphasize; + + return source; +} + bool ShouldDisplayAssemblySource( const lldb::SBLineEntry &line_entry, lldb::StopDisassemblyType stop_disassembly_display) { @@ -619,12 +663,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, frame_name = name; } - if (frame_name.empty()) { + if (frame_name.empty()) // If the function name is unavailable, display the pc address as a 16-digit // hex string, e.g. "0x0000000000012345" - llvm::raw_string_ostream os(frame_name); - os << llvm::format_hex(frame.GetPC(), 18); - } + frame_name = GetLoadAddressString(frame.GetPC()); // We only include `[opt]` if a custom frame format is not specified. if (!format && frame.GetFunction().GetIsOptimized()) @@ -641,17 +683,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, } else if (frame.GetSymbol().IsValid()) { // If no source is associated with the frame, use the DAPFrameID to track // the 'source' and generate assembly. - llvm::json::Object source; - EmplaceSafeString(source, "name", frame_name); - char buf[PATH_MAX] = {0}; - size_t size = frame.GetModule().GetFileSpec().GetPath(buf, PATH_MAX); - EmplaceSafeString(source, "path", - std::string(buf, size) + '`' + frame_name); - source.try_emplace("sourceReference", MakeDAPFrameID(frame)); - // Mark the source as deemphasized since users will only be able to view - // assembly for these frames. - EmplaceSafeString(source, "presentationHint", "deemphasize"); - object.try_emplace("source", std::move(source)); + auto frame_address = frame.GetPCAddress(); + object.try_emplace("source", CreateAssemblySource( + frame.GetThread().GetProcess().GetTarget(), + frame_address)); // Calculate the line of the current PC from the start of the current // symbol. @@ -665,12 +700,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, object.try_emplace("column", 1); } else { // No valid line entry or symbol. - llvm::json::Object source; - EmplaceSafeString(source, "name", frame_name); - source.try_emplace("sourceReference", MakeDAPFrameID(frame)); - EmplaceSafeString(source, "presentationHint", "deemphasize"); - object.try_emplace("source", std::move(source)); - + auto frame_address = frame.GetPCAddress(); + object.try_emplace("source", CreateAssemblySource( + frame.GetThread().GetProcess().GetTarget(), + frame_address)); object.try_emplace("line", 1); object.try_emplace("column", 1); } diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h index 783f291338d8c..ac9b39739104f 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -269,6 +269,20 @@ protocol::Source CreateSource(const lldb::SBLineEntry &line_entry); /// definition outlined by Microsoft. protocol::Source CreateSource(llvm::StringRef source_path); +/// Create a "Source" object for a given frame, using its assembly for source. +/// +/// \param[in] target +/// The relevant target. +/// +/// \param[in] address +/// The address to use when creating the "Source" object. +/// +/// \return +/// A "Source" JSON object that follows the formal JSON +/// definition outlined by Microsoft. +protocol::Source CreateAssemblySource(const lldb::SBTarget &target, + lldb::SBAddress &address); + /// Return true if the given line entry should be displayed as assembly. /// /// \param[in] line_entry >From 0f2ed75b78f717a2af774837c15105fd58e3029b Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 02:22:19 +0200 Subject: [PATCH 6/6] add breakpoint-assembly test --- .../test/tools/lldb-dap/dap_server.py | 7 ++++ .../test/tools/lldb-dap/lldbdap_testcase.py | 10 +++++ .../lldb-dap/breakpoint-assembly/Makefile | 3 ++ .../TestDAP_breakpointAssembly.py | 42 +++++++++++++++++++ .../tools/lldb-dap/breakpoint-assembly/main.c | 14 +++++++ .../breakpoint/TestDAP_setBreakpoints.py | 1 + .../TestDAP_setExceptionBreakpoints.py | 1 + .../TestDAP_setFunctionBreakpoints.py | 1 + 8 files changed, 79 insertions(+) create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index d3589e78b6bc7..42a56f0606db6 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -959,6 +959,13 @@ def request_setBreakpoints(self, file_path, line_array, data=None): """ (dir, base) = os.path.split(file_path) source_dict = {"name": base, "path": file_path} + return self.request_setBreakpoints_with_source(source_dict, line_array, data) + + def request_setBreakpointsAssembly(self, sourceReference, line_array, data=None): + source_dict = {"sourceReference": sourceReference} + return self.request_setBreakpoints_with_source(source_dict, line_array, data) + + def request_setBreakpoints_with_source(self, source_dict, line_array, data=None): args_dict = { "source": source_dict, "sourceModified": False, diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index d7cf8e2864324..f4d138daccb25 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -63,6 +63,16 @@ def set_source_breakpoints(self, source_path, lines, data=None): for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) return breakpoint_ids + + def set_source_breakpoints_assembly(self, source_reference, lines, data=None): + response = self.dap_server.request_setBreakpointsAssembly(source_reference, lines, data) + if response is None: + return [] + breakpoints = response["body"]["breakpoints"] + breakpoint_ids = [] + for breakpoint in breakpoints: + breakpoint_ids.append("%i" % (breakpoint["id"])) + return breakpoint_ids def set_function_breakpoints(self, functions, condition=None, hitCondition=None): """Sets breakpoints by function name given an array of function names diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile new file mode 100644 index 0000000000000..10495940055b6 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py new file mode 100644 index 0000000000000..ba9df3a18590b --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py @@ -0,0 +1,42 @@ +""" +Test lldb-dap setBreakpoints request +""" + + +import dap_server +import shutil +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +import lldbdap_testcase +import os + + +class TestDAP_setBreakpointsAssembly(lldbdap_testcase.DAPTestCaseBase): + # @skipIfWindows + def test_functionality(self): + """Tests hitting assembly source breakpoints""" + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + + self.dap_server.request_evaluate( + "`settings set stop-disassembly-display no-debuginfo", context="repl" + ) + + assmebly_func_breakpoints = self.set_function_breakpoints(["assembly_func"]) + self.continue_to_breakpoints(assmebly_func_breakpoints) + + assembly_func_frame = self.get_stackFrames()[0] + self.assertIn( + "sourceReference", + assembly_func_frame.get("source"), + "Expected assembly source frame", + ) + + line = assembly_func_frame["line"] + + # Set an assembly breakpoint in the next line and check that it's hit + assembly_breakpoint_ids = self.set_source_breakpoints_assembly( + assembly_func_frame["source"]["sourceReference"], [line + 1] + ) + self.continue_to_breakpoints(assembly_breakpoint_ids) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c new file mode 100644 index 0000000000000..350739006f903 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c @@ -0,0 +1,14 @@ +#include + +__attribute__((nodebug)) int assembly_func(int n) { + n += 1; + n += 2; + n += 3; + + return n; +} + +int main(int argc, char const *argv[]) { + assembly_func(10); + return 0; +} diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index 26df2573555df..aae1251b17c93 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,6 +12,7 @@ import os + at skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py index 92ac66cd44c5d..4dc8c5b3c7ded 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py @@ -10,6 +10,7 @@ import lldbdap_testcase + at skip("Temporarily disable the breakpoint tests") class TestDAP_setExceptionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_functionality(self): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index 946595f639edc..baaca4d974d5d 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,6 +10,7 @@ import lldbdap_testcase + at skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): From lldb-commits at lists.llvm.org Sat May 17 17:27:31 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sat, 17 May 2025 17:27:31 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68292973.630a0220.547f7.e9d5@mx.google.com> https://github.com/eronnen updated https://github.com/llvm/llvm-project/pull/139969 >From d6325b3f6a8602fc96ad72acecfcccda1120614d Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sat, 10 May 2025 20:45:17 +0200 Subject: [PATCH 1/6] support assembly in BreakpointLocationsRequestHandler --- .../breakpoint/TestDAP_setBreakpoints.py | 1 - .../TestDAP_setExceptionBreakpoints.py | 1 - .../TestDAP_setFunctionBreakpoints.py | 1 - lldb/tools/lldb-dap/DAP.h | 3 + .../Handler/BreakpointLocationsHandler.cpp | 77 +++++++++++++++---- lldb/tools/lldb-dap/Handler/RequestHandler.h | 11 +++ .../lldb-dap/Handler/SourceRequestHandler.cpp | 4 +- 7 files changed, 76 insertions(+), 22 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index aae1251b17c93..26df2573555df 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,7 +12,6 @@ import os - at skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py index 4dc8c5b3c7ded..92ac66cd44c5d 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setExceptionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_functionality(self): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index baaca4d974d5d..946595f639edc 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 8f24c6cf82924..00aa4276852c5 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -219,6 +219,9 @@ struct DAP { llvm::StringSet<> modules; /// @} + /// Number of lines of assembly code to show when no debug info is available. + uint32_t number_of_assembly_lines_for_nodebug = 32; + /// Creates a new DAP sessions. /// /// \param[in] log diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 2ac886c3a5d2c..9eea549d72b00 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "JSONUtils.h" +#include "LLDBUtils.h" #include "RequestHandler.h" #include @@ -19,19 +19,50 @@ namespace lldb_dap { llvm::Expected BreakpointLocationsRequestHandler::Run( const protocol::BreakpointLocationsArguments &args) const { - std::string path = args.source.path.value_or(""); uint32_t start_line = args.line; uint32_t start_column = args.column.value_or(LLDB_INVALID_COLUMN_NUMBER); uint32_t end_line = args.endLine.value_or(start_line); uint32_t end_column = args.endColumn.value_or(std::numeric_limits::max()); + // Find all relevant lines & columns + llvm::SmallVector, 8> locations; + if (args.source.sourceReference) { + AddAssemblyBreakpointLocations(locations, *args.source.sourceReference, + start_line, end_line); + } else { + std::string path = args.source.path.value_or(""); + AddSourceBreakpointLocations(locations, std::move(path), start_line, + start_column, end_line, end_column); + } + + // The line entries are sorted by addresses, but we must return the list + // ordered by line / column position. + std::sort(locations.begin(), locations.end()); + locations.erase(llvm::unique(locations), locations.end()); + + std::vector breakpoint_locations; + for (auto &l : locations) { + protocol::BreakpointLocation lc; + lc.line = l.first; + lc.column = l.second; + breakpoint_locations.push_back(std::move(lc)); + } + + return protocol::BreakpointLocationsResponseBody{ + /*breakpoints=*/std::move(breakpoint_locations)}; +} + +template +void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const { + lldb::SBFileSpec file_spec(path.c_str(), true); lldb::SBSymbolContextList compile_units = dap.target.FindCompileUnits(file_spec); - // Find all relevant lines & columns - llvm::SmallVector, 8> locations; for (uint32_t c_idx = 0, c_limit = compile_units.GetSize(); c_idx < c_limit; ++c_idx) { const lldb::SBCompileUnit &compile_unit = @@ -71,22 +102,34 @@ BreakpointLocationsRequestHandler::Run( locations.emplace_back(line, column); } } +} - // The line entries are sorted by addresses, but we must return the list - // ordered by line / column position. - std::sort(locations.begin(), locations.end()); - locations.erase(llvm::unique(locations), locations.end()); +template +void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { + lldb::SBProcess process = dap.target.GetProcess(); + lldb::SBThread thread = + process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); + lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - std::vector breakpoint_locations; - for (auto &l : locations) { - protocol::BreakpointLocation lc; - lc.line = l.first; - lc.column = l.second; - breakpoint_locations.push_back(std::move(lc)); - } + if (!frame.IsValid()) + return; - return protocol::BreakpointLocationsResponseBody{ - /*breakpoints=*/std::move(breakpoint_locations)}; + lldb::SBSymbol symbol = frame.GetSymbol(); + if (symbol.IsValid()) { + lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); + } + } else { + for (uint32_t i = start_line - 1; + i < dap.number_of_assembly_lines_for_nodebug && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); + } + } } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index e6bccfe12f402..21753bc0552f9 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -16,6 +16,7 @@ #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/JSON.h" @@ -232,6 +233,16 @@ class BreakpointLocationsRequestHandler } llvm::Expected Run(const protocol::BreakpointLocationsArguments &args) const override; + + template + void AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const; + template + void AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const; }; class CompletionsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp index 0ddd87881a164..fb396a3dc8862 100644 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp @@ -52,8 +52,8 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { insts.GetDescription(stream, exe_ctx); } else { // No valid symbol, just return the disassembly. - lldb::SBInstructionList insts = - dap.target.ReadInstructions(frame.GetPCAddress(), 32); + lldb::SBInstructionList insts = dap.target.ReadInstructions( + frame.GetPCAddress(), dap.number_of_assembly_lines_for_nodebug); insts.GetDescription(stream, exe_ctx); } >From ee492031bee8106fb2a4ff22a8563005f5afd86c Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 11 May 2025 19:49:03 +0200 Subject: [PATCH 2/6] support assembly in SetBreakpointsRequestHandler --- lldb/tools/lldb-dap/DAP.h | 1 + .../Handler/BreakpointLocationsHandler.cpp | 20 ++--- lldb/tools/lldb-dap/Handler/RequestHandler.h | 9 ++ .../Handler/SetBreakpointsRequestHandler.cpp | 90 ++++++++++++++++++- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 22 +++++ lldb/tools/lldb-dap/SourceBreakpoint.h | 1 + 6 files changed, 127 insertions(+), 16 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 00aa4276852c5..5ce0e534611c1 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -169,6 +169,7 @@ struct DAP { Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; + llvm::DenseMap assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 9eea549d72b00..be02c47056310 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -117,18 +117,14 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( return; lldb::SBSymbol symbol = frame.GetSymbol(); - if (symbol.IsValid()) { - lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); - ++i) { - locations.emplace_back(i, 0); - } - } else { - for (uint32_t i = start_line - 1; - i < dap.number_of_assembly_lines_for_nodebug && i < (end_line - 1); - ++i) { - locations.emplace_back(i, 0); - } + if (!symbol.IsValid()) + return; + + // start_line is relative to the symbol's start address + lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); } } diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 21753bc0552f9..72843aaef8150 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -389,6 +389,15 @@ class SetBreakpointsRequestHandler } llvm::Expected Run(const protocol::SetBreakpointsArguments &args) const override; + + std::vector SetSourceBreakpoints( + const std::string &path, + const std::optional> &breakpoints) + const; + std::vector SetAssemblyBreakpoints( + int64_t sourceReference, + const std::optional> &breakpoints) + const; }; class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 86e090b66afe9..71f9e5578ef08 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -9,8 +9,11 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" +#include +#include #include namespace lldb_dap { @@ -23,15 +26,30 @@ llvm::Expected SetBreakpointsRequestHandler::Run( const protocol::SetBreakpointsArguments &args) const { const auto &source = args.source; - const auto path = source.path.value_or(""); + std::vector response_breakpoints; + if (source.sourceReference) + response_breakpoints = SetAssemblyBreakpoints( + source.sourceReference.value(), args.breakpoints); + else if (source.path) + response_breakpoints = + SetSourceBreakpoints(source.path.value(), args.breakpoints); + + return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; +} + +std::vector +SetBreakpointsRequestHandler::SetSourceBreakpoints( + const std::string &path, + const std::optional> &breakpoints) + const { std::vector response_breakpoints; // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; // "breakpoints" may be unset, in which case we treat it the same as being set // to an empty array. - if (args.breakpoints) { - for (const auto &bp : *args.breakpoints) { + if (breakpoints) { + for (const auto &bp : *breakpoints) { SourceBreakpoint src_bp(dap, bp); std::pair bp_pos(src_bp.GetLine(), src_bp.GetColumn()); @@ -73,7 +91,71 @@ SetBreakpointsRequestHandler::Run( } } - return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; + return response_breakpoints; +} + +std::vector +SetBreakpointsRequestHandler::SetAssemblyBreakpoints( + int64_t sourceReference, + const std::optional> &breakpoints) + const { + std::vector response_breakpoints; + + lldb::SBProcess process = dap.target.GetProcess(); + lldb::SBThread thread = + process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); + lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); + + if (!frame.IsValid()) + return response_breakpoints; + + lldb::SBSymbol symbol = frame.GetSymbol(); + if (!symbol.IsValid()) + return response_breakpoints; // Not yet supporting breakpoints in assembly + // without a valid symbol + + SourceBreakpointMap request_bps; + if (breakpoints) { + for (const auto &bp : *breakpoints) { + SourceBreakpoint src_bp(dap, bp); + std::pair bp_pos(src_bp.GetLine(), 0); + request_bps.try_emplace(bp_pos, src_bp); + const auto [iv, inserted] = + dap.assembly_breakpoints[sourceReference].try_emplace(bp_pos, src_bp); + // We check if this breakpoint already exists to update it + if (inserted) + iv->getSecond().SetBreakpoint(symbol); + else + iv->getSecond().UpdateBreakpoint(src_bp); + + protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); + protocol::Source source; + source.sourceReference = sourceReference; + source.name = symbol.GetName(); + response_bp.source = std::move(source); + + if (!response_bp.line) + response_bp.line = src_bp.GetLine(); + if (!response_bp.column) + response_bp.column = src_bp.GetColumn(); + response_breakpoints.push_back(response_bp); + } + } + + // Delete existing breakpoints for this sourceReference that are not in the + // request_bps set. + auto old_src_bp_pos = dap.assembly_breakpoints.find(sourceReference); + if (old_src_bp_pos != dap.assembly_breakpoints.end()) { + for (auto &old_bp : old_src_bp_pos->second) { + auto request_pos = request_bps.find(old_bp.first); + if (request_pos == request_bps.end()) { + dap.target.BreakpointDelete(old_bp.second.GetID()); + old_src_bp_pos->second.erase(old_bp.first); + } + } + } + + return response_breakpoints; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 4581c995b4260..938b8fb8bcdda 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -13,7 +13,9 @@ #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBFileSpecList.h" #include "lldb/API/SBFrame.h" +#include "lldb/API/SBInstruction.h" #include "lldb/API/SBMutex.h" +#include "lldb/API/SBSymbol.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" #include "lldb/API/SBValue.h" @@ -45,6 +47,26 @@ void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) { Breakpoint::SetBreakpoint(); } +void SourceBreakpoint::SetBreakpoint(lldb::SBSymbol &symbol) { + lldb::SBMutex lock = m_dap.GetAPIMutex(); + std::lock_guard guard(lock); + + if (m_line == 0) + return; + + lldb::SBInstructionList inst_list = + m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); + if (inst_list.GetSize() < m_line) + return; + lldb::SBAddress address = + inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + + m_bp = m_dap.target.BreakpointCreateBySBAddress(address); + if (!m_log_message.empty()) + SetLogMessage(); + Breakpoint::SetBreakpoint(); +} + void SourceBreakpoint::UpdateBreakpoint(const SourceBreakpoint &request_bp) { if (m_log_message != request_bp.m_log_message) { m_log_message = request_bp.m_log_message; diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h index 5b15296f861c5..8589800e50983 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.h +++ b/lldb/tools/lldb-dap/SourceBreakpoint.h @@ -26,6 +26,7 @@ class SourceBreakpoint : public Breakpoint { // Set this breakpoint in LLDB as a new breakpoint void SetBreakpoint(const llvm::StringRef source_path); + void SetBreakpoint(lldb::SBSymbol &symbol); void UpdateBreakpoint(const SourceBreakpoint &request_bp); void SetLogMessage(); >From dbb2f9bd55b3f86247e03b2610fca9576e124637 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Wed, 14 May 2025 23:51:41 +0200 Subject: [PATCH 3/6] fix resolving of assembly source breakpoints --- lldb/tools/lldb-dap/Breakpoint.cpp | 45 ++++++++++++++++--- lldb/tools/lldb-dap/DAP.h | 3 +- .../Handler/BreakpointLocationsHandler.cpp | 4 +- lldb/tools/lldb-dap/Handler/RequestHandler.h | 4 +- .../Handler/SetBreakpointsRequestHandler.cpp | 30 ++++++------- lldb/tools/lldb-dap/package-lock.json | 4 +- lldb/tools/lldb-dap/package.json | 5 ++- 7 files changed, 63 insertions(+), 32 deletions(-) diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 26d633d1d172e..87fcd15b0a568 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -9,10 +9,12 @@ #include "Breakpoint.h" #include "DAP.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "lldb/API/SBAddress.h" #include "lldb/API/SBBreakpointLocation.h" #include "lldb/API/SBLineEntry.h" #include "lldb/API/SBMutex.h" +#include "lldb/lldb-enumerations.h" #include "llvm/ADT/StringExtras.h" #include #include @@ -63,14 +65,43 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { std::string formatted_addr = "0x" + llvm::utohexstr(bp_addr.GetLoadAddress(m_bp.GetTarget())); breakpoint.instructionReference = formatted_addr; + + lldb::StopDisassemblyType stop_disassembly_display = + GetStopDisassemblyDisplay(m_dap.debugger); auto line_entry = bp_addr.GetLineEntry(); - const auto line = line_entry.GetLine(); - if (line != UINT32_MAX) - breakpoint.line = line; - const auto column = line_entry.GetColumn(); - if (column != 0) - breakpoint.column = column; - breakpoint.source = CreateSource(line_entry); + if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) { + const auto line = line_entry.GetLine(); + if (line != UINT32_MAX) + breakpoint.line = line; + const auto column = line_entry.GetColumn(); + if (column != 0) + breakpoint.column = column; + breakpoint.source = CreateSource(line_entry); + } else { + // Breakpoint made by assembly + auto symbol_context = bp_addr.GetSymbolContext( + lldb::eSymbolContextSymbol | lldb::eSymbolContextModule); + if (symbol_context.IsValid()) { + auto symbol = symbol_context.GetSymbol(); + breakpoint.line = + m_bp.GetTarget() + .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) + .GetSize() + + 1; + protocol::Source source; + source.name = symbol.GetName(); + + auto module = symbol_context.GetModule(); + if (module.IsValid()) { + std::string path = module.GetFileSpec().GetDirectory(); + path += "/"; + path += module.GetFileSpec().GetFilename(); + source.path = std::move(path); + } + + breakpoint.source = std::move(source); + } + } } return breakpoint; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 5ce0e534611c1..b0fe265b7bca1 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -169,7 +169,8 @@ struct DAP { Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; - llvm::DenseMap assembly_breakpoints; + llvm::DenseMap> + assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index be02c47056310..06ada47a6f27f 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -122,9 +122,9 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( // start_line is relative to the symbol's start address lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i <= (end_line - 1); ++i) { - locations.emplace_back(i, 0); + locations.emplace_back(i, 1); } } diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 72843aaef8150..80898d1ee5ef1 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -391,11 +391,11 @@ class SetBreakpointsRequestHandler Run(const protocol::SetBreakpointsArguments &args) const override; std::vector SetSourceBreakpoints( - const std::string &path, + const protocol::Source &source, const std::optional> &breakpoints) const; std::vector SetAssemblyBreakpoints( - int64_t sourceReference, + const protocol::Source &source, const std::optional> &breakpoints) const; }; diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 71f9e5578ef08..4fefd8b440c7d 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -28,21 +28,20 @@ SetBreakpointsRequestHandler::Run( const auto &source = args.source; std::vector response_breakpoints; if (source.sourceReference) - response_breakpoints = SetAssemblyBreakpoints( - source.sourceReference.value(), args.breakpoints); + response_breakpoints = SetAssemblyBreakpoints(source, args.breakpoints); else if (source.path) - response_breakpoints = - SetSourceBreakpoints(source.path.value(), args.breakpoints); + response_breakpoints = SetSourceBreakpoints(source, args.breakpoints); return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; } std::vector SetBreakpointsRequestHandler::SetSourceBreakpoints( - const std::string &path, + const protocol::Source &source, const std::optional> &breakpoints) const { std::vector response_breakpoints; + std::string path = source.path.value_or(""); // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; @@ -96,10 +95,11 @@ SetBreakpointsRequestHandler::SetSourceBreakpoints( std::vector SetBreakpointsRequestHandler::SetAssemblyBreakpoints( - int64_t sourceReference, + const protocol::Source &source, const std::optional> &breakpoints) const { std::vector response_breakpoints; + int64_t sourceReference = source.sourceReference.value_or(0); lldb::SBProcess process = dap.target.GetProcess(); lldb::SBThread thread = @@ -114,14 +114,14 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( return response_breakpoints; // Not yet supporting breakpoints in assembly // without a valid symbol - SourceBreakpointMap request_bps; + llvm::DenseMap request_bps; if (breakpoints) { for (const auto &bp : *breakpoints) { SourceBreakpoint src_bp(dap, bp); - std::pair bp_pos(src_bp.GetLine(), 0); - request_bps.try_emplace(bp_pos, src_bp); + request_bps.try_emplace(src_bp.GetLine(), src_bp); const auto [iv, inserted] = - dap.assembly_breakpoints[sourceReference].try_emplace(bp_pos, src_bp); + dap.assembly_breakpoints[sourceReference].try_emplace( + src_bp.GetLine(), src_bp); // We check if this breakpoint already exists to update it if (inserted) iv->getSecond().SetBreakpoint(symbol); @@ -129,15 +129,11 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( iv->getSecond().UpdateBreakpoint(src_bp); protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - protocol::Source source; - source.sourceReference = sourceReference; - source.name = symbol.GetName(); - response_bp.source = std::move(source); - + response_bp.source = source; if (!response_bp.line) response_bp.line = src_bp.GetLine(); - if (!response_bp.column) - response_bp.column = src_bp.GetColumn(); + if (bp.column) + response_bp.column = *bp.column; response_breakpoints.push_back(response_bp); } } diff --git a/lldb/tools/lldb-dap/package-lock.json b/lldb/tools/lldb-dap/package-lock.json index 0a2b9e764067e..af90a9573aee6 100644 --- a/lldb/tools/lldb-dap/package-lock.json +++ b/lldb/tools/lldb-dap/package-lock.json @@ -1,12 +1,12 @@ { "name": "lldb-dap", - "version": "0.2.13", + "version": "0.2.14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lldb-dap", - "version": "0.2.13", + "version": "0.2.14", "license": "Apache 2.0 License with LLVM exceptions", "devDependencies": { "@types/node": "^18.19.41", diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index d5ca604798799..73e70cd961f4f 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -1,7 +1,7 @@ { "name": "lldb-dap", "displayName": "LLDB DAP", - "version": "0.2.13", + "version": "0.2.14", "publisher": "llvm-vs-code-extensions", "homepage": "https://lldb.llvm.org", "description": "Debugging with LLDB in Visual Studio Code", @@ -265,6 +265,9 @@ ] }, "breakpoints": [ + { + "language": "lldb.disassembly" + }, { "language": "ada" }, >From 3699524618ed76f969cc26a63610fe54e3605139 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Thu, 15 May 2025 00:36:10 +0200 Subject: [PATCH 4/6] remove include --- lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 4fefd8b440c7d..d69da5bd02c1e 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -12,8 +12,6 @@ #include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" -#include -#include #include namespace lldb_dap { >From 61623deb7e249a8ca0c63e3f66955790da5e4ced Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sat, 17 May 2025 21:05:27 +0200 Subject: [PATCH 5/6] use load address as sourceReference --- lldb/include/lldb/API/SBFileSpec.h | 3 + lldb/source/API/SBFileSpec.cpp | 8 ++ lldb/tools/lldb-dap/Breakpoint.cpp | 18 +---- .../Handler/BreakpointLocationsHandler.cpp | 11 +-- .../Handler/SetBreakpointsRequestHandler.cpp | 11 +-- .../lldb-dap/Handler/SourceRequestHandler.cpp | 18 ++--- lldb/tools/lldb-dap/JSONUtils.cpp | 75 +++++++++++++------ lldb/tools/lldb-dap/JSONUtils.h | 14 ++++ 8 files changed, 96 insertions(+), 62 deletions(-) diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index 36641843aabeb..303cb7d712cbf 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -10,6 +10,7 @@ #define LLDB_API_SBFILESPEC_H #include "lldb/API/SBDefines.h" +#include "lldb/API/SBStream.h" namespace lldb { @@ -53,6 +54,8 @@ class LLDB_API SBFileSpec { uint32_t GetPath(char *dst_path, size_t dst_len) const; + bool GetPath(lldb::SBStream &dst_path) const; + static int ResolvePath(const char *src_path, char *dst_path, size_t dst_len); bool GetDescription(lldb::SBStream &description) const; diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp index a7df9afc4b8eb..cb44dac1d4fcc 100644 --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -19,6 +19,7 @@ #include #include +#include using namespace lldb; using namespace lldb_private; @@ -147,6 +148,13 @@ uint32_t SBFileSpec::GetPath(char *dst_path, size_t dst_len) const { return result; } +bool SBFileSpec::GetPath(SBStream &dst_path) const { + LLDB_INSTRUMENT_VA(this, dst_path); + + std::string path = m_opaque_up->GetPath(); + return dst_path->PutCString(path.c_str()) > 0; +} + const lldb_private::FileSpec *SBFileSpec::operator->() const { return m_opaque_up.get(); } diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 87fcd15b0a568..a54a34e0f936d 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -79,27 +79,15 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { breakpoint.source = CreateSource(line_entry); } else { // Breakpoint made by assembly - auto symbol_context = bp_addr.GetSymbolContext( - lldb::eSymbolContextSymbol | lldb::eSymbolContextModule); - if (symbol_context.IsValid()) { - auto symbol = symbol_context.GetSymbol(); + auto symbol = bp_addr.GetSymbol(); + if (symbol.IsValid()) { breakpoint.line = m_bp.GetTarget() .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) .GetSize() + 1; - protocol::Source source; - source.name = symbol.GetName(); - auto module = symbol_context.GetModule(); - if (module.IsValid()) { - std::string path = module.GetFileSpec().GetDirectory(); - path += "/"; - path += module.GetFileSpec().GetFilename(); - source.path = std::move(path); - } - - breakpoint.source = std::move(source); + breakpoint.source = CreateAssemblySource(m_dap.target, bp_addr); } } } diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 06ada47a6f27f..c4d658caeee2d 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "LLDBUtils.h" #include "RequestHandler.h" #include @@ -108,15 +107,11 @@ template void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( llvm::SmallVector, N> &locations, int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { - lldb::SBProcess process = dap.target.GetProcess(); - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - - if (!frame.IsValid()) + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) return; - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) return; diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index d69da5bd02c1e..7b401f06e9a85 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -9,7 +9,6 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" -#include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" #include @@ -99,15 +98,11 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( std::vector response_breakpoints; int64_t sourceReference = source.sourceReference.value_or(0); - lldb::SBProcess process = dap.target.GetProcess(); - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - - if (!frame.IsValid()) + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) return response_breakpoints; - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) return response_breakpoints; // Not yet supporting breakpoints in assembly // without a valid symbol diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp index fb396a3dc8862..9249e2aa6fef7 100644 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp @@ -11,6 +11,7 @@ #include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" +#include "lldb/API/SBAddress.h" #include "lldb/API/SBExecutionContext.h" #include "lldb/API/SBFrame.h" #include "lldb/API/SBInstructionList.h" @@ -19,6 +20,7 @@ #include "lldb/API/SBSymbol.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" +#include "lldb/lldb-types.h" #include "llvm/Support/Error.h" namespace lldb_dap { @@ -34,18 +36,14 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { return llvm::make_error( "invalid arguments, expected source.sourceReference to be set"); - lldb::SBProcess process = dap.target.GetProcess(); - // Upper 32 bits is the thread index ID - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(source)); - // Lower 32 bits is the frame index - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(source)); - if (!frame.IsValid()) + lldb::SBAddress address(source, dap.target); + if (!address.IsValid()) return llvm::make_error("source not found"); + lldb::SBSymbol symbol = address.GetSymbol(); + lldb::SBStream stream; - lldb::SBExecutionContext exe_ctx(frame); - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBExecutionContext exe_ctx(dap.target); if (symbol.IsValid()) { lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); @@ -53,7 +51,7 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { } else { // No valid symbol, just return the disassembly. lldb::SBInstructionList insts = dap.target.ReadInstructions( - frame.GetPCAddress(), dap.number_of_assembly_lines_for_nodebug); + address, dap.number_of_assembly_lines_for_nodebug); insts.GetDescription(stream, exe_ctx); } diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 714947a4d3b9c..c8151c3d64ea4 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -490,6 +490,13 @@ CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp) { return filter; } +static std::string GetLoadAddressString(const lldb::addr_t addr) { + std::string result; + llvm::raw_string_ostream os(result); + os << llvm::format_hex(addr, 18); + return result; +} + protocol::Source CreateSource(const lldb::SBFileSpec &file) { protocol::Source source; if (file.IsValid()) { @@ -516,6 +523,43 @@ protocol::Source CreateSource(llvm::StringRef source_path) { return source; } +protocol::Source CreateAssemblySource(const lldb::SBTarget &target, + lldb::SBAddress &address) { + protocol::Source source; + + auto symbol = address.GetSymbol(); + std::string name; + if (symbol.IsValid()) { + source.sourceReference = symbol.GetStartAddress().GetLoadAddress(target); + name = symbol.GetName(); + } else { + const auto load_addr = address.GetLoadAddress(target); + source.sourceReference = load_addr; + name = GetLoadAddressString(load_addr); + } + + lldb::SBModule module = address.GetModule(); + if (module.IsValid()) { + lldb::SBFileSpec file_spec = module.GetFileSpec(); + if (file_spec.IsValid()) { + lldb::SBStream module_path; + if (file_spec.GetPath(module_path)) { + std::string path = module_path.GetData(); + source.path = path + '`' + name; + } + } + } + + source.name = std::move(name); + + // Mark the source as deemphasized since users will only be able to view + // assembly for these frames. + source.presentationHint = + protocol::Source::PresentationHint::eSourcePresentationHintDeemphasize; + + return source; +} + bool ShouldDisplayAssemblySource( const lldb::SBLineEntry &line_entry, lldb::StopDisassemblyType stop_disassembly_display) { @@ -619,12 +663,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, frame_name = name; } - if (frame_name.empty()) { + if (frame_name.empty()) // If the function name is unavailable, display the pc address as a 16-digit // hex string, e.g. "0x0000000000012345" - llvm::raw_string_ostream os(frame_name); - os << llvm::format_hex(frame.GetPC(), 18); - } + frame_name = GetLoadAddressString(frame.GetPC()); // We only include `[opt]` if a custom frame format is not specified. if (!format && frame.GetFunction().GetIsOptimized()) @@ -641,17 +683,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, } else if (frame.GetSymbol().IsValid()) { // If no source is associated with the frame, use the DAPFrameID to track // the 'source' and generate assembly. - llvm::json::Object source; - EmplaceSafeString(source, "name", frame_name); - char buf[PATH_MAX] = {0}; - size_t size = frame.GetModule().GetFileSpec().GetPath(buf, PATH_MAX); - EmplaceSafeString(source, "path", - std::string(buf, size) + '`' + frame_name); - source.try_emplace("sourceReference", MakeDAPFrameID(frame)); - // Mark the source as deemphasized since users will only be able to view - // assembly for these frames. - EmplaceSafeString(source, "presentationHint", "deemphasize"); - object.try_emplace("source", std::move(source)); + auto frame_address = frame.GetPCAddress(); + object.try_emplace("source", CreateAssemblySource( + frame.GetThread().GetProcess().GetTarget(), + frame_address)); // Calculate the line of the current PC from the start of the current // symbol. @@ -665,12 +700,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, object.try_emplace("column", 1); } else { // No valid line entry or symbol. - llvm::json::Object source; - EmplaceSafeString(source, "name", frame_name); - source.try_emplace("sourceReference", MakeDAPFrameID(frame)); - EmplaceSafeString(source, "presentationHint", "deemphasize"); - object.try_emplace("source", std::move(source)); - + auto frame_address = frame.GetPCAddress(); + object.try_emplace("source", CreateAssemblySource( + frame.GetThread().GetProcess().GetTarget(), + frame_address)); object.try_emplace("line", 1); object.try_emplace("column", 1); } diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h index 783f291338d8c..ac9b39739104f 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -269,6 +269,20 @@ protocol::Source CreateSource(const lldb::SBLineEntry &line_entry); /// definition outlined by Microsoft. protocol::Source CreateSource(llvm::StringRef source_path); +/// Create a "Source" object for a given frame, using its assembly for source. +/// +/// \param[in] target +/// The relevant target. +/// +/// \param[in] address +/// The address to use when creating the "Source" object. +/// +/// \return +/// A "Source" JSON object that follows the formal JSON +/// definition outlined by Microsoft. +protocol::Source CreateAssemblySource(const lldb::SBTarget &target, + lldb::SBAddress &address); + /// Return true if the given line entry should be displayed as assembly. /// /// \param[in] line_entry >From f5fd76de3ad25b9cbf6ce065e06c98ff30b070a8 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 02:22:19 +0200 Subject: [PATCH 6/6] add breakpoint-assembly test --- .../test/tools/lldb-dap/dap_server.py | 7 ++++ .../test/tools/lldb-dap/lldbdap_testcase.py | 10 +++++ .../lldb-dap/breakpoint-assembly/Makefile | 3 ++ .../TestDAP_breakpointAssembly.py | 42 +++++++++++++++++++ .../tools/lldb-dap/breakpoint-assembly/main.c | 14 +++++++ .../breakpoint/TestDAP_setBreakpoints.py | 1 + .../TestDAP_setExceptionBreakpoints.py | 1 + .../TestDAP_setFunctionBreakpoints.py | 1 + 8 files changed, 79 insertions(+) create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index 70fd0b0c419db..4a907a5e36901 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -955,6 +955,13 @@ def request_setBreakpoints(self, file_path, line_array, data=None): """ (dir, base) = os.path.split(file_path) source_dict = {"name": base, "path": file_path} + return self.request_setBreakpoints_with_source(source_dict, line_array, data) + + def request_setBreakpointsAssembly(self, sourceReference, line_array, data=None): + source_dict = {"sourceReference": sourceReference} + return self.request_setBreakpoints_with_source(source_dict, line_array, data) + + def request_setBreakpoints_with_source(self, source_dict, line_array, data=None): args_dict = { "source": source_dict, "sourceModified": False, diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index afdc746ed0d0d..427f66a7da0c8 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -63,6 +63,16 @@ def set_source_breakpoints(self, source_path, lines, data=None): for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) return breakpoint_ids + + def set_source_breakpoints_assembly(self, source_reference, lines, data=None): + response = self.dap_server.request_setBreakpointsAssembly(source_reference, lines, data) + if response is None: + return [] + breakpoints = response["body"]["breakpoints"] + breakpoint_ids = [] + for breakpoint in breakpoints: + breakpoint_ids.append("%i" % (breakpoint["id"])) + return breakpoint_ids def set_function_breakpoints(self, functions, condition=None, hitCondition=None): """Sets breakpoints by function name given an array of function names diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile new file mode 100644 index 0000000000000..10495940055b6 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py new file mode 100644 index 0000000000000..ba9df3a18590b --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py @@ -0,0 +1,42 @@ +""" +Test lldb-dap setBreakpoints request +""" + + +import dap_server +import shutil +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +import lldbdap_testcase +import os + + +class TestDAP_setBreakpointsAssembly(lldbdap_testcase.DAPTestCaseBase): + # @skipIfWindows + def test_functionality(self): + """Tests hitting assembly source breakpoints""" + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + + self.dap_server.request_evaluate( + "`settings set stop-disassembly-display no-debuginfo", context="repl" + ) + + assmebly_func_breakpoints = self.set_function_breakpoints(["assembly_func"]) + self.continue_to_breakpoints(assmebly_func_breakpoints) + + assembly_func_frame = self.get_stackFrames()[0] + self.assertIn( + "sourceReference", + assembly_func_frame.get("source"), + "Expected assembly source frame", + ) + + line = assembly_func_frame["line"] + + # Set an assembly breakpoint in the next line and check that it's hit + assembly_breakpoint_ids = self.set_source_breakpoints_assembly( + assembly_func_frame["source"]["sourceReference"], [line + 1] + ) + self.continue_to_breakpoints(assembly_breakpoint_ids) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c new file mode 100644 index 0000000000000..350739006f903 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c @@ -0,0 +1,14 @@ +#include + +__attribute__((nodebug)) int assembly_func(int n) { + n += 1; + n += 2; + n += 3; + + return n; +} + +int main(int argc, char const *argv[]) { + assembly_func(10); + return 0; +} diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index 26df2573555df..aae1251b17c93 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,6 +12,7 @@ import os + at skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py index 92ac66cd44c5d..4dc8c5b3c7ded 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py @@ -10,6 +10,7 @@ import lldbdap_testcase + at skip("Temporarily disable the breakpoint tests") class TestDAP_setExceptionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_functionality(self): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index 946595f639edc..baaca4d974d5d 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,6 +10,7 @@ import lldbdap_testcase + at skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): From lldb-commits at lists.llvm.org Sat May 17 17:27:50 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sat, 17 May 2025 17:27:50 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68292986.630a0220.278354.e60a@mx.google.com> https://github.com/eronnen ready_for_review https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sat May 17 17:28:22 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sat, 17 May 2025 17:28:22 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <682929a6.170a0220.198fb6.9628@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Ely Ronnen (eronnen)
Changes * Support assembly source breakpoints * Change `sourceReference` to be the load address for simplicity and consistency across threads/frames [Screencast From 2025-05-17 23-57-30.webm](https://github.com/user-attachments/assets/2e7c181d-42c1-4121-8f13-b180c19d0e33) --- Patch is 29.52 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/139969.diff 19 Files Affected: - (modified) lldb/include/lldb/API/SBFileSpec.h (+3) - (modified) lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py (+7) - (modified) lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py (+10) - (modified) lldb/source/API/SBFileSpec.cpp (+8) - (added) lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile (+3) - (added) lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py (+42) - (added) lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c (+14) - (modified) lldb/tools/lldb-dap/Breakpoint.cpp (+26-7) - (modified) lldb/tools/lldb-dap/DAP.h (+5) - (modified) lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp (+51-17) - (modified) lldb/tools/lldb-dap/Handler/RequestHandler.h (+20) - (modified) lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp (+75-4) - (modified) lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp (+9-11) - (modified) lldb/tools/lldb-dap/JSONUtils.cpp (+54-21) - (modified) lldb/tools/lldb-dap/JSONUtils.h (+14) - (modified) lldb/tools/lldb-dap/SourceBreakpoint.cpp (+22) - (modified) lldb/tools/lldb-dap/SourceBreakpoint.h (+1) - (modified) lldb/tools/lldb-dap/package-lock.json (+2-2) - (modified) lldb/tools/lldb-dap/package.json (+4-1) ``````````diff diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index 36641843aabeb..303cb7d712cbf 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -10,6 +10,7 @@ #define LLDB_API_SBFILESPEC_H #include "lldb/API/SBDefines.h" +#include "lldb/API/SBStream.h" namespace lldb { @@ -53,6 +54,8 @@ class LLDB_API SBFileSpec { uint32_t GetPath(char *dst_path, size_t dst_len) const; + bool GetPath(lldb::SBStream &dst_path) const; + static int ResolvePath(const char *src_path, char *dst_path, size_t dst_len); bool GetDescription(lldb::SBStream &description) const; diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index 70fd0b0c419db..4a907a5e36901 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -955,6 +955,13 @@ def request_setBreakpoints(self, file_path, line_array, data=None): """ (dir, base) = os.path.split(file_path) source_dict = {"name": base, "path": file_path} + return self.request_setBreakpoints_with_source(source_dict, line_array, data) + + def request_setBreakpointsAssembly(self, sourceReference, line_array, data=None): + source_dict = {"sourceReference": sourceReference} + return self.request_setBreakpoints_with_source(source_dict, line_array, data) + + def request_setBreakpoints_with_source(self, source_dict, line_array, data=None): args_dict = { "source": source_dict, "sourceModified": False, diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index afdc746ed0d0d..427f66a7da0c8 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -63,6 +63,16 @@ def set_source_breakpoints(self, source_path, lines, data=None): for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) return breakpoint_ids + + def set_source_breakpoints_assembly(self, source_reference, lines, data=None): + response = self.dap_server.request_setBreakpointsAssembly(source_reference, lines, data) + if response is None: + return [] + breakpoints = response["body"]["breakpoints"] + breakpoint_ids = [] + for breakpoint in breakpoints: + breakpoint_ids.append("%i" % (breakpoint["id"])) + return breakpoint_ids def set_function_breakpoints(self, functions, condition=None, hitCondition=None): """Sets breakpoints by function name given an array of function names diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp index a7df9afc4b8eb..cb44dac1d4fcc 100644 --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -19,6 +19,7 @@ #include #include +#include using namespace lldb; using namespace lldb_private; @@ -147,6 +148,13 @@ uint32_t SBFileSpec::GetPath(char *dst_path, size_t dst_len) const { return result; } +bool SBFileSpec::GetPath(SBStream &dst_path) const { + LLDB_INSTRUMENT_VA(this, dst_path); + + std::string path = m_opaque_up->GetPath(); + return dst_path->PutCString(path.c_str()) > 0; +} + const lldb_private::FileSpec *SBFileSpec::operator->() const { return m_opaque_up.get(); } diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile new file mode 100644 index 0000000000000..10495940055b6 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py new file mode 100644 index 0000000000000..ba9df3a18590b --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py @@ -0,0 +1,42 @@ +""" +Test lldb-dap setBreakpoints request +""" + + +import dap_server +import shutil +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +import lldbdap_testcase +import os + + +class TestDAP_setBreakpointsAssembly(lldbdap_testcase.DAPTestCaseBase): + # @skipIfWindows + def test_functionality(self): + """Tests hitting assembly source breakpoints""" + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + + self.dap_server.request_evaluate( + "`settings set stop-disassembly-display no-debuginfo", context="repl" + ) + + assmebly_func_breakpoints = self.set_function_breakpoints(["assembly_func"]) + self.continue_to_breakpoints(assmebly_func_breakpoints) + + assembly_func_frame = self.get_stackFrames()[0] + self.assertIn( + "sourceReference", + assembly_func_frame.get("source"), + "Expected assembly source frame", + ) + + line = assembly_func_frame["line"] + + # Set an assembly breakpoint in the next line and check that it's hit + assembly_breakpoint_ids = self.set_source_breakpoints_assembly( + assembly_func_frame["source"]["sourceReference"], [line + 1] + ) + self.continue_to_breakpoints(assembly_breakpoint_ids) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c new file mode 100644 index 0000000000000..350739006f903 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c @@ -0,0 +1,14 @@ +#include + +__attribute__((nodebug)) int assembly_func(int n) { + n += 1; + n += 2; + n += 3; + + return n; +} + +int main(int argc, char const *argv[]) { + assembly_func(10); + return 0; +} diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 26d633d1d172e..a54a34e0f936d 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -9,10 +9,12 @@ #include "Breakpoint.h" #include "DAP.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "lldb/API/SBAddress.h" #include "lldb/API/SBBreakpointLocation.h" #include "lldb/API/SBLineEntry.h" #include "lldb/API/SBMutex.h" +#include "lldb/lldb-enumerations.h" #include "llvm/ADT/StringExtras.h" #include #include @@ -63,14 +65,31 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { std::string formatted_addr = "0x" + llvm::utohexstr(bp_addr.GetLoadAddress(m_bp.GetTarget())); breakpoint.instructionReference = formatted_addr; + + lldb::StopDisassemblyType stop_disassembly_display = + GetStopDisassemblyDisplay(m_dap.debugger); auto line_entry = bp_addr.GetLineEntry(); - const auto line = line_entry.GetLine(); - if (line != UINT32_MAX) - breakpoint.line = line; - const auto column = line_entry.GetColumn(); - if (column != 0) - breakpoint.column = column; - breakpoint.source = CreateSource(line_entry); + if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) { + const auto line = line_entry.GetLine(); + if (line != UINT32_MAX) + breakpoint.line = line; + const auto column = line_entry.GetColumn(); + if (column != 0) + breakpoint.column = column; + breakpoint.source = CreateSource(line_entry); + } else { + // Breakpoint made by assembly + auto symbol = bp_addr.GetSymbol(); + if (symbol.IsValid()) { + breakpoint.line = + m_bp.GetTarget() + .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) + .GetSize() + + 1; + + breakpoint.source = CreateAssemblySource(m_dap.target, bp_addr); + } + } } return breakpoint; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 8f24c6cf82924..b0fe265b7bca1 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -169,6 +169,8 @@ struct DAP { Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; + llvm::DenseMap> + assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; @@ -219,6 +221,9 @@ struct DAP { llvm::StringSet<> modules; /// @} + /// Number of lines of assembly code to show when no debug info is available. + uint32_t number_of_assembly_lines_for_nodebug = 32; + /// Creates a new DAP sessions. /// /// \param[in] log diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 2ac886c3a5d2c..c4d658caeee2d 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "JSONUtils.h" #include "RequestHandler.h" #include @@ -19,19 +18,50 @@ namespace lldb_dap { llvm::Expected BreakpointLocationsRequestHandler::Run( const protocol::BreakpointLocationsArguments &args) const { - std::string path = args.source.path.value_or(""); uint32_t start_line = args.line; uint32_t start_column = args.column.value_or(LLDB_INVALID_COLUMN_NUMBER); uint32_t end_line = args.endLine.value_or(start_line); uint32_t end_column = args.endColumn.value_or(std::numeric_limits::max()); + // Find all relevant lines & columns + llvm::SmallVector, 8> locations; + if (args.source.sourceReference) { + AddAssemblyBreakpointLocations(locations, *args.source.sourceReference, + start_line, end_line); + } else { + std::string path = args.source.path.value_or(""); + AddSourceBreakpointLocations(locations, std::move(path), start_line, + start_column, end_line, end_column); + } + + // The line entries are sorted by addresses, but we must return the list + // ordered by line / column position. + std::sort(locations.begin(), locations.end()); + locations.erase(llvm::unique(locations), locations.end()); + + std::vector breakpoint_locations; + for (auto &l : locations) { + protocol::BreakpointLocation lc; + lc.line = l.first; + lc.column = l.second; + breakpoint_locations.push_back(std::move(lc)); + } + + return protocol::BreakpointLocationsResponseBody{ + /*breakpoints=*/std::move(breakpoint_locations)}; +} + +template +void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const { + lldb::SBFileSpec file_spec(path.c_str(), true); lldb::SBSymbolContextList compile_units = dap.target.FindCompileUnits(file_spec); - // Find all relevant lines & columns - llvm::SmallVector, 8> locations; for (uint32_t c_idx = 0, c_limit = compile_units.GetSize(); c_idx < c_limit; ++c_idx) { const lldb::SBCompileUnit &compile_unit = @@ -71,22 +101,26 @@ BreakpointLocationsRequestHandler::Run( locations.emplace_back(line, column); } } +} - // The line entries are sorted by addresses, but we must return the list - // ordered by line / column position. - std::sort(locations.begin(), locations.end()); - locations.erase(llvm::unique(locations), locations.end()); +template +void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) + return; - std::vector breakpoint_locations; - for (auto &l : locations) { - protocol::BreakpointLocation lc; - lc.line = l.first; - lc.column = l.second; - breakpoint_locations.push_back(std::move(lc)); - } + lldb::SBSymbol symbol = address.GetSymbol(); + if (!symbol.IsValid()) + return; - return protocol::BreakpointLocationsResponseBody{ - /*breakpoints=*/std::move(breakpoint_locations)}; + // start_line is relative to the symbol's start address + lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i <= (end_line - 1); + ++i) { + locations.emplace_back(i, 1); + } } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index e6bccfe12f402..80898d1ee5ef1 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -16,6 +16,7 @@ #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/JSON.h" @@ -232,6 +233,16 @@ class BreakpointLocationsRequestHandler } llvm::Expected Run(const protocol::BreakpointLocationsArguments &args) const override; + + template + void AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const; + template + void AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const; }; class CompletionsRequestHandler : public LegacyRequestHandler { @@ -378,6 +389,15 @@ class SetBreakpointsRequestHandler } llvm::Expected Run(const protocol::SetBreakpointsArguments &args) const override; + + std::vector SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints) + const; + std::vector SetAssemblyBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints) + const; }; class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 86e090b66afe9..7b401f06e9a85 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -23,15 +23,29 @@ llvm::Expected SetBreakpointsRequestHandler::Run( const protocol::SetBreakpointsArguments &args) const { const auto &source = args.source; - const auto path = source.path.value_or(""); std::vector response_breakpoints; + if (source.sourceReference) + response_breakpoints = SetAssemblyBreakpoints(source, args.breakpoints); + else if (source.path) + response_breakpoints = SetSourceBreakpoints(source, args.breakpoints); + + return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; +} + +std::vector +SetBreakpointsRequestHandler::SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints) + const { + std::vector response_breakpoints; + std::string path = source.path.value_or(""); // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; // "breakpoints" may be unset, in which case we treat it the same as being set // to an empty array. - if (args.breakpoints) { - for (const auto &bp : *args.breakpoints) { + if (breakpoints) { + for (const auto &bp : *breakpoints) { SourceBreakpoint src_bp(dap, bp); std::pair bp_pos(src_bp.GetLine(), src_bp.GetColumn()); @@ -73,7 +87,64 @@ SetBreakpointsRequestHandler::Run( } } - return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; + return response_breakpoints; +} + +std::vector +SetBreakpointsRequestHandler::SetAssemblyBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints) + const { + std::vector response_breakpoints; + int64_t sourceReference = source.sourceReference.value_or(0); + + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) + return response_breakpoints; + + lldb::SBSymbol symbol = address.GetSymbol(); + if (!symbol.IsValid()) + return response_breakpoints; // Not yet supporting breakpoints in assembly + // without a valid symbol + + llvm::DenseMap request_bps; + if (breakpoints) { + for (const auto &bp : *breakpoints) { + SourceBreakpoint src_bp(dap, bp); + request_bps.try_emplace(src_bp.GetLine(), src_bp); + const auto [iv, inserted] = + dap.assembly_breakpoints[sourceReference].try_emplace( + src_bp.GetLine(), src_bp); + // We check if this breakpoint already exists to update it + if (inserted) + iv->getSecond().SetBreakpoint(symbol); + else + iv->getSecond().UpdateBreakpoint(src_bp); + + protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); + response_bp.source = source; + if (!response_bp.line) + response_bp.line = src_bp.GetLine(); + if (bp.column) + response_bp.column = *bp.column; + response_breakpoints.push_back(response_bp); + } + } + + // Delete existing breakpoints for this sourceReference that are not in the + // request_bps set. + auto old_src_bp_pos = dap.assembly_breakpoints.find(sourceReference); + if (old_src_bp_pos != dap.assembly_breakpoints.end()) { + for (auto &old_bp : old_src_bp_pos->second) { + auto request_pos = request_bps.find(old_bp.first); + if (request_pos == request_bps.end()) { + dap.target.BreakpointDelete(old_bp.second.GetID()); + old_src_bp_pos->second.erase(old_bp.first); + } + } + } + + return response_breakpoints; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp index 0ddd87881a164..9249e2aa6fef7 100644 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp @@ -11,6 +11,7 @@ #include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" +#include "lldb/API/SBAddress.h" #include "lldb/API/SBExecutionContext.h" #include "lldb/API/SBFrame.h" #include "lldb/API/SBInstructionList.h" @@ -19,6 +20,7 @@ #include "lldb/API/SBSymbol.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" +#include "lldb/lldb-types.h" #include "llvm/Support/Error.h" namespace lldb_dap { @@ -34,26 +36,22 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { return llvm::make_error( "invalid arguments, expected source.sourceReference to be set"); - lldb::SBProcess process = dap.target.GetProcess(); - // Upper 32 bits is the thread index ID - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(source)); - ... [truncated] ``````````
https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sat May 17 17:30:47 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sat, 17 May 2025 17:30:47 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68292a37.050a0220.4973.a38e@mx.google.com> github-actions[bot] wrote: :warning: Python code formatter, darker found issues in your code. :warning:
You can test this locally with the following command: ``````````bash darker --check --diff -r HEAD~1...HEAD lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py ``````````
View the diff from darker here. ``````````diff --- packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py 2025-05-18 00:26:37.000000 +0000 +++ packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py 2025-05-18 00:30:17.199504 +0000 @@ -61,13 +61,15 @@ breakpoints = response["body"]["breakpoints"] breakpoint_ids = [] for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) return breakpoint_ids - + def set_source_breakpoints_assembly(self, source_reference, lines, data=None): - response = self.dap_server.request_setBreakpointsAssembly(source_reference, lines, data) + response = self.dap_server.request_setBreakpointsAssembly( + source_reference, lines, data + ) if response is None: return [] breakpoints = response["body"]["breakpoints"] breakpoint_ids = [] for breakpoint in breakpoints: ``````````
https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sat May 17 17:45:54 2025 From: lldb-commits at lists.llvm.org (Dave Lee via lldb-commits) Date: Sat, 17 May 2025 17:45:54 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Add templated CompilerType::GetTypeSystem (NFC) (PR #140424) Message-ID: https://github.com/kastiglione created https://github.com/llvm/llvm-project/pull/140424 None >From f00b0d192a921c6cec369d2d674b617a9ca1f706 Mon Sep 17 00:00:00 2001 From: Dave Lee Date: Fri, 16 May 2025 11:47:08 -0700 Subject: [PATCH] [lldb] Add templated CompilerType::GetTypeSystem (NFC) --- lldb/include/lldb/Symbol/CompilerType.h | 5 +++ .../Clang/ClangASTImporter.cpp | 4 +-- .../ExpressionParser/Clang/ClangASTSource.cpp | 3 +- .../Clang/ClangExpressionDeclMap.cpp | 9 +++--- .../ExpressionParser/Clang/ClangUtil.cpp | 2 +- .../Clang/NameSearchContext.cpp | 4 +-- .../Language/CPlusPlus/BlockPointer.cpp | 4 +-- .../Plugins/Language/CPlusPlus/Coroutines.cpp | 3 +- .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 8 ++--- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 6 ++-- .../NativePDB/SymbolFileNativePDB.cpp | 3 +- .../TypeSystem/Clang/TypeSystemClang.cpp | 31 +++++++------------ .../DynamicValueObjectLocalBuffer.cpp | 4 +-- 13 files changed, 36 insertions(+), 50 deletions(-) diff --git a/lldb/include/lldb/Symbol/CompilerType.h b/lldb/include/lldb/Symbol/CompilerType.h index b8badfda92cf3..df8489a7fe582 100644 --- a/lldb/include/lldb/Symbol/CompilerType.h +++ b/lldb/include/lldb/Symbol/CompilerType.h @@ -276,6 +276,11 @@ class CompilerType { /// TypeSystem::TypeSystemSPWrapper can be compared for equality. TypeSystemSPWrapper GetTypeSystem() const; + template + std::shared_ptr GetTypeSystem() const { + return GetTypeSystem().dyn_cast_or_null(); + } + ConstString GetTypeName(bool BaseOnly = false) const; ConstString GetDisplayTypeName() const; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp index db9a6dd197b3a..c8c8ba53e3bae 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -37,7 +37,7 @@ CompilerType ClangASTImporter::CopyType(TypeSystemClang &dst_ast, const CompilerType &src_type) { clang::ASTContext &dst_clang_ast = dst_ast.getASTContext(); - auto src_ast = src_type.GetTypeSystem().dyn_cast_or_null(); + auto src_ast = src_type.GetTypeSystem(); if (!src_ast) return CompilerType(); @@ -307,7 +307,7 @@ CompilerType ClangASTImporter::DeportType(TypeSystemClang &dst, const CompilerType &src_type) { Log *log = GetLog(LLDBLog::Expressions); - auto src_ctxt = src_type.GetTypeSystem().dyn_cast_or_null(); + auto src_ctxt = src_type.GetTypeSystem(); if (!src_ctxt) return {}; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index 34129807277d5..4b52f6aafcb75 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -1477,8 +1477,7 @@ ClangASTImporter::DeclOrigin ClangASTSource::GetDeclOrigin(const clang::Decl *de } CompilerType ClangASTSource::GuardedCopyType(const CompilerType &src_type) { - auto ts = src_type.GetTypeSystem(); - auto src_ast = ts.dyn_cast_or_null(); + auto src_ast = src_type.GetTypeSystem(); if (!src_ast) return {}; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index 667cb8a900459..db4973b4a4d3e 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -219,7 +219,7 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, bool is_result, bool is_lvalue) { assert(m_parser_vars.get()); - auto ast = parser_type.GetTypeSystem().dyn_cast_or_null(); + auto ast = parser_type.GetTypeSystem(); if (ast == nullptr) return false; @@ -1486,8 +1486,8 @@ bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var, return false; } - auto ts = var_type->GetForwardCompilerType().GetTypeSystem(); - auto clang_ast = ts.dyn_cast_or_null(); + auto clang_ast = + var_type->GetForwardCompilerType().GetTypeSystem(); if (!clang_ast) { LLDB_LOG(log, "Skipped a definition because it has no Clang AST"); @@ -1606,8 +1606,7 @@ void ClangExpressionDeclMap::AddOneVariable( TypeFromUser user_type = valobj->GetCompilerType(); - auto clang_ast = - user_type.GetTypeSystem().dyn_cast_or_null(); + auto clang_ast = user_type.GetTypeSystem(); if (!clang_ast) { LLDB_LOG(log, "Skipped a definition because it has no Clang AST"); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp index 4cda426e72704..20de4b7f735e7 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp @@ -19,7 +19,7 @@ bool ClangUtil::IsClangType(const CompilerType &ct) { if (!ct) return false; - if (!ct.GetTypeSystem().dyn_cast_or_null()) + if (!ct.GetTypeSystem()) return false; if (!ct.GetOpaqueQualType()) diff --git a/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp index da59855a9f162..45ad4f1ad98b9 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp @@ -19,7 +19,7 @@ clang::NamedDecl *NameSearchContext::AddVarDecl(const CompilerType &type) { if (!type.IsValid()) return nullptr; - auto lldb_ast = type.GetTypeSystem().dyn_cast_or_null(); + auto lldb_ast = type.GetTypeSystem(); if (!lldb_ast) return nullptr; @@ -45,7 +45,7 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, if (m_function_types.count(type)) return nullptr; - auto lldb_ast = type.GetTypeSystem().dyn_cast_or_null(); + auto lldb_ast = type.GetTypeSystem(); if (!lldb_ast) return nullptr; diff --git a/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp b/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp index 23e83616e0843..9ab1bf03250b1 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp @@ -50,8 +50,8 @@ class BlockPointerSyntheticFrontEnd : public SyntheticChildrenFrontEnd { return; } - auto ts = block_pointer_type.GetTypeSystem(); - auto clang_ast_context = ts.dyn_cast_or_null(); + auto clang_ast_context = + block_pointer_type.GetTypeSystem(); if (!clang_ast_context) return; diff --git a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp index 376555936e89d..d3cdb231fbb01 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp @@ -141,8 +141,7 @@ lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::Update() { if (frame_ptr_addr == 0 || frame_ptr_addr == LLDB_INVALID_ADDRESS) return lldb::ChildCacheState::eRefetch; - auto ts = valobj_sp->GetCompilerType().GetTypeSystem(); - auto ast_ctx = ts.dyn_cast_or_null(); + auto ast_ctx = valobj_sp->GetCompilerType().GetTypeSystem(); if (!ast_ctx) return lldb::ChildCacheState::eRefetch; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index e3a866e2b6d48..0c26c276cc530 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -1531,8 +1531,7 @@ void DWARFASTParserClang::ParseInheritance( const lldb::ModuleSP &module_sp, std::vector> &base_classes, ClangASTImporter::LayoutInfo &layout_info) { - auto ast = - class_clang_type.GetTypeSystem().dyn_cast_or_null(); + auto ast = class_clang_type.GetTypeSystem(); if (ast == nullptr) return; @@ -2823,7 +2822,7 @@ llvm::Expected DWARFASTParserClang::ExtractIntFromFormValue( const CompilerType &int_type, const DWARFFormValue &form_value) const { clang::QualType qt = ClangUtil::GetQualType(int_type); assert(qt->isIntegralOrEnumerationType()); - auto ts_ptr = int_type.GetTypeSystem().dyn_cast_or_null(); + auto ts_ptr = int_type.GetTypeSystem(); if (!ts_ptr) return llvm::createStringError(llvm::inconvertibleErrorCode(), "TypeSystem not clang"); @@ -3131,8 +3130,7 @@ bool DWARFASTParserClang::ParseChildMembers( FieldInfo last_field_info; ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule(); - auto ts = class_clang_type.GetTypeSystem(); - auto ast = ts.dyn_cast_or_null(); + auto ast = class_clang_type.GetTypeSystem(); if (ast == nullptr) return false; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 0fc7f79be70ec..3f2f1a3b427dc 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1538,8 +1538,7 @@ bool SymbolFileDWARF::HasForwardDeclForCompilerType( compiler_type_no_qualifiers.GetOpaqueQualType())) { return true; } - auto type_system = compiler_type.GetTypeSystem(); - auto clang_type_system = type_system.dyn_cast_or_null(); + auto clang_type_system = compiler_type.GetTypeSystem(); if (!clang_type_system) return false; DWARFASTParserClang *ast_parser = @@ -1549,8 +1548,7 @@ bool SymbolFileDWARF::HasForwardDeclForCompilerType( bool SymbolFileDWARF::CompleteType(CompilerType &compiler_type) { std::lock_guard guard(GetModuleMutex()); - auto clang_type_system = - compiler_type.GetTypeSystem().dyn_cast_or_null(); + auto clang_type_system = compiler_type.GetTypeSystem(); if (clang_type_system) { DWARFASTParserClang *ast_parser = static_cast(clang_type_system->GetDWARFParser()); diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp index ce0360120efeb..dadc969c48a3a 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -2141,8 +2141,7 @@ SymbolFileNativePDB::GetDynamicArrayInfoForUID( bool SymbolFileNativePDB::CompleteType(CompilerType &compiler_type) { std::lock_guard guard(GetModuleMutex()); - auto ts = compiler_type.GetTypeSystem(); - auto clang_type_system = ts.dyn_cast_or_null(); + auto clang_type_system = compiler_type.GetTypeSystem(); if (!clang_type_system) return false; diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 28081e8f6b965..bc9a41b58c0d7 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -1135,7 +1135,7 @@ CompilerType TypeSystemClang::GetCStringType(bool is_const) { bool TypeSystemClang::AreTypesSame(CompilerType type1, CompilerType type2, bool ignore_qualifiers) { - auto ast = type1.GetTypeSystem().dyn_cast_or_null(); + auto ast = type1.GetTypeSystem(); if (!ast || type1.GetTypeSystem() != type2.GetTypeSystem()) return false; @@ -7333,8 +7333,7 @@ clang::FieldDecl *TypeSystemClang::AddFieldToRecordType( uint32_t bitfield_bit_size) { if (!type.IsValid() || !field_clang_type.IsValid()) return nullptr; - auto ts = type.GetTypeSystem(); - auto ast = ts.dyn_cast_or_null(); + auto ast = type.GetTypeSystem(); if (!ast) return nullptr; clang::ASTContext &clang_ast = ast->getASTContext(); @@ -7437,8 +7436,7 @@ void TypeSystemClang::BuildIndirectFields(const CompilerType &type) { if (!type) return; - auto ts = type.GetTypeSystem(); - auto ast = ts.dyn_cast_or_null(); + auto ast = type.GetTypeSystem(); if (!ast) return; @@ -7544,8 +7542,7 @@ void TypeSystemClang::BuildIndirectFields(const CompilerType &type) { void TypeSystemClang::SetIsPacked(const CompilerType &type) { if (type) { - auto ts = type.GetTypeSystem(); - auto ast = ts.dyn_cast_or_null(); + auto ast = type.GetTypeSystem(); if (ast) { clang::RecordDecl *record_decl = GetAsRecordDecl(type); @@ -7564,8 +7561,7 @@ clang::VarDecl *TypeSystemClang::AddVariableToRecordType( if (!type.IsValid() || !var_type.IsValid()) return nullptr; - auto ts = type.GetTypeSystem(); - auto ast = ts.dyn_cast_or_null(); + auto ast = type.GetTypeSystem(); if (!ast) return nullptr; @@ -7890,8 +7886,7 @@ bool TypeSystemClang::TransferBaseClasses( bool TypeSystemClang::SetObjCSuperClass( const CompilerType &type, const CompilerType &superclass_clang_type) { - auto ts = type.GetTypeSystem(); - auto ast = ts.dyn_cast_or_null(); + auto ast = type.GetTypeSystem(); if (!ast) return false; clang::ASTContext &clang_ast = ast->getASTContext(); @@ -7919,8 +7914,7 @@ bool TypeSystemClang::AddObjCClassProperty( if (!type || !property_clang_type.IsValid() || property_name == nullptr || property_name[0] == '\0') return false; - auto ts = type.GetTypeSystem(); - auto ast = ts.dyn_cast_or_null(); + auto ast = type.GetTypeSystem(); if (!ast) return false; clang::ASTContext &clang_ast = ast->getASTContext(); @@ -8139,8 +8133,7 @@ clang::ObjCMethodDecl *TypeSystemClang::AddMethodToObjCObjectType( if (class_interface_decl == nullptr) return nullptr; - auto ts = type.GetTypeSystem(); - auto lldb_ast = ts.dyn_cast_or_null(); + auto lldb_ast = type.GetTypeSystem(); if (lldb_ast == nullptr) return nullptr; clang::ASTContext &ast = lldb_ast->getASTContext(); @@ -8344,8 +8337,7 @@ bool TypeSystemClang::CompleteTagDeclarationDefinition( if (qual_type.isNull()) return false; - auto ts = type.GetTypeSystem(); - auto lldb_ast = ts.dyn_cast_or_null(); + auto lldb_ast = type.GetTypeSystem(); if (lldb_ast == nullptr) return false; @@ -8489,8 +8481,7 @@ TypeSystemClang::CreateMemberPointerType(const CompilerType &type, const CompilerType &pointee_type) { if (type && pointee_type.IsValid() && type.GetTypeSystem() == pointee_type.GetTypeSystem()) { - auto ts = type.GetTypeSystem(); - auto ast = ts.dyn_cast_or_null(); + auto ast = type.GetTypeSystem(); if (!ast) return CompilerType(); return ast->GetType(ast->getASTContext().getMemberPointerType( @@ -9554,7 +9545,7 @@ void TypeSystemClang::RequireCompleteType(CompilerType type) { lldbassert(started && "Unable to start a class type definition."); TypeSystemClang::CompleteTagDeclarationDefinition(type); const clang::TagDecl *td = ClangUtil::GetAsTagDecl(type); - auto ts = type.GetTypeSystem().dyn_cast_or_null(); + auto ts = type.GetTypeSystem(); if (ts) ts->SetDeclIsForcefullyCompleted(td); } diff --git a/lldb/unittests/ValueObject/DynamicValueObjectLocalBuffer.cpp b/lldb/unittests/ValueObject/DynamicValueObjectLocalBuffer.cpp index 417708dd2dc22..0f3d2d2ba9d68 100644 --- a/lldb/unittests/ValueObject/DynamicValueObjectLocalBuffer.cpp +++ b/lldb/unittests/ValueObject/DynamicValueObjectLocalBuffer.cpp @@ -58,9 +58,7 @@ struct MockLanguageRuntime : public LanguageRuntime { TypeAndOrName &class_type_or_name, Address &address, Value::ValueType &value_type, llvm::ArrayRef &local_buffer) override { - auto ast = in_value.GetCompilerType() - .GetTypeSystem() - .dyn_cast_or_null(); + auto ast = in_value.GetCompilerType().GetTypeSystem(); auto int_type = createRecordWithField( *ast, "TypeWitInt", ast->GetBasicType(lldb::BasicType::eBasicTypeInt), From lldb-commits at lists.llvm.org Sat May 17 17:46:30 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sat, 17 May 2025 17:46:30 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Add templated CompilerType::GetTypeSystem (NFC) (PR #140424) In-Reply-To: Message-ID: <68292de6.050a0220.3be8e8.a3f3@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Dave Lee (kastiglione)
Changes --- Full diff: https://github.com/llvm/llvm-project/pull/140424.diff 13 Files Affected: - (modified) lldb/include/lldb/Symbol/CompilerType.h (+5) - (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp (+2-2) - (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp (+1-2) - (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp (+4-5) - (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp (+1-1) - (modified) lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp (+2-2) - (modified) lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp (+2-2) - (modified) lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp (+1-2) - (modified) lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp (+3-5) - (modified) lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp (+2-4) - (modified) lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp (+1-2) - (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp (+11-20) - (modified) lldb/unittests/ValueObject/DynamicValueObjectLocalBuffer.cpp (+1-3) ``````````diff diff --git a/lldb/include/lldb/Symbol/CompilerType.h b/lldb/include/lldb/Symbol/CompilerType.h index b8badfda92cf3..df8489a7fe582 100644 --- a/lldb/include/lldb/Symbol/CompilerType.h +++ b/lldb/include/lldb/Symbol/CompilerType.h @@ -276,6 +276,11 @@ class CompilerType { /// TypeSystem::TypeSystemSPWrapper can be compared for equality. TypeSystemSPWrapper GetTypeSystem() const; + template + std::shared_ptr GetTypeSystem() const { + return GetTypeSystem().dyn_cast_or_null(); + } + ConstString GetTypeName(bool BaseOnly = false) const; ConstString GetDisplayTypeName() const; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp index db9a6dd197b3a..c8c8ba53e3bae 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -37,7 +37,7 @@ CompilerType ClangASTImporter::CopyType(TypeSystemClang &dst_ast, const CompilerType &src_type) { clang::ASTContext &dst_clang_ast = dst_ast.getASTContext(); - auto src_ast = src_type.GetTypeSystem().dyn_cast_or_null(); + auto src_ast = src_type.GetTypeSystem(); if (!src_ast) return CompilerType(); @@ -307,7 +307,7 @@ CompilerType ClangASTImporter::DeportType(TypeSystemClang &dst, const CompilerType &src_type) { Log *log = GetLog(LLDBLog::Expressions); - auto src_ctxt = src_type.GetTypeSystem().dyn_cast_or_null(); + auto src_ctxt = src_type.GetTypeSystem(); if (!src_ctxt) return {}; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index 34129807277d5..4b52f6aafcb75 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -1477,8 +1477,7 @@ ClangASTImporter::DeclOrigin ClangASTSource::GetDeclOrigin(const clang::Decl *de } CompilerType ClangASTSource::GuardedCopyType(const CompilerType &src_type) { - auto ts = src_type.GetTypeSystem(); - auto src_ast = ts.dyn_cast_or_null(); + auto src_ast = src_type.GetTypeSystem(); if (!src_ast) return {}; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index 667cb8a900459..db4973b4a4d3e 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -219,7 +219,7 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, bool is_result, bool is_lvalue) { assert(m_parser_vars.get()); - auto ast = parser_type.GetTypeSystem().dyn_cast_or_null(); + auto ast = parser_type.GetTypeSystem(); if (ast == nullptr) return false; @@ -1486,8 +1486,8 @@ bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var, return false; } - auto ts = var_type->GetForwardCompilerType().GetTypeSystem(); - auto clang_ast = ts.dyn_cast_or_null(); + auto clang_ast = + var_type->GetForwardCompilerType().GetTypeSystem(); if (!clang_ast) { LLDB_LOG(log, "Skipped a definition because it has no Clang AST"); @@ -1606,8 +1606,7 @@ void ClangExpressionDeclMap::AddOneVariable( TypeFromUser user_type = valobj->GetCompilerType(); - auto clang_ast = - user_type.GetTypeSystem().dyn_cast_or_null(); + auto clang_ast = user_type.GetTypeSystem(); if (!clang_ast) { LLDB_LOG(log, "Skipped a definition because it has no Clang AST"); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp index 4cda426e72704..20de4b7f735e7 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp @@ -19,7 +19,7 @@ bool ClangUtil::IsClangType(const CompilerType &ct) { if (!ct) return false; - if (!ct.GetTypeSystem().dyn_cast_or_null()) + if (!ct.GetTypeSystem()) return false; if (!ct.GetOpaqueQualType()) diff --git a/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp index da59855a9f162..45ad4f1ad98b9 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp @@ -19,7 +19,7 @@ clang::NamedDecl *NameSearchContext::AddVarDecl(const CompilerType &type) { if (!type.IsValid()) return nullptr; - auto lldb_ast = type.GetTypeSystem().dyn_cast_or_null(); + auto lldb_ast = type.GetTypeSystem(); if (!lldb_ast) return nullptr; @@ -45,7 +45,7 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, if (m_function_types.count(type)) return nullptr; - auto lldb_ast = type.GetTypeSystem().dyn_cast_or_null(); + auto lldb_ast = type.GetTypeSystem(); if (!lldb_ast) return nullptr; diff --git a/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp b/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp index 23e83616e0843..9ab1bf03250b1 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp @@ -50,8 +50,8 @@ class BlockPointerSyntheticFrontEnd : public SyntheticChildrenFrontEnd { return; } - auto ts = block_pointer_type.GetTypeSystem(); - auto clang_ast_context = ts.dyn_cast_or_null(); + auto clang_ast_context = + block_pointer_type.GetTypeSystem(); if (!clang_ast_context) return; diff --git a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp index 376555936e89d..d3cdb231fbb01 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp @@ -141,8 +141,7 @@ lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::Update() { if (frame_ptr_addr == 0 || frame_ptr_addr == LLDB_INVALID_ADDRESS) return lldb::ChildCacheState::eRefetch; - auto ts = valobj_sp->GetCompilerType().GetTypeSystem(); - auto ast_ctx = ts.dyn_cast_or_null(); + auto ast_ctx = valobj_sp->GetCompilerType().GetTypeSystem(); if (!ast_ctx) return lldb::ChildCacheState::eRefetch; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index e3a866e2b6d48..0c26c276cc530 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -1531,8 +1531,7 @@ void DWARFASTParserClang::ParseInheritance( const lldb::ModuleSP &module_sp, std::vector> &base_classes, ClangASTImporter::LayoutInfo &layout_info) { - auto ast = - class_clang_type.GetTypeSystem().dyn_cast_or_null(); + auto ast = class_clang_type.GetTypeSystem(); if (ast == nullptr) return; @@ -2823,7 +2822,7 @@ llvm::Expected DWARFASTParserClang::ExtractIntFromFormValue( const CompilerType &int_type, const DWARFFormValue &form_value) const { clang::QualType qt = ClangUtil::GetQualType(int_type); assert(qt->isIntegralOrEnumerationType()); - auto ts_ptr = int_type.GetTypeSystem().dyn_cast_or_null(); + auto ts_ptr = int_type.GetTypeSystem(); if (!ts_ptr) return llvm::createStringError(llvm::inconvertibleErrorCode(), "TypeSystem not clang"); @@ -3131,8 +3130,7 @@ bool DWARFASTParserClang::ParseChildMembers( FieldInfo last_field_info; ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule(); - auto ts = class_clang_type.GetTypeSystem(); - auto ast = ts.dyn_cast_or_null(); + auto ast = class_clang_type.GetTypeSystem(); if (ast == nullptr) return false; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 0fc7f79be70ec..3f2f1a3b427dc 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1538,8 +1538,7 @@ bool SymbolFileDWARF::HasForwardDeclForCompilerType( compiler_type_no_qualifiers.GetOpaqueQualType())) { return true; } - auto type_system = compiler_type.GetTypeSystem(); - auto clang_type_system = type_system.dyn_cast_or_null(); + auto clang_type_system = compiler_type.GetTypeSystem(); if (!clang_type_system) return false; DWARFASTParserClang *ast_parser = @@ -1549,8 +1548,7 @@ bool SymbolFileDWARF::HasForwardDeclForCompilerType( bool SymbolFileDWARF::CompleteType(CompilerType &compiler_type) { std::lock_guard guard(GetModuleMutex()); - auto clang_type_system = - compiler_type.GetTypeSystem().dyn_cast_or_null(); + auto clang_type_system = compiler_type.GetTypeSystem(); if (clang_type_system) { DWARFASTParserClang *ast_parser = static_cast(clang_type_system->GetDWARFParser()); diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp index ce0360120efeb..dadc969c48a3a 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -2141,8 +2141,7 @@ SymbolFileNativePDB::GetDynamicArrayInfoForUID( bool SymbolFileNativePDB::CompleteType(CompilerType &compiler_type) { std::lock_guard guard(GetModuleMutex()); - auto ts = compiler_type.GetTypeSystem(); - auto clang_type_system = ts.dyn_cast_or_null(); + auto clang_type_system = compiler_type.GetTypeSystem(); if (!clang_type_system) return false; diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 28081e8f6b965..bc9a41b58c0d7 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -1135,7 +1135,7 @@ CompilerType TypeSystemClang::GetCStringType(bool is_const) { bool TypeSystemClang::AreTypesSame(CompilerType type1, CompilerType type2, bool ignore_qualifiers) { - auto ast = type1.GetTypeSystem().dyn_cast_or_null(); + auto ast = type1.GetTypeSystem(); if (!ast || type1.GetTypeSystem() != type2.GetTypeSystem()) return false; @@ -7333,8 +7333,7 @@ clang::FieldDecl *TypeSystemClang::AddFieldToRecordType( uint32_t bitfield_bit_size) { if (!type.IsValid() || !field_clang_type.IsValid()) return nullptr; - auto ts = type.GetTypeSystem(); - auto ast = ts.dyn_cast_or_null(); + auto ast = type.GetTypeSystem(); if (!ast) return nullptr; clang::ASTContext &clang_ast = ast->getASTContext(); @@ -7437,8 +7436,7 @@ void TypeSystemClang::BuildIndirectFields(const CompilerType &type) { if (!type) return; - auto ts = type.GetTypeSystem(); - auto ast = ts.dyn_cast_or_null(); + auto ast = type.GetTypeSystem(); if (!ast) return; @@ -7544,8 +7542,7 @@ void TypeSystemClang::BuildIndirectFields(const CompilerType &type) { void TypeSystemClang::SetIsPacked(const CompilerType &type) { if (type) { - auto ts = type.GetTypeSystem(); - auto ast = ts.dyn_cast_or_null(); + auto ast = type.GetTypeSystem(); if (ast) { clang::RecordDecl *record_decl = GetAsRecordDecl(type); @@ -7564,8 +7561,7 @@ clang::VarDecl *TypeSystemClang::AddVariableToRecordType( if (!type.IsValid() || !var_type.IsValid()) return nullptr; - auto ts = type.GetTypeSystem(); - auto ast = ts.dyn_cast_or_null(); + auto ast = type.GetTypeSystem(); if (!ast) return nullptr; @@ -7890,8 +7886,7 @@ bool TypeSystemClang::TransferBaseClasses( bool TypeSystemClang::SetObjCSuperClass( const CompilerType &type, const CompilerType &superclass_clang_type) { - auto ts = type.GetTypeSystem(); - auto ast = ts.dyn_cast_or_null(); + auto ast = type.GetTypeSystem(); if (!ast) return false; clang::ASTContext &clang_ast = ast->getASTContext(); @@ -7919,8 +7914,7 @@ bool TypeSystemClang::AddObjCClassProperty( if (!type || !property_clang_type.IsValid() || property_name == nullptr || property_name[0] == '\0') return false; - auto ts = type.GetTypeSystem(); - auto ast = ts.dyn_cast_or_null(); + auto ast = type.GetTypeSystem(); if (!ast) return false; clang::ASTContext &clang_ast = ast->getASTContext(); @@ -8139,8 +8133,7 @@ clang::ObjCMethodDecl *TypeSystemClang::AddMethodToObjCObjectType( if (class_interface_decl == nullptr) return nullptr; - auto ts = type.GetTypeSystem(); - auto lldb_ast = ts.dyn_cast_or_null(); + auto lldb_ast = type.GetTypeSystem(); if (lldb_ast == nullptr) return nullptr; clang::ASTContext &ast = lldb_ast->getASTContext(); @@ -8344,8 +8337,7 @@ bool TypeSystemClang::CompleteTagDeclarationDefinition( if (qual_type.isNull()) return false; - auto ts = type.GetTypeSystem(); - auto lldb_ast = ts.dyn_cast_or_null(); + auto lldb_ast = type.GetTypeSystem(); if (lldb_ast == nullptr) return false; @@ -8489,8 +8481,7 @@ TypeSystemClang::CreateMemberPointerType(const CompilerType &type, const CompilerType &pointee_type) { if (type && pointee_type.IsValid() && type.GetTypeSystem() == pointee_type.GetTypeSystem()) { - auto ts = type.GetTypeSystem(); - auto ast = ts.dyn_cast_or_null(); + auto ast = type.GetTypeSystem(); if (!ast) return CompilerType(); return ast->GetType(ast->getASTContext().getMemberPointerType( @@ -9554,7 +9545,7 @@ void TypeSystemClang::RequireCompleteType(CompilerType type) { lldbassert(started && "Unable to start a class type definition."); TypeSystemClang::CompleteTagDeclarationDefinition(type); const clang::TagDecl *td = ClangUtil::GetAsTagDecl(type); - auto ts = type.GetTypeSystem().dyn_cast_or_null(); + auto ts = type.GetTypeSystem(); if (ts) ts->SetDeclIsForcefullyCompleted(td); } diff --git a/lldb/unittests/ValueObject/DynamicValueObjectLocalBuffer.cpp b/lldb/unittests/ValueObject/DynamicValueObjectLocalBuffer.cpp index 417708dd2dc22..0f3d2d2ba9d68 100644 --- a/lldb/unittests/ValueObject/DynamicValueObjectLocalBuffer.cpp +++ b/lldb/unittests/ValueObject/DynamicValueObjectLocalBuffer.cpp @@ -58,9 +58,7 @@ struct MockLanguageRuntime : public LanguageRuntime { TypeAndOrName &class_type_or_name, Address &address, Value::ValueType &value_type, llvm::ArrayRef &local_buffer) override { - auto ast = in_value.GetCompilerType() - .GetTypeSystem() - .dyn_cast_or_null(); + auto ast = in_value.GetCompilerType().GetTypeSystem(); auto int_type = createRecordWithField( *ast, "TypeWitInt", ast->GetBasicType(lldb::BasicType::eBasicTypeInt), ``````````
https://github.com/llvm/llvm-project/pull/140424 From lldb-commits at lists.llvm.org Sat May 17 17:47:29 2025 From: lldb-commits at lists.llvm.org (Dave Lee via lldb-commits) Date: Sat, 17 May 2025 17:47:29 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Add templated CompilerType::GetTypeSystem (NFC) (PR #140424) In-Reply-To: Message-ID: <68292e21.170a0220.3a6e10.65f6@mx.google.com> https://github.com/kastiglione edited https://github.com/llvm/llvm-project/pull/140424 From lldb-commits at lists.llvm.org Sat May 17 18:33:59 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sat, 17 May 2025 18:33:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68293907.050a0220.26a250.b31e@mx.google.com> ================ @@ -71,22 +101,26 @@ BreakpointLocationsRequestHandler::Run( locations.emplace_back(line, column); } } +} - // The line entries are sorted by addresses, but we must return the list - // ordered by line / column position. - std::sort(locations.begin(), locations.end()); - locations.erase(llvm::unique(locations), locations.end()); +template +void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, ---------------- JDevlieghere wrote: You can avoid the template by taking a reference to a `SmallVectorImpl>`, which `SmallVector` inherits from. https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sat May 17 18:33:59 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sat, 17 May 2025 18:33:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68293907.170a0220.34373.99a6@mx.google.com> ================ @@ -53,6 +54,8 @@ class LLDB_API SBFileSpec { uint32_t GetPath(char *dst_path, size_t dst_len) const; + bool GetPath(lldb::SBStream &dst_path) const; ---------------- JDevlieghere wrote: I have mixed feelings about adding this API. Generally, we usually use streams when we have potentially multiline output which isn't the case. Here I'm also worried about setting a precedent that will lead to having more methods overloaded with streams. If this were private API I wouldn't mind, but since we guarantee ABI stability for the SB API, once an API has been added, we have to support it forever. How about adding a helper to LLDBUtils that takes a `SBFileSpec` and returns the path as a std::string? https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sat May 17 18:33:59 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sat, 17 May 2025 18:33:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68293907.170a0220.15d084.9ddc@mx.google.com> ================ @@ -219,6 +221,9 @@ struct DAP { llvm::StringSet<> modules; /// @} + /// Number of lines of assembly code to show when no debug info is available. + uint32_t number_of_assembly_lines_for_nodebug = 32; ---------------- JDevlieghere wrote: Is this a constant? ```suggestion static constexpr uint32_t number_of_assembly_lines_for_nodebug = 32; ``` https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sat May 17 18:33:59 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sat, 17 May 2025 18:33:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68293907.170a0220.184911.97db@mx.google.com> ================ @@ -73,7 +87,64 @@ SetBreakpointsRequestHandler::Run( } } - return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; + return response_breakpoints; +} + +std::vector +SetBreakpointsRequestHandler::SetAssemblyBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints) + const { + std::vector response_breakpoints; + int64_t sourceReference = source.sourceReference.value_or(0); + + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) + return response_breakpoints; + + lldb::SBSymbol symbol = address.GetSymbol(); + if (!symbol.IsValid()) + return response_breakpoints; // Not yet supporting breakpoints in assembly + // without a valid symbol + + llvm::DenseMap request_bps; + if (breakpoints) { + for (const auto &bp : *breakpoints) { + SourceBreakpoint src_bp(dap, bp); + request_bps.try_emplace(src_bp.GetLine(), src_bp); + const auto [iv, inserted] = + dap.assembly_breakpoints[sourceReference].try_emplace( + src_bp.GetLine(), src_bp); + // We check if this breakpoint already exists to update it ---------------- JDevlieghere wrote: ```suggestion // We check if this breakpoint already exists to update it. ``` https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sat May 17 18:33:59 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sat, 17 May 2025 18:33:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68293907.a70a0220.212871.af31@mx.google.com> ================ @@ -73,7 +87,64 @@ SetBreakpointsRequestHandler::Run( } } - return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; + return response_breakpoints; +} + +std::vector +SetBreakpointsRequestHandler::SetAssemblyBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints) + const { + std::vector response_breakpoints; + int64_t sourceReference = source.sourceReference.value_or(0); + + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) + return response_breakpoints; + + lldb::SBSymbol symbol = address.GetSymbol(); + if (!symbol.IsValid()) + return response_breakpoints; // Not yet supporting breakpoints in assembly + // without a valid symbol + + llvm::DenseMap request_bps; + if (breakpoints) { + for (const auto &bp : *breakpoints) { + SourceBreakpoint src_bp(dap, bp); + request_bps.try_emplace(src_bp.GetLine(), src_bp); + const auto [iv, inserted] = + dap.assembly_breakpoints[sourceReference].try_emplace( ---------------- JDevlieghere wrote: This together with the logic to either add or update a breakpoint seems like it could be abstracted away behind a function in the dap class. Something like `dap.SetAssemblyBreakpoint(uint32_t line, SourceBreakpoint& source_bp)`. Same thing with the delete below and then we can make `assembly_breakpoints` a member and provide some more abstraction. https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sat May 17 18:33:59 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sat, 17 May 2025 18:33:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68293907.170a0220.162f30.67b7@mx.google.com> ================ @@ -19,19 +18,50 @@ namespace lldb_dap { llvm::Expected BreakpointLocationsRequestHandler::Run( const protocol::BreakpointLocationsArguments &args) const { - std::string path = args.source.path.value_or(""); uint32_t start_line = args.line; uint32_t start_column = args.column.value_or(LLDB_INVALID_COLUMN_NUMBER); uint32_t end_line = args.endLine.value_or(start_line); uint32_t end_column = args.endColumn.value_or(std::numeric_limits::max()); + // Find all relevant lines & columns ---------------- JDevlieghere wrote: ```suggestion // Find all relevant lines & columns. ``` https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sat May 17 18:33:59 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sat, 17 May 2025 18:33:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68293907.170a0220.689dd.9b9c@mx.google.com> ================ @@ -73,7 +87,64 @@ SetBreakpointsRequestHandler::Run( } } - return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; + return response_breakpoints; +} + +std::vector +SetBreakpointsRequestHandler::SetAssemblyBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints) + const { + std::vector response_breakpoints; + int64_t sourceReference = source.sourceReference.value_or(0); + + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) + return response_breakpoints; + + lldb::SBSymbol symbol = address.GetSymbol(); + if (!symbol.IsValid()) + return response_breakpoints; // Not yet supporting breakpoints in assembly + // without a valid symbol ---------------- JDevlieghere wrote: Don't worry about adding the braces when you have a comment. ```suggestion if (!symbol.IsValid()) { // Not yet supporting breakpoints in assembly without a valid symbol. return response_breakpoints; } ``` https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sat May 17 18:33:59 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sat, 17 May 2025 18:33:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68293907.170a0220.7cdba.b00c@mx.google.com> ================ @@ -71,22 +101,26 @@ BreakpointLocationsRequestHandler::Run( locations.emplace_back(line, column); } } +} - // The line entries are sorted by addresses, but we must return the list - // ordered by line / column position. - std::sort(locations.begin(), locations.end()); - locations.erase(llvm::unique(locations), locations.end()); +template +void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, ---------------- JDevlieghere wrote: Looking at how this is called, maybe you don't even need to take this by reference, and you can have this return a `llvm::SmallVector, 8>`. Honestly I don't even know if the `SmallVector` optimization is worth it here, personally I would've just returned a regular `std::vector`. If you change the return type, you can also change the name of the method from `Add` to `Get`. Now it looks like there's potentially multiple calls adding values to the location list. https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sat May 17 18:33:59 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sat, 17 May 2025 18:33:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68293907.170a0220.1b64f.c7ad@mx.google.com> ================ @@ -19,19 +18,50 @@ namespace lldb_dap { llvm::Expected BreakpointLocationsRequestHandler::Run( const protocol::BreakpointLocationsArguments &args) const { - std::string path = args.source.path.value_or(""); uint32_t start_line = args.line; uint32_t start_column = args.column.value_or(LLDB_INVALID_COLUMN_NUMBER); uint32_t end_line = args.endLine.value_or(start_line); uint32_t end_column = args.endColumn.value_or(std::numeric_limits::max()); + // Find all relevant lines & columns + llvm::SmallVector, 8> locations; + if (args.source.sourceReference) { + AddAssemblyBreakpointLocations(locations, *args.source.sourceReference, + start_line, end_line); + } else { + std::string path = args.source.path.value_or(""); + AddSourceBreakpointLocations(locations, std::move(path), start_line, + start_column, end_line, end_column); + } + + // The line entries are sorted by addresses, but we must return the list + // ordered by line / column position. + std::sort(locations.begin(), locations.end()); + locations.erase(llvm::unique(locations), locations.end()); + + std::vector breakpoint_locations; + for (auto &l : locations) { + protocol::BreakpointLocation lc; + lc.line = l.first; + lc.column = l.second; + breakpoint_locations.push_back(std::move(lc)); + } ---------------- JDevlieghere wrote: I think you should be able to create the locations in place like this: ```suggestion for (auto &l : locations) breakpoint_locations.emplace_back({l.first, l.second}); ``` https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sat May 17 18:33:59 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sat, 17 May 2025 18:33:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68293907.630a0220.176f68.d8b5@mx.google.com> ================ @@ -73,7 +87,64 @@ SetBreakpointsRequestHandler::Run( } } - return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; + return response_breakpoints; +} + +std::vector +SetBreakpointsRequestHandler::SetAssemblyBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints) + const { + std::vector response_breakpoints; + int64_t sourceReference = source.sourceReference.value_or(0); + + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) + return response_breakpoints; + + lldb::SBSymbol symbol = address.GetSymbol(); + if (!symbol.IsValid()) + return response_breakpoints; // Not yet supporting breakpoints in assembly + // without a valid symbol + + llvm::DenseMap request_bps; ---------------- JDevlieghere wrote: Let's add a comment saying what the key is, or better change the variable name to make it obvious: `line_to_requested_source_bps` or something. https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sat May 17 18:58:11 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sat, 17 May 2025 18:58:11 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Fix raciness in launch and attach tests (PR #137920) In-Reply-To: Message-ID: <68293eb3.170a0220.1bea2b.94f0@mx.google.com> https://github.com/JDevlieghere closed https://github.com/llvm/llvm-project/pull/137920 From lldb-commits at lists.llvm.org Sat May 17 23:03:29 2025 From: lldb-commits at lists.llvm.org (Kazu Hirata via lldb-commits) Date: Sat, 17 May 2025 23:03:29 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Remove redundant calls to std::unique_ptr::get (NFC) (NFC) (PR #140440) Message-ID: https://github.com/kazutakahirata created https://github.com/llvm/llvm-project/pull/140440 None >From 308551bc503d13d3a9f991325fdeba0126a54f7e Mon Sep 17 00:00:00 2001 From: Kazu Hirata Date: Sat, 17 May 2025 22:59:12 -0700 Subject: [PATCH] [lldb] Remove redundant calls to std::unique_ptr::get (NFC) (NFC) --- lldb/source/Target/RegisterContextUnwind.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index 2958923a98010..1884d8d53a7f6 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -273,7 +273,7 @@ void RegisterContextUnwind::InitializeZerothFrame() { call_site_unwind_plan = func_unwinders_sp->GetUnwindPlanAtCallSite( process->GetTarget(), m_thread); - if (call_site_unwind_plan.get() != nullptr) { + if (call_site_unwind_plan != nullptr) { m_fallback_unwind_plan_sp = call_site_unwind_plan; if (TryFallbackUnwindPlan()) cfa_status = true; @@ -1725,10 +1725,10 @@ RegisterContextUnwind::SavedLocationForRegister( // tricky frame and our usual techniques can continue to be used. bool RegisterContextUnwind::TryFallbackUnwindPlan() { - if (m_fallback_unwind_plan_sp.get() == nullptr) + if (m_fallback_unwind_plan_sp == nullptr) return false; - if (m_full_unwind_plan_sp.get() == nullptr) + if (m_full_unwind_plan_sp == nullptr) return false; if (m_full_unwind_plan_sp.get() == m_fallback_unwind_plan_sp.get() || @@ -1776,7 +1776,7 @@ bool RegisterContextUnwind::TryFallbackUnwindPlan() { // fallback UnwindPlan. We checked if m_fallback_unwind_plan_sp was nullptr // at the top -- the only way it became nullptr since then is via // SavedLocationForRegister(). - if (m_fallback_unwind_plan_sp.get() == nullptr) + if (m_fallback_unwind_plan_sp == nullptr) return true; // Switch the full UnwindPlan to be the fallback UnwindPlan. If we decide @@ -1865,10 +1865,10 @@ bool RegisterContextUnwind::TryFallbackUnwindPlan() { } bool RegisterContextUnwind::ForceSwitchToFallbackUnwindPlan() { - if (m_fallback_unwind_plan_sp.get() == nullptr) + if (m_fallback_unwind_plan_sp == nullptr) return false; - if (m_full_unwind_plan_sp.get() == nullptr) + if (m_full_unwind_plan_sp == nullptr) return false; if (m_full_unwind_plan_sp.get() == m_fallback_unwind_plan_sp.get() || From lldb-commits at lists.llvm.org Sat May 17 23:04:02 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sat, 17 May 2025 23:04:02 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Remove redundant calls to std::unique_ptr::get (NFC) (NFC) (PR #140440) In-Reply-To: Message-ID: <68297852.050a0220.40824.b7e3@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Kazu Hirata (kazutakahirata)
Changes --- Full diff: https://github.com/llvm/llvm-project/pull/140440.diff 1 Files Affected: - (modified) lldb/source/Target/RegisterContextUnwind.cpp (+6-6) ``````````diff diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index 2958923a98010..1884d8d53a7f6 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -273,7 +273,7 @@ void RegisterContextUnwind::InitializeZerothFrame() { call_site_unwind_plan = func_unwinders_sp->GetUnwindPlanAtCallSite( process->GetTarget(), m_thread); - if (call_site_unwind_plan.get() != nullptr) { + if (call_site_unwind_plan != nullptr) { m_fallback_unwind_plan_sp = call_site_unwind_plan; if (TryFallbackUnwindPlan()) cfa_status = true; @@ -1725,10 +1725,10 @@ RegisterContextUnwind::SavedLocationForRegister( // tricky frame and our usual techniques can continue to be used. bool RegisterContextUnwind::TryFallbackUnwindPlan() { - if (m_fallback_unwind_plan_sp.get() == nullptr) + if (m_fallback_unwind_plan_sp == nullptr) return false; - if (m_full_unwind_plan_sp.get() == nullptr) + if (m_full_unwind_plan_sp == nullptr) return false; if (m_full_unwind_plan_sp.get() == m_fallback_unwind_plan_sp.get() || @@ -1776,7 +1776,7 @@ bool RegisterContextUnwind::TryFallbackUnwindPlan() { // fallback UnwindPlan. We checked if m_fallback_unwind_plan_sp was nullptr // at the top -- the only way it became nullptr since then is via // SavedLocationForRegister(). - if (m_fallback_unwind_plan_sp.get() == nullptr) + if (m_fallback_unwind_plan_sp == nullptr) return true; // Switch the full UnwindPlan to be the fallback UnwindPlan. If we decide @@ -1865,10 +1865,10 @@ bool RegisterContextUnwind::TryFallbackUnwindPlan() { } bool RegisterContextUnwind::ForceSwitchToFallbackUnwindPlan() { - if (m_fallback_unwind_plan_sp.get() == nullptr) + if (m_fallback_unwind_plan_sp == nullptr) return false; - if (m_full_unwind_plan_sp.get() == nullptr) + if (m_full_unwind_plan_sp == nullptr) return false; if (m_full_unwind_plan_sp.get() == m_fallback_unwind_plan_sp.get() || ``````````
https://github.com/llvm/llvm-project/pull/140440 From lldb-commits at lists.llvm.org Sat May 17 23:23:40 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Sat, 17 May 2025 23:23:40 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Member variable cleanup in DAP.{cpp, h} (NFC) (PR #140390) In-Reply-To: Message-ID: <68297cec.170a0220.f1a80.9fe2@mx.google.com> https://github.com/ashgti approved this pull request. https://github.com/llvm/llvm-project/pull/140390 From lldb-commits at lists.llvm.org Sun May 18 01:06:11 2025 From: lldb-commits at lists.llvm.org (Matt Arsenault via lldb-commits) Date: Sun, 18 May 2025 01:06:11 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Remove redundant calls to std::unique_ptr::get (NFC) (NFC) (PR #140440) In-Reply-To: Message-ID: <682994f3.a70a0220.dc1fd.a5e0@mx.google.com> https://github.com/arsenm approved this pull request. https://github.com/llvm/llvm-project/pull/140440 From lldb-commits at lists.llvm.org Sun May 18 01:10:14 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sun, 18 May 2025 01:10:14 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Suppport testing with debug-python on Windows (PR #140443) Message-ID: https://github.com/Nerixyz created https://github.com/llvm/llvm-project/pull/140443 When trying to run the LLDB API tests on Windows with a debug configuration, they fail, because the `_lldb` module won't be found. As explained in https://github.com/llvm/llvm-project/issues/51272, this is because lit will run the test with `python.exe` but the module is built for the debug version of python, `python_d.exe`. CMake already resolved the debug executable in `Python3_EXECUTABLE_DEBUG`, so this PR changes the `config.python_executable` to point to `python_d.exe` on Windows in debug mode. The check is equivalent to the one done in the top-level LLDB CMakeLists [when setting the python suffix](https://github.com/llvm/llvm-project/blob/3ccb15d6caf57f2a866d496ada2fb52d14b179d2/lldb/CMakeLists.txt#L79-L86). >From f82a1f31be6cb4c18ae8100c40d813e4236ffd92 Mon Sep 17 00:00:00 2001 From: Nerixyz Date: Sun, 18 May 2025 09:54:54 +0200 Subject: [PATCH] [lldb] Suppport testing with debug-python on Windows --- lldb/test/API/CMakeLists.txt | 6 ++++++ lldb/test/API/lit.site.cfg.py.in | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lldb/test/API/CMakeLists.txt b/lldb/test/API/CMakeLists.txt index da51f2252d023..b1ace6296f46a 100644 --- a/lldb/test/API/CMakeLists.txt +++ b/lldb/test/API/CMakeLists.txt @@ -139,6 +139,12 @@ if(CMAKE_HOST_APPLE) endif() endif() +if(WIN32 AND CMAKE_BUILD_TYPE STREQUAL Debug) + set(LLDB_PYTHON_API_TEST_EXECUTABLE "${Python3_EXECUTABLE_DEBUG}") +else() + set(LLDB_PYTHON_API_TEST_EXECUTABLE "${Python3_EXECUTABLE}") +endif() + set(dotest_args_replacement ${LLVM_BUILD_MODE}) if(LLDB_BUILT_STANDALONE) diff --git a/lldb/test/API/lit.site.cfg.py.in b/lldb/test/API/lit.site.cfg.py.in index ecebc44774859..54807de8819d2 100644 --- a/lldb/test/API/lit.site.cfg.py.in +++ b/lldb/test/API/lit.site.cfg.py.in @@ -19,7 +19,7 @@ config.shared_libs = @LLVM_ENABLE_SHARED_LIBS@ config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@" config.target_triple = "@LLVM_TARGET_TRIPLE@" config.lldb_build_directory = "@LLDB_TEST_BUILD_DIRECTORY@" -config.python_executable = "@Python3_EXECUTABLE@" +config.python_executable = "@LLDB_PYTHON_API_TEST_EXECUTABLE@" config.lua_executable = "@LUA_EXECUTABLE@" config.lldb_lua_cpath = "@LLDB_LUA_CPATH@" config.lua_test_entry = "TestLuaAPI.py" From lldb-commits at lists.llvm.org Sun May 18 01:10:50 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sun, 18 May 2025 01:10:50 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Suppport testing with debug-python on Windows (PR #140443) In-Reply-To: Message-ID: <6829960a.630a0220.29c3e1.fca1@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: nerix (Nerixyz)
Changes When trying to run the LLDB API tests on Windows with a debug configuration, they fail, because the `_lldb` module won't be found. As explained in https://github.com/llvm/llvm-project/issues/51272, this is because lit will run the test with `python.exe` but the module is built for the debug version of python, `python_d.exe`. CMake already resolved the debug executable in `Python3_EXECUTABLE_DEBUG`, so this PR changes the `config.python_executable` to point to `python_d.exe` on Windows in debug mode. The check is equivalent to the one done in the top-level LLDB CMakeLists [when setting the python suffix](https://github.com/llvm/llvm-project/blob/3ccb15d6caf57f2a866d496ada2fb52d14b179d2/lldb/CMakeLists.txt#L79-L86). --- Full diff: https://github.com/llvm/llvm-project/pull/140443.diff 2 Files Affected: - (modified) lldb/test/API/CMakeLists.txt (+6) - (modified) lldb/test/API/lit.site.cfg.py.in (+1-1) ``````````diff diff --git a/lldb/test/API/CMakeLists.txt b/lldb/test/API/CMakeLists.txt index da51f2252d023..b1ace6296f46a 100644 --- a/lldb/test/API/CMakeLists.txt +++ b/lldb/test/API/CMakeLists.txt @@ -139,6 +139,12 @@ if(CMAKE_HOST_APPLE) endif() endif() +if(WIN32 AND CMAKE_BUILD_TYPE STREQUAL Debug) + set(LLDB_PYTHON_API_TEST_EXECUTABLE "${Python3_EXECUTABLE_DEBUG}") +else() + set(LLDB_PYTHON_API_TEST_EXECUTABLE "${Python3_EXECUTABLE}") +endif() + set(dotest_args_replacement ${LLVM_BUILD_MODE}) if(LLDB_BUILT_STANDALONE) diff --git a/lldb/test/API/lit.site.cfg.py.in b/lldb/test/API/lit.site.cfg.py.in index ecebc44774859..54807de8819d2 100644 --- a/lldb/test/API/lit.site.cfg.py.in +++ b/lldb/test/API/lit.site.cfg.py.in @@ -19,7 +19,7 @@ config.shared_libs = @LLVM_ENABLE_SHARED_LIBS@ config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@" config.target_triple = "@LLVM_TARGET_TRIPLE@" config.lldb_build_directory = "@LLDB_TEST_BUILD_DIRECTORY@" -config.python_executable = "@Python3_EXECUTABLE@" +config.python_executable = "@LLDB_PYTHON_API_TEST_EXECUTABLE@" config.lua_executable = "@LUA_EXECUTABLE@" config.lldb_lua_cpath = "@LLDB_LUA_CPATH@" config.lua_test_entry = "TestLuaAPI.py" ``````````
https://github.com/llvm/llvm-project/pull/140443 From lldb-commits at lists.llvm.org Sun May 18 01:29:59 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 01:29:59 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68299a87.170a0220.2744fe.bf77@mx.google.com> ================ @@ -53,6 +54,8 @@ class LLDB_API SBFileSpec { uint32_t GetPath(char *dst_path, size_t dst_len) const; + bool GetPath(lldb::SBStream &dst_path) const; ---------------- eronnen wrote: makes sense, I was trying to avoid the potential problem of the path being longer than `MAX_PATH` but it's still possible to get the real size using `GetFilename` and `GetDirectory` https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sun May 18 01:30:09 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 01:30:09 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68299a91.a70a0220.fe66a.c0a3@mx.google.com> ================ @@ -219,6 +221,9 @@ struct DAP { llvm::StringSet<> modules; /// @} + /// Number of lines of assembly code to show when no debug info is available. + uint32_t number_of_assembly_lines_for_nodebug = 32; ---------------- eronnen wrote: :100: https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sun May 18 01:36:14 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 01:36:14 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68299bfe.170a0220.267a4.a3d3@mx.google.com> ================ @@ -71,22 +101,26 @@ BreakpointLocationsRequestHandler::Run( locations.emplace_back(line, column); } } +} - // The line entries are sorted by addresses, but we must return the list - // ordered by line / column position. - std::sort(locations.begin(), locations.end()); - locations.erase(llvm::unique(locations), locations.end()); +template +void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, ---------------- eronnen wrote: Agreem chganged to return `std::vector` https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sun May 18 01:37:44 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 01:37:44 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68299c58.a70a0220.9e00b.c1c2@mx.google.com> ================ @@ -73,7 +87,64 @@ SetBreakpointsRequestHandler::Run( } } - return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; + return response_breakpoints; +} + +std::vector +SetBreakpointsRequestHandler::SetAssemblyBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints) + const { + std::vector response_breakpoints; + int64_t sourceReference = source.sourceReference.value_or(0); + + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) + return response_breakpoints; + + lldb::SBSymbol symbol = address.GetSymbol(); + if (!symbol.IsValid()) + return response_breakpoints; // Not yet supporting breakpoints in assembly + // without a valid symbol ---------------- eronnen wrote: :100: https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sun May 18 01:38:16 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 01:38:16 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68299c78.630a0220.3ae16.dc69@mx.google.com> ================ @@ -73,7 +87,64 @@ SetBreakpointsRequestHandler::Run( } } - return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; + return response_breakpoints; +} + +std::vector +SetBreakpointsRequestHandler::SetAssemblyBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints) + const { + std::vector response_breakpoints; + int64_t sourceReference = source.sourceReference.value_or(0); + + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) + return response_breakpoints; + + lldb::SBSymbol symbol = address.GetSymbol(); + if (!symbol.IsValid()) + return response_breakpoints; // Not yet supporting breakpoints in assembly + // without a valid symbol + + llvm::DenseMap request_bps; + if (breakpoints) { + for (const auto &bp : *breakpoints) { + SourceBreakpoint src_bp(dap, bp); + request_bps.try_emplace(src_bp.GetLine(), src_bp); + const auto [iv, inserted] = + dap.assembly_breakpoints[sourceReference].try_emplace( + src_bp.GetLine(), src_bp); + // We check if this breakpoint already exists to update it ---------------- eronnen wrote: :100: https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sun May 18 01:38:35 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 01:38:35 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68299c8b.170a0220.20cd50.ad18@mx.google.com> ================ @@ -19,19 +18,50 @@ namespace lldb_dap { llvm::Expected BreakpointLocationsRequestHandler::Run( const protocol::BreakpointLocationsArguments &args) const { - std::string path = args.source.path.value_or(""); uint32_t start_line = args.line; uint32_t start_column = args.column.value_or(LLDB_INVALID_COLUMN_NUMBER); uint32_t end_line = args.endLine.value_or(start_line); uint32_t end_column = args.endColumn.value_or(std::numeric_limits::max()); + // Find all relevant lines & columns ---------------- eronnen wrote: :100: https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sun May 18 01:39:42 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 01:39:42 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68299cce.050a0220.f2722.b6ce@mx.google.com> ================ @@ -19,19 +18,50 @@ namespace lldb_dap { llvm::Expected BreakpointLocationsRequestHandler::Run( const protocol::BreakpointLocationsArguments &args) const { - std::string path = args.source.path.value_or(""); uint32_t start_line = args.line; uint32_t start_column = args.column.value_or(LLDB_INVALID_COLUMN_NUMBER); uint32_t end_line = args.endLine.value_or(start_line); uint32_t end_column = args.endColumn.value_or(std::numeric_limits::max()); + // Find all relevant lines & columns + llvm::SmallVector, 8> locations; + if (args.source.sourceReference) { + AddAssemblyBreakpointLocations(locations, *args.source.sourceReference, + start_line, end_line); + } else { + std::string path = args.source.path.value_or(""); + AddSourceBreakpointLocations(locations, std::move(path), start_line, + start_column, end_line, end_column); + } + + // The line entries are sorted by addresses, but we must return the list + // ordered by line / column position. + std::sort(locations.begin(), locations.end()); + locations.erase(llvm::unique(locations), locations.end()); + + std::vector breakpoint_locations; + for (auto &l : locations) { + protocol::BreakpointLocation lc; + lc.line = l.first; + lc.column = l.second; + breakpoint_locations.push_back(std::move(lc)); + } ---------------- eronnen wrote: :100: https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sun May 18 01:53:16 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 01:53:16 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <68299ffc.050a0220.34f28d.b4ea@mx.google.com> https://github.com/eronnen edited https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sun May 18 04:40:00 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 04:40:00 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <6829c710.a70a0220.1fec6a.b412@mx.google.com> https://github.com/eronnen updated https://github.com/llvm/llvm-project/pull/139969 >From d6325b3f6a8602fc96ad72acecfcccda1120614d Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sat, 10 May 2025 20:45:17 +0200 Subject: [PATCH 01/10] support assembly in BreakpointLocationsRequestHandler --- .../breakpoint/TestDAP_setBreakpoints.py | 1 - .../TestDAP_setExceptionBreakpoints.py | 1 - .../TestDAP_setFunctionBreakpoints.py | 1 - lldb/tools/lldb-dap/DAP.h | 3 + .../Handler/BreakpointLocationsHandler.cpp | 77 +++++++++++++++---- lldb/tools/lldb-dap/Handler/RequestHandler.h | 11 +++ .../lldb-dap/Handler/SourceRequestHandler.cpp | 4 +- 7 files changed, 76 insertions(+), 22 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index aae1251b17c93..26df2573555df 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,7 +12,6 @@ import os - at skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py index 4dc8c5b3c7ded..92ac66cd44c5d 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setExceptionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_functionality(self): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index baaca4d974d5d..946595f639edc 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 8f24c6cf82924..00aa4276852c5 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -219,6 +219,9 @@ struct DAP { llvm::StringSet<> modules; /// @} + /// Number of lines of assembly code to show when no debug info is available. + uint32_t number_of_assembly_lines_for_nodebug = 32; + /// Creates a new DAP sessions. /// /// \param[in] log diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 2ac886c3a5d2c..9eea549d72b00 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "JSONUtils.h" +#include "LLDBUtils.h" #include "RequestHandler.h" #include @@ -19,19 +19,50 @@ namespace lldb_dap { llvm::Expected BreakpointLocationsRequestHandler::Run( const protocol::BreakpointLocationsArguments &args) const { - std::string path = args.source.path.value_or(""); uint32_t start_line = args.line; uint32_t start_column = args.column.value_or(LLDB_INVALID_COLUMN_NUMBER); uint32_t end_line = args.endLine.value_or(start_line); uint32_t end_column = args.endColumn.value_or(std::numeric_limits::max()); + // Find all relevant lines & columns + llvm::SmallVector, 8> locations; + if (args.source.sourceReference) { + AddAssemblyBreakpointLocations(locations, *args.source.sourceReference, + start_line, end_line); + } else { + std::string path = args.source.path.value_or(""); + AddSourceBreakpointLocations(locations, std::move(path), start_line, + start_column, end_line, end_column); + } + + // The line entries are sorted by addresses, but we must return the list + // ordered by line / column position. + std::sort(locations.begin(), locations.end()); + locations.erase(llvm::unique(locations), locations.end()); + + std::vector breakpoint_locations; + for (auto &l : locations) { + protocol::BreakpointLocation lc; + lc.line = l.first; + lc.column = l.second; + breakpoint_locations.push_back(std::move(lc)); + } + + return protocol::BreakpointLocationsResponseBody{ + /*breakpoints=*/std::move(breakpoint_locations)}; +} + +template +void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const { + lldb::SBFileSpec file_spec(path.c_str(), true); lldb::SBSymbolContextList compile_units = dap.target.FindCompileUnits(file_spec); - // Find all relevant lines & columns - llvm::SmallVector, 8> locations; for (uint32_t c_idx = 0, c_limit = compile_units.GetSize(); c_idx < c_limit; ++c_idx) { const lldb::SBCompileUnit &compile_unit = @@ -71,22 +102,34 @@ BreakpointLocationsRequestHandler::Run( locations.emplace_back(line, column); } } +} - // The line entries are sorted by addresses, but we must return the list - // ordered by line / column position. - std::sort(locations.begin(), locations.end()); - locations.erase(llvm::unique(locations), locations.end()); +template +void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { + lldb::SBProcess process = dap.target.GetProcess(); + lldb::SBThread thread = + process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); + lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - std::vector breakpoint_locations; - for (auto &l : locations) { - protocol::BreakpointLocation lc; - lc.line = l.first; - lc.column = l.second; - breakpoint_locations.push_back(std::move(lc)); - } + if (!frame.IsValid()) + return; - return protocol::BreakpointLocationsResponseBody{ - /*breakpoints=*/std::move(breakpoint_locations)}; + lldb::SBSymbol symbol = frame.GetSymbol(); + if (symbol.IsValid()) { + lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); + } + } else { + for (uint32_t i = start_line - 1; + i < dap.number_of_assembly_lines_for_nodebug && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); + } + } } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index e6bccfe12f402..21753bc0552f9 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -16,6 +16,7 @@ #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/JSON.h" @@ -232,6 +233,16 @@ class BreakpointLocationsRequestHandler } llvm::Expected Run(const protocol::BreakpointLocationsArguments &args) const override; + + template + void AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const; + template + void AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const; }; class CompletionsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp index 0ddd87881a164..fb396a3dc8862 100644 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp @@ -52,8 +52,8 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { insts.GetDescription(stream, exe_ctx); } else { // No valid symbol, just return the disassembly. - lldb::SBInstructionList insts = - dap.target.ReadInstructions(frame.GetPCAddress(), 32); + lldb::SBInstructionList insts = dap.target.ReadInstructions( + frame.GetPCAddress(), dap.number_of_assembly_lines_for_nodebug); insts.GetDescription(stream, exe_ctx); } >From ee492031bee8106fb2a4ff22a8563005f5afd86c Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 11 May 2025 19:49:03 +0200 Subject: [PATCH 02/10] support assembly in SetBreakpointsRequestHandler --- lldb/tools/lldb-dap/DAP.h | 1 + .../Handler/BreakpointLocationsHandler.cpp | 20 ++--- lldb/tools/lldb-dap/Handler/RequestHandler.h | 9 ++ .../Handler/SetBreakpointsRequestHandler.cpp | 90 ++++++++++++++++++- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 22 +++++ lldb/tools/lldb-dap/SourceBreakpoint.h | 1 + 6 files changed, 127 insertions(+), 16 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 00aa4276852c5..5ce0e534611c1 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -169,6 +169,7 @@ struct DAP { Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; + llvm::DenseMap assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 9eea549d72b00..be02c47056310 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -117,18 +117,14 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( return; lldb::SBSymbol symbol = frame.GetSymbol(); - if (symbol.IsValid()) { - lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); - ++i) { - locations.emplace_back(i, 0); - } - } else { - for (uint32_t i = start_line - 1; - i < dap.number_of_assembly_lines_for_nodebug && i < (end_line - 1); - ++i) { - locations.emplace_back(i, 0); - } + if (!symbol.IsValid()) + return; + + // start_line is relative to the symbol's start address + lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); } } diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 21753bc0552f9..72843aaef8150 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -389,6 +389,15 @@ class SetBreakpointsRequestHandler } llvm::Expected Run(const protocol::SetBreakpointsArguments &args) const override; + + std::vector SetSourceBreakpoints( + const std::string &path, + const std::optional> &breakpoints) + const; + std::vector SetAssemblyBreakpoints( + int64_t sourceReference, + const std::optional> &breakpoints) + const; }; class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 86e090b66afe9..71f9e5578ef08 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -9,8 +9,11 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" +#include +#include #include namespace lldb_dap { @@ -23,15 +26,30 @@ llvm::Expected SetBreakpointsRequestHandler::Run( const protocol::SetBreakpointsArguments &args) const { const auto &source = args.source; - const auto path = source.path.value_or(""); + std::vector response_breakpoints; + if (source.sourceReference) + response_breakpoints = SetAssemblyBreakpoints( + source.sourceReference.value(), args.breakpoints); + else if (source.path) + response_breakpoints = + SetSourceBreakpoints(source.path.value(), args.breakpoints); + + return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; +} + +std::vector +SetBreakpointsRequestHandler::SetSourceBreakpoints( + const std::string &path, + const std::optional> &breakpoints) + const { std::vector response_breakpoints; // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; // "breakpoints" may be unset, in which case we treat it the same as being set // to an empty array. - if (args.breakpoints) { - for (const auto &bp : *args.breakpoints) { + if (breakpoints) { + for (const auto &bp : *breakpoints) { SourceBreakpoint src_bp(dap, bp); std::pair bp_pos(src_bp.GetLine(), src_bp.GetColumn()); @@ -73,7 +91,71 @@ SetBreakpointsRequestHandler::Run( } } - return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; + return response_breakpoints; +} + +std::vector +SetBreakpointsRequestHandler::SetAssemblyBreakpoints( + int64_t sourceReference, + const std::optional> &breakpoints) + const { + std::vector response_breakpoints; + + lldb::SBProcess process = dap.target.GetProcess(); + lldb::SBThread thread = + process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); + lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); + + if (!frame.IsValid()) + return response_breakpoints; + + lldb::SBSymbol symbol = frame.GetSymbol(); + if (!symbol.IsValid()) + return response_breakpoints; // Not yet supporting breakpoints in assembly + // without a valid symbol + + SourceBreakpointMap request_bps; + if (breakpoints) { + for (const auto &bp : *breakpoints) { + SourceBreakpoint src_bp(dap, bp); + std::pair bp_pos(src_bp.GetLine(), 0); + request_bps.try_emplace(bp_pos, src_bp); + const auto [iv, inserted] = + dap.assembly_breakpoints[sourceReference].try_emplace(bp_pos, src_bp); + // We check if this breakpoint already exists to update it + if (inserted) + iv->getSecond().SetBreakpoint(symbol); + else + iv->getSecond().UpdateBreakpoint(src_bp); + + protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); + protocol::Source source; + source.sourceReference = sourceReference; + source.name = symbol.GetName(); + response_bp.source = std::move(source); + + if (!response_bp.line) + response_bp.line = src_bp.GetLine(); + if (!response_bp.column) + response_bp.column = src_bp.GetColumn(); + response_breakpoints.push_back(response_bp); + } + } + + // Delete existing breakpoints for this sourceReference that are not in the + // request_bps set. + auto old_src_bp_pos = dap.assembly_breakpoints.find(sourceReference); + if (old_src_bp_pos != dap.assembly_breakpoints.end()) { + for (auto &old_bp : old_src_bp_pos->second) { + auto request_pos = request_bps.find(old_bp.first); + if (request_pos == request_bps.end()) { + dap.target.BreakpointDelete(old_bp.second.GetID()); + old_src_bp_pos->second.erase(old_bp.first); + } + } + } + + return response_breakpoints; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 4581c995b4260..938b8fb8bcdda 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -13,7 +13,9 @@ #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBFileSpecList.h" #include "lldb/API/SBFrame.h" +#include "lldb/API/SBInstruction.h" #include "lldb/API/SBMutex.h" +#include "lldb/API/SBSymbol.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" #include "lldb/API/SBValue.h" @@ -45,6 +47,26 @@ void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) { Breakpoint::SetBreakpoint(); } +void SourceBreakpoint::SetBreakpoint(lldb::SBSymbol &symbol) { + lldb::SBMutex lock = m_dap.GetAPIMutex(); + std::lock_guard guard(lock); + + if (m_line == 0) + return; + + lldb::SBInstructionList inst_list = + m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); + if (inst_list.GetSize() < m_line) + return; + lldb::SBAddress address = + inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + + m_bp = m_dap.target.BreakpointCreateBySBAddress(address); + if (!m_log_message.empty()) + SetLogMessage(); + Breakpoint::SetBreakpoint(); +} + void SourceBreakpoint::UpdateBreakpoint(const SourceBreakpoint &request_bp) { if (m_log_message != request_bp.m_log_message) { m_log_message = request_bp.m_log_message; diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h index 5b15296f861c5..8589800e50983 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.h +++ b/lldb/tools/lldb-dap/SourceBreakpoint.h @@ -26,6 +26,7 @@ class SourceBreakpoint : public Breakpoint { // Set this breakpoint in LLDB as a new breakpoint void SetBreakpoint(const llvm::StringRef source_path); + void SetBreakpoint(lldb::SBSymbol &symbol); void UpdateBreakpoint(const SourceBreakpoint &request_bp); void SetLogMessage(); >From dbb2f9bd55b3f86247e03b2610fca9576e124637 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Wed, 14 May 2025 23:51:41 +0200 Subject: [PATCH 03/10] fix resolving of assembly source breakpoints --- lldb/tools/lldb-dap/Breakpoint.cpp | 45 ++++++++++++++++--- lldb/tools/lldb-dap/DAP.h | 3 +- .../Handler/BreakpointLocationsHandler.cpp | 4 +- lldb/tools/lldb-dap/Handler/RequestHandler.h | 4 +- .../Handler/SetBreakpointsRequestHandler.cpp | 30 ++++++------- lldb/tools/lldb-dap/package-lock.json | 4 +- lldb/tools/lldb-dap/package.json | 5 ++- 7 files changed, 63 insertions(+), 32 deletions(-) diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 26d633d1d172e..87fcd15b0a568 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -9,10 +9,12 @@ #include "Breakpoint.h" #include "DAP.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "lldb/API/SBAddress.h" #include "lldb/API/SBBreakpointLocation.h" #include "lldb/API/SBLineEntry.h" #include "lldb/API/SBMutex.h" +#include "lldb/lldb-enumerations.h" #include "llvm/ADT/StringExtras.h" #include #include @@ -63,14 +65,43 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { std::string formatted_addr = "0x" + llvm::utohexstr(bp_addr.GetLoadAddress(m_bp.GetTarget())); breakpoint.instructionReference = formatted_addr; + + lldb::StopDisassemblyType stop_disassembly_display = + GetStopDisassemblyDisplay(m_dap.debugger); auto line_entry = bp_addr.GetLineEntry(); - const auto line = line_entry.GetLine(); - if (line != UINT32_MAX) - breakpoint.line = line; - const auto column = line_entry.GetColumn(); - if (column != 0) - breakpoint.column = column; - breakpoint.source = CreateSource(line_entry); + if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) { + const auto line = line_entry.GetLine(); + if (line != UINT32_MAX) + breakpoint.line = line; + const auto column = line_entry.GetColumn(); + if (column != 0) + breakpoint.column = column; + breakpoint.source = CreateSource(line_entry); + } else { + // Breakpoint made by assembly + auto symbol_context = bp_addr.GetSymbolContext( + lldb::eSymbolContextSymbol | lldb::eSymbolContextModule); + if (symbol_context.IsValid()) { + auto symbol = symbol_context.GetSymbol(); + breakpoint.line = + m_bp.GetTarget() + .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) + .GetSize() + + 1; + protocol::Source source; + source.name = symbol.GetName(); + + auto module = symbol_context.GetModule(); + if (module.IsValid()) { + std::string path = module.GetFileSpec().GetDirectory(); + path += "/"; + path += module.GetFileSpec().GetFilename(); + source.path = std::move(path); + } + + breakpoint.source = std::move(source); + } + } } return breakpoint; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 5ce0e534611c1..b0fe265b7bca1 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -169,7 +169,8 @@ struct DAP { Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; - llvm::DenseMap assembly_breakpoints; + llvm::DenseMap> + assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index be02c47056310..06ada47a6f27f 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -122,9 +122,9 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( // start_line is relative to the symbol's start address lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i <= (end_line - 1); ++i) { - locations.emplace_back(i, 0); + locations.emplace_back(i, 1); } } diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 72843aaef8150..80898d1ee5ef1 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -391,11 +391,11 @@ class SetBreakpointsRequestHandler Run(const protocol::SetBreakpointsArguments &args) const override; std::vector SetSourceBreakpoints( - const std::string &path, + const protocol::Source &source, const std::optional> &breakpoints) const; std::vector SetAssemblyBreakpoints( - int64_t sourceReference, + const protocol::Source &source, const std::optional> &breakpoints) const; }; diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 71f9e5578ef08..4fefd8b440c7d 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -28,21 +28,20 @@ SetBreakpointsRequestHandler::Run( const auto &source = args.source; std::vector response_breakpoints; if (source.sourceReference) - response_breakpoints = SetAssemblyBreakpoints( - source.sourceReference.value(), args.breakpoints); + response_breakpoints = SetAssemblyBreakpoints(source, args.breakpoints); else if (source.path) - response_breakpoints = - SetSourceBreakpoints(source.path.value(), args.breakpoints); + response_breakpoints = SetSourceBreakpoints(source, args.breakpoints); return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; } std::vector SetBreakpointsRequestHandler::SetSourceBreakpoints( - const std::string &path, + const protocol::Source &source, const std::optional> &breakpoints) const { std::vector response_breakpoints; + std::string path = source.path.value_or(""); // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; @@ -96,10 +95,11 @@ SetBreakpointsRequestHandler::SetSourceBreakpoints( std::vector SetBreakpointsRequestHandler::SetAssemblyBreakpoints( - int64_t sourceReference, + const protocol::Source &source, const std::optional> &breakpoints) const { std::vector response_breakpoints; + int64_t sourceReference = source.sourceReference.value_or(0); lldb::SBProcess process = dap.target.GetProcess(); lldb::SBThread thread = @@ -114,14 +114,14 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( return response_breakpoints; // Not yet supporting breakpoints in assembly // without a valid symbol - SourceBreakpointMap request_bps; + llvm::DenseMap request_bps; if (breakpoints) { for (const auto &bp : *breakpoints) { SourceBreakpoint src_bp(dap, bp); - std::pair bp_pos(src_bp.GetLine(), 0); - request_bps.try_emplace(bp_pos, src_bp); + request_bps.try_emplace(src_bp.GetLine(), src_bp); const auto [iv, inserted] = - dap.assembly_breakpoints[sourceReference].try_emplace(bp_pos, src_bp); + dap.assembly_breakpoints[sourceReference].try_emplace( + src_bp.GetLine(), src_bp); // We check if this breakpoint already exists to update it if (inserted) iv->getSecond().SetBreakpoint(symbol); @@ -129,15 +129,11 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( iv->getSecond().UpdateBreakpoint(src_bp); protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - protocol::Source source; - source.sourceReference = sourceReference; - source.name = symbol.GetName(); - response_bp.source = std::move(source); - + response_bp.source = source; if (!response_bp.line) response_bp.line = src_bp.GetLine(); - if (!response_bp.column) - response_bp.column = src_bp.GetColumn(); + if (bp.column) + response_bp.column = *bp.column; response_breakpoints.push_back(response_bp); } } diff --git a/lldb/tools/lldb-dap/package-lock.json b/lldb/tools/lldb-dap/package-lock.json index 0a2b9e764067e..af90a9573aee6 100644 --- a/lldb/tools/lldb-dap/package-lock.json +++ b/lldb/tools/lldb-dap/package-lock.json @@ -1,12 +1,12 @@ { "name": "lldb-dap", - "version": "0.2.13", + "version": "0.2.14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lldb-dap", - "version": "0.2.13", + "version": "0.2.14", "license": "Apache 2.0 License with LLVM exceptions", "devDependencies": { "@types/node": "^18.19.41", diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index d5ca604798799..73e70cd961f4f 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -1,7 +1,7 @@ { "name": "lldb-dap", "displayName": "LLDB DAP", - "version": "0.2.13", + "version": "0.2.14", "publisher": "llvm-vs-code-extensions", "homepage": "https://lldb.llvm.org", "description": "Debugging with LLDB in Visual Studio Code", @@ -265,6 +265,9 @@ ] }, "breakpoints": [ + { + "language": "lldb.disassembly" + }, { "language": "ada" }, >From 3699524618ed76f969cc26a63610fe54e3605139 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Thu, 15 May 2025 00:36:10 +0200 Subject: [PATCH 04/10] remove include --- lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 4fefd8b440c7d..d69da5bd02c1e 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -12,8 +12,6 @@ #include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" -#include -#include #include namespace lldb_dap { >From 61623deb7e249a8ca0c63e3f66955790da5e4ced Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sat, 17 May 2025 21:05:27 +0200 Subject: [PATCH 05/10] use load address as sourceReference --- lldb/include/lldb/API/SBFileSpec.h | 3 + lldb/source/API/SBFileSpec.cpp | 8 ++ lldb/tools/lldb-dap/Breakpoint.cpp | 18 +---- .../Handler/BreakpointLocationsHandler.cpp | 11 +-- .../Handler/SetBreakpointsRequestHandler.cpp | 11 +-- .../lldb-dap/Handler/SourceRequestHandler.cpp | 18 ++--- lldb/tools/lldb-dap/JSONUtils.cpp | 75 +++++++++++++------ lldb/tools/lldb-dap/JSONUtils.h | 14 ++++ 8 files changed, 96 insertions(+), 62 deletions(-) diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index 36641843aabeb..303cb7d712cbf 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -10,6 +10,7 @@ #define LLDB_API_SBFILESPEC_H #include "lldb/API/SBDefines.h" +#include "lldb/API/SBStream.h" namespace lldb { @@ -53,6 +54,8 @@ class LLDB_API SBFileSpec { uint32_t GetPath(char *dst_path, size_t dst_len) const; + bool GetPath(lldb::SBStream &dst_path) const; + static int ResolvePath(const char *src_path, char *dst_path, size_t dst_len); bool GetDescription(lldb::SBStream &description) const; diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp index a7df9afc4b8eb..cb44dac1d4fcc 100644 --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -19,6 +19,7 @@ #include #include +#include using namespace lldb; using namespace lldb_private; @@ -147,6 +148,13 @@ uint32_t SBFileSpec::GetPath(char *dst_path, size_t dst_len) const { return result; } +bool SBFileSpec::GetPath(SBStream &dst_path) const { + LLDB_INSTRUMENT_VA(this, dst_path); + + std::string path = m_opaque_up->GetPath(); + return dst_path->PutCString(path.c_str()) > 0; +} + const lldb_private::FileSpec *SBFileSpec::operator->() const { return m_opaque_up.get(); } diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 87fcd15b0a568..a54a34e0f936d 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -79,27 +79,15 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { breakpoint.source = CreateSource(line_entry); } else { // Breakpoint made by assembly - auto symbol_context = bp_addr.GetSymbolContext( - lldb::eSymbolContextSymbol | lldb::eSymbolContextModule); - if (symbol_context.IsValid()) { - auto symbol = symbol_context.GetSymbol(); + auto symbol = bp_addr.GetSymbol(); + if (symbol.IsValid()) { breakpoint.line = m_bp.GetTarget() .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) .GetSize() + 1; - protocol::Source source; - source.name = symbol.GetName(); - auto module = symbol_context.GetModule(); - if (module.IsValid()) { - std::string path = module.GetFileSpec().GetDirectory(); - path += "/"; - path += module.GetFileSpec().GetFilename(); - source.path = std::move(path); - } - - breakpoint.source = std::move(source); + breakpoint.source = CreateAssemblySource(m_dap.target, bp_addr); } } } diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 06ada47a6f27f..c4d658caeee2d 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "LLDBUtils.h" #include "RequestHandler.h" #include @@ -108,15 +107,11 @@ template void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( llvm::SmallVector, N> &locations, int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { - lldb::SBProcess process = dap.target.GetProcess(); - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - - if (!frame.IsValid()) + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) return; - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) return; diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index d69da5bd02c1e..7b401f06e9a85 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -9,7 +9,6 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" -#include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" #include @@ -99,15 +98,11 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( std::vector response_breakpoints; int64_t sourceReference = source.sourceReference.value_or(0); - lldb::SBProcess process = dap.target.GetProcess(); - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - - if (!frame.IsValid()) + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) return response_breakpoints; - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) return response_breakpoints; // Not yet supporting breakpoints in assembly // without a valid symbol diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp index fb396a3dc8862..9249e2aa6fef7 100644 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp @@ -11,6 +11,7 @@ #include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" +#include "lldb/API/SBAddress.h" #include "lldb/API/SBExecutionContext.h" #include "lldb/API/SBFrame.h" #include "lldb/API/SBInstructionList.h" @@ -19,6 +20,7 @@ #include "lldb/API/SBSymbol.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" +#include "lldb/lldb-types.h" #include "llvm/Support/Error.h" namespace lldb_dap { @@ -34,18 +36,14 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { return llvm::make_error( "invalid arguments, expected source.sourceReference to be set"); - lldb::SBProcess process = dap.target.GetProcess(); - // Upper 32 bits is the thread index ID - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(source)); - // Lower 32 bits is the frame index - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(source)); - if (!frame.IsValid()) + lldb::SBAddress address(source, dap.target); + if (!address.IsValid()) return llvm::make_error("source not found"); + lldb::SBSymbol symbol = address.GetSymbol(); + lldb::SBStream stream; - lldb::SBExecutionContext exe_ctx(frame); - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBExecutionContext exe_ctx(dap.target); if (symbol.IsValid()) { lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); @@ -53,7 +51,7 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { } else { // No valid symbol, just return the disassembly. lldb::SBInstructionList insts = dap.target.ReadInstructions( - frame.GetPCAddress(), dap.number_of_assembly_lines_for_nodebug); + address, dap.number_of_assembly_lines_for_nodebug); insts.GetDescription(stream, exe_ctx); } diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 714947a4d3b9c..c8151c3d64ea4 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -490,6 +490,13 @@ CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp) { return filter; } +static std::string GetLoadAddressString(const lldb::addr_t addr) { + std::string result; + llvm::raw_string_ostream os(result); + os << llvm::format_hex(addr, 18); + return result; +} + protocol::Source CreateSource(const lldb::SBFileSpec &file) { protocol::Source source; if (file.IsValid()) { @@ -516,6 +523,43 @@ protocol::Source CreateSource(llvm::StringRef source_path) { return source; } +protocol::Source CreateAssemblySource(const lldb::SBTarget &target, + lldb::SBAddress &address) { + protocol::Source source; + + auto symbol = address.GetSymbol(); + std::string name; + if (symbol.IsValid()) { + source.sourceReference = symbol.GetStartAddress().GetLoadAddress(target); + name = symbol.GetName(); + } else { + const auto load_addr = address.GetLoadAddress(target); + source.sourceReference = load_addr; + name = GetLoadAddressString(load_addr); + } + + lldb::SBModule module = address.GetModule(); + if (module.IsValid()) { + lldb::SBFileSpec file_spec = module.GetFileSpec(); + if (file_spec.IsValid()) { + lldb::SBStream module_path; + if (file_spec.GetPath(module_path)) { + std::string path = module_path.GetData(); + source.path = path + '`' + name; + } + } + } + + source.name = std::move(name); + + // Mark the source as deemphasized since users will only be able to view + // assembly for these frames. + source.presentationHint = + protocol::Source::PresentationHint::eSourcePresentationHintDeemphasize; + + return source; +} + bool ShouldDisplayAssemblySource( const lldb::SBLineEntry &line_entry, lldb::StopDisassemblyType stop_disassembly_display) { @@ -619,12 +663,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, frame_name = name; } - if (frame_name.empty()) { + if (frame_name.empty()) // If the function name is unavailable, display the pc address as a 16-digit // hex string, e.g. "0x0000000000012345" - llvm::raw_string_ostream os(frame_name); - os << llvm::format_hex(frame.GetPC(), 18); - } + frame_name = GetLoadAddressString(frame.GetPC()); // We only include `[opt]` if a custom frame format is not specified. if (!format && frame.GetFunction().GetIsOptimized()) @@ -641,17 +683,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, } else if (frame.GetSymbol().IsValid()) { // If no source is associated with the frame, use the DAPFrameID to track // the 'source' and generate assembly. - llvm::json::Object source; - EmplaceSafeString(source, "name", frame_name); - char buf[PATH_MAX] = {0}; - size_t size = frame.GetModule().GetFileSpec().GetPath(buf, PATH_MAX); - EmplaceSafeString(source, "path", - std::string(buf, size) + '`' + frame_name); - source.try_emplace("sourceReference", MakeDAPFrameID(frame)); - // Mark the source as deemphasized since users will only be able to view - // assembly for these frames. - EmplaceSafeString(source, "presentationHint", "deemphasize"); - object.try_emplace("source", std::move(source)); + auto frame_address = frame.GetPCAddress(); + object.try_emplace("source", CreateAssemblySource( + frame.GetThread().GetProcess().GetTarget(), + frame_address)); // Calculate the line of the current PC from the start of the current // symbol. @@ -665,12 +700,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, object.try_emplace("column", 1); } else { // No valid line entry or symbol. - llvm::json::Object source; - EmplaceSafeString(source, "name", frame_name); - source.try_emplace("sourceReference", MakeDAPFrameID(frame)); - EmplaceSafeString(source, "presentationHint", "deemphasize"); - object.try_emplace("source", std::move(source)); - + auto frame_address = frame.GetPCAddress(); + object.try_emplace("source", CreateAssemblySource( + frame.GetThread().GetProcess().GetTarget(), + frame_address)); object.try_emplace("line", 1); object.try_emplace("column", 1); } diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h index 783f291338d8c..ac9b39739104f 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -269,6 +269,20 @@ protocol::Source CreateSource(const lldb::SBLineEntry &line_entry); /// definition outlined by Microsoft. protocol::Source CreateSource(llvm::StringRef source_path); +/// Create a "Source" object for a given frame, using its assembly for source. +/// +/// \param[in] target +/// The relevant target. +/// +/// \param[in] address +/// The address to use when creating the "Source" object. +/// +/// \return +/// A "Source" JSON object that follows the formal JSON +/// definition outlined by Microsoft. +protocol::Source CreateAssemblySource(const lldb::SBTarget &target, + lldb::SBAddress &address); + /// Return true if the given line entry should be displayed as assembly. /// /// \param[in] line_entry >From f5fd76de3ad25b9cbf6ce065e06c98ff30b070a8 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 02:22:19 +0200 Subject: [PATCH 06/10] add breakpoint-assembly test --- .../test/tools/lldb-dap/dap_server.py | 7 ++++ .../test/tools/lldb-dap/lldbdap_testcase.py | 10 +++++ .../lldb-dap/breakpoint-assembly/Makefile | 3 ++ .../TestDAP_breakpointAssembly.py | 42 +++++++++++++++++++ .../tools/lldb-dap/breakpoint-assembly/main.c | 14 +++++++ .../breakpoint/TestDAP_setBreakpoints.py | 1 + .../TestDAP_setExceptionBreakpoints.py | 1 + .../TestDAP_setFunctionBreakpoints.py | 1 + 8 files changed, 79 insertions(+) create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index 70fd0b0c419db..4a907a5e36901 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -955,6 +955,13 @@ def request_setBreakpoints(self, file_path, line_array, data=None): """ (dir, base) = os.path.split(file_path) source_dict = {"name": base, "path": file_path} + return self.request_setBreakpoints_with_source(source_dict, line_array, data) + + def request_setBreakpointsAssembly(self, sourceReference, line_array, data=None): + source_dict = {"sourceReference": sourceReference} + return self.request_setBreakpoints_with_source(source_dict, line_array, data) + + def request_setBreakpoints_with_source(self, source_dict, line_array, data=None): args_dict = { "source": source_dict, "sourceModified": False, diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index afdc746ed0d0d..427f66a7da0c8 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -63,6 +63,16 @@ def set_source_breakpoints(self, source_path, lines, data=None): for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) return breakpoint_ids + + def set_source_breakpoints_assembly(self, source_reference, lines, data=None): + response = self.dap_server.request_setBreakpointsAssembly(source_reference, lines, data) + if response is None: + return [] + breakpoints = response["body"]["breakpoints"] + breakpoint_ids = [] + for breakpoint in breakpoints: + breakpoint_ids.append("%i" % (breakpoint["id"])) + return breakpoint_ids def set_function_breakpoints(self, functions, condition=None, hitCondition=None): """Sets breakpoints by function name given an array of function names diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile new file mode 100644 index 0000000000000..10495940055b6 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py new file mode 100644 index 0000000000000..ba9df3a18590b --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py @@ -0,0 +1,42 @@ +""" +Test lldb-dap setBreakpoints request +""" + + +import dap_server +import shutil +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +import lldbdap_testcase +import os + + +class TestDAP_setBreakpointsAssembly(lldbdap_testcase.DAPTestCaseBase): + # @skipIfWindows + def test_functionality(self): + """Tests hitting assembly source breakpoints""" + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + + self.dap_server.request_evaluate( + "`settings set stop-disassembly-display no-debuginfo", context="repl" + ) + + assmebly_func_breakpoints = self.set_function_breakpoints(["assembly_func"]) + self.continue_to_breakpoints(assmebly_func_breakpoints) + + assembly_func_frame = self.get_stackFrames()[0] + self.assertIn( + "sourceReference", + assembly_func_frame.get("source"), + "Expected assembly source frame", + ) + + line = assembly_func_frame["line"] + + # Set an assembly breakpoint in the next line and check that it's hit + assembly_breakpoint_ids = self.set_source_breakpoints_assembly( + assembly_func_frame["source"]["sourceReference"], [line + 1] + ) + self.continue_to_breakpoints(assembly_breakpoint_ids) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c new file mode 100644 index 0000000000000..350739006f903 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c @@ -0,0 +1,14 @@ +#include + +__attribute__((nodebug)) int assembly_func(int n) { + n += 1; + n += 2; + n += 3; + + return n; +} + +int main(int argc, char const *argv[]) { + assembly_func(10); + return 0; +} diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index 26df2573555df..aae1251b17c93 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,6 +12,7 @@ import os + at skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py index 92ac66cd44c5d..4dc8c5b3c7ded 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py @@ -10,6 +10,7 @@ import lldbdap_testcase + at skip("Temporarily disable the breakpoint tests") class TestDAP_setExceptionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_functionality(self): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index 946595f639edc..baaca4d974d5d 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,6 +10,7 @@ import lldbdap_testcase + at skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): >From 40f68e418bfbb6564b3834382c4a33a3104fc33d Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 10:23:11 +0200 Subject: [PATCH 07/10] python format --- .../lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index 427f66a7da0c8..3bf649a087fdb 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -63,9 +63,11 @@ def set_source_breakpoints(self, source_path, lines, data=None): for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) return breakpoint_ids - + def set_source_breakpoints_assembly(self, source_reference, lines, data=None): - response = self.dap_server.request_setBreakpointsAssembly(source_reference, lines, data) + response = self.dap_server.request_setBreakpointsAssembly( + source_reference, lines, data + ) if response is None: return [] breakpoints = response["body"]["breakpoints"] >From 199512fd7a0900d45070b95dd52ef5ef136e2719 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 10:54:43 +0200 Subject: [PATCH 08/10] restore SBFileSpec and fix assembly breakpoints CR --- lldb/include/lldb/API/SBFileSpec.h | 2 - lldb/source/API/SBFileSpec.cpp | 7 --- lldb/tools/lldb-dap/DAP.h | 2 +- .../Handler/BreakpointLocationsHandler.cpp | 47 ++++++++++--------- lldb/tools/lldb-dap/Handler/RequestHandler.h | 17 ++++--- .../Handler/SetBreakpointsRequestHandler.cpp | 9 ++-- lldb/tools/lldb-dap/JSONUtils.cpp | 6 +-- lldb/tools/lldb-dap/LLDBUtils.cpp | 10 ++++ lldb/tools/lldb-dap/LLDBUtils.h | 10 ++++ 9 files changed, 60 insertions(+), 50 deletions(-) diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index 303cb7d712cbf..1bb28b2ddab01 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -54,8 +54,6 @@ class LLDB_API SBFileSpec { uint32_t GetPath(char *dst_path, size_t dst_len) const; - bool GetPath(lldb::SBStream &dst_path) const; - static int ResolvePath(const char *src_path, char *dst_path, size_t dst_len); bool GetDescription(lldb::SBStream &description) const; diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp index cb44dac1d4fcc..f18857f59171a 100644 --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -148,13 +148,6 @@ uint32_t SBFileSpec::GetPath(char *dst_path, size_t dst_len) const { return result; } -bool SBFileSpec::GetPath(SBStream &dst_path) const { - LLDB_INSTRUMENT_VA(this, dst_path); - - std::string path = m_opaque_up->GetPath(); - return dst_path->PutCString(path.c_str()) > 0; -} - const lldb_private::FileSpec *SBFileSpec::operator->() const { return m_opaque_up.get(); } diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index b0fe265b7bca1..20f95be792f41 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -222,7 +222,7 @@ struct DAP { /// @} /// Number of lines of assembly code to show when no debug info is available. - uint32_t number_of_assembly_lines_for_nodebug = 32; + static constexpr uint32_t number_of_assembly_lines_for_nodebug = 32; /// Creates a new DAP sessions. /// diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index c4d658caeee2d..794b83a9e0e1e 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -8,6 +8,7 @@ #include "DAP.h" #include "RequestHandler.h" +#include #include namespace lldb_dap { @@ -24,15 +25,15 @@ BreakpointLocationsRequestHandler::Run( uint32_t end_column = args.endColumn.value_or(std::numeric_limits::max()); - // Find all relevant lines & columns - llvm::SmallVector, 8> locations; - if (args.source.sourceReference) { - AddAssemblyBreakpointLocations(locations, *args.source.sourceReference, - start_line, end_line); - } else { + // Find all relevant lines & columns. + std::vector> locations; + if (args.source.sourceReference) + locations = GetAssemblyBreakpointLocations(*args.source.sourceReference, + start_line, end_line); + else { std::string path = args.source.path.value_or(""); - AddSourceBreakpointLocations(locations, std::move(path), start_line, - start_column, end_line, end_column); + locations = GetSourceBreakpointLocations( + std::move(path), start_line, start_column, end_line, end_column); } // The line entries are sorted by addresses, but we must return the list @@ -41,23 +42,19 @@ BreakpointLocationsRequestHandler::Run( locations.erase(llvm::unique(locations), locations.end()); std::vector breakpoint_locations; - for (auto &l : locations) { - protocol::BreakpointLocation lc; - lc.line = l.first; - lc.column = l.second; - breakpoint_locations.push_back(std::move(lc)); - } + for (auto &l : locations) + breakpoint_locations.push_back( + {l.first, l.second, std::nullopt, std::nullopt}); return protocol::BreakpointLocationsResponseBody{ /*breakpoints=*/std::move(breakpoint_locations)}; } -template -void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( - llvm::SmallVector, N> &locations, +std::vector> +BreakpointLocationsRequestHandler::GetSourceBreakpointLocations( std::string path, uint32_t start_line, uint32_t start_column, uint32_t end_line, uint32_t end_column) const { - + std::vector> locations; lldb::SBFileSpec file_spec(path.c_str(), true); lldb::SBSymbolContextList compile_units = dap.target.FindCompileUnits(file_spec); @@ -101,19 +98,21 @@ void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( locations.emplace_back(line, column); } } + + return locations; } -template -void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( - llvm::SmallVector, N> &locations, +std::vector> +BreakpointLocationsRequestHandler::GetAssemblyBreakpointLocations( int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { + std::vector> locations; lldb::SBAddress address(sourceReference, dap.target); if (!address.IsValid()) - return; + return locations; lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) - return; + return locations; // start_line is relative to the symbol's start address lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); @@ -121,6 +120,8 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( ++i) { locations.emplace_back(i, 1); } + + return locations; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 80898d1ee5ef1..e708abb50d5c0 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -23,6 +23,7 @@ #include #include #include +#include template struct is_optional : std::false_type {}; @@ -234,15 +235,13 @@ class BreakpointLocationsRequestHandler llvm::Expected Run(const protocol::BreakpointLocationsArguments &args) const override; - template - void AddSourceBreakpointLocations( - llvm::SmallVector, N> &locations, - std::string path, uint32_t start_line, uint32_t start_column, - uint32_t end_line, uint32_t end_column) const; - template - void AddAssemblyBreakpointLocations( - llvm::SmallVector, N> &locations, - int64_t sourceReference, uint32_t start_line, uint32_t end_line) const; + std::vector> + GetSourceBreakpointLocations(std::string path, uint32_t start_line, + uint32_t start_column, uint32_t end_line, + uint32_t end_column) const; + std::vector> + GetAssemblyBreakpointLocations(int64_t sourceReference, uint32_t start_line, + uint32_t end_line) const; }; class CompletionsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 7b401f06e9a85..bf0b584753c07 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -103,9 +103,10 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( return response_breakpoints; lldb::SBSymbol symbol = address.GetSymbol(); - if (!symbol.IsValid()) - return response_breakpoints; // Not yet supporting breakpoints in assembly - // without a valid symbol + if (!symbol.IsValid()) { + // Not yet supporting breakpoints in assembly without a valid symbol. + return response_breakpoints; + } llvm::DenseMap request_bps; if (breakpoints) { @@ -115,7 +116,7 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( const auto [iv, inserted] = dap.assembly_breakpoints[sourceReference].try_emplace( src_bp.GetLine(), src_bp); - // We check if this breakpoint already exists to update it + // We check if this breakpoint already exists to update it. if (inserted) iv->getSecond().SetBreakpoint(symbol); else diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index c8151c3d64ea4..1d2a6ff60e502 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -542,11 +542,9 @@ protocol::Source CreateAssemblySource(const lldb::SBTarget &target, if (module.IsValid()) { lldb::SBFileSpec file_spec = module.GetFileSpec(); if (file_spec.IsValid()) { - lldb::SBStream module_path; - if (file_spec.GetPath(module_path)) { - std::string path = module_path.GetData(); + std::string path = GetSBFileSpecPath(file_spec); + if (!path.empty()) source.path = path + '`' + name; - } } } diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp index 0e7bb2b9058a7..3c7623ec1215d 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.cpp +++ b/lldb/tools/lldb-dap/LLDBUtils.cpp @@ -20,6 +20,7 @@ #include "llvm/Support/JSON.h" #include "llvm/Support/raw_ostream.h" +#include #include #include @@ -242,4 +243,13 @@ ScopeSyncMode::ScopeSyncMode(lldb::SBDebugger &debugger) ScopeSyncMode::~ScopeSyncMode() { m_debugger.SetAsync(m_async); } +std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec) { + const auto directory_length = ::strlen(file_spec.GetDirectory()); + const auto file_name_length = ::strlen(file_spec.GetFilename()); + + std::string path(directory_length + file_name_length + 2, '\0'); + file_spec.GetPath(path.data(), path.length()); + return path; +} + } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/LLDBUtils.h b/lldb/tools/lldb-dap/LLDBUtils.h index 711fc6051231c..7fdf4b859ee61 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.h +++ b/lldb/tools/lldb-dap/LLDBUtils.h @@ -13,6 +13,7 @@ #include "lldb/API/SBDebugger.h" #include "lldb/API/SBEnvironment.h" #include "lldb/API/SBError.h" +#include "lldb/API/SBFileSpec.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" @@ -161,6 +162,15 @@ uint32_t GetLLDBFrameID(uint64_t dap_frame_id); lldb::SBEnvironment GetEnvironmentFromArguments(const llvm::json::Object &arguments); +/// Gets an SBFileSpec and returns its path as a string. +/// +/// \param[in] file_spec +/// The file spec. +/// +/// \return +/// The file path as a string. +std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec); + /// Helper for sending telemetry to lldb server, if client-telemetry is enabled. class TelemetryDispatcher { public: >From dbad33b314bb59f6e0d22fd07dddb35e2a0e30d9 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 12:57:59 +0200 Subject: [PATCH 09/10] abstracted source breakpoints maps by DAP --- lldb/tools/lldb-dap/Breakpoint.cpp | 4 +- lldb/tools/lldb-dap/DAP.cpp | 75 +++++++++++ lldb/tools/lldb-dap/DAP.h | 29 +++- lldb/tools/lldb-dap/Handler/RequestHandler.h | 9 -- .../Handler/SetBreakpointsRequestHandler.cpp | 125 +----------------- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 54 +++++--- lldb/tools/lldb-dap/SourceBreakpoint.h | 7 +- 7 files changed, 140 insertions(+), 163 deletions(-) diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index a54a34e0f936d..fd7531f42c518 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -71,10 +71,10 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { auto line_entry = bp_addr.GetLineEntry(); if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) { const auto line = line_entry.GetLine(); - if (line != UINT32_MAX) + if (line != LLDB_INVALID_LINE_NUMBER) breakpoint.line = line; const auto column = line_entry.GetColumn(); - if (column != 0) + if (column != LLDB_INVALID_COLUMN_NUMBER) breakpoint.column = column; breakpoint.source = CreateSource(line_entry); } else { diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 0d5eba6c40961..1fe46fc619d73 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1620,6 +1620,81 @@ void DAP::EventThread() { } } +std::vector DAP::SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints) { + std::vector response_breakpoints; + if (source.sourceReference) { + // breakpoint set by assembly source. + auto &existing_breakpoints_pos = + m_source_assembly_breakpoints[*source.sourceReference]; + response_breakpoints = + SetSourceBreakpoints(source, breakpoints, existing_breakpoints_pos); + } else { + // breakpoint set by a regular source file. + const auto path = source.path.value_or(""); + auto &existing_breakpoints_pos = m_source_breakpoints[path]; + response_breakpoints = + SetSourceBreakpoints(source, breakpoints, existing_breakpoints_pos); + } + + return response_breakpoints; +} + +std::vector DAP::SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints, + SourceBreakpointMap &existing_breakpoints) { + std::vector response_breakpoints; + + SourceBreakpointMap request_breakpoints; + if (breakpoints) { + for (const auto &bp : *breakpoints) { + SourceBreakpoint src_bp(*this, bp, source); + std::pair bp_pos(src_bp.GetLine(), + src_bp.GetColumn()); + request_breakpoints.try_emplace(bp_pos, src_bp); + + const auto [iv, inserted] = + existing_breakpoints.try_emplace(bp_pos, src_bp); + // We check if this breakpoint already exists to update it. + if (inserted) + iv->second.SetBreakpoint(); + else + iv->second.UpdateBreakpoint(src_bp); + + protocol::Breakpoint response_breakpoint = + iv->second.ToProtocolBreakpoint(); + response_breakpoint.source = source; + + if (!response_breakpoint.line && + src_bp.GetLine() != LLDB_INVALID_LINE_NUMBER) + response_breakpoint.line = src_bp.GetLine(); + if (!response_breakpoint.column && + src_bp.GetColumn() != LLDB_INVALID_COLUMN_NUMBER) + response_breakpoint.column = src_bp.GetColumn(); + response_breakpoints.push_back(response_breakpoint); + } + } + + // Delete any breakpoints in this source file that aren't in the + // request_bps set. There is no call to remove breakpoints other than + // calling this function with a smaller or empty "breakpoints" list. + for (auto it = existing_breakpoints.begin(); + it != existing_breakpoints.end();) { + auto request_pos = request_breakpoints.find(it->first); + if (request_pos == request_breakpoints.end()) { + // This breakpoint no longer exists in this source file, delete it + target.BreakpointDelete(it->second.GetID()); + it = existing_breakpoints.erase(it); + } else { + ++it; + } + } + + return response_breakpoints; +} + void DAP::RegisterRequests() { RegisterRequest(); RegisterRequest(); diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 20f95be792f41..3a0a7fc1678ba 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -60,7 +60,7 @@ namespace lldb_dap { -typedef llvm::DenseMap, SourceBreakpoint> +typedef std::map, SourceBreakpoint> SourceBreakpointMap; typedef llvm::StringMap FunctionBreakpointMap; typedef llvm::DenseMap @@ -168,9 +168,6 @@ struct DAP { lldb::SBTarget target; Variables variables; lldb::SBBroadcaster broadcaster; - llvm::StringMap source_breakpoints; - llvm::DenseMap> - assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; @@ -428,7 +425,28 @@ struct DAP { void StartEventThread(); void StartProgressEventThread(); + /// Sets the given protocol `breakpoints` in the given `source`, while + /// removing any existing breakpoints in the given source if they are not in + /// `breakpoint`. + /// + /// \param[in] source + /// The relevant source of the breakpoints. + /// + /// \param[in] breakpoints + /// The breakpoints to set. + /// + /// \return a vector of the breakpoints that were set. + std::vector SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> + &breakpoints); + private: + std::vector SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints, + SourceBreakpointMap &existing_breakpoints); + /// Registration of request handler. /// @{ void RegisterRequests(); @@ -457,6 +475,9 @@ struct DAP { std::mutex m_active_request_mutex; const protocol::Request *m_active_request; + + llvm::StringMap m_source_breakpoints; + llvm::DenseMap m_source_assembly_breakpoints; }; } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index e708abb50d5c0..54f728414021e 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -388,15 +388,6 @@ class SetBreakpointsRequestHandler } llvm::Expected Run(const protocol::SetBreakpointsArguments &args) const override; - - std::vector SetSourceBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const; - std::vector SetAssemblyBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const; }; class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index bf0b584753c07..0ff88f62f8f51 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -22,130 +22,9 @@ namespace lldb_dap { llvm::Expected SetBreakpointsRequestHandler::Run( const protocol::SetBreakpointsArguments &args) const { - const auto &source = args.source; - std::vector response_breakpoints; - if (source.sourceReference) - response_breakpoints = SetAssemblyBreakpoints(source, args.breakpoints); - else if (source.path) - response_breakpoints = SetSourceBreakpoints(source, args.breakpoints); - + const auto response_breakpoints = + dap.SetSourceBreakpoints(args.source, args.breakpoints); return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; } -std::vector -SetBreakpointsRequestHandler::SetSourceBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const { - std::vector response_breakpoints; - std::string path = source.path.value_or(""); - - // Decode the source breakpoint infos for this "setBreakpoints" request - SourceBreakpointMap request_bps; - // "breakpoints" may be unset, in which case we treat it the same as being set - // to an empty array. - if (breakpoints) { - for (const auto &bp : *breakpoints) { - SourceBreakpoint src_bp(dap, bp); - std::pair bp_pos(src_bp.GetLine(), - src_bp.GetColumn()); - request_bps.try_emplace(bp_pos, src_bp); - const auto [iv, inserted] = - dap.source_breakpoints[path].try_emplace(bp_pos, src_bp); - // We check if this breakpoint already exists to update it - if (inserted) - iv->getSecond().SetBreakpoint(path.data()); - else - iv->getSecond().UpdateBreakpoint(src_bp); - - protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - - // Use the path from the request if it is set - if (!path.empty()) - response_bp.source = CreateSource(path); - - if (!response_bp.line) - response_bp.line = src_bp.GetLine(); - if (!response_bp.column) - response_bp.column = src_bp.GetColumn(); - response_breakpoints.push_back(response_bp); - } - } - - // Delete any breakpoints in this source file that aren't in the - // request_bps set. There is no call to remove breakpoints other than - // calling this function with a smaller or empty "breakpoints" list. - auto old_src_bp_pos = dap.source_breakpoints.find(path); - if (old_src_bp_pos != dap.source_breakpoints.end()) { - for (auto &old_bp : old_src_bp_pos->second) { - auto request_pos = request_bps.find(old_bp.first); - if (request_pos == request_bps.end()) { - // This breakpoint no longer exists in this source file, delete it - dap.target.BreakpointDelete(old_bp.second.GetID()); - old_src_bp_pos->second.erase(old_bp.first); - } - } - } - - return response_breakpoints; -} - -std::vector -SetBreakpointsRequestHandler::SetAssemblyBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const { - std::vector response_breakpoints; - int64_t sourceReference = source.sourceReference.value_or(0); - - lldb::SBAddress address(sourceReference, dap.target); - if (!address.IsValid()) - return response_breakpoints; - - lldb::SBSymbol symbol = address.GetSymbol(); - if (!symbol.IsValid()) { - // Not yet supporting breakpoints in assembly without a valid symbol. - return response_breakpoints; - } - - llvm::DenseMap request_bps; - if (breakpoints) { - for (const auto &bp : *breakpoints) { - SourceBreakpoint src_bp(dap, bp); - request_bps.try_emplace(src_bp.GetLine(), src_bp); - const auto [iv, inserted] = - dap.assembly_breakpoints[sourceReference].try_emplace( - src_bp.GetLine(), src_bp); - // We check if this breakpoint already exists to update it. - if (inserted) - iv->getSecond().SetBreakpoint(symbol); - else - iv->getSecond().UpdateBreakpoint(src_bp); - - protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - response_bp.source = source; - if (!response_bp.line) - response_bp.line = src_bp.GetLine(); - if (bp.column) - response_bp.column = *bp.column; - response_breakpoints.push_back(response_bp); - } - } - - // Delete existing breakpoints for this sourceReference that are not in the - // request_bps set. - auto old_src_bp_pos = dap.assembly_breakpoints.find(sourceReference); - if (old_src_bp_pos != dap.assembly_breakpoints.end()) { - for (auto &old_bp : old_src_bp_pos->second) { - auto request_pos = request_bps.find(old_bp.first); - if (request_pos == request_bps.end()) { - dap.target.BreakpointDelete(old_bp.second.GetID()); - old_src_bp_pos->second.erase(old_bp.first); - } - } - } - - return response_breakpoints; -} - } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 938b8fb8bcdda..50ebfbe8aef20 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -29,39 +29,49 @@ namespace lldb_dap { SourceBreakpoint::SourceBreakpoint(DAP &dap, - const protocol::SourceBreakpoint &breakpoint) + const protocol::SourceBreakpoint &breakpoint, + const protocol::Source &source) : Breakpoint(dap, breakpoint.condition, breakpoint.hitCondition), - m_log_message(breakpoint.logMessage.value_or("")), + m_log_message(breakpoint.logMessage.value_or("")), m_source(source), m_line(breakpoint.line), m_column(breakpoint.column.value_or(LLDB_INVALID_COLUMN_NUMBER)) {} -void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) { - lldb::SBMutex lock = m_dap.GetAPIMutex(); - std::lock_guard guard(lock); - - lldb::SBFileSpecList module_list; - m_bp = m_dap.target.BreakpointCreateByLocation( - source_path.str().c_str(), m_line, m_column, 0, module_list); - if (!m_log_message.empty()) - SetLogMessage(); - Breakpoint::SetBreakpoint(); -} - -void SourceBreakpoint::SetBreakpoint(lldb::SBSymbol &symbol) { +void SourceBreakpoint::SetBreakpoint() { lldb::SBMutex lock = m_dap.GetAPIMutex(); std::lock_guard guard(lock); if (m_line == 0) return; - lldb::SBInstructionList inst_list = - m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); - if (inst_list.GetSize() < m_line) - return; - lldb::SBAddress address = - inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + if (m_source.sourceReference) { + // breakpoint set by assembly source. + lldb::SBAddress source_address(*m_source.sourceReference, m_dap.target); + if (!source_address.IsValid()) + return; + + lldb::SBSymbol symbol = source_address.GetSymbol(); + if (!symbol.IsValid()) { + // Not yet supporting breakpoints in assembly without a valid symbol. + return; + } + + lldb::SBInstructionList inst_list = + m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); + if (inst_list.GetSize() < m_line) + return; + + lldb::SBAddress address = + inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + + m_bp = m_dap.target.BreakpointCreateBySBAddress(address); + } else { + // breakpoint set by a regular source file. + const auto source_path = m_source.path.value_or(""); + lldb::SBFileSpecList module_list; + m_bp = m_dap.target.BreakpointCreateByLocation(source_path.c_str(), m_line, + m_column, 0, module_list); + } - m_bp = m_dap.target.BreakpointCreateBySBAddress(address); if (!m_log_message.empty()) SetLogMessage(); Breakpoint::SetBreakpoint(); diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h index 8589800e50983..3221ecbf28ece 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.h +++ b/lldb/tools/lldb-dap/SourceBreakpoint.h @@ -22,11 +22,11 @@ namespace lldb_dap { class SourceBreakpoint : public Breakpoint { public: - SourceBreakpoint(DAP &d, const protocol::SourceBreakpoint &breakpoint); + SourceBreakpoint(DAP &d, const protocol::SourceBreakpoint &breakpoint, + const protocol::Source &source); // Set this breakpoint in LLDB as a new breakpoint - void SetBreakpoint(const llvm::StringRef source_path); - void SetBreakpoint(lldb::SBSymbol &symbol); + void SetBreakpoint(); void UpdateBreakpoint(const SourceBreakpoint &request_bp); void SetLogMessage(); @@ -63,6 +63,7 @@ class SourceBreakpoint : public Breakpoint { std::string m_log_message; std::vector m_log_message_parts; + protocol::Source m_source; /// The original breakpoint source. uint32_t m_line; ///< The source line of the breakpoint or logpoint uint32_t m_column; ///< An optional source column of the breakpoint }; >From 2e9edca37c0953e2d2a6cf2d278bb353f1e0960b Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 13:39:05 +0200 Subject: [PATCH 10/10] improve assembvly breakpoint test to check clear --- .../TestDAP_breakpointAssembly.py | 17 +++++++++++++++-- .../tools/lldb-dap/breakpoint-assembly/main.c | 4 +++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py index ba9df3a18590b..dacc1cd8349f1 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py @@ -6,7 +6,7 @@ import dap_server import shutil from lldbsuite.test.decorators import * -from lldbsuite.test.lldbtest import * +from lldbsuite.test.lldbtest import line_number from lldbsuite.test import lldbutil import lldbdap_testcase import os @@ -23,6 +23,9 @@ def test_functionality(self): "`settings set stop-disassembly-display no-debuginfo", context="repl" ) + finish_line = line_number("main.c", "// Break here") + finish_breakpoints = self.set_source_breakpoints("main.c", [finish_line]) + assmebly_func_breakpoints = self.set_function_breakpoints(["assembly_func"]) self.continue_to_breakpoints(assmebly_func_breakpoints) @@ -36,7 +39,17 @@ def test_functionality(self): line = assembly_func_frame["line"] # Set an assembly breakpoint in the next line and check that it's hit + source_reference = assembly_func_frame["source"]["sourceReference"] assembly_breakpoint_ids = self.set_source_breakpoints_assembly( - assembly_func_frame["source"]["sourceReference"], [line + 1] + source_reference, [line + 1] ) self.continue_to_breakpoints(assembly_breakpoint_ids) + + # Continue again and verify it hits in the next function call + self.continue_to_breakpoints(assmebly_func_breakpoints) + self.continue_to_breakpoints(assembly_breakpoint_ids) + + # Clear the breakpoint and then check that the assembly breakpoint does not hit next time + self.set_source_breakpoints_assembly(source_reference, []) + self.continue_to_breakpoints(assmebly_func_breakpoints) + self.continue_to_breakpoints(finish_breakpoints) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c index 350739006f903..e3a21df11958f 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c @@ -10,5 +10,7 @@ __attribute__((nodebug)) int assembly_func(int n) { int main(int argc, char const *argv[]) { assembly_func(10); - return 0; + assembly_func(20); + assembly_func(30); + return 0; // Break here } From lldb-commits at lists.llvm.org Sun May 18 04:44:46 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 04:44:46 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <6829c82e.170a0220.966cd.03a8@mx.google.com> ================ @@ -73,7 +87,64 @@ SetBreakpointsRequestHandler::Run( } } - return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; + return response_breakpoints; +} + +std::vector +SetBreakpointsRequestHandler::SetAssemblyBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints) + const { + std::vector response_breakpoints; + int64_t sourceReference = source.sourceReference.value_or(0); + + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) + return response_breakpoints; + + lldb::SBSymbol symbol = address.GetSymbol(); + if (!symbol.IsValid()) + return response_breakpoints; // Not yet supporting breakpoints in assembly + // without a valid symbol + + llvm::DenseMap request_bps; ---------------- eronnen wrote: Changes the implementation https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sun May 18 04:44:56 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 04:44:56 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <6829c838.170a0220.33cc7b.a68c@mx.google.com> https://github.com/eronnen edited https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sun May 18 04:46:00 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 04:46:00 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <6829c878.630a0220.221a3c.f874@mx.google.com> ================ @@ -73,7 +87,64 @@ SetBreakpointsRequestHandler::Run( } } - return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; + return response_breakpoints; +} + +std::vector +SetBreakpointsRequestHandler::SetAssemblyBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints) + const { + std::vector response_breakpoints; + int64_t sourceReference = source.sourceReference.value_or(0); + + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) + return response_breakpoints; + + lldb::SBSymbol symbol = address.GetSymbol(); + if (!symbol.IsValid()) + return response_breakpoints; // Not yet supporting breakpoints in assembly + // without a valid symbol + + llvm::DenseMap request_bps; + if (breakpoints) { + for (const auto &bp : *breakpoints) { + SourceBreakpoint src_bp(dap, bp); + request_bps.try_emplace(src_bp.GetLine(), src_bp); + const auto [iv, inserted] = + dap.assembly_breakpoints[sourceReference].try_emplace( ---------------- eronnen wrote: :100: Great idea, moved this implementation to a DAP function using the same function for both source and assembly breakpoints https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sun May 18 04:52:57 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 04:52:57 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <6829ca19.170a0220.111159.c8f4@mx.google.com> https://github.com/eronnen updated https://github.com/llvm/llvm-project/pull/139969 >From d6325b3f6a8602fc96ad72acecfcccda1120614d Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sat, 10 May 2025 20:45:17 +0200 Subject: [PATCH 01/11] support assembly in BreakpointLocationsRequestHandler --- .../breakpoint/TestDAP_setBreakpoints.py | 1 - .../TestDAP_setExceptionBreakpoints.py | 1 - .../TestDAP_setFunctionBreakpoints.py | 1 - lldb/tools/lldb-dap/DAP.h | 3 + .../Handler/BreakpointLocationsHandler.cpp | 77 +++++++++++++++---- lldb/tools/lldb-dap/Handler/RequestHandler.h | 11 +++ .../lldb-dap/Handler/SourceRequestHandler.cpp | 4 +- 7 files changed, 76 insertions(+), 22 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index aae1251b17c93..26df2573555df 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,7 +12,6 @@ import os - at skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py index 4dc8c5b3c7ded..92ac66cd44c5d 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setExceptionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_functionality(self): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index baaca4d974d5d..946595f639edc 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 8f24c6cf82924..00aa4276852c5 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -219,6 +219,9 @@ struct DAP { llvm::StringSet<> modules; /// @} + /// Number of lines of assembly code to show when no debug info is available. + uint32_t number_of_assembly_lines_for_nodebug = 32; + /// Creates a new DAP sessions. /// /// \param[in] log diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 2ac886c3a5d2c..9eea549d72b00 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "JSONUtils.h" +#include "LLDBUtils.h" #include "RequestHandler.h" #include @@ -19,19 +19,50 @@ namespace lldb_dap { llvm::Expected BreakpointLocationsRequestHandler::Run( const protocol::BreakpointLocationsArguments &args) const { - std::string path = args.source.path.value_or(""); uint32_t start_line = args.line; uint32_t start_column = args.column.value_or(LLDB_INVALID_COLUMN_NUMBER); uint32_t end_line = args.endLine.value_or(start_line); uint32_t end_column = args.endColumn.value_or(std::numeric_limits::max()); + // Find all relevant lines & columns + llvm::SmallVector, 8> locations; + if (args.source.sourceReference) { + AddAssemblyBreakpointLocations(locations, *args.source.sourceReference, + start_line, end_line); + } else { + std::string path = args.source.path.value_or(""); + AddSourceBreakpointLocations(locations, std::move(path), start_line, + start_column, end_line, end_column); + } + + // The line entries are sorted by addresses, but we must return the list + // ordered by line / column position. + std::sort(locations.begin(), locations.end()); + locations.erase(llvm::unique(locations), locations.end()); + + std::vector breakpoint_locations; + for (auto &l : locations) { + protocol::BreakpointLocation lc; + lc.line = l.first; + lc.column = l.second; + breakpoint_locations.push_back(std::move(lc)); + } + + return protocol::BreakpointLocationsResponseBody{ + /*breakpoints=*/std::move(breakpoint_locations)}; +} + +template +void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const { + lldb::SBFileSpec file_spec(path.c_str(), true); lldb::SBSymbolContextList compile_units = dap.target.FindCompileUnits(file_spec); - // Find all relevant lines & columns - llvm::SmallVector, 8> locations; for (uint32_t c_idx = 0, c_limit = compile_units.GetSize(); c_idx < c_limit; ++c_idx) { const lldb::SBCompileUnit &compile_unit = @@ -71,22 +102,34 @@ BreakpointLocationsRequestHandler::Run( locations.emplace_back(line, column); } } +} - // The line entries are sorted by addresses, but we must return the list - // ordered by line / column position. - std::sort(locations.begin(), locations.end()); - locations.erase(llvm::unique(locations), locations.end()); +template +void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { + lldb::SBProcess process = dap.target.GetProcess(); + lldb::SBThread thread = + process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); + lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - std::vector breakpoint_locations; - for (auto &l : locations) { - protocol::BreakpointLocation lc; - lc.line = l.first; - lc.column = l.second; - breakpoint_locations.push_back(std::move(lc)); - } + if (!frame.IsValid()) + return; - return protocol::BreakpointLocationsResponseBody{ - /*breakpoints=*/std::move(breakpoint_locations)}; + lldb::SBSymbol symbol = frame.GetSymbol(); + if (symbol.IsValid()) { + lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); + } + } else { + for (uint32_t i = start_line - 1; + i < dap.number_of_assembly_lines_for_nodebug && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); + } + } } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index e6bccfe12f402..21753bc0552f9 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -16,6 +16,7 @@ #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/JSON.h" @@ -232,6 +233,16 @@ class BreakpointLocationsRequestHandler } llvm::Expected Run(const protocol::BreakpointLocationsArguments &args) const override; + + template + void AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const; + template + void AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const; }; class CompletionsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp index 0ddd87881a164..fb396a3dc8862 100644 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp @@ -52,8 +52,8 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { insts.GetDescription(stream, exe_ctx); } else { // No valid symbol, just return the disassembly. - lldb::SBInstructionList insts = - dap.target.ReadInstructions(frame.GetPCAddress(), 32); + lldb::SBInstructionList insts = dap.target.ReadInstructions( + frame.GetPCAddress(), dap.number_of_assembly_lines_for_nodebug); insts.GetDescription(stream, exe_ctx); } >From ee492031bee8106fb2a4ff22a8563005f5afd86c Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 11 May 2025 19:49:03 +0200 Subject: [PATCH 02/11] support assembly in SetBreakpointsRequestHandler --- lldb/tools/lldb-dap/DAP.h | 1 + .../Handler/BreakpointLocationsHandler.cpp | 20 ++--- lldb/tools/lldb-dap/Handler/RequestHandler.h | 9 ++ .../Handler/SetBreakpointsRequestHandler.cpp | 90 ++++++++++++++++++- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 22 +++++ lldb/tools/lldb-dap/SourceBreakpoint.h | 1 + 6 files changed, 127 insertions(+), 16 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 00aa4276852c5..5ce0e534611c1 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -169,6 +169,7 @@ struct DAP { Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; + llvm::DenseMap assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 9eea549d72b00..be02c47056310 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -117,18 +117,14 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( return; lldb::SBSymbol symbol = frame.GetSymbol(); - if (symbol.IsValid()) { - lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); - ++i) { - locations.emplace_back(i, 0); - } - } else { - for (uint32_t i = start_line - 1; - i < dap.number_of_assembly_lines_for_nodebug && i < (end_line - 1); - ++i) { - locations.emplace_back(i, 0); - } + if (!symbol.IsValid()) + return; + + // start_line is relative to the symbol's start address + lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); } } diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 21753bc0552f9..72843aaef8150 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -389,6 +389,15 @@ class SetBreakpointsRequestHandler } llvm::Expected Run(const protocol::SetBreakpointsArguments &args) const override; + + std::vector SetSourceBreakpoints( + const std::string &path, + const std::optional> &breakpoints) + const; + std::vector SetAssemblyBreakpoints( + int64_t sourceReference, + const std::optional> &breakpoints) + const; }; class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 86e090b66afe9..71f9e5578ef08 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -9,8 +9,11 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" +#include +#include #include namespace lldb_dap { @@ -23,15 +26,30 @@ llvm::Expected SetBreakpointsRequestHandler::Run( const protocol::SetBreakpointsArguments &args) const { const auto &source = args.source; - const auto path = source.path.value_or(""); + std::vector response_breakpoints; + if (source.sourceReference) + response_breakpoints = SetAssemblyBreakpoints( + source.sourceReference.value(), args.breakpoints); + else if (source.path) + response_breakpoints = + SetSourceBreakpoints(source.path.value(), args.breakpoints); + + return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; +} + +std::vector +SetBreakpointsRequestHandler::SetSourceBreakpoints( + const std::string &path, + const std::optional> &breakpoints) + const { std::vector response_breakpoints; // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; // "breakpoints" may be unset, in which case we treat it the same as being set // to an empty array. - if (args.breakpoints) { - for (const auto &bp : *args.breakpoints) { + if (breakpoints) { + for (const auto &bp : *breakpoints) { SourceBreakpoint src_bp(dap, bp); std::pair bp_pos(src_bp.GetLine(), src_bp.GetColumn()); @@ -73,7 +91,71 @@ SetBreakpointsRequestHandler::Run( } } - return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; + return response_breakpoints; +} + +std::vector +SetBreakpointsRequestHandler::SetAssemblyBreakpoints( + int64_t sourceReference, + const std::optional> &breakpoints) + const { + std::vector response_breakpoints; + + lldb::SBProcess process = dap.target.GetProcess(); + lldb::SBThread thread = + process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); + lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); + + if (!frame.IsValid()) + return response_breakpoints; + + lldb::SBSymbol symbol = frame.GetSymbol(); + if (!symbol.IsValid()) + return response_breakpoints; // Not yet supporting breakpoints in assembly + // without a valid symbol + + SourceBreakpointMap request_bps; + if (breakpoints) { + for (const auto &bp : *breakpoints) { + SourceBreakpoint src_bp(dap, bp); + std::pair bp_pos(src_bp.GetLine(), 0); + request_bps.try_emplace(bp_pos, src_bp); + const auto [iv, inserted] = + dap.assembly_breakpoints[sourceReference].try_emplace(bp_pos, src_bp); + // We check if this breakpoint already exists to update it + if (inserted) + iv->getSecond().SetBreakpoint(symbol); + else + iv->getSecond().UpdateBreakpoint(src_bp); + + protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); + protocol::Source source; + source.sourceReference = sourceReference; + source.name = symbol.GetName(); + response_bp.source = std::move(source); + + if (!response_bp.line) + response_bp.line = src_bp.GetLine(); + if (!response_bp.column) + response_bp.column = src_bp.GetColumn(); + response_breakpoints.push_back(response_bp); + } + } + + // Delete existing breakpoints for this sourceReference that are not in the + // request_bps set. + auto old_src_bp_pos = dap.assembly_breakpoints.find(sourceReference); + if (old_src_bp_pos != dap.assembly_breakpoints.end()) { + for (auto &old_bp : old_src_bp_pos->second) { + auto request_pos = request_bps.find(old_bp.first); + if (request_pos == request_bps.end()) { + dap.target.BreakpointDelete(old_bp.second.GetID()); + old_src_bp_pos->second.erase(old_bp.first); + } + } + } + + return response_breakpoints; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 4581c995b4260..938b8fb8bcdda 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -13,7 +13,9 @@ #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBFileSpecList.h" #include "lldb/API/SBFrame.h" +#include "lldb/API/SBInstruction.h" #include "lldb/API/SBMutex.h" +#include "lldb/API/SBSymbol.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" #include "lldb/API/SBValue.h" @@ -45,6 +47,26 @@ void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) { Breakpoint::SetBreakpoint(); } +void SourceBreakpoint::SetBreakpoint(lldb::SBSymbol &symbol) { + lldb::SBMutex lock = m_dap.GetAPIMutex(); + std::lock_guard guard(lock); + + if (m_line == 0) + return; + + lldb::SBInstructionList inst_list = + m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); + if (inst_list.GetSize() < m_line) + return; + lldb::SBAddress address = + inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + + m_bp = m_dap.target.BreakpointCreateBySBAddress(address); + if (!m_log_message.empty()) + SetLogMessage(); + Breakpoint::SetBreakpoint(); +} + void SourceBreakpoint::UpdateBreakpoint(const SourceBreakpoint &request_bp) { if (m_log_message != request_bp.m_log_message) { m_log_message = request_bp.m_log_message; diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h index 5b15296f861c5..8589800e50983 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.h +++ b/lldb/tools/lldb-dap/SourceBreakpoint.h @@ -26,6 +26,7 @@ class SourceBreakpoint : public Breakpoint { // Set this breakpoint in LLDB as a new breakpoint void SetBreakpoint(const llvm::StringRef source_path); + void SetBreakpoint(lldb::SBSymbol &symbol); void UpdateBreakpoint(const SourceBreakpoint &request_bp); void SetLogMessage(); >From dbb2f9bd55b3f86247e03b2610fca9576e124637 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Wed, 14 May 2025 23:51:41 +0200 Subject: [PATCH 03/11] fix resolving of assembly source breakpoints --- lldb/tools/lldb-dap/Breakpoint.cpp | 45 ++++++++++++++++--- lldb/tools/lldb-dap/DAP.h | 3 +- .../Handler/BreakpointLocationsHandler.cpp | 4 +- lldb/tools/lldb-dap/Handler/RequestHandler.h | 4 +- .../Handler/SetBreakpointsRequestHandler.cpp | 30 ++++++------- lldb/tools/lldb-dap/package-lock.json | 4 +- lldb/tools/lldb-dap/package.json | 5 ++- 7 files changed, 63 insertions(+), 32 deletions(-) diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 26d633d1d172e..87fcd15b0a568 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -9,10 +9,12 @@ #include "Breakpoint.h" #include "DAP.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "lldb/API/SBAddress.h" #include "lldb/API/SBBreakpointLocation.h" #include "lldb/API/SBLineEntry.h" #include "lldb/API/SBMutex.h" +#include "lldb/lldb-enumerations.h" #include "llvm/ADT/StringExtras.h" #include #include @@ -63,14 +65,43 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { std::string formatted_addr = "0x" + llvm::utohexstr(bp_addr.GetLoadAddress(m_bp.GetTarget())); breakpoint.instructionReference = formatted_addr; + + lldb::StopDisassemblyType stop_disassembly_display = + GetStopDisassemblyDisplay(m_dap.debugger); auto line_entry = bp_addr.GetLineEntry(); - const auto line = line_entry.GetLine(); - if (line != UINT32_MAX) - breakpoint.line = line; - const auto column = line_entry.GetColumn(); - if (column != 0) - breakpoint.column = column; - breakpoint.source = CreateSource(line_entry); + if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) { + const auto line = line_entry.GetLine(); + if (line != UINT32_MAX) + breakpoint.line = line; + const auto column = line_entry.GetColumn(); + if (column != 0) + breakpoint.column = column; + breakpoint.source = CreateSource(line_entry); + } else { + // Breakpoint made by assembly + auto symbol_context = bp_addr.GetSymbolContext( + lldb::eSymbolContextSymbol | lldb::eSymbolContextModule); + if (symbol_context.IsValid()) { + auto symbol = symbol_context.GetSymbol(); + breakpoint.line = + m_bp.GetTarget() + .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) + .GetSize() + + 1; + protocol::Source source; + source.name = symbol.GetName(); + + auto module = symbol_context.GetModule(); + if (module.IsValid()) { + std::string path = module.GetFileSpec().GetDirectory(); + path += "/"; + path += module.GetFileSpec().GetFilename(); + source.path = std::move(path); + } + + breakpoint.source = std::move(source); + } + } } return breakpoint; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 5ce0e534611c1..b0fe265b7bca1 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -169,7 +169,8 @@ struct DAP { Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; - llvm::DenseMap assembly_breakpoints; + llvm::DenseMap> + assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index be02c47056310..06ada47a6f27f 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -122,9 +122,9 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( // start_line is relative to the symbol's start address lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i <= (end_line - 1); ++i) { - locations.emplace_back(i, 0); + locations.emplace_back(i, 1); } } diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 72843aaef8150..80898d1ee5ef1 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -391,11 +391,11 @@ class SetBreakpointsRequestHandler Run(const protocol::SetBreakpointsArguments &args) const override; std::vector SetSourceBreakpoints( - const std::string &path, + const protocol::Source &source, const std::optional> &breakpoints) const; std::vector SetAssemblyBreakpoints( - int64_t sourceReference, + const protocol::Source &source, const std::optional> &breakpoints) const; }; diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 71f9e5578ef08..4fefd8b440c7d 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -28,21 +28,20 @@ SetBreakpointsRequestHandler::Run( const auto &source = args.source; std::vector response_breakpoints; if (source.sourceReference) - response_breakpoints = SetAssemblyBreakpoints( - source.sourceReference.value(), args.breakpoints); + response_breakpoints = SetAssemblyBreakpoints(source, args.breakpoints); else if (source.path) - response_breakpoints = - SetSourceBreakpoints(source.path.value(), args.breakpoints); + response_breakpoints = SetSourceBreakpoints(source, args.breakpoints); return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; } std::vector SetBreakpointsRequestHandler::SetSourceBreakpoints( - const std::string &path, + const protocol::Source &source, const std::optional> &breakpoints) const { std::vector response_breakpoints; + std::string path = source.path.value_or(""); // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; @@ -96,10 +95,11 @@ SetBreakpointsRequestHandler::SetSourceBreakpoints( std::vector SetBreakpointsRequestHandler::SetAssemblyBreakpoints( - int64_t sourceReference, + const protocol::Source &source, const std::optional> &breakpoints) const { std::vector response_breakpoints; + int64_t sourceReference = source.sourceReference.value_or(0); lldb::SBProcess process = dap.target.GetProcess(); lldb::SBThread thread = @@ -114,14 +114,14 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( return response_breakpoints; // Not yet supporting breakpoints in assembly // without a valid symbol - SourceBreakpointMap request_bps; + llvm::DenseMap request_bps; if (breakpoints) { for (const auto &bp : *breakpoints) { SourceBreakpoint src_bp(dap, bp); - std::pair bp_pos(src_bp.GetLine(), 0); - request_bps.try_emplace(bp_pos, src_bp); + request_bps.try_emplace(src_bp.GetLine(), src_bp); const auto [iv, inserted] = - dap.assembly_breakpoints[sourceReference].try_emplace(bp_pos, src_bp); + dap.assembly_breakpoints[sourceReference].try_emplace( + src_bp.GetLine(), src_bp); // We check if this breakpoint already exists to update it if (inserted) iv->getSecond().SetBreakpoint(symbol); @@ -129,15 +129,11 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( iv->getSecond().UpdateBreakpoint(src_bp); protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - protocol::Source source; - source.sourceReference = sourceReference; - source.name = symbol.GetName(); - response_bp.source = std::move(source); - + response_bp.source = source; if (!response_bp.line) response_bp.line = src_bp.GetLine(); - if (!response_bp.column) - response_bp.column = src_bp.GetColumn(); + if (bp.column) + response_bp.column = *bp.column; response_breakpoints.push_back(response_bp); } } diff --git a/lldb/tools/lldb-dap/package-lock.json b/lldb/tools/lldb-dap/package-lock.json index 0a2b9e764067e..af90a9573aee6 100644 --- a/lldb/tools/lldb-dap/package-lock.json +++ b/lldb/tools/lldb-dap/package-lock.json @@ -1,12 +1,12 @@ { "name": "lldb-dap", - "version": "0.2.13", + "version": "0.2.14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lldb-dap", - "version": "0.2.13", + "version": "0.2.14", "license": "Apache 2.0 License with LLVM exceptions", "devDependencies": { "@types/node": "^18.19.41", diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index d5ca604798799..73e70cd961f4f 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -1,7 +1,7 @@ { "name": "lldb-dap", "displayName": "LLDB DAP", - "version": "0.2.13", + "version": "0.2.14", "publisher": "llvm-vs-code-extensions", "homepage": "https://lldb.llvm.org", "description": "Debugging with LLDB in Visual Studio Code", @@ -265,6 +265,9 @@ ] }, "breakpoints": [ + { + "language": "lldb.disassembly" + }, { "language": "ada" }, >From 3699524618ed76f969cc26a63610fe54e3605139 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Thu, 15 May 2025 00:36:10 +0200 Subject: [PATCH 04/11] remove include --- lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 4fefd8b440c7d..d69da5bd02c1e 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -12,8 +12,6 @@ #include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" -#include -#include #include namespace lldb_dap { >From 61623deb7e249a8ca0c63e3f66955790da5e4ced Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sat, 17 May 2025 21:05:27 +0200 Subject: [PATCH 05/11] use load address as sourceReference --- lldb/include/lldb/API/SBFileSpec.h | 3 + lldb/source/API/SBFileSpec.cpp | 8 ++ lldb/tools/lldb-dap/Breakpoint.cpp | 18 +---- .../Handler/BreakpointLocationsHandler.cpp | 11 +-- .../Handler/SetBreakpointsRequestHandler.cpp | 11 +-- .../lldb-dap/Handler/SourceRequestHandler.cpp | 18 ++--- lldb/tools/lldb-dap/JSONUtils.cpp | 75 +++++++++++++------ lldb/tools/lldb-dap/JSONUtils.h | 14 ++++ 8 files changed, 96 insertions(+), 62 deletions(-) diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index 36641843aabeb..303cb7d712cbf 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -10,6 +10,7 @@ #define LLDB_API_SBFILESPEC_H #include "lldb/API/SBDefines.h" +#include "lldb/API/SBStream.h" namespace lldb { @@ -53,6 +54,8 @@ class LLDB_API SBFileSpec { uint32_t GetPath(char *dst_path, size_t dst_len) const; + bool GetPath(lldb::SBStream &dst_path) const; + static int ResolvePath(const char *src_path, char *dst_path, size_t dst_len); bool GetDescription(lldb::SBStream &description) const; diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp index a7df9afc4b8eb..cb44dac1d4fcc 100644 --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -19,6 +19,7 @@ #include #include +#include using namespace lldb; using namespace lldb_private; @@ -147,6 +148,13 @@ uint32_t SBFileSpec::GetPath(char *dst_path, size_t dst_len) const { return result; } +bool SBFileSpec::GetPath(SBStream &dst_path) const { + LLDB_INSTRUMENT_VA(this, dst_path); + + std::string path = m_opaque_up->GetPath(); + return dst_path->PutCString(path.c_str()) > 0; +} + const lldb_private::FileSpec *SBFileSpec::operator->() const { return m_opaque_up.get(); } diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 87fcd15b0a568..a54a34e0f936d 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -79,27 +79,15 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { breakpoint.source = CreateSource(line_entry); } else { // Breakpoint made by assembly - auto symbol_context = bp_addr.GetSymbolContext( - lldb::eSymbolContextSymbol | lldb::eSymbolContextModule); - if (symbol_context.IsValid()) { - auto symbol = symbol_context.GetSymbol(); + auto symbol = bp_addr.GetSymbol(); + if (symbol.IsValid()) { breakpoint.line = m_bp.GetTarget() .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) .GetSize() + 1; - protocol::Source source; - source.name = symbol.GetName(); - auto module = symbol_context.GetModule(); - if (module.IsValid()) { - std::string path = module.GetFileSpec().GetDirectory(); - path += "/"; - path += module.GetFileSpec().GetFilename(); - source.path = std::move(path); - } - - breakpoint.source = std::move(source); + breakpoint.source = CreateAssemblySource(m_dap.target, bp_addr); } } } diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 06ada47a6f27f..c4d658caeee2d 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "LLDBUtils.h" #include "RequestHandler.h" #include @@ -108,15 +107,11 @@ template void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( llvm::SmallVector, N> &locations, int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { - lldb::SBProcess process = dap.target.GetProcess(); - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - - if (!frame.IsValid()) + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) return; - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) return; diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index d69da5bd02c1e..7b401f06e9a85 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -9,7 +9,6 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" -#include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" #include @@ -99,15 +98,11 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( std::vector response_breakpoints; int64_t sourceReference = source.sourceReference.value_or(0); - lldb::SBProcess process = dap.target.GetProcess(); - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - - if (!frame.IsValid()) + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) return response_breakpoints; - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) return response_breakpoints; // Not yet supporting breakpoints in assembly // without a valid symbol diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp index fb396a3dc8862..9249e2aa6fef7 100644 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp @@ -11,6 +11,7 @@ #include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" +#include "lldb/API/SBAddress.h" #include "lldb/API/SBExecutionContext.h" #include "lldb/API/SBFrame.h" #include "lldb/API/SBInstructionList.h" @@ -19,6 +20,7 @@ #include "lldb/API/SBSymbol.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" +#include "lldb/lldb-types.h" #include "llvm/Support/Error.h" namespace lldb_dap { @@ -34,18 +36,14 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { return llvm::make_error( "invalid arguments, expected source.sourceReference to be set"); - lldb::SBProcess process = dap.target.GetProcess(); - // Upper 32 bits is the thread index ID - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(source)); - // Lower 32 bits is the frame index - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(source)); - if (!frame.IsValid()) + lldb::SBAddress address(source, dap.target); + if (!address.IsValid()) return llvm::make_error("source not found"); + lldb::SBSymbol symbol = address.GetSymbol(); + lldb::SBStream stream; - lldb::SBExecutionContext exe_ctx(frame); - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBExecutionContext exe_ctx(dap.target); if (symbol.IsValid()) { lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); @@ -53,7 +51,7 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { } else { // No valid symbol, just return the disassembly. lldb::SBInstructionList insts = dap.target.ReadInstructions( - frame.GetPCAddress(), dap.number_of_assembly_lines_for_nodebug); + address, dap.number_of_assembly_lines_for_nodebug); insts.GetDescription(stream, exe_ctx); } diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 714947a4d3b9c..c8151c3d64ea4 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -490,6 +490,13 @@ CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp) { return filter; } +static std::string GetLoadAddressString(const lldb::addr_t addr) { + std::string result; + llvm::raw_string_ostream os(result); + os << llvm::format_hex(addr, 18); + return result; +} + protocol::Source CreateSource(const lldb::SBFileSpec &file) { protocol::Source source; if (file.IsValid()) { @@ -516,6 +523,43 @@ protocol::Source CreateSource(llvm::StringRef source_path) { return source; } +protocol::Source CreateAssemblySource(const lldb::SBTarget &target, + lldb::SBAddress &address) { + protocol::Source source; + + auto symbol = address.GetSymbol(); + std::string name; + if (symbol.IsValid()) { + source.sourceReference = symbol.GetStartAddress().GetLoadAddress(target); + name = symbol.GetName(); + } else { + const auto load_addr = address.GetLoadAddress(target); + source.sourceReference = load_addr; + name = GetLoadAddressString(load_addr); + } + + lldb::SBModule module = address.GetModule(); + if (module.IsValid()) { + lldb::SBFileSpec file_spec = module.GetFileSpec(); + if (file_spec.IsValid()) { + lldb::SBStream module_path; + if (file_spec.GetPath(module_path)) { + std::string path = module_path.GetData(); + source.path = path + '`' + name; + } + } + } + + source.name = std::move(name); + + // Mark the source as deemphasized since users will only be able to view + // assembly for these frames. + source.presentationHint = + protocol::Source::PresentationHint::eSourcePresentationHintDeemphasize; + + return source; +} + bool ShouldDisplayAssemblySource( const lldb::SBLineEntry &line_entry, lldb::StopDisassemblyType stop_disassembly_display) { @@ -619,12 +663,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, frame_name = name; } - if (frame_name.empty()) { + if (frame_name.empty()) // If the function name is unavailable, display the pc address as a 16-digit // hex string, e.g. "0x0000000000012345" - llvm::raw_string_ostream os(frame_name); - os << llvm::format_hex(frame.GetPC(), 18); - } + frame_name = GetLoadAddressString(frame.GetPC()); // We only include `[opt]` if a custom frame format is not specified. if (!format && frame.GetFunction().GetIsOptimized()) @@ -641,17 +683,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, } else if (frame.GetSymbol().IsValid()) { // If no source is associated with the frame, use the DAPFrameID to track // the 'source' and generate assembly. - llvm::json::Object source; - EmplaceSafeString(source, "name", frame_name); - char buf[PATH_MAX] = {0}; - size_t size = frame.GetModule().GetFileSpec().GetPath(buf, PATH_MAX); - EmplaceSafeString(source, "path", - std::string(buf, size) + '`' + frame_name); - source.try_emplace("sourceReference", MakeDAPFrameID(frame)); - // Mark the source as deemphasized since users will only be able to view - // assembly for these frames. - EmplaceSafeString(source, "presentationHint", "deemphasize"); - object.try_emplace("source", std::move(source)); + auto frame_address = frame.GetPCAddress(); + object.try_emplace("source", CreateAssemblySource( + frame.GetThread().GetProcess().GetTarget(), + frame_address)); // Calculate the line of the current PC from the start of the current // symbol. @@ -665,12 +700,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, object.try_emplace("column", 1); } else { // No valid line entry or symbol. - llvm::json::Object source; - EmplaceSafeString(source, "name", frame_name); - source.try_emplace("sourceReference", MakeDAPFrameID(frame)); - EmplaceSafeString(source, "presentationHint", "deemphasize"); - object.try_emplace("source", std::move(source)); - + auto frame_address = frame.GetPCAddress(); + object.try_emplace("source", CreateAssemblySource( + frame.GetThread().GetProcess().GetTarget(), + frame_address)); object.try_emplace("line", 1); object.try_emplace("column", 1); } diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h index 783f291338d8c..ac9b39739104f 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -269,6 +269,20 @@ protocol::Source CreateSource(const lldb::SBLineEntry &line_entry); /// definition outlined by Microsoft. protocol::Source CreateSource(llvm::StringRef source_path); +/// Create a "Source" object for a given frame, using its assembly for source. +/// +/// \param[in] target +/// The relevant target. +/// +/// \param[in] address +/// The address to use when creating the "Source" object. +/// +/// \return +/// A "Source" JSON object that follows the formal JSON +/// definition outlined by Microsoft. +protocol::Source CreateAssemblySource(const lldb::SBTarget &target, + lldb::SBAddress &address); + /// Return true if the given line entry should be displayed as assembly. /// /// \param[in] line_entry >From f5fd76de3ad25b9cbf6ce065e06c98ff30b070a8 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 02:22:19 +0200 Subject: [PATCH 06/11] add breakpoint-assembly test --- .../test/tools/lldb-dap/dap_server.py | 7 ++++ .../test/tools/lldb-dap/lldbdap_testcase.py | 10 +++++ .../lldb-dap/breakpoint-assembly/Makefile | 3 ++ .../TestDAP_breakpointAssembly.py | 42 +++++++++++++++++++ .../tools/lldb-dap/breakpoint-assembly/main.c | 14 +++++++ .../breakpoint/TestDAP_setBreakpoints.py | 1 + .../TestDAP_setExceptionBreakpoints.py | 1 + .../TestDAP_setFunctionBreakpoints.py | 1 + 8 files changed, 79 insertions(+) create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index 70fd0b0c419db..4a907a5e36901 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -955,6 +955,13 @@ def request_setBreakpoints(self, file_path, line_array, data=None): """ (dir, base) = os.path.split(file_path) source_dict = {"name": base, "path": file_path} + return self.request_setBreakpoints_with_source(source_dict, line_array, data) + + def request_setBreakpointsAssembly(self, sourceReference, line_array, data=None): + source_dict = {"sourceReference": sourceReference} + return self.request_setBreakpoints_with_source(source_dict, line_array, data) + + def request_setBreakpoints_with_source(self, source_dict, line_array, data=None): args_dict = { "source": source_dict, "sourceModified": False, diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index afdc746ed0d0d..427f66a7da0c8 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -63,6 +63,16 @@ def set_source_breakpoints(self, source_path, lines, data=None): for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) return breakpoint_ids + + def set_source_breakpoints_assembly(self, source_reference, lines, data=None): + response = self.dap_server.request_setBreakpointsAssembly(source_reference, lines, data) + if response is None: + return [] + breakpoints = response["body"]["breakpoints"] + breakpoint_ids = [] + for breakpoint in breakpoints: + breakpoint_ids.append("%i" % (breakpoint["id"])) + return breakpoint_ids def set_function_breakpoints(self, functions, condition=None, hitCondition=None): """Sets breakpoints by function name given an array of function names diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile new file mode 100644 index 0000000000000..10495940055b6 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py new file mode 100644 index 0000000000000..ba9df3a18590b --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py @@ -0,0 +1,42 @@ +""" +Test lldb-dap setBreakpoints request +""" + + +import dap_server +import shutil +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +import lldbdap_testcase +import os + + +class TestDAP_setBreakpointsAssembly(lldbdap_testcase.DAPTestCaseBase): + # @skipIfWindows + def test_functionality(self): + """Tests hitting assembly source breakpoints""" + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + + self.dap_server.request_evaluate( + "`settings set stop-disassembly-display no-debuginfo", context="repl" + ) + + assmebly_func_breakpoints = self.set_function_breakpoints(["assembly_func"]) + self.continue_to_breakpoints(assmebly_func_breakpoints) + + assembly_func_frame = self.get_stackFrames()[0] + self.assertIn( + "sourceReference", + assembly_func_frame.get("source"), + "Expected assembly source frame", + ) + + line = assembly_func_frame["line"] + + # Set an assembly breakpoint in the next line and check that it's hit + assembly_breakpoint_ids = self.set_source_breakpoints_assembly( + assembly_func_frame["source"]["sourceReference"], [line + 1] + ) + self.continue_to_breakpoints(assembly_breakpoint_ids) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c new file mode 100644 index 0000000000000..350739006f903 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c @@ -0,0 +1,14 @@ +#include + +__attribute__((nodebug)) int assembly_func(int n) { + n += 1; + n += 2; + n += 3; + + return n; +} + +int main(int argc, char const *argv[]) { + assembly_func(10); + return 0; +} diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index 26df2573555df..aae1251b17c93 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,6 +12,7 @@ import os + at skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py index 92ac66cd44c5d..4dc8c5b3c7ded 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py @@ -10,6 +10,7 @@ import lldbdap_testcase + at skip("Temporarily disable the breakpoint tests") class TestDAP_setExceptionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_functionality(self): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index 946595f639edc..baaca4d974d5d 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,6 +10,7 @@ import lldbdap_testcase + at skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): >From 40f68e418bfbb6564b3834382c4a33a3104fc33d Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 10:23:11 +0200 Subject: [PATCH 07/11] python format --- .../lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index 427f66a7da0c8..3bf649a087fdb 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -63,9 +63,11 @@ def set_source_breakpoints(self, source_path, lines, data=None): for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) return breakpoint_ids - + def set_source_breakpoints_assembly(self, source_reference, lines, data=None): - response = self.dap_server.request_setBreakpointsAssembly(source_reference, lines, data) + response = self.dap_server.request_setBreakpointsAssembly( + source_reference, lines, data + ) if response is None: return [] breakpoints = response["body"]["breakpoints"] >From 199512fd7a0900d45070b95dd52ef5ef136e2719 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 10:54:43 +0200 Subject: [PATCH 08/11] restore SBFileSpec and fix assembly breakpoints CR --- lldb/include/lldb/API/SBFileSpec.h | 2 - lldb/source/API/SBFileSpec.cpp | 7 --- lldb/tools/lldb-dap/DAP.h | 2 +- .../Handler/BreakpointLocationsHandler.cpp | 47 ++++++++++--------- lldb/tools/lldb-dap/Handler/RequestHandler.h | 17 ++++--- .../Handler/SetBreakpointsRequestHandler.cpp | 9 ++-- lldb/tools/lldb-dap/JSONUtils.cpp | 6 +-- lldb/tools/lldb-dap/LLDBUtils.cpp | 10 ++++ lldb/tools/lldb-dap/LLDBUtils.h | 10 ++++ 9 files changed, 60 insertions(+), 50 deletions(-) diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index 303cb7d712cbf..1bb28b2ddab01 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -54,8 +54,6 @@ class LLDB_API SBFileSpec { uint32_t GetPath(char *dst_path, size_t dst_len) const; - bool GetPath(lldb::SBStream &dst_path) const; - static int ResolvePath(const char *src_path, char *dst_path, size_t dst_len); bool GetDescription(lldb::SBStream &description) const; diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp index cb44dac1d4fcc..f18857f59171a 100644 --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -148,13 +148,6 @@ uint32_t SBFileSpec::GetPath(char *dst_path, size_t dst_len) const { return result; } -bool SBFileSpec::GetPath(SBStream &dst_path) const { - LLDB_INSTRUMENT_VA(this, dst_path); - - std::string path = m_opaque_up->GetPath(); - return dst_path->PutCString(path.c_str()) > 0; -} - const lldb_private::FileSpec *SBFileSpec::operator->() const { return m_opaque_up.get(); } diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index b0fe265b7bca1..20f95be792f41 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -222,7 +222,7 @@ struct DAP { /// @} /// Number of lines of assembly code to show when no debug info is available. - uint32_t number_of_assembly_lines_for_nodebug = 32; + static constexpr uint32_t number_of_assembly_lines_for_nodebug = 32; /// Creates a new DAP sessions. /// diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index c4d658caeee2d..794b83a9e0e1e 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -8,6 +8,7 @@ #include "DAP.h" #include "RequestHandler.h" +#include #include namespace lldb_dap { @@ -24,15 +25,15 @@ BreakpointLocationsRequestHandler::Run( uint32_t end_column = args.endColumn.value_or(std::numeric_limits::max()); - // Find all relevant lines & columns - llvm::SmallVector, 8> locations; - if (args.source.sourceReference) { - AddAssemblyBreakpointLocations(locations, *args.source.sourceReference, - start_line, end_line); - } else { + // Find all relevant lines & columns. + std::vector> locations; + if (args.source.sourceReference) + locations = GetAssemblyBreakpointLocations(*args.source.sourceReference, + start_line, end_line); + else { std::string path = args.source.path.value_or(""); - AddSourceBreakpointLocations(locations, std::move(path), start_line, - start_column, end_line, end_column); + locations = GetSourceBreakpointLocations( + std::move(path), start_line, start_column, end_line, end_column); } // The line entries are sorted by addresses, but we must return the list @@ -41,23 +42,19 @@ BreakpointLocationsRequestHandler::Run( locations.erase(llvm::unique(locations), locations.end()); std::vector breakpoint_locations; - for (auto &l : locations) { - protocol::BreakpointLocation lc; - lc.line = l.first; - lc.column = l.second; - breakpoint_locations.push_back(std::move(lc)); - } + for (auto &l : locations) + breakpoint_locations.push_back( + {l.first, l.second, std::nullopt, std::nullopt}); return protocol::BreakpointLocationsResponseBody{ /*breakpoints=*/std::move(breakpoint_locations)}; } -template -void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( - llvm::SmallVector, N> &locations, +std::vector> +BreakpointLocationsRequestHandler::GetSourceBreakpointLocations( std::string path, uint32_t start_line, uint32_t start_column, uint32_t end_line, uint32_t end_column) const { - + std::vector> locations; lldb::SBFileSpec file_spec(path.c_str(), true); lldb::SBSymbolContextList compile_units = dap.target.FindCompileUnits(file_spec); @@ -101,19 +98,21 @@ void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( locations.emplace_back(line, column); } } + + return locations; } -template -void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( - llvm::SmallVector, N> &locations, +std::vector> +BreakpointLocationsRequestHandler::GetAssemblyBreakpointLocations( int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { + std::vector> locations; lldb::SBAddress address(sourceReference, dap.target); if (!address.IsValid()) - return; + return locations; lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) - return; + return locations; // start_line is relative to the symbol's start address lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); @@ -121,6 +120,8 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( ++i) { locations.emplace_back(i, 1); } + + return locations; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 80898d1ee5ef1..e708abb50d5c0 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -23,6 +23,7 @@ #include #include #include +#include template struct is_optional : std::false_type {}; @@ -234,15 +235,13 @@ class BreakpointLocationsRequestHandler llvm::Expected Run(const protocol::BreakpointLocationsArguments &args) const override; - template - void AddSourceBreakpointLocations( - llvm::SmallVector, N> &locations, - std::string path, uint32_t start_line, uint32_t start_column, - uint32_t end_line, uint32_t end_column) const; - template - void AddAssemblyBreakpointLocations( - llvm::SmallVector, N> &locations, - int64_t sourceReference, uint32_t start_line, uint32_t end_line) const; + std::vector> + GetSourceBreakpointLocations(std::string path, uint32_t start_line, + uint32_t start_column, uint32_t end_line, + uint32_t end_column) const; + std::vector> + GetAssemblyBreakpointLocations(int64_t sourceReference, uint32_t start_line, + uint32_t end_line) const; }; class CompletionsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 7b401f06e9a85..bf0b584753c07 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -103,9 +103,10 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( return response_breakpoints; lldb::SBSymbol symbol = address.GetSymbol(); - if (!symbol.IsValid()) - return response_breakpoints; // Not yet supporting breakpoints in assembly - // without a valid symbol + if (!symbol.IsValid()) { + // Not yet supporting breakpoints in assembly without a valid symbol. + return response_breakpoints; + } llvm::DenseMap request_bps; if (breakpoints) { @@ -115,7 +116,7 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( const auto [iv, inserted] = dap.assembly_breakpoints[sourceReference].try_emplace( src_bp.GetLine(), src_bp); - // We check if this breakpoint already exists to update it + // We check if this breakpoint already exists to update it. if (inserted) iv->getSecond().SetBreakpoint(symbol); else diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index c8151c3d64ea4..1d2a6ff60e502 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -542,11 +542,9 @@ protocol::Source CreateAssemblySource(const lldb::SBTarget &target, if (module.IsValid()) { lldb::SBFileSpec file_spec = module.GetFileSpec(); if (file_spec.IsValid()) { - lldb::SBStream module_path; - if (file_spec.GetPath(module_path)) { - std::string path = module_path.GetData(); + std::string path = GetSBFileSpecPath(file_spec); + if (!path.empty()) source.path = path + '`' + name; - } } } diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp index 0e7bb2b9058a7..3c7623ec1215d 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.cpp +++ b/lldb/tools/lldb-dap/LLDBUtils.cpp @@ -20,6 +20,7 @@ #include "llvm/Support/JSON.h" #include "llvm/Support/raw_ostream.h" +#include #include #include @@ -242,4 +243,13 @@ ScopeSyncMode::ScopeSyncMode(lldb::SBDebugger &debugger) ScopeSyncMode::~ScopeSyncMode() { m_debugger.SetAsync(m_async); } +std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec) { + const auto directory_length = ::strlen(file_spec.GetDirectory()); + const auto file_name_length = ::strlen(file_spec.GetFilename()); + + std::string path(directory_length + file_name_length + 2, '\0'); + file_spec.GetPath(path.data(), path.length()); + return path; +} + } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/LLDBUtils.h b/lldb/tools/lldb-dap/LLDBUtils.h index 711fc6051231c..7fdf4b859ee61 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.h +++ b/lldb/tools/lldb-dap/LLDBUtils.h @@ -13,6 +13,7 @@ #include "lldb/API/SBDebugger.h" #include "lldb/API/SBEnvironment.h" #include "lldb/API/SBError.h" +#include "lldb/API/SBFileSpec.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" @@ -161,6 +162,15 @@ uint32_t GetLLDBFrameID(uint64_t dap_frame_id); lldb::SBEnvironment GetEnvironmentFromArguments(const llvm::json::Object &arguments); +/// Gets an SBFileSpec and returns its path as a string. +/// +/// \param[in] file_spec +/// The file spec. +/// +/// \return +/// The file path as a string. +std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec); + /// Helper for sending telemetry to lldb server, if client-telemetry is enabled. class TelemetryDispatcher { public: >From dbad33b314bb59f6e0d22fd07dddb35e2a0e30d9 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 12:57:59 +0200 Subject: [PATCH 09/11] abstracted source breakpoints maps by DAP --- lldb/tools/lldb-dap/Breakpoint.cpp | 4 +- lldb/tools/lldb-dap/DAP.cpp | 75 +++++++++++ lldb/tools/lldb-dap/DAP.h | 29 +++- lldb/tools/lldb-dap/Handler/RequestHandler.h | 9 -- .../Handler/SetBreakpointsRequestHandler.cpp | 125 +----------------- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 54 +++++--- lldb/tools/lldb-dap/SourceBreakpoint.h | 7 +- 7 files changed, 140 insertions(+), 163 deletions(-) diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index a54a34e0f936d..fd7531f42c518 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -71,10 +71,10 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { auto line_entry = bp_addr.GetLineEntry(); if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) { const auto line = line_entry.GetLine(); - if (line != UINT32_MAX) + if (line != LLDB_INVALID_LINE_NUMBER) breakpoint.line = line; const auto column = line_entry.GetColumn(); - if (column != 0) + if (column != LLDB_INVALID_COLUMN_NUMBER) breakpoint.column = column; breakpoint.source = CreateSource(line_entry); } else { diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 0d5eba6c40961..1fe46fc619d73 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1620,6 +1620,81 @@ void DAP::EventThread() { } } +std::vector DAP::SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints) { + std::vector response_breakpoints; + if (source.sourceReference) { + // breakpoint set by assembly source. + auto &existing_breakpoints_pos = + m_source_assembly_breakpoints[*source.sourceReference]; + response_breakpoints = + SetSourceBreakpoints(source, breakpoints, existing_breakpoints_pos); + } else { + // breakpoint set by a regular source file. + const auto path = source.path.value_or(""); + auto &existing_breakpoints_pos = m_source_breakpoints[path]; + response_breakpoints = + SetSourceBreakpoints(source, breakpoints, existing_breakpoints_pos); + } + + return response_breakpoints; +} + +std::vector DAP::SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints, + SourceBreakpointMap &existing_breakpoints) { + std::vector response_breakpoints; + + SourceBreakpointMap request_breakpoints; + if (breakpoints) { + for (const auto &bp : *breakpoints) { + SourceBreakpoint src_bp(*this, bp, source); + std::pair bp_pos(src_bp.GetLine(), + src_bp.GetColumn()); + request_breakpoints.try_emplace(bp_pos, src_bp); + + const auto [iv, inserted] = + existing_breakpoints.try_emplace(bp_pos, src_bp); + // We check if this breakpoint already exists to update it. + if (inserted) + iv->second.SetBreakpoint(); + else + iv->second.UpdateBreakpoint(src_bp); + + protocol::Breakpoint response_breakpoint = + iv->second.ToProtocolBreakpoint(); + response_breakpoint.source = source; + + if (!response_breakpoint.line && + src_bp.GetLine() != LLDB_INVALID_LINE_NUMBER) + response_breakpoint.line = src_bp.GetLine(); + if (!response_breakpoint.column && + src_bp.GetColumn() != LLDB_INVALID_COLUMN_NUMBER) + response_breakpoint.column = src_bp.GetColumn(); + response_breakpoints.push_back(response_breakpoint); + } + } + + // Delete any breakpoints in this source file that aren't in the + // request_bps set. There is no call to remove breakpoints other than + // calling this function with a smaller or empty "breakpoints" list. + for (auto it = existing_breakpoints.begin(); + it != existing_breakpoints.end();) { + auto request_pos = request_breakpoints.find(it->first); + if (request_pos == request_breakpoints.end()) { + // This breakpoint no longer exists in this source file, delete it + target.BreakpointDelete(it->second.GetID()); + it = existing_breakpoints.erase(it); + } else { + ++it; + } + } + + return response_breakpoints; +} + void DAP::RegisterRequests() { RegisterRequest(); RegisterRequest(); diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 20f95be792f41..3a0a7fc1678ba 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -60,7 +60,7 @@ namespace lldb_dap { -typedef llvm::DenseMap, SourceBreakpoint> +typedef std::map, SourceBreakpoint> SourceBreakpointMap; typedef llvm::StringMap FunctionBreakpointMap; typedef llvm::DenseMap @@ -168,9 +168,6 @@ struct DAP { lldb::SBTarget target; Variables variables; lldb::SBBroadcaster broadcaster; - llvm::StringMap source_breakpoints; - llvm::DenseMap> - assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; @@ -428,7 +425,28 @@ struct DAP { void StartEventThread(); void StartProgressEventThread(); + /// Sets the given protocol `breakpoints` in the given `source`, while + /// removing any existing breakpoints in the given source if they are not in + /// `breakpoint`. + /// + /// \param[in] source + /// The relevant source of the breakpoints. + /// + /// \param[in] breakpoints + /// The breakpoints to set. + /// + /// \return a vector of the breakpoints that were set. + std::vector SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> + &breakpoints); + private: + std::vector SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints, + SourceBreakpointMap &existing_breakpoints); + /// Registration of request handler. /// @{ void RegisterRequests(); @@ -457,6 +475,9 @@ struct DAP { std::mutex m_active_request_mutex; const protocol::Request *m_active_request; + + llvm::StringMap m_source_breakpoints; + llvm::DenseMap m_source_assembly_breakpoints; }; } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index e708abb50d5c0..54f728414021e 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -388,15 +388,6 @@ class SetBreakpointsRequestHandler } llvm::Expected Run(const protocol::SetBreakpointsArguments &args) const override; - - std::vector SetSourceBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const; - std::vector SetAssemblyBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const; }; class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index bf0b584753c07..0ff88f62f8f51 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -22,130 +22,9 @@ namespace lldb_dap { llvm::Expected SetBreakpointsRequestHandler::Run( const protocol::SetBreakpointsArguments &args) const { - const auto &source = args.source; - std::vector response_breakpoints; - if (source.sourceReference) - response_breakpoints = SetAssemblyBreakpoints(source, args.breakpoints); - else if (source.path) - response_breakpoints = SetSourceBreakpoints(source, args.breakpoints); - + const auto response_breakpoints = + dap.SetSourceBreakpoints(args.source, args.breakpoints); return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; } -std::vector -SetBreakpointsRequestHandler::SetSourceBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const { - std::vector response_breakpoints; - std::string path = source.path.value_or(""); - - // Decode the source breakpoint infos for this "setBreakpoints" request - SourceBreakpointMap request_bps; - // "breakpoints" may be unset, in which case we treat it the same as being set - // to an empty array. - if (breakpoints) { - for (const auto &bp : *breakpoints) { - SourceBreakpoint src_bp(dap, bp); - std::pair bp_pos(src_bp.GetLine(), - src_bp.GetColumn()); - request_bps.try_emplace(bp_pos, src_bp); - const auto [iv, inserted] = - dap.source_breakpoints[path].try_emplace(bp_pos, src_bp); - // We check if this breakpoint already exists to update it - if (inserted) - iv->getSecond().SetBreakpoint(path.data()); - else - iv->getSecond().UpdateBreakpoint(src_bp); - - protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - - // Use the path from the request if it is set - if (!path.empty()) - response_bp.source = CreateSource(path); - - if (!response_bp.line) - response_bp.line = src_bp.GetLine(); - if (!response_bp.column) - response_bp.column = src_bp.GetColumn(); - response_breakpoints.push_back(response_bp); - } - } - - // Delete any breakpoints in this source file that aren't in the - // request_bps set. There is no call to remove breakpoints other than - // calling this function with a smaller or empty "breakpoints" list. - auto old_src_bp_pos = dap.source_breakpoints.find(path); - if (old_src_bp_pos != dap.source_breakpoints.end()) { - for (auto &old_bp : old_src_bp_pos->second) { - auto request_pos = request_bps.find(old_bp.first); - if (request_pos == request_bps.end()) { - // This breakpoint no longer exists in this source file, delete it - dap.target.BreakpointDelete(old_bp.second.GetID()); - old_src_bp_pos->second.erase(old_bp.first); - } - } - } - - return response_breakpoints; -} - -std::vector -SetBreakpointsRequestHandler::SetAssemblyBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const { - std::vector response_breakpoints; - int64_t sourceReference = source.sourceReference.value_or(0); - - lldb::SBAddress address(sourceReference, dap.target); - if (!address.IsValid()) - return response_breakpoints; - - lldb::SBSymbol symbol = address.GetSymbol(); - if (!symbol.IsValid()) { - // Not yet supporting breakpoints in assembly without a valid symbol. - return response_breakpoints; - } - - llvm::DenseMap request_bps; - if (breakpoints) { - for (const auto &bp : *breakpoints) { - SourceBreakpoint src_bp(dap, bp); - request_bps.try_emplace(src_bp.GetLine(), src_bp); - const auto [iv, inserted] = - dap.assembly_breakpoints[sourceReference].try_emplace( - src_bp.GetLine(), src_bp); - // We check if this breakpoint already exists to update it. - if (inserted) - iv->getSecond().SetBreakpoint(symbol); - else - iv->getSecond().UpdateBreakpoint(src_bp); - - protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - response_bp.source = source; - if (!response_bp.line) - response_bp.line = src_bp.GetLine(); - if (bp.column) - response_bp.column = *bp.column; - response_breakpoints.push_back(response_bp); - } - } - - // Delete existing breakpoints for this sourceReference that are not in the - // request_bps set. - auto old_src_bp_pos = dap.assembly_breakpoints.find(sourceReference); - if (old_src_bp_pos != dap.assembly_breakpoints.end()) { - for (auto &old_bp : old_src_bp_pos->second) { - auto request_pos = request_bps.find(old_bp.first); - if (request_pos == request_bps.end()) { - dap.target.BreakpointDelete(old_bp.second.GetID()); - old_src_bp_pos->second.erase(old_bp.first); - } - } - } - - return response_breakpoints; -} - } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 938b8fb8bcdda..50ebfbe8aef20 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -29,39 +29,49 @@ namespace lldb_dap { SourceBreakpoint::SourceBreakpoint(DAP &dap, - const protocol::SourceBreakpoint &breakpoint) + const protocol::SourceBreakpoint &breakpoint, + const protocol::Source &source) : Breakpoint(dap, breakpoint.condition, breakpoint.hitCondition), - m_log_message(breakpoint.logMessage.value_or("")), + m_log_message(breakpoint.logMessage.value_or("")), m_source(source), m_line(breakpoint.line), m_column(breakpoint.column.value_or(LLDB_INVALID_COLUMN_NUMBER)) {} -void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) { - lldb::SBMutex lock = m_dap.GetAPIMutex(); - std::lock_guard guard(lock); - - lldb::SBFileSpecList module_list; - m_bp = m_dap.target.BreakpointCreateByLocation( - source_path.str().c_str(), m_line, m_column, 0, module_list); - if (!m_log_message.empty()) - SetLogMessage(); - Breakpoint::SetBreakpoint(); -} - -void SourceBreakpoint::SetBreakpoint(lldb::SBSymbol &symbol) { +void SourceBreakpoint::SetBreakpoint() { lldb::SBMutex lock = m_dap.GetAPIMutex(); std::lock_guard guard(lock); if (m_line == 0) return; - lldb::SBInstructionList inst_list = - m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); - if (inst_list.GetSize() < m_line) - return; - lldb::SBAddress address = - inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + if (m_source.sourceReference) { + // breakpoint set by assembly source. + lldb::SBAddress source_address(*m_source.sourceReference, m_dap.target); + if (!source_address.IsValid()) + return; + + lldb::SBSymbol symbol = source_address.GetSymbol(); + if (!symbol.IsValid()) { + // Not yet supporting breakpoints in assembly without a valid symbol. + return; + } + + lldb::SBInstructionList inst_list = + m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); + if (inst_list.GetSize() < m_line) + return; + + lldb::SBAddress address = + inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + + m_bp = m_dap.target.BreakpointCreateBySBAddress(address); + } else { + // breakpoint set by a regular source file. + const auto source_path = m_source.path.value_or(""); + lldb::SBFileSpecList module_list; + m_bp = m_dap.target.BreakpointCreateByLocation(source_path.c_str(), m_line, + m_column, 0, module_list); + } - m_bp = m_dap.target.BreakpointCreateBySBAddress(address); if (!m_log_message.empty()) SetLogMessage(); Breakpoint::SetBreakpoint(); diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h index 8589800e50983..3221ecbf28ece 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.h +++ b/lldb/tools/lldb-dap/SourceBreakpoint.h @@ -22,11 +22,11 @@ namespace lldb_dap { class SourceBreakpoint : public Breakpoint { public: - SourceBreakpoint(DAP &d, const protocol::SourceBreakpoint &breakpoint); + SourceBreakpoint(DAP &d, const protocol::SourceBreakpoint &breakpoint, + const protocol::Source &source); // Set this breakpoint in LLDB as a new breakpoint - void SetBreakpoint(const llvm::StringRef source_path); - void SetBreakpoint(lldb::SBSymbol &symbol); + void SetBreakpoint(); void UpdateBreakpoint(const SourceBreakpoint &request_bp); void SetLogMessage(); @@ -63,6 +63,7 @@ class SourceBreakpoint : public Breakpoint { std::string m_log_message; std::vector m_log_message_parts; + protocol::Source m_source; /// The original breakpoint source. uint32_t m_line; ///< The source line of the breakpoint or logpoint uint32_t m_column; ///< An optional source column of the breakpoint }; >From 2e9edca37c0953e2d2a6cf2d278bb353f1e0960b Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 13:39:05 +0200 Subject: [PATCH 10/11] improve assembvly breakpoint test to check clear --- .../TestDAP_breakpointAssembly.py | 17 +++++++++++++++-- .../tools/lldb-dap/breakpoint-assembly/main.c | 4 +++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py index ba9df3a18590b..dacc1cd8349f1 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py @@ -6,7 +6,7 @@ import dap_server import shutil from lldbsuite.test.decorators import * -from lldbsuite.test.lldbtest import * +from lldbsuite.test.lldbtest import line_number from lldbsuite.test import lldbutil import lldbdap_testcase import os @@ -23,6 +23,9 @@ def test_functionality(self): "`settings set stop-disassembly-display no-debuginfo", context="repl" ) + finish_line = line_number("main.c", "// Break here") + finish_breakpoints = self.set_source_breakpoints("main.c", [finish_line]) + assmebly_func_breakpoints = self.set_function_breakpoints(["assembly_func"]) self.continue_to_breakpoints(assmebly_func_breakpoints) @@ -36,7 +39,17 @@ def test_functionality(self): line = assembly_func_frame["line"] # Set an assembly breakpoint in the next line and check that it's hit + source_reference = assembly_func_frame["source"]["sourceReference"] assembly_breakpoint_ids = self.set_source_breakpoints_assembly( - assembly_func_frame["source"]["sourceReference"], [line + 1] + source_reference, [line + 1] ) self.continue_to_breakpoints(assembly_breakpoint_ids) + + # Continue again and verify it hits in the next function call + self.continue_to_breakpoints(assmebly_func_breakpoints) + self.continue_to_breakpoints(assembly_breakpoint_ids) + + # Clear the breakpoint and then check that the assembly breakpoint does not hit next time + self.set_source_breakpoints_assembly(source_reference, []) + self.continue_to_breakpoints(assmebly_func_breakpoints) + self.continue_to_breakpoints(finish_breakpoints) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c index 350739006f903..e3a21df11958f 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c @@ -10,5 +10,7 @@ __attribute__((nodebug)) int assembly_func(int n) { int main(int argc, char const *argv[]) { assembly_func(10); - return 0; + assembly_func(20); + assembly_func(30); + return 0; // Break here } >From 0515c6dc6e46b6296621e871b43286ae88ea9b6b Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 13:52:40 +0200 Subject: [PATCH 11/11] fix GetSBFileSpecPath extra char --- lldb/tools/lldb-dap/LLDBUtils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp index 3c7623ec1215d..fe0bcda19b4cd 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.cpp +++ b/lldb/tools/lldb-dap/LLDBUtils.cpp @@ -247,8 +247,8 @@ std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec) { const auto directory_length = ::strlen(file_spec.GetDirectory()); const auto file_name_length = ::strlen(file_spec.GetFilename()); - std::string path(directory_length + file_name_length + 2, '\0'); - file_spec.GetPath(path.data(), path.length()); + std::string path(directory_length + file_name_length + 1, '\0'); + file_spec.GetPath(path.data(), path.length() + 1); return path; } From lldb-commits at lists.llvm.org Sun May 18 04:54:58 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 04:54:58 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <6829ca92.170a0220.1446b4.aab1@mx.google.com> ================ @@ -53,6 +54,8 @@ class LLDB_API SBFileSpec { uint32_t GetPath(char *dst_path, size_t dst_len) const; + bool GetPath(lldb::SBStream &dst_path) const; ---------------- eronnen wrote: moved to LLDBUtils https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sun May 18 05:00:10 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 05:00:10 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <6829cbca.170a0220.3437a.ab50@mx.google.com> https://github.com/eronnen updated https://github.com/llvm/llvm-project/pull/139969 >From d6325b3f6a8602fc96ad72acecfcccda1120614d Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sat, 10 May 2025 20:45:17 +0200 Subject: [PATCH 01/12] support assembly in BreakpointLocationsRequestHandler --- .../breakpoint/TestDAP_setBreakpoints.py | 1 - .../TestDAP_setExceptionBreakpoints.py | 1 - .../TestDAP_setFunctionBreakpoints.py | 1 - lldb/tools/lldb-dap/DAP.h | 3 + .../Handler/BreakpointLocationsHandler.cpp | 77 +++++++++++++++---- lldb/tools/lldb-dap/Handler/RequestHandler.h | 11 +++ .../lldb-dap/Handler/SourceRequestHandler.cpp | 4 +- 7 files changed, 76 insertions(+), 22 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index aae1251b17c93..26df2573555df 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,7 +12,6 @@ import os - at skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py index 4dc8c5b3c7ded..92ac66cd44c5d 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setExceptionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_functionality(self): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index baaca4d974d5d..946595f639edc 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 8f24c6cf82924..00aa4276852c5 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -219,6 +219,9 @@ struct DAP { llvm::StringSet<> modules; /// @} + /// Number of lines of assembly code to show when no debug info is available. + uint32_t number_of_assembly_lines_for_nodebug = 32; + /// Creates a new DAP sessions. /// /// \param[in] log diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 2ac886c3a5d2c..9eea549d72b00 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "JSONUtils.h" +#include "LLDBUtils.h" #include "RequestHandler.h" #include @@ -19,19 +19,50 @@ namespace lldb_dap { llvm::Expected BreakpointLocationsRequestHandler::Run( const protocol::BreakpointLocationsArguments &args) const { - std::string path = args.source.path.value_or(""); uint32_t start_line = args.line; uint32_t start_column = args.column.value_or(LLDB_INVALID_COLUMN_NUMBER); uint32_t end_line = args.endLine.value_or(start_line); uint32_t end_column = args.endColumn.value_or(std::numeric_limits::max()); + // Find all relevant lines & columns + llvm::SmallVector, 8> locations; + if (args.source.sourceReference) { + AddAssemblyBreakpointLocations(locations, *args.source.sourceReference, + start_line, end_line); + } else { + std::string path = args.source.path.value_or(""); + AddSourceBreakpointLocations(locations, std::move(path), start_line, + start_column, end_line, end_column); + } + + // The line entries are sorted by addresses, but we must return the list + // ordered by line / column position. + std::sort(locations.begin(), locations.end()); + locations.erase(llvm::unique(locations), locations.end()); + + std::vector breakpoint_locations; + for (auto &l : locations) { + protocol::BreakpointLocation lc; + lc.line = l.first; + lc.column = l.second; + breakpoint_locations.push_back(std::move(lc)); + } + + return protocol::BreakpointLocationsResponseBody{ + /*breakpoints=*/std::move(breakpoint_locations)}; +} + +template +void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const { + lldb::SBFileSpec file_spec(path.c_str(), true); lldb::SBSymbolContextList compile_units = dap.target.FindCompileUnits(file_spec); - // Find all relevant lines & columns - llvm::SmallVector, 8> locations; for (uint32_t c_idx = 0, c_limit = compile_units.GetSize(); c_idx < c_limit; ++c_idx) { const lldb::SBCompileUnit &compile_unit = @@ -71,22 +102,34 @@ BreakpointLocationsRequestHandler::Run( locations.emplace_back(line, column); } } +} - // The line entries are sorted by addresses, but we must return the list - // ordered by line / column position. - std::sort(locations.begin(), locations.end()); - locations.erase(llvm::unique(locations), locations.end()); +template +void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { + lldb::SBProcess process = dap.target.GetProcess(); + lldb::SBThread thread = + process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); + lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - std::vector breakpoint_locations; - for (auto &l : locations) { - protocol::BreakpointLocation lc; - lc.line = l.first; - lc.column = l.second; - breakpoint_locations.push_back(std::move(lc)); - } + if (!frame.IsValid()) + return; - return protocol::BreakpointLocationsResponseBody{ - /*breakpoints=*/std::move(breakpoint_locations)}; + lldb::SBSymbol symbol = frame.GetSymbol(); + if (symbol.IsValid()) { + lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); + } + } else { + for (uint32_t i = start_line - 1; + i < dap.number_of_assembly_lines_for_nodebug && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); + } + } } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index e6bccfe12f402..21753bc0552f9 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -16,6 +16,7 @@ #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/JSON.h" @@ -232,6 +233,16 @@ class BreakpointLocationsRequestHandler } llvm::Expected Run(const protocol::BreakpointLocationsArguments &args) const override; + + template + void AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const; + template + void AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const; }; class CompletionsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp index 0ddd87881a164..fb396a3dc8862 100644 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp @@ -52,8 +52,8 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { insts.GetDescription(stream, exe_ctx); } else { // No valid symbol, just return the disassembly. - lldb::SBInstructionList insts = - dap.target.ReadInstructions(frame.GetPCAddress(), 32); + lldb::SBInstructionList insts = dap.target.ReadInstructions( + frame.GetPCAddress(), dap.number_of_assembly_lines_for_nodebug); insts.GetDescription(stream, exe_ctx); } >From ee492031bee8106fb2a4ff22a8563005f5afd86c Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 11 May 2025 19:49:03 +0200 Subject: [PATCH 02/12] support assembly in SetBreakpointsRequestHandler --- lldb/tools/lldb-dap/DAP.h | 1 + .../Handler/BreakpointLocationsHandler.cpp | 20 ++--- lldb/tools/lldb-dap/Handler/RequestHandler.h | 9 ++ .../Handler/SetBreakpointsRequestHandler.cpp | 90 ++++++++++++++++++- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 22 +++++ lldb/tools/lldb-dap/SourceBreakpoint.h | 1 + 6 files changed, 127 insertions(+), 16 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 00aa4276852c5..5ce0e534611c1 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -169,6 +169,7 @@ struct DAP { Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; + llvm::DenseMap assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 9eea549d72b00..be02c47056310 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -117,18 +117,14 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( return; lldb::SBSymbol symbol = frame.GetSymbol(); - if (symbol.IsValid()) { - lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); - ++i) { - locations.emplace_back(i, 0); - } - } else { - for (uint32_t i = start_line - 1; - i < dap.number_of_assembly_lines_for_nodebug && i < (end_line - 1); - ++i) { - locations.emplace_back(i, 0); - } + if (!symbol.IsValid()) + return; + + // start_line is relative to the symbol's start address + lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); } } diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 21753bc0552f9..72843aaef8150 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -389,6 +389,15 @@ class SetBreakpointsRequestHandler } llvm::Expected Run(const protocol::SetBreakpointsArguments &args) const override; + + std::vector SetSourceBreakpoints( + const std::string &path, + const std::optional> &breakpoints) + const; + std::vector SetAssemblyBreakpoints( + int64_t sourceReference, + const std::optional> &breakpoints) + const; }; class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 86e090b66afe9..71f9e5578ef08 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -9,8 +9,11 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" +#include +#include #include namespace lldb_dap { @@ -23,15 +26,30 @@ llvm::Expected SetBreakpointsRequestHandler::Run( const protocol::SetBreakpointsArguments &args) const { const auto &source = args.source; - const auto path = source.path.value_or(""); + std::vector response_breakpoints; + if (source.sourceReference) + response_breakpoints = SetAssemblyBreakpoints( + source.sourceReference.value(), args.breakpoints); + else if (source.path) + response_breakpoints = + SetSourceBreakpoints(source.path.value(), args.breakpoints); + + return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; +} + +std::vector +SetBreakpointsRequestHandler::SetSourceBreakpoints( + const std::string &path, + const std::optional> &breakpoints) + const { std::vector response_breakpoints; // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; // "breakpoints" may be unset, in which case we treat it the same as being set // to an empty array. - if (args.breakpoints) { - for (const auto &bp : *args.breakpoints) { + if (breakpoints) { + for (const auto &bp : *breakpoints) { SourceBreakpoint src_bp(dap, bp); std::pair bp_pos(src_bp.GetLine(), src_bp.GetColumn()); @@ -73,7 +91,71 @@ SetBreakpointsRequestHandler::Run( } } - return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; + return response_breakpoints; +} + +std::vector +SetBreakpointsRequestHandler::SetAssemblyBreakpoints( + int64_t sourceReference, + const std::optional> &breakpoints) + const { + std::vector response_breakpoints; + + lldb::SBProcess process = dap.target.GetProcess(); + lldb::SBThread thread = + process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); + lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); + + if (!frame.IsValid()) + return response_breakpoints; + + lldb::SBSymbol symbol = frame.GetSymbol(); + if (!symbol.IsValid()) + return response_breakpoints; // Not yet supporting breakpoints in assembly + // without a valid symbol + + SourceBreakpointMap request_bps; + if (breakpoints) { + for (const auto &bp : *breakpoints) { + SourceBreakpoint src_bp(dap, bp); + std::pair bp_pos(src_bp.GetLine(), 0); + request_bps.try_emplace(bp_pos, src_bp); + const auto [iv, inserted] = + dap.assembly_breakpoints[sourceReference].try_emplace(bp_pos, src_bp); + // We check if this breakpoint already exists to update it + if (inserted) + iv->getSecond().SetBreakpoint(symbol); + else + iv->getSecond().UpdateBreakpoint(src_bp); + + protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); + protocol::Source source; + source.sourceReference = sourceReference; + source.name = symbol.GetName(); + response_bp.source = std::move(source); + + if (!response_bp.line) + response_bp.line = src_bp.GetLine(); + if (!response_bp.column) + response_bp.column = src_bp.GetColumn(); + response_breakpoints.push_back(response_bp); + } + } + + // Delete existing breakpoints for this sourceReference that are not in the + // request_bps set. + auto old_src_bp_pos = dap.assembly_breakpoints.find(sourceReference); + if (old_src_bp_pos != dap.assembly_breakpoints.end()) { + for (auto &old_bp : old_src_bp_pos->second) { + auto request_pos = request_bps.find(old_bp.first); + if (request_pos == request_bps.end()) { + dap.target.BreakpointDelete(old_bp.second.GetID()); + old_src_bp_pos->second.erase(old_bp.first); + } + } + } + + return response_breakpoints; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 4581c995b4260..938b8fb8bcdda 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -13,7 +13,9 @@ #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBFileSpecList.h" #include "lldb/API/SBFrame.h" +#include "lldb/API/SBInstruction.h" #include "lldb/API/SBMutex.h" +#include "lldb/API/SBSymbol.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" #include "lldb/API/SBValue.h" @@ -45,6 +47,26 @@ void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) { Breakpoint::SetBreakpoint(); } +void SourceBreakpoint::SetBreakpoint(lldb::SBSymbol &symbol) { + lldb::SBMutex lock = m_dap.GetAPIMutex(); + std::lock_guard guard(lock); + + if (m_line == 0) + return; + + lldb::SBInstructionList inst_list = + m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); + if (inst_list.GetSize() < m_line) + return; + lldb::SBAddress address = + inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + + m_bp = m_dap.target.BreakpointCreateBySBAddress(address); + if (!m_log_message.empty()) + SetLogMessage(); + Breakpoint::SetBreakpoint(); +} + void SourceBreakpoint::UpdateBreakpoint(const SourceBreakpoint &request_bp) { if (m_log_message != request_bp.m_log_message) { m_log_message = request_bp.m_log_message; diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h index 5b15296f861c5..8589800e50983 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.h +++ b/lldb/tools/lldb-dap/SourceBreakpoint.h @@ -26,6 +26,7 @@ class SourceBreakpoint : public Breakpoint { // Set this breakpoint in LLDB as a new breakpoint void SetBreakpoint(const llvm::StringRef source_path); + void SetBreakpoint(lldb::SBSymbol &symbol); void UpdateBreakpoint(const SourceBreakpoint &request_bp); void SetLogMessage(); >From dbb2f9bd55b3f86247e03b2610fca9576e124637 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Wed, 14 May 2025 23:51:41 +0200 Subject: [PATCH 03/12] fix resolving of assembly source breakpoints --- lldb/tools/lldb-dap/Breakpoint.cpp | 45 ++++++++++++++++--- lldb/tools/lldb-dap/DAP.h | 3 +- .../Handler/BreakpointLocationsHandler.cpp | 4 +- lldb/tools/lldb-dap/Handler/RequestHandler.h | 4 +- .../Handler/SetBreakpointsRequestHandler.cpp | 30 ++++++------- lldb/tools/lldb-dap/package-lock.json | 4 +- lldb/tools/lldb-dap/package.json | 5 ++- 7 files changed, 63 insertions(+), 32 deletions(-) diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 26d633d1d172e..87fcd15b0a568 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -9,10 +9,12 @@ #include "Breakpoint.h" #include "DAP.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "lldb/API/SBAddress.h" #include "lldb/API/SBBreakpointLocation.h" #include "lldb/API/SBLineEntry.h" #include "lldb/API/SBMutex.h" +#include "lldb/lldb-enumerations.h" #include "llvm/ADT/StringExtras.h" #include #include @@ -63,14 +65,43 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { std::string formatted_addr = "0x" + llvm::utohexstr(bp_addr.GetLoadAddress(m_bp.GetTarget())); breakpoint.instructionReference = formatted_addr; + + lldb::StopDisassemblyType stop_disassembly_display = + GetStopDisassemblyDisplay(m_dap.debugger); auto line_entry = bp_addr.GetLineEntry(); - const auto line = line_entry.GetLine(); - if (line != UINT32_MAX) - breakpoint.line = line; - const auto column = line_entry.GetColumn(); - if (column != 0) - breakpoint.column = column; - breakpoint.source = CreateSource(line_entry); + if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) { + const auto line = line_entry.GetLine(); + if (line != UINT32_MAX) + breakpoint.line = line; + const auto column = line_entry.GetColumn(); + if (column != 0) + breakpoint.column = column; + breakpoint.source = CreateSource(line_entry); + } else { + // Breakpoint made by assembly + auto symbol_context = bp_addr.GetSymbolContext( + lldb::eSymbolContextSymbol | lldb::eSymbolContextModule); + if (symbol_context.IsValid()) { + auto symbol = symbol_context.GetSymbol(); + breakpoint.line = + m_bp.GetTarget() + .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) + .GetSize() + + 1; + protocol::Source source; + source.name = symbol.GetName(); + + auto module = symbol_context.GetModule(); + if (module.IsValid()) { + std::string path = module.GetFileSpec().GetDirectory(); + path += "/"; + path += module.GetFileSpec().GetFilename(); + source.path = std::move(path); + } + + breakpoint.source = std::move(source); + } + } } return breakpoint; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 5ce0e534611c1..b0fe265b7bca1 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -169,7 +169,8 @@ struct DAP { Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; - llvm::DenseMap assembly_breakpoints; + llvm::DenseMap> + assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index be02c47056310..06ada47a6f27f 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -122,9 +122,9 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( // start_line is relative to the symbol's start address lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i <= (end_line - 1); ++i) { - locations.emplace_back(i, 0); + locations.emplace_back(i, 1); } } diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 72843aaef8150..80898d1ee5ef1 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -391,11 +391,11 @@ class SetBreakpointsRequestHandler Run(const protocol::SetBreakpointsArguments &args) const override; std::vector SetSourceBreakpoints( - const std::string &path, + const protocol::Source &source, const std::optional> &breakpoints) const; std::vector SetAssemblyBreakpoints( - int64_t sourceReference, + const protocol::Source &source, const std::optional> &breakpoints) const; }; diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 71f9e5578ef08..4fefd8b440c7d 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -28,21 +28,20 @@ SetBreakpointsRequestHandler::Run( const auto &source = args.source; std::vector response_breakpoints; if (source.sourceReference) - response_breakpoints = SetAssemblyBreakpoints( - source.sourceReference.value(), args.breakpoints); + response_breakpoints = SetAssemblyBreakpoints(source, args.breakpoints); else if (source.path) - response_breakpoints = - SetSourceBreakpoints(source.path.value(), args.breakpoints); + response_breakpoints = SetSourceBreakpoints(source, args.breakpoints); return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; } std::vector SetBreakpointsRequestHandler::SetSourceBreakpoints( - const std::string &path, + const protocol::Source &source, const std::optional> &breakpoints) const { std::vector response_breakpoints; + std::string path = source.path.value_or(""); // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; @@ -96,10 +95,11 @@ SetBreakpointsRequestHandler::SetSourceBreakpoints( std::vector SetBreakpointsRequestHandler::SetAssemblyBreakpoints( - int64_t sourceReference, + const protocol::Source &source, const std::optional> &breakpoints) const { std::vector response_breakpoints; + int64_t sourceReference = source.sourceReference.value_or(0); lldb::SBProcess process = dap.target.GetProcess(); lldb::SBThread thread = @@ -114,14 +114,14 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( return response_breakpoints; // Not yet supporting breakpoints in assembly // without a valid symbol - SourceBreakpointMap request_bps; + llvm::DenseMap request_bps; if (breakpoints) { for (const auto &bp : *breakpoints) { SourceBreakpoint src_bp(dap, bp); - std::pair bp_pos(src_bp.GetLine(), 0); - request_bps.try_emplace(bp_pos, src_bp); + request_bps.try_emplace(src_bp.GetLine(), src_bp); const auto [iv, inserted] = - dap.assembly_breakpoints[sourceReference].try_emplace(bp_pos, src_bp); + dap.assembly_breakpoints[sourceReference].try_emplace( + src_bp.GetLine(), src_bp); // We check if this breakpoint already exists to update it if (inserted) iv->getSecond().SetBreakpoint(symbol); @@ -129,15 +129,11 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( iv->getSecond().UpdateBreakpoint(src_bp); protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - protocol::Source source; - source.sourceReference = sourceReference; - source.name = symbol.GetName(); - response_bp.source = std::move(source); - + response_bp.source = source; if (!response_bp.line) response_bp.line = src_bp.GetLine(); - if (!response_bp.column) - response_bp.column = src_bp.GetColumn(); + if (bp.column) + response_bp.column = *bp.column; response_breakpoints.push_back(response_bp); } } diff --git a/lldb/tools/lldb-dap/package-lock.json b/lldb/tools/lldb-dap/package-lock.json index 0a2b9e764067e..af90a9573aee6 100644 --- a/lldb/tools/lldb-dap/package-lock.json +++ b/lldb/tools/lldb-dap/package-lock.json @@ -1,12 +1,12 @@ { "name": "lldb-dap", - "version": "0.2.13", + "version": "0.2.14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lldb-dap", - "version": "0.2.13", + "version": "0.2.14", "license": "Apache 2.0 License with LLVM exceptions", "devDependencies": { "@types/node": "^18.19.41", diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index d5ca604798799..73e70cd961f4f 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -1,7 +1,7 @@ { "name": "lldb-dap", "displayName": "LLDB DAP", - "version": "0.2.13", + "version": "0.2.14", "publisher": "llvm-vs-code-extensions", "homepage": "https://lldb.llvm.org", "description": "Debugging with LLDB in Visual Studio Code", @@ -265,6 +265,9 @@ ] }, "breakpoints": [ + { + "language": "lldb.disassembly" + }, { "language": "ada" }, >From 3699524618ed76f969cc26a63610fe54e3605139 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Thu, 15 May 2025 00:36:10 +0200 Subject: [PATCH 04/12] remove include --- lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 4fefd8b440c7d..d69da5bd02c1e 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -12,8 +12,6 @@ #include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" -#include -#include #include namespace lldb_dap { >From 61623deb7e249a8ca0c63e3f66955790da5e4ced Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sat, 17 May 2025 21:05:27 +0200 Subject: [PATCH 05/12] use load address as sourceReference --- lldb/include/lldb/API/SBFileSpec.h | 3 + lldb/source/API/SBFileSpec.cpp | 8 ++ lldb/tools/lldb-dap/Breakpoint.cpp | 18 +---- .../Handler/BreakpointLocationsHandler.cpp | 11 +-- .../Handler/SetBreakpointsRequestHandler.cpp | 11 +-- .../lldb-dap/Handler/SourceRequestHandler.cpp | 18 ++--- lldb/tools/lldb-dap/JSONUtils.cpp | 75 +++++++++++++------ lldb/tools/lldb-dap/JSONUtils.h | 14 ++++ 8 files changed, 96 insertions(+), 62 deletions(-) diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index 36641843aabeb..303cb7d712cbf 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -10,6 +10,7 @@ #define LLDB_API_SBFILESPEC_H #include "lldb/API/SBDefines.h" +#include "lldb/API/SBStream.h" namespace lldb { @@ -53,6 +54,8 @@ class LLDB_API SBFileSpec { uint32_t GetPath(char *dst_path, size_t dst_len) const; + bool GetPath(lldb::SBStream &dst_path) const; + static int ResolvePath(const char *src_path, char *dst_path, size_t dst_len); bool GetDescription(lldb::SBStream &description) const; diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp index a7df9afc4b8eb..cb44dac1d4fcc 100644 --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -19,6 +19,7 @@ #include #include +#include using namespace lldb; using namespace lldb_private; @@ -147,6 +148,13 @@ uint32_t SBFileSpec::GetPath(char *dst_path, size_t dst_len) const { return result; } +bool SBFileSpec::GetPath(SBStream &dst_path) const { + LLDB_INSTRUMENT_VA(this, dst_path); + + std::string path = m_opaque_up->GetPath(); + return dst_path->PutCString(path.c_str()) > 0; +} + const lldb_private::FileSpec *SBFileSpec::operator->() const { return m_opaque_up.get(); } diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 87fcd15b0a568..a54a34e0f936d 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -79,27 +79,15 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { breakpoint.source = CreateSource(line_entry); } else { // Breakpoint made by assembly - auto symbol_context = bp_addr.GetSymbolContext( - lldb::eSymbolContextSymbol | lldb::eSymbolContextModule); - if (symbol_context.IsValid()) { - auto symbol = symbol_context.GetSymbol(); + auto symbol = bp_addr.GetSymbol(); + if (symbol.IsValid()) { breakpoint.line = m_bp.GetTarget() .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) .GetSize() + 1; - protocol::Source source; - source.name = symbol.GetName(); - auto module = symbol_context.GetModule(); - if (module.IsValid()) { - std::string path = module.GetFileSpec().GetDirectory(); - path += "/"; - path += module.GetFileSpec().GetFilename(); - source.path = std::move(path); - } - - breakpoint.source = std::move(source); + breakpoint.source = CreateAssemblySource(m_dap.target, bp_addr); } } } diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 06ada47a6f27f..c4d658caeee2d 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "LLDBUtils.h" #include "RequestHandler.h" #include @@ -108,15 +107,11 @@ template void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( llvm::SmallVector, N> &locations, int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { - lldb::SBProcess process = dap.target.GetProcess(); - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - - if (!frame.IsValid()) + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) return; - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) return; diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index d69da5bd02c1e..7b401f06e9a85 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -9,7 +9,6 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" -#include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" #include @@ -99,15 +98,11 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( std::vector response_breakpoints; int64_t sourceReference = source.sourceReference.value_or(0); - lldb::SBProcess process = dap.target.GetProcess(); - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - - if (!frame.IsValid()) + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) return response_breakpoints; - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) return response_breakpoints; // Not yet supporting breakpoints in assembly // without a valid symbol diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp index fb396a3dc8862..9249e2aa6fef7 100644 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp @@ -11,6 +11,7 @@ #include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" +#include "lldb/API/SBAddress.h" #include "lldb/API/SBExecutionContext.h" #include "lldb/API/SBFrame.h" #include "lldb/API/SBInstructionList.h" @@ -19,6 +20,7 @@ #include "lldb/API/SBSymbol.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" +#include "lldb/lldb-types.h" #include "llvm/Support/Error.h" namespace lldb_dap { @@ -34,18 +36,14 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { return llvm::make_error( "invalid arguments, expected source.sourceReference to be set"); - lldb::SBProcess process = dap.target.GetProcess(); - // Upper 32 bits is the thread index ID - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(source)); - // Lower 32 bits is the frame index - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(source)); - if (!frame.IsValid()) + lldb::SBAddress address(source, dap.target); + if (!address.IsValid()) return llvm::make_error("source not found"); + lldb::SBSymbol symbol = address.GetSymbol(); + lldb::SBStream stream; - lldb::SBExecutionContext exe_ctx(frame); - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBExecutionContext exe_ctx(dap.target); if (symbol.IsValid()) { lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); @@ -53,7 +51,7 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { } else { // No valid symbol, just return the disassembly. lldb::SBInstructionList insts = dap.target.ReadInstructions( - frame.GetPCAddress(), dap.number_of_assembly_lines_for_nodebug); + address, dap.number_of_assembly_lines_for_nodebug); insts.GetDescription(stream, exe_ctx); } diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 714947a4d3b9c..c8151c3d64ea4 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -490,6 +490,13 @@ CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp) { return filter; } +static std::string GetLoadAddressString(const lldb::addr_t addr) { + std::string result; + llvm::raw_string_ostream os(result); + os << llvm::format_hex(addr, 18); + return result; +} + protocol::Source CreateSource(const lldb::SBFileSpec &file) { protocol::Source source; if (file.IsValid()) { @@ -516,6 +523,43 @@ protocol::Source CreateSource(llvm::StringRef source_path) { return source; } +protocol::Source CreateAssemblySource(const lldb::SBTarget &target, + lldb::SBAddress &address) { + protocol::Source source; + + auto symbol = address.GetSymbol(); + std::string name; + if (symbol.IsValid()) { + source.sourceReference = symbol.GetStartAddress().GetLoadAddress(target); + name = symbol.GetName(); + } else { + const auto load_addr = address.GetLoadAddress(target); + source.sourceReference = load_addr; + name = GetLoadAddressString(load_addr); + } + + lldb::SBModule module = address.GetModule(); + if (module.IsValid()) { + lldb::SBFileSpec file_spec = module.GetFileSpec(); + if (file_spec.IsValid()) { + lldb::SBStream module_path; + if (file_spec.GetPath(module_path)) { + std::string path = module_path.GetData(); + source.path = path + '`' + name; + } + } + } + + source.name = std::move(name); + + // Mark the source as deemphasized since users will only be able to view + // assembly for these frames. + source.presentationHint = + protocol::Source::PresentationHint::eSourcePresentationHintDeemphasize; + + return source; +} + bool ShouldDisplayAssemblySource( const lldb::SBLineEntry &line_entry, lldb::StopDisassemblyType stop_disassembly_display) { @@ -619,12 +663,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, frame_name = name; } - if (frame_name.empty()) { + if (frame_name.empty()) // If the function name is unavailable, display the pc address as a 16-digit // hex string, e.g. "0x0000000000012345" - llvm::raw_string_ostream os(frame_name); - os << llvm::format_hex(frame.GetPC(), 18); - } + frame_name = GetLoadAddressString(frame.GetPC()); // We only include `[opt]` if a custom frame format is not specified. if (!format && frame.GetFunction().GetIsOptimized()) @@ -641,17 +683,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, } else if (frame.GetSymbol().IsValid()) { // If no source is associated with the frame, use the DAPFrameID to track // the 'source' and generate assembly. - llvm::json::Object source; - EmplaceSafeString(source, "name", frame_name); - char buf[PATH_MAX] = {0}; - size_t size = frame.GetModule().GetFileSpec().GetPath(buf, PATH_MAX); - EmplaceSafeString(source, "path", - std::string(buf, size) + '`' + frame_name); - source.try_emplace("sourceReference", MakeDAPFrameID(frame)); - // Mark the source as deemphasized since users will only be able to view - // assembly for these frames. - EmplaceSafeString(source, "presentationHint", "deemphasize"); - object.try_emplace("source", std::move(source)); + auto frame_address = frame.GetPCAddress(); + object.try_emplace("source", CreateAssemblySource( + frame.GetThread().GetProcess().GetTarget(), + frame_address)); // Calculate the line of the current PC from the start of the current // symbol. @@ -665,12 +700,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, object.try_emplace("column", 1); } else { // No valid line entry or symbol. - llvm::json::Object source; - EmplaceSafeString(source, "name", frame_name); - source.try_emplace("sourceReference", MakeDAPFrameID(frame)); - EmplaceSafeString(source, "presentationHint", "deemphasize"); - object.try_emplace("source", std::move(source)); - + auto frame_address = frame.GetPCAddress(); + object.try_emplace("source", CreateAssemblySource( + frame.GetThread().GetProcess().GetTarget(), + frame_address)); object.try_emplace("line", 1); object.try_emplace("column", 1); } diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h index 783f291338d8c..ac9b39739104f 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -269,6 +269,20 @@ protocol::Source CreateSource(const lldb::SBLineEntry &line_entry); /// definition outlined by Microsoft. protocol::Source CreateSource(llvm::StringRef source_path); +/// Create a "Source" object for a given frame, using its assembly for source. +/// +/// \param[in] target +/// The relevant target. +/// +/// \param[in] address +/// The address to use when creating the "Source" object. +/// +/// \return +/// A "Source" JSON object that follows the formal JSON +/// definition outlined by Microsoft. +protocol::Source CreateAssemblySource(const lldb::SBTarget &target, + lldb::SBAddress &address); + /// Return true if the given line entry should be displayed as assembly. /// /// \param[in] line_entry >From f5fd76de3ad25b9cbf6ce065e06c98ff30b070a8 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 02:22:19 +0200 Subject: [PATCH 06/12] add breakpoint-assembly test --- .../test/tools/lldb-dap/dap_server.py | 7 ++++ .../test/tools/lldb-dap/lldbdap_testcase.py | 10 +++++ .../lldb-dap/breakpoint-assembly/Makefile | 3 ++ .../TestDAP_breakpointAssembly.py | 42 +++++++++++++++++++ .../tools/lldb-dap/breakpoint-assembly/main.c | 14 +++++++ .../breakpoint/TestDAP_setBreakpoints.py | 1 + .../TestDAP_setExceptionBreakpoints.py | 1 + .../TestDAP_setFunctionBreakpoints.py | 1 + 8 files changed, 79 insertions(+) create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index 70fd0b0c419db..4a907a5e36901 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -955,6 +955,13 @@ def request_setBreakpoints(self, file_path, line_array, data=None): """ (dir, base) = os.path.split(file_path) source_dict = {"name": base, "path": file_path} + return self.request_setBreakpoints_with_source(source_dict, line_array, data) + + def request_setBreakpointsAssembly(self, sourceReference, line_array, data=None): + source_dict = {"sourceReference": sourceReference} + return self.request_setBreakpoints_with_source(source_dict, line_array, data) + + def request_setBreakpoints_with_source(self, source_dict, line_array, data=None): args_dict = { "source": source_dict, "sourceModified": False, diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index afdc746ed0d0d..427f66a7da0c8 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -63,6 +63,16 @@ def set_source_breakpoints(self, source_path, lines, data=None): for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) return breakpoint_ids + + def set_source_breakpoints_assembly(self, source_reference, lines, data=None): + response = self.dap_server.request_setBreakpointsAssembly(source_reference, lines, data) + if response is None: + return [] + breakpoints = response["body"]["breakpoints"] + breakpoint_ids = [] + for breakpoint in breakpoints: + breakpoint_ids.append("%i" % (breakpoint["id"])) + return breakpoint_ids def set_function_breakpoints(self, functions, condition=None, hitCondition=None): """Sets breakpoints by function name given an array of function names diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile new file mode 100644 index 0000000000000..10495940055b6 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py new file mode 100644 index 0000000000000..ba9df3a18590b --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py @@ -0,0 +1,42 @@ +""" +Test lldb-dap setBreakpoints request +""" + + +import dap_server +import shutil +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +import lldbdap_testcase +import os + + +class TestDAP_setBreakpointsAssembly(lldbdap_testcase.DAPTestCaseBase): + # @skipIfWindows + def test_functionality(self): + """Tests hitting assembly source breakpoints""" + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + + self.dap_server.request_evaluate( + "`settings set stop-disassembly-display no-debuginfo", context="repl" + ) + + assmebly_func_breakpoints = self.set_function_breakpoints(["assembly_func"]) + self.continue_to_breakpoints(assmebly_func_breakpoints) + + assembly_func_frame = self.get_stackFrames()[0] + self.assertIn( + "sourceReference", + assembly_func_frame.get("source"), + "Expected assembly source frame", + ) + + line = assembly_func_frame["line"] + + # Set an assembly breakpoint in the next line and check that it's hit + assembly_breakpoint_ids = self.set_source_breakpoints_assembly( + assembly_func_frame["source"]["sourceReference"], [line + 1] + ) + self.continue_to_breakpoints(assembly_breakpoint_ids) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c new file mode 100644 index 0000000000000..350739006f903 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c @@ -0,0 +1,14 @@ +#include + +__attribute__((nodebug)) int assembly_func(int n) { + n += 1; + n += 2; + n += 3; + + return n; +} + +int main(int argc, char const *argv[]) { + assembly_func(10); + return 0; +} diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index 26df2573555df..aae1251b17c93 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,6 +12,7 @@ import os + at skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py index 92ac66cd44c5d..4dc8c5b3c7ded 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py @@ -10,6 +10,7 @@ import lldbdap_testcase + at skip("Temporarily disable the breakpoint tests") class TestDAP_setExceptionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_functionality(self): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index 946595f639edc..baaca4d974d5d 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,6 +10,7 @@ import lldbdap_testcase + at skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): >From 40f68e418bfbb6564b3834382c4a33a3104fc33d Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 10:23:11 +0200 Subject: [PATCH 07/12] python format --- .../lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index 427f66a7da0c8..3bf649a087fdb 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -63,9 +63,11 @@ def set_source_breakpoints(self, source_path, lines, data=None): for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) return breakpoint_ids - + def set_source_breakpoints_assembly(self, source_reference, lines, data=None): - response = self.dap_server.request_setBreakpointsAssembly(source_reference, lines, data) + response = self.dap_server.request_setBreakpointsAssembly( + source_reference, lines, data + ) if response is None: return [] breakpoints = response["body"]["breakpoints"] >From 199512fd7a0900d45070b95dd52ef5ef136e2719 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 10:54:43 +0200 Subject: [PATCH 08/12] restore SBFileSpec and fix assembly breakpoints CR --- lldb/include/lldb/API/SBFileSpec.h | 2 - lldb/source/API/SBFileSpec.cpp | 7 --- lldb/tools/lldb-dap/DAP.h | 2 +- .../Handler/BreakpointLocationsHandler.cpp | 47 ++++++++++--------- lldb/tools/lldb-dap/Handler/RequestHandler.h | 17 ++++--- .../Handler/SetBreakpointsRequestHandler.cpp | 9 ++-- lldb/tools/lldb-dap/JSONUtils.cpp | 6 +-- lldb/tools/lldb-dap/LLDBUtils.cpp | 10 ++++ lldb/tools/lldb-dap/LLDBUtils.h | 10 ++++ 9 files changed, 60 insertions(+), 50 deletions(-) diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index 303cb7d712cbf..1bb28b2ddab01 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -54,8 +54,6 @@ class LLDB_API SBFileSpec { uint32_t GetPath(char *dst_path, size_t dst_len) const; - bool GetPath(lldb::SBStream &dst_path) const; - static int ResolvePath(const char *src_path, char *dst_path, size_t dst_len); bool GetDescription(lldb::SBStream &description) const; diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp index cb44dac1d4fcc..f18857f59171a 100644 --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -148,13 +148,6 @@ uint32_t SBFileSpec::GetPath(char *dst_path, size_t dst_len) const { return result; } -bool SBFileSpec::GetPath(SBStream &dst_path) const { - LLDB_INSTRUMENT_VA(this, dst_path); - - std::string path = m_opaque_up->GetPath(); - return dst_path->PutCString(path.c_str()) > 0; -} - const lldb_private::FileSpec *SBFileSpec::operator->() const { return m_opaque_up.get(); } diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index b0fe265b7bca1..20f95be792f41 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -222,7 +222,7 @@ struct DAP { /// @} /// Number of lines of assembly code to show when no debug info is available. - uint32_t number_of_assembly_lines_for_nodebug = 32; + static constexpr uint32_t number_of_assembly_lines_for_nodebug = 32; /// Creates a new DAP sessions. /// diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index c4d658caeee2d..794b83a9e0e1e 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -8,6 +8,7 @@ #include "DAP.h" #include "RequestHandler.h" +#include #include namespace lldb_dap { @@ -24,15 +25,15 @@ BreakpointLocationsRequestHandler::Run( uint32_t end_column = args.endColumn.value_or(std::numeric_limits::max()); - // Find all relevant lines & columns - llvm::SmallVector, 8> locations; - if (args.source.sourceReference) { - AddAssemblyBreakpointLocations(locations, *args.source.sourceReference, - start_line, end_line); - } else { + // Find all relevant lines & columns. + std::vector> locations; + if (args.source.sourceReference) + locations = GetAssemblyBreakpointLocations(*args.source.sourceReference, + start_line, end_line); + else { std::string path = args.source.path.value_or(""); - AddSourceBreakpointLocations(locations, std::move(path), start_line, - start_column, end_line, end_column); + locations = GetSourceBreakpointLocations( + std::move(path), start_line, start_column, end_line, end_column); } // The line entries are sorted by addresses, but we must return the list @@ -41,23 +42,19 @@ BreakpointLocationsRequestHandler::Run( locations.erase(llvm::unique(locations), locations.end()); std::vector breakpoint_locations; - for (auto &l : locations) { - protocol::BreakpointLocation lc; - lc.line = l.first; - lc.column = l.second; - breakpoint_locations.push_back(std::move(lc)); - } + for (auto &l : locations) + breakpoint_locations.push_back( + {l.first, l.second, std::nullopt, std::nullopt}); return protocol::BreakpointLocationsResponseBody{ /*breakpoints=*/std::move(breakpoint_locations)}; } -template -void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( - llvm::SmallVector, N> &locations, +std::vector> +BreakpointLocationsRequestHandler::GetSourceBreakpointLocations( std::string path, uint32_t start_line, uint32_t start_column, uint32_t end_line, uint32_t end_column) const { - + std::vector> locations; lldb::SBFileSpec file_spec(path.c_str(), true); lldb::SBSymbolContextList compile_units = dap.target.FindCompileUnits(file_spec); @@ -101,19 +98,21 @@ void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( locations.emplace_back(line, column); } } + + return locations; } -template -void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( - llvm::SmallVector, N> &locations, +std::vector> +BreakpointLocationsRequestHandler::GetAssemblyBreakpointLocations( int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { + std::vector> locations; lldb::SBAddress address(sourceReference, dap.target); if (!address.IsValid()) - return; + return locations; lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) - return; + return locations; // start_line is relative to the symbol's start address lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); @@ -121,6 +120,8 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( ++i) { locations.emplace_back(i, 1); } + + return locations; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 80898d1ee5ef1..e708abb50d5c0 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -23,6 +23,7 @@ #include #include #include +#include template struct is_optional : std::false_type {}; @@ -234,15 +235,13 @@ class BreakpointLocationsRequestHandler llvm::Expected Run(const protocol::BreakpointLocationsArguments &args) const override; - template - void AddSourceBreakpointLocations( - llvm::SmallVector, N> &locations, - std::string path, uint32_t start_line, uint32_t start_column, - uint32_t end_line, uint32_t end_column) const; - template - void AddAssemblyBreakpointLocations( - llvm::SmallVector, N> &locations, - int64_t sourceReference, uint32_t start_line, uint32_t end_line) const; + std::vector> + GetSourceBreakpointLocations(std::string path, uint32_t start_line, + uint32_t start_column, uint32_t end_line, + uint32_t end_column) const; + std::vector> + GetAssemblyBreakpointLocations(int64_t sourceReference, uint32_t start_line, + uint32_t end_line) const; }; class CompletionsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 7b401f06e9a85..bf0b584753c07 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -103,9 +103,10 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( return response_breakpoints; lldb::SBSymbol symbol = address.GetSymbol(); - if (!symbol.IsValid()) - return response_breakpoints; // Not yet supporting breakpoints in assembly - // without a valid symbol + if (!symbol.IsValid()) { + // Not yet supporting breakpoints in assembly without a valid symbol. + return response_breakpoints; + } llvm::DenseMap request_bps; if (breakpoints) { @@ -115,7 +116,7 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( const auto [iv, inserted] = dap.assembly_breakpoints[sourceReference].try_emplace( src_bp.GetLine(), src_bp); - // We check if this breakpoint already exists to update it + // We check if this breakpoint already exists to update it. if (inserted) iv->getSecond().SetBreakpoint(symbol); else diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index c8151c3d64ea4..1d2a6ff60e502 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -542,11 +542,9 @@ protocol::Source CreateAssemblySource(const lldb::SBTarget &target, if (module.IsValid()) { lldb::SBFileSpec file_spec = module.GetFileSpec(); if (file_spec.IsValid()) { - lldb::SBStream module_path; - if (file_spec.GetPath(module_path)) { - std::string path = module_path.GetData(); + std::string path = GetSBFileSpecPath(file_spec); + if (!path.empty()) source.path = path + '`' + name; - } } } diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp index 0e7bb2b9058a7..3c7623ec1215d 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.cpp +++ b/lldb/tools/lldb-dap/LLDBUtils.cpp @@ -20,6 +20,7 @@ #include "llvm/Support/JSON.h" #include "llvm/Support/raw_ostream.h" +#include #include #include @@ -242,4 +243,13 @@ ScopeSyncMode::ScopeSyncMode(lldb::SBDebugger &debugger) ScopeSyncMode::~ScopeSyncMode() { m_debugger.SetAsync(m_async); } +std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec) { + const auto directory_length = ::strlen(file_spec.GetDirectory()); + const auto file_name_length = ::strlen(file_spec.GetFilename()); + + std::string path(directory_length + file_name_length + 2, '\0'); + file_spec.GetPath(path.data(), path.length()); + return path; +} + } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/LLDBUtils.h b/lldb/tools/lldb-dap/LLDBUtils.h index 711fc6051231c..7fdf4b859ee61 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.h +++ b/lldb/tools/lldb-dap/LLDBUtils.h @@ -13,6 +13,7 @@ #include "lldb/API/SBDebugger.h" #include "lldb/API/SBEnvironment.h" #include "lldb/API/SBError.h" +#include "lldb/API/SBFileSpec.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" @@ -161,6 +162,15 @@ uint32_t GetLLDBFrameID(uint64_t dap_frame_id); lldb::SBEnvironment GetEnvironmentFromArguments(const llvm::json::Object &arguments); +/// Gets an SBFileSpec and returns its path as a string. +/// +/// \param[in] file_spec +/// The file spec. +/// +/// \return +/// The file path as a string. +std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec); + /// Helper for sending telemetry to lldb server, if client-telemetry is enabled. class TelemetryDispatcher { public: >From dbad33b314bb59f6e0d22fd07dddb35e2a0e30d9 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 12:57:59 +0200 Subject: [PATCH 09/12] abstracted source breakpoints maps by DAP --- lldb/tools/lldb-dap/Breakpoint.cpp | 4 +- lldb/tools/lldb-dap/DAP.cpp | 75 +++++++++++ lldb/tools/lldb-dap/DAP.h | 29 +++- lldb/tools/lldb-dap/Handler/RequestHandler.h | 9 -- .../Handler/SetBreakpointsRequestHandler.cpp | 125 +----------------- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 54 +++++--- lldb/tools/lldb-dap/SourceBreakpoint.h | 7 +- 7 files changed, 140 insertions(+), 163 deletions(-) diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index a54a34e0f936d..fd7531f42c518 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -71,10 +71,10 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { auto line_entry = bp_addr.GetLineEntry(); if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) { const auto line = line_entry.GetLine(); - if (line != UINT32_MAX) + if (line != LLDB_INVALID_LINE_NUMBER) breakpoint.line = line; const auto column = line_entry.GetColumn(); - if (column != 0) + if (column != LLDB_INVALID_COLUMN_NUMBER) breakpoint.column = column; breakpoint.source = CreateSource(line_entry); } else { diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 0d5eba6c40961..1fe46fc619d73 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1620,6 +1620,81 @@ void DAP::EventThread() { } } +std::vector DAP::SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints) { + std::vector response_breakpoints; + if (source.sourceReference) { + // breakpoint set by assembly source. + auto &existing_breakpoints_pos = + m_source_assembly_breakpoints[*source.sourceReference]; + response_breakpoints = + SetSourceBreakpoints(source, breakpoints, existing_breakpoints_pos); + } else { + // breakpoint set by a regular source file. + const auto path = source.path.value_or(""); + auto &existing_breakpoints_pos = m_source_breakpoints[path]; + response_breakpoints = + SetSourceBreakpoints(source, breakpoints, existing_breakpoints_pos); + } + + return response_breakpoints; +} + +std::vector DAP::SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints, + SourceBreakpointMap &existing_breakpoints) { + std::vector response_breakpoints; + + SourceBreakpointMap request_breakpoints; + if (breakpoints) { + for (const auto &bp : *breakpoints) { + SourceBreakpoint src_bp(*this, bp, source); + std::pair bp_pos(src_bp.GetLine(), + src_bp.GetColumn()); + request_breakpoints.try_emplace(bp_pos, src_bp); + + const auto [iv, inserted] = + existing_breakpoints.try_emplace(bp_pos, src_bp); + // We check if this breakpoint already exists to update it. + if (inserted) + iv->second.SetBreakpoint(); + else + iv->second.UpdateBreakpoint(src_bp); + + protocol::Breakpoint response_breakpoint = + iv->second.ToProtocolBreakpoint(); + response_breakpoint.source = source; + + if (!response_breakpoint.line && + src_bp.GetLine() != LLDB_INVALID_LINE_NUMBER) + response_breakpoint.line = src_bp.GetLine(); + if (!response_breakpoint.column && + src_bp.GetColumn() != LLDB_INVALID_COLUMN_NUMBER) + response_breakpoint.column = src_bp.GetColumn(); + response_breakpoints.push_back(response_breakpoint); + } + } + + // Delete any breakpoints in this source file that aren't in the + // request_bps set. There is no call to remove breakpoints other than + // calling this function with a smaller or empty "breakpoints" list. + for (auto it = existing_breakpoints.begin(); + it != existing_breakpoints.end();) { + auto request_pos = request_breakpoints.find(it->first); + if (request_pos == request_breakpoints.end()) { + // This breakpoint no longer exists in this source file, delete it + target.BreakpointDelete(it->second.GetID()); + it = existing_breakpoints.erase(it); + } else { + ++it; + } + } + + return response_breakpoints; +} + void DAP::RegisterRequests() { RegisterRequest(); RegisterRequest(); diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 20f95be792f41..3a0a7fc1678ba 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -60,7 +60,7 @@ namespace lldb_dap { -typedef llvm::DenseMap, SourceBreakpoint> +typedef std::map, SourceBreakpoint> SourceBreakpointMap; typedef llvm::StringMap FunctionBreakpointMap; typedef llvm::DenseMap @@ -168,9 +168,6 @@ struct DAP { lldb::SBTarget target; Variables variables; lldb::SBBroadcaster broadcaster; - llvm::StringMap source_breakpoints; - llvm::DenseMap> - assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; @@ -428,7 +425,28 @@ struct DAP { void StartEventThread(); void StartProgressEventThread(); + /// Sets the given protocol `breakpoints` in the given `source`, while + /// removing any existing breakpoints in the given source if they are not in + /// `breakpoint`. + /// + /// \param[in] source + /// The relevant source of the breakpoints. + /// + /// \param[in] breakpoints + /// The breakpoints to set. + /// + /// \return a vector of the breakpoints that were set. + std::vector SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> + &breakpoints); + private: + std::vector SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints, + SourceBreakpointMap &existing_breakpoints); + /// Registration of request handler. /// @{ void RegisterRequests(); @@ -457,6 +475,9 @@ struct DAP { std::mutex m_active_request_mutex; const protocol::Request *m_active_request; + + llvm::StringMap m_source_breakpoints; + llvm::DenseMap m_source_assembly_breakpoints; }; } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index e708abb50d5c0..54f728414021e 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -388,15 +388,6 @@ class SetBreakpointsRequestHandler } llvm::Expected Run(const protocol::SetBreakpointsArguments &args) const override; - - std::vector SetSourceBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const; - std::vector SetAssemblyBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const; }; class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index bf0b584753c07..0ff88f62f8f51 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -22,130 +22,9 @@ namespace lldb_dap { llvm::Expected SetBreakpointsRequestHandler::Run( const protocol::SetBreakpointsArguments &args) const { - const auto &source = args.source; - std::vector response_breakpoints; - if (source.sourceReference) - response_breakpoints = SetAssemblyBreakpoints(source, args.breakpoints); - else if (source.path) - response_breakpoints = SetSourceBreakpoints(source, args.breakpoints); - + const auto response_breakpoints = + dap.SetSourceBreakpoints(args.source, args.breakpoints); return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; } -std::vector -SetBreakpointsRequestHandler::SetSourceBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const { - std::vector response_breakpoints; - std::string path = source.path.value_or(""); - - // Decode the source breakpoint infos for this "setBreakpoints" request - SourceBreakpointMap request_bps; - // "breakpoints" may be unset, in which case we treat it the same as being set - // to an empty array. - if (breakpoints) { - for (const auto &bp : *breakpoints) { - SourceBreakpoint src_bp(dap, bp); - std::pair bp_pos(src_bp.GetLine(), - src_bp.GetColumn()); - request_bps.try_emplace(bp_pos, src_bp); - const auto [iv, inserted] = - dap.source_breakpoints[path].try_emplace(bp_pos, src_bp); - // We check if this breakpoint already exists to update it - if (inserted) - iv->getSecond().SetBreakpoint(path.data()); - else - iv->getSecond().UpdateBreakpoint(src_bp); - - protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - - // Use the path from the request if it is set - if (!path.empty()) - response_bp.source = CreateSource(path); - - if (!response_bp.line) - response_bp.line = src_bp.GetLine(); - if (!response_bp.column) - response_bp.column = src_bp.GetColumn(); - response_breakpoints.push_back(response_bp); - } - } - - // Delete any breakpoints in this source file that aren't in the - // request_bps set. There is no call to remove breakpoints other than - // calling this function with a smaller or empty "breakpoints" list. - auto old_src_bp_pos = dap.source_breakpoints.find(path); - if (old_src_bp_pos != dap.source_breakpoints.end()) { - for (auto &old_bp : old_src_bp_pos->second) { - auto request_pos = request_bps.find(old_bp.first); - if (request_pos == request_bps.end()) { - // This breakpoint no longer exists in this source file, delete it - dap.target.BreakpointDelete(old_bp.second.GetID()); - old_src_bp_pos->second.erase(old_bp.first); - } - } - } - - return response_breakpoints; -} - -std::vector -SetBreakpointsRequestHandler::SetAssemblyBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const { - std::vector response_breakpoints; - int64_t sourceReference = source.sourceReference.value_or(0); - - lldb::SBAddress address(sourceReference, dap.target); - if (!address.IsValid()) - return response_breakpoints; - - lldb::SBSymbol symbol = address.GetSymbol(); - if (!symbol.IsValid()) { - // Not yet supporting breakpoints in assembly without a valid symbol. - return response_breakpoints; - } - - llvm::DenseMap request_bps; - if (breakpoints) { - for (const auto &bp : *breakpoints) { - SourceBreakpoint src_bp(dap, bp); - request_bps.try_emplace(src_bp.GetLine(), src_bp); - const auto [iv, inserted] = - dap.assembly_breakpoints[sourceReference].try_emplace( - src_bp.GetLine(), src_bp); - // We check if this breakpoint already exists to update it. - if (inserted) - iv->getSecond().SetBreakpoint(symbol); - else - iv->getSecond().UpdateBreakpoint(src_bp); - - protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - response_bp.source = source; - if (!response_bp.line) - response_bp.line = src_bp.GetLine(); - if (bp.column) - response_bp.column = *bp.column; - response_breakpoints.push_back(response_bp); - } - } - - // Delete existing breakpoints for this sourceReference that are not in the - // request_bps set. - auto old_src_bp_pos = dap.assembly_breakpoints.find(sourceReference); - if (old_src_bp_pos != dap.assembly_breakpoints.end()) { - for (auto &old_bp : old_src_bp_pos->second) { - auto request_pos = request_bps.find(old_bp.first); - if (request_pos == request_bps.end()) { - dap.target.BreakpointDelete(old_bp.second.GetID()); - old_src_bp_pos->second.erase(old_bp.first); - } - } - } - - return response_breakpoints; -} - } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 938b8fb8bcdda..50ebfbe8aef20 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -29,39 +29,49 @@ namespace lldb_dap { SourceBreakpoint::SourceBreakpoint(DAP &dap, - const protocol::SourceBreakpoint &breakpoint) + const protocol::SourceBreakpoint &breakpoint, + const protocol::Source &source) : Breakpoint(dap, breakpoint.condition, breakpoint.hitCondition), - m_log_message(breakpoint.logMessage.value_or("")), + m_log_message(breakpoint.logMessage.value_or("")), m_source(source), m_line(breakpoint.line), m_column(breakpoint.column.value_or(LLDB_INVALID_COLUMN_NUMBER)) {} -void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) { - lldb::SBMutex lock = m_dap.GetAPIMutex(); - std::lock_guard guard(lock); - - lldb::SBFileSpecList module_list; - m_bp = m_dap.target.BreakpointCreateByLocation( - source_path.str().c_str(), m_line, m_column, 0, module_list); - if (!m_log_message.empty()) - SetLogMessage(); - Breakpoint::SetBreakpoint(); -} - -void SourceBreakpoint::SetBreakpoint(lldb::SBSymbol &symbol) { +void SourceBreakpoint::SetBreakpoint() { lldb::SBMutex lock = m_dap.GetAPIMutex(); std::lock_guard guard(lock); if (m_line == 0) return; - lldb::SBInstructionList inst_list = - m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); - if (inst_list.GetSize() < m_line) - return; - lldb::SBAddress address = - inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + if (m_source.sourceReference) { + // breakpoint set by assembly source. + lldb::SBAddress source_address(*m_source.sourceReference, m_dap.target); + if (!source_address.IsValid()) + return; + + lldb::SBSymbol symbol = source_address.GetSymbol(); + if (!symbol.IsValid()) { + // Not yet supporting breakpoints in assembly without a valid symbol. + return; + } + + lldb::SBInstructionList inst_list = + m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); + if (inst_list.GetSize() < m_line) + return; + + lldb::SBAddress address = + inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + + m_bp = m_dap.target.BreakpointCreateBySBAddress(address); + } else { + // breakpoint set by a regular source file. + const auto source_path = m_source.path.value_or(""); + lldb::SBFileSpecList module_list; + m_bp = m_dap.target.BreakpointCreateByLocation(source_path.c_str(), m_line, + m_column, 0, module_list); + } - m_bp = m_dap.target.BreakpointCreateBySBAddress(address); if (!m_log_message.empty()) SetLogMessage(); Breakpoint::SetBreakpoint(); diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h index 8589800e50983..3221ecbf28ece 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.h +++ b/lldb/tools/lldb-dap/SourceBreakpoint.h @@ -22,11 +22,11 @@ namespace lldb_dap { class SourceBreakpoint : public Breakpoint { public: - SourceBreakpoint(DAP &d, const protocol::SourceBreakpoint &breakpoint); + SourceBreakpoint(DAP &d, const protocol::SourceBreakpoint &breakpoint, + const protocol::Source &source); // Set this breakpoint in LLDB as a new breakpoint - void SetBreakpoint(const llvm::StringRef source_path); - void SetBreakpoint(lldb::SBSymbol &symbol); + void SetBreakpoint(); void UpdateBreakpoint(const SourceBreakpoint &request_bp); void SetLogMessage(); @@ -63,6 +63,7 @@ class SourceBreakpoint : public Breakpoint { std::string m_log_message; std::vector m_log_message_parts; + protocol::Source m_source; /// The original breakpoint source. uint32_t m_line; ///< The source line of the breakpoint or logpoint uint32_t m_column; ///< An optional source column of the breakpoint }; >From 2e9edca37c0953e2d2a6cf2d278bb353f1e0960b Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 13:39:05 +0200 Subject: [PATCH 10/12] improve assembvly breakpoint test to check clear --- .../TestDAP_breakpointAssembly.py | 17 +++++++++++++++-- .../tools/lldb-dap/breakpoint-assembly/main.c | 4 +++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py index ba9df3a18590b..dacc1cd8349f1 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py @@ -6,7 +6,7 @@ import dap_server import shutil from lldbsuite.test.decorators import * -from lldbsuite.test.lldbtest import * +from lldbsuite.test.lldbtest import line_number from lldbsuite.test import lldbutil import lldbdap_testcase import os @@ -23,6 +23,9 @@ def test_functionality(self): "`settings set stop-disassembly-display no-debuginfo", context="repl" ) + finish_line = line_number("main.c", "// Break here") + finish_breakpoints = self.set_source_breakpoints("main.c", [finish_line]) + assmebly_func_breakpoints = self.set_function_breakpoints(["assembly_func"]) self.continue_to_breakpoints(assmebly_func_breakpoints) @@ -36,7 +39,17 @@ def test_functionality(self): line = assembly_func_frame["line"] # Set an assembly breakpoint in the next line and check that it's hit + source_reference = assembly_func_frame["source"]["sourceReference"] assembly_breakpoint_ids = self.set_source_breakpoints_assembly( - assembly_func_frame["source"]["sourceReference"], [line + 1] + source_reference, [line + 1] ) self.continue_to_breakpoints(assembly_breakpoint_ids) + + # Continue again and verify it hits in the next function call + self.continue_to_breakpoints(assmebly_func_breakpoints) + self.continue_to_breakpoints(assembly_breakpoint_ids) + + # Clear the breakpoint and then check that the assembly breakpoint does not hit next time + self.set_source_breakpoints_assembly(source_reference, []) + self.continue_to_breakpoints(assmebly_func_breakpoints) + self.continue_to_breakpoints(finish_breakpoints) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c index 350739006f903..e3a21df11958f 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c @@ -10,5 +10,7 @@ __attribute__((nodebug)) int assembly_func(int n) { int main(int argc, char const *argv[]) { assembly_func(10); - return 0; + assembly_func(20); + assembly_func(30); + return 0; // Break here } >From 0515c6dc6e46b6296621e871b43286ae88ea9b6b Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 13:52:40 +0200 Subject: [PATCH 11/12] fix GetSBFileSpecPath extra char --- lldb/tools/lldb-dap/LLDBUtils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp index 3c7623ec1215d..fe0bcda19b4cd 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.cpp +++ b/lldb/tools/lldb-dap/LLDBUtils.cpp @@ -247,8 +247,8 @@ std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec) { const auto directory_length = ::strlen(file_spec.GetDirectory()); const auto file_name_length = ::strlen(file_spec.GetFilename()); - std::string path(directory_length + file_name_length + 2, '\0'); - file_spec.GetPath(path.data(), path.length()); + std::string path(directory_length + file_name_length + 1, '\0'); + file_spec.GetPath(path.data(), path.length() + 1); return path; } >From 9dbca55d01c7faddc9df4586ba25c6fac421d909 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 13:59:53 +0200 Subject: [PATCH 12/12] restore SBFileSpec changes --- lldb/include/lldb/API/SBFileSpec.h | 1 - lldb/source/API/SBFileSpec.cpp | 1 - lldb/tools/lldb-dap/DAP.cpp | 8 ++++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index 1bb28b2ddab01..36641843aabeb 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -10,7 +10,6 @@ #define LLDB_API_SBFILESPEC_H #include "lldb/API/SBDefines.h" -#include "lldb/API/SBStream.h" namespace lldb { diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp index f18857f59171a..a7df9afc4b8eb 100644 --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -19,7 +19,6 @@ #include #include -#include using namespace lldb; using namespace lldb_private; diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 1fe46fc619d73..d7ef886dd2419 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1626,16 +1626,16 @@ std::vector DAP::SetSourceBreakpoints( std::vector response_breakpoints; if (source.sourceReference) { // breakpoint set by assembly source. - auto &existing_breakpoints_pos = + auto &existing_breakpoints = m_source_assembly_breakpoints[*source.sourceReference]; response_breakpoints = - SetSourceBreakpoints(source, breakpoints, existing_breakpoints_pos); + SetSourceBreakpoints(source, breakpoints, existing_breakpoints); } else { // breakpoint set by a regular source file. const auto path = source.path.value_or(""); - auto &existing_breakpoints_pos = m_source_breakpoints[path]; + auto &existing_breakpoints = m_source_breakpoints[path]; response_breakpoints = - SetSourceBreakpoints(source, breakpoints, existing_breakpoints_pos); + SetSourceBreakpoints(source, breakpoints, existing_breakpoints); } return response_breakpoints; From lldb-commits at lists.llvm.org Sun May 18 05:01:44 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 05:01:44 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <6829cc28.170a0220.2a1e0b.493f@mx.google.com> https://github.com/eronnen updated https://github.com/llvm/llvm-project/pull/139969 >From d6325b3f6a8602fc96ad72acecfcccda1120614d Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sat, 10 May 2025 20:45:17 +0200 Subject: [PATCH 01/13] support assembly in BreakpointLocationsRequestHandler --- .../breakpoint/TestDAP_setBreakpoints.py | 1 - .../TestDAP_setExceptionBreakpoints.py | 1 - .../TestDAP_setFunctionBreakpoints.py | 1 - lldb/tools/lldb-dap/DAP.h | 3 + .../Handler/BreakpointLocationsHandler.cpp | 77 +++++++++++++++---- lldb/tools/lldb-dap/Handler/RequestHandler.h | 11 +++ .../lldb-dap/Handler/SourceRequestHandler.cpp | 4 +- 7 files changed, 76 insertions(+), 22 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index aae1251b17c93..26df2573555df 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,7 +12,6 @@ import os - at skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py index 4dc8c5b3c7ded..92ac66cd44c5d 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setExceptionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_functionality(self): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index baaca4d974d5d..946595f639edc 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 8f24c6cf82924..00aa4276852c5 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -219,6 +219,9 @@ struct DAP { llvm::StringSet<> modules; /// @} + /// Number of lines of assembly code to show when no debug info is available. + uint32_t number_of_assembly_lines_for_nodebug = 32; + /// Creates a new DAP sessions. /// /// \param[in] log diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 2ac886c3a5d2c..9eea549d72b00 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "JSONUtils.h" +#include "LLDBUtils.h" #include "RequestHandler.h" #include @@ -19,19 +19,50 @@ namespace lldb_dap { llvm::Expected BreakpointLocationsRequestHandler::Run( const protocol::BreakpointLocationsArguments &args) const { - std::string path = args.source.path.value_or(""); uint32_t start_line = args.line; uint32_t start_column = args.column.value_or(LLDB_INVALID_COLUMN_NUMBER); uint32_t end_line = args.endLine.value_or(start_line); uint32_t end_column = args.endColumn.value_or(std::numeric_limits::max()); + // Find all relevant lines & columns + llvm::SmallVector, 8> locations; + if (args.source.sourceReference) { + AddAssemblyBreakpointLocations(locations, *args.source.sourceReference, + start_line, end_line); + } else { + std::string path = args.source.path.value_or(""); + AddSourceBreakpointLocations(locations, std::move(path), start_line, + start_column, end_line, end_column); + } + + // The line entries are sorted by addresses, but we must return the list + // ordered by line / column position. + std::sort(locations.begin(), locations.end()); + locations.erase(llvm::unique(locations), locations.end()); + + std::vector breakpoint_locations; + for (auto &l : locations) { + protocol::BreakpointLocation lc; + lc.line = l.first; + lc.column = l.second; + breakpoint_locations.push_back(std::move(lc)); + } + + return protocol::BreakpointLocationsResponseBody{ + /*breakpoints=*/std::move(breakpoint_locations)}; +} + +template +void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const { + lldb::SBFileSpec file_spec(path.c_str(), true); lldb::SBSymbolContextList compile_units = dap.target.FindCompileUnits(file_spec); - // Find all relevant lines & columns - llvm::SmallVector, 8> locations; for (uint32_t c_idx = 0, c_limit = compile_units.GetSize(); c_idx < c_limit; ++c_idx) { const lldb::SBCompileUnit &compile_unit = @@ -71,22 +102,34 @@ BreakpointLocationsRequestHandler::Run( locations.emplace_back(line, column); } } +} - // The line entries are sorted by addresses, but we must return the list - // ordered by line / column position. - std::sort(locations.begin(), locations.end()); - locations.erase(llvm::unique(locations), locations.end()); +template +void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { + lldb::SBProcess process = dap.target.GetProcess(); + lldb::SBThread thread = + process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); + lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - std::vector breakpoint_locations; - for (auto &l : locations) { - protocol::BreakpointLocation lc; - lc.line = l.first; - lc.column = l.second; - breakpoint_locations.push_back(std::move(lc)); - } + if (!frame.IsValid()) + return; - return protocol::BreakpointLocationsResponseBody{ - /*breakpoints=*/std::move(breakpoint_locations)}; + lldb::SBSymbol symbol = frame.GetSymbol(); + if (symbol.IsValid()) { + lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); + } + } else { + for (uint32_t i = start_line - 1; + i < dap.number_of_assembly_lines_for_nodebug && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); + } + } } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index e6bccfe12f402..21753bc0552f9 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -16,6 +16,7 @@ #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/JSON.h" @@ -232,6 +233,16 @@ class BreakpointLocationsRequestHandler } llvm::Expected Run(const protocol::BreakpointLocationsArguments &args) const override; + + template + void AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const; + template + void AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const; }; class CompletionsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp index 0ddd87881a164..fb396a3dc8862 100644 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp @@ -52,8 +52,8 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { insts.GetDescription(stream, exe_ctx); } else { // No valid symbol, just return the disassembly. - lldb::SBInstructionList insts = - dap.target.ReadInstructions(frame.GetPCAddress(), 32); + lldb::SBInstructionList insts = dap.target.ReadInstructions( + frame.GetPCAddress(), dap.number_of_assembly_lines_for_nodebug); insts.GetDescription(stream, exe_ctx); } >From ee492031bee8106fb2a4ff22a8563005f5afd86c Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 11 May 2025 19:49:03 +0200 Subject: [PATCH 02/13] support assembly in SetBreakpointsRequestHandler --- lldb/tools/lldb-dap/DAP.h | 1 + .../Handler/BreakpointLocationsHandler.cpp | 20 ++--- lldb/tools/lldb-dap/Handler/RequestHandler.h | 9 ++ .../Handler/SetBreakpointsRequestHandler.cpp | 90 ++++++++++++++++++- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 22 +++++ lldb/tools/lldb-dap/SourceBreakpoint.h | 1 + 6 files changed, 127 insertions(+), 16 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 00aa4276852c5..5ce0e534611c1 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -169,6 +169,7 @@ struct DAP { Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; + llvm::DenseMap assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 9eea549d72b00..be02c47056310 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -117,18 +117,14 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( return; lldb::SBSymbol symbol = frame.GetSymbol(); - if (symbol.IsValid()) { - lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); - ++i) { - locations.emplace_back(i, 0); - } - } else { - for (uint32_t i = start_line - 1; - i < dap.number_of_assembly_lines_for_nodebug && i < (end_line - 1); - ++i) { - locations.emplace_back(i, 0); - } + if (!symbol.IsValid()) + return; + + // start_line is relative to the symbol's start address + lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); } } diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 21753bc0552f9..72843aaef8150 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -389,6 +389,15 @@ class SetBreakpointsRequestHandler } llvm::Expected Run(const protocol::SetBreakpointsArguments &args) const override; + + std::vector SetSourceBreakpoints( + const std::string &path, + const std::optional> &breakpoints) + const; + std::vector SetAssemblyBreakpoints( + int64_t sourceReference, + const std::optional> &breakpoints) + const; }; class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 86e090b66afe9..71f9e5578ef08 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -9,8 +9,11 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" +#include +#include #include namespace lldb_dap { @@ -23,15 +26,30 @@ llvm::Expected SetBreakpointsRequestHandler::Run( const protocol::SetBreakpointsArguments &args) const { const auto &source = args.source; - const auto path = source.path.value_or(""); + std::vector response_breakpoints; + if (source.sourceReference) + response_breakpoints = SetAssemblyBreakpoints( + source.sourceReference.value(), args.breakpoints); + else if (source.path) + response_breakpoints = + SetSourceBreakpoints(source.path.value(), args.breakpoints); + + return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; +} + +std::vector +SetBreakpointsRequestHandler::SetSourceBreakpoints( + const std::string &path, + const std::optional> &breakpoints) + const { std::vector response_breakpoints; // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; // "breakpoints" may be unset, in which case we treat it the same as being set // to an empty array. - if (args.breakpoints) { - for (const auto &bp : *args.breakpoints) { + if (breakpoints) { + for (const auto &bp : *breakpoints) { SourceBreakpoint src_bp(dap, bp); std::pair bp_pos(src_bp.GetLine(), src_bp.GetColumn()); @@ -73,7 +91,71 @@ SetBreakpointsRequestHandler::Run( } } - return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; + return response_breakpoints; +} + +std::vector +SetBreakpointsRequestHandler::SetAssemblyBreakpoints( + int64_t sourceReference, + const std::optional> &breakpoints) + const { + std::vector response_breakpoints; + + lldb::SBProcess process = dap.target.GetProcess(); + lldb::SBThread thread = + process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); + lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); + + if (!frame.IsValid()) + return response_breakpoints; + + lldb::SBSymbol symbol = frame.GetSymbol(); + if (!symbol.IsValid()) + return response_breakpoints; // Not yet supporting breakpoints in assembly + // without a valid symbol + + SourceBreakpointMap request_bps; + if (breakpoints) { + for (const auto &bp : *breakpoints) { + SourceBreakpoint src_bp(dap, bp); + std::pair bp_pos(src_bp.GetLine(), 0); + request_bps.try_emplace(bp_pos, src_bp); + const auto [iv, inserted] = + dap.assembly_breakpoints[sourceReference].try_emplace(bp_pos, src_bp); + // We check if this breakpoint already exists to update it + if (inserted) + iv->getSecond().SetBreakpoint(symbol); + else + iv->getSecond().UpdateBreakpoint(src_bp); + + protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); + protocol::Source source; + source.sourceReference = sourceReference; + source.name = symbol.GetName(); + response_bp.source = std::move(source); + + if (!response_bp.line) + response_bp.line = src_bp.GetLine(); + if (!response_bp.column) + response_bp.column = src_bp.GetColumn(); + response_breakpoints.push_back(response_bp); + } + } + + // Delete existing breakpoints for this sourceReference that are not in the + // request_bps set. + auto old_src_bp_pos = dap.assembly_breakpoints.find(sourceReference); + if (old_src_bp_pos != dap.assembly_breakpoints.end()) { + for (auto &old_bp : old_src_bp_pos->second) { + auto request_pos = request_bps.find(old_bp.first); + if (request_pos == request_bps.end()) { + dap.target.BreakpointDelete(old_bp.second.GetID()); + old_src_bp_pos->second.erase(old_bp.first); + } + } + } + + return response_breakpoints; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 4581c995b4260..938b8fb8bcdda 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -13,7 +13,9 @@ #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBFileSpecList.h" #include "lldb/API/SBFrame.h" +#include "lldb/API/SBInstruction.h" #include "lldb/API/SBMutex.h" +#include "lldb/API/SBSymbol.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" #include "lldb/API/SBValue.h" @@ -45,6 +47,26 @@ void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) { Breakpoint::SetBreakpoint(); } +void SourceBreakpoint::SetBreakpoint(lldb::SBSymbol &symbol) { + lldb::SBMutex lock = m_dap.GetAPIMutex(); + std::lock_guard guard(lock); + + if (m_line == 0) + return; + + lldb::SBInstructionList inst_list = + m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); + if (inst_list.GetSize() < m_line) + return; + lldb::SBAddress address = + inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + + m_bp = m_dap.target.BreakpointCreateBySBAddress(address); + if (!m_log_message.empty()) + SetLogMessage(); + Breakpoint::SetBreakpoint(); +} + void SourceBreakpoint::UpdateBreakpoint(const SourceBreakpoint &request_bp) { if (m_log_message != request_bp.m_log_message) { m_log_message = request_bp.m_log_message; diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h index 5b15296f861c5..8589800e50983 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.h +++ b/lldb/tools/lldb-dap/SourceBreakpoint.h @@ -26,6 +26,7 @@ class SourceBreakpoint : public Breakpoint { // Set this breakpoint in LLDB as a new breakpoint void SetBreakpoint(const llvm::StringRef source_path); + void SetBreakpoint(lldb::SBSymbol &symbol); void UpdateBreakpoint(const SourceBreakpoint &request_bp); void SetLogMessage(); >From dbb2f9bd55b3f86247e03b2610fca9576e124637 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Wed, 14 May 2025 23:51:41 +0200 Subject: [PATCH 03/13] fix resolving of assembly source breakpoints --- lldb/tools/lldb-dap/Breakpoint.cpp | 45 ++++++++++++++++--- lldb/tools/lldb-dap/DAP.h | 3 +- .../Handler/BreakpointLocationsHandler.cpp | 4 +- lldb/tools/lldb-dap/Handler/RequestHandler.h | 4 +- .../Handler/SetBreakpointsRequestHandler.cpp | 30 ++++++------- lldb/tools/lldb-dap/package-lock.json | 4 +- lldb/tools/lldb-dap/package.json | 5 ++- 7 files changed, 63 insertions(+), 32 deletions(-) diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 26d633d1d172e..87fcd15b0a568 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -9,10 +9,12 @@ #include "Breakpoint.h" #include "DAP.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "lldb/API/SBAddress.h" #include "lldb/API/SBBreakpointLocation.h" #include "lldb/API/SBLineEntry.h" #include "lldb/API/SBMutex.h" +#include "lldb/lldb-enumerations.h" #include "llvm/ADT/StringExtras.h" #include #include @@ -63,14 +65,43 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { std::string formatted_addr = "0x" + llvm::utohexstr(bp_addr.GetLoadAddress(m_bp.GetTarget())); breakpoint.instructionReference = formatted_addr; + + lldb::StopDisassemblyType stop_disassembly_display = + GetStopDisassemblyDisplay(m_dap.debugger); auto line_entry = bp_addr.GetLineEntry(); - const auto line = line_entry.GetLine(); - if (line != UINT32_MAX) - breakpoint.line = line; - const auto column = line_entry.GetColumn(); - if (column != 0) - breakpoint.column = column; - breakpoint.source = CreateSource(line_entry); + if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) { + const auto line = line_entry.GetLine(); + if (line != UINT32_MAX) + breakpoint.line = line; + const auto column = line_entry.GetColumn(); + if (column != 0) + breakpoint.column = column; + breakpoint.source = CreateSource(line_entry); + } else { + // Breakpoint made by assembly + auto symbol_context = bp_addr.GetSymbolContext( + lldb::eSymbolContextSymbol | lldb::eSymbolContextModule); + if (symbol_context.IsValid()) { + auto symbol = symbol_context.GetSymbol(); + breakpoint.line = + m_bp.GetTarget() + .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) + .GetSize() + + 1; + protocol::Source source; + source.name = symbol.GetName(); + + auto module = symbol_context.GetModule(); + if (module.IsValid()) { + std::string path = module.GetFileSpec().GetDirectory(); + path += "/"; + path += module.GetFileSpec().GetFilename(); + source.path = std::move(path); + } + + breakpoint.source = std::move(source); + } + } } return breakpoint; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 5ce0e534611c1..b0fe265b7bca1 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -169,7 +169,8 @@ struct DAP { Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; - llvm::DenseMap assembly_breakpoints; + llvm::DenseMap> + assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index be02c47056310..06ada47a6f27f 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -122,9 +122,9 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( // start_line is relative to the symbol's start address lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i <= (end_line - 1); ++i) { - locations.emplace_back(i, 0); + locations.emplace_back(i, 1); } } diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 72843aaef8150..80898d1ee5ef1 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -391,11 +391,11 @@ class SetBreakpointsRequestHandler Run(const protocol::SetBreakpointsArguments &args) const override; std::vector SetSourceBreakpoints( - const std::string &path, + const protocol::Source &source, const std::optional> &breakpoints) const; std::vector SetAssemblyBreakpoints( - int64_t sourceReference, + const protocol::Source &source, const std::optional> &breakpoints) const; }; diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 71f9e5578ef08..4fefd8b440c7d 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -28,21 +28,20 @@ SetBreakpointsRequestHandler::Run( const auto &source = args.source; std::vector response_breakpoints; if (source.sourceReference) - response_breakpoints = SetAssemblyBreakpoints( - source.sourceReference.value(), args.breakpoints); + response_breakpoints = SetAssemblyBreakpoints(source, args.breakpoints); else if (source.path) - response_breakpoints = - SetSourceBreakpoints(source.path.value(), args.breakpoints); + response_breakpoints = SetSourceBreakpoints(source, args.breakpoints); return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; } std::vector SetBreakpointsRequestHandler::SetSourceBreakpoints( - const std::string &path, + const protocol::Source &source, const std::optional> &breakpoints) const { std::vector response_breakpoints; + std::string path = source.path.value_or(""); // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; @@ -96,10 +95,11 @@ SetBreakpointsRequestHandler::SetSourceBreakpoints( std::vector SetBreakpointsRequestHandler::SetAssemblyBreakpoints( - int64_t sourceReference, + const protocol::Source &source, const std::optional> &breakpoints) const { std::vector response_breakpoints; + int64_t sourceReference = source.sourceReference.value_or(0); lldb::SBProcess process = dap.target.GetProcess(); lldb::SBThread thread = @@ -114,14 +114,14 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( return response_breakpoints; // Not yet supporting breakpoints in assembly // without a valid symbol - SourceBreakpointMap request_bps; + llvm::DenseMap request_bps; if (breakpoints) { for (const auto &bp : *breakpoints) { SourceBreakpoint src_bp(dap, bp); - std::pair bp_pos(src_bp.GetLine(), 0); - request_bps.try_emplace(bp_pos, src_bp); + request_bps.try_emplace(src_bp.GetLine(), src_bp); const auto [iv, inserted] = - dap.assembly_breakpoints[sourceReference].try_emplace(bp_pos, src_bp); + dap.assembly_breakpoints[sourceReference].try_emplace( + src_bp.GetLine(), src_bp); // We check if this breakpoint already exists to update it if (inserted) iv->getSecond().SetBreakpoint(symbol); @@ -129,15 +129,11 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( iv->getSecond().UpdateBreakpoint(src_bp); protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - protocol::Source source; - source.sourceReference = sourceReference; - source.name = symbol.GetName(); - response_bp.source = std::move(source); - + response_bp.source = source; if (!response_bp.line) response_bp.line = src_bp.GetLine(); - if (!response_bp.column) - response_bp.column = src_bp.GetColumn(); + if (bp.column) + response_bp.column = *bp.column; response_breakpoints.push_back(response_bp); } } diff --git a/lldb/tools/lldb-dap/package-lock.json b/lldb/tools/lldb-dap/package-lock.json index 0a2b9e764067e..af90a9573aee6 100644 --- a/lldb/tools/lldb-dap/package-lock.json +++ b/lldb/tools/lldb-dap/package-lock.json @@ -1,12 +1,12 @@ { "name": "lldb-dap", - "version": "0.2.13", + "version": "0.2.14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lldb-dap", - "version": "0.2.13", + "version": "0.2.14", "license": "Apache 2.0 License with LLVM exceptions", "devDependencies": { "@types/node": "^18.19.41", diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index d5ca604798799..73e70cd961f4f 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -1,7 +1,7 @@ { "name": "lldb-dap", "displayName": "LLDB DAP", - "version": "0.2.13", + "version": "0.2.14", "publisher": "llvm-vs-code-extensions", "homepage": "https://lldb.llvm.org", "description": "Debugging with LLDB in Visual Studio Code", @@ -265,6 +265,9 @@ ] }, "breakpoints": [ + { + "language": "lldb.disassembly" + }, { "language": "ada" }, >From 3699524618ed76f969cc26a63610fe54e3605139 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Thu, 15 May 2025 00:36:10 +0200 Subject: [PATCH 04/13] remove include --- lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 4fefd8b440c7d..d69da5bd02c1e 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -12,8 +12,6 @@ #include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" -#include -#include #include namespace lldb_dap { >From 61623deb7e249a8ca0c63e3f66955790da5e4ced Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sat, 17 May 2025 21:05:27 +0200 Subject: [PATCH 05/13] use load address as sourceReference --- lldb/include/lldb/API/SBFileSpec.h | 3 + lldb/source/API/SBFileSpec.cpp | 8 ++ lldb/tools/lldb-dap/Breakpoint.cpp | 18 +---- .../Handler/BreakpointLocationsHandler.cpp | 11 +-- .../Handler/SetBreakpointsRequestHandler.cpp | 11 +-- .../lldb-dap/Handler/SourceRequestHandler.cpp | 18 ++--- lldb/tools/lldb-dap/JSONUtils.cpp | 75 +++++++++++++------ lldb/tools/lldb-dap/JSONUtils.h | 14 ++++ 8 files changed, 96 insertions(+), 62 deletions(-) diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index 36641843aabeb..303cb7d712cbf 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -10,6 +10,7 @@ #define LLDB_API_SBFILESPEC_H #include "lldb/API/SBDefines.h" +#include "lldb/API/SBStream.h" namespace lldb { @@ -53,6 +54,8 @@ class LLDB_API SBFileSpec { uint32_t GetPath(char *dst_path, size_t dst_len) const; + bool GetPath(lldb::SBStream &dst_path) const; + static int ResolvePath(const char *src_path, char *dst_path, size_t dst_len); bool GetDescription(lldb::SBStream &description) const; diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp index a7df9afc4b8eb..cb44dac1d4fcc 100644 --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -19,6 +19,7 @@ #include #include +#include using namespace lldb; using namespace lldb_private; @@ -147,6 +148,13 @@ uint32_t SBFileSpec::GetPath(char *dst_path, size_t dst_len) const { return result; } +bool SBFileSpec::GetPath(SBStream &dst_path) const { + LLDB_INSTRUMENT_VA(this, dst_path); + + std::string path = m_opaque_up->GetPath(); + return dst_path->PutCString(path.c_str()) > 0; +} + const lldb_private::FileSpec *SBFileSpec::operator->() const { return m_opaque_up.get(); } diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 87fcd15b0a568..a54a34e0f936d 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -79,27 +79,15 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { breakpoint.source = CreateSource(line_entry); } else { // Breakpoint made by assembly - auto symbol_context = bp_addr.GetSymbolContext( - lldb::eSymbolContextSymbol | lldb::eSymbolContextModule); - if (symbol_context.IsValid()) { - auto symbol = symbol_context.GetSymbol(); + auto symbol = bp_addr.GetSymbol(); + if (symbol.IsValid()) { breakpoint.line = m_bp.GetTarget() .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) .GetSize() + 1; - protocol::Source source; - source.name = symbol.GetName(); - auto module = symbol_context.GetModule(); - if (module.IsValid()) { - std::string path = module.GetFileSpec().GetDirectory(); - path += "/"; - path += module.GetFileSpec().GetFilename(); - source.path = std::move(path); - } - - breakpoint.source = std::move(source); + breakpoint.source = CreateAssemblySource(m_dap.target, bp_addr); } } } diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 06ada47a6f27f..c4d658caeee2d 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "LLDBUtils.h" #include "RequestHandler.h" #include @@ -108,15 +107,11 @@ template void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( llvm::SmallVector, N> &locations, int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { - lldb::SBProcess process = dap.target.GetProcess(); - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - - if (!frame.IsValid()) + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) return; - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) return; diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index d69da5bd02c1e..7b401f06e9a85 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -9,7 +9,6 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" -#include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" #include @@ -99,15 +98,11 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( std::vector response_breakpoints; int64_t sourceReference = source.sourceReference.value_or(0); - lldb::SBProcess process = dap.target.GetProcess(); - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - - if (!frame.IsValid()) + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) return response_breakpoints; - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) return response_breakpoints; // Not yet supporting breakpoints in assembly // without a valid symbol diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp index fb396a3dc8862..9249e2aa6fef7 100644 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp @@ -11,6 +11,7 @@ #include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" +#include "lldb/API/SBAddress.h" #include "lldb/API/SBExecutionContext.h" #include "lldb/API/SBFrame.h" #include "lldb/API/SBInstructionList.h" @@ -19,6 +20,7 @@ #include "lldb/API/SBSymbol.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" +#include "lldb/lldb-types.h" #include "llvm/Support/Error.h" namespace lldb_dap { @@ -34,18 +36,14 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { return llvm::make_error( "invalid arguments, expected source.sourceReference to be set"); - lldb::SBProcess process = dap.target.GetProcess(); - // Upper 32 bits is the thread index ID - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(source)); - // Lower 32 bits is the frame index - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(source)); - if (!frame.IsValid()) + lldb::SBAddress address(source, dap.target); + if (!address.IsValid()) return llvm::make_error("source not found"); + lldb::SBSymbol symbol = address.GetSymbol(); + lldb::SBStream stream; - lldb::SBExecutionContext exe_ctx(frame); - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBExecutionContext exe_ctx(dap.target); if (symbol.IsValid()) { lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); @@ -53,7 +51,7 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { } else { // No valid symbol, just return the disassembly. lldb::SBInstructionList insts = dap.target.ReadInstructions( - frame.GetPCAddress(), dap.number_of_assembly_lines_for_nodebug); + address, dap.number_of_assembly_lines_for_nodebug); insts.GetDescription(stream, exe_ctx); } diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 714947a4d3b9c..c8151c3d64ea4 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -490,6 +490,13 @@ CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp) { return filter; } +static std::string GetLoadAddressString(const lldb::addr_t addr) { + std::string result; + llvm::raw_string_ostream os(result); + os << llvm::format_hex(addr, 18); + return result; +} + protocol::Source CreateSource(const lldb::SBFileSpec &file) { protocol::Source source; if (file.IsValid()) { @@ -516,6 +523,43 @@ protocol::Source CreateSource(llvm::StringRef source_path) { return source; } +protocol::Source CreateAssemblySource(const lldb::SBTarget &target, + lldb::SBAddress &address) { + protocol::Source source; + + auto symbol = address.GetSymbol(); + std::string name; + if (symbol.IsValid()) { + source.sourceReference = symbol.GetStartAddress().GetLoadAddress(target); + name = symbol.GetName(); + } else { + const auto load_addr = address.GetLoadAddress(target); + source.sourceReference = load_addr; + name = GetLoadAddressString(load_addr); + } + + lldb::SBModule module = address.GetModule(); + if (module.IsValid()) { + lldb::SBFileSpec file_spec = module.GetFileSpec(); + if (file_spec.IsValid()) { + lldb::SBStream module_path; + if (file_spec.GetPath(module_path)) { + std::string path = module_path.GetData(); + source.path = path + '`' + name; + } + } + } + + source.name = std::move(name); + + // Mark the source as deemphasized since users will only be able to view + // assembly for these frames. + source.presentationHint = + protocol::Source::PresentationHint::eSourcePresentationHintDeemphasize; + + return source; +} + bool ShouldDisplayAssemblySource( const lldb::SBLineEntry &line_entry, lldb::StopDisassemblyType stop_disassembly_display) { @@ -619,12 +663,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, frame_name = name; } - if (frame_name.empty()) { + if (frame_name.empty()) // If the function name is unavailable, display the pc address as a 16-digit // hex string, e.g. "0x0000000000012345" - llvm::raw_string_ostream os(frame_name); - os << llvm::format_hex(frame.GetPC(), 18); - } + frame_name = GetLoadAddressString(frame.GetPC()); // We only include `[opt]` if a custom frame format is not specified. if (!format && frame.GetFunction().GetIsOptimized()) @@ -641,17 +683,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, } else if (frame.GetSymbol().IsValid()) { // If no source is associated with the frame, use the DAPFrameID to track // the 'source' and generate assembly. - llvm::json::Object source; - EmplaceSafeString(source, "name", frame_name); - char buf[PATH_MAX] = {0}; - size_t size = frame.GetModule().GetFileSpec().GetPath(buf, PATH_MAX); - EmplaceSafeString(source, "path", - std::string(buf, size) + '`' + frame_name); - source.try_emplace("sourceReference", MakeDAPFrameID(frame)); - // Mark the source as deemphasized since users will only be able to view - // assembly for these frames. - EmplaceSafeString(source, "presentationHint", "deemphasize"); - object.try_emplace("source", std::move(source)); + auto frame_address = frame.GetPCAddress(); + object.try_emplace("source", CreateAssemblySource( + frame.GetThread().GetProcess().GetTarget(), + frame_address)); // Calculate the line of the current PC from the start of the current // symbol. @@ -665,12 +700,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, object.try_emplace("column", 1); } else { // No valid line entry or symbol. - llvm::json::Object source; - EmplaceSafeString(source, "name", frame_name); - source.try_emplace("sourceReference", MakeDAPFrameID(frame)); - EmplaceSafeString(source, "presentationHint", "deemphasize"); - object.try_emplace("source", std::move(source)); - + auto frame_address = frame.GetPCAddress(); + object.try_emplace("source", CreateAssemblySource( + frame.GetThread().GetProcess().GetTarget(), + frame_address)); object.try_emplace("line", 1); object.try_emplace("column", 1); } diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h index 783f291338d8c..ac9b39739104f 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -269,6 +269,20 @@ protocol::Source CreateSource(const lldb::SBLineEntry &line_entry); /// definition outlined by Microsoft. protocol::Source CreateSource(llvm::StringRef source_path); +/// Create a "Source" object for a given frame, using its assembly for source. +/// +/// \param[in] target +/// The relevant target. +/// +/// \param[in] address +/// The address to use when creating the "Source" object. +/// +/// \return +/// A "Source" JSON object that follows the formal JSON +/// definition outlined by Microsoft. +protocol::Source CreateAssemblySource(const lldb::SBTarget &target, + lldb::SBAddress &address); + /// Return true if the given line entry should be displayed as assembly. /// /// \param[in] line_entry >From f5fd76de3ad25b9cbf6ce065e06c98ff30b070a8 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 02:22:19 +0200 Subject: [PATCH 06/13] add breakpoint-assembly test --- .../test/tools/lldb-dap/dap_server.py | 7 ++++ .../test/tools/lldb-dap/lldbdap_testcase.py | 10 +++++ .../lldb-dap/breakpoint-assembly/Makefile | 3 ++ .../TestDAP_breakpointAssembly.py | 42 +++++++++++++++++++ .../tools/lldb-dap/breakpoint-assembly/main.c | 14 +++++++ .../breakpoint/TestDAP_setBreakpoints.py | 1 + .../TestDAP_setExceptionBreakpoints.py | 1 + .../TestDAP_setFunctionBreakpoints.py | 1 + 8 files changed, 79 insertions(+) create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index 70fd0b0c419db..4a907a5e36901 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -955,6 +955,13 @@ def request_setBreakpoints(self, file_path, line_array, data=None): """ (dir, base) = os.path.split(file_path) source_dict = {"name": base, "path": file_path} + return self.request_setBreakpoints_with_source(source_dict, line_array, data) + + def request_setBreakpointsAssembly(self, sourceReference, line_array, data=None): + source_dict = {"sourceReference": sourceReference} + return self.request_setBreakpoints_with_source(source_dict, line_array, data) + + def request_setBreakpoints_with_source(self, source_dict, line_array, data=None): args_dict = { "source": source_dict, "sourceModified": False, diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index afdc746ed0d0d..427f66a7da0c8 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -63,6 +63,16 @@ def set_source_breakpoints(self, source_path, lines, data=None): for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) return breakpoint_ids + + def set_source_breakpoints_assembly(self, source_reference, lines, data=None): + response = self.dap_server.request_setBreakpointsAssembly(source_reference, lines, data) + if response is None: + return [] + breakpoints = response["body"]["breakpoints"] + breakpoint_ids = [] + for breakpoint in breakpoints: + breakpoint_ids.append("%i" % (breakpoint["id"])) + return breakpoint_ids def set_function_breakpoints(self, functions, condition=None, hitCondition=None): """Sets breakpoints by function name given an array of function names diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile new file mode 100644 index 0000000000000..10495940055b6 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py new file mode 100644 index 0000000000000..ba9df3a18590b --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py @@ -0,0 +1,42 @@ +""" +Test lldb-dap setBreakpoints request +""" + + +import dap_server +import shutil +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +import lldbdap_testcase +import os + + +class TestDAP_setBreakpointsAssembly(lldbdap_testcase.DAPTestCaseBase): + # @skipIfWindows + def test_functionality(self): + """Tests hitting assembly source breakpoints""" + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + + self.dap_server.request_evaluate( + "`settings set stop-disassembly-display no-debuginfo", context="repl" + ) + + assmebly_func_breakpoints = self.set_function_breakpoints(["assembly_func"]) + self.continue_to_breakpoints(assmebly_func_breakpoints) + + assembly_func_frame = self.get_stackFrames()[0] + self.assertIn( + "sourceReference", + assembly_func_frame.get("source"), + "Expected assembly source frame", + ) + + line = assembly_func_frame["line"] + + # Set an assembly breakpoint in the next line and check that it's hit + assembly_breakpoint_ids = self.set_source_breakpoints_assembly( + assembly_func_frame["source"]["sourceReference"], [line + 1] + ) + self.continue_to_breakpoints(assembly_breakpoint_ids) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c new file mode 100644 index 0000000000000..350739006f903 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c @@ -0,0 +1,14 @@ +#include + +__attribute__((nodebug)) int assembly_func(int n) { + n += 1; + n += 2; + n += 3; + + return n; +} + +int main(int argc, char const *argv[]) { + assembly_func(10); + return 0; +} diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index 26df2573555df..aae1251b17c93 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,6 +12,7 @@ import os + at skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py index 92ac66cd44c5d..4dc8c5b3c7ded 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py @@ -10,6 +10,7 @@ import lldbdap_testcase + at skip("Temporarily disable the breakpoint tests") class TestDAP_setExceptionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_functionality(self): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index 946595f639edc..baaca4d974d5d 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,6 +10,7 @@ import lldbdap_testcase + at skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): >From 40f68e418bfbb6564b3834382c4a33a3104fc33d Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 10:23:11 +0200 Subject: [PATCH 07/13] python format --- .../lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index 427f66a7da0c8..3bf649a087fdb 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -63,9 +63,11 @@ def set_source_breakpoints(self, source_path, lines, data=None): for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) return breakpoint_ids - + def set_source_breakpoints_assembly(self, source_reference, lines, data=None): - response = self.dap_server.request_setBreakpointsAssembly(source_reference, lines, data) + response = self.dap_server.request_setBreakpointsAssembly( + source_reference, lines, data + ) if response is None: return [] breakpoints = response["body"]["breakpoints"] >From 199512fd7a0900d45070b95dd52ef5ef136e2719 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 10:54:43 +0200 Subject: [PATCH 08/13] restore SBFileSpec and fix assembly breakpoints CR --- lldb/include/lldb/API/SBFileSpec.h | 2 - lldb/source/API/SBFileSpec.cpp | 7 --- lldb/tools/lldb-dap/DAP.h | 2 +- .../Handler/BreakpointLocationsHandler.cpp | 47 ++++++++++--------- lldb/tools/lldb-dap/Handler/RequestHandler.h | 17 ++++--- .../Handler/SetBreakpointsRequestHandler.cpp | 9 ++-- lldb/tools/lldb-dap/JSONUtils.cpp | 6 +-- lldb/tools/lldb-dap/LLDBUtils.cpp | 10 ++++ lldb/tools/lldb-dap/LLDBUtils.h | 10 ++++ 9 files changed, 60 insertions(+), 50 deletions(-) diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index 303cb7d712cbf..1bb28b2ddab01 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -54,8 +54,6 @@ class LLDB_API SBFileSpec { uint32_t GetPath(char *dst_path, size_t dst_len) const; - bool GetPath(lldb::SBStream &dst_path) const; - static int ResolvePath(const char *src_path, char *dst_path, size_t dst_len); bool GetDescription(lldb::SBStream &description) const; diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp index cb44dac1d4fcc..f18857f59171a 100644 --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -148,13 +148,6 @@ uint32_t SBFileSpec::GetPath(char *dst_path, size_t dst_len) const { return result; } -bool SBFileSpec::GetPath(SBStream &dst_path) const { - LLDB_INSTRUMENT_VA(this, dst_path); - - std::string path = m_opaque_up->GetPath(); - return dst_path->PutCString(path.c_str()) > 0; -} - const lldb_private::FileSpec *SBFileSpec::operator->() const { return m_opaque_up.get(); } diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index b0fe265b7bca1..20f95be792f41 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -222,7 +222,7 @@ struct DAP { /// @} /// Number of lines of assembly code to show when no debug info is available. - uint32_t number_of_assembly_lines_for_nodebug = 32; + static constexpr uint32_t number_of_assembly_lines_for_nodebug = 32; /// Creates a new DAP sessions. /// diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index c4d658caeee2d..794b83a9e0e1e 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -8,6 +8,7 @@ #include "DAP.h" #include "RequestHandler.h" +#include #include namespace lldb_dap { @@ -24,15 +25,15 @@ BreakpointLocationsRequestHandler::Run( uint32_t end_column = args.endColumn.value_or(std::numeric_limits::max()); - // Find all relevant lines & columns - llvm::SmallVector, 8> locations; - if (args.source.sourceReference) { - AddAssemblyBreakpointLocations(locations, *args.source.sourceReference, - start_line, end_line); - } else { + // Find all relevant lines & columns. + std::vector> locations; + if (args.source.sourceReference) + locations = GetAssemblyBreakpointLocations(*args.source.sourceReference, + start_line, end_line); + else { std::string path = args.source.path.value_or(""); - AddSourceBreakpointLocations(locations, std::move(path), start_line, - start_column, end_line, end_column); + locations = GetSourceBreakpointLocations( + std::move(path), start_line, start_column, end_line, end_column); } // The line entries are sorted by addresses, but we must return the list @@ -41,23 +42,19 @@ BreakpointLocationsRequestHandler::Run( locations.erase(llvm::unique(locations), locations.end()); std::vector breakpoint_locations; - for (auto &l : locations) { - protocol::BreakpointLocation lc; - lc.line = l.first; - lc.column = l.second; - breakpoint_locations.push_back(std::move(lc)); - } + for (auto &l : locations) + breakpoint_locations.push_back( + {l.first, l.second, std::nullopt, std::nullopt}); return protocol::BreakpointLocationsResponseBody{ /*breakpoints=*/std::move(breakpoint_locations)}; } -template -void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( - llvm::SmallVector, N> &locations, +std::vector> +BreakpointLocationsRequestHandler::GetSourceBreakpointLocations( std::string path, uint32_t start_line, uint32_t start_column, uint32_t end_line, uint32_t end_column) const { - + std::vector> locations; lldb::SBFileSpec file_spec(path.c_str(), true); lldb::SBSymbolContextList compile_units = dap.target.FindCompileUnits(file_spec); @@ -101,19 +98,21 @@ void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( locations.emplace_back(line, column); } } + + return locations; } -template -void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( - llvm::SmallVector, N> &locations, +std::vector> +BreakpointLocationsRequestHandler::GetAssemblyBreakpointLocations( int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { + std::vector> locations; lldb::SBAddress address(sourceReference, dap.target); if (!address.IsValid()) - return; + return locations; lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) - return; + return locations; // start_line is relative to the symbol's start address lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); @@ -121,6 +120,8 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( ++i) { locations.emplace_back(i, 1); } + + return locations; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 80898d1ee5ef1..e708abb50d5c0 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -23,6 +23,7 @@ #include #include #include +#include template struct is_optional : std::false_type {}; @@ -234,15 +235,13 @@ class BreakpointLocationsRequestHandler llvm::Expected Run(const protocol::BreakpointLocationsArguments &args) const override; - template - void AddSourceBreakpointLocations( - llvm::SmallVector, N> &locations, - std::string path, uint32_t start_line, uint32_t start_column, - uint32_t end_line, uint32_t end_column) const; - template - void AddAssemblyBreakpointLocations( - llvm::SmallVector, N> &locations, - int64_t sourceReference, uint32_t start_line, uint32_t end_line) const; + std::vector> + GetSourceBreakpointLocations(std::string path, uint32_t start_line, + uint32_t start_column, uint32_t end_line, + uint32_t end_column) const; + std::vector> + GetAssemblyBreakpointLocations(int64_t sourceReference, uint32_t start_line, + uint32_t end_line) const; }; class CompletionsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 7b401f06e9a85..bf0b584753c07 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -103,9 +103,10 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( return response_breakpoints; lldb::SBSymbol symbol = address.GetSymbol(); - if (!symbol.IsValid()) - return response_breakpoints; // Not yet supporting breakpoints in assembly - // without a valid symbol + if (!symbol.IsValid()) { + // Not yet supporting breakpoints in assembly without a valid symbol. + return response_breakpoints; + } llvm::DenseMap request_bps; if (breakpoints) { @@ -115,7 +116,7 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( const auto [iv, inserted] = dap.assembly_breakpoints[sourceReference].try_emplace( src_bp.GetLine(), src_bp); - // We check if this breakpoint already exists to update it + // We check if this breakpoint already exists to update it. if (inserted) iv->getSecond().SetBreakpoint(symbol); else diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index c8151c3d64ea4..1d2a6ff60e502 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -542,11 +542,9 @@ protocol::Source CreateAssemblySource(const lldb::SBTarget &target, if (module.IsValid()) { lldb::SBFileSpec file_spec = module.GetFileSpec(); if (file_spec.IsValid()) { - lldb::SBStream module_path; - if (file_spec.GetPath(module_path)) { - std::string path = module_path.GetData(); + std::string path = GetSBFileSpecPath(file_spec); + if (!path.empty()) source.path = path + '`' + name; - } } } diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp index 0e7bb2b9058a7..3c7623ec1215d 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.cpp +++ b/lldb/tools/lldb-dap/LLDBUtils.cpp @@ -20,6 +20,7 @@ #include "llvm/Support/JSON.h" #include "llvm/Support/raw_ostream.h" +#include #include #include @@ -242,4 +243,13 @@ ScopeSyncMode::ScopeSyncMode(lldb::SBDebugger &debugger) ScopeSyncMode::~ScopeSyncMode() { m_debugger.SetAsync(m_async); } +std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec) { + const auto directory_length = ::strlen(file_spec.GetDirectory()); + const auto file_name_length = ::strlen(file_spec.GetFilename()); + + std::string path(directory_length + file_name_length + 2, '\0'); + file_spec.GetPath(path.data(), path.length()); + return path; +} + } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/LLDBUtils.h b/lldb/tools/lldb-dap/LLDBUtils.h index 711fc6051231c..7fdf4b859ee61 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.h +++ b/lldb/tools/lldb-dap/LLDBUtils.h @@ -13,6 +13,7 @@ #include "lldb/API/SBDebugger.h" #include "lldb/API/SBEnvironment.h" #include "lldb/API/SBError.h" +#include "lldb/API/SBFileSpec.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" @@ -161,6 +162,15 @@ uint32_t GetLLDBFrameID(uint64_t dap_frame_id); lldb::SBEnvironment GetEnvironmentFromArguments(const llvm::json::Object &arguments); +/// Gets an SBFileSpec and returns its path as a string. +/// +/// \param[in] file_spec +/// The file spec. +/// +/// \return +/// The file path as a string. +std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec); + /// Helper for sending telemetry to lldb server, if client-telemetry is enabled. class TelemetryDispatcher { public: >From dbad33b314bb59f6e0d22fd07dddb35e2a0e30d9 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 12:57:59 +0200 Subject: [PATCH 09/13] abstracted source breakpoints maps by DAP --- lldb/tools/lldb-dap/Breakpoint.cpp | 4 +- lldb/tools/lldb-dap/DAP.cpp | 75 +++++++++++ lldb/tools/lldb-dap/DAP.h | 29 +++- lldb/tools/lldb-dap/Handler/RequestHandler.h | 9 -- .../Handler/SetBreakpointsRequestHandler.cpp | 125 +----------------- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 54 +++++--- lldb/tools/lldb-dap/SourceBreakpoint.h | 7 +- 7 files changed, 140 insertions(+), 163 deletions(-) diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index a54a34e0f936d..fd7531f42c518 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -71,10 +71,10 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { auto line_entry = bp_addr.GetLineEntry(); if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) { const auto line = line_entry.GetLine(); - if (line != UINT32_MAX) + if (line != LLDB_INVALID_LINE_NUMBER) breakpoint.line = line; const auto column = line_entry.GetColumn(); - if (column != 0) + if (column != LLDB_INVALID_COLUMN_NUMBER) breakpoint.column = column; breakpoint.source = CreateSource(line_entry); } else { diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 0d5eba6c40961..1fe46fc619d73 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1620,6 +1620,81 @@ void DAP::EventThread() { } } +std::vector DAP::SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints) { + std::vector response_breakpoints; + if (source.sourceReference) { + // breakpoint set by assembly source. + auto &existing_breakpoints_pos = + m_source_assembly_breakpoints[*source.sourceReference]; + response_breakpoints = + SetSourceBreakpoints(source, breakpoints, existing_breakpoints_pos); + } else { + // breakpoint set by a regular source file. + const auto path = source.path.value_or(""); + auto &existing_breakpoints_pos = m_source_breakpoints[path]; + response_breakpoints = + SetSourceBreakpoints(source, breakpoints, existing_breakpoints_pos); + } + + return response_breakpoints; +} + +std::vector DAP::SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints, + SourceBreakpointMap &existing_breakpoints) { + std::vector response_breakpoints; + + SourceBreakpointMap request_breakpoints; + if (breakpoints) { + for (const auto &bp : *breakpoints) { + SourceBreakpoint src_bp(*this, bp, source); + std::pair bp_pos(src_bp.GetLine(), + src_bp.GetColumn()); + request_breakpoints.try_emplace(bp_pos, src_bp); + + const auto [iv, inserted] = + existing_breakpoints.try_emplace(bp_pos, src_bp); + // We check if this breakpoint already exists to update it. + if (inserted) + iv->second.SetBreakpoint(); + else + iv->second.UpdateBreakpoint(src_bp); + + protocol::Breakpoint response_breakpoint = + iv->second.ToProtocolBreakpoint(); + response_breakpoint.source = source; + + if (!response_breakpoint.line && + src_bp.GetLine() != LLDB_INVALID_LINE_NUMBER) + response_breakpoint.line = src_bp.GetLine(); + if (!response_breakpoint.column && + src_bp.GetColumn() != LLDB_INVALID_COLUMN_NUMBER) + response_breakpoint.column = src_bp.GetColumn(); + response_breakpoints.push_back(response_breakpoint); + } + } + + // Delete any breakpoints in this source file that aren't in the + // request_bps set. There is no call to remove breakpoints other than + // calling this function with a smaller or empty "breakpoints" list. + for (auto it = existing_breakpoints.begin(); + it != existing_breakpoints.end();) { + auto request_pos = request_breakpoints.find(it->first); + if (request_pos == request_breakpoints.end()) { + // This breakpoint no longer exists in this source file, delete it + target.BreakpointDelete(it->second.GetID()); + it = existing_breakpoints.erase(it); + } else { + ++it; + } + } + + return response_breakpoints; +} + void DAP::RegisterRequests() { RegisterRequest(); RegisterRequest(); diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 20f95be792f41..3a0a7fc1678ba 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -60,7 +60,7 @@ namespace lldb_dap { -typedef llvm::DenseMap, SourceBreakpoint> +typedef std::map, SourceBreakpoint> SourceBreakpointMap; typedef llvm::StringMap FunctionBreakpointMap; typedef llvm::DenseMap @@ -168,9 +168,6 @@ struct DAP { lldb::SBTarget target; Variables variables; lldb::SBBroadcaster broadcaster; - llvm::StringMap source_breakpoints; - llvm::DenseMap> - assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; @@ -428,7 +425,28 @@ struct DAP { void StartEventThread(); void StartProgressEventThread(); + /// Sets the given protocol `breakpoints` in the given `source`, while + /// removing any existing breakpoints in the given source if they are not in + /// `breakpoint`. + /// + /// \param[in] source + /// The relevant source of the breakpoints. + /// + /// \param[in] breakpoints + /// The breakpoints to set. + /// + /// \return a vector of the breakpoints that were set. + std::vector SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> + &breakpoints); + private: + std::vector SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints, + SourceBreakpointMap &existing_breakpoints); + /// Registration of request handler. /// @{ void RegisterRequests(); @@ -457,6 +475,9 @@ struct DAP { std::mutex m_active_request_mutex; const protocol::Request *m_active_request; + + llvm::StringMap m_source_breakpoints; + llvm::DenseMap m_source_assembly_breakpoints; }; } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index e708abb50d5c0..54f728414021e 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -388,15 +388,6 @@ class SetBreakpointsRequestHandler } llvm::Expected Run(const protocol::SetBreakpointsArguments &args) const override; - - std::vector SetSourceBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const; - std::vector SetAssemblyBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const; }; class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index bf0b584753c07..0ff88f62f8f51 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -22,130 +22,9 @@ namespace lldb_dap { llvm::Expected SetBreakpointsRequestHandler::Run( const protocol::SetBreakpointsArguments &args) const { - const auto &source = args.source; - std::vector response_breakpoints; - if (source.sourceReference) - response_breakpoints = SetAssemblyBreakpoints(source, args.breakpoints); - else if (source.path) - response_breakpoints = SetSourceBreakpoints(source, args.breakpoints); - + const auto response_breakpoints = + dap.SetSourceBreakpoints(args.source, args.breakpoints); return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; } -std::vector -SetBreakpointsRequestHandler::SetSourceBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const { - std::vector response_breakpoints; - std::string path = source.path.value_or(""); - - // Decode the source breakpoint infos for this "setBreakpoints" request - SourceBreakpointMap request_bps; - // "breakpoints" may be unset, in which case we treat it the same as being set - // to an empty array. - if (breakpoints) { - for (const auto &bp : *breakpoints) { - SourceBreakpoint src_bp(dap, bp); - std::pair bp_pos(src_bp.GetLine(), - src_bp.GetColumn()); - request_bps.try_emplace(bp_pos, src_bp); - const auto [iv, inserted] = - dap.source_breakpoints[path].try_emplace(bp_pos, src_bp); - // We check if this breakpoint already exists to update it - if (inserted) - iv->getSecond().SetBreakpoint(path.data()); - else - iv->getSecond().UpdateBreakpoint(src_bp); - - protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - - // Use the path from the request if it is set - if (!path.empty()) - response_bp.source = CreateSource(path); - - if (!response_bp.line) - response_bp.line = src_bp.GetLine(); - if (!response_bp.column) - response_bp.column = src_bp.GetColumn(); - response_breakpoints.push_back(response_bp); - } - } - - // Delete any breakpoints in this source file that aren't in the - // request_bps set. There is no call to remove breakpoints other than - // calling this function with a smaller or empty "breakpoints" list. - auto old_src_bp_pos = dap.source_breakpoints.find(path); - if (old_src_bp_pos != dap.source_breakpoints.end()) { - for (auto &old_bp : old_src_bp_pos->second) { - auto request_pos = request_bps.find(old_bp.first); - if (request_pos == request_bps.end()) { - // This breakpoint no longer exists in this source file, delete it - dap.target.BreakpointDelete(old_bp.second.GetID()); - old_src_bp_pos->second.erase(old_bp.first); - } - } - } - - return response_breakpoints; -} - -std::vector -SetBreakpointsRequestHandler::SetAssemblyBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const { - std::vector response_breakpoints; - int64_t sourceReference = source.sourceReference.value_or(0); - - lldb::SBAddress address(sourceReference, dap.target); - if (!address.IsValid()) - return response_breakpoints; - - lldb::SBSymbol symbol = address.GetSymbol(); - if (!symbol.IsValid()) { - // Not yet supporting breakpoints in assembly without a valid symbol. - return response_breakpoints; - } - - llvm::DenseMap request_bps; - if (breakpoints) { - for (const auto &bp : *breakpoints) { - SourceBreakpoint src_bp(dap, bp); - request_bps.try_emplace(src_bp.GetLine(), src_bp); - const auto [iv, inserted] = - dap.assembly_breakpoints[sourceReference].try_emplace( - src_bp.GetLine(), src_bp); - // We check if this breakpoint already exists to update it. - if (inserted) - iv->getSecond().SetBreakpoint(symbol); - else - iv->getSecond().UpdateBreakpoint(src_bp); - - protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - response_bp.source = source; - if (!response_bp.line) - response_bp.line = src_bp.GetLine(); - if (bp.column) - response_bp.column = *bp.column; - response_breakpoints.push_back(response_bp); - } - } - - // Delete existing breakpoints for this sourceReference that are not in the - // request_bps set. - auto old_src_bp_pos = dap.assembly_breakpoints.find(sourceReference); - if (old_src_bp_pos != dap.assembly_breakpoints.end()) { - for (auto &old_bp : old_src_bp_pos->second) { - auto request_pos = request_bps.find(old_bp.first); - if (request_pos == request_bps.end()) { - dap.target.BreakpointDelete(old_bp.second.GetID()); - old_src_bp_pos->second.erase(old_bp.first); - } - } - } - - return response_breakpoints; -} - } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 938b8fb8bcdda..50ebfbe8aef20 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -29,39 +29,49 @@ namespace lldb_dap { SourceBreakpoint::SourceBreakpoint(DAP &dap, - const protocol::SourceBreakpoint &breakpoint) + const protocol::SourceBreakpoint &breakpoint, + const protocol::Source &source) : Breakpoint(dap, breakpoint.condition, breakpoint.hitCondition), - m_log_message(breakpoint.logMessage.value_or("")), + m_log_message(breakpoint.logMessage.value_or("")), m_source(source), m_line(breakpoint.line), m_column(breakpoint.column.value_or(LLDB_INVALID_COLUMN_NUMBER)) {} -void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) { - lldb::SBMutex lock = m_dap.GetAPIMutex(); - std::lock_guard guard(lock); - - lldb::SBFileSpecList module_list; - m_bp = m_dap.target.BreakpointCreateByLocation( - source_path.str().c_str(), m_line, m_column, 0, module_list); - if (!m_log_message.empty()) - SetLogMessage(); - Breakpoint::SetBreakpoint(); -} - -void SourceBreakpoint::SetBreakpoint(lldb::SBSymbol &symbol) { +void SourceBreakpoint::SetBreakpoint() { lldb::SBMutex lock = m_dap.GetAPIMutex(); std::lock_guard guard(lock); if (m_line == 0) return; - lldb::SBInstructionList inst_list = - m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); - if (inst_list.GetSize() < m_line) - return; - lldb::SBAddress address = - inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + if (m_source.sourceReference) { + // breakpoint set by assembly source. + lldb::SBAddress source_address(*m_source.sourceReference, m_dap.target); + if (!source_address.IsValid()) + return; + + lldb::SBSymbol symbol = source_address.GetSymbol(); + if (!symbol.IsValid()) { + // Not yet supporting breakpoints in assembly without a valid symbol. + return; + } + + lldb::SBInstructionList inst_list = + m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); + if (inst_list.GetSize() < m_line) + return; + + lldb::SBAddress address = + inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + + m_bp = m_dap.target.BreakpointCreateBySBAddress(address); + } else { + // breakpoint set by a regular source file. + const auto source_path = m_source.path.value_or(""); + lldb::SBFileSpecList module_list; + m_bp = m_dap.target.BreakpointCreateByLocation(source_path.c_str(), m_line, + m_column, 0, module_list); + } - m_bp = m_dap.target.BreakpointCreateBySBAddress(address); if (!m_log_message.empty()) SetLogMessage(); Breakpoint::SetBreakpoint(); diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h index 8589800e50983..3221ecbf28ece 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.h +++ b/lldb/tools/lldb-dap/SourceBreakpoint.h @@ -22,11 +22,11 @@ namespace lldb_dap { class SourceBreakpoint : public Breakpoint { public: - SourceBreakpoint(DAP &d, const protocol::SourceBreakpoint &breakpoint); + SourceBreakpoint(DAP &d, const protocol::SourceBreakpoint &breakpoint, + const protocol::Source &source); // Set this breakpoint in LLDB as a new breakpoint - void SetBreakpoint(const llvm::StringRef source_path); - void SetBreakpoint(lldb::SBSymbol &symbol); + void SetBreakpoint(); void UpdateBreakpoint(const SourceBreakpoint &request_bp); void SetLogMessage(); @@ -63,6 +63,7 @@ class SourceBreakpoint : public Breakpoint { std::string m_log_message; std::vector m_log_message_parts; + protocol::Source m_source; /// The original breakpoint source. uint32_t m_line; ///< The source line of the breakpoint or logpoint uint32_t m_column; ///< An optional source column of the breakpoint }; >From 2e9edca37c0953e2d2a6cf2d278bb353f1e0960b Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 13:39:05 +0200 Subject: [PATCH 10/13] improve assembvly breakpoint test to check clear --- .../TestDAP_breakpointAssembly.py | 17 +++++++++++++++-- .../tools/lldb-dap/breakpoint-assembly/main.c | 4 +++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py index ba9df3a18590b..dacc1cd8349f1 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py @@ -6,7 +6,7 @@ import dap_server import shutil from lldbsuite.test.decorators import * -from lldbsuite.test.lldbtest import * +from lldbsuite.test.lldbtest import line_number from lldbsuite.test import lldbutil import lldbdap_testcase import os @@ -23,6 +23,9 @@ def test_functionality(self): "`settings set stop-disassembly-display no-debuginfo", context="repl" ) + finish_line = line_number("main.c", "// Break here") + finish_breakpoints = self.set_source_breakpoints("main.c", [finish_line]) + assmebly_func_breakpoints = self.set_function_breakpoints(["assembly_func"]) self.continue_to_breakpoints(assmebly_func_breakpoints) @@ -36,7 +39,17 @@ def test_functionality(self): line = assembly_func_frame["line"] # Set an assembly breakpoint in the next line and check that it's hit + source_reference = assembly_func_frame["source"]["sourceReference"] assembly_breakpoint_ids = self.set_source_breakpoints_assembly( - assembly_func_frame["source"]["sourceReference"], [line + 1] + source_reference, [line + 1] ) self.continue_to_breakpoints(assembly_breakpoint_ids) + + # Continue again and verify it hits in the next function call + self.continue_to_breakpoints(assmebly_func_breakpoints) + self.continue_to_breakpoints(assembly_breakpoint_ids) + + # Clear the breakpoint and then check that the assembly breakpoint does not hit next time + self.set_source_breakpoints_assembly(source_reference, []) + self.continue_to_breakpoints(assmebly_func_breakpoints) + self.continue_to_breakpoints(finish_breakpoints) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c index 350739006f903..e3a21df11958f 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c @@ -10,5 +10,7 @@ __attribute__((nodebug)) int assembly_func(int n) { int main(int argc, char const *argv[]) { assembly_func(10); - return 0; + assembly_func(20); + assembly_func(30); + return 0; // Break here } >From 0515c6dc6e46b6296621e871b43286ae88ea9b6b Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 13:52:40 +0200 Subject: [PATCH 11/13] fix GetSBFileSpecPath extra char --- lldb/tools/lldb-dap/LLDBUtils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp index 3c7623ec1215d..fe0bcda19b4cd 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.cpp +++ b/lldb/tools/lldb-dap/LLDBUtils.cpp @@ -247,8 +247,8 @@ std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec) { const auto directory_length = ::strlen(file_spec.GetDirectory()); const auto file_name_length = ::strlen(file_spec.GetFilename()); - std::string path(directory_length + file_name_length + 2, '\0'); - file_spec.GetPath(path.data(), path.length()); + std::string path(directory_length + file_name_length + 1, '\0'); + file_spec.GetPath(path.data(), path.length() + 1); return path; } >From 9dbca55d01c7faddc9df4586ba25c6fac421d909 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 13:59:53 +0200 Subject: [PATCH 12/13] restore SBFileSpec changes --- lldb/include/lldb/API/SBFileSpec.h | 1 - lldb/source/API/SBFileSpec.cpp | 1 - lldb/tools/lldb-dap/DAP.cpp | 8 ++++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index 1bb28b2ddab01..36641843aabeb 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -10,7 +10,6 @@ #define LLDB_API_SBFILESPEC_H #include "lldb/API/SBDefines.h" -#include "lldb/API/SBStream.h" namespace lldb { diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp index f18857f59171a..a7df9afc4b8eb 100644 --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -19,7 +19,6 @@ #include #include -#include using namespace lldb; using namespace lldb_private; diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 1fe46fc619d73..d7ef886dd2419 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1626,16 +1626,16 @@ std::vector DAP::SetSourceBreakpoints( std::vector response_breakpoints; if (source.sourceReference) { // breakpoint set by assembly source. - auto &existing_breakpoints_pos = + auto &existing_breakpoints = m_source_assembly_breakpoints[*source.sourceReference]; response_breakpoints = - SetSourceBreakpoints(source, breakpoints, existing_breakpoints_pos); + SetSourceBreakpoints(source, breakpoints, existing_breakpoints); } else { // breakpoint set by a regular source file. const auto path = source.path.value_or(""); - auto &existing_breakpoints_pos = m_source_breakpoints[path]; + auto &existing_breakpoints = m_source_breakpoints[path]; response_breakpoints = - SetSourceBreakpoints(source, breakpoints, existing_breakpoints_pos); + SetSourceBreakpoints(source, breakpoints, existing_breakpoints); } return response_breakpoints; >From 396970d6a46063450741b6b0c9c528078e433e24 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 14:01:28 +0200 Subject: [PATCH 13/13] single line if with comments curly braces --- lldb/tools/lldb-dap/JSONUtils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 1d2a6ff60e502..dcc25c9212432 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -661,10 +661,11 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, frame_name = name; } - if (frame_name.empty()) + if (frame_name.empty()) { // If the function name is unavailable, display the pc address as a 16-digit // hex string, e.g. "0x0000000000012345" frame_name = GetLoadAddressString(frame.GetPC()); + } // We only include `[opt]` if a custom frame format is not specified. if (!format && frame.GetFunction().GetIsOptimized()) From lldb-commits at lists.llvm.org Sun May 18 05:04:45 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 05:04:45 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Move the command plugins out of the DAP header (PR #140396) In-Reply-To: Message-ID: <6829ccdd.170a0220.95b01.ab79@mx.google.com> https://github.com/eronnen approved this pull request. https://github.com/llvm/llvm-project/pull/140396 From lldb-commits at lists.llvm.org Sun May 18 05:06:56 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 05:06:56 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <6829cd60.170a0220.38baf2.a411@mx.google.com> https://github.com/eronnen updated https://github.com/llvm/llvm-project/pull/139969 >From d6325b3f6a8602fc96ad72acecfcccda1120614d Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sat, 10 May 2025 20:45:17 +0200 Subject: [PATCH 01/14] support assembly in BreakpointLocationsRequestHandler --- .../breakpoint/TestDAP_setBreakpoints.py | 1 - .../TestDAP_setExceptionBreakpoints.py | 1 - .../TestDAP_setFunctionBreakpoints.py | 1 - lldb/tools/lldb-dap/DAP.h | 3 + .../Handler/BreakpointLocationsHandler.cpp | 77 +++++++++++++++---- lldb/tools/lldb-dap/Handler/RequestHandler.h | 11 +++ .../lldb-dap/Handler/SourceRequestHandler.cpp | 4 +- 7 files changed, 76 insertions(+), 22 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index aae1251b17c93..26df2573555df 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,7 +12,6 @@ import os - at skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py index 4dc8c5b3c7ded..92ac66cd44c5d 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setExceptionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_functionality(self): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index baaca4d974d5d..946595f639edc 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 8f24c6cf82924..00aa4276852c5 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -219,6 +219,9 @@ struct DAP { llvm::StringSet<> modules; /// @} + /// Number of lines of assembly code to show when no debug info is available. + uint32_t number_of_assembly_lines_for_nodebug = 32; + /// Creates a new DAP sessions. /// /// \param[in] log diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 2ac886c3a5d2c..9eea549d72b00 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "JSONUtils.h" +#include "LLDBUtils.h" #include "RequestHandler.h" #include @@ -19,19 +19,50 @@ namespace lldb_dap { llvm::Expected BreakpointLocationsRequestHandler::Run( const protocol::BreakpointLocationsArguments &args) const { - std::string path = args.source.path.value_or(""); uint32_t start_line = args.line; uint32_t start_column = args.column.value_or(LLDB_INVALID_COLUMN_NUMBER); uint32_t end_line = args.endLine.value_or(start_line); uint32_t end_column = args.endColumn.value_or(std::numeric_limits::max()); + // Find all relevant lines & columns + llvm::SmallVector, 8> locations; + if (args.source.sourceReference) { + AddAssemblyBreakpointLocations(locations, *args.source.sourceReference, + start_line, end_line); + } else { + std::string path = args.source.path.value_or(""); + AddSourceBreakpointLocations(locations, std::move(path), start_line, + start_column, end_line, end_column); + } + + // The line entries are sorted by addresses, but we must return the list + // ordered by line / column position. + std::sort(locations.begin(), locations.end()); + locations.erase(llvm::unique(locations), locations.end()); + + std::vector breakpoint_locations; + for (auto &l : locations) { + protocol::BreakpointLocation lc; + lc.line = l.first; + lc.column = l.second; + breakpoint_locations.push_back(std::move(lc)); + } + + return protocol::BreakpointLocationsResponseBody{ + /*breakpoints=*/std::move(breakpoint_locations)}; +} + +template +void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const { + lldb::SBFileSpec file_spec(path.c_str(), true); lldb::SBSymbolContextList compile_units = dap.target.FindCompileUnits(file_spec); - // Find all relevant lines & columns - llvm::SmallVector, 8> locations; for (uint32_t c_idx = 0, c_limit = compile_units.GetSize(); c_idx < c_limit; ++c_idx) { const lldb::SBCompileUnit &compile_unit = @@ -71,22 +102,34 @@ BreakpointLocationsRequestHandler::Run( locations.emplace_back(line, column); } } +} - // The line entries are sorted by addresses, but we must return the list - // ordered by line / column position. - std::sort(locations.begin(), locations.end()); - locations.erase(llvm::unique(locations), locations.end()); +template +void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { + lldb::SBProcess process = dap.target.GetProcess(); + lldb::SBThread thread = + process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); + lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - std::vector breakpoint_locations; - for (auto &l : locations) { - protocol::BreakpointLocation lc; - lc.line = l.first; - lc.column = l.second; - breakpoint_locations.push_back(std::move(lc)); - } + if (!frame.IsValid()) + return; - return protocol::BreakpointLocationsResponseBody{ - /*breakpoints=*/std::move(breakpoint_locations)}; + lldb::SBSymbol symbol = frame.GetSymbol(); + if (symbol.IsValid()) { + lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); + } + } else { + for (uint32_t i = start_line - 1; + i < dap.number_of_assembly_lines_for_nodebug && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); + } + } } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index e6bccfe12f402..21753bc0552f9 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -16,6 +16,7 @@ #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/JSON.h" @@ -232,6 +233,16 @@ class BreakpointLocationsRequestHandler } llvm::Expected Run(const protocol::BreakpointLocationsArguments &args) const override; + + template + void AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const; + template + void AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const; }; class CompletionsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp index 0ddd87881a164..fb396a3dc8862 100644 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp @@ -52,8 +52,8 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { insts.GetDescription(stream, exe_ctx); } else { // No valid symbol, just return the disassembly. - lldb::SBInstructionList insts = - dap.target.ReadInstructions(frame.GetPCAddress(), 32); + lldb::SBInstructionList insts = dap.target.ReadInstructions( + frame.GetPCAddress(), dap.number_of_assembly_lines_for_nodebug); insts.GetDescription(stream, exe_ctx); } >From ee492031bee8106fb2a4ff22a8563005f5afd86c Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 11 May 2025 19:49:03 +0200 Subject: [PATCH 02/14] support assembly in SetBreakpointsRequestHandler --- lldb/tools/lldb-dap/DAP.h | 1 + .../Handler/BreakpointLocationsHandler.cpp | 20 ++--- lldb/tools/lldb-dap/Handler/RequestHandler.h | 9 ++ .../Handler/SetBreakpointsRequestHandler.cpp | 90 ++++++++++++++++++- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 22 +++++ lldb/tools/lldb-dap/SourceBreakpoint.h | 1 + 6 files changed, 127 insertions(+), 16 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 00aa4276852c5..5ce0e534611c1 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -169,6 +169,7 @@ struct DAP { Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; + llvm::DenseMap assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 9eea549d72b00..be02c47056310 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -117,18 +117,14 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( return; lldb::SBSymbol symbol = frame.GetSymbol(); - if (symbol.IsValid()) { - lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); - ++i) { - locations.emplace_back(i, 0); - } - } else { - for (uint32_t i = start_line - 1; - i < dap.number_of_assembly_lines_for_nodebug && i < (end_line - 1); - ++i) { - locations.emplace_back(i, 0); - } + if (!symbol.IsValid()) + return; + + // start_line is relative to the symbol's start address + lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); } } diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 21753bc0552f9..72843aaef8150 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -389,6 +389,15 @@ class SetBreakpointsRequestHandler } llvm::Expected Run(const protocol::SetBreakpointsArguments &args) const override; + + std::vector SetSourceBreakpoints( + const std::string &path, + const std::optional> &breakpoints) + const; + std::vector SetAssemblyBreakpoints( + int64_t sourceReference, + const std::optional> &breakpoints) + const; }; class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 86e090b66afe9..71f9e5578ef08 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -9,8 +9,11 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" +#include +#include #include namespace lldb_dap { @@ -23,15 +26,30 @@ llvm::Expected SetBreakpointsRequestHandler::Run( const protocol::SetBreakpointsArguments &args) const { const auto &source = args.source; - const auto path = source.path.value_or(""); + std::vector response_breakpoints; + if (source.sourceReference) + response_breakpoints = SetAssemblyBreakpoints( + source.sourceReference.value(), args.breakpoints); + else if (source.path) + response_breakpoints = + SetSourceBreakpoints(source.path.value(), args.breakpoints); + + return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; +} + +std::vector +SetBreakpointsRequestHandler::SetSourceBreakpoints( + const std::string &path, + const std::optional> &breakpoints) + const { std::vector response_breakpoints; // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; // "breakpoints" may be unset, in which case we treat it the same as being set // to an empty array. - if (args.breakpoints) { - for (const auto &bp : *args.breakpoints) { + if (breakpoints) { + for (const auto &bp : *breakpoints) { SourceBreakpoint src_bp(dap, bp); std::pair bp_pos(src_bp.GetLine(), src_bp.GetColumn()); @@ -73,7 +91,71 @@ SetBreakpointsRequestHandler::Run( } } - return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; + return response_breakpoints; +} + +std::vector +SetBreakpointsRequestHandler::SetAssemblyBreakpoints( + int64_t sourceReference, + const std::optional> &breakpoints) + const { + std::vector response_breakpoints; + + lldb::SBProcess process = dap.target.GetProcess(); + lldb::SBThread thread = + process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); + lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); + + if (!frame.IsValid()) + return response_breakpoints; + + lldb::SBSymbol symbol = frame.GetSymbol(); + if (!symbol.IsValid()) + return response_breakpoints; // Not yet supporting breakpoints in assembly + // without a valid symbol + + SourceBreakpointMap request_bps; + if (breakpoints) { + for (const auto &bp : *breakpoints) { + SourceBreakpoint src_bp(dap, bp); + std::pair bp_pos(src_bp.GetLine(), 0); + request_bps.try_emplace(bp_pos, src_bp); + const auto [iv, inserted] = + dap.assembly_breakpoints[sourceReference].try_emplace(bp_pos, src_bp); + // We check if this breakpoint already exists to update it + if (inserted) + iv->getSecond().SetBreakpoint(symbol); + else + iv->getSecond().UpdateBreakpoint(src_bp); + + protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); + protocol::Source source; + source.sourceReference = sourceReference; + source.name = symbol.GetName(); + response_bp.source = std::move(source); + + if (!response_bp.line) + response_bp.line = src_bp.GetLine(); + if (!response_bp.column) + response_bp.column = src_bp.GetColumn(); + response_breakpoints.push_back(response_bp); + } + } + + // Delete existing breakpoints for this sourceReference that are not in the + // request_bps set. + auto old_src_bp_pos = dap.assembly_breakpoints.find(sourceReference); + if (old_src_bp_pos != dap.assembly_breakpoints.end()) { + for (auto &old_bp : old_src_bp_pos->second) { + auto request_pos = request_bps.find(old_bp.first); + if (request_pos == request_bps.end()) { + dap.target.BreakpointDelete(old_bp.second.GetID()); + old_src_bp_pos->second.erase(old_bp.first); + } + } + } + + return response_breakpoints; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 4581c995b4260..938b8fb8bcdda 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -13,7 +13,9 @@ #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBFileSpecList.h" #include "lldb/API/SBFrame.h" +#include "lldb/API/SBInstruction.h" #include "lldb/API/SBMutex.h" +#include "lldb/API/SBSymbol.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" #include "lldb/API/SBValue.h" @@ -45,6 +47,26 @@ void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) { Breakpoint::SetBreakpoint(); } +void SourceBreakpoint::SetBreakpoint(lldb::SBSymbol &symbol) { + lldb::SBMutex lock = m_dap.GetAPIMutex(); + std::lock_guard guard(lock); + + if (m_line == 0) + return; + + lldb::SBInstructionList inst_list = + m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); + if (inst_list.GetSize() < m_line) + return; + lldb::SBAddress address = + inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + + m_bp = m_dap.target.BreakpointCreateBySBAddress(address); + if (!m_log_message.empty()) + SetLogMessage(); + Breakpoint::SetBreakpoint(); +} + void SourceBreakpoint::UpdateBreakpoint(const SourceBreakpoint &request_bp) { if (m_log_message != request_bp.m_log_message) { m_log_message = request_bp.m_log_message; diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h index 5b15296f861c5..8589800e50983 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.h +++ b/lldb/tools/lldb-dap/SourceBreakpoint.h @@ -26,6 +26,7 @@ class SourceBreakpoint : public Breakpoint { // Set this breakpoint in LLDB as a new breakpoint void SetBreakpoint(const llvm::StringRef source_path); + void SetBreakpoint(lldb::SBSymbol &symbol); void UpdateBreakpoint(const SourceBreakpoint &request_bp); void SetLogMessage(); >From dbb2f9bd55b3f86247e03b2610fca9576e124637 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Wed, 14 May 2025 23:51:41 +0200 Subject: [PATCH 03/14] fix resolving of assembly source breakpoints --- lldb/tools/lldb-dap/Breakpoint.cpp | 45 ++++++++++++++++--- lldb/tools/lldb-dap/DAP.h | 3 +- .../Handler/BreakpointLocationsHandler.cpp | 4 +- lldb/tools/lldb-dap/Handler/RequestHandler.h | 4 +- .../Handler/SetBreakpointsRequestHandler.cpp | 30 ++++++------- lldb/tools/lldb-dap/package-lock.json | 4 +- lldb/tools/lldb-dap/package.json | 5 ++- 7 files changed, 63 insertions(+), 32 deletions(-) diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 26d633d1d172e..87fcd15b0a568 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -9,10 +9,12 @@ #include "Breakpoint.h" #include "DAP.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "lldb/API/SBAddress.h" #include "lldb/API/SBBreakpointLocation.h" #include "lldb/API/SBLineEntry.h" #include "lldb/API/SBMutex.h" +#include "lldb/lldb-enumerations.h" #include "llvm/ADT/StringExtras.h" #include #include @@ -63,14 +65,43 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { std::string formatted_addr = "0x" + llvm::utohexstr(bp_addr.GetLoadAddress(m_bp.GetTarget())); breakpoint.instructionReference = formatted_addr; + + lldb::StopDisassemblyType stop_disassembly_display = + GetStopDisassemblyDisplay(m_dap.debugger); auto line_entry = bp_addr.GetLineEntry(); - const auto line = line_entry.GetLine(); - if (line != UINT32_MAX) - breakpoint.line = line; - const auto column = line_entry.GetColumn(); - if (column != 0) - breakpoint.column = column; - breakpoint.source = CreateSource(line_entry); + if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) { + const auto line = line_entry.GetLine(); + if (line != UINT32_MAX) + breakpoint.line = line; + const auto column = line_entry.GetColumn(); + if (column != 0) + breakpoint.column = column; + breakpoint.source = CreateSource(line_entry); + } else { + // Breakpoint made by assembly + auto symbol_context = bp_addr.GetSymbolContext( + lldb::eSymbolContextSymbol | lldb::eSymbolContextModule); + if (symbol_context.IsValid()) { + auto symbol = symbol_context.GetSymbol(); + breakpoint.line = + m_bp.GetTarget() + .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) + .GetSize() + + 1; + protocol::Source source; + source.name = symbol.GetName(); + + auto module = symbol_context.GetModule(); + if (module.IsValid()) { + std::string path = module.GetFileSpec().GetDirectory(); + path += "/"; + path += module.GetFileSpec().GetFilename(); + source.path = std::move(path); + } + + breakpoint.source = std::move(source); + } + } } return breakpoint; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 5ce0e534611c1..b0fe265b7bca1 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -169,7 +169,8 @@ struct DAP { Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; - llvm::DenseMap assembly_breakpoints; + llvm::DenseMap> + assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index be02c47056310..06ada47a6f27f 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -122,9 +122,9 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( // start_line is relative to the symbol's start address lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i <= (end_line - 1); ++i) { - locations.emplace_back(i, 0); + locations.emplace_back(i, 1); } } diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 72843aaef8150..80898d1ee5ef1 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -391,11 +391,11 @@ class SetBreakpointsRequestHandler Run(const protocol::SetBreakpointsArguments &args) const override; std::vector SetSourceBreakpoints( - const std::string &path, + const protocol::Source &source, const std::optional> &breakpoints) const; std::vector SetAssemblyBreakpoints( - int64_t sourceReference, + const protocol::Source &source, const std::optional> &breakpoints) const; }; diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 71f9e5578ef08..4fefd8b440c7d 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -28,21 +28,20 @@ SetBreakpointsRequestHandler::Run( const auto &source = args.source; std::vector response_breakpoints; if (source.sourceReference) - response_breakpoints = SetAssemblyBreakpoints( - source.sourceReference.value(), args.breakpoints); + response_breakpoints = SetAssemblyBreakpoints(source, args.breakpoints); else if (source.path) - response_breakpoints = - SetSourceBreakpoints(source.path.value(), args.breakpoints); + response_breakpoints = SetSourceBreakpoints(source, args.breakpoints); return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; } std::vector SetBreakpointsRequestHandler::SetSourceBreakpoints( - const std::string &path, + const protocol::Source &source, const std::optional> &breakpoints) const { std::vector response_breakpoints; + std::string path = source.path.value_or(""); // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; @@ -96,10 +95,11 @@ SetBreakpointsRequestHandler::SetSourceBreakpoints( std::vector SetBreakpointsRequestHandler::SetAssemblyBreakpoints( - int64_t sourceReference, + const protocol::Source &source, const std::optional> &breakpoints) const { std::vector response_breakpoints; + int64_t sourceReference = source.sourceReference.value_or(0); lldb::SBProcess process = dap.target.GetProcess(); lldb::SBThread thread = @@ -114,14 +114,14 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( return response_breakpoints; // Not yet supporting breakpoints in assembly // without a valid symbol - SourceBreakpointMap request_bps; + llvm::DenseMap request_bps; if (breakpoints) { for (const auto &bp : *breakpoints) { SourceBreakpoint src_bp(dap, bp); - std::pair bp_pos(src_bp.GetLine(), 0); - request_bps.try_emplace(bp_pos, src_bp); + request_bps.try_emplace(src_bp.GetLine(), src_bp); const auto [iv, inserted] = - dap.assembly_breakpoints[sourceReference].try_emplace(bp_pos, src_bp); + dap.assembly_breakpoints[sourceReference].try_emplace( + src_bp.GetLine(), src_bp); // We check if this breakpoint already exists to update it if (inserted) iv->getSecond().SetBreakpoint(symbol); @@ -129,15 +129,11 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( iv->getSecond().UpdateBreakpoint(src_bp); protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - protocol::Source source; - source.sourceReference = sourceReference; - source.name = symbol.GetName(); - response_bp.source = std::move(source); - + response_bp.source = source; if (!response_bp.line) response_bp.line = src_bp.GetLine(); - if (!response_bp.column) - response_bp.column = src_bp.GetColumn(); + if (bp.column) + response_bp.column = *bp.column; response_breakpoints.push_back(response_bp); } } diff --git a/lldb/tools/lldb-dap/package-lock.json b/lldb/tools/lldb-dap/package-lock.json index 0a2b9e764067e..af90a9573aee6 100644 --- a/lldb/tools/lldb-dap/package-lock.json +++ b/lldb/tools/lldb-dap/package-lock.json @@ -1,12 +1,12 @@ { "name": "lldb-dap", - "version": "0.2.13", + "version": "0.2.14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lldb-dap", - "version": "0.2.13", + "version": "0.2.14", "license": "Apache 2.0 License with LLVM exceptions", "devDependencies": { "@types/node": "^18.19.41", diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index d5ca604798799..73e70cd961f4f 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -1,7 +1,7 @@ { "name": "lldb-dap", "displayName": "LLDB DAP", - "version": "0.2.13", + "version": "0.2.14", "publisher": "llvm-vs-code-extensions", "homepage": "https://lldb.llvm.org", "description": "Debugging with LLDB in Visual Studio Code", @@ -265,6 +265,9 @@ ] }, "breakpoints": [ + { + "language": "lldb.disassembly" + }, { "language": "ada" }, >From 3699524618ed76f969cc26a63610fe54e3605139 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Thu, 15 May 2025 00:36:10 +0200 Subject: [PATCH 04/14] remove include --- lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 4fefd8b440c7d..d69da5bd02c1e 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -12,8 +12,6 @@ #include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" -#include -#include #include namespace lldb_dap { >From 61623deb7e249a8ca0c63e3f66955790da5e4ced Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sat, 17 May 2025 21:05:27 +0200 Subject: [PATCH 05/14] use load address as sourceReference --- lldb/include/lldb/API/SBFileSpec.h | 3 + lldb/source/API/SBFileSpec.cpp | 8 ++ lldb/tools/lldb-dap/Breakpoint.cpp | 18 +---- .../Handler/BreakpointLocationsHandler.cpp | 11 +-- .../Handler/SetBreakpointsRequestHandler.cpp | 11 +-- .../lldb-dap/Handler/SourceRequestHandler.cpp | 18 ++--- lldb/tools/lldb-dap/JSONUtils.cpp | 75 +++++++++++++------ lldb/tools/lldb-dap/JSONUtils.h | 14 ++++ 8 files changed, 96 insertions(+), 62 deletions(-) diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index 36641843aabeb..303cb7d712cbf 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -10,6 +10,7 @@ #define LLDB_API_SBFILESPEC_H #include "lldb/API/SBDefines.h" +#include "lldb/API/SBStream.h" namespace lldb { @@ -53,6 +54,8 @@ class LLDB_API SBFileSpec { uint32_t GetPath(char *dst_path, size_t dst_len) const; + bool GetPath(lldb::SBStream &dst_path) const; + static int ResolvePath(const char *src_path, char *dst_path, size_t dst_len); bool GetDescription(lldb::SBStream &description) const; diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp index a7df9afc4b8eb..cb44dac1d4fcc 100644 --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -19,6 +19,7 @@ #include #include +#include using namespace lldb; using namespace lldb_private; @@ -147,6 +148,13 @@ uint32_t SBFileSpec::GetPath(char *dst_path, size_t dst_len) const { return result; } +bool SBFileSpec::GetPath(SBStream &dst_path) const { + LLDB_INSTRUMENT_VA(this, dst_path); + + std::string path = m_opaque_up->GetPath(); + return dst_path->PutCString(path.c_str()) > 0; +} + const lldb_private::FileSpec *SBFileSpec::operator->() const { return m_opaque_up.get(); } diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 87fcd15b0a568..a54a34e0f936d 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -79,27 +79,15 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { breakpoint.source = CreateSource(line_entry); } else { // Breakpoint made by assembly - auto symbol_context = bp_addr.GetSymbolContext( - lldb::eSymbolContextSymbol | lldb::eSymbolContextModule); - if (symbol_context.IsValid()) { - auto symbol = symbol_context.GetSymbol(); + auto symbol = bp_addr.GetSymbol(); + if (symbol.IsValid()) { breakpoint.line = m_bp.GetTarget() .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) .GetSize() + 1; - protocol::Source source; - source.name = symbol.GetName(); - auto module = symbol_context.GetModule(); - if (module.IsValid()) { - std::string path = module.GetFileSpec().GetDirectory(); - path += "/"; - path += module.GetFileSpec().GetFilename(); - source.path = std::move(path); - } - - breakpoint.source = std::move(source); + breakpoint.source = CreateAssemblySource(m_dap.target, bp_addr); } } } diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 06ada47a6f27f..c4d658caeee2d 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "LLDBUtils.h" #include "RequestHandler.h" #include @@ -108,15 +107,11 @@ template void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( llvm::SmallVector, N> &locations, int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { - lldb::SBProcess process = dap.target.GetProcess(); - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - - if (!frame.IsValid()) + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) return; - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) return; diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index d69da5bd02c1e..7b401f06e9a85 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -9,7 +9,6 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" -#include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" #include @@ -99,15 +98,11 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( std::vector response_breakpoints; int64_t sourceReference = source.sourceReference.value_or(0); - lldb::SBProcess process = dap.target.GetProcess(); - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - - if (!frame.IsValid()) + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) return response_breakpoints; - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) return response_breakpoints; // Not yet supporting breakpoints in assembly // without a valid symbol diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp index fb396a3dc8862..9249e2aa6fef7 100644 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp @@ -11,6 +11,7 @@ #include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" +#include "lldb/API/SBAddress.h" #include "lldb/API/SBExecutionContext.h" #include "lldb/API/SBFrame.h" #include "lldb/API/SBInstructionList.h" @@ -19,6 +20,7 @@ #include "lldb/API/SBSymbol.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" +#include "lldb/lldb-types.h" #include "llvm/Support/Error.h" namespace lldb_dap { @@ -34,18 +36,14 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { return llvm::make_error( "invalid arguments, expected source.sourceReference to be set"); - lldb::SBProcess process = dap.target.GetProcess(); - // Upper 32 bits is the thread index ID - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(source)); - // Lower 32 bits is the frame index - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(source)); - if (!frame.IsValid()) + lldb::SBAddress address(source, dap.target); + if (!address.IsValid()) return llvm::make_error("source not found"); + lldb::SBSymbol symbol = address.GetSymbol(); + lldb::SBStream stream; - lldb::SBExecutionContext exe_ctx(frame); - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBExecutionContext exe_ctx(dap.target); if (symbol.IsValid()) { lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); @@ -53,7 +51,7 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { } else { // No valid symbol, just return the disassembly. lldb::SBInstructionList insts = dap.target.ReadInstructions( - frame.GetPCAddress(), dap.number_of_assembly_lines_for_nodebug); + address, dap.number_of_assembly_lines_for_nodebug); insts.GetDescription(stream, exe_ctx); } diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 714947a4d3b9c..c8151c3d64ea4 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -490,6 +490,13 @@ CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp) { return filter; } +static std::string GetLoadAddressString(const lldb::addr_t addr) { + std::string result; + llvm::raw_string_ostream os(result); + os << llvm::format_hex(addr, 18); + return result; +} + protocol::Source CreateSource(const lldb::SBFileSpec &file) { protocol::Source source; if (file.IsValid()) { @@ -516,6 +523,43 @@ protocol::Source CreateSource(llvm::StringRef source_path) { return source; } +protocol::Source CreateAssemblySource(const lldb::SBTarget &target, + lldb::SBAddress &address) { + protocol::Source source; + + auto symbol = address.GetSymbol(); + std::string name; + if (symbol.IsValid()) { + source.sourceReference = symbol.GetStartAddress().GetLoadAddress(target); + name = symbol.GetName(); + } else { + const auto load_addr = address.GetLoadAddress(target); + source.sourceReference = load_addr; + name = GetLoadAddressString(load_addr); + } + + lldb::SBModule module = address.GetModule(); + if (module.IsValid()) { + lldb::SBFileSpec file_spec = module.GetFileSpec(); + if (file_spec.IsValid()) { + lldb::SBStream module_path; + if (file_spec.GetPath(module_path)) { + std::string path = module_path.GetData(); + source.path = path + '`' + name; + } + } + } + + source.name = std::move(name); + + // Mark the source as deemphasized since users will only be able to view + // assembly for these frames. + source.presentationHint = + protocol::Source::PresentationHint::eSourcePresentationHintDeemphasize; + + return source; +} + bool ShouldDisplayAssemblySource( const lldb::SBLineEntry &line_entry, lldb::StopDisassemblyType stop_disassembly_display) { @@ -619,12 +663,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, frame_name = name; } - if (frame_name.empty()) { + if (frame_name.empty()) // If the function name is unavailable, display the pc address as a 16-digit // hex string, e.g. "0x0000000000012345" - llvm::raw_string_ostream os(frame_name); - os << llvm::format_hex(frame.GetPC(), 18); - } + frame_name = GetLoadAddressString(frame.GetPC()); // We only include `[opt]` if a custom frame format is not specified. if (!format && frame.GetFunction().GetIsOptimized()) @@ -641,17 +683,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, } else if (frame.GetSymbol().IsValid()) { // If no source is associated with the frame, use the DAPFrameID to track // the 'source' and generate assembly. - llvm::json::Object source; - EmplaceSafeString(source, "name", frame_name); - char buf[PATH_MAX] = {0}; - size_t size = frame.GetModule().GetFileSpec().GetPath(buf, PATH_MAX); - EmplaceSafeString(source, "path", - std::string(buf, size) + '`' + frame_name); - source.try_emplace("sourceReference", MakeDAPFrameID(frame)); - // Mark the source as deemphasized since users will only be able to view - // assembly for these frames. - EmplaceSafeString(source, "presentationHint", "deemphasize"); - object.try_emplace("source", std::move(source)); + auto frame_address = frame.GetPCAddress(); + object.try_emplace("source", CreateAssemblySource( + frame.GetThread().GetProcess().GetTarget(), + frame_address)); // Calculate the line of the current PC from the start of the current // symbol. @@ -665,12 +700,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, object.try_emplace("column", 1); } else { // No valid line entry or symbol. - llvm::json::Object source; - EmplaceSafeString(source, "name", frame_name); - source.try_emplace("sourceReference", MakeDAPFrameID(frame)); - EmplaceSafeString(source, "presentationHint", "deemphasize"); - object.try_emplace("source", std::move(source)); - + auto frame_address = frame.GetPCAddress(); + object.try_emplace("source", CreateAssemblySource( + frame.GetThread().GetProcess().GetTarget(), + frame_address)); object.try_emplace("line", 1); object.try_emplace("column", 1); } diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h index 783f291338d8c..ac9b39739104f 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -269,6 +269,20 @@ protocol::Source CreateSource(const lldb::SBLineEntry &line_entry); /// definition outlined by Microsoft. protocol::Source CreateSource(llvm::StringRef source_path); +/// Create a "Source" object for a given frame, using its assembly for source. +/// +/// \param[in] target +/// The relevant target. +/// +/// \param[in] address +/// The address to use when creating the "Source" object. +/// +/// \return +/// A "Source" JSON object that follows the formal JSON +/// definition outlined by Microsoft. +protocol::Source CreateAssemblySource(const lldb::SBTarget &target, + lldb::SBAddress &address); + /// Return true if the given line entry should be displayed as assembly. /// /// \param[in] line_entry >From f5fd76de3ad25b9cbf6ce065e06c98ff30b070a8 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 02:22:19 +0200 Subject: [PATCH 06/14] add breakpoint-assembly test --- .../test/tools/lldb-dap/dap_server.py | 7 ++++ .../test/tools/lldb-dap/lldbdap_testcase.py | 10 +++++ .../lldb-dap/breakpoint-assembly/Makefile | 3 ++ .../TestDAP_breakpointAssembly.py | 42 +++++++++++++++++++ .../tools/lldb-dap/breakpoint-assembly/main.c | 14 +++++++ .../breakpoint/TestDAP_setBreakpoints.py | 1 + .../TestDAP_setExceptionBreakpoints.py | 1 + .../TestDAP_setFunctionBreakpoints.py | 1 + 8 files changed, 79 insertions(+) create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index 70fd0b0c419db..4a907a5e36901 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -955,6 +955,13 @@ def request_setBreakpoints(self, file_path, line_array, data=None): """ (dir, base) = os.path.split(file_path) source_dict = {"name": base, "path": file_path} + return self.request_setBreakpoints_with_source(source_dict, line_array, data) + + def request_setBreakpointsAssembly(self, sourceReference, line_array, data=None): + source_dict = {"sourceReference": sourceReference} + return self.request_setBreakpoints_with_source(source_dict, line_array, data) + + def request_setBreakpoints_with_source(self, source_dict, line_array, data=None): args_dict = { "source": source_dict, "sourceModified": False, diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index afdc746ed0d0d..427f66a7da0c8 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -63,6 +63,16 @@ def set_source_breakpoints(self, source_path, lines, data=None): for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) return breakpoint_ids + + def set_source_breakpoints_assembly(self, source_reference, lines, data=None): + response = self.dap_server.request_setBreakpointsAssembly(source_reference, lines, data) + if response is None: + return [] + breakpoints = response["body"]["breakpoints"] + breakpoint_ids = [] + for breakpoint in breakpoints: + breakpoint_ids.append("%i" % (breakpoint["id"])) + return breakpoint_ids def set_function_breakpoints(self, functions, condition=None, hitCondition=None): """Sets breakpoints by function name given an array of function names diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile new file mode 100644 index 0000000000000..10495940055b6 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py new file mode 100644 index 0000000000000..ba9df3a18590b --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py @@ -0,0 +1,42 @@ +""" +Test lldb-dap setBreakpoints request +""" + + +import dap_server +import shutil +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +import lldbdap_testcase +import os + + +class TestDAP_setBreakpointsAssembly(lldbdap_testcase.DAPTestCaseBase): + # @skipIfWindows + def test_functionality(self): + """Tests hitting assembly source breakpoints""" + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + + self.dap_server.request_evaluate( + "`settings set stop-disassembly-display no-debuginfo", context="repl" + ) + + assmebly_func_breakpoints = self.set_function_breakpoints(["assembly_func"]) + self.continue_to_breakpoints(assmebly_func_breakpoints) + + assembly_func_frame = self.get_stackFrames()[0] + self.assertIn( + "sourceReference", + assembly_func_frame.get("source"), + "Expected assembly source frame", + ) + + line = assembly_func_frame["line"] + + # Set an assembly breakpoint in the next line and check that it's hit + assembly_breakpoint_ids = self.set_source_breakpoints_assembly( + assembly_func_frame["source"]["sourceReference"], [line + 1] + ) + self.continue_to_breakpoints(assembly_breakpoint_ids) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c new file mode 100644 index 0000000000000..350739006f903 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c @@ -0,0 +1,14 @@ +#include + +__attribute__((nodebug)) int assembly_func(int n) { + n += 1; + n += 2; + n += 3; + + return n; +} + +int main(int argc, char const *argv[]) { + assembly_func(10); + return 0; +} diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index 26df2573555df..aae1251b17c93 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,6 +12,7 @@ import os + at skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py index 92ac66cd44c5d..4dc8c5b3c7ded 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py @@ -10,6 +10,7 @@ import lldbdap_testcase + at skip("Temporarily disable the breakpoint tests") class TestDAP_setExceptionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_functionality(self): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index 946595f639edc..baaca4d974d5d 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,6 +10,7 @@ import lldbdap_testcase + at skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): >From 40f68e418bfbb6564b3834382c4a33a3104fc33d Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 10:23:11 +0200 Subject: [PATCH 07/14] python format --- .../lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index 427f66a7da0c8..3bf649a087fdb 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -63,9 +63,11 @@ def set_source_breakpoints(self, source_path, lines, data=None): for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) return breakpoint_ids - + def set_source_breakpoints_assembly(self, source_reference, lines, data=None): - response = self.dap_server.request_setBreakpointsAssembly(source_reference, lines, data) + response = self.dap_server.request_setBreakpointsAssembly( + source_reference, lines, data + ) if response is None: return [] breakpoints = response["body"]["breakpoints"] >From 199512fd7a0900d45070b95dd52ef5ef136e2719 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 10:54:43 +0200 Subject: [PATCH 08/14] restore SBFileSpec and fix assembly breakpoints CR --- lldb/include/lldb/API/SBFileSpec.h | 2 - lldb/source/API/SBFileSpec.cpp | 7 --- lldb/tools/lldb-dap/DAP.h | 2 +- .../Handler/BreakpointLocationsHandler.cpp | 47 ++++++++++--------- lldb/tools/lldb-dap/Handler/RequestHandler.h | 17 ++++--- .../Handler/SetBreakpointsRequestHandler.cpp | 9 ++-- lldb/tools/lldb-dap/JSONUtils.cpp | 6 +-- lldb/tools/lldb-dap/LLDBUtils.cpp | 10 ++++ lldb/tools/lldb-dap/LLDBUtils.h | 10 ++++ 9 files changed, 60 insertions(+), 50 deletions(-) diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index 303cb7d712cbf..1bb28b2ddab01 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -54,8 +54,6 @@ class LLDB_API SBFileSpec { uint32_t GetPath(char *dst_path, size_t dst_len) const; - bool GetPath(lldb::SBStream &dst_path) const; - static int ResolvePath(const char *src_path, char *dst_path, size_t dst_len); bool GetDescription(lldb::SBStream &description) const; diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp index cb44dac1d4fcc..f18857f59171a 100644 --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -148,13 +148,6 @@ uint32_t SBFileSpec::GetPath(char *dst_path, size_t dst_len) const { return result; } -bool SBFileSpec::GetPath(SBStream &dst_path) const { - LLDB_INSTRUMENT_VA(this, dst_path); - - std::string path = m_opaque_up->GetPath(); - return dst_path->PutCString(path.c_str()) > 0; -} - const lldb_private::FileSpec *SBFileSpec::operator->() const { return m_opaque_up.get(); } diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index b0fe265b7bca1..20f95be792f41 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -222,7 +222,7 @@ struct DAP { /// @} /// Number of lines of assembly code to show when no debug info is available. - uint32_t number_of_assembly_lines_for_nodebug = 32; + static constexpr uint32_t number_of_assembly_lines_for_nodebug = 32; /// Creates a new DAP sessions. /// diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index c4d658caeee2d..794b83a9e0e1e 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -8,6 +8,7 @@ #include "DAP.h" #include "RequestHandler.h" +#include #include namespace lldb_dap { @@ -24,15 +25,15 @@ BreakpointLocationsRequestHandler::Run( uint32_t end_column = args.endColumn.value_or(std::numeric_limits::max()); - // Find all relevant lines & columns - llvm::SmallVector, 8> locations; - if (args.source.sourceReference) { - AddAssemblyBreakpointLocations(locations, *args.source.sourceReference, - start_line, end_line); - } else { + // Find all relevant lines & columns. + std::vector> locations; + if (args.source.sourceReference) + locations = GetAssemblyBreakpointLocations(*args.source.sourceReference, + start_line, end_line); + else { std::string path = args.source.path.value_or(""); - AddSourceBreakpointLocations(locations, std::move(path), start_line, - start_column, end_line, end_column); + locations = GetSourceBreakpointLocations( + std::move(path), start_line, start_column, end_line, end_column); } // The line entries are sorted by addresses, but we must return the list @@ -41,23 +42,19 @@ BreakpointLocationsRequestHandler::Run( locations.erase(llvm::unique(locations), locations.end()); std::vector breakpoint_locations; - for (auto &l : locations) { - protocol::BreakpointLocation lc; - lc.line = l.first; - lc.column = l.second; - breakpoint_locations.push_back(std::move(lc)); - } + for (auto &l : locations) + breakpoint_locations.push_back( + {l.first, l.second, std::nullopt, std::nullopt}); return protocol::BreakpointLocationsResponseBody{ /*breakpoints=*/std::move(breakpoint_locations)}; } -template -void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( - llvm::SmallVector, N> &locations, +std::vector> +BreakpointLocationsRequestHandler::GetSourceBreakpointLocations( std::string path, uint32_t start_line, uint32_t start_column, uint32_t end_line, uint32_t end_column) const { - + std::vector> locations; lldb::SBFileSpec file_spec(path.c_str(), true); lldb::SBSymbolContextList compile_units = dap.target.FindCompileUnits(file_spec); @@ -101,19 +98,21 @@ void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( locations.emplace_back(line, column); } } + + return locations; } -template -void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( - llvm::SmallVector, N> &locations, +std::vector> +BreakpointLocationsRequestHandler::GetAssemblyBreakpointLocations( int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { + std::vector> locations; lldb::SBAddress address(sourceReference, dap.target); if (!address.IsValid()) - return; + return locations; lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) - return; + return locations; // start_line is relative to the symbol's start address lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); @@ -121,6 +120,8 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( ++i) { locations.emplace_back(i, 1); } + + return locations; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 80898d1ee5ef1..e708abb50d5c0 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -23,6 +23,7 @@ #include #include #include +#include template struct is_optional : std::false_type {}; @@ -234,15 +235,13 @@ class BreakpointLocationsRequestHandler llvm::Expected Run(const protocol::BreakpointLocationsArguments &args) const override; - template - void AddSourceBreakpointLocations( - llvm::SmallVector, N> &locations, - std::string path, uint32_t start_line, uint32_t start_column, - uint32_t end_line, uint32_t end_column) const; - template - void AddAssemblyBreakpointLocations( - llvm::SmallVector, N> &locations, - int64_t sourceReference, uint32_t start_line, uint32_t end_line) const; + std::vector> + GetSourceBreakpointLocations(std::string path, uint32_t start_line, + uint32_t start_column, uint32_t end_line, + uint32_t end_column) const; + std::vector> + GetAssemblyBreakpointLocations(int64_t sourceReference, uint32_t start_line, + uint32_t end_line) const; }; class CompletionsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 7b401f06e9a85..bf0b584753c07 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -103,9 +103,10 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( return response_breakpoints; lldb::SBSymbol symbol = address.GetSymbol(); - if (!symbol.IsValid()) - return response_breakpoints; // Not yet supporting breakpoints in assembly - // without a valid symbol + if (!symbol.IsValid()) { + // Not yet supporting breakpoints in assembly without a valid symbol. + return response_breakpoints; + } llvm::DenseMap request_bps; if (breakpoints) { @@ -115,7 +116,7 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( const auto [iv, inserted] = dap.assembly_breakpoints[sourceReference].try_emplace( src_bp.GetLine(), src_bp); - // We check if this breakpoint already exists to update it + // We check if this breakpoint already exists to update it. if (inserted) iv->getSecond().SetBreakpoint(symbol); else diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index c8151c3d64ea4..1d2a6ff60e502 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -542,11 +542,9 @@ protocol::Source CreateAssemblySource(const lldb::SBTarget &target, if (module.IsValid()) { lldb::SBFileSpec file_spec = module.GetFileSpec(); if (file_spec.IsValid()) { - lldb::SBStream module_path; - if (file_spec.GetPath(module_path)) { - std::string path = module_path.GetData(); + std::string path = GetSBFileSpecPath(file_spec); + if (!path.empty()) source.path = path + '`' + name; - } } } diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp index 0e7bb2b9058a7..3c7623ec1215d 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.cpp +++ b/lldb/tools/lldb-dap/LLDBUtils.cpp @@ -20,6 +20,7 @@ #include "llvm/Support/JSON.h" #include "llvm/Support/raw_ostream.h" +#include #include #include @@ -242,4 +243,13 @@ ScopeSyncMode::ScopeSyncMode(lldb::SBDebugger &debugger) ScopeSyncMode::~ScopeSyncMode() { m_debugger.SetAsync(m_async); } +std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec) { + const auto directory_length = ::strlen(file_spec.GetDirectory()); + const auto file_name_length = ::strlen(file_spec.GetFilename()); + + std::string path(directory_length + file_name_length + 2, '\0'); + file_spec.GetPath(path.data(), path.length()); + return path; +} + } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/LLDBUtils.h b/lldb/tools/lldb-dap/LLDBUtils.h index 711fc6051231c..7fdf4b859ee61 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.h +++ b/lldb/tools/lldb-dap/LLDBUtils.h @@ -13,6 +13,7 @@ #include "lldb/API/SBDebugger.h" #include "lldb/API/SBEnvironment.h" #include "lldb/API/SBError.h" +#include "lldb/API/SBFileSpec.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" @@ -161,6 +162,15 @@ uint32_t GetLLDBFrameID(uint64_t dap_frame_id); lldb::SBEnvironment GetEnvironmentFromArguments(const llvm::json::Object &arguments); +/// Gets an SBFileSpec and returns its path as a string. +/// +/// \param[in] file_spec +/// The file spec. +/// +/// \return +/// The file path as a string. +std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec); + /// Helper for sending telemetry to lldb server, if client-telemetry is enabled. class TelemetryDispatcher { public: >From dbad33b314bb59f6e0d22fd07dddb35e2a0e30d9 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 12:57:59 +0200 Subject: [PATCH 09/14] abstracted source breakpoints maps by DAP --- lldb/tools/lldb-dap/Breakpoint.cpp | 4 +- lldb/tools/lldb-dap/DAP.cpp | 75 +++++++++++ lldb/tools/lldb-dap/DAP.h | 29 +++- lldb/tools/lldb-dap/Handler/RequestHandler.h | 9 -- .../Handler/SetBreakpointsRequestHandler.cpp | 125 +----------------- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 54 +++++--- lldb/tools/lldb-dap/SourceBreakpoint.h | 7 +- 7 files changed, 140 insertions(+), 163 deletions(-) diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index a54a34e0f936d..fd7531f42c518 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -71,10 +71,10 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { auto line_entry = bp_addr.GetLineEntry(); if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) { const auto line = line_entry.GetLine(); - if (line != UINT32_MAX) + if (line != LLDB_INVALID_LINE_NUMBER) breakpoint.line = line; const auto column = line_entry.GetColumn(); - if (column != 0) + if (column != LLDB_INVALID_COLUMN_NUMBER) breakpoint.column = column; breakpoint.source = CreateSource(line_entry); } else { diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 0d5eba6c40961..1fe46fc619d73 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1620,6 +1620,81 @@ void DAP::EventThread() { } } +std::vector DAP::SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints) { + std::vector response_breakpoints; + if (source.sourceReference) { + // breakpoint set by assembly source. + auto &existing_breakpoints_pos = + m_source_assembly_breakpoints[*source.sourceReference]; + response_breakpoints = + SetSourceBreakpoints(source, breakpoints, existing_breakpoints_pos); + } else { + // breakpoint set by a regular source file. + const auto path = source.path.value_or(""); + auto &existing_breakpoints_pos = m_source_breakpoints[path]; + response_breakpoints = + SetSourceBreakpoints(source, breakpoints, existing_breakpoints_pos); + } + + return response_breakpoints; +} + +std::vector DAP::SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints, + SourceBreakpointMap &existing_breakpoints) { + std::vector response_breakpoints; + + SourceBreakpointMap request_breakpoints; + if (breakpoints) { + for (const auto &bp : *breakpoints) { + SourceBreakpoint src_bp(*this, bp, source); + std::pair bp_pos(src_bp.GetLine(), + src_bp.GetColumn()); + request_breakpoints.try_emplace(bp_pos, src_bp); + + const auto [iv, inserted] = + existing_breakpoints.try_emplace(bp_pos, src_bp); + // We check if this breakpoint already exists to update it. + if (inserted) + iv->second.SetBreakpoint(); + else + iv->second.UpdateBreakpoint(src_bp); + + protocol::Breakpoint response_breakpoint = + iv->second.ToProtocolBreakpoint(); + response_breakpoint.source = source; + + if (!response_breakpoint.line && + src_bp.GetLine() != LLDB_INVALID_LINE_NUMBER) + response_breakpoint.line = src_bp.GetLine(); + if (!response_breakpoint.column && + src_bp.GetColumn() != LLDB_INVALID_COLUMN_NUMBER) + response_breakpoint.column = src_bp.GetColumn(); + response_breakpoints.push_back(response_breakpoint); + } + } + + // Delete any breakpoints in this source file that aren't in the + // request_bps set. There is no call to remove breakpoints other than + // calling this function with a smaller or empty "breakpoints" list. + for (auto it = existing_breakpoints.begin(); + it != existing_breakpoints.end();) { + auto request_pos = request_breakpoints.find(it->first); + if (request_pos == request_breakpoints.end()) { + // This breakpoint no longer exists in this source file, delete it + target.BreakpointDelete(it->second.GetID()); + it = existing_breakpoints.erase(it); + } else { + ++it; + } + } + + return response_breakpoints; +} + void DAP::RegisterRequests() { RegisterRequest(); RegisterRequest(); diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 20f95be792f41..3a0a7fc1678ba 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -60,7 +60,7 @@ namespace lldb_dap { -typedef llvm::DenseMap, SourceBreakpoint> +typedef std::map, SourceBreakpoint> SourceBreakpointMap; typedef llvm::StringMap FunctionBreakpointMap; typedef llvm::DenseMap @@ -168,9 +168,6 @@ struct DAP { lldb::SBTarget target; Variables variables; lldb::SBBroadcaster broadcaster; - llvm::StringMap source_breakpoints; - llvm::DenseMap> - assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; @@ -428,7 +425,28 @@ struct DAP { void StartEventThread(); void StartProgressEventThread(); + /// Sets the given protocol `breakpoints` in the given `source`, while + /// removing any existing breakpoints in the given source if they are not in + /// `breakpoint`. + /// + /// \param[in] source + /// The relevant source of the breakpoints. + /// + /// \param[in] breakpoints + /// The breakpoints to set. + /// + /// \return a vector of the breakpoints that were set. + std::vector SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> + &breakpoints); + private: + std::vector SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints, + SourceBreakpointMap &existing_breakpoints); + /// Registration of request handler. /// @{ void RegisterRequests(); @@ -457,6 +475,9 @@ struct DAP { std::mutex m_active_request_mutex; const protocol::Request *m_active_request; + + llvm::StringMap m_source_breakpoints; + llvm::DenseMap m_source_assembly_breakpoints; }; } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index e708abb50d5c0..54f728414021e 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -388,15 +388,6 @@ class SetBreakpointsRequestHandler } llvm::Expected Run(const protocol::SetBreakpointsArguments &args) const override; - - std::vector SetSourceBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const; - std::vector SetAssemblyBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const; }; class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index bf0b584753c07..0ff88f62f8f51 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -22,130 +22,9 @@ namespace lldb_dap { llvm::Expected SetBreakpointsRequestHandler::Run( const protocol::SetBreakpointsArguments &args) const { - const auto &source = args.source; - std::vector response_breakpoints; - if (source.sourceReference) - response_breakpoints = SetAssemblyBreakpoints(source, args.breakpoints); - else if (source.path) - response_breakpoints = SetSourceBreakpoints(source, args.breakpoints); - + const auto response_breakpoints = + dap.SetSourceBreakpoints(args.source, args.breakpoints); return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; } -std::vector -SetBreakpointsRequestHandler::SetSourceBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const { - std::vector response_breakpoints; - std::string path = source.path.value_or(""); - - // Decode the source breakpoint infos for this "setBreakpoints" request - SourceBreakpointMap request_bps; - // "breakpoints" may be unset, in which case we treat it the same as being set - // to an empty array. - if (breakpoints) { - for (const auto &bp : *breakpoints) { - SourceBreakpoint src_bp(dap, bp); - std::pair bp_pos(src_bp.GetLine(), - src_bp.GetColumn()); - request_bps.try_emplace(bp_pos, src_bp); - const auto [iv, inserted] = - dap.source_breakpoints[path].try_emplace(bp_pos, src_bp); - // We check if this breakpoint already exists to update it - if (inserted) - iv->getSecond().SetBreakpoint(path.data()); - else - iv->getSecond().UpdateBreakpoint(src_bp); - - protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - - // Use the path from the request if it is set - if (!path.empty()) - response_bp.source = CreateSource(path); - - if (!response_bp.line) - response_bp.line = src_bp.GetLine(); - if (!response_bp.column) - response_bp.column = src_bp.GetColumn(); - response_breakpoints.push_back(response_bp); - } - } - - // Delete any breakpoints in this source file that aren't in the - // request_bps set. There is no call to remove breakpoints other than - // calling this function with a smaller or empty "breakpoints" list. - auto old_src_bp_pos = dap.source_breakpoints.find(path); - if (old_src_bp_pos != dap.source_breakpoints.end()) { - for (auto &old_bp : old_src_bp_pos->second) { - auto request_pos = request_bps.find(old_bp.first); - if (request_pos == request_bps.end()) { - // This breakpoint no longer exists in this source file, delete it - dap.target.BreakpointDelete(old_bp.second.GetID()); - old_src_bp_pos->second.erase(old_bp.first); - } - } - } - - return response_breakpoints; -} - -std::vector -SetBreakpointsRequestHandler::SetAssemblyBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const { - std::vector response_breakpoints; - int64_t sourceReference = source.sourceReference.value_or(0); - - lldb::SBAddress address(sourceReference, dap.target); - if (!address.IsValid()) - return response_breakpoints; - - lldb::SBSymbol symbol = address.GetSymbol(); - if (!symbol.IsValid()) { - // Not yet supporting breakpoints in assembly without a valid symbol. - return response_breakpoints; - } - - llvm::DenseMap request_bps; - if (breakpoints) { - for (const auto &bp : *breakpoints) { - SourceBreakpoint src_bp(dap, bp); - request_bps.try_emplace(src_bp.GetLine(), src_bp); - const auto [iv, inserted] = - dap.assembly_breakpoints[sourceReference].try_emplace( - src_bp.GetLine(), src_bp); - // We check if this breakpoint already exists to update it. - if (inserted) - iv->getSecond().SetBreakpoint(symbol); - else - iv->getSecond().UpdateBreakpoint(src_bp); - - protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - response_bp.source = source; - if (!response_bp.line) - response_bp.line = src_bp.GetLine(); - if (bp.column) - response_bp.column = *bp.column; - response_breakpoints.push_back(response_bp); - } - } - - // Delete existing breakpoints for this sourceReference that are not in the - // request_bps set. - auto old_src_bp_pos = dap.assembly_breakpoints.find(sourceReference); - if (old_src_bp_pos != dap.assembly_breakpoints.end()) { - for (auto &old_bp : old_src_bp_pos->second) { - auto request_pos = request_bps.find(old_bp.first); - if (request_pos == request_bps.end()) { - dap.target.BreakpointDelete(old_bp.second.GetID()); - old_src_bp_pos->second.erase(old_bp.first); - } - } - } - - return response_breakpoints; -} - } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 938b8fb8bcdda..50ebfbe8aef20 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -29,39 +29,49 @@ namespace lldb_dap { SourceBreakpoint::SourceBreakpoint(DAP &dap, - const protocol::SourceBreakpoint &breakpoint) + const protocol::SourceBreakpoint &breakpoint, + const protocol::Source &source) : Breakpoint(dap, breakpoint.condition, breakpoint.hitCondition), - m_log_message(breakpoint.logMessage.value_or("")), + m_log_message(breakpoint.logMessage.value_or("")), m_source(source), m_line(breakpoint.line), m_column(breakpoint.column.value_or(LLDB_INVALID_COLUMN_NUMBER)) {} -void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) { - lldb::SBMutex lock = m_dap.GetAPIMutex(); - std::lock_guard guard(lock); - - lldb::SBFileSpecList module_list; - m_bp = m_dap.target.BreakpointCreateByLocation( - source_path.str().c_str(), m_line, m_column, 0, module_list); - if (!m_log_message.empty()) - SetLogMessage(); - Breakpoint::SetBreakpoint(); -} - -void SourceBreakpoint::SetBreakpoint(lldb::SBSymbol &symbol) { +void SourceBreakpoint::SetBreakpoint() { lldb::SBMutex lock = m_dap.GetAPIMutex(); std::lock_guard guard(lock); if (m_line == 0) return; - lldb::SBInstructionList inst_list = - m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); - if (inst_list.GetSize() < m_line) - return; - lldb::SBAddress address = - inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + if (m_source.sourceReference) { + // breakpoint set by assembly source. + lldb::SBAddress source_address(*m_source.sourceReference, m_dap.target); + if (!source_address.IsValid()) + return; + + lldb::SBSymbol symbol = source_address.GetSymbol(); + if (!symbol.IsValid()) { + // Not yet supporting breakpoints in assembly without a valid symbol. + return; + } + + lldb::SBInstructionList inst_list = + m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); + if (inst_list.GetSize() < m_line) + return; + + lldb::SBAddress address = + inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + + m_bp = m_dap.target.BreakpointCreateBySBAddress(address); + } else { + // breakpoint set by a regular source file. + const auto source_path = m_source.path.value_or(""); + lldb::SBFileSpecList module_list; + m_bp = m_dap.target.BreakpointCreateByLocation(source_path.c_str(), m_line, + m_column, 0, module_list); + } - m_bp = m_dap.target.BreakpointCreateBySBAddress(address); if (!m_log_message.empty()) SetLogMessage(); Breakpoint::SetBreakpoint(); diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h index 8589800e50983..3221ecbf28ece 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.h +++ b/lldb/tools/lldb-dap/SourceBreakpoint.h @@ -22,11 +22,11 @@ namespace lldb_dap { class SourceBreakpoint : public Breakpoint { public: - SourceBreakpoint(DAP &d, const protocol::SourceBreakpoint &breakpoint); + SourceBreakpoint(DAP &d, const protocol::SourceBreakpoint &breakpoint, + const protocol::Source &source); // Set this breakpoint in LLDB as a new breakpoint - void SetBreakpoint(const llvm::StringRef source_path); - void SetBreakpoint(lldb::SBSymbol &symbol); + void SetBreakpoint(); void UpdateBreakpoint(const SourceBreakpoint &request_bp); void SetLogMessage(); @@ -63,6 +63,7 @@ class SourceBreakpoint : public Breakpoint { std::string m_log_message; std::vector m_log_message_parts; + protocol::Source m_source; /// The original breakpoint source. uint32_t m_line; ///< The source line of the breakpoint or logpoint uint32_t m_column; ///< An optional source column of the breakpoint }; >From 2e9edca37c0953e2d2a6cf2d278bb353f1e0960b Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 13:39:05 +0200 Subject: [PATCH 10/14] improve assembvly breakpoint test to check clear --- .../TestDAP_breakpointAssembly.py | 17 +++++++++++++++-- .../tools/lldb-dap/breakpoint-assembly/main.c | 4 +++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py index ba9df3a18590b..dacc1cd8349f1 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py @@ -6,7 +6,7 @@ import dap_server import shutil from lldbsuite.test.decorators import * -from lldbsuite.test.lldbtest import * +from lldbsuite.test.lldbtest import line_number from lldbsuite.test import lldbutil import lldbdap_testcase import os @@ -23,6 +23,9 @@ def test_functionality(self): "`settings set stop-disassembly-display no-debuginfo", context="repl" ) + finish_line = line_number("main.c", "// Break here") + finish_breakpoints = self.set_source_breakpoints("main.c", [finish_line]) + assmebly_func_breakpoints = self.set_function_breakpoints(["assembly_func"]) self.continue_to_breakpoints(assmebly_func_breakpoints) @@ -36,7 +39,17 @@ def test_functionality(self): line = assembly_func_frame["line"] # Set an assembly breakpoint in the next line and check that it's hit + source_reference = assembly_func_frame["source"]["sourceReference"] assembly_breakpoint_ids = self.set_source_breakpoints_assembly( - assembly_func_frame["source"]["sourceReference"], [line + 1] + source_reference, [line + 1] ) self.continue_to_breakpoints(assembly_breakpoint_ids) + + # Continue again and verify it hits in the next function call + self.continue_to_breakpoints(assmebly_func_breakpoints) + self.continue_to_breakpoints(assembly_breakpoint_ids) + + # Clear the breakpoint and then check that the assembly breakpoint does not hit next time + self.set_source_breakpoints_assembly(source_reference, []) + self.continue_to_breakpoints(assmebly_func_breakpoints) + self.continue_to_breakpoints(finish_breakpoints) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c index 350739006f903..e3a21df11958f 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c @@ -10,5 +10,7 @@ __attribute__((nodebug)) int assembly_func(int n) { int main(int argc, char const *argv[]) { assembly_func(10); - return 0; + assembly_func(20); + assembly_func(30); + return 0; // Break here } >From 0515c6dc6e46b6296621e871b43286ae88ea9b6b Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 13:52:40 +0200 Subject: [PATCH 11/14] fix GetSBFileSpecPath extra char --- lldb/tools/lldb-dap/LLDBUtils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp index 3c7623ec1215d..fe0bcda19b4cd 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.cpp +++ b/lldb/tools/lldb-dap/LLDBUtils.cpp @@ -247,8 +247,8 @@ std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec) { const auto directory_length = ::strlen(file_spec.GetDirectory()); const auto file_name_length = ::strlen(file_spec.GetFilename()); - std::string path(directory_length + file_name_length + 2, '\0'); - file_spec.GetPath(path.data(), path.length()); + std::string path(directory_length + file_name_length + 1, '\0'); + file_spec.GetPath(path.data(), path.length() + 1); return path; } >From 9dbca55d01c7faddc9df4586ba25c6fac421d909 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 13:59:53 +0200 Subject: [PATCH 12/14] restore SBFileSpec changes --- lldb/include/lldb/API/SBFileSpec.h | 1 - lldb/source/API/SBFileSpec.cpp | 1 - lldb/tools/lldb-dap/DAP.cpp | 8 ++++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index 1bb28b2ddab01..36641843aabeb 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -10,7 +10,6 @@ #define LLDB_API_SBFILESPEC_H #include "lldb/API/SBDefines.h" -#include "lldb/API/SBStream.h" namespace lldb { diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp index f18857f59171a..a7df9afc4b8eb 100644 --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -19,7 +19,6 @@ #include #include -#include using namespace lldb; using namespace lldb_private; diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 1fe46fc619d73..d7ef886dd2419 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1626,16 +1626,16 @@ std::vector DAP::SetSourceBreakpoints( std::vector response_breakpoints; if (source.sourceReference) { // breakpoint set by assembly source. - auto &existing_breakpoints_pos = + auto &existing_breakpoints = m_source_assembly_breakpoints[*source.sourceReference]; response_breakpoints = - SetSourceBreakpoints(source, breakpoints, existing_breakpoints_pos); + SetSourceBreakpoints(source, breakpoints, existing_breakpoints); } else { // breakpoint set by a regular source file. const auto path = source.path.value_or(""); - auto &existing_breakpoints_pos = m_source_breakpoints[path]; + auto &existing_breakpoints = m_source_breakpoints[path]; response_breakpoints = - SetSourceBreakpoints(source, breakpoints, existing_breakpoints_pos); + SetSourceBreakpoints(source, breakpoints, existing_breakpoints); } return response_breakpoints; >From 396970d6a46063450741b6b0c9c528078e433e24 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 14:01:28 +0200 Subject: [PATCH 13/14] single line if with comments curly braces --- lldb/tools/lldb-dap/JSONUtils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 1d2a6ff60e502..dcc25c9212432 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -661,10 +661,11 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, frame_name = name; } - if (frame_name.empty()) + if (frame_name.empty()) { // If the function name is unavailable, display the pc address as a 16-digit // hex string, e.g. "0x0000000000012345" frame_name = GetLoadAddressString(frame.GetPC()); + } // We only include `[opt]` if a custom frame format is not specified. if (!format && frame.GetFunction().GetIsOptimized()) >From 7a0e0eeb1232028e535d2057198c8e8a7f0487d6 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 14:06:40 +0200 Subject: [PATCH 14/14] unecessary include --- lldb/tools/lldb-dap/Handler/RequestHandler.h | 1 - 1 file changed, 1 deletion(-) diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 54f728414021e..4670e23ca33d4 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -16,7 +16,6 @@ #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" #include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/JSON.h" From lldb-commits at lists.llvm.org Sun May 18 05:24:52 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 05:24:52 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Move the Variables struct into its own file (PR #140393) In-Reply-To: Message-ID: <6829d194.170a0220.af901.a05f@mx.google.com> https://github.com/eronnen approved this pull request. https://github.com/llvm/llvm-project/pull/140393 From lldb-commits at lists.llvm.org Sun May 18 05:30:05 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 05:30:05 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <6829d2cd.170a0220.2564f6.a3fe@mx.google.com> https://github.com/eronnen updated https://github.com/llvm/llvm-project/pull/139969 >From d6325b3f6a8602fc96ad72acecfcccda1120614d Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sat, 10 May 2025 20:45:17 +0200 Subject: [PATCH 01/15] support assembly in BreakpointLocationsRequestHandler --- .../breakpoint/TestDAP_setBreakpoints.py | 1 - .../TestDAP_setExceptionBreakpoints.py | 1 - .../TestDAP_setFunctionBreakpoints.py | 1 - lldb/tools/lldb-dap/DAP.h | 3 + .../Handler/BreakpointLocationsHandler.cpp | 77 +++++++++++++++---- lldb/tools/lldb-dap/Handler/RequestHandler.h | 11 +++ .../lldb-dap/Handler/SourceRequestHandler.cpp | 4 +- 7 files changed, 76 insertions(+), 22 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index aae1251b17c93..26df2573555df 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,7 +12,6 @@ import os - at skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py index 4dc8c5b3c7ded..92ac66cd44c5d 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setExceptionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_functionality(self): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index baaca4d974d5d..946595f639edc 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 8f24c6cf82924..00aa4276852c5 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -219,6 +219,9 @@ struct DAP { llvm::StringSet<> modules; /// @} + /// Number of lines of assembly code to show when no debug info is available. + uint32_t number_of_assembly_lines_for_nodebug = 32; + /// Creates a new DAP sessions. /// /// \param[in] log diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 2ac886c3a5d2c..9eea549d72b00 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "JSONUtils.h" +#include "LLDBUtils.h" #include "RequestHandler.h" #include @@ -19,19 +19,50 @@ namespace lldb_dap { llvm::Expected BreakpointLocationsRequestHandler::Run( const protocol::BreakpointLocationsArguments &args) const { - std::string path = args.source.path.value_or(""); uint32_t start_line = args.line; uint32_t start_column = args.column.value_or(LLDB_INVALID_COLUMN_NUMBER); uint32_t end_line = args.endLine.value_or(start_line); uint32_t end_column = args.endColumn.value_or(std::numeric_limits::max()); + // Find all relevant lines & columns + llvm::SmallVector, 8> locations; + if (args.source.sourceReference) { + AddAssemblyBreakpointLocations(locations, *args.source.sourceReference, + start_line, end_line); + } else { + std::string path = args.source.path.value_or(""); + AddSourceBreakpointLocations(locations, std::move(path), start_line, + start_column, end_line, end_column); + } + + // The line entries are sorted by addresses, but we must return the list + // ordered by line / column position. + std::sort(locations.begin(), locations.end()); + locations.erase(llvm::unique(locations), locations.end()); + + std::vector breakpoint_locations; + for (auto &l : locations) { + protocol::BreakpointLocation lc; + lc.line = l.first; + lc.column = l.second; + breakpoint_locations.push_back(std::move(lc)); + } + + return protocol::BreakpointLocationsResponseBody{ + /*breakpoints=*/std::move(breakpoint_locations)}; +} + +template +void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const { + lldb::SBFileSpec file_spec(path.c_str(), true); lldb::SBSymbolContextList compile_units = dap.target.FindCompileUnits(file_spec); - // Find all relevant lines & columns - llvm::SmallVector, 8> locations; for (uint32_t c_idx = 0, c_limit = compile_units.GetSize(); c_idx < c_limit; ++c_idx) { const lldb::SBCompileUnit &compile_unit = @@ -71,22 +102,34 @@ BreakpointLocationsRequestHandler::Run( locations.emplace_back(line, column); } } +} - // The line entries are sorted by addresses, but we must return the list - // ordered by line / column position. - std::sort(locations.begin(), locations.end()); - locations.erase(llvm::unique(locations), locations.end()); +template +void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { + lldb::SBProcess process = dap.target.GetProcess(); + lldb::SBThread thread = + process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); + lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - std::vector breakpoint_locations; - for (auto &l : locations) { - protocol::BreakpointLocation lc; - lc.line = l.first; - lc.column = l.second; - breakpoint_locations.push_back(std::move(lc)); - } + if (!frame.IsValid()) + return; - return protocol::BreakpointLocationsResponseBody{ - /*breakpoints=*/std::move(breakpoint_locations)}; + lldb::SBSymbol symbol = frame.GetSymbol(); + if (symbol.IsValid()) { + lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); + } + } else { + for (uint32_t i = start_line - 1; + i < dap.number_of_assembly_lines_for_nodebug && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); + } + } } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index e6bccfe12f402..21753bc0552f9 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -16,6 +16,7 @@ #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/JSON.h" @@ -232,6 +233,16 @@ class BreakpointLocationsRequestHandler } llvm::Expected Run(const protocol::BreakpointLocationsArguments &args) const override; + + template + void AddSourceBreakpointLocations( + llvm::SmallVector, N> &locations, + std::string path, uint32_t start_line, uint32_t start_column, + uint32_t end_line, uint32_t end_column) const; + template + void AddAssemblyBreakpointLocations( + llvm::SmallVector, N> &locations, + int64_t sourceReference, uint32_t start_line, uint32_t end_line) const; }; class CompletionsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp index 0ddd87881a164..fb396a3dc8862 100644 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp @@ -52,8 +52,8 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { insts.GetDescription(stream, exe_ctx); } else { // No valid symbol, just return the disassembly. - lldb::SBInstructionList insts = - dap.target.ReadInstructions(frame.GetPCAddress(), 32); + lldb::SBInstructionList insts = dap.target.ReadInstructions( + frame.GetPCAddress(), dap.number_of_assembly_lines_for_nodebug); insts.GetDescription(stream, exe_ctx); } >From ee492031bee8106fb2a4ff22a8563005f5afd86c Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 11 May 2025 19:49:03 +0200 Subject: [PATCH 02/15] support assembly in SetBreakpointsRequestHandler --- lldb/tools/lldb-dap/DAP.h | 1 + .../Handler/BreakpointLocationsHandler.cpp | 20 ++--- lldb/tools/lldb-dap/Handler/RequestHandler.h | 9 ++ .../Handler/SetBreakpointsRequestHandler.cpp | 90 ++++++++++++++++++- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 22 +++++ lldb/tools/lldb-dap/SourceBreakpoint.h | 1 + 6 files changed, 127 insertions(+), 16 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 00aa4276852c5..5ce0e534611c1 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -169,6 +169,7 @@ struct DAP { Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; + llvm::DenseMap assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 9eea549d72b00..be02c47056310 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -117,18 +117,14 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( return; lldb::SBSymbol symbol = frame.GetSymbol(); - if (symbol.IsValid()) { - lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); - ++i) { - locations.emplace_back(i, 0); - } - } else { - for (uint32_t i = start_line - 1; - i < dap.number_of_assembly_lines_for_nodebug && i < (end_line - 1); - ++i) { - locations.emplace_back(i, 0); - } + if (!symbol.IsValid()) + return; + + // start_line is relative to the symbol's start address + lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + ++i) { + locations.emplace_back(i, 0); } } diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 21753bc0552f9..72843aaef8150 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -389,6 +389,15 @@ class SetBreakpointsRequestHandler } llvm::Expected Run(const protocol::SetBreakpointsArguments &args) const override; + + std::vector SetSourceBreakpoints( + const std::string &path, + const std::optional> &breakpoints) + const; + std::vector SetAssemblyBreakpoints( + int64_t sourceReference, + const std::optional> &breakpoints) + const; }; class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 86e090b66afe9..71f9e5578ef08 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -9,8 +9,11 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" +#include +#include #include namespace lldb_dap { @@ -23,15 +26,30 @@ llvm::Expected SetBreakpointsRequestHandler::Run( const protocol::SetBreakpointsArguments &args) const { const auto &source = args.source; - const auto path = source.path.value_or(""); + std::vector response_breakpoints; + if (source.sourceReference) + response_breakpoints = SetAssemblyBreakpoints( + source.sourceReference.value(), args.breakpoints); + else if (source.path) + response_breakpoints = + SetSourceBreakpoints(source.path.value(), args.breakpoints); + + return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; +} + +std::vector +SetBreakpointsRequestHandler::SetSourceBreakpoints( + const std::string &path, + const std::optional> &breakpoints) + const { std::vector response_breakpoints; // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; // "breakpoints" may be unset, in which case we treat it the same as being set // to an empty array. - if (args.breakpoints) { - for (const auto &bp : *args.breakpoints) { + if (breakpoints) { + for (const auto &bp : *breakpoints) { SourceBreakpoint src_bp(dap, bp); std::pair bp_pos(src_bp.GetLine(), src_bp.GetColumn()); @@ -73,7 +91,71 @@ SetBreakpointsRequestHandler::Run( } } - return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; + return response_breakpoints; +} + +std::vector +SetBreakpointsRequestHandler::SetAssemblyBreakpoints( + int64_t sourceReference, + const std::optional> &breakpoints) + const { + std::vector response_breakpoints; + + lldb::SBProcess process = dap.target.GetProcess(); + lldb::SBThread thread = + process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); + lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); + + if (!frame.IsValid()) + return response_breakpoints; + + lldb::SBSymbol symbol = frame.GetSymbol(); + if (!symbol.IsValid()) + return response_breakpoints; // Not yet supporting breakpoints in assembly + // without a valid symbol + + SourceBreakpointMap request_bps; + if (breakpoints) { + for (const auto &bp : *breakpoints) { + SourceBreakpoint src_bp(dap, bp); + std::pair bp_pos(src_bp.GetLine(), 0); + request_bps.try_emplace(bp_pos, src_bp); + const auto [iv, inserted] = + dap.assembly_breakpoints[sourceReference].try_emplace(bp_pos, src_bp); + // We check if this breakpoint already exists to update it + if (inserted) + iv->getSecond().SetBreakpoint(symbol); + else + iv->getSecond().UpdateBreakpoint(src_bp); + + protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); + protocol::Source source; + source.sourceReference = sourceReference; + source.name = symbol.GetName(); + response_bp.source = std::move(source); + + if (!response_bp.line) + response_bp.line = src_bp.GetLine(); + if (!response_bp.column) + response_bp.column = src_bp.GetColumn(); + response_breakpoints.push_back(response_bp); + } + } + + // Delete existing breakpoints for this sourceReference that are not in the + // request_bps set. + auto old_src_bp_pos = dap.assembly_breakpoints.find(sourceReference); + if (old_src_bp_pos != dap.assembly_breakpoints.end()) { + for (auto &old_bp : old_src_bp_pos->second) { + auto request_pos = request_bps.find(old_bp.first); + if (request_pos == request_bps.end()) { + dap.target.BreakpointDelete(old_bp.second.GetID()); + old_src_bp_pos->second.erase(old_bp.first); + } + } + } + + return response_breakpoints; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 4581c995b4260..938b8fb8bcdda 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -13,7 +13,9 @@ #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBFileSpecList.h" #include "lldb/API/SBFrame.h" +#include "lldb/API/SBInstruction.h" #include "lldb/API/SBMutex.h" +#include "lldb/API/SBSymbol.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" #include "lldb/API/SBValue.h" @@ -45,6 +47,26 @@ void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) { Breakpoint::SetBreakpoint(); } +void SourceBreakpoint::SetBreakpoint(lldb::SBSymbol &symbol) { + lldb::SBMutex lock = m_dap.GetAPIMutex(); + std::lock_guard guard(lock); + + if (m_line == 0) + return; + + lldb::SBInstructionList inst_list = + m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); + if (inst_list.GetSize() < m_line) + return; + lldb::SBAddress address = + inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + + m_bp = m_dap.target.BreakpointCreateBySBAddress(address); + if (!m_log_message.empty()) + SetLogMessage(); + Breakpoint::SetBreakpoint(); +} + void SourceBreakpoint::UpdateBreakpoint(const SourceBreakpoint &request_bp) { if (m_log_message != request_bp.m_log_message) { m_log_message = request_bp.m_log_message; diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h index 5b15296f861c5..8589800e50983 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.h +++ b/lldb/tools/lldb-dap/SourceBreakpoint.h @@ -26,6 +26,7 @@ class SourceBreakpoint : public Breakpoint { // Set this breakpoint in LLDB as a new breakpoint void SetBreakpoint(const llvm::StringRef source_path); + void SetBreakpoint(lldb::SBSymbol &symbol); void UpdateBreakpoint(const SourceBreakpoint &request_bp); void SetLogMessage(); >From dbb2f9bd55b3f86247e03b2610fca9576e124637 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Wed, 14 May 2025 23:51:41 +0200 Subject: [PATCH 03/15] fix resolving of assembly source breakpoints --- lldb/tools/lldb-dap/Breakpoint.cpp | 45 ++++++++++++++++--- lldb/tools/lldb-dap/DAP.h | 3 +- .../Handler/BreakpointLocationsHandler.cpp | 4 +- lldb/tools/lldb-dap/Handler/RequestHandler.h | 4 +- .../Handler/SetBreakpointsRequestHandler.cpp | 30 ++++++------- lldb/tools/lldb-dap/package-lock.json | 4 +- lldb/tools/lldb-dap/package.json | 5 ++- 7 files changed, 63 insertions(+), 32 deletions(-) diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 26d633d1d172e..87fcd15b0a568 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -9,10 +9,12 @@ #include "Breakpoint.h" #include "DAP.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "lldb/API/SBAddress.h" #include "lldb/API/SBBreakpointLocation.h" #include "lldb/API/SBLineEntry.h" #include "lldb/API/SBMutex.h" +#include "lldb/lldb-enumerations.h" #include "llvm/ADT/StringExtras.h" #include #include @@ -63,14 +65,43 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { std::string formatted_addr = "0x" + llvm::utohexstr(bp_addr.GetLoadAddress(m_bp.GetTarget())); breakpoint.instructionReference = formatted_addr; + + lldb::StopDisassemblyType stop_disassembly_display = + GetStopDisassemblyDisplay(m_dap.debugger); auto line_entry = bp_addr.GetLineEntry(); - const auto line = line_entry.GetLine(); - if (line != UINT32_MAX) - breakpoint.line = line; - const auto column = line_entry.GetColumn(); - if (column != 0) - breakpoint.column = column; - breakpoint.source = CreateSource(line_entry); + if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) { + const auto line = line_entry.GetLine(); + if (line != UINT32_MAX) + breakpoint.line = line; + const auto column = line_entry.GetColumn(); + if (column != 0) + breakpoint.column = column; + breakpoint.source = CreateSource(line_entry); + } else { + // Breakpoint made by assembly + auto symbol_context = bp_addr.GetSymbolContext( + lldb::eSymbolContextSymbol | lldb::eSymbolContextModule); + if (symbol_context.IsValid()) { + auto symbol = symbol_context.GetSymbol(); + breakpoint.line = + m_bp.GetTarget() + .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) + .GetSize() + + 1; + protocol::Source source; + source.name = symbol.GetName(); + + auto module = symbol_context.GetModule(); + if (module.IsValid()) { + std::string path = module.GetFileSpec().GetDirectory(); + path += "/"; + path += module.GetFileSpec().GetFilename(); + source.path = std::move(path); + } + + breakpoint.source = std::move(source); + } + } } return breakpoint; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 5ce0e534611c1..b0fe265b7bca1 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -169,7 +169,8 @@ struct DAP { Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; - llvm::DenseMap assembly_breakpoints; + llvm::DenseMap> + assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index be02c47056310..06ada47a6f27f 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -122,9 +122,9 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( // start_line is relative to the symbol's start address lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - for (uint32_t i = start_line - 1; i < insts.GetSize() && i < (end_line - 1); + for (uint32_t i = start_line - 1; i < insts.GetSize() && i <= (end_line - 1); ++i) { - locations.emplace_back(i, 0); + locations.emplace_back(i, 1); } } diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 72843aaef8150..80898d1ee5ef1 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -391,11 +391,11 @@ class SetBreakpointsRequestHandler Run(const protocol::SetBreakpointsArguments &args) const override; std::vector SetSourceBreakpoints( - const std::string &path, + const protocol::Source &source, const std::optional> &breakpoints) const; std::vector SetAssemblyBreakpoints( - int64_t sourceReference, + const protocol::Source &source, const std::optional> &breakpoints) const; }; diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 71f9e5578ef08..4fefd8b440c7d 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -28,21 +28,20 @@ SetBreakpointsRequestHandler::Run( const auto &source = args.source; std::vector response_breakpoints; if (source.sourceReference) - response_breakpoints = SetAssemblyBreakpoints( - source.sourceReference.value(), args.breakpoints); + response_breakpoints = SetAssemblyBreakpoints(source, args.breakpoints); else if (source.path) - response_breakpoints = - SetSourceBreakpoints(source.path.value(), args.breakpoints); + response_breakpoints = SetSourceBreakpoints(source, args.breakpoints); return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; } std::vector SetBreakpointsRequestHandler::SetSourceBreakpoints( - const std::string &path, + const protocol::Source &source, const std::optional> &breakpoints) const { std::vector response_breakpoints; + std::string path = source.path.value_or(""); // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; @@ -96,10 +95,11 @@ SetBreakpointsRequestHandler::SetSourceBreakpoints( std::vector SetBreakpointsRequestHandler::SetAssemblyBreakpoints( - int64_t sourceReference, + const protocol::Source &source, const std::optional> &breakpoints) const { std::vector response_breakpoints; + int64_t sourceReference = source.sourceReference.value_or(0); lldb::SBProcess process = dap.target.GetProcess(); lldb::SBThread thread = @@ -114,14 +114,14 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( return response_breakpoints; // Not yet supporting breakpoints in assembly // without a valid symbol - SourceBreakpointMap request_bps; + llvm::DenseMap request_bps; if (breakpoints) { for (const auto &bp : *breakpoints) { SourceBreakpoint src_bp(dap, bp); - std::pair bp_pos(src_bp.GetLine(), 0); - request_bps.try_emplace(bp_pos, src_bp); + request_bps.try_emplace(src_bp.GetLine(), src_bp); const auto [iv, inserted] = - dap.assembly_breakpoints[sourceReference].try_emplace(bp_pos, src_bp); + dap.assembly_breakpoints[sourceReference].try_emplace( + src_bp.GetLine(), src_bp); // We check if this breakpoint already exists to update it if (inserted) iv->getSecond().SetBreakpoint(symbol); @@ -129,15 +129,11 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( iv->getSecond().UpdateBreakpoint(src_bp); protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - protocol::Source source; - source.sourceReference = sourceReference; - source.name = symbol.GetName(); - response_bp.source = std::move(source); - + response_bp.source = source; if (!response_bp.line) response_bp.line = src_bp.GetLine(); - if (!response_bp.column) - response_bp.column = src_bp.GetColumn(); + if (bp.column) + response_bp.column = *bp.column; response_breakpoints.push_back(response_bp); } } diff --git a/lldb/tools/lldb-dap/package-lock.json b/lldb/tools/lldb-dap/package-lock.json index 0a2b9e764067e..af90a9573aee6 100644 --- a/lldb/tools/lldb-dap/package-lock.json +++ b/lldb/tools/lldb-dap/package-lock.json @@ -1,12 +1,12 @@ { "name": "lldb-dap", - "version": "0.2.13", + "version": "0.2.14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lldb-dap", - "version": "0.2.13", + "version": "0.2.14", "license": "Apache 2.0 License with LLVM exceptions", "devDependencies": { "@types/node": "^18.19.41", diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index d5ca604798799..73e70cd961f4f 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -1,7 +1,7 @@ { "name": "lldb-dap", "displayName": "LLDB DAP", - "version": "0.2.13", + "version": "0.2.14", "publisher": "llvm-vs-code-extensions", "homepage": "https://lldb.llvm.org", "description": "Debugging with LLDB in Visual Studio Code", @@ -265,6 +265,9 @@ ] }, "breakpoints": [ + { + "language": "lldb.disassembly" + }, { "language": "ada" }, >From 3699524618ed76f969cc26a63610fe54e3605139 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Thu, 15 May 2025 00:36:10 +0200 Subject: [PATCH 04/15] remove include --- lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 4fefd8b440c7d..d69da5bd02c1e 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -12,8 +12,6 @@ #include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" -#include -#include #include namespace lldb_dap { >From 61623deb7e249a8ca0c63e3f66955790da5e4ced Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sat, 17 May 2025 21:05:27 +0200 Subject: [PATCH 05/15] use load address as sourceReference --- lldb/include/lldb/API/SBFileSpec.h | 3 + lldb/source/API/SBFileSpec.cpp | 8 ++ lldb/tools/lldb-dap/Breakpoint.cpp | 18 +---- .../Handler/BreakpointLocationsHandler.cpp | 11 +-- .../Handler/SetBreakpointsRequestHandler.cpp | 11 +-- .../lldb-dap/Handler/SourceRequestHandler.cpp | 18 ++--- lldb/tools/lldb-dap/JSONUtils.cpp | 75 +++++++++++++------ lldb/tools/lldb-dap/JSONUtils.h | 14 ++++ 8 files changed, 96 insertions(+), 62 deletions(-) diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index 36641843aabeb..303cb7d712cbf 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -10,6 +10,7 @@ #define LLDB_API_SBFILESPEC_H #include "lldb/API/SBDefines.h" +#include "lldb/API/SBStream.h" namespace lldb { @@ -53,6 +54,8 @@ class LLDB_API SBFileSpec { uint32_t GetPath(char *dst_path, size_t dst_len) const; + bool GetPath(lldb::SBStream &dst_path) const; + static int ResolvePath(const char *src_path, char *dst_path, size_t dst_len); bool GetDescription(lldb::SBStream &description) const; diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp index a7df9afc4b8eb..cb44dac1d4fcc 100644 --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -19,6 +19,7 @@ #include #include +#include using namespace lldb; using namespace lldb_private; @@ -147,6 +148,13 @@ uint32_t SBFileSpec::GetPath(char *dst_path, size_t dst_len) const { return result; } +bool SBFileSpec::GetPath(SBStream &dst_path) const { + LLDB_INSTRUMENT_VA(this, dst_path); + + std::string path = m_opaque_up->GetPath(); + return dst_path->PutCString(path.c_str()) > 0; +} + const lldb_private::FileSpec *SBFileSpec::operator->() const { return m_opaque_up.get(); } diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 87fcd15b0a568..a54a34e0f936d 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -79,27 +79,15 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { breakpoint.source = CreateSource(line_entry); } else { // Breakpoint made by assembly - auto symbol_context = bp_addr.GetSymbolContext( - lldb::eSymbolContextSymbol | lldb::eSymbolContextModule); - if (symbol_context.IsValid()) { - auto symbol = symbol_context.GetSymbol(); + auto symbol = bp_addr.GetSymbol(); + if (symbol.IsValid()) { breakpoint.line = m_bp.GetTarget() .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) .GetSize() + 1; - protocol::Source source; - source.name = symbol.GetName(); - auto module = symbol_context.GetModule(); - if (module.IsValid()) { - std::string path = module.GetFileSpec().GetDirectory(); - path += "/"; - path += module.GetFileSpec().GetFilename(); - source.path = std::move(path); - } - - breakpoint.source = std::move(source); + breakpoint.source = CreateAssemblySource(m_dap.target, bp_addr); } } } diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index 06ada47a6f27f..c4d658caeee2d 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "DAP.h" -#include "LLDBUtils.h" #include "RequestHandler.h" #include @@ -108,15 +107,11 @@ template void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( llvm::SmallVector, N> &locations, int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { - lldb::SBProcess process = dap.target.GetProcess(); - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - - if (!frame.IsValid()) + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) return; - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) return; diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index d69da5bd02c1e..7b401f06e9a85 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -9,7 +9,6 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" -#include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" #include @@ -99,15 +98,11 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( std::vector response_breakpoints; int64_t sourceReference = source.sourceReference.value_or(0); - lldb::SBProcess process = dap.target.GetProcess(); - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(sourceReference)); - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(sourceReference)); - - if (!frame.IsValid()) + lldb::SBAddress address(sourceReference, dap.target); + if (!address.IsValid()) return response_breakpoints; - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) return response_breakpoints; // Not yet supporting breakpoints in assembly // without a valid symbol diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp index fb396a3dc8862..9249e2aa6fef7 100644 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp @@ -11,6 +11,7 @@ #include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" +#include "lldb/API/SBAddress.h" #include "lldb/API/SBExecutionContext.h" #include "lldb/API/SBFrame.h" #include "lldb/API/SBInstructionList.h" @@ -19,6 +20,7 @@ #include "lldb/API/SBSymbol.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" +#include "lldb/lldb-types.h" #include "llvm/Support/Error.h" namespace lldb_dap { @@ -34,18 +36,14 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { return llvm::make_error( "invalid arguments, expected source.sourceReference to be set"); - lldb::SBProcess process = dap.target.GetProcess(); - // Upper 32 bits is the thread index ID - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(source)); - // Lower 32 bits is the frame index - lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(source)); - if (!frame.IsValid()) + lldb::SBAddress address(source, dap.target); + if (!address.IsValid()) return llvm::make_error("source not found"); + lldb::SBSymbol symbol = address.GetSymbol(); + lldb::SBStream stream; - lldb::SBExecutionContext exe_ctx(frame); - lldb::SBSymbol symbol = frame.GetSymbol(); + lldb::SBExecutionContext exe_ctx(dap.target); if (symbol.IsValid()) { lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); @@ -53,7 +51,7 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const { } else { // No valid symbol, just return the disassembly. lldb::SBInstructionList insts = dap.target.ReadInstructions( - frame.GetPCAddress(), dap.number_of_assembly_lines_for_nodebug); + address, dap.number_of_assembly_lines_for_nodebug); insts.GetDescription(stream, exe_ctx); } diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 714947a4d3b9c..c8151c3d64ea4 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -490,6 +490,13 @@ CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp) { return filter; } +static std::string GetLoadAddressString(const lldb::addr_t addr) { + std::string result; + llvm::raw_string_ostream os(result); + os << llvm::format_hex(addr, 18); + return result; +} + protocol::Source CreateSource(const lldb::SBFileSpec &file) { protocol::Source source; if (file.IsValid()) { @@ -516,6 +523,43 @@ protocol::Source CreateSource(llvm::StringRef source_path) { return source; } +protocol::Source CreateAssemblySource(const lldb::SBTarget &target, + lldb::SBAddress &address) { + protocol::Source source; + + auto symbol = address.GetSymbol(); + std::string name; + if (symbol.IsValid()) { + source.sourceReference = symbol.GetStartAddress().GetLoadAddress(target); + name = symbol.GetName(); + } else { + const auto load_addr = address.GetLoadAddress(target); + source.sourceReference = load_addr; + name = GetLoadAddressString(load_addr); + } + + lldb::SBModule module = address.GetModule(); + if (module.IsValid()) { + lldb::SBFileSpec file_spec = module.GetFileSpec(); + if (file_spec.IsValid()) { + lldb::SBStream module_path; + if (file_spec.GetPath(module_path)) { + std::string path = module_path.GetData(); + source.path = path + '`' + name; + } + } + } + + source.name = std::move(name); + + // Mark the source as deemphasized since users will only be able to view + // assembly for these frames. + source.presentationHint = + protocol::Source::PresentationHint::eSourcePresentationHintDeemphasize; + + return source; +} + bool ShouldDisplayAssemblySource( const lldb::SBLineEntry &line_entry, lldb::StopDisassemblyType stop_disassembly_display) { @@ -619,12 +663,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, frame_name = name; } - if (frame_name.empty()) { + if (frame_name.empty()) // If the function name is unavailable, display the pc address as a 16-digit // hex string, e.g. "0x0000000000012345" - llvm::raw_string_ostream os(frame_name); - os << llvm::format_hex(frame.GetPC(), 18); - } + frame_name = GetLoadAddressString(frame.GetPC()); // We only include `[opt]` if a custom frame format is not specified. if (!format && frame.GetFunction().GetIsOptimized()) @@ -641,17 +683,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, } else if (frame.GetSymbol().IsValid()) { // If no source is associated with the frame, use the DAPFrameID to track // the 'source' and generate assembly. - llvm::json::Object source; - EmplaceSafeString(source, "name", frame_name); - char buf[PATH_MAX] = {0}; - size_t size = frame.GetModule().GetFileSpec().GetPath(buf, PATH_MAX); - EmplaceSafeString(source, "path", - std::string(buf, size) + '`' + frame_name); - source.try_emplace("sourceReference", MakeDAPFrameID(frame)); - // Mark the source as deemphasized since users will only be able to view - // assembly for these frames. - EmplaceSafeString(source, "presentationHint", "deemphasize"); - object.try_emplace("source", std::move(source)); + auto frame_address = frame.GetPCAddress(); + object.try_emplace("source", CreateAssemblySource( + frame.GetThread().GetProcess().GetTarget(), + frame_address)); // Calculate the line of the current PC from the start of the current // symbol. @@ -665,12 +700,10 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, object.try_emplace("column", 1); } else { // No valid line entry or symbol. - llvm::json::Object source; - EmplaceSafeString(source, "name", frame_name); - source.try_emplace("sourceReference", MakeDAPFrameID(frame)); - EmplaceSafeString(source, "presentationHint", "deemphasize"); - object.try_emplace("source", std::move(source)); - + auto frame_address = frame.GetPCAddress(); + object.try_emplace("source", CreateAssemblySource( + frame.GetThread().GetProcess().GetTarget(), + frame_address)); object.try_emplace("line", 1); object.try_emplace("column", 1); } diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h index 783f291338d8c..ac9b39739104f 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -269,6 +269,20 @@ protocol::Source CreateSource(const lldb::SBLineEntry &line_entry); /// definition outlined by Microsoft. protocol::Source CreateSource(llvm::StringRef source_path); +/// Create a "Source" object for a given frame, using its assembly for source. +/// +/// \param[in] target +/// The relevant target. +/// +/// \param[in] address +/// The address to use when creating the "Source" object. +/// +/// \return +/// A "Source" JSON object that follows the formal JSON +/// definition outlined by Microsoft. +protocol::Source CreateAssemblySource(const lldb::SBTarget &target, + lldb::SBAddress &address); + /// Return true if the given line entry should be displayed as assembly. /// /// \param[in] line_entry >From f5fd76de3ad25b9cbf6ce065e06c98ff30b070a8 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 02:22:19 +0200 Subject: [PATCH 06/15] add breakpoint-assembly test --- .../test/tools/lldb-dap/dap_server.py | 7 ++++ .../test/tools/lldb-dap/lldbdap_testcase.py | 10 +++++ .../lldb-dap/breakpoint-assembly/Makefile | 3 ++ .../TestDAP_breakpointAssembly.py | 42 +++++++++++++++++++ .../tools/lldb-dap/breakpoint-assembly/main.c | 14 +++++++ .../breakpoint/TestDAP_setBreakpoints.py | 1 + .../TestDAP_setExceptionBreakpoints.py | 1 + .../TestDAP_setFunctionBreakpoints.py | 1 + 8 files changed, 79 insertions(+) create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py create mode 100644 lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index 70fd0b0c419db..4a907a5e36901 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -955,6 +955,13 @@ def request_setBreakpoints(self, file_path, line_array, data=None): """ (dir, base) = os.path.split(file_path) source_dict = {"name": base, "path": file_path} + return self.request_setBreakpoints_with_source(source_dict, line_array, data) + + def request_setBreakpointsAssembly(self, sourceReference, line_array, data=None): + source_dict = {"sourceReference": sourceReference} + return self.request_setBreakpoints_with_source(source_dict, line_array, data) + + def request_setBreakpoints_with_source(self, source_dict, line_array, data=None): args_dict = { "source": source_dict, "sourceModified": False, diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index afdc746ed0d0d..427f66a7da0c8 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -63,6 +63,16 @@ def set_source_breakpoints(self, source_path, lines, data=None): for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) return breakpoint_ids + + def set_source_breakpoints_assembly(self, source_reference, lines, data=None): + response = self.dap_server.request_setBreakpointsAssembly(source_reference, lines, data) + if response is None: + return [] + breakpoints = response["body"]["breakpoints"] + breakpoint_ids = [] + for breakpoint in breakpoints: + breakpoint_ids.append("%i" % (breakpoint["id"])) + return breakpoint_ids def set_function_breakpoints(self, functions, condition=None, hitCondition=None): """Sets breakpoints by function name given an array of function names diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile new file mode 100644 index 0000000000000..10495940055b6 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py new file mode 100644 index 0000000000000..ba9df3a18590b --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py @@ -0,0 +1,42 @@ +""" +Test lldb-dap setBreakpoints request +""" + + +import dap_server +import shutil +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +import lldbdap_testcase +import os + + +class TestDAP_setBreakpointsAssembly(lldbdap_testcase.DAPTestCaseBase): + # @skipIfWindows + def test_functionality(self): + """Tests hitting assembly source breakpoints""" + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + + self.dap_server.request_evaluate( + "`settings set stop-disassembly-display no-debuginfo", context="repl" + ) + + assmebly_func_breakpoints = self.set_function_breakpoints(["assembly_func"]) + self.continue_to_breakpoints(assmebly_func_breakpoints) + + assembly_func_frame = self.get_stackFrames()[0] + self.assertIn( + "sourceReference", + assembly_func_frame.get("source"), + "Expected assembly source frame", + ) + + line = assembly_func_frame["line"] + + # Set an assembly breakpoint in the next line and check that it's hit + assembly_breakpoint_ids = self.set_source_breakpoints_assembly( + assembly_func_frame["source"]["sourceReference"], [line + 1] + ) + self.continue_to_breakpoints(assembly_breakpoint_ids) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c new file mode 100644 index 0000000000000..350739006f903 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c @@ -0,0 +1,14 @@ +#include + +__attribute__((nodebug)) int assembly_func(int n) { + n += 1; + n += 2; + n += 3; + + return n; +} + +int main(int argc, char const *argv[]) { + assembly_func(10); + return 0; +} diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index 26df2573555df..aae1251b17c93 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,6 +12,7 @@ import os + at skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py index 92ac66cd44c5d..4dc8c5b3c7ded 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py @@ -10,6 +10,7 @@ import lldbdap_testcase + at skip("Temporarily disable the breakpoint tests") class TestDAP_setExceptionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_functionality(self): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index 946595f639edc..baaca4d974d5d 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,6 +10,7 @@ import lldbdap_testcase + at skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): >From 40f68e418bfbb6564b3834382c4a33a3104fc33d Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 10:23:11 +0200 Subject: [PATCH 07/15] python format --- .../lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index 427f66a7da0c8..3bf649a087fdb 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -63,9 +63,11 @@ def set_source_breakpoints(self, source_path, lines, data=None): for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) return breakpoint_ids - + def set_source_breakpoints_assembly(self, source_reference, lines, data=None): - response = self.dap_server.request_setBreakpointsAssembly(source_reference, lines, data) + response = self.dap_server.request_setBreakpointsAssembly( + source_reference, lines, data + ) if response is None: return [] breakpoints = response["body"]["breakpoints"] >From 199512fd7a0900d45070b95dd52ef5ef136e2719 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 10:54:43 +0200 Subject: [PATCH 08/15] restore SBFileSpec and fix assembly breakpoints CR --- lldb/include/lldb/API/SBFileSpec.h | 2 - lldb/source/API/SBFileSpec.cpp | 7 --- lldb/tools/lldb-dap/DAP.h | 2 +- .../Handler/BreakpointLocationsHandler.cpp | 47 ++++++++++--------- lldb/tools/lldb-dap/Handler/RequestHandler.h | 17 ++++--- .../Handler/SetBreakpointsRequestHandler.cpp | 9 ++-- lldb/tools/lldb-dap/JSONUtils.cpp | 6 +-- lldb/tools/lldb-dap/LLDBUtils.cpp | 10 ++++ lldb/tools/lldb-dap/LLDBUtils.h | 10 ++++ 9 files changed, 60 insertions(+), 50 deletions(-) diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index 303cb7d712cbf..1bb28b2ddab01 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -54,8 +54,6 @@ class LLDB_API SBFileSpec { uint32_t GetPath(char *dst_path, size_t dst_len) const; - bool GetPath(lldb::SBStream &dst_path) const; - static int ResolvePath(const char *src_path, char *dst_path, size_t dst_len); bool GetDescription(lldb::SBStream &description) const; diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp index cb44dac1d4fcc..f18857f59171a 100644 --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -148,13 +148,6 @@ uint32_t SBFileSpec::GetPath(char *dst_path, size_t dst_len) const { return result; } -bool SBFileSpec::GetPath(SBStream &dst_path) const { - LLDB_INSTRUMENT_VA(this, dst_path); - - std::string path = m_opaque_up->GetPath(); - return dst_path->PutCString(path.c_str()) > 0; -} - const lldb_private::FileSpec *SBFileSpec::operator->() const { return m_opaque_up.get(); } diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index b0fe265b7bca1..20f95be792f41 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -222,7 +222,7 @@ struct DAP { /// @} /// Number of lines of assembly code to show when no debug info is available. - uint32_t number_of_assembly_lines_for_nodebug = 32; + static constexpr uint32_t number_of_assembly_lines_for_nodebug = 32; /// Creates a new DAP sessions. /// diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp index c4d658caeee2d..794b83a9e0e1e 100644 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp @@ -8,6 +8,7 @@ #include "DAP.h" #include "RequestHandler.h" +#include #include namespace lldb_dap { @@ -24,15 +25,15 @@ BreakpointLocationsRequestHandler::Run( uint32_t end_column = args.endColumn.value_or(std::numeric_limits::max()); - // Find all relevant lines & columns - llvm::SmallVector, 8> locations; - if (args.source.sourceReference) { - AddAssemblyBreakpointLocations(locations, *args.source.sourceReference, - start_line, end_line); - } else { + // Find all relevant lines & columns. + std::vector> locations; + if (args.source.sourceReference) + locations = GetAssemblyBreakpointLocations(*args.source.sourceReference, + start_line, end_line); + else { std::string path = args.source.path.value_or(""); - AddSourceBreakpointLocations(locations, std::move(path), start_line, - start_column, end_line, end_column); + locations = GetSourceBreakpointLocations( + std::move(path), start_line, start_column, end_line, end_column); } // The line entries are sorted by addresses, but we must return the list @@ -41,23 +42,19 @@ BreakpointLocationsRequestHandler::Run( locations.erase(llvm::unique(locations), locations.end()); std::vector breakpoint_locations; - for (auto &l : locations) { - protocol::BreakpointLocation lc; - lc.line = l.first; - lc.column = l.second; - breakpoint_locations.push_back(std::move(lc)); - } + for (auto &l : locations) + breakpoint_locations.push_back( + {l.first, l.second, std::nullopt, std::nullopt}); return protocol::BreakpointLocationsResponseBody{ /*breakpoints=*/std::move(breakpoint_locations)}; } -template -void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( - llvm::SmallVector, N> &locations, +std::vector> +BreakpointLocationsRequestHandler::GetSourceBreakpointLocations( std::string path, uint32_t start_line, uint32_t start_column, uint32_t end_line, uint32_t end_column) const { - + std::vector> locations; lldb::SBFileSpec file_spec(path.c_str(), true); lldb::SBSymbolContextList compile_units = dap.target.FindCompileUnits(file_spec); @@ -101,19 +98,21 @@ void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations( locations.emplace_back(line, column); } } + + return locations; } -template -void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( - llvm::SmallVector, N> &locations, +std::vector> +BreakpointLocationsRequestHandler::GetAssemblyBreakpointLocations( int64_t sourceReference, uint32_t start_line, uint32_t end_line) const { + std::vector> locations; lldb::SBAddress address(sourceReference, dap.target); if (!address.IsValid()) - return; + return locations; lldb::SBSymbol symbol = address.GetSymbol(); if (!symbol.IsValid()) - return; + return locations; // start_line is relative to the symbol's start address lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); @@ -121,6 +120,8 @@ void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations( ++i) { locations.emplace_back(i, 1); } + + return locations; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 80898d1ee5ef1..e708abb50d5c0 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -23,6 +23,7 @@ #include #include #include +#include template struct is_optional : std::false_type {}; @@ -234,15 +235,13 @@ class BreakpointLocationsRequestHandler llvm::Expected Run(const protocol::BreakpointLocationsArguments &args) const override; - template - void AddSourceBreakpointLocations( - llvm::SmallVector, N> &locations, - std::string path, uint32_t start_line, uint32_t start_column, - uint32_t end_line, uint32_t end_column) const; - template - void AddAssemblyBreakpointLocations( - llvm::SmallVector, N> &locations, - int64_t sourceReference, uint32_t start_line, uint32_t end_line) const; + std::vector> + GetSourceBreakpointLocations(std::string path, uint32_t start_line, + uint32_t start_column, uint32_t end_line, + uint32_t end_column) const; + std::vector> + GetAssemblyBreakpointLocations(int64_t sourceReference, uint32_t start_line, + uint32_t end_line) const; }; class CompletionsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 7b401f06e9a85..bf0b584753c07 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -103,9 +103,10 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( return response_breakpoints; lldb::SBSymbol symbol = address.GetSymbol(); - if (!symbol.IsValid()) - return response_breakpoints; // Not yet supporting breakpoints in assembly - // without a valid symbol + if (!symbol.IsValid()) { + // Not yet supporting breakpoints in assembly without a valid symbol. + return response_breakpoints; + } llvm::DenseMap request_bps; if (breakpoints) { @@ -115,7 +116,7 @@ SetBreakpointsRequestHandler::SetAssemblyBreakpoints( const auto [iv, inserted] = dap.assembly_breakpoints[sourceReference].try_emplace( src_bp.GetLine(), src_bp); - // We check if this breakpoint already exists to update it + // We check if this breakpoint already exists to update it. if (inserted) iv->getSecond().SetBreakpoint(symbol); else diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index c8151c3d64ea4..1d2a6ff60e502 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -542,11 +542,9 @@ protocol::Source CreateAssemblySource(const lldb::SBTarget &target, if (module.IsValid()) { lldb::SBFileSpec file_spec = module.GetFileSpec(); if (file_spec.IsValid()) { - lldb::SBStream module_path; - if (file_spec.GetPath(module_path)) { - std::string path = module_path.GetData(); + std::string path = GetSBFileSpecPath(file_spec); + if (!path.empty()) source.path = path + '`' + name; - } } } diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp index 0e7bb2b9058a7..3c7623ec1215d 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.cpp +++ b/lldb/tools/lldb-dap/LLDBUtils.cpp @@ -20,6 +20,7 @@ #include "llvm/Support/JSON.h" #include "llvm/Support/raw_ostream.h" +#include #include #include @@ -242,4 +243,13 @@ ScopeSyncMode::ScopeSyncMode(lldb::SBDebugger &debugger) ScopeSyncMode::~ScopeSyncMode() { m_debugger.SetAsync(m_async); } +std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec) { + const auto directory_length = ::strlen(file_spec.GetDirectory()); + const auto file_name_length = ::strlen(file_spec.GetFilename()); + + std::string path(directory_length + file_name_length + 2, '\0'); + file_spec.GetPath(path.data(), path.length()); + return path; +} + } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/LLDBUtils.h b/lldb/tools/lldb-dap/LLDBUtils.h index 711fc6051231c..7fdf4b859ee61 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.h +++ b/lldb/tools/lldb-dap/LLDBUtils.h @@ -13,6 +13,7 @@ #include "lldb/API/SBDebugger.h" #include "lldb/API/SBEnvironment.h" #include "lldb/API/SBError.h" +#include "lldb/API/SBFileSpec.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" @@ -161,6 +162,15 @@ uint32_t GetLLDBFrameID(uint64_t dap_frame_id); lldb::SBEnvironment GetEnvironmentFromArguments(const llvm::json::Object &arguments); +/// Gets an SBFileSpec and returns its path as a string. +/// +/// \param[in] file_spec +/// The file spec. +/// +/// \return +/// The file path as a string. +std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec); + /// Helper for sending telemetry to lldb server, if client-telemetry is enabled. class TelemetryDispatcher { public: >From dbad33b314bb59f6e0d22fd07dddb35e2a0e30d9 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 12:57:59 +0200 Subject: [PATCH 09/15] abstracted source breakpoints maps by DAP --- lldb/tools/lldb-dap/Breakpoint.cpp | 4 +- lldb/tools/lldb-dap/DAP.cpp | 75 +++++++++++ lldb/tools/lldb-dap/DAP.h | 29 +++- lldb/tools/lldb-dap/Handler/RequestHandler.h | 9 -- .../Handler/SetBreakpointsRequestHandler.cpp | 125 +----------------- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 54 +++++--- lldb/tools/lldb-dap/SourceBreakpoint.h | 7 +- 7 files changed, 140 insertions(+), 163 deletions(-) diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index a54a34e0f936d..fd7531f42c518 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -71,10 +71,10 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { auto line_entry = bp_addr.GetLineEntry(); if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) { const auto line = line_entry.GetLine(); - if (line != UINT32_MAX) + if (line != LLDB_INVALID_LINE_NUMBER) breakpoint.line = line; const auto column = line_entry.GetColumn(); - if (column != 0) + if (column != LLDB_INVALID_COLUMN_NUMBER) breakpoint.column = column; breakpoint.source = CreateSource(line_entry); } else { diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 0d5eba6c40961..1fe46fc619d73 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1620,6 +1620,81 @@ void DAP::EventThread() { } } +std::vector DAP::SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints) { + std::vector response_breakpoints; + if (source.sourceReference) { + // breakpoint set by assembly source. + auto &existing_breakpoints_pos = + m_source_assembly_breakpoints[*source.sourceReference]; + response_breakpoints = + SetSourceBreakpoints(source, breakpoints, existing_breakpoints_pos); + } else { + // breakpoint set by a regular source file. + const auto path = source.path.value_or(""); + auto &existing_breakpoints_pos = m_source_breakpoints[path]; + response_breakpoints = + SetSourceBreakpoints(source, breakpoints, existing_breakpoints_pos); + } + + return response_breakpoints; +} + +std::vector DAP::SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints, + SourceBreakpointMap &existing_breakpoints) { + std::vector response_breakpoints; + + SourceBreakpointMap request_breakpoints; + if (breakpoints) { + for (const auto &bp : *breakpoints) { + SourceBreakpoint src_bp(*this, bp, source); + std::pair bp_pos(src_bp.GetLine(), + src_bp.GetColumn()); + request_breakpoints.try_emplace(bp_pos, src_bp); + + const auto [iv, inserted] = + existing_breakpoints.try_emplace(bp_pos, src_bp); + // We check if this breakpoint already exists to update it. + if (inserted) + iv->second.SetBreakpoint(); + else + iv->second.UpdateBreakpoint(src_bp); + + protocol::Breakpoint response_breakpoint = + iv->second.ToProtocolBreakpoint(); + response_breakpoint.source = source; + + if (!response_breakpoint.line && + src_bp.GetLine() != LLDB_INVALID_LINE_NUMBER) + response_breakpoint.line = src_bp.GetLine(); + if (!response_breakpoint.column && + src_bp.GetColumn() != LLDB_INVALID_COLUMN_NUMBER) + response_breakpoint.column = src_bp.GetColumn(); + response_breakpoints.push_back(response_breakpoint); + } + } + + // Delete any breakpoints in this source file that aren't in the + // request_bps set. There is no call to remove breakpoints other than + // calling this function with a smaller or empty "breakpoints" list. + for (auto it = existing_breakpoints.begin(); + it != existing_breakpoints.end();) { + auto request_pos = request_breakpoints.find(it->first); + if (request_pos == request_breakpoints.end()) { + // This breakpoint no longer exists in this source file, delete it + target.BreakpointDelete(it->second.GetID()); + it = existing_breakpoints.erase(it); + } else { + ++it; + } + } + + return response_breakpoints; +} + void DAP::RegisterRequests() { RegisterRequest(); RegisterRequest(); diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 20f95be792f41..3a0a7fc1678ba 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -60,7 +60,7 @@ namespace lldb_dap { -typedef llvm::DenseMap, SourceBreakpoint> +typedef std::map, SourceBreakpoint> SourceBreakpointMap; typedef llvm::StringMap FunctionBreakpointMap; typedef llvm::DenseMap @@ -168,9 +168,6 @@ struct DAP { lldb::SBTarget target; Variables variables; lldb::SBBroadcaster broadcaster; - llvm::StringMap source_breakpoints; - llvm::DenseMap> - assembly_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; @@ -428,7 +425,28 @@ struct DAP { void StartEventThread(); void StartProgressEventThread(); + /// Sets the given protocol `breakpoints` in the given `source`, while + /// removing any existing breakpoints in the given source if they are not in + /// `breakpoint`. + /// + /// \param[in] source + /// The relevant source of the breakpoints. + /// + /// \param[in] breakpoints + /// The breakpoints to set. + /// + /// \return a vector of the breakpoints that were set. + std::vector SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> + &breakpoints); + private: + std::vector SetSourceBreakpoints( + const protocol::Source &source, + const std::optional> &breakpoints, + SourceBreakpointMap &existing_breakpoints); + /// Registration of request handler. /// @{ void RegisterRequests(); @@ -457,6 +475,9 @@ struct DAP { std::mutex m_active_request_mutex; const protocol::Request *m_active_request; + + llvm::StringMap m_source_breakpoints; + llvm::DenseMap m_source_assembly_breakpoints; }; } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index e708abb50d5c0..54f728414021e 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -388,15 +388,6 @@ class SetBreakpointsRequestHandler } llvm::Expected Run(const protocol::SetBreakpointsArguments &args) const override; - - std::vector SetSourceBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const; - std::vector SetAssemblyBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const; }; class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index bf0b584753c07..0ff88f62f8f51 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -22,130 +22,9 @@ namespace lldb_dap { llvm::Expected SetBreakpointsRequestHandler::Run( const protocol::SetBreakpointsArguments &args) const { - const auto &source = args.source; - std::vector response_breakpoints; - if (source.sourceReference) - response_breakpoints = SetAssemblyBreakpoints(source, args.breakpoints); - else if (source.path) - response_breakpoints = SetSourceBreakpoints(source, args.breakpoints); - + const auto response_breakpoints = + dap.SetSourceBreakpoints(args.source, args.breakpoints); return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; } -std::vector -SetBreakpointsRequestHandler::SetSourceBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const { - std::vector response_breakpoints; - std::string path = source.path.value_or(""); - - // Decode the source breakpoint infos for this "setBreakpoints" request - SourceBreakpointMap request_bps; - // "breakpoints" may be unset, in which case we treat it the same as being set - // to an empty array. - if (breakpoints) { - for (const auto &bp : *breakpoints) { - SourceBreakpoint src_bp(dap, bp); - std::pair bp_pos(src_bp.GetLine(), - src_bp.GetColumn()); - request_bps.try_emplace(bp_pos, src_bp); - const auto [iv, inserted] = - dap.source_breakpoints[path].try_emplace(bp_pos, src_bp); - // We check if this breakpoint already exists to update it - if (inserted) - iv->getSecond().SetBreakpoint(path.data()); - else - iv->getSecond().UpdateBreakpoint(src_bp); - - protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - - // Use the path from the request if it is set - if (!path.empty()) - response_bp.source = CreateSource(path); - - if (!response_bp.line) - response_bp.line = src_bp.GetLine(); - if (!response_bp.column) - response_bp.column = src_bp.GetColumn(); - response_breakpoints.push_back(response_bp); - } - } - - // Delete any breakpoints in this source file that aren't in the - // request_bps set. There is no call to remove breakpoints other than - // calling this function with a smaller or empty "breakpoints" list. - auto old_src_bp_pos = dap.source_breakpoints.find(path); - if (old_src_bp_pos != dap.source_breakpoints.end()) { - for (auto &old_bp : old_src_bp_pos->second) { - auto request_pos = request_bps.find(old_bp.first); - if (request_pos == request_bps.end()) { - // This breakpoint no longer exists in this source file, delete it - dap.target.BreakpointDelete(old_bp.second.GetID()); - old_src_bp_pos->second.erase(old_bp.first); - } - } - } - - return response_breakpoints; -} - -std::vector -SetBreakpointsRequestHandler::SetAssemblyBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) - const { - std::vector response_breakpoints; - int64_t sourceReference = source.sourceReference.value_or(0); - - lldb::SBAddress address(sourceReference, dap.target); - if (!address.IsValid()) - return response_breakpoints; - - lldb::SBSymbol symbol = address.GetSymbol(); - if (!symbol.IsValid()) { - // Not yet supporting breakpoints in assembly without a valid symbol. - return response_breakpoints; - } - - llvm::DenseMap request_bps; - if (breakpoints) { - for (const auto &bp : *breakpoints) { - SourceBreakpoint src_bp(dap, bp); - request_bps.try_emplace(src_bp.GetLine(), src_bp); - const auto [iv, inserted] = - dap.assembly_breakpoints[sourceReference].try_emplace( - src_bp.GetLine(), src_bp); - // We check if this breakpoint already exists to update it. - if (inserted) - iv->getSecond().SetBreakpoint(symbol); - else - iv->getSecond().UpdateBreakpoint(src_bp); - - protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint(); - response_bp.source = source; - if (!response_bp.line) - response_bp.line = src_bp.GetLine(); - if (bp.column) - response_bp.column = *bp.column; - response_breakpoints.push_back(response_bp); - } - } - - // Delete existing breakpoints for this sourceReference that are not in the - // request_bps set. - auto old_src_bp_pos = dap.assembly_breakpoints.find(sourceReference); - if (old_src_bp_pos != dap.assembly_breakpoints.end()) { - for (auto &old_bp : old_src_bp_pos->second) { - auto request_pos = request_bps.find(old_bp.first); - if (request_pos == request_bps.end()) { - dap.target.BreakpointDelete(old_bp.second.GetID()); - old_src_bp_pos->second.erase(old_bp.first); - } - } - } - - return response_breakpoints; -} - } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 938b8fb8bcdda..50ebfbe8aef20 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -29,39 +29,49 @@ namespace lldb_dap { SourceBreakpoint::SourceBreakpoint(DAP &dap, - const protocol::SourceBreakpoint &breakpoint) + const protocol::SourceBreakpoint &breakpoint, + const protocol::Source &source) : Breakpoint(dap, breakpoint.condition, breakpoint.hitCondition), - m_log_message(breakpoint.logMessage.value_or("")), + m_log_message(breakpoint.logMessage.value_or("")), m_source(source), m_line(breakpoint.line), m_column(breakpoint.column.value_or(LLDB_INVALID_COLUMN_NUMBER)) {} -void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) { - lldb::SBMutex lock = m_dap.GetAPIMutex(); - std::lock_guard guard(lock); - - lldb::SBFileSpecList module_list; - m_bp = m_dap.target.BreakpointCreateByLocation( - source_path.str().c_str(), m_line, m_column, 0, module_list); - if (!m_log_message.empty()) - SetLogMessage(); - Breakpoint::SetBreakpoint(); -} - -void SourceBreakpoint::SetBreakpoint(lldb::SBSymbol &symbol) { +void SourceBreakpoint::SetBreakpoint() { lldb::SBMutex lock = m_dap.GetAPIMutex(); std::lock_guard guard(lock); if (m_line == 0) return; - lldb::SBInstructionList inst_list = - m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); - if (inst_list.GetSize() < m_line) - return; - lldb::SBAddress address = - inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + if (m_source.sourceReference) { + // breakpoint set by assembly source. + lldb::SBAddress source_address(*m_source.sourceReference, m_dap.target); + if (!source_address.IsValid()) + return; + + lldb::SBSymbol symbol = source_address.GetSymbol(); + if (!symbol.IsValid()) { + // Not yet supporting breakpoints in assembly without a valid symbol. + return; + } + + lldb::SBInstructionList inst_list = + m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); + if (inst_list.GetSize() < m_line) + return; + + lldb::SBAddress address = + inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + + m_bp = m_dap.target.BreakpointCreateBySBAddress(address); + } else { + // breakpoint set by a regular source file. + const auto source_path = m_source.path.value_or(""); + lldb::SBFileSpecList module_list; + m_bp = m_dap.target.BreakpointCreateByLocation(source_path.c_str(), m_line, + m_column, 0, module_list); + } - m_bp = m_dap.target.BreakpointCreateBySBAddress(address); if (!m_log_message.empty()) SetLogMessage(); Breakpoint::SetBreakpoint(); diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h index 8589800e50983..3221ecbf28ece 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.h +++ b/lldb/tools/lldb-dap/SourceBreakpoint.h @@ -22,11 +22,11 @@ namespace lldb_dap { class SourceBreakpoint : public Breakpoint { public: - SourceBreakpoint(DAP &d, const protocol::SourceBreakpoint &breakpoint); + SourceBreakpoint(DAP &d, const protocol::SourceBreakpoint &breakpoint, + const protocol::Source &source); // Set this breakpoint in LLDB as a new breakpoint - void SetBreakpoint(const llvm::StringRef source_path); - void SetBreakpoint(lldb::SBSymbol &symbol); + void SetBreakpoint(); void UpdateBreakpoint(const SourceBreakpoint &request_bp); void SetLogMessage(); @@ -63,6 +63,7 @@ class SourceBreakpoint : public Breakpoint { std::string m_log_message; std::vector m_log_message_parts; + protocol::Source m_source; /// The original breakpoint source. uint32_t m_line; ///< The source line of the breakpoint or logpoint uint32_t m_column; ///< An optional source column of the breakpoint }; >From 2e9edca37c0953e2d2a6cf2d278bb353f1e0960b Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 13:39:05 +0200 Subject: [PATCH 10/15] improve assembvly breakpoint test to check clear --- .../TestDAP_breakpointAssembly.py | 17 +++++++++++++++-- .../tools/lldb-dap/breakpoint-assembly/main.c | 4 +++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py index ba9df3a18590b..dacc1cd8349f1 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py @@ -6,7 +6,7 @@ import dap_server import shutil from lldbsuite.test.decorators import * -from lldbsuite.test.lldbtest import * +from lldbsuite.test.lldbtest import line_number from lldbsuite.test import lldbutil import lldbdap_testcase import os @@ -23,6 +23,9 @@ def test_functionality(self): "`settings set stop-disassembly-display no-debuginfo", context="repl" ) + finish_line = line_number("main.c", "// Break here") + finish_breakpoints = self.set_source_breakpoints("main.c", [finish_line]) + assmebly_func_breakpoints = self.set_function_breakpoints(["assembly_func"]) self.continue_to_breakpoints(assmebly_func_breakpoints) @@ -36,7 +39,17 @@ def test_functionality(self): line = assembly_func_frame["line"] # Set an assembly breakpoint in the next line and check that it's hit + source_reference = assembly_func_frame["source"]["sourceReference"] assembly_breakpoint_ids = self.set_source_breakpoints_assembly( - assembly_func_frame["source"]["sourceReference"], [line + 1] + source_reference, [line + 1] ) self.continue_to_breakpoints(assembly_breakpoint_ids) + + # Continue again and verify it hits in the next function call + self.continue_to_breakpoints(assmebly_func_breakpoints) + self.continue_to_breakpoints(assembly_breakpoint_ids) + + # Clear the breakpoint and then check that the assembly breakpoint does not hit next time + self.set_source_breakpoints_assembly(source_reference, []) + self.continue_to_breakpoints(assmebly_func_breakpoints) + self.continue_to_breakpoints(finish_breakpoints) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c index 350739006f903..e3a21df11958f 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c @@ -10,5 +10,7 @@ __attribute__((nodebug)) int assembly_func(int n) { int main(int argc, char const *argv[]) { assembly_func(10); - return 0; + assembly_func(20); + assembly_func(30); + return 0; // Break here } >From 0515c6dc6e46b6296621e871b43286ae88ea9b6b Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 13:52:40 +0200 Subject: [PATCH 11/15] fix GetSBFileSpecPath extra char --- lldb/tools/lldb-dap/LLDBUtils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp index 3c7623ec1215d..fe0bcda19b4cd 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.cpp +++ b/lldb/tools/lldb-dap/LLDBUtils.cpp @@ -247,8 +247,8 @@ std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec) { const auto directory_length = ::strlen(file_spec.GetDirectory()); const auto file_name_length = ::strlen(file_spec.GetFilename()); - std::string path(directory_length + file_name_length + 2, '\0'); - file_spec.GetPath(path.data(), path.length()); + std::string path(directory_length + file_name_length + 1, '\0'); + file_spec.GetPath(path.data(), path.length() + 1); return path; } >From 9dbca55d01c7faddc9df4586ba25c6fac421d909 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 13:59:53 +0200 Subject: [PATCH 12/15] restore SBFileSpec changes --- lldb/include/lldb/API/SBFileSpec.h | 1 - lldb/source/API/SBFileSpec.cpp | 1 - lldb/tools/lldb-dap/DAP.cpp | 8 ++++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index 1bb28b2ddab01..36641843aabeb 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -10,7 +10,6 @@ #define LLDB_API_SBFILESPEC_H #include "lldb/API/SBDefines.h" -#include "lldb/API/SBStream.h" namespace lldb { diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp index f18857f59171a..a7df9afc4b8eb 100644 --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -19,7 +19,6 @@ #include #include -#include using namespace lldb; using namespace lldb_private; diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 1fe46fc619d73..d7ef886dd2419 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1626,16 +1626,16 @@ std::vector DAP::SetSourceBreakpoints( std::vector response_breakpoints; if (source.sourceReference) { // breakpoint set by assembly source. - auto &existing_breakpoints_pos = + auto &existing_breakpoints = m_source_assembly_breakpoints[*source.sourceReference]; response_breakpoints = - SetSourceBreakpoints(source, breakpoints, existing_breakpoints_pos); + SetSourceBreakpoints(source, breakpoints, existing_breakpoints); } else { // breakpoint set by a regular source file. const auto path = source.path.value_or(""); - auto &existing_breakpoints_pos = m_source_breakpoints[path]; + auto &existing_breakpoints = m_source_breakpoints[path]; response_breakpoints = - SetSourceBreakpoints(source, breakpoints, existing_breakpoints_pos); + SetSourceBreakpoints(source, breakpoints, existing_breakpoints); } return response_breakpoints; >From 396970d6a46063450741b6b0c9c528078e433e24 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 14:01:28 +0200 Subject: [PATCH 13/15] single line if with comments curly braces --- lldb/tools/lldb-dap/JSONUtils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 1d2a6ff60e502..dcc25c9212432 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -661,10 +661,11 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, frame_name = name; } - if (frame_name.empty()) + if (frame_name.empty()) { // If the function name is unavailable, display the pc address as a 16-digit // hex string, e.g. "0x0000000000012345" frame_name = GetLoadAddressString(frame.GetPC()); + } // We only include `[opt]` if a custom frame format is not specified. if (!format && frame.GetFunction().GetIsOptimized()) >From 7a0e0eeb1232028e535d2057198c8e8a7f0487d6 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 14:06:40 +0200 Subject: [PATCH 14/15] unecessary include --- lldb/tools/lldb-dap/Handler/RequestHandler.h | 1 - 1 file changed, 1 deletion(-) diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 54f728414021e..4670e23ca33d4 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -16,7 +16,6 @@ #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" #include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/JSON.h" >From 71dce6cdfd0bc682a6e0d58ac2beb090417b1668 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 14:29:35 +0200 Subject: [PATCH 15/15] unecessary source member --- lldb/tools/lldb-dap/DAP.cpp | 4 ++-- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 13 ++++++------- lldb/tools/lldb-dap/SourceBreakpoint.h | 6 ++---- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index d7ef886dd2419..309133e15db70 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1650,7 +1650,7 @@ std::vector DAP::SetSourceBreakpoints( SourceBreakpointMap request_breakpoints; if (breakpoints) { for (const auto &bp : *breakpoints) { - SourceBreakpoint src_bp(*this, bp, source); + SourceBreakpoint src_bp(*this, bp); std::pair bp_pos(src_bp.GetLine(), src_bp.GetColumn()); request_breakpoints.try_emplace(bp_pos, src_bp); @@ -1659,7 +1659,7 @@ std::vector DAP::SetSourceBreakpoints( existing_breakpoints.try_emplace(bp_pos, src_bp); // We check if this breakpoint already exists to update it. if (inserted) - iv->second.SetBreakpoint(); + iv->second.SetBreakpoint(source); else iv->second.UpdateBreakpoint(src_bp); diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 50ebfbe8aef20..16cd07cc8b9ae 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -29,23 +29,22 @@ namespace lldb_dap { SourceBreakpoint::SourceBreakpoint(DAP &dap, - const protocol::SourceBreakpoint &breakpoint, - const protocol::Source &source) + const protocol::SourceBreakpoint &breakpoint) : Breakpoint(dap, breakpoint.condition, breakpoint.hitCondition), - m_log_message(breakpoint.logMessage.value_or("")), m_source(source), + m_log_message(breakpoint.logMessage.value_or("")), m_line(breakpoint.line), m_column(breakpoint.column.value_or(LLDB_INVALID_COLUMN_NUMBER)) {} -void SourceBreakpoint::SetBreakpoint() { +void SourceBreakpoint::SetBreakpoint(const protocol::Source &source) { lldb::SBMutex lock = m_dap.GetAPIMutex(); std::lock_guard guard(lock); if (m_line == 0) return; - if (m_source.sourceReference) { + if (source.sourceReference) { // breakpoint set by assembly source. - lldb::SBAddress source_address(*m_source.sourceReference, m_dap.target); + lldb::SBAddress source_address(*source.sourceReference, m_dap.target); if (!source_address.IsValid()) return; @@ -66,7 +65,7 @@ void SourceBreakpoint::SetBreakpoint() { m_bp = m_dap.target.BreakpointCreateBySBAddress(address); } else { // breakpoint set by a regular source file. - const auto source_path = m_source.path.value_or(""); + const auto source_path = source.path.value_or(""); lldb::SBFileSpecList module_list; m_bp = m_dap.target.BreakpointCreateByLocation(source_path.c_str(), m_line, m_column, 0, module_list); diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h index 3221ecbf28ece..542773a4c980f 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.h +++ b/lldb/tools/lldb-dap/SourceBreakpoint.h @@ -22,11 +22,10 @@ namespace lldb_dap { class SourceBreakpoint : public Breakpoint { public: - SourceBreakpoint(DAP &d, const protocol::SourceBreakpoint &breakpoint, - const protocol::Source &source); + SourceBreakpoint(DAP &d, const protocol::SourceBreakpoint &breakpoint); // Set this breakpoint in LLDB as a new breakpoint - void SetBreakpoint(); + void SetBreakpoint(const protocol::Source &source); void UpdateBreakpoint(const SourceBreakpoint &request_bp); void SetLogMessage(); @@ -63,7 +62,6 @@ class SourceBreakpoint : public Breakpoint { std::string m_log_message; std::vector m_log_message_parts; - protocol::Source m_source; /// The original breakpoint source. uint32_t m_line; ///< The source line of the breakpoint or logpoint uint32_t m_column; ///< An optional source column of the breakpoint }; From lldb-commits at lists.llvm.org Sun May 18 05:39:02 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 05:39:02 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <6829d4e6.170a0220.103927.a75c@mx.google.com> https://github.com/eronnen edited https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sun May 18 07:01:49 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 07:01:49 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] assembly breakpoints (PR #139969) In-Reply-To: Message-ID: <6829e84d.170a0220.2c2147.aaeb@mx.google.com> ================ @@ -60,7 +60,7 @@ namespace lldb_dap { -typedef llvm::DenseMap, SourceBreakpoint> +typedef std::map, SourceBreakpoint> ---------------- eronnen wrote: changed to `std::map` because I'm not sure how to remove from the map while iterating it with `DenseMap` https://github.com/llvm/llvm-project/pull/139969 From lldb-commits at lists.llvm.org Sun May 18 07:36:12 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sun, 18 May 2025 07:36:12 -0700 (PDT) Subject: [Lldb-commits] [lldb] a86344c - [lldb] Remove redundant calls to std::unique_ptr::get (NFC) (NFC) (#140440) Message-ID: <6829f05c.050a0220.196fe4.b992@mx.google.com> Author: Kazu Hirata Date: 2025-05-18T07:36:09-07:00 New Revision: a86344c5a9854ae38d925566d3e9fbc0854254f6 URL: https://github.com/llvm/llvm-project/commit/a86344c5a9854ae38d925566d3e9fbc0854254f6 DIFF: https://github.com/llvm/llvm-project/commit/a86344c5a9854ae38d925566d3e9fbc0854254f6.diff LOG: [lldb] Remove redundant calls to std::unique_ptr::get (NFC) (NFC) (#140440) Added: Modified: lldb/source/Target/RegisterContextUnwind.cpp Removed: ################################################################################ diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index 2958923a98010..1884d8d53a7f6 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -273,7 +273,7 @@ void RegisterContextUnwind::InitializeZerothFrame() { call_site_unwind_plan = func_unwinders_sp->GetUnwindPlanAtCallSite( process->GetTarget(), m_thread); - if (call_site_unwind_plan.get() != nullptr) { + if (call_site_unwind_plan != nullptr) { m_fallback_unwind_plan_sp = call_site_unwind_plan; if (TryFallbackUnwindPlan()) cfa_status = true; @@ -1725,10 +1725,10 @@ RegisterContextUnwind::SavedLocationForRegister( // tricky frame and our usual techniques can continue to be used. bool RegisterContextUnwind::TryFallbackUnwindPlan() { - if (m_fallback_unwind_plan_sp.get() == nullptr) + if (m_fallback_unwind_plan_sp == nullptr) return false; - if (m_full_unwind_plan_sp.get() == nullptr) + if (m_full_unwind_plan_sp == nullptr) return false; if (m_full_unwind_plan_sp.get() == m_fallback_unwind_plan_sp.get() || @@ -1776,7 +1776,7 @@ bool RegisterContextUnwind::TryFallbackUnwindPlan() { // fallback UnwindPlan. We checked if m_fallback_unwind_plan_sp was nullptr // at the top -- the only way it became nullptr since then is via // SavedLocationForRegister(). - if (m_fallback_unwind_plan_sp.get() == nullptr) + if (m_fallback_unwind_plan_sp == nullptr) return true; // Switch the full UnwindPlan to be the fallback UnwindPlan. If we decide @@ -1865,10 +1865,10 @@ bool RegisterContextUnwind::TryFallbackUnwindPlan() { } bool RegisterContextUnwind::ForceSwitchToFallbackUnwindPlan() { - if (m_fallback_unwind_plan_sp.get() == nullptr) + if (m_fallback_unwind_plan_sp == nullptr) return false; - if (m_full_unwind_plan_sp.get() == nullptr) + if (m_full_unwind_plan_sp == nullptr) return false; if (m_full_unwind_plan_sp.get() == m_fallback_unwind_plan_sp.get() || From lldb-commits at lists.llvm.org Sun May 18 07:36:15 2025 From: lldb-commits at lists.llvm.org (Kazu Hirata via lldb-commits) Date: Sun, 18 May 2025 07:36:15 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Remove redundant calls to std::unique_ptr::get (NFC) (NFC) (PR #140440) In-Reply-To: Message-ID: <6829f05f.170a0220.21a721.b093@mx.google.com> https://github.com/kazutakahirata closed https://github.com/llvm/llvm-project/pull/140440 From lldb-commits at lists.llvm.org Sun May 18 08:03:40 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Sun, 18 May 2025 08:03:40 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Take two at refactoring the startup sequence. (PR #140331) In-Reply-To: Message-ID: <6829f6cc.170a0220.26f119.82de@mx.google.com> da-viper wrote: > @da-viper I think this version may be a bit cleaner for #140154, let me know if that works for you Yeah it fixes the issue in #140154 https://github.com/llvm/llvm-project/pull/140331 From lldb-commits at lists.llvm.org Sun May 18 08:05:27 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Sun, 18 May 2025 08:05:27 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb][lldb-dap] Basic implementation of a deferred request. (PR #140260) In-Reply-To: Message-ID: <6829f737.a70a0220.3101b8.be26@mx.google.com> da-viper wrote: I don't think there is a need for this anymore as #140331 fixes this issue. https://github.com/llvm/llvm-project/pull/140260 From lldb-commits at lists.llvm.org Sun May 18 08:07:15 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Sun, 18 May 2025 08:07:15 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Member variable cleanup in DAP.{cpp, h} (NFC) (PR #140390) In-Reply-To: Message-ID: <6829f7a3.170a0220.270341.a7fc@mx.google.com> https://github.com/da-viper approved this pull request. https://github.com/llvm/llvm-project/pull/140390 From lldb-commits at lists.llvm.org Sun May 18 08:11:36 2025 From: lldb-commits at lists.llvm.org (Ebuka Ezike via lldb-commits) Date: Sun, 18 May 2025 08:11:36 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Move the Variables struct into its own file (PR #140393) In-Reply-To: Message-ID: <6829f8a8.630a0220.414b3.7bbd@mx.google.com> https://github.com/da-viper approved this pull request. https://github.com/llvm/llvm-project/pull/140393 From lldb-commits at lists.llvm.org Sun May 18 10:23:02 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sun, 18 May 2025 10:23:02 -0700 (PDT) Subject: [Lldb-commits] [lldb] 5ab3c52 - [lldb-dap] Member variable cleanup in DAP.{cpp, h} (NFC) (#140390) Message-ID: <682a1776.a70a0220.27a4c6.d0fc@mx.google.com> Author: Jonas Devlieghere Date: 2025-05-18T10:22:59-07:00 New Revision: 5ab3c5215688f62dbc3707f0e9cc2e8b69c0a7f0 URL: https://github.com/llvm/llvm-project/commit/5ab3c5215688f62dbc3707f0e9cc2e8b69c0a7f0 DIFF: https://github.com/llvm/llvm-project/commit/5ab3c5215688f62dbc3707f0e9cc2e8b69c0a7f0.diff LOG: [lldb-dap] Member variable cleanup in DAP.{cpp,h} (NFC) (#140390) - Use in-class member initialization to simplify the constructor. - Remove unimplemented SetConfigurationDone. - Consistently use Doxygen-style comments. Added: Modified: lldb/tools/lldb-dap/DAP.cpp lldb/tools/lldb-dap/DAP.h Removed: ################################################################################ diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 0d5eba6c40961..d813cdb0b9074 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -118,13 +118,9 @@ llvm::StringRef DAP::debug_adapter_path = ""; DAP::DAP(Log *log, const ReplMode default_repl_mode, std::vector pre_init_commands, Transport &transport) : log(log), transport(transport), broadcaster("lldb-dap"), - exception_breakpoints(), focus_tid(LLDB_INVALID_THREAD_ID), - stop_at_entry(false), is_attach(false), - restarting_process_id(LLDB_INVALID_PROCESS_ID), configuration_done(false), - waiting_for_run_in_terminal(false), progress_event_reporter( [&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }), - reverse_request_seq(0), repl_mode(default_repl_mode) { + repl_mode(default_repl_mode) { configuration.preInitCommands = std::move(pre_init_commands); RegisterRequests(); } diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 8f24c6cf82924..975e2b290e1f9 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -162,10 +162,16 @@ struct DAP { lldb::SBFile in; OutputRedirector out; OutputRedirector err; + /// Configuration specified by the launch or attach commands. protocol::Configuration configuration; + + /// The debugger instance for this DAP session. lldb::SBDebugger debugger; + + /// The target instance for this DAP session. lldb::SBTarget target; + Variables variables; lldb::SBBroadcaster broadcaster; llvm::StringMap source_breakpoints; @@ -173,39 +179,53 @@ struct DAP { InstructionBreakpointMap instruction_breakpoints; std::optional> exception_breakpoints; llvm::once_flag init_exception_breakpoints_flag; - // Map step in target id to list of function targets that user can choose. + + /// Map step in target id to list of function targets that user can choose. llvm::DenseMap step_in_targets; - // A copy of the last LaunchRequest so we can reuse its arguments if we get a - // RestartRequest. Restarting an AttachRequest is not supported. + + /// A copy of the last LaunchRequest so we can reuse its arguments if we get a + /// RestartRequest. Restarting an AttachRequest is not supported. std::optional last_launch_request; - lldb::tid_t focus_tid; + + /// The focused thread for this DAP session. + lldb::tid_t focus_tid = LLDB_INVALID_THREAD_ID; + bool disconnecting = false; llvm::once_flag terminated_event_flag; - bool stop_at_entry; - bool is_attach; - // The process event thread normally responds to process exited events by - // shutting down the entire adapter. When we're restarting, we keep the id of - // the old process here so we can detect this case and keep running. - lldb::pid_t restarting_process_id; + bool stop_at_entry = false; + bool is_attach = false; + + /// The process event thread normally responds to process exited events by + /// shutting down the entire adapter. When we're restarting, we keep the id of + /// the old process here so we can detect this case and keep running. + lldb::pid_t restarting_process_id = LLDB_INVALID_PROCESS_ID; + + /// Whether we have received the ConfigurationDone request, indicating that + /// the client has finished initialization of the debug adapter. bool configuration_done; - bool waiting_for_run_in_terminal; + + bool waiting_for_run_in_terminal = false; ProgressEventReporter progress_event_reporter; - // Keep track of the last stop thread index IDs as threads won't go away - // unless we send a "thread" event to indicate the thread exited. + + /// Keep track of the last stop thread index IDs as threads won't go away + /// unless we send a "thread" event to indicate the thread exited. llvm::DenseSet thread_ids; - uint32_t reverse_request_seq; + + uint32_t reverse_request_seq = 0; std::mutex call_mutex; llvm::SmallDenseMap> inflight_reverse_requests; ReplMode repl_mode; lldb::SBFormat frame_format; lldb::SBFormat thread_format; - // This is used to allow request_evaluate to handle empty expressions - // (ie the user pressed 'return' and expects the previous expression to - // repeat). If the previous expression was a command, this string will be - // empty; if the previous expression was a variable expression, this string - // will contain that expression. + + /// This is used to allow request_evaluate to handle empty expressions + /// (ie the user pressed 'return' and expects the previous expression to + /// repeat). If the previous expression was a command, this string will be + /// empty; if the previous expression was a variable expression, this string + /// will contain that expression. std::string last_nonempty_var_expression; + /// The set of features supported by the connected client. llvm::DenseSet clientFeatures; @@ -257,8 +277,6 @@ struct DAP { /// Configures the debug adapter for launching/attaching. void SetConfiguration(const protocol::Configuration &confing, bool is_attach); - void SetConfigurationDone(); - /// Configure source maps based on the current `DAPConfiguration`. void ConfigureSourceMaps(); From lldb-commits at lists.llvm.org Sun May 18 10:23:05 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sun, 18 May 2025 10:23:05 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Member variable cleanup in DAP.{cpp, h} (NFC) (PR #140390) In-Reply-To: Message-ID: <682a1779.630a0220.2e7f2f.fca8@mx.google.com> https://github.com/JDevlieghere closed https://github.com/llvm/llvm-project/pull/140390 From lldb-commits at lists.llvm.org Sun May 18 10:57:17 2025 From: lldb-commits at lists.llvm.org (LLVM Continuous Integration via lldb-commits) Date: Sun, 18 May 2025 10:57:17 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Member variable cleanup in DAP.{cpp, h} (NFC) (PR #140390) In-Reply-To: Message-ID: <682a1f7d.a70a0220.2647b3.cb47@mx.google.com> llvm-ci wrote: LLVM Buildbot has detected a new failure on builder `lldb-remote-linux-win` running on `as-builder-10` while building `lldb` at step 17 "test-check-lldb-api". Full details are available at: https://lab.llvm.org/buildbot/#/builders/197/builds/5499
Here is the relevant piece of the build log for the reference ``` Step 17 (test-check-lldb-api) failure: Test just built components: check-lldb-api completed (failure) ******************** TEST 'lldb-api :: commands/source/info/TestSourceInfo.py' FAILED ******************** Script: -- C:/Python312/python.exe C:/buildbot/as-builder-10/lldb-x-aarch64/llvm-project/lldb\test\API\dotest.py -u CXXFLAGS -u CFLAGS --env LLVM_LIBS_DIR=C:/buildbot/as-builder-10/lldb-x-aarch64/build/./lib --env LLVM_INCLUDE_DIR=C:/buildbot/as-builder-10/lldb-x-aarch64/build/include --env LLVM_TOOLS_DIR=C:/buildbot/as-builder-10/lldb-x-aarch64/build/./bin --arch aarch64 --build-dir C:/buildbot/as-builder-10/lldb-x-aarch64/build/lldb-test-build.noindex --lldb-module-cache-dir C:/buildbot/as-builder-10/lldb-x-aarch64/build/lldb-test-build.noindex/module-cache-lldb\lldb-api --clang-module-cache-dir C:/buildbot/as-builder-10/lldb-x-aarch64/build/lldb-test-build.noindex/module-cache-clang\lldb-api --executable C:/buildbot/as-builder-10/lldb-x-aarch64/build/./bin/lldb.exe --compiler C:/buildbot/as-builder-10/lldb-x-aarch64/build/./bin/clang.exe --dsymutil C:/buildbot/as-builder-10/lldb-x-aarch64/build/./bin/dsymutil.exe --make C:/ninja/make.exe --llvm-tools-dir C:/buildbot/as-builder-10/lldb-x-aarch64/build/./bin --lldb-obj-root C:/buildbot/as-builder-10/lldb-x-aarch64/build/tools/lldb --lldb-libs-dir C:/buildbot/as-builder-10/lldb-x-aarch64/build/./lib --platform-url connect://jetson-agx-0086.lab.llvm.org:1234 --platform-working-dir /home/ubuntu/lldb-tests --sysroot c:/buildbot/fs/jetson-agx-ubuntu --env ARCH_CFLAGS=-mcpu=cortex-a78 --platform-name remote-linux --skip-category=lldb-server C:\buildbot\as-builder-10\lldb-x-aarch64\llvm-project\lldb\test\API\commands\source\info -p TestSourceInfo.py -- Exit Code: 3221226356 Command Output (stdout): -- lldb version 21.0.0git (https://github.com/llvm/llvm-project.git revision 5ab3c5215688f62dbc3707f0e9cc2e8b69c0a7f0) clang revision 5ab3c5215688f62dbc3707f0e9cc2e8b69c0a7f0 llvm revision 5ab3c5215688f62dbc3707f0e9cc2e8b69c0a7f0 Setting up remote platform 'remote-linux' Connecting to remote platform 'remote-linux' at 'connect://jetson-agx-0086.lab.llvm.org:1234'... Connected. Setting remote platform working directory to '/home/ubuntu/lldb-tests'... Skipping the following test categories: ['lldb-server', 'dsym', 'gmodules', 'debugserver', 'objc', 'lldb-dap'] -- Command Output (stderr): -- UNSUPPORTED: LLDB (C:\buildbot\as-builder-10\lldb-x-aarch64\build\bin\clang.exe-aarch64) :: test_dsym (lldbsuite.test.lldbtest.TestSourceInfo.test_dsym) (test case does not fall in any category of interest for this run) PASS: LLDB (C:\buildbot\as-builder-10\lldb-x-aarch64\build\bin\clang.exe-aarch64) :: test_dwarf (lldbsuite.test.lldbtest.TestSourceInfo.test_dwarf) PASS: LLDB (C:\buildbot\as-builder-10\lldb-x-aarch64\build\bin\clang.exe-aarch64) :: test_dwo (lldbsuite.test.lldbtest.TestSourceInfo.test_dwo) ---------------------------------------------------------------------- Ran 3 tests in 1.294s OK (skipped=1) Windows fatal exception: code 0xc0000374 Current thread 0x00003284 (most recent call first): -- ******************** ```
https://github.com/llvm/llvm-project/pull/140390 From lldb-commits at lists.llvm.org Sun May 18 10:57:20 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sun, 18 May 2025 10:57:20 -0700 (PDT) Subject: [Lldb-commits] [lldb] 3d0c616 - [lldb-dap] Move the Variables struct into its own file (#140393) Message-ID: <682a1f80.170a0220.e637b.f5dd@mx.google.com> Author: Jonas Devlieghere Date: 2025-05-18T10:57:16-07:00 New Revision: 3d0c616ce30cdc3d9c26dda8fdc608a6c85f00a6 URL: https://github.com/llvm/llvm-project/commit/3d0c616ce30cdc3d9c26dda8fdc608a6c85f00a6 DIFF: https://github.com/llvm/llvm-project/commit/3d0c616ce30cdc3d9c26dda8fdc608a6c85f00a6.diff LOG: [lldb-dap] Move the Variables struct into its own file (#140393) Move the Variables struct out of DAP.h and into its own file to reduce the complexity of the latter. This PR also makes the members that are implementation details private and adds a handful of basic unit tests. Added: lldb/tools/lldb-dap/Variables.cpp lldb/tools/lldb-dap/Variables.h lldb/unittests/DAP/VariablesTest.cpp Modified: lldb/tools/lldb-dap/CMakeLists.txt lldb/tools/lldb-dap/DAP.cpp lldb/tools/lldb-dap/DAP.h lldb/unittests/DAP/CMakeLists.txt Removed: ################################################################################ diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 5dedee8a87f41..f8e81eaff8606 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -23,6 +23,7 @@ add_lldb_library(lldbDAP RunInTerminal.cpp SourceBreakpoint.cpp Transport.cpp + Variables.cpp Watchpoint.cpp Handler/ResponseHandler.cpp diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index d813cdb0b9074..8868131622243 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1017,45 +1017,6 @@ lldb::SBError DAP::WaitForProcessToStop(std::chrono::seconds seconds) { return error; } -void Variables::Clear() { - locals.Clear(); - globals.Clear(); - registers.Clear(); - referenced_variables.clear(); -} - -int64_t Variables::GetNewVariableReference(bool is_permanent) { - if (is_permanent) - return next_permanent_var_ref++; - return next_temporary_var_ref++; -} - -bool Variables::IsPermanentVariableReference(int64_t var_ref) { - return var_ref >= PermanentVariableStartIndex; -} - -lldb::SBValue Variables::GetVariable(int64_t var_ref) const { - if (IsPermanentVariableReference(var_ref)) { - auto pos = referenced_permanent_variables.find(var_ref); - if (pos != referenced_permanent_variables.end()) - return pos->second; - } else { - auto pos = referenced_variables.find(var_ref); - if (pos != referenced_variables.end()) - return pos->second; - } - return lldb::SBValue(); -} - -int64_t Variables::InsertVariable(lldb::SBValue variable, bool is_permanent) { - int64_t var_ref = GetNewVariableReference(is_permanent); - if (is_permanent) - referenced_permanent_variables.insert(std::make_pair(var_ref, variable)); - else - referenced_variables.insert(std::make_pair(var_ref, variable)); - return var_ref; -} - bool StartDebuggingRequestHandler::DoExecute( lldb::SBDebugger debugger, char **command, lldb::SBCommandReturnObject &result) { @@ -1292,60 +1253,6 @@ DAP::GetInstructionBPFromStopReason(lldb::SBThread &thread) { return inst_bp; } -lldb::SBValueList *Variables::GetTopLevelScope(int64_t variablesReference) { - switch (variablesReference) { - case VARREF_LOCALS: - return &locals; - case VARREF_GLOBALS: - return &globals; - case VARREF_REGS: - return ®isters; - default: - return nullptr; - } -} - -lldb::SBValue Variables::FindVariable(uint64_t variablesReference, - llvm::StringRef name) { - lldb::SBValue variable; - if (lldb::SBValueList *top_scope = GetTopLevelScope(variablesReference)) { - bool is_duplicated_variable_name = name.contains(" @"); - // variablesReference is one of our scopes, not an actual variable it is - // asking for a variable in locals or globals or registers - int64_t end_idx = top_scope->GetSize(); - // Searching backward so that we choose the variable in closest scope - // among variables of the same name. - for (int64_t i = end_idx - 1; i >= 0; --i) { - lldb::SBValue curr_variable = top_scope->GetValueAtIndex(i); - std::string variable_name = CreateUniqueVariableNameForDisplay( - curr_variable, is_duplicated_variable_name); - if (variable_name == name) { - variable = curr_variable; - break; - } - } - } else { - // This is not under the globals or locals scope, so there are no - // duplicated names. - - // We have a named item within an actual variable so we need to find it - // withing the container variable by name. - lldb::SBValue container = GetVariable(variablesReference); - variable = container.GetChildMemberWithName(name.data()); - if (!variable.IsValid()) { - if (name.starts_with("[")) { - llvm::StringRef index_str(name.drop_front(1)); - uint64_t index = 0; - if (!index_str.consumeInteger(0, index)) { - if (index_str == "]") - variable = container.GetChildAtIndex(index); - } - } - } - } - return variable; -} - protocol::Capabilities DAP::GetCapabilities() { protocol::Capabilities capabilities; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 975e2b290e1f9..eafc92776fca7 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -20,6 +20,7 @@ #include "Protocol/ProtocolTypes.h" #include "SourceBreakpoint.h" #include "Transport.h" +#include "Variables.h" #include "lldb/API/SBBroadcaster.h" #include "lldb/API/SBCommandInterpreter.h" #include "lldb/API/SBDebugger.h" @@ -30,8 +31,6 @@ #include "lldb/API/SBMutex.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" -#include "lldb/API/SBValue.h" -#include "lldb/API/SBValueList.h" #include "lldb/lldb-types.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" @@ -52,10 +51,6 @@ #include #include -#define VARREF_LOCALS (int64_t)1 -#define VARREF_GLOBALS (int64_t)2 -#define VARREF_REGS (int64_t)3 -#define VARREF_FIRST_VAR_IDX (int64_t)4 #define NO_TYPENAME "" namespace lldb_dap { @@ -88,50 +83,6 @@ enum class PacketStatus { enum class ReplMode { Variable = 0, Command, Auto }; -struct Variables { - /// Variable_reference start index of permanent expandable variable. - static constexpr int64_t PermanentVariableStartIndex = (1ll << 32); - - lldb::SBValueList locals; - lldb::SBValueList globals; - lldb::SBValueList registers; - - int64_t next_temporary_var_ref{VARREF_FIRST_VAR_IDX}; - int64_t next_permanent_var_ref{PermanentVariableStartIndex}; - - /// Variables that are alive in this stop state. - /// Will be cleared when debuggee resumes. - llvm::DenseMap referenced_variables; - /// Variables that persist across entire debug session. - /// These are the variables evaluated from debug console REPL. - llvm::DenseMap referenced_permanent_variables; - - /// Check if \p var_ref points to a variable that should persist for the - /// entire duration of the debug session, e.g. repl expandable variables - static bool IsPermanentVariableReference(int64_t var_ref); - - /// \return a new variableReference. - /// Specify is_permanent as true for variable that should persist entire - /// debug session. - int64_t GetNewVariableReference(bool is_permanent); - - /// \return the expandable variable corresponding with variableReference - /// value of \p value. - /// If \p var_ref is invalid an empty SBValue is returned. - lldb::SBValue GetVariable(int64_t var_ref) const; - - /// Insert a new \p variable. - /// \return variableReference assigned to this expandable variable. - int64_t InsertVariable(lldb::SBValue variable, bool is_permanent); - - lldb::SBValueList *GetTopLevelScope(int64_t variablesReference); - - lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef name); - - /// Clear all scope variables and non-permanent expandable variables. - void Clear(); -}; - struct StartDebuggingRequestHandler : public lldb::SBCommandPluginInterface { DAP &dap; explicit StartDebuggingRequestHandler(DAP &d) : dap(d) {}; diff --git a/lldb/tools/lldb-dap/Variables.cpp b/lldb/tools/lldb-dap/Variables.cpp new file mode 100644 index 0000000000000..777e3183d8c0d --- /dev/null +++ b/lldb/tools/lldb-dap/Variables.cpp @@ -0,0 +1,105 @@ +//===-- Variables.cpp ---------------------------------------------------*-===// +// +// 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 "Variables.h" +#include "JSONUtils.h" + +using namespace lldb_dap; + +lldb::SBValueList *Variables::GetTopLevelScope(int64_t variablesReference) { + switch (variablesReference) { + case VARREF_LOCALS: + return &locals; + case VARREF_GLOBALS: + return &globals; + case VARREF_REGS: + return ®isters; + default: + return nullptr; + } +} + +void Variables::Clear() { + locals.Clear(); + globals.Clear(); + registers.Clear(); + m_referencedvariables.clear(); +} + +int64_t Variables::GetNewVariableReference(bool is_permanent) { + if (is_permanent) + return m_next_permanent_var_ref++; + return m_next_temporary_var_ref++; +} + +bool Variables::IsPermanentVariableReference(int64_t var_ref) { + return var_ref >= PermanentVariableStartIndex; +} + +lldb::SBValue Variables::GetVariable(int64_t var_ref) const { + if (IsPermanentVariableReference(var_ref)) { + auto pos = m_referencedpermanent_variables.find(var_ref); + if (pos != m_referencedpermanent_variables.end()) + return pos->second; + } else { + auto pos = m_referencedvariables.find(var_ref); + if (pos != m_referencedvariables.end()) + return pos->second; + } + return lldb::SBValue(); +} + +int64_t Variables::InsertVariable(lldb::SBValue variable, bool is_permanent) { + int64_t var_ref = GetNewVariableReference(is_permanent); + if (is_permanent) + m_referencedpermanent_variables.insert(std::make_pair(var_ref, variable)); + else + m_referencedvariables.insert(std::make_pair(var_ref, variable)); + return var_ref; +} + +lldb::SBValue Variables::FindVariable(uint64_t variablesReference, + llvm::StringRef name) { + lldb::SBValue variable; + if (lldb::SBValueList *top_scope = GetTopLevelScope(variablesReference)) { + bool is_duplicated_variable_name = name.contains(" @"); + // variablesReference is one of our scopes, not an actual variable it is + // asking for a variable in locals or globals or registers + int64_t end_idx = top_scope->GetSize(); + // Searching backward so that we choose the variable in closest scope + // among variables of the same name. + for (int64_t i = end_idx - 1; i >= 0; --i) { + lldb::SBValue curr_variable = top_scope->GetValueAtIndex(i); + std::string variable_name = CreateUniqueVariableNameForDisplay( + curr_variable, is_duplicated_variable_name); + if (variable_name == name) { + variable = curr_variable; + break; + } + } + } else { + // This is not under the globals or locals scope, so there are no + // duplicated names. + + // We have a named item within an actual variable so we need to find it + // withing the container variable by name. + lldb::SBValue container = GetVariable(variablesReference); + variable = container.GetChildMemberWithName(name.data()); + if (!variable.IsValid()) { + if (name.starts_with("[")) { + llvm::StringRef index_str(name.drop_front(1)); + uint64_t index = 0; + if (!index_str.consumeInteger(0, index)) { + if (index_str == "]") + variable = container.GetChildAtIndex(index); + } + } + } + } + return variable; +} diff --git a/lldb/tools/lldb-dap/Variables.h b/lldb/tools/lldb-dap/Variables.h new file mode 100644 index 0000000000000..0ed84b36aef99 --- /dev/null +++ b/lldb/tools/lldb-dap/Variables.h @@ -0,0 +1,71 @@ +//===-- Variables.h -----------------------------------------------------*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TOOLS_LLDB_DAP_VARIABLES_H +#define LLDB_TOOLS_LLDB_DAP_VARIABLES_H + +#include "lldb/API/SBValue.h" +#include "lldb/API/SBValueList.h" +#include "llvm/ADT/DenseMap.h" + +#define VARREF_FIRST_VAR_IDX (int64_t)4 +#define VARREF_LOCALS (int64_t)1 +#define VARREF_GLOBALS (int64_t)2 +#define VARREF_REGS (int64_t)3 + +namespace lldb_dap { + +struct Variables { + lldb::SBValueList locals; + lldb::SBValueList globals; + lldb::SBValueList registers; + + /// Check if \p var_ref points to a variable that should persist for the + /// entire duration of the debug session, e.g. repl expandable variables + static bool IsPermanentVariableReference(int64_t var_ref); + + /// \return a new variableReference. + /// Specify is_permanent as true for variable that should persist entire + /// debug session. + int64_t GetNewVariableReference(bool is_permanent); + + /// \return the expandable variable corresponding with variableReference + /// value of \p value. + /// If \p var_ref is invalid an empty SBValue is returned. + lldb::SBValue GetVariable(int64_t var_ref) const; + + /// Insert a new \p variable. + /// \return variableReference assigned to this expandable variable. + int64_t InsertVariable(lldb::SBValue variable, bool is_permanent); + + lldb::SBValueList *GetTopLevelScope(int64_t variablesReference); + + lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef name); + + /// Clear all scope variables and non-permanent expandable variables. + void Clear(); + +private: + /// Variable_reference start index of permanent expandable variable. + static constexpr int64_t PermanentVariableStartIndex = (1ll << 32); + + /// Variables that are alive in this stop state. + /// Will be cleared when debuggee resumes. + llvm::DenseMap m_referencedvariables; + + /// Variables that persist across entire debug session. + /// These are the variables evaluated from debug console REPL. + llvm::DenseMap m_referencedpermanent_variables; + + int64_t m_next_temporary_var_ref{VARREF_FIRST_VAR_IDX}; + int64_t m_next_permanent_var_ref{PermanentVariableStartIndex}; +}; + +} // namespace lldb_dap + +#endif diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index af7d11e2e95e2..429a12e9fb505 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -6,6 +6,7 @@ add_lldb_unittest(DAPTests ProtocolTypesTest.cpp TestBase.cpp TransportTest.cpp + VariablesTest.cpp LINK_LIBS lldbDAP diff --git a/lldb/unittests/DAP/VariablesTest.cpp b/lldb/unittests/DAP/VariablesTest.cpp new file mode 100644 index 0000000000000..6b14fc6c3945d --- /dev/null +++ b/lldb/unittests/DAP/VariablesTest.cpp @@ -0,0 +1,85 @@ +//===-- VariablesTest.cpp -------------------------------------------------===// +// +// 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 "Variables.h" +#include "lldb/API/SBValue.h" +#include "lldb/API/SBValueList.h" +#include "gtest/gtest.h" + +using namespace lldb_dap; + +class VariablesTest : public ::testing::Test { +protected: + enum : bool { Permanent = true, Temporary = false }; + Variables vars; +}; + +TEST_F(VariablesTest, GetNewVariableReference_UniqueAndRanges) { + const int64_t temp1 = vars.GetNewVariableReference(Temporary); + const int64_t temp2 = vars.GetNewVariableReference(Temporary); + const int64_t perm1 = vars.GetNewVariableReference(Permanent); + const int64_t perm2 = vars.GetNewVariableReference(Permanent); + + EXPECT_NE(temp1, temp2); + EXPECT_NE(perm1, perm2); + EXPECT_LT(temp1, perm1); + EXPECT_LT(temp2, perm1); +} + +TEST_F(VariablesTest, InsertAndGetVariable_Temporary) { + lldb::SBValue dummy; + const int64_t ref = vars.InsertVariable(dummy, Temporary); + lldb::SBValue out = vars.GetVariable(ref); + + EXPECT_EQ(out.IsValid(), dummy.IsValid()); +} + +TEST_F(VariablesTest, InsertAndGetVariable_Permanent) { + lldb::SBValue dummy; + const int64_t ref = vars.InsertVariable(dummy, Permanent); + lldb::SBValue out = vars.GetVariable(ref); + + EXPECT_EQ(out.IsValid(), dummy.IsValid()); +} + +TEST_F(VariablesTest, IsPermanentVariableReference) { + const int64_t perm = vars.GetNewVariableReference(Permanent); + const int64_t temp = vars.GetNewVariableReference(Temporary); + + EXPECT_TRUE(Variables::IsPermanentVariableReference(perm)); + EXPECT_FALSE(Variables::IsPermanentVariableReference(temp)); +} + +TEST_F(VariablesTest, Clear_RemovesTemporaryKeepsPermanent) { + lldb::SBValue dummy; + const int64_t temp = vars.InsertVariable(dummy, Temporary); + const int64_t perm = vars.InsertVariable(dummy, Permanent); + vars.Clear(); + + EXPECT_FALSE(vars.GetVariable(temp).IsValid()); + EXPECT_EQ(vars.GetVariable(perm).IsValid(), dummy.IsValid()); +} + +TEST_F(VariablesTest, GetTopLevelScope_ReturnsCorrectScope) { + vars.locals.Append(lldb::SBValue()); + vars.globals.Append(lldb::SBValue()); + vars.registers.Append(lldb::SBValue()); + + EXPECT_EQ(vars.GetTopLevelScope(VARREF_LOCALS), &vars.locals); + EXPECT_EQ(vars.GetTopLevelScope(VARREF_GLOBALS), &vars.globals); + EXPECT_EQ(vars.GetTopLevelScope(VARREF_REGS), &vars.registers); + EXPECT_EQ(vars.GetTopLevelScope(9999), nullptr); +} + +TEST_F(VariablesTest, FindVariable_LocalsByName) { + lldb::SBValue dummy; + vars.locals.Append(dummy); + lldb::SBValue found = vars.FindVariable(VARREF_LOCALS, ""); + + EXPECT_EQ(found.IsValid(), dummy.IsValid()); +} From lldb-commits at lists.llvm.org Sun May 18 10:57:23 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sun, 18 May 2025 10:57:23 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Move the Variables struct into its own file (PR #140393) In-Reply-To: Message-ID: <682a1f83.170a0220.375e3d.b28c@mx.google.com> https://github.com/JDevlieghere closed https://github.com/llvm/llvm-project/pull/140393 From lldb-commits at lists.llvm.org Sun May 18 11:04:22 2025 From: lldb-commits at lists.llvm.org (Kazu Hirata via lldb-commits) Date: Sun, 18 May 2025 11:04:22 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use llvm::is_contained (NFC) (PR #140466) Message-ID: https://github.com/kazutakahirata created https://github.com/llvm/llvm-project/pull/140466 None >From 71e7fe5e2898b6ccaef56622515f7e7f8eca005d Mon Sep 17 00:00:00 2001 From: Kazu Hirata Date: Sun, 18 May 2025 10:39:39 -0700 Subject: [PATCH] [lldb] Use llvm::is_contained (NFC) --- lldb/source/Expression/FunctionCaller.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lldb/source/Expression/FunctionCaller.cpp b/lldb/source/Expression/FunctionCaller.cpp index ddf1e1151bdcf..83cac130ba728 100644 --- a/lldb/source/Expression/FunctionCaller.cpp +++ b/lldb/source/Expression/FunctionCaller.cpp @@ -171,10 +171,8 @@ bool FunctionCaller::WriteFunctionArguments( m_wrapper_args_addrs.push_back(args_addr_ref); } else { // Make sure this is an address that we've already handed out. - if (find(m_wrapper_args_addrs.begin(), m_wrapper_args_addrs.end(), - args_addr_ref) == m_wrapper_args_addrs.end()) { + if (!llvm::is_contained(m_wrapper_args_addrs, args_addr_ref)) return false; - } } // TODO: verify fun_addr needs to be a callable address From lldb-commits at lists.llvm.org Sun May 18 11:04:55 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sun, 18 May 2025 11:04:55 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Use llvm::is_contained (NFC) (PR #140466) In-Reply-To: Message-ID: <682a2147.630a0220.ac96c.fe30@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Kazu Hirata (kazutakahirata)
Changes --- Full diff: https://github.com/llvm/llvm-project/pull/140466.diff 1 Files Affected: - (modified) lldb/source/Expression/FunctionCaller.cpp (+1-3) ``````````diff diff --git a/lldb/source/Expression/FunctionCaller.cpp b/lldb/source/Expression/FunctionCaller.cpp index ddf1e1151bdcf..83cac130ba728 100644 --- a/lldb/source/Expression/FunctionCaller.cpp +++ b/lldb/source/Expression/FunctionCaller.cpp @@ -171,10 +171,8 @@ bool FunctionCaller::WriteFunctionArguments( m_wrapper_args_addrs.push_back(args_addr_ref); } else { // Make sure this is an address that we've already handed out. - if (find(m_wrapper_args_addrs.begin(), m_wrapper_args_addrs.end(), - args_addr_ref) == m_wrapper_args_addrs.end()) { + if (!llvm::is_contained(m_wrapper_args_addrs, args_addr_ref)) return false; - } } // TODO: verify fun_addr needs to be a callable address ``````````
https://github.com/llvm/llvm-project/pull/140466 From lldb-commits at lists.llvm.org Sun May 18 11:21:07 2025 From: lldb-commits at lists.llvm.org (LLVM Continuous Integration via lldb-commits) Date: Sun, 18 May 2025 11:21:07 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Move the Variables struct into its own file (PR #140393) In-Reply-To: Message-ID: <682a2513.170a0220.2daa01.aff1@mx.google.com> llvm-ci wrote: LLVM Buildbot has detected a new failure on builder `fuchsia-x86_64-linux` running on `fuchsia-debian-64-us-central1-b-1` while building `lldb` at step 4 "annotate". Full details are available at: https://lab.llvm.org/buildbot/#/builders/11/builds/15391
Here is the relevant piece of the build log for the reference ``` Step 4 (annotate) failure: 'python ../llvm-zorg/zorg/buildbot/builders/annotated/fuchsia-linux.py ...' (failure) ... Passed : 46002 (97.93%) Expectedly Failed: 27 (0.06%) [1368/1370] Linking CXX executable unittests/Transforms/Scalar/ScalarTests [1369/1370] Running the LLVM regression tests llvm-lit: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/utils/lit/lit/llvm/config.py:520: note: using ld.lld: /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/ld.lld llvm-lit: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/utils/lit/lit/llvm/config.py:520: note: using lld-link: /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/lld-link llvm-lit: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/utils/lit/lit/llvm/config.py:520: note: using ld64.lld: /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/ld64.lld llvm-lit: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/utils/lit/lit/llvm/config.py:520: note: using wasm-ld: /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/wasm-ld -- Testing: 59199 tests, 60 workers -- Testing: 0.. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. FAIL: LLVM :: tools/dsymutil/X86/op-convert-offset.test (52159 of 59199) ******************** TEST 'LLVM :: tools/dsymutil/X86/op-convert-offset.test' FAILED ******************** Exit Code: 1 Command Output (stdout): -- warning: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o: timestamp mismatch between object file (2025-05-18 18:00:42.117291764) and debug map (2022-07-12 20:49:30.000000000) warning: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o: timestamp mismatch between object file (2025-05-18 18:00:42.117291764) and debug map (2022-07-12 20:49:30.000000000) warning: cann't read address attribute value. note: while processing op-convert-offset1.c -- Command Output (stderr): -- /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/dsymutil -oso-prepend-path /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset -o /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/test/tools/dsymutil/X86/Output/op-convert-offset.test.tmp.dSYM 2>&1 # RUN: at line 23 + /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/dsymutil -oso-prepend-path /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset -o /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/test/tools/dsymutil/X86/Output/op-convert-offset.test.tmp.dSYM /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/llvm-dwarfdump /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o 2>&1 | /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/FileCheck /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/op-convert-offset.test --check-prefix OBJ # RUN: at line 24 + /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/FileCheck /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/op-convert-offset.test --check-prefix OBJ + /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/llvm-dwarfdump /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/llvm-dwarfdump /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/test/tools/dsymutil/X86/Output/op-convert-offset.test.tmp.dSYM 2>&1 | /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/FileCheck /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/op-convert-offset.test --check-prefix DSYM # RUN: at line 25 + /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/llvm-dwarfdump /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/test/tools/dsymutil/X86/Output/op-convert-offset.test.tmp.dSYM + /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/FileCheck /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/op-convert-offset.test --check-prefix DSYM /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/dsymutil --linker parallel -oso-prepend-path /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset -o /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/test/tools/dsymutil/X86/Output/op-convert-offset.test.tmp.dSYM 2>&1 # RUN: at line 27 + /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/dsymutil --linker parallel -oso-prepend-path /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset -o /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/test/tools/dsymutil/X86/Output/op-convert-offset.test.tmp.dSYM /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/llvm-dwarfdump /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o 2>&1 | /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/FileCheck /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/op-convert-offset.test --check-prefix OBJ # RUN: at line 30 + /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/llvm-dwarfdump /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o + /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/FileCheck /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/op-convert-offset.test --check-prefix OBJ /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/llvm-dwarfdump /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/test/tools/dsymutil/X86/Output/op-convert-offset.test.tmp.dSYM 2>&1 | /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/FileCheck /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/op-convert-offset.test --check-prefix DSYM # RUN: at line 33 + /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/llvm-dwarfdump /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/test/tools/dsymutil/X86/Output/op-convert-offset.test.tmp.dSYM + /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/FileCheck /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/op-convert-offset.test --check-prefix DSYM /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/op-convert-offset.test:45:7: error: DSYM: expected string not found in input DSYM: 0x00000084: DW_TAG_base_type ^ :1:1: note: scanning from here /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/test/tools/dsymutil/X86/Output/op-convert-offset.test.tmp.dSYM/Contents/Resources/DWARF/op-convert-offset: file format Mach-O 64-bit x86-64 ^ :16:1: note: possible intended match here 0x0000001e: DW_TAG_base_type ^ Step 7 (check) failure: check (failure) ... Passed : 46002 (97.93%) Expectedly Failed: 27 (0.06%) [1368/1370] Linking CXX executable unittests/Transforms/Scalar/ScalarTests [1369/1370] Running the LLVM regression tests llvm-lit: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/utils/lit/lit/llvm/config.py:520: note: using ld.lld: /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/ld.lld llvm-lit: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/utils/lit/lit/llvm/config.py:520: note: using lld-link: /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/lld-link llvm-lit: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/utils/lit/lit/llvm/config.py:520: note: using ld64.lld: /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/ld64.lld llvm-lit: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/utils/lit/lit/llvm/config.py:520: note: using wasm-ld: /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/wasm-ld -- Testing: 59199 tests, 60 workers -- Testing: 0.. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. FAIL: LLVM :: tools/dsymutil/X86/op-convert-offset.test (52159 of 59199) ******************** TEST 'LLVM :: tools/dsymutil/X86/op-convert-offset.test' FAILED ******************** Exit Code: 1 Command Output (stdout): -- warning: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o: timestamp mismatch between object file (2025-05-18 18:00:42.117291764) and debug map (2022-07-12 20:49:30.000000000) warning: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o: timestamp mismatch between object file (2025-05-18 18:00:42.117291764) and debug map (2022-07-12 20:49:30.000000000) warning: cann't read address attribute value. note: while processing op-convert-offset1.c -- Command Output (stderr): -- /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/dsymutil -oso-prepend-path /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset -o /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/test/tools/dsymutil/X86/Output/op-convert-offset.test.tmp.dSYM 2>&1 # RUN: at line 23 + /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/dsymutil -oso-prepend-path /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset -o /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/test/tools/dsymutil/X86/Output/op-convert-offset.test.tmp.dSYM /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/llvm-dwarfdump /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o 2>&1 | /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/FileCheck /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/op-convert-offset.test --check-prefix OBJ # RUN: at line 24 + /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/FileCheck /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/op-convert-offset.test --check-prefix OBJ + /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/llvm-dwarfdump /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/llvm-dwarfdump /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/test/tools/dsymutil/X86/Output/op-convert-offset.test.tmp.dSYM 2>&1 | /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/FileCheck /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/op-convert-offset.test --check-prefix DSYM # RUN: at line 25 + /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/llvm-dwarfdump /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/test/tools/dsymutil/X86/Output/op-convert-offset.test.tmp.dSYM + /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/FileCheck /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/op-convert-offset.test --check-prefix DSYM /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/dsymutil --linker parallel -oso-prepend-path /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset -o /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/test/tools/dsymutil/X86/Output/op-convert-offset.test.tmp.dSYM 2>&1 # RUN: at line 27 + /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/dsymutil --linker parallel -oso-prepend-path /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset -o /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/test/tools/dsymutil/X86/Output/op-convert-offset.test.tmp.dSYM /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/llvm-dwarfdump /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o 2>&1 | /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/FileCheck /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/op-convert-offset.test --check-prefix OBJ # RUN: at line 30 + /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/llvm-dwarfdump /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o + /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/FileCheck /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/op-convert-offset.test --check-prefix OBJ /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/llvm-dwarfdump /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/test/tools/dsymutil/X86/Output/op-convert-offset.test.tmp.dSYM 2>&1 | /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/FileCheck /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/op-convert-offset.test --check-prefix DSYM # RUN: at line 33 + /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/llvm-dwarfdump /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/test/tools/dsymutil/X86/Output/op-convert-offset.test.tmp.dSYM + /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/bin/FileCheck /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/op-convert-offset.test --check-prefix DSYM /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/test/tools/dsymutil/X86/op-convert-offset.test:45:7: error: DSYM: expected string not found in input DSYM: 0x00000084: DW_TAG_base_type ^ :1:1: note: scanning from here /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-vw417js_/test/tools/dsymutil/X86/Output/op-convert-offset.test.tmp.dSYM/Contents/Resources/DWARF/op-convert-offset: file format Mach-O 64-bit x86-64 ^ :16:1: note: possible intended match here 0x0000001e: DW_TAG_base_type ^ ```
https://github.com/llvm/llvm-project/pull/140393 From lldb-commits at lists.llvm.org Sun May 18 12:01:03 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 12:01:03 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Synchronously wait for breakpoints resolves in tests (PR #140470) Message-ID: https://github.com/eronnen created https://github.com/llvm/llvm-project/pull/140470 Attempt to improve tests by synchronously waiting for breakpoints to resolve. Not sure if it will fix all the tests but I think it should make the tests more stable >From 0bb463172bdabe20e08f743107906bce424c4b4c Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 20:56:47 +0200 Subject: [PATCH] [lldb-dap] Attempt to synchronously wait for breakpoints resolve in lldb-dap tests in order to stabilize the tests --- .../test/tools/lldb-dap/dap_server.py | 6 +++-- .../test/tools/lldb-dap/lldbdap_testcase.py | 26 +++++++++++++++++-- .../breakpoint/TestDAP_setBreakpoints.py | 1 - .../TestDAP_setFunctionBreakpoints.py | 1 - .../tools/lldb-dap/module/TestDAP_module.py | 4 ++- .../TestDAP_terminatedEvent.py | 4 ++- ...TestGetTargetBreakpointsRequestHandler.cpp | 10 +++++-- 7 files changed, 42 insertions(+), 10 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index 70fd0b0c419db..1b63ec77abba6 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -1187,7 +1187,7 @@ def request_locations(self, locationReference): } return self.send_recv(command_dict) - def request_testGetTargetBreakpoints(self): + def request_testGetTargetBreakpoints(self, only_resolved=False): """A request packet used in the LLDB test suite to get all currently set breakpoint infos for all breakpoints currently set in the target. @@ -1195,7 +1195,9 @@ def request_testGetTargetBreakpoints(self): command_dict = { "command": "_testGetTargetBreakpoints", "type": "request", - "arguments": {}, + "arguments": { + "onlyResolved": only_resolved, + }, } return self.send_recv(command_dict) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index afdc746ed0d0d..cc45811bd5f27 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -48,7 +48,7 @@ def build_and_create_debug_adapter_for_attach(self): self.build_and_create_debug_adapter(dictionary={"EXE": unique_name}) return self.getBuildArtifact(unique_name) - def set_source_breakpoints(self, source_path, lines, data=None): + def set_source_breakpoints(self, source_path, lines, data=None, wait_for_resolve=True): """Sets source breakpoints and returns an array of strings containing the breakpoint IDs ("1", "2") for each breakpoint that was set. Parameter data is array of data objects for breakpoints. @@ -62,9 +62,11 @@ def set_source_breakpoints(self, source_path, lines, data=None): breakpoint_ids = [] for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) + if wait_for_resolve: + self.wait_for_breakpoints_to_resolve(breakpoint_ids, timeout=10) return breakpoint_ids - def set_function_breakpoints(self, functions, condition=None, hitCondition=None): + def set_function_breakpoints(self, functions, condition=None, hitCondition=None, wait_for_resolve=True): """Sets breakpoints by function name given an array of function names and returns an array of strings containing the breakpoint IDs ("1", "2") for each breakpoint that was set. @@ -78,7 +80,27 @@ def set_function_breakpoints(self, functions, condition=None, hitCondition=None) breakpoint_ids = [] for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) + if wait_for_resolve: + self.wait_for_breakpoints_to_resolve(breakpoint_ids, timeout=10) return breakpoint_ids + + def wait_for_breakpoints_to_resolve(self, breakpoint_ids: list[str], timeout: Optional[float] = None): + unresolved_breakpoints = set(breakpoint_ids) + + # Check already resolved breakpoints + resolved_breakpoints = self.dap_server.request_testGetTargetBreakpoints(only_resolved=True)["body"]["breakpoints"] + for resolved_breakpoint in resolved_breakpoints: + unresolved_breakpoints.discard(str(resolved_breakpoint["id"])) + + while len(unresolved_breakpoints) > 0: + breakpoint_event = self.dap_server.wait_for_event("breakpoint", timeout=timeout) + if breakpoint_event is None: + break + + if breakpoint_event["body"]["reason"] in ["changed", "new"]: + unresolved_breakpoints.discard(str(breakpoint_event["body"]["breakpoint"]["id"])) + + self.assertEqual(len(unresolved_breakpoints), 0, f"Expected to resolve all breakpoints. Unresolved breakpoint ids: {unresolved_breakpoints}") def waitUntil(self, condition_callback): for _ in range(20): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index aae1251b17c93..26df2573555df 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,7 +12,6 @@ import os - at skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index baaca4d974d5d..946595f639edc 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): diff --git a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py index 3fc0f752ee39e..2cea2a94adbbd 100644 --- a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py +++ b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py @@ -16,7 +16,9 @@ def run_test(self, symbol_basename, expect_debug_info_size): program = self.getBuildArtifact(program_basename) self.build_and_launch(program) functions = ["foo"] - breakpoint_ids = self.set_function_breakpoints(functions) + + # This breakpoint will be resolved only when the libfoo module is loaded + breakpoint_ids = self.set_function_breakpoints(functions, wait_for_resolve=False) self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint") self.continue_to_breakpoints(breakpoint_ids) active_modules = self.dap_server.get_modules() diff --git a/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py b/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py index b0abe2a38dac4..1622fb2d14de2 100644 --- a/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py +++ b/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py @@ -35,7 +35,9 @@ def test_terminated_event(self): self.build_and_launch(program) # Set breakpoints functions = ["foo"] - breakpoint_ids = self.set_function_breakpoints(functions) + + # This breakpoint will be resolved only when the libfoo module is loaded + breakpoint_ids = self.set_function_breakpoints(functions, wait_for_resolve=False) self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint") main_bp_line = line_number("main.cpp", "// main breakpoint 1") breakpoint_ids.append(self.set_source_breakpoints("main.cpp", [main_bp_line])) diff --git a/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp index 5f4f016f6a1ef..129eb31b8356b 100644 --- a/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp @@ -15,12 +15,18 @@ namespace lldb_dap { void TestGetTargetBreakpointsRequestHandler::operator()( const llvm::json::Object &request) const { + const auto *arguments = request.getObject("arguments"); + bool only_resolved = GetBoolean(arguments, "onlyResolved").value_or(false); + llvm::json::Object response; FillResponse(request, response); llvm::json::Array response_breakpoints; for (uint32_t i = 0; dap.target.GetBreakpointAtIndex(i).IsValid(); ++i) { - auto bp = Breakpoint(dap, dap.target.GetBreakpointAtIndex(i)); - response_breakpoints.push_back(bp.ToProtocolBreakpoint()); + const auto target_bp = dap.target.GetBreakpointAtIndex(i); + if (!only_resolved || target_bp.GetNumResolvedLocations() > 0) { + auto bp = Breakpoint(dap, target_bp); + response_breakpoints.push_back(bp.ToProtocolBreakpoint()); + } } llvm::json::Object body; body.try_emplace("breakpoints", std::move(response_breakpoints)); From lldb-commits at lists.llvm.org Sun May 18 12:01:32 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sun, 18 May 2025 12:01:32 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Synchronously wait for breakpoints resolves in tests (PR #140470) In-Reply-To: Message-ID: <682a2e8c.170a0220.4321e.d766@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Ely Ronnen (eronnen)
Changes Attempt to improve tests by synchronously waiting for breakpoints to resolve. Not sure if it will fix all the tests but I think it should make the tests more stable --- Full diff: https://github.com/llvm/llvm-project/pull/140470.diff 7 Files Affected: - (modified) lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py (+4-2) - (modified) lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py (+24-2) - (modified) lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py (-1) - (modified) lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py (-1) - (modified) lldb/test/API/tools/lldb-dap/module/TestDAP_module.py (+3-1) - (modified) lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py (+3-1) - (modified) lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp (+8-2) ``````````diff diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index 70fd0b0c419db..1b63ec77abba6 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -1187,7 +1187,7 @@ def request_locations(self, locationReference): } return self.send_recv(command_dict) - def request_testGetTargetBreakpoints(self): + def request_testGetTargetBreakpoints(self, only_resolved=False): """A request packet used in the LLDB test suite to get all currently set breakpoint infos for all breakpoints currently set in the target. @@ -1195,7 +1195,9 @@ def request_testGetTargetBreakpoints(self): command_dict = { "command": "_testGetTargetBreakpoints", "type": "request", - "arguments": {}, + "arguments": { + "onlyResolved": only_resolved, + }, } return self.send_recv(command_dict) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index afdc746ed0d0d..cc45811bd5f27 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -48,7 +48,7 @@ def build_and_create_debug_adapter_for_attach(self): self.build_and_create_debug_adapter(dictionary={"EXE": unique_name}) return self.getBuildArtifact(unique_name) - def set_source_breakpoints(self, source_path, lines, data=None): + def set_source_breakpoints(self, source_path, lines, data=None, wait_for_resolve=True): """Sets source breakpoints and returns an array of strings containing the breakpoint IDs ("1", "2") for each breakpoint that was set. Parameter data is array of data objects for breakpoints. @@ -62,9 +62,11 @@ def set_source_breakpoints(self, source_path, lines, data=None): breakpoint_ids = [] for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) + if wait_for_resolve: + self.wait_for_breakpoints_to_resolve(breakpoint_ids, timeout=10) return breakpoint_ids - def set_function_breakpoints(self, functions, condition=None, hitCondition=None): + def set_function_breakpoints(self, functions, condition=None, hitCondition=None, wait_for_resolve=True): """Sets breakpoints by function name given an array of function names and returns an array of strings containing the breakpoint IDs ("1", "2") for each breakpoint that was set. @@ -78,7 +80,27 @@ def set_function_breakpoints(self, functions, condition=None, hitCondition=None) breakpoint_ids = [] for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) + if wait_for_resolve: + self.wait_for_breakpoints_to_resolve(breakpoint_ids, timeout=10) return breakpoint_ids + + def wait_for_breakpoints_to_resolve(self, breakpoint_ids: list[str], timeout: Optional[float] = None): + unresolved_breakpoints = set(breakpoint_ids) + + # Check already resolved breakpoints + resolved_breakpoints = self.dap_server.request_testGetTargetBreakpoints(only_resolved=True)["body"]["breakpoints"] + for resolved_breakpoint in resolved_breakpoints: + unresolved_breakpoints.discard(str(resolved_breakpoint["id"])) + + while len(unresolved_breakpoints) > 0: + breakpoint_event = self.dap_server.wait_for_event("breakpoint", timeout=timeout) + if breakpoint_event is None: + break + + if breakpoint_event["body"]["reason"] in ["changed", "new"]: + unresolved_breakpoints.discard(str(breakpoint_event["body"]["breakpoint"]["id"])) + + self.assertEqual(len(unresolved_breakpoints), 0, f"Expected to resolve all breakpoints. Unresolved breakpoint ids: {unresolved_breakpoints}") def waitUntil(self, condition_callback): for _ in range(20): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index aae1251b17c93..26df2573555df 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,7 +12,6 @@ import os - at skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index baaca4d974d5d..946595f639edc 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): diff --git a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py index 3fc0f752ee39e..2cea2a94adbbd 100644 --- a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py +++ b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py @@ -16,7 +16,9 @@ def run_test(self, symbol_basename, expect_debug_info_size): program = self.getBuildArtifact(program_basename) self.build_and_launch(program) functions = ["foo"] - breakpoint_ids = self.set_function_breakpoints(functions) + + # This breakpoint will be resolved only when the libfoo module is loaded + breakpoint_ids = self.set_function_breakpoints(functions, wait_for_resolve=False) self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint") self.continue_to_breakpoints(breakpoint_ids) active_modules = self.dap_server.get_modules() diff --git a/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py b/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py index b0abe2a38dac4..1622fb2d14de2 100644 --- a/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py +++ b/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py @@ -35,7 +35,9 @@ def test_terminated_event(self): self.build_and_launch(program) # Set breakpoints functions = ["foo"] - breakpoint_ids = self.set_function_breakpoints(functions) + + # This breakpoint will be resolved only when the libfoo module is loaded + breakpoint_ids = self.set_function_breakpoints(functions, wait_for_resolve=False) self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint") main_bp_line = line_number("main.cpp", "// main breakpoint 1") breakpoint_ids.append(self.set_source_breakpoints("main.cpp", [main_bp_line])) diff --git a/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp index 5f4f016f6a1ef..129eb31b8356b 100644 --- a/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp @@ -15,12 +15,18 @@ namespace lldb_dap { void TestGetTargetBreakpointsRequestHandler::operator()( const llvm::json::Object &request) const { + const auto *arguments = request.getObject("arguments"); + bool only_resolved = GetBoolean(arguments, "onlyResolved").value_or(false); + llvm::json::Object response; FillResponse(request, response); llvm::json::Array response_breakpoints; for (uint32_t i = 0; dap.target.GetBreakpointAtIndex(i).IsValid(); ++i) { - auto bp = Breakpoint(dap, dap.target.GetBreakpointAtIndex(i)); - response_breakpoints.push_back(bp.ToProtocolBreakpoint()); + const auto target_bp = dap.target.GetBreakpointAtIndex(i); + if (!only_resolved || target_bp.GetNumResolvedLocations() > 0) { + auto bp = Breakpoint(dap, target_bp); + response_breakpoints.push_back(bp.ToProtocolBreakpoint()); + } } llvm::json::Object body; body.try_emplace("breakpoints", std::move(response_breakpoints)); ``````````
https://github.com/llvm/llvm-project/pull/140470 From lldb-commits at lists.llvm.org Sun May 18 12:03:17 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sun, 18 May 2025 12:03:17 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Synchronously wait for breakpoints resolves in tests (PR #140470) In-Reply-To: Message-ID: <682a2ef5.170a0220.1df4f4.b4cf@mx.google.com> github-actions[bot] wrote: :warning: Python code formatter, darker found issues in your code. :warning:
You can test this locally with the following command: ``````````bash darker --check --diff -r HEAD~1...HEAD lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py lldb/test/API/tools/lldb-dap/module/TestDAP_module.py lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py ``````````
View the diff from darker here. ``````````diff --- packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py 2025-05-18 18:56:47.000000 +0000 +++ packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py 2025-05-18 19:02:49.174312 +0000 @@ -46,11 +46,13 @@ named binary.""" unique_name = str(uuid.uuid4()) self.build_and_create_debug_adapter(dictionary={"EXE": unique_name}) return self.getBuildArtifact(unique_name) - def set_source_breakpoints(self, source_path, lines, data=None, wait_for_resolve=True): + def set_source_breakpoints( + self, source_path, lines, data=None, wait_for_resolve=True + ): """Sets source breakpoints and returns an array of strings containing the breakpoint IDs ("1", "2") for each breakpoint that was set. Parameter data is array of data objects for breakpoints. Each object in data is 1:1 mapping with the entry in lines. It contains optional location/hitCondition/logMessage parameters. @@ -64,11 +66,13 @@ breakpoint_ids.append("%i" % (breakpoint["id"])) if wait_for_resolve: self.wait_for_breakpoints_to_resolve(breakpoint_ids, timeout=10) return breakpoint_ids - def set_function_breakpoints(self, functions, condition=None, hitCondition=None, wait_for_resolve=True): + def set_function_breakpoints( + self, functions, condition=None, hitCondition=None, wait_for_resolve=True + ): """Sets breakpoints by function name given an array of function names and returns an array of strings containing the breakpoint IDs ("1", "2") for each breakpoint that was set. """ response = self.dap_server.request_setFunctionBreakpoints( @@ -81,28 +85,40 @@ for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) if wait_for_resolve: self.wait_for_breakpoints_to_resolve(breakpoint_ids, timeout=10) return breakpoint_ids - - def wait_for_breakpoints_to_resolve(self, breakpoint_ids: list[str], timeout: Optional[float] = None): + + def wait_for_breakpoints_to_resolve( + self, breakpoint_ids: list[str], timeout: Optional[float] = None + ): unresolved_breakpoints = set(breakpoint_ids) - + # Check already resolved breakpoints - resolved_breakpoints = self.dap_server.request_testGetTargetBreakpoints(only_resolved=True)["body"]["breakpoints"] + resolved_breakpoints = self.dap_server.request_testGetTargetBreakpoints( + only_resolved=True + )["body"]["breakpoints"] for resolved_breakpoint in resolved_breakpoints: unresolved_breakpoints.discard(str(resolved_breakpoint["id"])) while len(unresolved_breakpoints) > 0: - breakpoint_event = self.dap_server.wait_for_event("breakpoint", timeout=timeout) + breakpoint_event = self.dap_server.wait_for_event( + "breakpoint", timeout=timeout + ) if breakpoint_event is None: break if breakpoint_event["body"]["reason"] in ["changed", "new"]: - unresolved_breakpoints.discard(str(breakpoint_event["body"]["breakpoint"]["id"])) - - self.assertEqual(len(unresolved_breakpoints), 0, f"Expected to resolve all breakpoints. Unresolved breakpoint ids: {unresolved_breakpoints}") + unresolved_breakpoints.discard( + str(breakpoint_event["body"]["breakpoint"]["id"]) + ) + + self.assertEqual( + len(unresolved_breakpoints), + 0, + f"Expected to resolve all breakpoints. Unresolved breakpoint ids: {unresolved_breakpoints}", + ) def waitUntil(self, condition_callback): for _ in range(20): if condition_callback(): return True --- test/API/tools/lldb-dap/module/TestDAP_module.py 2025-05-18 18:56:47.000000 +0000 +++ test/API/tools/lldb-dap/module/TestDAP_module.py 2025-05-18 19:02:49.351547 +0000 @@ -14,13 +14,15 @@ def run_test(self, symbol_basename, expect_debug_info_size): program_basename = "a.out.stripped" program = self.getBuildArtifact(program_basename) self.build_and_launch(program) functions = ["foo"] - + # This breakpoint will be resolved only when the libfoo module is loaded - breakpoint_ids = self.set_function_breakpoints(functions, wait_for_resolve=False) + breakpoint_ids = self.set_function_breakpoints( + functions, wait_for_resolve=False + ) self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint") self.continue_to_breakpoints(breakpoint_ids) active_modules = self.dap_server.get_modules() program_module = active_modules[program_basename] self.assertIn( --- test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py 2025-05-18 18:56:47.000000 +0000 +++ test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py 2025-05-18 19:02:49.377165 +0000 @@ -33,13 +33,15 @@ program_basename = "a.out.stripped" program = self.getBuildArtifact(program_basename) self.build_and_launch(program) # Set breakpoints functions = ["foo"] - + # This breakpoint will be resolved only when the libfoo module is loaded - breakpoint_ids = self.set_function_breakpoints(functions, wait_for_resolve=False) + breakpoint_ids = self.set_function_breakpoints( + functions, wait_for_resolve=False + ) self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint") main_bp_line = line_number("main.cpp", "// main breakpoint 1") breakpoint_ids.append(self.set_source_breakpoints("main.cpp", [main_bp_line])) self.continue_to_breakpoints(breakpoint_ids) ``````````
https://github.com/llvm/llvm-project/pull/140470 From lldb-commits at lists.llvm.org Sun May 18 12:11:43 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 12:11:43 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Synchronously wait for breakpoints resolves in tests (PR #140470) In-Reply-To: Message-ID: <682a30ef.a70a0220.1bb56c.c3a1@mx.google.com> https://github.com/eronnen updated https://github.com/llvm/llvm-project/pull/140470 >From 542fd2a828a2ed64b23b91c84e444f56e650ad20 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 20:56:47 +0200 Subject: [PATCH 1/2] [lldb-dap] Attempt to synchronously wait for breakpoints resolve in lldb-dap tests in order to stabilize the tests --- .../test/tools/lldb-dap/dap_server.py | 6 +++-- .../test/tools/lldb-dap/lldbdap_testcase.py | 26 +++++++++++++++++-- .../breakpoint/TestDAP_setBreakpoints.py | 1 - .../TestDAP_setFunctionBreakpoints.py | 1 - .../tools/lldb-dap/module/TestDAP_module.py | 4 ++- .../TestDAP_terminatedEvent.py | 6 +++-- ...TestGetTargetBreakpointsRequestHandler.cpp | 10 +++++-- 7 files changed, 43 insertions(+), 11 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index 70fd0b0c419db..1b63ec77abba6 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -1187,7 +1187,7 @@ def request_locations(self, locationReference): } return self.send_recv(command_dict) - def request_testGetTargetBreakpoints(self): + def request_testGetTargetBreakpoints(self, only_resolved=False): """A request packet used in the LLDB test suite to get all currently set breakpoint infos for all breakpoints currently set in the target. @@ -1195,7 +1195,9 @@ def request_testGetTargetBreakpoints(self): command_dict = { "command": "_testGetTargetBreakpoints", "type": "request", - "arguments": {}, + "arguments": { + "onlyResolved": only_resolved, + }, } return self.send_recv(command_dict) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index afdc746ed0d0d..cc45811bd5f27 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -48,7 +48,7 @@ def build_and_create_debug_adapter_for_attach(self): self.build_and_create_debug_adapter(dictionary={"EXE": unique_name}) return self.getBuildArtifact(unique_name) - def set_source_breakpoints(self, source_path, lines, data=None): + def set_source_breakpoints(self, source_path, lines, data=None, wait_for_resolve=True): """Sets source breakpoints and returns an array of strings containing the breakpoint IDs ("1", "2") for each breakpoint that was set. Parameter data is array of data objects for breakpoints. @@ -62,9 +62,11 @@ def set_source_breakpoints(self, source_path, lines, data=None): breakpoint_ids = [] for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) + if wait_for_resolve: + self.wait_for_breakpoints_to_resolve(breakpoint_ids, timeout=10) return breakpoint_ids - def set_function_breakpoints(self, functions, condition=None, hitCondition=None): + def set_function_breakpoints(self, functions, condition=None, hitCondition=None, wait_for_resolve=True): """Sets breakpoints by function name given an array of function names and returns an array of strings containing the breakpoint IDs ("1", "2") for each breakpoint that was set. @@ -78,7 +80,27 @@ def set_function_breakpoints(self, functions, condition=None, hitCondition=None) breakpoint_ids = [] for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) + if wait_for_resolve: + self.wait_for_breakpoints_to_resolve(breakpoint_ids, timeout=10) return breakpoint_ids + + def wait_for_breakpoints_to_resolve(self, breakpoint_ids: list[str], timeout: Optional[float] = None): + unresolved_breakpoints = set(breakpoint_ids) + + # Check already resolved breakpoints + resolved_breakpoints = self.dap_server.request_testGetTargetBreakpoints(only_resolved=True)["body"]["breakpoints"] + for resolved_breakpoint in resolved_breakpoints: + unresolved_breakpoints.discard(str(resolved_breakpoint["id"])) + + while len(unresolved_breakpoints) > 0: + breakpoint_event = self.dap_server.wait_for_event("breakpoint", timeout=timeout) + if breakpoint_event is None: + break + + if breakpoint_event["body"]["reason"] in ["changed", "new"]: + unresolved_breakpoints.discard(str(breakpoint_event["body"]["breakpoint"]["id"])) + + self.assertEqual(len(unresolved_breakpoints), 0, f"Expected to resolve all breakpoints. Unresolved breakpoint ids: {unresolved_breakpoints}") def waitUntil(self, condition_callback): for _ in range(20): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py index aae1251b17c93..26df2573555df 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py @@ -12,7 +12,6 @@ import os - at skip("Temporarily disable the breakpoint tests") class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase): def setUp(self): lldbdap_testcase.DAPTestCaseBase.setUp(self) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py index baaca4d974d5d..946595f639edc 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py @@ -10,7 +10,6 @@ import lldbdap_testcase - at skip("Temporarily disable the breakpoint tests") class TestDAP_setFunctionBreakpoints(lldbdap_testcase.DAPTestCaseBase): @skipIfWindows def test_set_and_clear(self): diff --git a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py index 3fc0f752ee39e..2cea2a94adbbd 100644 --- a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py +++ b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py @@ -16,7 +16,9 @@ def run_test(self, symbol_basename, expect_debug_info_size): program = self.getBuildArtifact(program_basename) self.build_and_launch(program) functions = ["foo"] - breakpoint_ids = self.set_function_breakpoints(functions) + + # This breakpoint will be resolved only when the libfoo module is loaded + breakpoint_ids = self.set_function_breakpoints(functions, wait_for_resolve=False) self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint") self.continue_to_breakpoints(breakpoint_ids) active_modules = self.dap_server.get_modules() diff --git a/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py b/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py index b0abe2a38dac4..a93a4a2fa77cb 100644 --- a/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py +++ b/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py @@ -35,10 +35,12 @@ def test_terminated_event(self): self.build_and_launch(program) # Set breakpoints functions = ["foo"] - breakpoint_ids = self.set_function_breakpoints(functions) + + # This breakpoint will be resolved only when the libfoo module is loaded + breakpoint_ids = self.set_function_breakpoints(functions, wait_for_resolve=False) self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint") main_bp_line = line_number("main.cpp", "// main breakpoint 1") - breakpoint_ids.append(self.set_source_breakpoints("main.cpp", [main_bp_line])) + breakpoint_ids.append(self.set_source_breakpoints("main.cpp", [main_bp_line], wait_for_resolve=False)) self.continue_to_breakpoints(breakpoint_ids) self.continue_to_exit() diff --git a/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp index 5f4f016f6a1ef..129eb31b8356b 100644 --- a/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp @@ -15,12 +15,18 @@ namespace lldb_dap { void TestGetTargetBreakpointsRequestHandler::operator()( const llvm::json::Object &request) const { + const auto *arguments = request.getObject("arguments"); + bool only_resolved = GetBoolean(arguments, "onlyResolved").value_or(false); + llvm::json::Object response; FillResponse(request, response); llvm::json::Array response_breakpoints; for (uint32_t i = 0; dap.target.GetBreakpointAtIndex(i).IsValid(); ++i) { - auto bp = Breakpoint(dap, dap.target.GetBreakpointAtIndex(i)); - response_breakpoints.push_back(bp.ToProtocolBreakpoint()); + const auto target_bp = dap.target.GetBreakpointAtIndex(i); + if (!only_resolved || target_bp.GetNumResolvedLocations() > 0) { + auto bp = Breakpoint(dap, target_bp); + response_breakpoints.push_back(bp.ToProtocolBreakpoint()); + } } llvm::json::Object body; body.try_emplace("breakpoints", std::move(response_breakpoints)); >From 3f08a3613c526a83db69b50069881d6f2815e210 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 21:11:25 +0200 Subject: [PATCH 2/2] python format --- .../test/tools/lldb-dap/lldbdap_testcase.py | 34 ++++++++++++++----- .../tools/lldb-dap/module/TestDAP_module.py | 6 ++-- .../TestDAP_terminatedEvent.py | 12 +++++-- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index cc45811bd5f27..0da89b0a219f1 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -48,7 +48,9 @@ def build_and_create_debug_adapter_for_attach(self): self.build_and_create_debug_adapter(dictionary={"EXE": unique_name}) return self.getBuildArtifact(unique_name) - def set_source_breakpoints(self, source_path, lines, data=None, wait_for_resolve=True): + def set_source_breakpoints( + self, source_path, lines, data=None, wait_for_resolve=True + ): """Sets source breakpoints and returns an array of strings containing the breakpoint IDs ("1", "2") for each breakpoint that was set. Parameter data is array of data objects for breakpoints. @@ -66,7 +68,9 @@ def set_source_breakpoints(self, source_path, lines, data=None, wait_for_resolve self.wait_for_breakpoints_to_resolve(breakpoint_ids, timeout=10) return breakpoint_ids - def set_function_breakpoints(self, functions, condition=None, hitCondition=None, wait_for_resolve=True): + def set_function_breakpoints( + self, functions, condition=None, hitCondition=None, wait_for_resolve=True + ): """Sets breakpoints by function name given an array of function names and returns an array of strings containing the breakpoint IDs ("1", "2") for each breakpoint that was set. @@ -83,24 +87,36 @@ def set_function_breakpoints(self, functions, condition=None, hitCondition=None, if wait_for_resolve: self.wait_for_breakpoints_to_resolve(breakpoint_ids, timeout=10) return breakpoint_ids - - def wait_for_breakpoints_to_resolve(self, breakpoint_ids: list[str], timeout: Optional[float] = None): + + def wait_for_breakpoints_to_resolve( + self, breakpoint_ids: list[str], timeout: Optional[float] = None + ): unresolved_breakpoints = set(breakpoint_ids) - + # Check already resolved breakpoints - resolved_breakpoints = self.dap_server.request_testGetTargetBreakpoints(only_resolved=True)["body"]["breakpoints"] + resolved_breakpoints = self.dap_server.request_testGetTargetBreakpoints( + only_resolved=True + )["body"]["breakpoints"] for resolved_breakpoint in resolved_breakpoints: unresolved_breakpoints.discard(str(resolved_breakpoint["id"])) while len(unresolved_breakpoints) > 0: - breakpoint_event = self.dap_server.wait_for_event("breakpoint", timeout=timeout) + breakpoint_event = self.dap_server.wait_for_event( + "breakpoint", timeout=timeout + ) if breakpoint_event is None: break if breakpoint_event["body"]["reason"] in ["changed", "new"]: - unresolved_breakpoints.discard(str(breakpoint_event["body"]["breakpoint"]["id"])) + unresolved_breakpoints.discard( + str(breakpoint_event["body"]["breakpoint"]["id"]) + ) - self.assertEqual(len(unresolved_breakpoints), 0, f"Expected to resolve all breakpoints. Unresolved breakpoint ids: {unresolved_breakpoints}") + self.assertEqual( + len(unresolved_breakpoints), + 0, + f"Expected to resolve all breakpoints. Unresolved breakpoint ids: {unresolved_breakpoints}", + ) def waitUntil(self, condition_callback): for _ in range(20): diff --git a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py index 2cea2a94adbbd..4fc221668a8ee 100644 --- a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py +++ b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py @@ -16,9 +16,11 @@ def run_test(self, symbol_basename, expect_debug_info_size): program = self.getBuildArtifact(program_basename) self.build_and_launch(program) functions = ["foo"] - + # This breakpoint will be resolved only when the libfoo module is loaded - breakpoint_ids = self.set_function_breakpoints(functions, wait_for_resolve=False) + breakpoint_ids = self.set_function_breakpoints( + functions, wait_for_resolve=False + ) self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint") self.continue_to_breakpoints(breakpoint_ids) active_modules = self.dap_server.get_modules() diff --git a/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py b/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py index a93a4a2fa77cb..7de85bd1589cd 100644 --- a/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py +++ b/lldb/test/API/tools/lldb-dap/terminated-event/TestDAP_terminatedEvent.py @@ -35,12 +35,18 @@ def test_terminated_event(self): self.build_and_launch(program) # Set breakpoints functions = ["foo"] - + # This breakpoint will be resolved only when the libfoo module is loaded - breakpoint_ids = self.set_function_breakpoints(functions, wait_for_resolve=False) + breakpoint_ids = self.set_function_breakpoints( + functions, wait_for_resolve=False + ) self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint") main_bp_line = line_number("main.cpp", "// main breakpoint 1") - breakpoint_ids.append(self.set_source_breakpoints("main.cpp", [main_bp_line], wait_for_resolve=False)) + breakpoint_ids.append( + self.set_source_breakpoints( + "main.cpp", [main_bp_line], wait_for_resolve=False + ) + ) self.continue_to_breakpoints(breakpoint_ids) self.continue_to_exit() From lldb-commits at lists.llvm.org Sun May 18 13:25:05 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sun, 18 May 2025 13:25:05 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Move the command plugins out of the DAP header (PR #140396) In-Reply-To: Message-ID: <682a4221.170a0220.2c70a3.b3c4@mx.google.com> https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/140396 >From 501550d4b96cd746b86467bdb77e432786d7e50c Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Sat, 17 May 2025 12:20:15 -0700 Subject: [PATCH] [lldb-dap] Move the command plugins out of the DAP header Move the command plugins out of the DAP header and into their file. This PR also renames the classes from "RequestHandler" to "Command". Although they are implemented in terms of sending requests, they are not "handlers". --- lldb/tools/lldb-dap/CMakeLists.txt | 1 + lldb/tools/lldb-dap/CommandPlugins.cpp | 163 ++++++++++++++++++ lldb/tools/lldb-dap/CommandPlugins.h | 40 +++++ lldb/tools/lldb-dap/DAP.cpp | 153 ---------------- lldb/tools/lldb-dap/DAP.h | 21 --- .../Handler/InitializeRequestHandler.cpp | 7 +- 6 files changed, 208 insertions(+), 177 deletions(-) create mode 100644 lldb/tools/lldb-dap/CommandPlugins.cpp create mode 100644 lldb/tools/lldb-dap/CommandPlugins.h diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index f8e81eaff8606..490aa4710af1a 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -8,6 +8,7 @@ add_public_tablegen_target(LLDBDAPOptionsTableGen) add_lldb_library(lldbDAP Breakpoint.cpp BreakpointBase.cpp + CommandPlugins.cpp DAP.cpp DAPError.cpp DAPLog.cpp diff --git a/lldb/tools/lldb-dap/CommandPlugins.cpp b/lldb/tools/lldb-dap/CommandPlugins.cpp new file mode 100644 index 0000000000000..4e7aa029e0f22 --- /dev/null +++ b/lldb/tools/lldb-dap/CommandPlugins.cpp @@ -0,0 +1,163 @@ +//===-- CommandPlugins.cpp ------------------------------------------------===// +// +// 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 "CommandPlugins.h" +#include "Handler/ResponseHandler.h" +#include "JSONUtils.h" +#include "lldb/API/SBStream.h" + +using namespace lldb_dap; + +bool StartDebuggingCommand::DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) { + // Command format like: `start-debugging ` + if (!command) { + result.SetError("Invalid use of start-debugging, expected format " + "`start-debugging `."); + return false; + } + + if (!command[0] || llvm::StringRef(command[0]).empty()) { + result.SetError("start-debugging request type missing."); + return false; + } + + if (!command[1] || llvm::StringRef(command[1]).empty()) { + result.SetError("start-debugging debug configuration missing."); + return false; + } + + llvm::StringRef request{command[0]}; + std::string raw_configuration{command[1]}; + + llvm::Expected configuration = + llvm::json::parse(raw_configuration); + + if (!configuration) { + llvm::Error err = configuration.takeError(); + std::string msg = "Failed to parse json configuration: " + + llvm::toString(std::move(err)) + "\n\n" + + raw_configuration; + result.SetError(msg.c_str()); + return false; + } + + dap.SendReverseRequest( + "startDebugging", + llvm::json::Object{{"request", request}, + {"configuration", std::move(*configuration)}}); + + result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); + + return true; +} + +bool ReplModeCommand::DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) { + // Command format like: `repl-mode ?` + // If a new mode is not specified report the current mode. + if (!command || llvm::StringRef(command[0]).empty()) { + std::string mode; + switch (dap.repl_mode) { + case ReplMode::Variable: + mode = "variable"; + break; + case ReplMode::Command: + mode = "command"; + break; + case ReplMode::Auto: + mode = "auto"; + break; + } + + result.Printf("lldb-dap repl-mode %s.\n", mode.c_str()); + result.SetStatus(lldb::eReturnStatusSuccessFinishResult); + + return true; + } + + llvm::StringRef new_mode{command[0]}; + + if (new_mode == "variable") { + dap.repl_mode = ReplMode::Variable; + } else if (new_mode == "command") { + dap.repl_mode = ReplMode::Command; + } else if (new_mode == "auto") { + dap.repl_mode = ReplMode::Auto; + } else { + lldb::SBStream error_message; + error_message.Printf("Invalid repl-mode '%s'. Expected one of 'variable', " + "'command' or 'auto'.\n", + new_mode.data()); + result.SetError(error_message.GetData()); + return false; + } + + result.Printf("lldb-dap repl-mode %s set.\n", new_mode.data()); + result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); + return true; +} + +/// Sends a DAP event with an optional body. +/// +/// https://code.visualstudio.com/api/references/vscode-api#debug.onDidReceiveDebugSessionCustomEvent +bool SendEventCommand::DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) { + // Command format like: `send-event ?` + if (!command || !command[0] || llvm::StringRef(command[0]).empty()) { + result.SetError("Not enough arguments found, expected format " + "`lldb-dap send-event ?`."); + return false; + } + + llvm::StringRef name{command[0]}; + // Events that are stateful and should be handled by lldb-dap internally. + const std::array internal_events{"breakpoint", "capabilities", "continued", + "exited", "initialize", "loadedSource", + "module", "process", "stopped", + "terminated", "thread"}; + if (llvm::is_contained(internal_events, name)) { + std::string msg = + llvm::formatv("Invalid use of lldb-dap send-event, event \"{0}\" " + "should be handled by lldb-dap internally.", + name) + .str(); + result.SetError(msg.c_str()); + return false; + } + + llvm::json::Object event(CreateEventObject(name)); + + if (command[1] && !llvm::StringRef(command[1]).empty()) { + // See if we have unused arguments. + if (command[2]) { + result.SetError( + "Additional arguments found, expected `lldb-dap send-event " + " ?`."); + return false; + } + + llvm::StringRef raw_body{command[1]}; + + llvm::Expected body = llvm::json::parse(raw_body); + + if (!body) { + llvm::Error err = body.takeError(); + std::string msg = "Failed to parse custom event body: " + + llvm::toString(std::move(err)); + result.SetError(msg.c_str()); + return false; + } + + event.try_emplace("body", std::move(*body)); + } + + dap.SendJSON(llvm::json::Value(std::move(event))); + result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); + return true; +} diff --git a/lldb/tools/lldb-dap/CommandPlugins.h b/lldb/tools/lldb-dap/CommandPlugins.h new file mode 100644 index 0000000000000..011c7fd2da2a1 --- /dev/null +++ b/lldb/tools/lldb-dap/CommandPlugins.h @@ -0,0 +1,40 @@ +//===-- CommandPlugins.h --------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TOOLS_LLDB_DAP_COMMANDPLUGINS_H +#define LLDB_TOOLS_LLDB_DAP_COMMANDPLUGINS_H + +#include "DAP.h" +#include "lldb/API/SBCommandInterpreter.h" + +namespace lldb_dap { + +struct StartDebuggingCommand : public lldb::SBCommandPluginInterface { + DAP &dap; + explicit StartDebuggingCommand(DAP &d) : dap(d) {}; + bool DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) override; +}; + +struct ReplModeCommand : public lldb::SBCommandPluginInterface { + DAP &dap; + explicit ReplModeCommand(DAP &d) : dap(d) {}; + bool DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) override; +}; + +struct SendEventCommand : public lldb::SBCommandPluginInterface { + DAP &dap; + explicit SendEventCommand(DAP &d) : dap(d) {}; + bool DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) override; +}; + +} // namespace lldb_dap + +#endif diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 8868131622243..af7a04a215fec 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1017,159 +1017,6 @@ lldb::SBError DAP::WaitForProcessToStop(std::chrono::seconds seconds) { return error; } -bool StartDebuggingRequestHandler::DoExecute( - lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) { - // Command format like: `start-debugging ` - if (!command) { - result.SetError("Invalid use of start-debugging, expected format " - "`start-debugging `."); - return false; - } - - if (!command[0] || llvm::StringRef(command[0]).empty()) { - result.SetError("start-debugging request type missing."); - return false; - } - - if (!command[1] || llvm::StringRef(command[1]).empty()) { - result.SetError("start-debugging debug configuration missing."); - return false; - } - - llvm::StringRef request{command[0]}; - std::string raw_configuration{command[1]}; - - llvm::Expected configuration = - llvm::json::parse(raw_configuration); - - if (!configuration) { - llvm::Error err = configuration.takeError(); - std::string msg = "Failed to parse json configuration: " + - llvm::toString(std::move(err)) + "\n\n" + - raw_configuration; - result.SetError(msg.c_str()); - return false; - } - - dap.SendReverseRequest( - "startDebugging", - llvm::json::Object{{"request", request}, - {"configuration", std::move(*configuration)}}); - - result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); - - return true; -} - -bool ReplModeRequestHandler::DoExecute(lldb::SBDebugger debugger, - char **command, - lldb::SBCommandReturnObject &result) { - // Command format like: `repl-mode ?` - // If a new mode is not specified report the current mode. - if (!command || llvm::StringRef(command[0]).empty()) { - std::string mode; - switch (dap.repl_mode) { - case ReplMode::Variable: - mode = "variable"; - break; - case ReplMode::Command: - mode = "command"; - break; - case ReplMode::Auto: - mode = "auto"; - break; - } - - result.Printf("lldb-dap repl-mode %s.\n", mode.c_str()); - result.SetStatus(lldb::eReturnStatusSuccessFinishResult); - - return true; - } - - llvm::StringRef new_mode{command[0]}; - - if (new_mode == "variable") { - dap.repl_mode = ReplMode::Variable; - } else if (new_mode == "command") { - dap.repl_mode = ReplMode::Command; - } else if (new_mode == "auto") { - dap.repl_mode = ReplMode::Auto; - } else { - lldb::SBStream error_message; - error_message.Printf("Invalid repl-mode '%s'. Expected one of 'variable', " - "'command' or 'auto'.\n", - new_mode.data()); - result.SetError(error_message.GetData()); - return false; - } - - result.Printf("lldb-dap repl-mode %s set.\n", new_mode.data()); - result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); - return true; -} - -// Sends a DAP event with an optional body. -// -// See -// https://code.visualstudio.com/api/references/vscode-api#debug.onDidReceiveDebugSessionCustomEvent -bool SendEventRequestHandler::DoExecute(lldb::SBDebugger debugger, - char **command, - lldb::SBCommandReturnObject &result) { - // Command format like: `send-event ?` - if (!command || !command[0] || llvm::StringRef(command[0]).empty()) { - result.SetError("Not enough arguments found, expected format " - "`lldb-dap send-event ?`."); - return false; - } - - llvm::StringRef name{command[0]}; - // Events that are stateful and should be handled by lldb-dap internally. - const std::array internal_events{"breakpoint", "capabilities", "continued", - "exited", "initialize", "loadedSource", - "module", "process", "stopped", - "terminated", "thread"}; - if (llvm::is_contained(internal_events, name)) { - std::string msg = - llvm::formatv("Invalid use of lldb-dap send-event, event \"{0}\" " - "should be handled by lldb-dap internally.", - name) - .str(); - result.SetError(msg.c_str()); - return false; - } - - llvm::json::Object event(CreateEventObject(name)); - - if (command[1] && !llvm::StringRef(command[1]).empty()) { - // See if we have unused arguments. - if (command[2]) { - result.SetError( - "Additional arguments found, expected `lldb-dap send-event " - " ?`."); - return false; - } - - llvm::StringRef raw_body{command[1]}; - - llvm::Expected body = llvm::json::parse(raw_body); - - if (!body) { - llvm::Error err = body.takeError(); - std::string msg = "Failed to parse custom event body: " + - llvm::toString(std::move(err)); - result.SetError(msg.c_str()); - return false; - } - - event.try_emplace("body", std::move(*body)); - } - - dap.SendJSON(llvm::json::Value(std::move(event))); - result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); - return true; -} - void DAP::ConfigureSourceMaps() { if (configuration.sourceMap.empty() && configuration.sourcePath.empty()) return; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index eafc92776fca7..44b8153ba2725 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -83,27 +83,6 @@ enum class PacketStatus { enum class ReplMode { Variable = 0, Command, Auto }; -struct StartDebuggingRequestHandler : public lldb::SBCommandPluginInterface { - DAP &dap; - explicit StartDebuggingRequestHandler(DAP &d) : dap(d) {}; - bool DoExecute(lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) override; -}; - -struct ReplModeRequestHandler : public lldb::SBCommandPluginInterface { - DAP &dap; - explicit ReplModeRequestHandler(DAP &d) : dap(d) {}; - bool DoExecute(lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) override; -}; - -struct SendEventRequestHandler : public lldb::SBCommandPluginInterface { - DAP &dap; - explicit SendEventRequestHandler(DAP &d) : dap(d) {}; - bool DoExecute(lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) override; -}; - struct DAP { /// Path to the lldb-dap binary itself. static llvm::StringRef debug_adapter_path; diff --git a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp index 0a178406b5a69..dcd02d61ca4f4 100644 --- a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "CommandPlugins.h" #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" @@ -59,14 +60,14 @@ llvm::Expected InitializeRequestHandler::Run( if (arguments.supportedFeatures.contains( eClientFeatureStartDebuggingRequest)) { cmd.AddCommand( - "start-debugging", new StartDebuggingRequestHandler(dap), + "start-debugging", new StartDebuggingCommand(dap), "Sends a startDebugging request from the debug adapter to the client " "to start a child debug session of the same type as the caller."); } cmd.AddCommand( - "repl-mode", new ReplModeRequestHandler(dap), + "repl-mode", new ReplModeCommand(dap), "Get or set the repl behavior of lldb-dap evaluation requests."); - cmd.AddCommand("send-event", new SendEventRequestHandler(dap), + cmd.AddCommand("send-event", new SendEventCommand(dap), "Sends an DAP event to the client."); if (arguments.supportedFeatures.contains(eClientFeatureProgressReporting)) From lldb-commits at lists.llvm.org Sun May 18 14:07:21 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sun, 18 May 2025 14:07:21 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for FifoFiles (PR #140480) Message-ID: https://github.com/JDevlieghere created https://github.com/llvm/llvm-project/pull/140480 None >From 8cc54e7e1f2134e2e6352e4f572f3b0f9a3ce59f Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Sun, 18 May 2025 14:05:46 -0700 Subject: [PATCH] [lldb-dap] Add unit test for FifoFiles --- lldb/unittests/DAP/CMakeLists.txt | 1 + lldb/unittests/DAP/FifoFilesTest.cpp | 102 +++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 lldb/unittests/DAP/FifoFilesTest.cpp diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index 429a12e9fb505..cd421401f167b 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -1,5 +1,6 @@ add_lldb_unittest(DAPTests DAPTest.cpp + FifoFilesTest.cpp Handler/DisconnectTest.cpp JSONUtilsTest.cpp LLDBUtilsTest.cpp diff --git a/lldb/unittests/DAP/FifoFilesTest.cpp b/lldb/unittests/DAP/FifoFilesTest.cpp new file mode 100644 index 0000000000000..1b664fbb14010 --- /dev/null +++ b/lldb/unittests/DAP/FifoFilesTest.cpp @@ -0,0 +1,102 @@ +//===-- FifoFilesTest.cpp -------------------------------------------------===// +// +// 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 "FifoFiles.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include + +using namespace lldb_dap; +using namespace llvm; + +namespace { + +std::string MakeTempFifoPath() { + llvm::SmallString<128> temp_path; + llvm::sys::fs::createUniquePath("lldb-dap-fifo-%%%%%%", temp_path, + /*MakeAbsolute=*/true); + return temp_path.str().str(); +} + +} // namespace + +TEST(FifoFilesTest, CreateAndDestroyFifoFile) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + // File should exist and be a FIFO. + EXPECT_TRUE(llvm::sys::fs::exists(fifo_path)); + + // Destructor should remove the file. + fifo->reset(); + EXPECT_FALSE(llvm::sys::fs::exists(fifo_path)); +} + +TEST(FifoFilesTest, SendAndReceiveJSON) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + FifoFileIO writer(fifo_path, "writer"); + FifoFileIO reader(fifo_path, "reader"); + + llvm::json::Object obj; + obj["foo"] = "bar"; + obj["num"] = 42; + + // Writer thread. + std::thread writer_thread([&]() { + EXPECT_THAT_ERROR(writer.SendJSON(llvm::json::Value(std::move(obj)), + std::chrono::milliseconds(500)), + llvm::Succeeded()); + }); + + // Reader thread. + std::thread reader_thread([&]() { + auto result = reader.ReadJSON(std::chrono::milliseconds(500)); + EXPECT_THAT_EXPECTED(result, llvm::Succeeded()); + auto *read_obj = result->getAsObject(); + + ASSERT_NE(read_obj, nullptr); + EXPECT_EQ((*read_obj)["foo"].getAsString(), "bar"); + EXPECT_EQ((*read_obj)["num"].getAsInteger(), 42); + }); + + writer_thread.join(); + reader_thread.join(); +} + +TEST(FifoFilesTest, ReadTimeout) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + FifoFileIO reader(fifo_path, "reader"); + + // No writer, should timeout. + auto result = reader.ReadJSON(std::chrono::milliseconds(100)); + EXPECT_THAT_EXPECTED(result, llvm::Failed()); +} + +TEST(FifoFilesTest, WriteTimeout) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + FifoFileIO writer(fifo_path, "writer"); + + // No reader, should timeout. + llvm::json::Object obj; + obj["foo"] = "bar"; + EXPECT_THAT_ERROR(writer.SendJSON(llvm::json::Value(std::move(obj)), + std::chrono::milliseconds(100)), + llvm::Failed()); +} From lldb-commits at lists.llvm.org Sun May 18 14:07:54 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sun, 18 May 2025 14:07:54 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for FifoFiles (PR #140480) In-Reply-To: Message-ID: <682a4c2a.050a0220.349151.cff6@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Jonas Devlieghere (JDevlieghere)
Changes --- Full diff: https://github.com/llvm/llvm-project/pull/140480.diff 2 Files Affected: - (modified) lldb/unittests/DAP/CMakeLists.txt (+1) - (added) lldb/unittests/DAP/FifoFilesTest.cpp (+102) ``````````diff diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index 429a12e9fb505..cd421401f167b 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -1,5 +1,6 @@ add_lldb_unittest(DAPTests DAPTest.cpp + FifoFilesTest.cpp Handler/DisconnectTest.cpp JSONUtilsTest.cpp LLDBUtilsTest.cpp diff --git a/lldb/unittests/DAP/FifoFilesTest.cpp b/lldb/unittests/DAP/FifoFilesTest.cpp new file mode 100644 index 0000000000000..1b664fbb14010 --- /dev/null +++ b/lldb/unittests/DAP/FifoFilesTest.cpp @@ -0,0 +1,102 @@ +//===-- FifoFilesTest.cpp -------------------------------------------------===// +// +// 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 "FifoFiles.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include + +using namespace lldb_dap; +using namespace llvm; + +namespace { + +std::string MakeTempFifoPath() { + llvm::SmallString<128> temp_path; + llvm::sys::fs::createUniquePath("lldb-dap-fifo-%%%%%%", temp_path, + /*MakeAbsolute=*/true); + return temp_path.str().str(); +} + +} // namespace + +TEST(FifoFilesTest, CreateAndDestroyFifoFile) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + // File should exist and be a FIFO. + EXPECT_TRUE(llvm::sys::fs::exists(fifo_path)); + + // Destructor should remove the file. + fifo->reset(); + EXPECT_FALSE(llvm::sys::fs::exists(fifo_path)); +} + +TEST(FifoFilesTest, SendAndReceiveJSON) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + FifoFileIO writer(fifo_path, "writer"); + FifoFileIO reader(fifo_path, "reader"); + + llvm::json::Object obj; + obj["foo"] = "bar"; + obj["num"] = 42; + + // Writer thread. + std::thread writer_thread([&]() { + EXPECT_THAT_ERROR(writer.SendJSON(llvm::json::Value(std::move(obj)), + std::chrono::milliseconds(500)), + llvm::Succeeded()); + }); + + // Reader thread. + std::thread reader_thread([&]() { + auto result = reader.ReadJSON(std::chrono::milliseconds(500)); + EXPECT_THAT_EXPECTED(result, llvm::Succeeded()); + auto *read_obj = result->getAsObject(); + + ASSERT_NE(read_obj, nullptr); + EXPECT_EQ((*read_obj)["foo"].getAsString(), "bar"); + EXPECT_EQ((*read_obj)["num"].getAsInteger(), 42); + }); + + writer_thread.join(); + reader_thread.join(); +} + +TEST(FifoFilesTest, ReadTimeout) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + FifoFileIO reader(fifo_path, "reader"); + + // No writer, should timeout. + auto result = reader.ReadJSON(std::chrono::milliseconds(100)); + EXPECT_THAT_EXPECTED(result, llvm::Failed()); +} + +TEST(FifoFilesTest, WriteTimeout) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + FifoFileIO writer(fifo_path, "writer"); + + // No reader, should timeout. + llvm::json::Object obj; + obj["foo"] = "bar"; + EXPECT_THAT_ERROR(writer.SendJSON(llvm::json::Value(std::move(obj)), + std::chrono::milliseconds(100)), + llvm::Failed()); +} ``````````
https://github.com/llvm/llvm-project/pull/140480 From lldb-commits at lists.llvm.org Sun May 18 14:08:11 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sun, 18 May 2025 14:08:11 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for FifoFiles (PR #140480) In-Reply-To: Message-ID: <682a4c3b.050a0220.40824.cebc@mx.google.com> https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/140480 >From 58f1ceb2c3d7e7e74d06f1ffb8b015794d011db5 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Sun, 18 May 2025 14:05:46 -0700 Subject: [PATCH] [lldb-dap] Add unit test for FifoFiles --- lldb/unittests/DAP/CMakeLists.txt | 1 + lldb/unittests/DAP/FifoFilesTest.cpp | 102 +++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 lldb/unittests/DAP/FifoFilesTest.cpp diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index 429a12e9fb505..cd421401f167b 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -1,5 +1,6 @@ add_lldb_unittest(DAPTests DAPTest.cpp + FifoFilesTest.cpp Handler/DisconnectTest.cpp JSONUtilsTest.cpp LLDBUtilsTest.cpp diff --git a/lldb/unittests/DAP/FifoFilesTest.cpp b/lldb/unittests/DAP/FifoFilesTest.cpp new file mode 100644 index 0000000000000..bbc1b608e91bd --- /dev/null +++ b/lldb/unittests/DAP/FifoFilesTest.cpp @@ -0,0 +1,102 @@ +//===-- FifoFilesTest.cpp -------------------------------------------------===// +// +// 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 "FifoFiles.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include + +using namespace lldb_dap; +using namespace llvm; + +namespace { + +std::string MakeTempFifoPath() { + llvm::SmallString<128> temp_path; + llvm::sys::fs::createUniquePath("lldb-dap-fifo-%%%%%%", temp_path, + /*MakeAbsolute=*/true); + return temp_path.str().str(); +} + +} // namespace + +TEST(FifoFilesTest, CreateAndDestroyFifoFile) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + // File should exist. + EXPECT_TRUE(llvm::sys::fs::exists(fifo_path)); + + // Destructor should remove the file. + fifo->reset(); + EXPECT_FALSE(llvm::sys::fs::exists(fifo_path)); +} + +TEST(FifoFilesTest, SendAndReceiveJSON) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + FifoFileIO writer(fifo_path, "writer"); + FifoFileIO reader(fifo_path, "reader"); + + llvm::json::Object obj; + obj["foo"] = "bar"; + obj["num"] = 42; + + // Writer thread. + std::thread writer_thread([&]() { + EXPECT_THAT_ERROR(writer.SendJSON(llvm::json::Value(std::move(obj)), + std::chrono::milliseconds(500)), + llvm::Succeeded()); + }); + + // Reader thread. + std::thread reader_thread([&]() { + auto result = reader.ReadJSON(std::chrono::milliseconds(500)); + EXPECT_THAT_EXPECTED(result, llvm::Succeeded()); + auto *read_obj = result->getAsObject(); + + ASSERT_NE(read_obj, nullptr); + EXPECT_EQ((*read_obj)["foo"].getAsString(), "bar"); + EXPECT_EQ((*read_obj)["num"].getAsInteger(), 42); + }); + + writer_thread.join(); + reader_thread.join(); +} + +TEST(FifoFilesTest, ReadTimeout) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + FifoFileIO reader(fifo_path, "reader"); + + // No writer, should timeout. + auto result = reader.ReadJSON(std::chrono::milliseconds(100)); + EXPECT_THAT_EXPECTED(result, llvm::Failed()); +} + +TEST(FifoFilesTest, WriteTimeout) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + FifoFileIO writer(fifo_path, "writer"); + + // No reader, should timeout. + llvm::json::Object obj; + obj["foo"] = "bar"; + EXPECT_THAT_ERROR(writer.SendJSON(llvm::json::Value(std::move(obj)), + std::chrono::milliseconds(100)), + llvm::Failed()); +} From lldb-commits at lists.llvm.org Sun May 18 14:52:47 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 14:52:47 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Migrate disassemble request to structured handler (PR #140482) Message-ID: https://github.com/eronnen created https://github.com/llvm/llvm-project/pull/140482 None >From b187a83605b9c50ea5dbe7674b755bc8706c2936 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 23:51:58 +0200 Subject: [PATCH] [lldb-dap] Migrate disassemble request to structured handler --- .../Handler/DisassembleRequestHandler.cpp | 176 ++++-------------- lldb/tools/lldb-dap/Handler/RequestHandler.h | 7 +- .../lldb-dap/Protocol/ProtocolRequests.cpp | 18 ++ .../lldb-dap/Protocol/ProtocolRequests.h | 31 +++ .../tools/lldb-dap/Protocol/ProtocolTypes.cpp | 34 ++++ lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 53 ++++++ 6 files changed, 179 insertions(+), 140 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp index d738f54ff1a9f..9df831c8b8c61 100644 --- a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp @@ -9,113 +9,30 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "Protocol/ProtocolRequests.h" +#include "Protocol/ProtocolTypes.h" #include "RequestHandler.h" #include "lldb/API/SBInstruction.h" #include "llvm/ADT/StringExtras.h" +using namespace lldb_dap::protocol; + namespace lldb_dap { -// "DisassembleRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Disassembles code stored at the provided -// location.\nClients should only call this request if the corresponding -// capability `supportsDisassembleRequest` is true.", "properties": { -// "command": { -// "type": "string", -// "enum": [ "disassemble" ] -// }, -// "arguments": { -// "$ref": "#/definitions/DisassembleArguments" -// } -// }, -// "required": [ "command", "arguments" ] -// }] -// }, -// "DisassembleArguments": { -// "type": "object", -// "description": "Arguments for `disassemble` request.", -// "properties": { -// "memoryReference": { -// "type": "string", -// "description": "Memory reference to the base location containing the -// instructions to disassemble." -// }, -// "offset": { -// "type": "integer", -// "description": "Offset (in bytes) to be applied to the reference -// location before disassembling. Can be negative." -// }, -// "instructionOffset": { -// "type": "integer", -// "description": "Offset (in instructions) to be applied after the byte -// offset (if any) before disassembling. Can be negative." -// }, -// "instructionCount": { -// "type": "integer", -// "description": "Number of instructions to disassemble starting at the -// specified location and offset.\nAn adapter must return exactly this -// number of instructions - any unavailable instructions should be -// replaced with an implementation-defined 'invalid instruction' value." -// }, -// "resolveSymbols": { -// "type": "boolean", -// "description": "If true, the adapter should attempt to resolve memory -// addresses and other values to symbolic names." -// } -// }, -// "required": [ "memoryReference", "instructionCount" ] -// }, -// "DisassembleResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to `disassemble` request.", -// "properties": { -// "body": { -// "type": "object", -// "properties": { -// "instructions": { -// "type": "array", -// "items": { -// "$ref": "#/definitions/DisassembledInstruction" -// }, -// "description": "The list of disassembled instructions." -// } -// }, -// "required": [ "instructions" ] -// } -// } -// }] -// } -void DisassembleRequestHandler::operator()( - const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - auto *arguments = request.getObject("arguments"); - - llvm::StringRef memoryReference = - GetString(arguments, "memoryReference").value_or(""); - auto addr_opt = DecodeMemoryReference(memoryReference); - if (!addr_opt.has_value()) { - response["success"] = false; - response["message"] = - "Malformed memory reference: " + memoryReference.str(); - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } - lldb::addr_t addr_ptr = *addr_opt; +/// Disassembles code stored at the provided location. +/// Clients should only call this request if the corresponding capability `supportsDisassembleRequest` is true. +llvm::Expected DisassembleRequestHandler::Run(const DisassembleArguments &args) const { + std::vector instructions; - addr_ptr += GetInteger(arguments, "instructionOffset").value_or(0); + auto addr_opt = DecodeMemoryReference(args.memoryReference); + if (!addr_opt.has_value()) + return llvm::make_error("Malformed memory reference: " + args.memoryReference); + + lldb::addr_t addr_ptr = *addr_opt; + addr_ptr += args.instructionOffset.value_or(0); lldb::SBAddress addr(addr_ptr, dap.target); - if (!addr.IsValid()) { - response["success"] = false; - response["message"] = "Memory reference not found in the current binary."; - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } - - const auto inst_count = - GetInteger(arguments, "instructionCount").value_or(0); + if (!addr.IsValid()) + return llvm::make_error("Memory reference not found in the current binary."); std::string flavor_string; const auto target_triple = llvm::StringRef(dap.target.GetTriple()); @@ -133,18 +50,12 @@ void DisassembleRequestHandler::operator()( } lldb::SBInstructionList insts = - dap.target.ReadInstructions(addr, inst_count, flavor_string.c_str()); + dap.target.ReadInstructions(addr, args.instructionCount, flavor_string.c_str()); - if (!insts.IsValid()) { - response["success"] = false; - response["message"] = "Failed to find instructions for memory address."; - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } + if (!insts.IsValid()) + return llvm::make_error("Failed to find instructions for memory address."); - const bool resolveSymbols = - GetBoolean(arguments, "resolveSymbols").value_or(false); - llvm::json::Array instructions; + const bool resolveSymbols = args.resolveSymbols.value_or(false); const auto num_insts = insts.GetSize(); for (size_t i = 0; i < num_insts; ++i) { lldb::SBInstruction inst = insts.GetInstructionAtIndex(i); @@ -165,11 +76,9 @@ void DisassembleRequestHandler::operator()( } } - llvm::json::Object disassembled_inst{ - {"address", "0x" + llvm::utohexstr(inst_addr)}, - {"instructionBytes", - bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : ""}, - }; + DisassembledInstruction disassembled_inst; + disassembled_inst.address = "0x" + llvm::utohexstr(inst_addr); + disassembled_inst.instructionBytes = bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : ""; std::string instruction; llvm::raw_string_ostream si(instruction); @@ -185,9 +94,8 @@ void DisassembleRequestHandler::operator()( : symbol.GetName()) << ": "; - if (resolveSymbols) { - disassembled_inst.try_emplace("symbol", symbol.GetDisplayName()); - } + if (resolveSymbols) + disassembled_inst.symbol = symbol.GetDisplayName(); } si << llvm::formatv("{0,7} {1,12}", m, o); @@ -195,7 +103,7 @@ void DisassembleRequestHandler::operator()( si << " ; " << c; } - disassembled_inst.try_emplace("instruction", instruction); + disassembled_inst.instruction = instruction; auto line_entry = addr.GetLineEntry(); // If the line number is 0 then the entry represents a compiler generated @@ -203,41 +111,35 @@ void DisassembleRequestHandler::operator()( if (line_entry.GetStartAddress() == addr && line_entry.IsValid() && line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) { auto source = CreateSource(line_entry); - disassembled_inst.try_emplace("location", source); + disassembled_inst.location = std::move(source); const auto line = line_entry.GetLine(); - if (line && line != LLDB_INVALID_LINE_NUMBER) { - disassembled_inst.try_emplace("line", line); - } + if (line != 0 && line != LLDB_INVALID_LINE_NUMBER) + disassembled_inst.line = line; + const auto column = line_entry.GetColumn(); - if (column && column != LLDB_INVALID_COLUMN_NUMBER) { - disassembled_inst.try_emplace("column", column); - } + if (column != 0 && column != LLDB_INVALID_COLUMN_NUMBER) + disassembled_inst.column = column; auto end_line_entry = line_entry.GetEndAddress().GetLineEntry(); if (end_line_entry.IsValid() && end_line_entry.GetFileSpec() == line_entry.GetFileSpec()) { const auto end_line = end_line_entry.GetLine(); - if (end_line && end_line != LLDB_INVALID_LINE_NUMBER && - end_line != line) { - disassembled_inst.try_emplace("endLine", end_line); + if (end_line != 0 && end_line != LLDB_INVALID_LINE_NUMBER && end_line != line) { + disassembled_inst.endLine = end_line; const auto end_column = end_line_entry.GetColumn(); - if (end_column && end_column != LLDB_INVALID_COLUMN_NUMBER && - end_column != column) { - disassembled_inst.try_emplace("endColumn", end_column - 1); - } + if (end_column != 0 && end_column != LLDB_INVALID_COLUMN_NUMBER && + end_column != column) + disassembled_inst.endColumn = end_column - 1; } } } - instructions.emplace_back(std::move(disassembled_inst)); + instructions.push_back(std::move(disassembled_inst)); } - llvm::json::Object body; - body.try_emplace("instructions", std::move(instructions)); - response.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(response))); + return DisassembleResponseBody{std::move(instructions)}; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index e6bccfe12f402..09bedb88d6b09 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -534,14 +534,15 @@ class LocationsRequestHandler : public LegacyRequestHandler { void operator()(const llvm::json::Object &request) const override; }; -class DisassembleRequestHandler : public LegacyRequestHandler { +class DisassembleRequestHandler final : public RequestHandler> { public: - using LegacyRequestHandler::LegacyRequestHandler; + using RequestHandler::RequestHandler; static llvm::StringLiteral GetCommand() { return "disassemble"; } FeatureSet GetSupportedFeatures() const override { return {protocol::eAdapterFeatureDisassembleRequest}; } - void operator()(const llvm::json::Object &request) const override; + llvm::Expected + Run(const protocol::DisassembleArguments &args) const override; }; class ReadMemoryRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp index 7efab87d39986..4160077d419e1 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp @@ -460,4 +460,22 @@ llvm::json::Value toJSON(const SetDataBreakpointsResponseBody &SDBR) { return result; } +bool fromJSON(const llvm::json::Value &Params, DisassembleArguments &DA, + llvm::json::Path P) { + json::ObjectMapper O(Params, P); + return O && O.map("memoryReference", DA.memoryReference) && + O.mapOptional("offset", DA.offset) && + O.mapOptional("instructionOffset", DA.instructionOffset) && + O.map("instructionCount", DA.instructionCount) && + O.mapOptional("resolveSymbols", DA.resolveSymbols); +} + +llvm::json::Value toJSON(const DisassembleResponseBody &DRB) { + llvm::json::Array instructions; + for (const auto &instruction : DRB.instructions) { + instructions.push_back(toJSON(instruction)); + } + return llvm::json::Object{{"instructions", std::move(instructions)}}; +} + } // namespace lldb_dap::protocol diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index b421c631344de..d48a3a3a14fb7 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -726,6 +726,37 @@ struct SetDataBreakpointsResponseBody { }; llvm::json::Value toJSON(const SetDataBreakpointsResponseBody &); +/// Arguments to `disassemble` request. +struct DisassembleArguments { + /// Memory reference to the base location containing the instructions to disassemble. + std::string memoryReference; + + /// Offset (in bytes) to be applied to the reference location before disassembling. Can be negative. + std::optional offset; + + /// Offset (in instructions) to be applied after the byte offset (if any) before disassembling. Can be negative. + std::optional instructionOffset; + + /// Number of instructions to disassemble starting at the specified location + /// and offset. + /// An adapter must return exactly this number of instructions - any + /// unavailable instructions should be replaced with an implementation-defined + /// 'invalid instruction' value. + uint32_t instructionCount; + + /// If true, the adapter should attempt to resolve memory addresses and other values to symbolic names. + std::optional resolveSymbols; +}; +bool fromJSON(const llvm::json::Value &, DisassembleArguments &, + llvm::json::Path); + +/// Response to `disassemble` request. +struct DisassembleResponseBody { + /// The list of disassembled instructions. + std::vector instructions; +}; +llvm::json::Value toJSON(const DisassembleResponseBody &); + } // namespace lldb_dap::protocol #endif diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index ce7519e3b16b8..94fe236d952a7 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -782,4 +782,38 @@ bool fromJSON(const llvm::json::Value &Params, InstructionBreakpoint &IB, O.mapOptional("mode", IB.mode); } +llvm::json::Value toJSON(const DisassembledInstruction::PresentationHint &PH) { + switch (PH) { + case DisassembledInstruction::eSourcePresentationHintNormal: + return "normal"; + case DisassembledInstruction::eSourcePresentationHintInvalid: + return "invalid"; + } + llvm_unreachable("unhandled presentation hint."); +} + +llvm::json::Value toJSON(const DisassembledInstruction &DI) { + llvm::json::Object result{{"address", DI.address}, + {"instruction", DI.instruction}}; + + if (DI.instructionBytes) + result.insert({"instructionBytes", *DI.instructionBytes}); + if (DI.symbol) + result.insert({"symbol", *DI.symbol}); + if (DI.location) + result.insert({"location", *DI.location}); + if (DI.line) + result.insert({"line", *DI.line}); + if (DI.column) + result.insert({"column", *DI.column}); + if (DI.endLine) + result.insert({"endLine", *DI.endLine}); + if (DI.endColumn) + result.insert({"endColumn", *DI.endColumn}); + if (DI.presentationHint) + result.insert({"presentationHint", *DI.presentationHint}); + + return result; +} + } // namespace lldb_dap::protocol diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index 3df77ee7374a7..262ac240a773f 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -627,6 +627,59 @@ struct InstructionBreakpoint { bool fromJSON(const llvm::json::Value &, InstructionBreakpoint &, llvm::json::Path); +/// Properties of a single disassembled instruction, returned by `disassemble` request. +struct DisassembledInstruction { + enum PresentationHint : unsigned { + eSourcePresentationHintNormal, + eSourcePresentationHintInvalid, + }; + + /// The address of the instruction. Treated as a hex value if prefixed with + /// `0x`, or as a decimal value otherwise. + std::string address; + + /// Raw bytes representing the instruction and its operands, in an + /// implementation-defined format. + std::optional instructionBytes; + + /// Text representing the instruction and its operands, in an + /// implementation-defined format. + std::string instruction; + + /// Name of the symbol that corresponds with the location of this instruction, + /// if any. + std::optional symbol; + + /// Source location that corresponds to this instruction, if any. + /// Should always be set (if available) on the first instruction returned, + /// but can be omitted afterwards if this instruction maps to the same source + /// file as the previous instruction. + std::optional location; + + /// The line within the source location that corresponds to this instruction, + /// if any. + std::optional line; + + /// The column within the line that corresponds to this instruction, if any. + std::optional column; + + /// The end line of the range that corresponds to this instruction, if any. + std::optional endLine; + + /// The end column of the range that corresponds to this instruction, if any. + std::optional endColumn; + + /// A hint for how to present the instruction in the UI. + /// + /// A value of `invalid` may be used to indicate this instruction is 'filler' + /// and cannot be reached by the program. For example, unreadable memory + /// addresses may be presented is 'invalid.' + /// Values: 'normal', 'invalid' + std::optional presentationHint; +}; +llvm::json::Value toJSON(const DisassembledInstruction::PresentationHint &); +llvm::json::Value toJSON(const DisassembledInstruction &); + } // namespace lldb_dap::protocol #endif From lldb-commits at lists.llvm.org Sun May 18 14:53:21 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sun, 18 May 2025 14:53:21 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Migrate disassemble request to structured handler (PR #140482) In-Reply-To: Message-ID: <682a56d1.a70a0220.125144.d810@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lldb Author: Ely Ronnen (eronnen)
Changes --- Full diff: https://github.com/llvm/llvm-project/pull/140482.diff 6 Files Affected: - (modified) lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp (+39-137) - (modified) lldb/tools/lldb-dap/Handler/RequestHandler.h (+4-3) - (modified) lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp (+18) - (modified) lldb/tools/lldb-dap/Protocol/ProtocolRequests.h (+31) - (modified) lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp (+34) - (modified) lldb/tools/lldb-dap/Protocol/ProtocolTypes.h (+53) ``````````diff diff --git a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp index d738f54ff1a9f..9df831c8b8c61 100644 --- a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp @@ -9,113 +9,30 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "Protocol/ProtocolRequests.h" +#include "Protocol/ProtocolTypes.h" #include "RequestHandler.h" #include "lldb/API/SBInstruction.h" #include "llvm/ADT/StringExtras.h" +using namespace lldb_dap::protocol; + namespace lldb_dap { -// "DisassembleRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Disassembles code stored at the provided -// location.\nClients should only call this request if the corresponding -// capability `supportsDisassembleRequest` is true.", "properties": { -// "command": { -// "type": "string", -// "enum": [ "disassemble" ] -// }, -// "arguments": { -// "$ref": "#/definitions/DisassembleArguments" -// } -// }, -// "required": [ "command", "arguments" ] -// }] -// }, -// "DisassembleArguments": { -// "type": "object", -// "description": "Arguments for `disassemble` request.", -// "properties": { -// "memoryReference": { -// "type": "string", -// "description": "Memory reference to the base location containing the -// instructions to disassemble." -// }, -// "offset": { -// "type": "integer", -// "description": "Offset (in bytes) to be applied to the reference -// location before disassembling. Can be negative." -// }, -// "instructionOffset": { -// "type": "integer", -// "description": "Offset (in instructions) to be applied after the byte -// offset (if any) before disassembling. Can be negative." -// }, -// "instructionCount": { -// "type": "integer", -// "description": "Number of instructions to disassemble starting at the -// specified location and offset.\nAn adapter must return exactly this -// number of instructions - any unavailable instructions should be -// replaced with an implementation-defined 'invalid instruction' value." -// }, -// "resolveSymbols": { -// "type": "boolean", -// "description": "If true, the adapter should attempt to resolve memory -// addresses and other values to symbolic names." -// } -// }, -// "required": [ "memoryReference", "instructionCount" ] -// }, -// "DisassembleResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to `disassemble` request.", -// "properties": { -// "body": { -// "type": "object", -// "properties": { -// "instructions": { -// "type": "array", -// "items": { -// "$ref": "#/definitions/DisassembledInstruction" -// }, -// "description": "The list of disassembled instructions." -// } -// }, -// "required": [ "instructions" ] -// } -// } -// }] -// } -void DisassembleRequestHandler::operator()( - const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - auto *arguments = request.getObject("arguments"); - - llvm::StringRef memoryReference = - GetString(arguments, "memoryReference").value_or(""); - auto addr_opt = DecodeMemoryReference(memoryReference); - if (!addr_opt.has_value()) { - response["success"] = false; - response["message"] = - "Malformed memory reference: " + memoryReference.str(); - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } - lldb::addr_t addr_ptr = *addr_opt; +/// Disassembles code stored at the provided location. +/// Clients should only call this request if the corresponding capability `supportsDisassembleRequest` is true. +llvm::Expected DisassembleRequestHandler::Run(const DisassembleArguments &args) const { + std::vector instructions; - addr_ptr += GetInteger(arguments, "instructionOffset").value_or(0); + auto addr_opt = DecodeMemoryReference(args.memoryReference); + if (!addr_opt.has_value()) + return llvm::make_error("Malformed memory reference: " + args.memoryReference); + + lldb::addr_t addr_ptr = *addr_opt; + addr_ptr += args.instructionOffset.value_or(0); lldb::SBAddress addr(addr_ptr, dap.target); - if (!addr.IsValid()) { - response["success"] = false; - response["message"] = "Memory reference not found in the current binary."; - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } - - const auto inst_count = - GetInteger(arguments, "instructionCount").value_or(0); + if (!addr.IsValid()) + return llvm::make_error("Memory reference not found in the current binary."); std::string flavor_string; const auto target_triple = llvm::StringRef(dap.target.GetTriple()); @@ -133,18 +50,12 @@ void DisassembleRequestHandler::operator()( } lldb::SBInstructionList insts = - dap.target.ReadInstructions(addr, inst_count, flavor_string.c_str()); + dap.target.ReadInstructions(addr, args.instructionCount, flavor_string.c_str()); - if (!insts.IsValid()) { - response["success"] = false; - response["message"] = "Failed to find instructions for memory address."; - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } + if (!insts.IsValid()) + return llvm::make_error("Failed to find instructions for memory address."); - const bool resolveSymbols = - GetBoolean(arguments, "resolveSymbols").value_or(false); - llvm::json::Array instructions; + const bool resolveSymbols = args.resolveSymbols.value_or(false); const auto num_insts = insts.GetSize(); for (size_t i = 0; i < num_insts; ++i) { lldb::SBInstruction inst = insts.GetInstructionAtIndex(i); @@ -165,11 +76,9 @@ void DisassembleRequestHandler::operator()( } } - llvm::json::Object disassembled_inst{ - {"address", "0x" + llvm::utohexstr(inst_addr)}, - {"instructionBytes", - bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : ""}, - }; + DisassembledInstruction disassembled_inst; + disassembled_inst.address = "0x" + llvm::utohexstr(inst_addr); + disassembled_inst.instructionBytes = bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : ""; std::string instruction; llvm::raw_string_ostream si(instruction); @@ -185,9 +94,8 @@ void DisassembleRequestHandler::operator()( : symbol.GetName()) << ": "; - if (resolveSymbols) { - disassembled_inst.try_emplace("symbol", symbol.GetDisplayName()); - } + if (resolveSymbols) + disassembled_inst.symbol = symbol.GetDisplayName(); } si << llvm::formatv("{0,7} {1,12}", m, o); @@ -195,7 +103,7 @@ void DisassembleRequestHandler::operator()( si << " ; " << c; } - disassembled_inst.try_emplace("instruction", instruction); + disassembled_inst.instruction = instruction; auto line_entry = addr.GetLineEntry(); // If the line number is 0 then the entry represents a compiler generated @@ -203,41 +111,35 @@ void DisassembleRequestHandler::operator()( if (line_entry.GetStartAddress() == addr && line_entry.IsValid() && line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) { auto source = CreateSource(line_entry); - disassembled_inst.try_emplace("location", source); + disassembled_inst.location = std::move(source); const auto line = line_entry.GetLine(); - if (line && line != LLDB_INVALID_LINE_NUMBER) { - disassembled_inst.try_emplace("line", line); - } + if (line != 0 && line != LLDB_INVALID_LINE_NUMBER) + disassembled_inst.line = line; + const auto column = line_entry.GetColumn(); - if (column && column != LLDB_INVALID_COLUMN_NUMBER) { - disassembled_inst.try_emplace("column", column); - } + if (column != 0 && column != LLDB_INVALID_COLUMN_NUMBER) + disassembled_inst.column = column; auto end_line_entry = line_entry.GetEndAddress().GetLineEntry(); if (end_line_entry.IsValid() && end_line_entry.GetFileSpec() == line_entry.GetFileSpec()) { const auto end_line = end_line_entry.GetLine(); - if (end_line && end_line != LLDB_INVALID_LINE_NUMBER && - end_line != line) { - disassembled_inst.try_emplace("endLine", end_line); + if (end_line != 0 && end_line != LLDB_INVALID_LINE_NUMBER && end_line != line) { + disassembled_inst.endLine = end_line; const auto end_column = end_line_entry.GetColumn(); - if (end_column && end_column != LLDB_INVALID_COLUMN_NUMBER && - end_column != column) { - disassembled_inst.try_emplace("endColumn", end_column - 1); - } + if (end_column != 0 && end_column != LLDB_INVALID_COLUMN_NUMBER && + end_column != column) + disassembled_inst.endColumn = end_column - 1; } } } - instructions.emplace_back(std::move(disassembled_inst)); + instructions.push_back(std::move(disassembled_inst)); } - llvm::json::Object body; - body.try_emplace("instructions", std::move(instructions)); - response.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(response))); + return DisassembleResponseBody{std::move(instructions)}; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index e6bccfe12f402..09bedb88d6b09 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -534,14 +534,15 @@ class LocationsRequestHandler : public LegacyRequestHandler { void operator()(const llvm::json::Object &request) const override; }; -class DisassembleRequestHandler : public LegacyRequestHandler { +class DisassembleRequestHandler final : public RequestHandler> { public: - using LegacyRequestHandler::LegacyRequestHandler; + using RequestHandler::RequestHandler; static llvm::StringLiteral GetCommand() { return "disassemble"; } FeatureSet GetSupportedFeatures() const override { return {protocol::eAdapterFeatureDisassembleRequest}; } - void operator()(const llvm::json::Object &request) const override; + llvm::Expected + Run(const protocol::DisassembleArguments &args) const override; }; class ReadMemoryRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp index 7efab87d39986..4160077d419e1 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp @@ -460,4 +460,22 @@ llvm::json::Value toJSON(const SetDataBreakpointsResponseBody &SDBR) { return result; } +bool fromJSON(const llvm::json::Value &Params, DisassembleArguments &DA, + llvm::json::Path P) { + json::ObjectMapper O(Params, P); + return O && O.map("memoryReference", DA.memoryReference) && + O.mapOptional("offset", DA.offset) && + O.mapOptional("instructionOffset", DA.instructionOffset) && + O.map("instructionCount", DA.instructionCount) && + O.mapOptional("resolveSymbols", DA.resolveSymbols); +} + +llvm::json::Value toJSON(const DisassembleResponseBody &DRB) { + llvm::json::Array instructions; + for (const auto &instruction : DRB.instructions) { + instructions.push_back(toJSON(instruction)); + } + return llvm::json::Object{{"instructions", std::move(instructions)}}; +} + } // namespace lldb_dap::protocol diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index b421c631344de..d48a3a3a14fb7 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -726,6 +726,37 @@ struct SetDataBreakpointsResponseBody { }; llvm::json::Value toJSON(const SetDataBreakpointsResponseBody &); +/// Arguments to `disassemble` request. +struct DisassembleArguments { + /// Memory reference to the base location containing the instructions to disassemble. + std::string memoryReference; + + /// Offset (in bytes) to be applied to the reference location before disassembling. Can be negative. + std::optional offset; + + /// Offset (in instructions) to be applied after the byte offset (if any) before disassembling. Can be negative. + std::optional instructionOffset; + + /// Number of instructions to disassemble starting at the specified location + /// and offset. + /// An adapter must return exactly this number of instructions - any + /// unavailable instructions should be replaced with an implementation-defined + /// 'invalid instruction' value. + uint32_t instructionCount; + + /// If true, the adapter should attempt to resolve memory addresses and other values to symbolic names. + std::optional resolveSymbols; +}; +bool fromJSON(const llvm::json::Value &, DisassembleArguments &, + llvm::json::Path); + +/// Response to `disassemble` request. +struct DisassembleResponseBody { + /// The list of disassembled instructions. + std::vector instructions; +}; +llvm::json::Value toJSON(const DisassembleResponseBody &); + } // namespace lldb_dap::protocol #endif diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index ce7519e3b16b8..94fe236d952a7 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -782,4 +782,38 @@ bool fromJSON(const llvm::json::Value &Params, InstructionBreakpoint &IB, O.mapOptional("mode", IB.mode); } +llvm::json::Value toJSON(const DisassembledInstruction::PresentationHint &PH) { + switch (PH) { + case DisassembledInstruction::eSourcePresentationHintNormal: + return "normal"; + case DisassembledInstruction::eSourcePresentationHintInvalid: + return "invalid"; + } + llvm_unreachable("unhandled presentation hint."); +} + +llvm::json::Value toJSON(const DisassembledInstruction &DI) { + llvm::json::Object result{{"address", DI.address}, + {"instruction", DI.instruction}}; + + if (DI.instructionBytes) + result.insert({"instructionBytes", *DI.instructionBytes}); + if (DI.symbol) + result.insert({"symbol", *DI.symbol}); + if (DI.location) + result.insert({"location", *DI.location}); + if (DI.line) + result.insert({"line", *DI.line}); + if (DI.column) + result.insert({"column", *DI.column}); + if (DI.endLine) + result.insert({"endLine", *DI.endLine}); + if (DI.endColumn) + result.insert({"endColumn", *DI.endColumn}); + if (DI.presentationHint) + result.insert({"presentationHint", *DI.presentationHint}); + + return result; +} + } // namespace lldb_dap::protocol diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index 3df77ee7374a7..262ac240a773f 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -627,6 +627,59 @@ struct InstructionBreakpoint { bool fromJSON(const llvm::json::Value &, InstructionBreakpoint &, llvm::json::Path); +/// Properties of a single disassembled instruction, returned by `disassemble` request. +struct DisassembledInstruction { + enum PresentationHint : unsigned { + eSourcePresentationHintNormal, + eSourcePresentationHintInvalid, + }; + + /// The address of the instruction. Treated as a hex value if prefixed with + /// `0x`, or as a decimal value otherwise. + std::string address; + + /// Raw bytes representing the instruction and its operands, in an + /// implementation-defined format. + std::optional instructionBytes; + + /// Text representing the instruction and its operands, in an + /// implementation-defined format. + std::string instruction; + + /// Name of the symbol that corresponds with the location of this instruction, + /// if any. + std::optional symbol; + + /// Source location that corresponds to this instruction, if any. + /// Should always be set (if available) on the first instruction returned, + /// but can be omitted afterwards if this instruction maps to the same source + /// file as the previous instruction. + std::optional location; + + /// The line within the source location that corresponds to this instruction, + /// if any. + std::optional line; + + /// The column within the line that corresponds to this instruction, if any. + std::optional column; + + /// The end line of the range that corresponds to this instruction, if any. + std::optional endLine; + + /// The end column of the range that corresponds to this instruction, if any. + std::optional endColumn; + + /// A hint for how to present the instruction in the UI. + /// + /// A value of `invalid` may be used to indicate this instruction is 'filler' + /// and cannot be reached by the program. For example, unreadable memory + /// addresses may be presented is 'invalid.' + /// Values: 'normal', 'invalid' + std::optional presentationHint; +}; +llvm::json::Value toJSON(const DisassembledInstruction::PresentationHint &); +llvm::json::Value toJSON(const DisassembledInstruction &); + } // namespace lldb_dap::protocol #endif ``````````
https://github.com/llvm/llvm-project/pull/140482 From lldb-commits at lists.llvm.org Sun May 18 14:53:22 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 14:53:22 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Migrate disassemble request to structured handler (PR #140482) In-Reply-To: Message-ID: <682a56d2.170a0220.76a6f.013b@mx.google.com> https://github.com/eronnen updated https://github.com/llvm/llvm-project/pull/140482 >From 1014235896b79eb4ea05a6822714a66adaa691ac Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 23:51:58 +0200 Subject: [PATCH] [lldb-dap] Migrate disassemble request to structured handler --- .../Handler/DisassembleRequestHandler.cpp | 183 +++++------------- lldb/tools/lldb-dap/Handler/RequestHandler.h | 9 +- .../lldb-dap/Protocol/ProtocolRequests.cpp | 18 ++ .../lldb-dap/Protocol/ProtocolRequests.h | 35 ++++ .../tools/lldb-dap/Protocol/ProtocolTypes.cpp | 34 ++++ lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 54 ++++++ 6 files changed, 193 insertions(+), 140 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp index d738f54ff1a9f..938078947259b 100644 --- a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp @@ -9,113 +9,34 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "Protocol/ProtocolRequests.h" +#include "Protocol/ProtocolTypes.h" #include "RequestHandler.h" #include "lldb/API/SBInstruction.h" #include "llvm/ADT/StringExtras.h" +using namespace lldb_dap::protocol; + namespace lldb_dap { -// "DisassembleRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Disassembles code stored at the provided -// location.\nClients should only call this request if the corresponding -// capability `supportsDisassembleRequest` is true.", "properties": { -// "command": { -// "type": "string", -// "enum": [ "disassemble" ] -// }, -// "arguments": { -// "$ref": "#/definitions/DisassembleArguments" -// } -// }, -// "required": [ "command", "arguments" ] -// }] -// }, -// "DisassembleArguments": { -// "type": "object", -// "description": "Arguments for `disassemble` request.", -// "properties": { -// "memoryReference": { -// "type": "string", -// "description": "Memory reference to the base location containing the -// instructions to disassemble." -// }, -// "offset": { -// "type": "integer", -// "description": "Offset (in bytes) to be applied to the reference -// location before disassembling. Can be negative." -// }, -// "instructionOffset": { -// "type": "integer", -// "description": "Offset (in instructions) to be applied after the byte -// offset (if any) before disassembling. Can be negative." -// }, -// "instructionCount": { -// "type": "integer", -// "description": "Number of instructions to disassemble starting at the -// specified location and offset.\nAn adapter must return exactly this -// number of instructions - any unavailable instructions should be -// replaced with an implementation-defined 'invalid instruction' value." -// }, -// "resolveSymbols": { -// "type": "boolean", -// "description": "If true, the adapter should attempt to resolve memory -// addresses and other values to symbolic names." -// } -// }, -// "required": [ "memoryReference", "instructionCount" ] -// }, -// "DisassembleResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to `disassemble` request.", -// "properties": { -// "body": { -// "type": "object", -// "properties": { -// "instructions": { -// "type": "array", -// "items": { -// "$ref": "#/definitions/DisassembledInstruction" -// }, -// "description": "The list of disassembled instructions." -// } -// }, -// "required": [ "instructions" ] -// } -// } -// }] -// } -void DisassembleRequestHandler::operator()( - const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - auto *arguments = request.getObject("arguments"); - - llvm::StringRef memoryReference = - GetString(arguments, "memoryReference").value_or(""); - auto addr_opt = DecodeMemoryReference(memoryReference); - if (!addr_opt.has_value()) { - response["success"] = false; - response["message"] = - "Malformed memory reference: " + memoryReference.str(); - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } - lldb::addr_t addr_ptr = *addr_opt; +/// Disassembles code stored at the provided location. +/// Clients should only call this request if the corresponding capability +/// `supportsDisassembleRequest` is true. +llvm::Expected +DisassembleRequestHandler::Run(const DisassembleArguments &args) const { + std::vector instructions; - addr_ptr += GetInteger(arguments, "instructionOffset").value_or(0); - lldb::SBAddress addr(addr_ptr, dap.target); - if (!addr.IsValid()) { - response["success"] = false; - response["message"] = "Memory reference not found in the current binary."; - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } + auto addr_opt = DecodeMemoryReference(args.memoryReference); + if (!addr_opt.has_value()) + return llvm::make_error("Malformed memory reference: " + + args.memoryReference); - const auto inst_count = - GetInteger(arguments, "instructionCount").value_or(0); + lldb::addr_t addr_ptr = *addr_opt; + addr_ptr += args.instructionOffset.value_or(0); + lldb::SBAddress addr(addr_ptr, dap.target); + if (!addr.IsValid()) + return llvm::make_error( + "Memory reference not found in the current binary."); std::string flavor_string; const auto target_triple = llvm::StringRef(dap.target.GetTriple()); @@ -132,19 +53,14 @@ void DisassembleRequestHandler::operator()( } } - lldb::SBInstructionList insts = - dap.target.ReadInstructions(addr, inst_count, flavor_string.c_str()); + lldb::SBInstructionList insts = dap.target.ReadInstructions( + addr, args.instructionCount, flavor_string.c_str()); - if (!insts.IsValid()) { - response["success"] = false; - response["message"] = "Failed to find instructions for memory address."; - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } + if (!insts.IsValid()) + return llvm::make_error( + "Failed to find instructions for memory address."); - const bool resolveSymbols = - GetBoolean(arguments, "resolveSymbols").value_or(false); - llvm::json::Array instructions; + const bool resolveSymbols = args.resolveSymbols.value_or(false); const auto num_insts = insts.GetSize(); for (size_t i = 0; i < num_insts; ++i) { lldb::SBInstruction inst = insts.GetInstructionAtIndex(i); @@ -165,11 +81,10 @@ void DisassembleRequestHandler::operator()( } } - llvm::json::Object disassembled_inst{ - {"address", "0x" + llvm::utohexstr(inst_addr)}, - {"instructionBytes", - bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : ""}, - }; + DisassembledInstruction disassembled_inst; + disassembled_inst.address = "0x" + llvm::utohexstr(inst_addr); + disassembled_inst.instructionBytes = + bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : ""; std::string instruction; llvm::raw_string_ostream si(instruction); @@ -185,9 +100,8 @@ void DisassembleRequestHandler::operator()( : symbol.GetName()) << ": "; - if (resolveSymbols) { - disassembled_inst.try_emplace("symbol", symbol.GetDisplayName()); - } + if (resolveSymbols) + disassembled_inst.symbol = symbol.GetDisplayName(); } si << llvm::formatv("{0,7} {1,12}", m, o); @@ -195,7 +109,7 @@ void DisassembleRequestHandler::operator()( si << " ; " << c; } - disassembled_inst.try_emplace("instruction", instruction); + disassembled_inst.instruction = instruction; auto line_entry = addr.GetLineEntry(); // If the line number is 0 then the entry represents a compiler generated @@ -203,41 +117,36 @@ void DisassembleRequestHandler::operator()( if (line_entry.GetStartAddress() == addr && line_entry.IsValid() && line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) { auto source = CreateSource(line_entry); - disassembled_inst.try_emplace("location", source); + disassembled_inst.location = std::move(source); const auto line = line_entry.GetLine(); - if (line && line != LLDB_INVALID_LINE_NUMBER) { - disassembled_inst.try_emplace("line", line); - } + if (line != 0 && line != LLDB_INVALID_LINE_NUMBER) + disassembled_inst.line = line; + const auto column = line_entry.GetColumn(); - if (column && column != LLDB_INVALID_COLUMN_NUMBER) { - disassembled_inst.try_emplace("column", column); - } + if (column != 0 && column != LLDB_INVALID_COLUMN_NUMBER) + disassembled_inst.column = column; auto end_line_entry = line_entry.GetEndAddress().GetLineEntry(); if (end_line_entry.IsValid() && end_line_entry.GetFileSpec() == line_entry.GetFileSpec()) { const auto end_line = end_line_entry.GetLine(); - if (end_line && end_line != LLDB_INVALID_LINE_NUMBER && + if (end_line != 0 && end_line != LLDB_INVALID_LINE_NUMBER && end_line != line) { - disassembled_inst.try_emplace("endLine", end_line); + disassembled_inst.endLine = end_line; const auto end_column = end_line_entry.GetColumn(); - if (end_column && end_column != LLDB_INVALID_COLUMN_NUMBER && - end_column != column) { - disassembled_inst.try_emplace("endColumn", end_column - 1); - } + if (end_column != 0 && end_column != LLDB_INVALID_COLUMN_NUMBER && + end_column != column) + disassembled_inst.endColumn = end_column - 1; } } } - instructions.emplace_back(std::move(disassembled_inst)); + instructions.push_back(std::move(disassembled_inst)); } - llvm::json::Object body; - body.try_emplace("instructions", std::move(instructions)); - response.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(response))); + return DisassembleResponseBody{std::move(instructions)}; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index e6bccfe12f402..998b98137a1ea 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -534,14 +534,17 @@ class LocationsRequestHandler : public LegacyRequestHandler { void operator()(const llvm::json::Object &request) const override; }; -class DisassembleRequestHandler : public LegacyRequestHandler { +class DisassembleRequestHandler final + : public RequestHandler> { public: - using LegacyRequestHandler::LegacyRequestHandler; + using RequestHandler::RequestHandler; static llvm::StringLiteral GetCommand() { return "disassemble"; } FeatureSet GetSupportedFeatures() const override { return {protocol::eAdapterFeatureDisassembleRequest}; } - void operator()(const llvm::json::Object &request) const override; + llvm::Expected + Run(const protocol::DisassembleArguments &args) const override; }; class ReadMemoryRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp index 7efab87d39986..4160077d419e1 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp @@ -460,4 +460,22 @@ llvm::json::Value toJSON(const SetDataBreakpointsResponseBody &SDBR) { return result; } +bool fromJSON(const llvm::json::Value &Params, DisassembleArguments &DA, + llvm::json::Path P) { + json::ObjectMapper O(Params, P); + return O && O.map("memoryReference", DA.memoryReference) && + O.mapOptional("offset", DA.offset) && + O.mapOptional("instructionOffset", DA.instructionOffset) && + O.map("instructionCount", DA.instructionCount) && + O.mapOptional("resolveSymbols", DA.resolveSymbols); +} + +llvm::json::Value toJSON(const DisassembleResponseBody &DRB) { + llvm::json::Array instructions; + for (const auto &instruction : DRB.instructions) { + instructions.push_back(toJSON(instruction)); + } + return llvm::json::Object{{"instructions", std::move(instructions)}}; +} + } // namespace lldb_dap::protocol diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index b421c631344de..c41f3a7296563 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -726,6 +726,41 @@ struct SetDataBreakpointsResponseBody { }; llvm::json::Value toJSON(const SetDataBreakpointsResponseBody &); +/// Arguments to `disassemble` request. +struct DisassembleArguments { + /// Memory reference to the base location containing the instructions to + /// disassemble. + std::string memoryReference; + + /// Offset (in bytes) to be applied to the reference location before + /// disassembling. Can be negative. + std::optional offset; + + /// Offset (in instructions) to be applied after the byte offset (if any) + /// before disassembling. Can be negative. + std::optional instructionOffset; + + /// Number of instructions to disassemble starting at the specified location + /// and offset. + /// An adapter must return exactly this number of instructions - any + /// unavailable instructions should be replaced with an implementation-defined + /// 'invalid instruction' value. + uint32_t instructionCount; + + /// If true, the adapter should attempt to resolve memory addresses and other + /// values to symbolic names. + std::optional resolveSymbols; +}; +bool fromJSON(const llvm::json::Value &, DisassembleArguments &, + llvm::json::Path); + +/// Response to `disassemble` request. +struct DisassembleResponseBody { + /// The list of disassembled instructions. + std::vector instructions; +}; +llvm::json::Value toJSON(const DisassembleResponseBody &); + } // namespace lldb_dap::protocol #endif diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index ce7519e3b16b8..94fe236d952a7 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -782,4 +782,38 @@ bool fromJSON(const llvm::json::Value &Params, InstructionBreakpoint &IB, O.mapOptional("mode", IB.mode); } +llvm::json::Value toJSON(const DisassembledInstruction::PresentationHint &PH) { + switch (PH) { + case DisassembledInstruction::eSourcePresentationHintNormal: + return "normal"; + case DisassembledInstruction::eSourcePresentationHintInvalid: + return "invalid"; + } + llvm_unreachable("unhandled presentation hint."); +} + +llvm::json::Value toJSON(const DisassembledInstruction &DI) { + llvm::json::Object result{{"address", DI.address}, + {"instruction", DI.instruction}}; + + if (DI.instructionBytes) + result.insert({"instructionBytes", *DI.instructionBytes}); + if (DI.symbol) + result.insert({"symbol", *DI.symbol}); + if (DI.location) + result.insert({"location", *DI.location}); + if (DI.line) + result.insert({"line", *DI.line}); + if (DI.column) + result.insert({"column", *DI.column}); + if (DI.endLine) + result.insert({"endLine", *DI.endLine}); + if (DI.endColumn) + result.insert({"endColumn", *DI.endColumn}); + if (DI.presentationHint) + result.insert({"presentationHint", *DI.presentationHint}); + + return result; +} + } // namespace lldb_dap::protocol diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index 3df77ee7374a7..5c6858904a3cf 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -627,6 +627,60 @@ struct InstructionBreakpoint { bool fromJSON(const llvm::json::Value &, InstructionBreakpoint &, llvm::json::Path); +/// Properties of a single disassembled instruction, returned by `disassemble` +/// request. +struct DisassembledInstruction { + enum PresentationHint : unsigned { + eSourcePresentationHintNormal, + eSourcePresentationHintInvalid, + }; + + /// The address of the instruction. Treated as a hex value if prefixed with + /// `0x`, or as a decimal value otherwise. + std::string address; + + /// Raw bytes representing the instruction and its operands, in an + /// implementation-defined format. + std::optional instructionBytes; + + /// Text representing the instruction and its operands, in an + /// implementation-defined format. + std::string instruction; + + /// Name of the symbol that corresponds with the location of this instruction, + /// if any. + std::optional symbol; + + /// Source location that corresponds to this instruction, if any. + /// Should always be set (if available) on the first instruction returned, + /// but can be omitted afterwards if this instruction maps to the same source + /// file as the previous instruction. + std::optional location; + + /// The line within the source location that corresponds to this instruction, + /// if any. + std::optional line; + + /// The column within the line that corresponds to this instruction, if any. + std::optional column; + + /// The end line of the range that corresponds to this instruction, if any. + std::optional endLine; + + /// The end column of the range that corresponds to this instruction, if any. + std::optional endColumn; + + /// A hint for how to present the instruction in the UI. + /// + /// A value of `invalid` may be used to indicate this instruction is 'filler' + /// and cannot be reached by the program. For example, unreadable memory + /// addresses may be presented is 'invalid.' + /// Values: 'normal', 'invalid' + std::optional presentationHint; +}; +llvm::json::Value toJSON(const DisassembledInstruction::PresentationHint &); +llvm::json::Value toJSON(const DisassembledInstruction &); + } // namespace lldb_dap::protocol #endif From lldb-commits at lists.llvm.org Sun May 18 16:35:03 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Sun, 18 May 2025 16:35:03 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Move the command plugins out of the DAP header (PR #140396) In-Reply-To: Message-ID: <682a6ea7.170a0220.22a144.b4f3@mx.google.com> https://github.com/ashgti approved this pull request. https://github.com/llvm/llvm-project/pull/140396 From lldb-commits at lists.llvm.org Sun May 18 16:39:03 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Sun, 18 May 2025 16:39:03 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for FifoFiles (PR #140480) In-Reply-To: Message-ID: <682a6f97.630a0220.30548b.fb5e@mx.google.com> https://github.com/ashgti edited https://github.com/llvm/llvm-project/pull/140480 From lldb-commits at lists.llvm.org Sun May 18 16:39:04 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Sun, 18 May 2025 16:39:04 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for FifoFiles (PR #140480) In-Reply-To: Message-ID: <682a6f98.170a0220.1c8301.d82a@mx.google.com> https://github.com/ashgti approved this pull request. LGTM, one question about the timeouts https://github.com/llvm/llvm-project/pull/140480 From lldb-commits at lists.llvm.org Sun May 18 16:39:05 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Sun, 18 May 2025 16:39:05 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for FifoFiles (PR #140480) In-Reply-To: Message-ID: <682a6f99.170a0220.1251e7.c0d1@mx.google.com> ================ @@ -0,0 +1,102 @@ +//===-- FifoFilesTest.cpp -------------------------------------------------===// +// +// 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 "FifoFiles.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include + +using namespace lldb_dap; +using namespace llvm; + +namespace { + +std::string MakeTempFifoPath() { + llvm::SmallString<128> temp_path; + llvm::sys::fs::createUniquePath("lldb-dap-fifo-%%%%%%", temp_path, + /*MakeAbsolute=*/true); + return temp_path.str().str(); +} + +} // namespace + +TEST(FifoFilesTest, CreateAndDestroyFifoFile) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + // File should exist. + EXPECT_TRUE(llvm::sys::fs::exists(fifo_path)); + + // Destructor should remove the file. + fifo->reset(); + EXPECT_FALSE(llvm::sys::fs::exists(fifo_path)); +} + +TEST(FifoFilesTest, SendAndReceiveJSON) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + FifoFileIO writer(fifo_path, "writer"); + FifoFileIO reader(fifo_path, "reader"); + + llvm::json::Object obj; + obj["foo"] = "bar"; + obj["num"] = 42; + + // Writer thread. + std::thread writer_thread([&]() { + EXPECT_THAT_ERROR(writer.SendJSON(llvm::json::Value(std::move(obj)), + std::chrono::milliseconds(500)), + llvm::Succeeded()); + }); + + // Reader thread. + std::thread reader_thread([&]() { + auto result = reader.ReadJSON(std::chrono::milliseconds(500)); + EXPECT_THAT_EXPECTED(result, llvm::Succeeded()); + auto *read_obj = result->getAsObject(); + + ASSERT_NE(read_obj, nullptr); + EXPECT_EQ((*read_obj)["foo"].getAsString(), "bar"); + EXPECT_EQ((*read_obj)["num"].getAsInteger(), 42); + }); + + writer_thread.join(); + reader_thread.join(); +} + +TEST(FifoFilesTest, ReadTimeout) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + FifoFileIO reader(fifo_path, "reader"); + + // No writer, should timeout. + auto result = reader.ReadJSON(std::chrono::milliseconds(100)); ---------------- ashgti wrote: Since we're expecting this to fail, should we shorten this timeout to like 1 ms? https://github.com/llvm/llvm-project/pull/140480 From lldb-commits at lists.llvm.org Sun May 18 16:39:05 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Sun, 18 May 2025 16:39:05 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for FifoFiles (PR #140480) In-Reply-To: Message-ID: <682a6f99.630a0220.29b44.0510@mx.google.com> ================ @@ -0,0 +1,102 @@ +//===-- FifoFilesTest.cpp -------------------------------------------------===// +// +// 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 "FifoFiles.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include + +using namespace lldb_dap; +using namespace llvm; + +namespace { + +std::string MakeTempFifoPath() { + llvm::SmallString<128> temp_path; + llvm::sys::fs::createUniquePath("lldb-dap-fifo-%%%%%%", temp_path, + /*MakeAbsolute=*/true); + return temp_path.str().str(); +} + +} // namespace + +TEST(FifoFilesTest, CreateAndDestroyFifoFile) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + // File should exist. + EXPECT_TRUE(llvm::sys::fs::exists(fifo_path)); + + // Destructor should remove the file. + fifo->reset(); + EXPECT_FALSE(llvm::sys::fs::exists(fifo_path)); +} + +TEST(FifoFilesTest, SendAndReceiveJSON) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + FifoFileIO writer(fifo_path, "writer"); + FifoFileIO reader(fifo_path, "reader"); + + llvm::json::Object obj; + obj["foo"] = "bar"; + obj["num"] = 42; + + // Writer thread. + std::thread writer_thread([&]() { + EXPECT_THAT_ERROR(writer.SendJSON(llvm::json::Value(std::move(obj)), + std::chrono::milliseconds(500)), + llvm::Succeeded()); + }); + + // Reader thread. + std::thread reader_thread([&]() { + auto result = reader.ReadJSON(std::chrono::milliseconds(500)); + EXPECT_THAT_EXPECTED(result, llvm::Succeeded()); + auto *read_obj = result->getAsObject(); + + ASSERT_NE(read_obj, nullptr); + EXPECT_EQ((*read_obj)["foo"].getAsString(), "bar"); + EXPECT_EQ((*read_obj)["num"].getAsInteger(), 42); + }); + + writer_thread.join(); + reader_thread.join(); +} + +TEST(FifoFilesTest, ReadTimeout) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + FifoFileIO reader(fifo_path, "reader"); + + // No writer, should timeout. + auto result = reader.ReadJSON(std::chrono::milliseconds(100)); + EXPECT_THAT_EXPECTED(result, llvm::Failed()); +} + +TEST(FifoFilesTest, WriteTimeout) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + FifoFileIO writer(fifo_path, "writer"); + + // No reader, should timeout. + llvm::json::Object obj; + obj["foo"] = "bar"; + EXPECT_THAT_ERROR(writer.SendJSON(llvm::json::Value(std::move(obj)), + std::chrono::milliseconds(100)), ---------------- ashgti wrote: Same as above https://github.com/llvm/llvm-project/pull/140480 From lldb-commits at lists.llvm.org Sun May 18 16:51:39 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Sun, 18 May 2025 16:51:39 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Synchronously wait for breakpoints resolves in tests (PR #140470) In-Reply-To: Message-ID: <682a728b.620a0220.dc029.d42f@mx.google.com> ================ @@ -1187,15 +1187,17 @@ def request_locations(self, locationReference): } return self.send_recv(command_dict) - def request_testGetTargetBreakpoints(self): + def request_testGetTargetBreakpoints(self, only_resolved=False): ---------------- ashgti wrote: I'm not sure we need to extend this, we could track the current state of breakpoints in `DebugCommunication` by updating `_handle_recv_packet` to check for breakpoint events and by updating `request_setBreakpoints` (and other kinds of breakpoints functions) to update the state when they get a response from the server. We could have a helper for getting the current state of a breakpoint by id and move `wait_for_breakpoints_to_resolve` into to `DebugCommunication`. https://github.com/llvm/llvm-project/pull/140470 From lldb-commits at lists.llvm.org Sun May 18 16:51:40 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Sun, 18 May 2025 16:51:40 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Synchronously wait for breakpoints resolves in tests (PR #140470) In-Reply-To: Message-ID: <682a728c.a70a0220.1ad578.c84d@mx.google.com> ================ @@ -78,8 +84,40 @@ def set_function_breakpoints(self, functions, condition=None, hitCondition=None) breakpoint_ids = [] for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) + if wait_for_resolve: + self.wait_for_breakpoints_to_resolve(breakpoint_ids, timeout=10) return breakpoint_ids + def wait_for_breakpoints_to_resolve( ---------------- ashgti wrote: Should we move this to `DebugCommunication` in dap_server.py? We already have helpers like `wait_for_stopped`, so this feels similar. https://github.com/llvm/llvm-project/pull/140470 From lldb-commits at lists.llvm.org Sun May 18 16:51:40 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Sun, 18 May 2025 16:51:40 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Synchronously wait for breakpoints resolves in tests (PR #140470) In-Reply-To: Message-ID: <682a728c.170a0220.826de.b823@mx.google.com> ================ @@ -78,8 +84,40 @@ def set_function_breakpoints(self, functions, condition=None, hitCondition=None) breakpoint_ids = [] for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) + if wait_for_resolve: + self.wait_for_breakpoints_to_resolve(breakpoint_ids, timeout=10) return breakpoint_ids + def wait_for_breakpoints_to_resolve( + self, breakpoint_ids: list[str], timeout: Optional[float] = None + ): + unresolved_breakpoints = set(breakpoint_ids) + + # Check already resolved breakpoints + resolved_breakpoints = self.dap_server.request_testGetTargetBreakpoints( + only_resolved=True + )["body"]["breakpoints"] + for resolved_breakpoint in resolved_breakpoints: + unresolved_breakpoints.discard(str(resolved_breakpoint["id"])) ---------------- ashgti wrote: I think if the we kept track of the client state in the DebugCommunication class we wouldn't need to make this custom request. https://github.com/llvm/llvm-project/pull/140470 From lldb-commits at lists.llvm.org Sun May 18 16:51:40 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Sun, 18 May 2025 16:51:40 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Synchronously wait for breakpoints resolves in tests (PR #140470) In-Reply-To: Message-ID: <682a728c.170a0220.3308d3.1582@mx.google.com> ================ @@ -62,9 +64,13 @@ def set_source_breakpoints(self, source_path, lines, data=None): breakpoint_ids = [] for breakpoint in breakpoints: breakpoint_ids.append("%i" % (breakpoint["id"])) + if wait_for_resolve: + self.wait_for_breakpoints_to_resolve(breakpoint_ids, timeout=10) ---------------- ashgti wrote: Can the timeout be a parameter that defaults to `DEFAULT_TIMEOUT`? https://github.com/llvm/llvm-project/pull/140470 From lldb-commits at lists.llvm.org Sun May 18 16:55:22 2025 From: lldb-commits at lists.llvm.org (Ely Ronnen via lldb-commits) Date: Sun, 18 May 2025 16:55:22 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] fix disassembly request instruction offset handling (PR #140486) Message-ID: https://github.com/eronnen created https://github.com/llvm/llvm-project/pull/140486 None >From 1014235896b79eb4ea05a6822714a66adaa691ac Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 18 May 2025 23:51:58 +0200 Subject: [PATCH 1/2] [lldb-dap] Migrate disassemble request to structured handler --- .../Handler/DisassembleRequestHandler.cpp | 183 +++++------------- lldb/tools/lldb-dap/Handler/RequestHandler.h | 9 +- .../lldb-dap/Protocol/ProtocolRequests.cpp | 18 ++ .../lldb-dap/Protocol/ProtocolRequests.h | 35 ++++ .../tools/lldb-dap/Protocol/ProtocolTypes.cpp | 34 ++++ lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 54 ++++++ 6 files changed, 193 insertions(+), 140 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp index d738f54ff1a9f..938078947259b 100644 --- a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp @@ -9,113 +9,34 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "Protocol/ProtocolRequests.h" +#include "Protocol/ProtocolTypes.h" #include "RequestHandler.h" #include "lldb/API/SBInstruction.h" #include "llvm/ADT/StringExtras.h" +using namespace lldb_dap::protocol; + namespace lldb_dap { -// "DisassembleRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Disassembles code stored at the provided -// location.\nClients should only call this request if the corresponding -// capability `supportsDisassembleRequest` is true.", "properties": { -// "command": { -// "type": "string", -// "enum": [ "disassemble" ] -// }, -// "arguments": { -// "$ref": "#/definitions/DisassembleArguments" -// } -// }, -// "required": [ "command", "arguments" ] -// }] -// }, -// "DisassembleArguments": { -// "type": "object", -// "description": "Arguments for `disassemble` request.", -// "properties": { -// "memoryReference": { -// "type": "string", -// "description": "Memory reference to the base location containing the -// instructions to disassemble." -// }, -// "offset": { -// "type": "integer", -// "description": "Offset (in bytes) to be applied to the reference -// location before disassembling. Can be negative." -// }, -// "instructionOffset": { -// "type": "integer", -// "description": "Offset (in instructions) to be applied after the byte -// offset (if any) before disassembling. Can be negative." -// }, -// "instructionCount": { -// "type": "integer", -// "description": "Number of instructions to disassemble starting at the -// specified location and offset.\nAn adapter must return exactly this -// number of instructions - any unavailable instructions should be -// replaced with an implementation-defined 'invalid instruction' value." -// }, -// "resolveSymbols": { -// "type": "boolean", -// "description": "If true, the adapter should attempt to resolve memory -// addresses and other values to symbolic names." -// } -// }, -// "required": [ "memoryReference", "instructionCount" ] -// }, -// "DisassembleResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to `disassemble` request.", -// "properties": { -// "body": { -// "type": "object", -// "properties": { -// "instructions": { -// "type": "array", -// "items": { -// "$ref": "#/definitions/DisassembledInstruction" -// }, -// "description": "The list of disassembled instructions." -// } -// }, -// "required": [ "instructions" ] -// } -// } -// }] -// } -void DisassembleRequestHandler::operator()( - const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - auto *arguments = request.getObject("arguments"); - - llvm::StringRef memoryReference = - GetString(arguments, "memoryReference").value_or(""); - auto addr_opt = DecodeMemoryReference(memoryReference); - if (!addr_opt.has_value()) { - response["success"] = false; - response["message"] = - "Malformed memory reference: " + memoryReference.str(); - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } - lldb::addr_t addr_ptr = *addr_opt; +/// Disassembles code stored at the provided location. +/// Clients should only call this request if the corresponding capability +/// `supportsDisassembleRequest` is true. +llvm::Expected +DisassembleRequestHandler::Run(const DisassembleArguments &args) const { + std::vector instructions; - addr_ptr += GetInteger(arguments, "instructionOffset").value_or(0); - lldb::SBAddress addr(addr_ptr, dap.target); - if (!addr.IsValid()) { - response["success"] = false; - response["message"] = "Memory reference not found in the current binary."; - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } + auto addr_opt = DecodeMemoryReference(args.memoryReference); + if (!addr_opt.has_value()) + return llvm::make_error("Malformed memory reference: " + + args.memoryReference); - const auto inst_count = - GetInteger(arguments, "instructionCount").value_or(0); + lldb::addr_t addr_ptr = *addr_opt; + addr_ptr += args.instructionOffset.value_or(0); + lldb::SBAddress addr(addr_ptr, dap.target); + if (!addr.IsValid()) + return llvm::make_error( + "Memory reference not found in the current binary."); std::string flavor_string; const auto target_triple = llvm::StringRef(dap.target.GetTriple()); @@ -132,19 +53,14 @@ void DisassembleRequestHandler::operator()( } } - lldb::SBInstructionList insts = - dap.target.ReadInstructions(addr, inst_count, flavor_string.c_str()); + lldb::SBInstructionList insts = dap.target.ReadInstructions( + addr, args.instructionCount, flavor_string.c_str()); - if (!insts.IsValid()) { - response["success"] = false; - response["message"] = "Failed to find instructions for memory address."; - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } + if (!insts.IsValid()) + return llvm::make_error( + "Failed to find instructions for memory address."); - const bool resolveSymbols = - GetBoolean(arguments, "resolveSymbols").value_or(false); - llvm::json::Array instructions; + const bool resolveSymbols = args.resolveSymbols.value_or(false); const auto num_insts = insts.GetSize(); for (size_t i = 0; i < num_insts; ++i) { lldb::SBInstruction inst = insts.GetInstructionAtIndex(i); @@ -165,11 +81,10 @@ void DisassembleRequestHandler::operator()( } } - llvm::json::Object disassembled_inst{ - {"address", "0x" + llvm::utohexstr(inst_addr)}, - {"instructionBytes", - bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : ""}, - }; + DisassembledInstruction disassembled_inst; + disassembled_inst.address = "0x" + llvm::utohexstr(inst_addr); + disassembled_inst.instructionBytes = + bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : ""; std::string instruction; llvm::raw_string_ostream si(instruction); @@ -185,9 +100,8 @@ void DisassembleRequestHandler::operator()( : symbol.GetName()) << ": "; - if (resolveSymbols) { - disassembled_inst.try_emplace("symbol", symbol.GetDisplayName()); - } + if (resolveSymbols) + disassembled_inst.symbol = symbol.GetDisplayName(); } si << llvm::formatv("{0,7} {1,12}", m, o); @@ -195,7 +109,7 @@ void DisassembleRequestHandler::operator()( si << " ; " << c; } - disassembled_inst.try_emplace("instruction", instruction); + disassembled_inst.instruction = instruction; auto line_entry = addr.GetLineEntry(); // If the line number is 0 then the entry represents a compiler generated @@ -203,41 +117,36 @@ void DisassembleRequestHandler::operator()( if (line_entry.GetStartAddress() == addr && line_entry.IsValid() && line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) { auto source = CreateSource(line_entry); - disassembled_inst.try_emplace("location", source); + disassembled_inst.location = std::move(source); const auto line = line_entry.GetLine(); - if (line && line != LLDB_INVALID_LINE_NUMBER) { - disassembled_inst.try_emplace("line", line); - } + if (line != 0 && line != LLDB_INVALID_LINE_NUMBER) + disassembled_inst.line = line; + const auto column = line_entry.GetColumn(); - if (column && column != LLDB_INVALID_COLUMN_NUMBER) { - disassembled_inst.try_emplace("column", column); - } + if (column != 0 && column != LLDB_INVALID_COLUMN_NUMBER) + disassembled_inst.column = column; auto end_line_entry = line_entry.GetEndAddress().GetLineEntry(); if (end_line_entry.IsValid() && end_line_entry.GetFileSpec() == line_entry.GetFileSpec()) { const auto end_line = end_line_entry.GetLine(); - if (end_line && end_line != LLDB_INVALID_LINE_NUMBER && + if (end_line != 0 && end_line != LLDB_INVALID_LINE_NUMBER && end_line != line) { - disassembled_inst.try_emplace("endLine", end_line); + disassembled_inst.endLine = end_line; const auto end_column = end_line_entry.GetColumn(); - if (end_column && end_column != LLDB_INVALID_COLUMN_NUMBER && - end_column != column) { - disassembled_inst.try_emplace("endColumn", end_column - 1); - } + if (end_column != 0 && end_column != LLDB_INVALID_COLUMN_NUMBER && + end_column != column) + disassembled_inst.endColumn = end_column - 1; } } } - instructions.emplace_back(std::move(disassembled_inst)); + instructions.push_back(std::move(disassembled_inst)); } - llvm::json::Object body; - body.try_emplace("instructions", std::move(instructions)); - response.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(response))); + return DisassembleResponseBody{std::move(instructions)}; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index e6bccfe12f402..998b98137a1ea 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -534,14 +534,17 @@ class LocationsRequestHandler : public LegacyRequestHandler { void operator()(const llvm::json::Object &request) const override; }; -class DisassembleRequestHandler : public LegacyRequestHandler { +class DisassembleRequestHandler final + : public RequestHandler> { public: - using LegacyRequestHandler::LegacyRequestHandler; + using RequestHandler::RequestHandler; static llvm::StringLiteral GetCommand() { return "disassemble"; } FeatureSet GetSupportedFeatures() const override { return {protocol::eAdapterFeatureDisassembleRequest}; } - void operator()(const llvm::json::Object &request) const override; + llvm::Expected + Run(const protocol::DisassembleArguments &args) const override; }; class ReadMemoryRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp index 7efab87d39986..4160077d419e1 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp @@ -460,4 +460,22 @@ llvm::json::Value toJSON(const SetDataBreakpointsResponseBody &SDBR) { return result; } +bool fromJSON(const llvm::json::Value &Params, DisassembleArguments &DA, + llvm::json::Path P) { + json::ObjectMapper O(Params, P); + return O && O.map("memoryReference", DA.memoryReference) && + O.mapOptional("offset", DA.offset) && + O.mapOptional("instructionOffset", DA.instructionOffset) && + O.map("instructionCount", DA.instructionCount) && + O.mapOptional("resolveSymbols", DA.resolveSymbols); +} + +llvm::json::Value toJSON(const DisassembleResponseBody &DRB) { + llvm::json::Array instructions; + for (const auto &instruction : DRB.instructions) { + instructions.push_back(toJSON(instruction)); + } + return llvm::json::Object{{"instructions", std::move(instructions)}}; +} + } // namespace lldb_dap::protocol diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index b421c631344de..c41f3a7296563 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -726,6 +726,41 @@ struct SetDataBreakpointsResponseBody { }; llvm::json::Value toJSON(const SetDataBreakpointsResponseBody &); +/// Arguments to `disassemble` request. +struct DisassembleArguments { + /// Memory reference to the base location containing the instructions to + /// disassemble. + std::string memoryReference; + + /// Offset (in bytes) to be applied to the reference location before + /// disassembling. Can be negative. + std::optional offset; + + /// Offset (in instructions) to be applied after the byte offset (if any) + /// before disassembling. Can be negative. + std::optional instructionOffset; + + /// Number of instructions to disassemble starting at the specified location + /// and offset. + /// An adapter must return exactly this number of instructions - any + /// unavailable instructions should be replaced with an implementation-defined + /// 'invalid instruction' value. + uint32_t instructionCount; + + /// If true, the adapter should attempt to resolve memory addresses and other + /// values to symbolic names. + std::optional resolveSymbols; +}; +bool fromJSON(const llvm::json::Value &, DisassembleArguments &, + llvm::json::Path); + +/// Response to `disassemble` request. +struct DisassembleResponseBody { + /// The list of disassembled instructions. + std::vector instructions; +}; +llvm::json::Value toJSON(const DisassembleResponseBody &); + } // namespace lldb_dap::protocol #endif diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index ce7519e3b16b8..94fe236d952a7 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -782,4 +782,38 @@ bool fromJSON(const llvm::json::Value &Params, InstructionBreakpoint &IB, O.mapOptional("mode", IB.mode); } +llvm::json::Value toJSON(const DisassembledInstruction::PresentationHint &PH) { + switch (PH) { + case DisassembledInstruction::eSourcePresentationHintNormal: + return "normal"; + case DisassembledInstruction::eSourcePresentationHintInvalid: + return "invalid"; + } + llvm_unreachable("unhandled presentation hint."); +} + +llvm::json::Value toJSON(const DisassembledInstruction &DI) { + llvm::json::Object result{{"address", DI.address}, + {"instruction", DI.instruction}}; + + if (DI.instructionBytes) + result.insert({"instructionBytes", *DI.instructionBytes}); + if (DI.symbol) + result.insert({"symbol", *DI.symbol}); + if (DI.location) + result.insert({"location", *DI.location}); + if (DI.line) + result.insert({"line", *DI.line}); + if (DI.column) + result.insert({"column", *DI.column}); + if (DI.endLine) + result.insert({"endLine", *DI.endLine}); + if (DI.endColumn) + result.insert({"endColumn", *DI.endColumn}); + if (DI.presentationHint) + result.insert({"presentationHint", *DI.presentationHint}); + + return result; +} + } // namespace lldb_dap::protocol diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index 3df77ee7374a7..5c6858904a3cf 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -627,6 +627,60 @@ struct InstructionBreakpoint { bool fromJSON(const llvm::json::Value &, InstructionBreakpoint &, llvm::json::Path); +/// Properties of a single disassembled instruction, returned by `disassemble` +/// request. +struct DisassembledInstruction { + enum PresentationHint : unsigned { + eSourcePresentationHintNormal, + eSourcePresentationHintInvalid, + }; + + /// The address of the instruction. Treated as a hex value if prefixed with + /// `0x`, or as a decimal value otherwise. + std::string address; + + /// Raw bytes representing the instruction and its operands, in an + /// implementation-defined format. + std::optional instructionBytes; + + /// Text representing the instruction and its operands, in an + /// implementation-defined format. + std::string instruction; + + /// Name of the symbol that corresponds with the location of this instruction, + /// if any. + std::optional symbol; + + /// Source location that corresponds to this instruction, if any. + /// Should always be set (if available) on the first instruction returned, + /// but can be omitted afterwards if this instruction maps to the same source + /// file as the previous instruction. + std::optional location; + + /// The line within the source location that corresponds to this instruction, + /// if any. + std::optional line; + + /// The column within the line that corresponds to this instruction, if any. + std::optional column; + + /// The end line of the range that corresponds to this instruction, if any. + std::optional endLine; + + /// The end column of the range that corresponds to this instruction, if any. + std::optional endColumn; + + /// A hint for how to present the instruction in the UI. + /// + /// A value of `invalid` may be used to indicate this instruction is 'filler' + /// and cannot be reached by the program. For example, unreadable memory + /// addresses may be presented is 'invalid.' + /// Values: 'normal', 'invalid' + std::optional presentationHint; +}; +llvm::json::Value toJSON(const DisassembledInstruction::PresentationHint &); +llvm::json::Value toJSON(const DisassembledInstruction &); + } // namespace lldb_dap::protocol #endif >From cf7600dbfdb081f5bce80d860bb84bdc6c35cd1b Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Mon, 19 May 2025 01:54:19 +0200 Subject: [PATCH 2/2] [lldb-dap] Fix disassemble request instruction offset handling --- .../Handler/DisassembleRequestHandler.cpp | 232 ++++++++++++------ lldb/tools/lldb-dap/Handler/RequestHandler.h | 4 + 2 files changed, 155 insertions(+), 81 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp index 938078947259b..88fdba3d9ca44 100644 --- a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp @@ -24,15 +24,14 @@ namespace lldb_dap { /// `supportsDisassembleRequest` is true. llvm::Expected DisassembleRequestHandler::Run(const DisassembleArguments &args) const { - std::vector instructions; - auto addr_opt = DecodeMemoryReference(args.memoryReference); if (!addr_opt.has_value()) return llvm::make_error("Malformed memory reference: " + args.memoryReference); lldb::addr_t addr_ptr = *addr_opt; - addr_ptr += args.instructionOffset.value_or(0); + addr_ptr += args.offset.value_or(0); + lldb::SBAddress addr(addr_ptr, dap.target); if (!addr.IsValid()) return llvm::make_error( @@ -53,100 +52,171 @@ DisassembleRequestHandler::Run(const DisassembleArguments &args) const { } } - lldb::SBInstructionList insts = dap.target.ReadInstructions( - addr, args.instructionCount, flavor_string.c_str()); + int64_t instructionOffset = args.instructionOffset.value_or(0); + if (instructionOffset > 0) { + lldb::SBInstructionList forward_insts = dap.target.ReadInstructions( + addr, instructionOffset + 1, flavor_string.c_str()); + if (forward_insts.GetSize() != static_cast(instructionOffset + 1)) { + return llvm::make_error( + "Failed to disassemble instructions after " + + std::to_string(instructionOffset) + + " instructions from the given address."); + } + addr = forward_insts.GetInstructionAtIndex(instructionOffset).GetAddress(); + } + + const bool resolveSymbols = args.resolveSymbols.value_or(false); + std::vector instructions; + if (instructionOffset < 0) { + // need to disassemble backwards, let's try from the start of the symbol if + // available. + size_t number_of_insts_before = std::abs(instructionOffset); + auto symbol = addr.GetSymbol(); + if (symbol.IsValid()) { + // add valid instructions before the current instruction using the symbol. + lldb::SBInstructionList symbol_insts = dap.target.ReadInstructions( + symbol.GetStartAddress(), addr, flavor_string.c_str()); + if (symbol_insts.IsValid()) { + size_t backwards_insts_start = + symbol_insts.GetSize() >= number_of_insts_before + ? symbol_insts.GetSize() - number_of_insts_before + : 0; + for (size_t i = backwards_insts_start; + i < symbol_insts.GetSize() && + instructions.size() < args.instructionCount; + ++i) { + lldb::SBInstruction inst = symbol_insts.GetInstructionAtIndex(i); + instructions.push_back( + SBInstructionToDisassembledInstruction(inst, resolveSymbols)); + --number_of_insts_before; + } + } + } + + // pad the instructions with invalid instructions if needed. + for (size_t i = 0; i < number_of_insts_before && + instructions.size() < args.instructionCount; + ++i) { + DisassembledInstruction invalid_inst; + invalid_inst.presentationHint = + DisassembledInstruction::eSourcePresentationHintInvalid; + instructions.insert(instructions.begin(), std::move(invalid_inst)); + } + } + + const auto instructions_left = args.instructionCount - instructions.size(); + lldb::SBInstructionList insts = dap.target.ReadInstructions( + addr, instructions_left, flavor_string.c_str()); if (!insts.IsValid()) return llvm::make_error( "Failed to find instructions for memory address."); - const bool resolveSymbols = args.resolveSymbols.value_or(false); + // add the disassembly from the given address forward const auto num_insts = insts.GetSize(); - for (size_t i = 0; i < num_insts; ++i) { + for (size_t i = 0; + i < num_insts && instructions.size() < args.instructionCount; ++i) { lldb::SBInstruction inst = insts.GetInstructionAtIndex(i); - auto addr = inst.GetAddress(); - const auto inst_addr = addr.GetLoadAddress(dap.target); - const char *m = inst.GetMnemonic(dap.target); - const char *o = inst.GetOperands(dap.target); - const char *c = inst.GetComment(dap.target); - auto d = inst.GetData(dap.target); - - std::string bytes; - llvm::raw_string_ostream sb(bytes); - for (unsigned i = 0; i < inst.GetByteSize(); i++) { - lldb::SBError error; - uint8_t b = d.GetUnsignedInt8(error, i); - if (error.Success()) { - sb << llvm::format("%2.2x ", b); - } - } + instructions.push_back( + SBInstructionToDisassembledInstruction(inst, resolveSymbols)); + } - DisassembledInstruction disassembled_inst; - disassembled_inst.address = "0x" + llvm::utohexstr(inst_addr); - disassembled_inst.instructionBytes = - bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : ""; - - std::string instruction; - llvm::raw_string_ostream si(instruction); - - lldb::SBSymbol symbol = addr.GetSymbol(); - // Only add the symbol on the first line of the function. - if (symbol.IsValid() && symbol.GetStartAddress() == addr) { - // If we have a valid symbol, append it as a label prefix for the first - // instruction. This is so you can see the start of a function/callsite - // in the assembly, at the moment VS Code (1.80) does not visualize the - // symbol associated with the assembly instruction. - si << (symbol.GetMangledName() != nullptr ? symbol.GetMangledName() - : symbol.GetName()) - << ": "; - - if (resolveSymbols) - disassembled_inst.symbol = symbol.GetDisplayName(); + // Pad the instructions with invalid instructions if needed. + if (instructions.size() < args.instructionCount) { + for (size_t i = instructions.size(); i < args.instructionCount; ++i) { + DisassembledInstruction invalid_inst; + invalid_inst.presentationHint = + DisassembledInstruction::eSourcePresentationHintInvalid; + instructions.push_back(std::move(invalid_inst)); } + } + + return DisassembleResponseBody{std::move(instructions)}; +} - si << llvm::formatv("{0,7} {1,12}", m, o); - if (c && c[0]) { - si << " ; " << c; +DisassembledInstruction +DisassembleRequestHandler::SBInstructionToDisassembledInstruction( + lldb::SBInstruction &inst, bool resolveSymbols) const { + auto addr = inst.GetAddress(); + const auto inst_addr = addr.GetLoadAddress(dap.target); + const char *m = inst.GetMnemonic(dap.target); + const char *o = inst.GetOperands(dap.target); + const char *c = inst.GetComment(dap.target); + auto d = inst.GetData(dap.target); + + std::string bytes; + llvm::raw_string_ostream sb(bytes); + for (unsigned i = 0; i < inst.GetByteSize(); i++) { + lldb::SBError error; + uint8_t b = d.GetUnsignedInt8(error, i); + if (error.Success()) { + sb << llvm::format("%2.2x ", b); } + } - disassembled_inst.instruction = instruction; - - auto line_entry = addr.GetLineEntry(); - // If the line number is 0 then the entry represents a compiler generated - // location. - if (line_entry.GetStartAddress() == addr && line_entry.IsValid() && - line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) { - auto source = CreateSource(line_entry); - disassembled_inst.location = std::move(source); - - const auto line = line_entry.GetLine(); - if (line != 0 && line != LLDB_INVALID_LINE_NUMBER) - disassembled_inst.line = line; - - const auto column = line_entry.GetColumn(); - if (column != 0 && column != LLDB_INVALID_COLUMN_NUMBER) - disassembled_inst.column = column; - - auto end_line_entry = line_entry.GetEndAddress().GetLineEntry(); - if (end_line_entry.IsValid() && - end_line_entry.GetFileSpec() == line_entry.GetFileSpec()) { - const auto end_line = end_line_entry.GetLine(); - if (end_line != 0 && end_line != LLDB_INVALID_LINE_NUMBER && - end_line != line) { - disassembled_inst.endLine = end_line; - - const auto end_column = end_line_entry.GetColumn(); - if (end_column != 0 && end_column != LLDB_INVALID_COLUMN_NUMBER && - end_column != column) - disassembled_inst.endColumn = end_column - 1; - } + DisassembledInstruction disassembled_inst; + disassembled_inst.address = "0x" + llvm::utohexstr(inst_addr); + disassembled_inst.instructionBytes = + bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : ""; + + std::string instruction; + llvm::raw_string_ostream si(instruction); + + lldb::SBSymbol symbol = addr.GetSymbol(); + // Only add the symbol on the first line of the function. + if (symbol.IsValid() && symbol.GetStartAddress() == addr) { + // If we have a valid symbol, append it as a label prefix for the first + // instruction. This is so you can see the start of a function/callsite + // in the assembly, at the moment VS Code (1.80) does not visualize the + // symbol associated with the assembly instruction. + si << (symbol.GetMangledName() != nullptr ? symbol.GetMangledName() + : symbol.GetName()) + << ": "; + + if (resolveSymbols) + disassembled_inst.symbol = symbol.GetDisplayName(); + } + + si << llvm::formatv("{0,7} {1,12}", m, o); + if (c && c[0]) { + si << " ; " << c; + } + + disassembled_inst.instruction = instruction; + + auto line_entry = addr.GetLineEntry(); + // If the line number is 0 then the entry represents a compiler generated + // location. + if (line_entry.GetStartAddress() == addr && line_entry.IsValid() && + line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) { + auto source = CreateSource(line_entry); + disassembled_inst.location = std::move(source); + + const auto line = line_entry.GetLine(); + if (line != 0 && line != LLDB_INVALID_LINE_NUMBER) + disassembled_inst.line = line; + + const auto column = line_entry.GetColumn(); + if (column != 0 && column != LLDB_INVALID_COLUMN_NUMBER) + disassembled_inst.column = column; + + auto end_line_entry = line_entry.GetEndAddress().GetLineEntry(); + if (end_line_entry.IsValid() && + end_line_entry.GetFileSpec() == line_entry.GetFileSpec()) { + const auto end_line = end_line_entry.GetLine(); + if (end_line != 0 && end_line != LLDB_INVALID_LINE_NUMBER && + end_line != line) { + disassembled_inst.endLine = end_line; + + const auto end_column = end_line_entry.GetColumn(); + if (end_column != 0 && end_column != LLDB_INVALID_COLUMN_NUMBER && + end_column != column) + disassembled_inst.endColumn = end_column - 1; } } - - instructions.push_back(std::move(disassembled_inst)); } - return DisassembleResponseBody{std::move(instructions)}; + return disassembled_inst; } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 998b98137a1ea..ccc2c829d9474 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -545,6 +545,10 @@ class DisassembleRequestHandler final } llvm::Expected Run(const protocol::DisassembleArguments &args) const override; + + protocol::DisassembledInstruction + SBInstructionToDisassembledInstruction(lldb::SBInstruction &inst, + bool resolveSymbols) const; }; class ReadMemoryRequestHandler : public LegacyRequestHandler { From lldb-commits at lists.llvm.org Sun May 18 17:06:25 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Sun, 18 May 2025 17:06:25 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Migrate disassemble request to structured handler (PR #140482) In-Reply-To: Message-ID: <682a7601.050a0220.25a5b7.c2a9@mx.google.com> https://github.com/ashgti edited https://github.com/llvm/llvm-project/pull/140482 From lldb-commits at lists.llvm.org Sun May 18 17:06:25 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Sun, 18 May 2025 17:06:25 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Migrate disassemble request to structured handler (PR #140482) In-Reply-To: Message-ID: <682a7601.170a0220.1480f9.698b@mx.google.com> https://github.com/ashgti commented: Should we also add unit tests to https://github.com/llvm/llvm-project/blob/main/lldb/unittests/DAP/ProtocolTypesTest.cpp for these new types as well? https://github.com/llvm/llvm-project/pull/140482 From lldb-commits at lists.llvm.org Sun May 18 17:06:26 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Sun, 18 May 2025 17:06:26 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Migrate disassemble request to structured handler (PR #140482) In-Reply-To: Message-ID: <682a7602.050a0220.3d501.ceea@mx.google.com> ================ @@ -627,6 +627,60 @@ struct InstructionBreakpoint { bool fromJSON(const llvm::json::Value &, InstructionBreakpoint &, llvm::json::Path); +/// Properties of a single disassembled instruction, returned by `disassemble` +/// request. +struct DisassembledInstruction { + enum PresentationHint : unsigned { + eSourcePresentationHintNormal, ---------------- ashgti wrote: Should this be `eDisassembledInstructionPresentationHintNormal`? (That does feel really long...). Maybe `eInstructionPresentationHintNormal`? and same for `Invalid` below. https://github.com/llvm/llvm-project/pull/140482 From lldb-commits at lists.llvm.org Sun May 18 17:06:26 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Sun, 18 May 2025 17:06:26 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Migrate disassemble request to structured handler (PR #140482) In-Reply-To: Message-ID: <682a7602.630a0220.ac96c.076d@mx.google.com> ================ @@ -627,6 +627,60 @@ struct InstructionBreakpoint { bool fromJSON(const llvm::json::Value &, InstructionBreakpoint &, llvm::json::Path); +/// Properties of a single disassembled instruction, returned by `disassemble` +/// request. +struct DisassembledInstruction { + enum PresentationHint : unsigned { + eSourcePresentationHintNormal, + eSourcePresentationHintInvalid, + }; + + /// The address of the instruction. Treated as a hex value if prefixed with + /// `0x`, or as a decimal value otherwise. + std::string address; ---------------- ashgti wrote: I wonder, should we use an `lldb::addr_t` for the type here and encode it to a hex string in the `toJSON()`? https://github.com/llvm/llvm-project/pull/140482 From lldb-commits at lists.llvm.org Sun May 18 17:23:30 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sun, 18 May 2025 17:23:30 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for FifoFiles (PR #140480) In-Reply-To: Message-ID: <682a7a02.170a0220.111159.dd86@mx.google.com> ================ @@ -0,0 +1,102 @@ +//===-- FifoFilesTest.cpp -------------------------------------------------===// +// +// 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 "FifoFiles.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include + +using namespace lldb_dap; +using namespace llvm; + +namespace { + +std::string MakeTempFifoPath() { + llvm::SmallString<128> temp_path; + llvm::sys::fs::createUniquePath("lldb-dap-fifo-%%%%%%", temp_path, + /*MakeAbsolute=*/true); + return temp_path.str().str(); +} + +} // namespace + +TEST(FifoFilesTest, CreateAndDestroyFifoFile) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + // File should exist. + EXPECT_TRUE(llvm::sys::fs::exists(fifo_path)); + + // Destructor should remove the file. + fifo->reset(); + EXPECT_FALSE(llvm::sys::fs::exists(fifo_path)); +} + +TEST(FifoFilesTest, SendAndReceiveJSON) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + FifoFileIO writer(fifo_path, "writer"); + FifoFileIO reader(fifo_path, "reader"); + + llvm::json::Object obj; + obj["foo"] = "bar"; + obj["num"] = 42; + + // Writer thread. + std::thread writer_thread([&]() { + EXPECT_THAT_ERROR(writer.SendJSON(llvm::json::Value(std::move(obj)), + std::chrono::milliseconds(500)), + llvm::Succeeded()); + }); + + // Reader thread. + std::thread reader_thread([&]() { + auto result = reader.ReadJSON(std::chrono::milliseconds(500)); + EXPECT_THAT_EXPECTED(result, llvm::Succeeded()); + auto *read_obj = result->getAsObject(); + + ASSERT_NE(read_obj, nullptr); + EXPECT_EQ((*read_obj)["foo"].getAsString(), "bar"); + EXPECT_EQ((*read_obj)["num"].getAsInteger(), 42); + }); + + writer_thread.join(); + reader_thread.join(); +} + +TEST(FifoFilesTest, ReadTimeout) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + FifoFileIO reader(fifo_path, "reader"); + + // No writer, should timeout. + auto result = reader.ReadJSON(std::chrono::milliseconds(100)); ---------------- JDevlieghere wrote: My reasoning was that too short of a timeout could lead to false negatives and a 100ms is short enough to be hardly noticeable while also accounting for load on the bots where something like 1ms can easily become 10-50ms. But I'm happy to make it shorter if you're worried about test slowdown. https://github.com/llvm/llvm-project/pull/140480 From lldb-commits at lists.llvm.org Sun May 18 17:32:32 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sun, 18 May 2025 17:32:32 -0700 (PDT) Subject: [Lldb-commits] [lldb] ad67315 - [lldb-dap] Move the command plugins out of the DAP header (#140396) Message-ID: <682a7c20.a70a0220.27bfd3.d991@mx.google.com> Author: Jonas Devlieghere Date: 2025-05-18T17:32:28-07:00 New Revision: ad673151085cc6cd85ae05714e201e0b6dd78e37 URL: https://github.com/llvm/llvm-project/commit/ad673151085cc6cd85ae05714e201e0b6dd78e37 DIFF: https://github.com/llvm/llvm-project/commit/ad673151085cc6cd85ae05714e201e0b6dd78e37.diff LOG: [lldb-dap] Move the command plugins out of the DAP header (#140396) Move the command plugins out of the DAP header and into their file. This PR also renames the classes from "RequestHandler" to "Command". Although they are implemented in terms of sending requests, they are not "handlers". Added: lldb/tools/lldb-dap/CommandPlugins.cpp lldb/tools/lldb-dap/CommandPlugins.h Modified: lldb/tools/lldb-dap/CMakeLists.txt lldb/tools/lldb-dap/DAP.cpp lldb/tools/lldb-dap/DAP.h lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp Removed: ################################################################################ diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index f8e81eaff8606..490aa4710af1a 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -8,6 +8,7 @@ add_public_tablegen_target(LLDBDAPOptionsTableGen) add_lldb_library(lldbDAP Breakpoint.cpp BreakpointBase.cpp + CommandPlugins.cpp DAP.cpp DAPError.cpp DAPLog.cpp diff --git a/lldb/tools/lldb-dap/CommandPlugins.cpp b/lldb/tools/lldb-dap/CommandPlugins.cpp new file mode 100644 index 0000000000000..4e7aa029e0f22 --- /dev/null +++ b/lldb/tools/lldb-dap/CommandPlugins.cpp @@ -0,0 +1,163 @@ +//===-- CommandPlugins.cpp ------------------------------------------------===// +// +// 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 "CommandPlugins.h" +#include "Handler/ResponseHandler.h" +#include "JSONUtils.h" +#include "lldb/API/SBStream.h" + +using namespace lldb_dap; + +bool StartDebuggingCommand::DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) { + // Command format like: `start-debugging ` + if (!command) { + result.SetError("Invalid use of start-debugging, expected format " + "`start-debugging `."); + return false; + } + + if (!command[0] || llvm::StringRef(command[0]).empty()) { + result.SetError("start-debugging request type missing."); + return false; + } + + if (!command[1] || llvm::StringRef(command[1]).empty()) { + result.SetError("start-debugging debug configuration missing."); + return false; + } + + llvm::StringRef request{command[0]}; + std::string raw_configuration{command[1]}; + + llvm::Expected configuration = + llvm::json::parse(raw_configuration); + + if (!configuration) { + llvm::Error err = configuration.takeError(); + std::string msg = "Failed to parse json configuration: " + + llvm::toString(std::move(err)) + "\n\n" + + raw_configuration; + result.SetError(msg.c_str()); + return false; + } + + dap.SendReverseRequest( + "startDebugging", + llvm::json::Object{{"request", request}, + {"configuration", std::move(*configuration)}}); + + result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); + + return true; +} + +bool ReplModeCommand::DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) { + // Command format like: `repl-mode ?` + // If a new mode is not specified report the current mode. + if (!command || llvm::StringRef(command[0]).empty()) { + std::string mode; + switch (dap.repl_mode) { + case ReplMode::Variable: + mode = "variable"; + break; + case ReplMode::Command: + mode = "command"; + break; + case ReplMode::Auto: + mode = "auto"; + break; + } + + result.Printf("lldb-dap repl-mode %s.\n", mode.c_str()); + result.SetStatus(lldb::eReturnStatusSuccessFinishResult); + + return true; + } + + llvm::StringRef new_mode{command[0]}; + + if (new_mode == "variable") { + dap.repl_mode = ReplMode::Variable; + } else if (new_mode == "command") { + dap.repl_mode = ReplMode::Command; + } else if (new_mode == "auto") { + dap.repl_mode = ReplMode::Auto; + } else { + lldb::SBStream error_message; + error_message.Printf("Invalid repl-mode '%s'. Expected one of 'variable', " + "'command' or 'auto'.\n", + new_mode.data()); + result.SetError(error_message.GetData()); + return false; + } + + result.Printf("lldb-dap repl-mode %s set.\n", new_mode.data()); + result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); + return true; +} + +/// Sends a DAP event with an optional body. +/// +/// https://code.visualstudio.com/api/references/vscode-api#debug.onDidReceiveDebugSessionCustomEvent +bool SendEventCommand::DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) { + // Command format like: `send-event ?` + if (!command || !command[0] || llvm::StringRef(command[0]).empty()) { + result.SetError("Not enough arguments found, expected format " + "`lldb-dap send-event ?`."); + return false; + } + + llvm::StringRef name{command[0]}; + // Events that are stateful and should be handled by lldb-dap internally. + const std::array internal_events{"breakpoint", "capabilities", "continued", + "exited", "initialize", "loadedSource", + "module", "process", "stopped", + "terminated", "thread"}; + if (llvm::is_contained(internal_events, name)) { + std::string msg = + llvm::formatv("Invalid use of lldb-dap send-event, event \"{0}\" " + "should be handled by lldb-dap internally.", + name) + .str(); + result.SetError(msg.c_str()); + return false; + } + + llvm::json::Object event(CreateEventObject(name)); + + if (command[1] && !llvm::StringRef(command[1]).empty()) { + // See if we have unused arguments. + if (command[2]) { + result.SetError( + "Additional arguments found, expected `lldb-dap send-event " + " ?`."); + return false; + } + + llvm::StringRef raw_body{command[1]}; + + llvm::Expected body = llvm::json::parse(raw_body); + + if (!body) { + llvm::Error err = body.takeError(); + std::string msg = "Failed to parse custom event body: " + + llvm::toString(std::move(err)); + result.SetError(msg.c_str()); + return false; + } + + event.try_emplace("body", std::move(*body)); + } + + dap.SendJSON(llvm::json::Value(std::move(event))); + result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); + return true; +} diff --git a/lldb/tools/lldb-dap/CommandPlugins.h b/lldb/tools/lldb-dap/CommandPlugins.h new file mode 100644 index 0000000000000..011c7fd2da2a1 --- /dev/null +++ b/lldb/tools/lldb-dap/CommandPlugins.h @@ -0,0 +1,40 @@ +//===-- CommandPlugins.h --------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TOOLS_LLDB_DAP_COMMANDPLUGINS_H +#define LLDB_TOOLS_LLDB_DAP_COMMANDPLUGINS_H + +#include "DAP.h" +#include "lldb/API/SBCommandInterpreter.h" + +namespace lldb_dap { + +struct StartDebuggingCommand : public lldb::SBCommandPluginInterface { + DAP &dap; + explicit StartDebuggingCommand(DAP &d) : dap(d) {}; + bool DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) override; +}; + +struct ReplModeCommand : public lldb::SBCommandPluginInterface { + DAP &dap; + explicit ReplModeCommand(DAP &d) : dap(d) {}; + bool DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) override; +}; + +struct SendEventCommand : public lldb::SBCommandPluginInterface { + DAP &dap; + explicit SendEventCommand(DAP &d) : dap(d) {}; + bool DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) override; +}; + +} // namespace lldb_dap + +#endif diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 8868131622243..af7a04a215fec 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1017,159 +1017,6 @@ lldb::SBError DAP::WaitForProcessToStop(std::chrono::seconds seconds) { return error; } -bool StartDebuggingRequestHandler::DoExecute( - lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) { - // Command format like: `start-debugging ` - if (!command) { - result.SetError("Invalid use of start-debugging, expected format " - "`start-debugging `."); - return false; - } - - if (!command[0] || llvm::StringRef(command[0]).empty()) { - result.SetError("start-debugging request type missing."); - return false; - } - - if (!command[1] || llvm::StringRef(command[1]).empty()) { - result.SetError("start-debugging debug configuration missing."); - return false; - } - - llvm::StringRef request{command[0]}; - std::string raw_configuration{command[1]}; - - llvm::Expected configuration = - llvm::json::parse(raw_configuration); - - if (!configuration) { - llvm::Error err = configuration.takeError(); - std::string msg = "Failed to parse json configuration: " + - llvm::toString(std::move(err)) + "\n\n" + - raw_configuration; - result.SetError(msg.c_str()); - return false; - } - - dap.SendReverseRequest( - "startDebugging", - llvm::json::Object{{"request", request}, - {"configuration", std::move(*configuration)}}); - - result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); - - return true; -} - -bool ReplModeRequestHandler::DoExecute(lldb::SBDebugger debugger, - char **command, - lldb::SBCommandReturnObject &result) { - // Command format like: `repl-mode ?` - // If a new mode is not specified report the current mode. - if (!command || llvm::StringRef(command[0]).empty()) { - std::string mode; - switch (dap.repl_mode) { - case ReplMode::Variable: - mode = "variable"; - break; - case ReplMode::Command: - mode = "command"; - break; - case ReplMode::Auto: - mode = "auto"; - break; - } - - result.Printf("lldb-dap repl-mode %s.\n", mode.c_str()); - result.SetStatus(lldb::eReturnStatusSuccessFinishResult); - - return true; - } - - llvm::StringRef new_mode{command[0]}; - - if (new_mode == "variable") { - dap.repl_mode = ReplMode::Variable; - } else if (new_mode == "command") { - dap.repl_mode = ReplMode::Command; - } else if (new_mode == "auto") { - dap.repl_mode = ReplMode::Auto; - } else { - lldb::SBStream error_message; - error_message.Printf("Invalid repl-mode '%s'. Expected one of 'variable', " - "'command' or 'auto'.\n", - new_mode.data()); - result.SetError(error_message.GetData()); - return false; - } - - result.Printf("lldb-dap repl-mode %s set.\n", new_mode.data()); - result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); - return true; -} - -// Sends a DAP event with an optional body. -// -// See -// https://code.visualstudio.com/api/references/vscode-api#debug.onDidReceiveDebugSessionCustomEvent -bool SendEventRequestHandler::DoExecute(lldb::SBDebugger debugger, - char **command, - lldb::SBCommandReturnObject &result) { - // Command format like: `send-event ?` - if (!command || !command[0] || llvm::StringRef(command[0]).empty()) { - result.SetError("Not enough arguments found, expected format " - "`lldb-dap send-event ?`."); - return false; - } - - llvm::StringRef name{command[0]}; - // Events that are stateful and should be handled by lldb-dap internally. - const std::array internal_events{"breakpoint", "capabilities", "continued", - "exited", "initialize", "loadedSource", - "module", "process", "stopped", - "terminated", "thread"}; - if (llvm::is_contained(internal_events, name)) { - std::string msg = - llvm::formatv("Invalid use of lldb-dap send-event, event \"{0}\" " - "should be handled by lldb-dap internally.", - name) - .str(); - result.SetError(msg.c_str()); - return false; - } - - llvm::json::Object event(CreateEventObject(name)); - - if (command[1] && !llvm::StringRef(command[1]).empty()) { - // See if we have unused arguments. - if (command[2]) { - result.SetError( - "Additional arguments found, expected `lldb-dap send-event " - " ?`."); - return false; - } - - llvm::StringRef raw_body{command[1]}; - - llvm::Expected body = llvm::json::parse(raw_body); - - if (!body) { - llvm::Error err = body.takeError(); - std::string msg = "Failed to parse custom event body: " + - llvm::toString(std::move(err)); - result.SetError(msg.c_str()); - return false; - } - - event.try_emplace("body", std::move(*body)); - } - - dap.SendJSON(llvm::json::Value(std::move(event))); - result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); - return true; -} - void DAP::ConfigureSourceMaps() { if (configuration.sourceMap.empty() && configuration.sourcePath.empty()) return; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index eafc92776fca7..44b8153ba2725 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -83,27 +83,6 @@ enum class PacketStatus { enum class ReplMode { Variable = 0, Command, Auto }; -struct StartDebuggingRequestHandler : public lldb::SBCommandPluginInterface { - DAP &dap; - explicit StartDebuggingRequestHandler(DAP &d) : dap(d) {}; - bool DoExecute(lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) override; -}; - -struct ReplModeRequestHandler : public lldb::SBCommandPluginInterface { - DAP &dap; - explicit ReplModeRequestHandler(DAP &d) : dap(d) {}; - bool DoExecute(lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) override; -}; - -struct SendEventRequestHandler : public lldb::SBCommandPluginInterface { - DAP &dap; - explicit SendEventRequestHandler(DAP &d) : dap(d) {}; - bool DoExecute(lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) override; -}; - struct DAP { /// Path to the lldb-dap binary itself. static llvm::StringRef debug_adapter_path; diff --git a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp index 0a178406b5a69..dcd02d61ca4f4 100644 --- a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "CommandPlugins.h" #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" @@ -59,14 +60,14 @@ llvm::Expected InitializeRequestHandler::Run( if (arguments.supportedFeatures.contains( eClientFeatureStartDebuggingRequest)) { cmd.AddCommand( - "start-debugging", new StartDebuggingRequestHandler(dap), + "start-debugging", new StartDebuggingCommand(dap), "Sends a startDebugging request from the debug adapter to the client " "to start a child debug session of the same type as the caller."); } cmd.AddCommand( - "repl-mode", new ReplModeRequestHandler(dap), + "repl-mode", new ReplModeCommand(dap), "Get or set the repl behavior of lldb-dap evaluation requests."); - cmd.AddCommand("send-event", new SendEventRequestHandler(dap), + cmd.AddCommand("send-event", new SendEventCommand(dap), "Sends an DAP event to the client."); if (arguments.supportedFeatures.contains(eClientFeatureProgressReporting)) From lldb-commits at lists.llvm.org Sun May 18 17:32:34 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sun, 18 May 2025 17:32:34 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Move the command plugins out of the DAP header (PR #140396) In-Reply-To: Message-ID: <682a7c22.a70a0220.dc1fd.bed1@mx.google.com> https://github.com/JDevlieghere closed https://github.com/llvm/llvm-project/pull/140396 From lldb-commits at lists.llvm.org Sun May 18 17:48:37 2025 From: lldb-commits at lists.llvm.org (Jacob Lalonde via lldb-commits) Date: Sun, 18 May 2025 17:48:37 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB][ELF Core] Support all the Generic (Negative) SI Codes. (PR #140150) In-Reply-To: Message-ID: <682a7fe5.170a0220.ed640.e5f8@mx.google.com> https://github.com/Jlalond updated https://github.com/llvm/llvm-project/pull/140150 >From 86ec6c076b9cf8e7afeb7d6bb0e334434f6e0d9e Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Thu, 15 May 2025 13:57:11 -0700 Subject: [PATCH 1/8] Update ThreadElfCore --- lldb/include/lldb/Target/UnixSignals.h | 6 ++++-- .../Plugins/Process/Utility/LinuxSignals.cpp | 17 ++++++++++++++--- .../Plugins/Process/elf-core/ThreadElfCore.cpp | 10 +++++++--- .../Plugins/Process/elf-core/ThreadElfCore.h | 6 ++++++ lldb/source/Target/UnixSignals.cpp | 9 +++++++-- 5 files changed, 38 insertions(+), 10 deletions(-) diff --git a/lldb/include/lldb/Target/UnixSignals.h b/lldb/include/lldb/Target/UnixSignals.h index b3605ccefddbe..a1807d69f329b 100644 --- a/lldb/include/lldb/Target/UnixSignals.h +++ b/lldb/include/lldb/Target/UnixSignals.h @@ -36,7 +36,9 @@ class UnixSignals { std::optional code = std::nullopt, std::optional addr = std::nullopt, std::optional lower = std::nullopt, - std::optional upper = std::nullopt) const; + std::optional upper = std::nullopt, + std::optional pid = std::nullopt, + std::optional uid = std::nullopt) const; bool SignalIsValid(int32_t signo) const; @@ -105,7 +107,7 @@ class UnixSignals { llvm::StringRef description, llvm::StringRef alias = llvm::StringRef()); - enum SignalCodePrintOption { None, Address, Bounds }; + enum SignalCodePrintOption { None, Address, Bounds, Sender }; // Instead of calling this directly, use a ADD_SIGCODE macro to get compile // time checks when on the native platform. diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index 9c4fe55147a28..25d4e4609bbb8 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -38,6 +38,17 @@ #define ADD_SIGCODE(signal_name, signal_value, code_name, code_value, ...) \ AddSignalCode(signal_value, code_value, __VA_ARGS__) #endif /* if defined(__linux__) && !defined(__mips__) */ +// See siginfo.h in the Linux Kernel, these codes can be sent for any signal. +#define ADD_LINUX_SIGNAL(signo, name, ...) \ + AddSignal(signo, name, __VA_ARGS__); \ + ADD_SIGCODE(signo, signo, SI_QUEUE, -1, "sent by sigqueue"); \ + ADD_SIGCODE(signo, signo, SI_TIMER, -2, "sent by timer expiration"); \ + ADD_SIGCODE(signo, signo, SI_MESGQ, -3, "sent by real time mesq state change"); \ + ADD_SIGCODE(signo, signo, SI_ASYNCIO, -4, "sent by AIO completion"); \ + ADD_SIGCODE(signo, signo, SI_SIGIO, -5, "sent by queued SIGIO"); \ + ADD_SIGCODE(signo, signo, SI_TKILL, -6, "sent by tkill system call"); \ + ADD_SIGCODE(signo, signo, SI_DETHREAD, -7, "sent by execve() killing subsidiary threads"); \ + ADD_SIGCODE(signo, signo, SI_ASYNCNL, -60, "sent by glibc async name lookup completion"); using namespace lldb_private; @@ -46,9 +57,9 @@ LinuxSignals::LinuxSignals() : UnixSignals() { Reset(); } void LinuxSignals::Reset() { m_signals.clear(); // clang-format off - // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION - // ====== ============== ======== ====== ====== =================================================== - AddSignal(1, "SIGHUP", false, true, true, "hangup"); + // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION + // ====== ============== ======== ====== ====== =================================================== + ADD_LINUX_SIGNAL(1, "SIGHUP", false, true, true, "hangup"); AddSignal(2, "SIGINT", true, true, true, "interrupt"); AddSignal(3, "SIGQUIT", false, true, true, "quit"); diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index a0cd0ee5025bd..267879a473463 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -584,9 +584,13 @@ Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, // 64b ELF have a 4 byte pad. if (data.GetAddressByteSize() == 8) offset += 4; - // Not every stop signal has a valid address, but that will get resolved in - // the unix_signals.GetSignalDescription() call below. - if (unix_signals.GetShouldStop(si_signo)) { + + if (si_code < 0) { + sigfault.kill._pid = data.GetU32(&offset); + sigfault.kill._uid = data.GetU32(&offset); + } else if (unix_signals.GetShouldStop(si_signo)) { + // Not every stop signal has a valid address, but that will get resolved in + // the unix_signals.GetSignalDescription() call below. // Instead of memcpy we call all these individually as the extractor will // handle endianness for us. sigfault.si_addr = data.GetAddress(&offset); diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h index 6f8d41351a6bf..2cbf794c2b5b1 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -96,6 +96,12 @@ struct ELFLinuxSigInfo { /* used when si_code=SEGV_PKUERR */ uint32_t _pkey; } bounds; + + // We need this for all the generic signals. + struct { + uint32_t _pid; /* sender's pid */ + uint32_t _uid; /* sender's uid */ + } _kill; } sigfault; enum SigInfoNoteType : uint8_t { eUnspecified, eNT_SIGINFO }; diff --git a/lldb/source/Target/UnixSignals.cpp b/lldb/source/Target/UnixSignals.cpp index da661003925c7..a5dbfd029410a 100644 --- a/lldb/source/Target/UnixSignals.cpp +++ b/lldb/source/Target/UnixSignals.cpp @@ -141,7 +141,9 @@ std::string UnixSignals::GetSignalDescription(int32_t signo, std::optional code, std::optional addr, std::optional lower, - std::optional upper) const { + std::optional upper, + std::optional pid, + std::optional uid) const { std::string str; collection::const_iterator pos = m_signals.find(signo); @@ -180,6 +182,10 @@ UnixSignals::GetSignalDescription(int32_t signo, std::optional code, strm << sc.m_description.str(); break; + case SignalCodePrintOption::Sender: + if (pid && uid) + strm << " (sender pid=" << *pid << ", uid=" << *uid << ")"; + break; } str += strm.str(); } @@ -397,4 +403,3 @@ bool UnixSignals::ResetSignal(int32_t signo, bool reset_stop, (*elem).second.Reset(reset_stop, reset_notify, reset_suppress); return true; } - >From 6d8a30cc38816f661cd3126613987ccbde39ab05 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Thu, 15 May 2025 14:33:15 -0700 Subject: [PATCH 2/8] Add sender option to LinuxSignals.cpp --- .../Plugins/Process/Utility/LinuxSignals.cpp | 142 +++++++++--------- .../Process/elf-core/ThreadElfCore.cpp | 32 ++-- .../Plugins/Process/elf-core/ThreadElfCore.h | 44 +++--- 3 files changed, 111 insertions(+), 107 deletions(-) diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index 25d4e4609bbb8..da0abf5a1f471 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -41,14 +41,14 @@ // See siginfo.h in the Linux Kernel, these codes can be sent for any signal. #define ADD_LINUX_SIGNAL(signo, name, ...) \ AddSignal(signo, name, __VA_ARGS__); \ - ADD_SIGCODE(signo, signo, SI_QUEUE, -1, "sent by sigqueue"); \ - ADD_SIGCODE(signo, signo, SI_TIMER, -2, "sent by timer expiration"); \ - ADD_SIGCODE(signo, signo, SI_MESGQ, -3, "sent by real time mesq state change"); \ - ADD_SIGCODE(signo, signo, SI_ASYNCIO, -4, "sent by AIO completion"); \ - ADD_SIGCODE(signo, signo, SI_SIGIO, -5, "sent by queued SIGIO"); \ - ADD_SIGCODE(signo, signo, SI_TKILL, -6, "sent by tkill system call"); \ - ADD_SIGCODE(signo, signo, SI_DETHREAD, -7, "sent by execve() killing subsidiary threads"); \ - ADD_SIGCODE(signo, signo, SI_ASYNCNL, -60, "sent by glibc async name lookup completion"); + ADD_SIGCODE(signo, signo, SI_QUEUE, -1, "sent by sigqueue", SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_TIMER, -2, "sent by timer expiration", SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_MESGQ, -3, "sent by real time mesq state change", SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_ASYNCIO, -4, "sent by AIO completion", SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_SIGIO, -5, "sent by queued SIGIO", SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_TKILL, -6, "sent by tkill system call", SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_DETHREAD, -7, "sent by execve() killing subsidiary threads", SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_ASYNCNL, -60, "sent by glibc async name lookup completion", SignalCodePrintOption::Sender); using namespace lldb_private; @@ -60,10 +60,10 @@ void LinuxSignals::Reset() { // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION // ====== ============== ======== ====== ====== =================================================== ADD_LINUX_SIGNAL(1, "SIGHUP", false, true, true, "hangup"); - AddSignal(2, "SIGINT", true, true, true, "interrupt"); - AddSignal(3, "SIGQUIT", false, true, true, "quit"); + ADD_LINUX_SIGNAL(2, "SIGINT", true, true, true, "interrupt"); + ADD_LINUX_SIGNAL(3, "SIGQUIT", false, true, true, "quit"); - AddSignal(4, "SIGILL", false, true, true, "illegal instruction"); + ADD_LINUX_SIGNAL(4, "SIGILL", false, true, true, "illegal instruction"); ADD_SIGCODE(SIGILL, 4, ILL_ILLOPC, 1, "illegal opcode"); ADD_SIGCODE(SIGILL, 4, ILL_ILLOPN, 2, "illegal operand"); ADD_SIGCODE(SIGILL, 4, ILL_ILLADR, 3, "illegal addressing mode"); @@ -73,15 +73,15 @@ void LinuxSignals::Reset() { ADD_SIGCODE(SIGILL, 4, ILL_COPROC, 7, "coprocessor error"); ADD_SIGCODE(SIGILL, 4, ILL_BADSTK, 8, "internal stack error"); - AddSignal(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)"); - AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT"); + ADD_LINUX_SIGNAL(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)"); + ADD_LINUX_SIGNAL(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT"); - AddSignal(7, "SIGBUS", false, true, true, "bus error"); + ADD_LINUX_SIGNAL(7, "SIGBUS", false, true, true, "bus error"); ADD_SIGCODE(SIGBUS, 7, BUS_ADRALN, 1, "illegal alignment"); ADD_SIGCODE(SIGBUS, 7, BUS_ADRERR, 2, "illegal address"); ADD_SIGCODE(SIGBUS, 7, BUS_OBJERR, 3, "hardware error"); - AddSignal(8, "SIGFPE", false, true, true, "floating point exception"); + ADD_LINUX_SIGNAL(8, "SIGFPE", false, true, true, "floating point exception"); ADD_SIGCODE(SIGFPE, 8, FPE_INTDIV, 1, "integer divide by zero"); ADD_SIGCODE(SIGFPE, 8, FPE_INTOVF, 2, "integer overflow"); ADD_SIGCODE(SIGFPE, 8, FPE_FLTDIV, 3, "floating point divide by zero"); @@ -91,10 +91,10 @@ void LinuxSignals::Reset() { ADD_SIGCODE(SIGFPE, 8, FPE_FLTINV, 7, "floating point invalid operation"); ADD_SIGCODE(SIGFPE, 8, FPE_FLTSUB, 8, "subscript out of range"); - AddSignal(9, "SIGKILL", false, true, true, "kill"); - AddSignal(10, "SIGUSR1", false, true, true, "user defined signal 1"); + ADD_LINUX_SIGNAL(9, "SIGKILL", false, true, true, "kill"); + ADD_LINUX_SIGNAL(10, "SIGUSR1", false, true, true, "user defined signal 1"); - AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation"); + ADD_LINUX_SIGNAL(11, "SIGSEGV", false, true, true, "segmentation violation"); ADD_SIGCODE(SIGSEGV, 11, SEGV_MAPERR, 1, "address not mapped to object", SignalCodePrintOption::Address); ADD_SIGCODE(SIGSEGV, 11, SEGV_ACCERR, 2, "invalid permissions for mapped object", SignalCodePrintOption::Address); ADD_SIGCODE(SIGSEGV, 11, SEGV_BNDERR, 3, "failed address bounds checks", SignalCodePrintOption::Bounds); @@ -105,58 +105,58 @@ void LinuxSignals::Reset() { // codes. One way to get this is via unaligned SIMD loads. Treat it as invalid address. ADD_SIGCODE(SIGSEGV, 11, SI_KERNEL, 0x80, "invalid address", SignalCodePrintOption::Address); - AddSignal(12, "SIGUSR2", false, true, true, "user defined signal 2"); - AddSignal(13, "SIGPIPE", false, true, true, "write to pipe with reading end closed"); - AddSignal(14, "SIGALRM", false, false, false, "alarm"); - AddSignal(15, "SIGTERM", false, true, true, "termination requested"); - AddSignal(16, "SIGSTKFLT", false, true, true, "stack fault"); - AddSignal(17, "SIGCHLD", false, false, true, "child status has changed", "SIGCLD"); - AddSignal(18, "SIGCONT", false, false, true, "process continue"); - AddSignal(19, "SIGSTOP", true, true, true, "process stop"); - AddSignal(20, "SIGTSTP", false, true, true, "tty stop"); - AddSignal(21, "SIGTTIN", false, true, true, "background tty read"); - AddSignal(22, "SIGTTOU", false, true, true, "background tty write"); - AddSignal(23, "SIGURG", false, true, true, "urgent data on socket"); - AddSignal(24, "SIGXCPU", false, true, true, "CPU resource exceeded"); - AddSignal(25, "SIGXFSZ", false, true, true, "file size limit exceeded"); - AddSignal(26, "SIGVTALRM", false, true, true, "virtual time alarm"); - AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm"); - AddSignal(28, "SIGWINCH", false, true, true, "window size changes"); - AddSignal(29, "SIGIO", false, true, true, "input/output ready/Pollable event", "SIGPOLL"); - AddSignal(30, "SIGPWR", false, true, true, "power failure"); - AddSignal(31, "SIGSYS", false, true, true, "invalid system call"); - AddSignal(32, "SIG32", false, false, false, "threading library internal signal 1"); - AddSignal(33, "SIG33", false, false, false, "threading library internal signal 2"); - AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0"); - AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1"); - AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2"); - AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3"); - AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4"); - AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5"); - AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6"); - AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7"); - AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8"); - AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9"); - AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10"); - AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11"); - AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12"); - AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13"); - AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14"); - AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15"); - AddSignal(50, "SIGRTMAX-14", false, false, false, "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output - AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17"); - AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18"); - AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19"); - AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20"); - AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21"); - AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22"); - AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23"); - AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24"); - AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25"); - AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26"); - AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27"); - AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28"); - AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29"); - AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30"); + ADD_LINUX_SIGNAL(12, "SIGUSR2", false, true, true, "user defined signal 2"); + ADD_LINUX_SIGNAL(13, "SIGPIPE", false, true, true, "write to pipe with reading end closed"); + ADD_LINUX_SIGNAL(14, "SIGALRM", false, false, false, "alarm"); + ADD_LINUX_SIGNAL(15, "SIGTERM", false, true, true, "termination requested"); + ADD_LINUX_SIGNAL(16, "SIGSTKFLT", false, true, true, "stack fault"); + ADD_LINUX_SIGNAL(17, "SIGCHLD", false, false, true, "child status has changed", "SIGCLD"); + ADD_LINUX_SIGNAL(18, "SIGCONT", false, false, true, "process continue"); + ADD_LINUX_SIGNAL(19, "SIGSTOP", true, true, true, "process stop"); + ADD_LINUX_SIGNAL(20, "SIGTSTP", false, true, true, "tty stop"); + ADD_LINUX_SIGNAL(21, "SIGTTIN", false, true, true, "background tty read"); + ADD_LINUX_SIGNAL(22, "SIGTTOU", false, true, true, "background tty write"); + ADD_LINUX_SIGNAL(23, "SIGURG", false, true, true, "urgent data on socket"); + ADD_LINUX_SIGNAL(24, "SIGXCPU", false, true, true, "CPU resource exceeded"); + ADD_LINUX_SIGNAL(25, "SIGXFSZ", false, true, true, "file size limit exceeded"); + ADD_LINUX_SIGNAL(26, "SIGVTALRM", false, true, true, "virtual time alarm"); + ADD_LINUX_SIGNAL(27, "SIGPROF", false, false, false, "profiling time alarm"); + ADD_LINUX_SIGNAL(28, "SIGWINCH", false, true, true, "window size changes"); + ADD_LINUX_SIGNAL(29, "SIGIO", false, true, true, "input/output ready/Pollable event", "SIGPOLL"); + ADD_LINUX_SIGNAL(30, "SIGPWR", false, true, true, "power failure"); + ADD_LINUX_SIGNAL(31, "SIGSYS", false, true, true, "invalid system call"); + ADD_LINUX_SIGNAL(32, "SIG32", false, false, false, "threading library internal signal 1"); + ADD_LINUX_SIGNAL(33, "SIG33", false, false, false, "threading library internal signal 2"); + ADD_LINUX_SIGNAL(34, "SIGRTMIN", false, false, false, "real time signal 0"); + ADD_LINUX_SIGNAL(35, "SIGRTMIN+1", false, false, false, "real time signal 1"); + ADD_LINUX_SIGNAL(36, "SIGRTMIN+2", false, false, false, "real time signal 2"); + ADD_LINUX_SIGNAL(37, "SIGRTMIN+3", false, false, false, "real time signal 3"); + ADD_LINUX_SIGNAL(38, "SIGRTMIN+4", false, false, false, "real time signal 4"); + ADD_LINUX_SIGNAL(39, "SIGRTMIN+5", false, false, false, "real time signal 5"); + ADD_LINUX_SIGNAL(40, "SIGRTMIN+6", false, false, false, "real time signal 6"); + ADD_LINUX_SIGNAL(41, "SIGRTMIN+7", false, false, false, "real time signal 7"); + ADD_LINUX_SIGNAL(42, "SIGRTMIN+8", false, false, false, "real time signal 8"); + ADD_LINUX_SIGNAL(43, "SIGRTMIN+9", false, false, false, "real time signal 9"); + ADD_LINUX_SIGNAL(44, "SIGRTMIN+10", false, false, false, "real time signal 10"); + ADD_LINUX_SIGNAL(45, "SIGRTMIN+11", false, false, false, "real time signal 11"); + ADD_LINUX_SIGNAL(46, "SIGRTMIN+12", false, false, false, "real time signal 12"); + ADD_LINUX_SIGNAL(47, "SIGRTMIN+13", false, false, false, "real time signal 13"); + ADD_LINUX_SIGNAL(48, "SIGRTMIN+14", false, false, false, "real time signal 14"); + ADD_LINUX_SIGNAL(49, "SIGRTMIN+15", false, false, false, "real time signal 15"); + ADD_LINUX_SIGNAL(50, "SIGRTMAX-14", false, false, false, "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output + ADD_LINUX_SIGNAL(51, "SIGRTMAX-13", false, false, false, "real time signal 17"); + ADD_LINUX_SIGNAL(52, "SIGRTMAX-12", false, false, false, "real time signal 18"); + ADD_LINUX_SIGNAL(53, "SIGRTMAX-11", false, false, false, "real time signal 19"); + ADD_LINUX_SIGNAL(54, "SIGRTMAX-10", false, false, false, "real time signal 20"); + ADD_LINUX_SIGNAL(55, "SIGRTMAX-9", false, false, false, "real time signal 21"); + ADD_LINUX_SIGNAL(56, "SIGRTMAX-8", false, false, false, "real time signal 22"); + ADD_LINUX_SIGNAL(57, "SIGRTMAX-7", false, false, false, "real time signal 23"); + ADD_LINUX_SIGNAL(58, "SIGRTMAX-6", false, false, false, "real time signal 24"); + ADD_LINUX_SIGNAL(59, "SIGRTMAX-5", false, false, false, "real time signal 25"); + ADD_LINUX_SIGNAL(60, "SIGRTMAX-4", false, false, false, "real time signal 26"); + ADD_LINUX_SIGNAL(61, "SIGRTMAX-3", false, false, false, "real time signal 27"); + ADD_LINUX_SIGNAL(62, "SIGRTMAX-2", false, false, false, "real time signal 28"); + ADD_LINUX_SIGNAL(63, "SIGRTMAX-1", false, false, false, "real time signal 29"); + ADD_LINUX_SIGNAL(64, "SIGRTMAX", false, false, false, "real time signal 30"); // clang-format on } diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index 267879a473463..ce0f65cd9f14c 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -586,24 +586,24 @@ Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, offset += 4; if (si_code < 0) { - sigfault.kill._pid = data.GetU32(&offset); - sigfault.kill._uid = data.GetU32(&offset); + sifields.kill.pid = data.GetU32(&offset); + sifields.kill.uid = data.GetU32(&offset); } else if (unix_signals.GetShouldStop(si_signo)) { // Not every stop signal has a valid address, but that will get resolved in // the unix_signals.GetSignalDescription() call below. // Instead of memcpy we call all these individually as the extractor will // handle endianness for us. - sigfault.si_addr = data.GetAddress(&offset); - sigfault.si_addr_lsb = data.GetU16(&offset); - if (data.GetByteSize() - offset >= sizeof(sigfault.bounds)) { - sigfault.bounds._addr_bnd._lower = data.GetAddress(&offset); - sigfault.bounds._addr_bnd._upper = data.GetAddress(&offset); - sigfault.bounds._pkey = data.GetU32(&offset); + sifields.sigfault.si_addr = data.GetAddress(&offset); + sifields.sigfault.si_addr_lsb = data.GetU16(&offset); + if (data.GetByteSize() - offset >= sizeof(sifields.sigfault.bounds)) { + sifields.sigfault.bounds._addr_bnd._lower = data.GetAddress(&offset); + sifields.sigfault.bounds._addr_bnd._upper = data.GetAddress(&offset); + sifields.sigfault.bounds._pkey = data.GetU32(&offset); } else { // Set these to 0 so we don't use bogus data for the description. - sigfault.bounds._addr_bnd._lower = 0; - sigfault.bounds._addr_bnd._upper = 0; - sigfault.bounds._pkey = 0; + sifields.sigfault.bounds._addr_bnd._lower = 0; + sifields.sigfault.bounds._addr_bnd._upper = 0; + sifields.sigfault.bounds._pkey = 0; } } @@ -613,13 +613,15 @@ Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, std::string ELFLinuxSigInfo::GetDescription( const lldb_private::UnixSignals &unix_signals) const { if (unix_signals.GetShouldStop(si_signo) && note_type == eNT_SIGINFO) { - if (sigfault.bounds._addr_bnd._upper != 0) + if (si_code < 0) + return unix_signals.GetSignalDescription(si_signo, si_code, std::nullopt, std::nullopt, std::nullopt, sifields.kill.pid, sifields.kill.uid); + else if (sifields.sigfault.bounds._addr_bnd._upper != 0) return unix_signals.GetSignalDescription( - si_signo, si_code, sigfault.si_addr, sigfault.bounds._addr_bnd._lower, - sigfault.bounds._addr_bnd._upper); + si_signo, si_code, sifields.sigfault.si_addr, sifields.sigfault.bounds._addr_bnd._lower, + sifields.sigfault.bounds._addr_bnd._upper); else return unix_signals.GetSignalDescription(si_signo, si_code, - sigfault.si_addr); + sifields.sigfault.si_addr); } // This looks weird, but there is an existing pattern where we don't pass a diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h index 2cbf794c2b5b1..2c254b4b522e9 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -82,27 +82,29 @@ struct ELFLinuxSigInfo { int32_t si_signo; // Order matters for the first 3. int32_t si_errno; int32_t si_code; - // Copied from siginfo_t so we don't have to include signal.h on non 'Nix - // builds. Slight modifications to ensure no 32b vs 64b differences. - struct alignas(8) { - lldb::addr_t si_addr; /* faulting insn/memory ref. */ - int16_t si_addr_lsb; /* Valid LSB of the reported address. */ - union { - /* used when si_code=SEGV_BNDERR */ - struct { - lldb::addr_t _lower; - lldb::addr_t _upper; - } _addr_bnd; - /* used when si_code=SEGV_PKUERR */ - uint32_t _pkey; - } bounds; - - // We need this for all the generic signals. - struct { - uint32_t _pid; /* sender's pid */ - uint32_t _uid; /* sender's uid */ - } _kill; - } sigfault; + union alignas(8) { + struct alignas(8) { + uint32_t pid; /* sender's pid */ + uint32_t uid; /* sender's uid */ + } kill; + // Copied from siginfo_t so we don't have to include signal.h on non 'Nix + // builds. Slight modifications to ensure no 32b vs 64b differences. + struct alignas(8) { + lldb::addr_t si_addr; /* faulting insn/memory ref. */ + int16_t si_addr_lsb; /* Valid LSB of the reported address. */ + union { + /* used when si_code=SEGV_BNDERR */ + struct { + lldb::addr_t _lower; + lldb::addr_t _upper; + } _addr_bnd; + /* used when si_code=SEGV_PKUERR */ + uint32_t _pkey; + } bounds; + + // We need this for all the generic signals. + } sigfault; + } sifields; enum SigInfoNoteType : uint8_t { eUnspecified, eNT_SIGINFO }; SigInfoNoteType note_type; >From 9e352e71666628c7e81f520e8619779cc7a6e150 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Thu, 15 May 2025 14:46:40 -0700 Subject: [PATCH 3/8] Add test for sender case --- lldb/unittests/Signals/UnixSignalsTest.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lldb/unittests/Signals/UnixSignalsTest.cpp b/lldb/unittests/Signals/UnixSignalsTest.cpp index 9a7d9afc2b185..825cc5ea6a782 100644 --- a/lldb/unittests/Signals/UnixSignalsTest.cpp +++ b/lldb/unittests/Signals/UnixSignalsTest.cpp @@ -27,6 +27,7 @@ class TestSignals : public UnixSignals { AddSignalCode(16, 2, "SIG16 with a fault address", SignalCodePrintOption::Address); AddSignalCode(16, 3, "bounds violation", SignalCodePrintOption::Bounds); + AddSignalCode(16, -6, "sent by tkill system call", SignalCodePrintOption::Sender); } }; @@ -124,6 +125,10 @@ TEST(UnixSignalsTest, GetAsString) { // No address given just print the code description. ASSERT_EQ("SIG16: SIG16 with a fault address", signals.GetSignalDescription(16, 2)); + // TKill, but with no sender + ASSERT_EQ("SIG16: sent by tkill system call", signals.GetSignalDescription(16, -6, 0xCAFEF00D)); + // TKill, but with no sender + ASSERT_EQ("SIG16: sent by tkill system call (sender pid=912, uid=99)", signals.GetSignalDescription(16, -6, 0xCAFEF00D, std::nullopt, std::nullopt, 912, 99)); const char *expected = "SIG16: bounds violation"; // Must pass all needed info to get full output. >From 1a1b9fa48bead59a15291a58814e363cd4412f55 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Thu, 15 May 2025 15:03:32 -0700 Subject: [PATCH 4/8] run GCF --- .../Plugins/Process/Utility/LinuxSignals.cpp | 31 +++++++++++++------ .../Process/elf-core/ThreadElfCore.cpp | 17 +++++----- .../Plugins/Process/elf-core/ThreadElfCore.h | 4 +-- lldb/source/Target/UnixSignals.cpp | 12 +++---- lldb/unittests/Signals/UnixSignalsTest.cpp | 10 ++++-- 5 files changed, 45 insertions(+), 29 deletions(-) diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index da0abf5a1f471..76c32e376eb4b 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -39,16 +39,27 @@ AddSignalCode(signal_value, code_value, __VA_ARGS__) #endif /* if defined(__linux__) && !defined(__mips__) */ // See siginfo.h in the Linux Kernel, these codes can be sent for any signal. -#define ADD_LINUX_SIGNAL(signo, name, ...) \ - AddSignal(signo, name, __VA_ARGS__); \ - ADD_SIGCODE(signo, signo, SI_QUEUE, -1, "sent by sigqueue", SignalCodePrintOption::Sender); \ - ADD_SIGCODE(signo, signo, SI_TIMER, -2, "sent by timer expiration", SignalCodePrintOption::Sender); \ - ADD_SIGCODE(signo, signo, SI_MESGQ, -3, "sent by real time mesq state change", SignalCodePrintOption::Sender); \ - ADD_SIGCODE(signo, signo, SI_ASYNCIO, -4, "sent by AIO completion", SignalCodePrintOption::Sender); \ - ADD_SIGCODE(signo, signo, SI_SIGIO, -5, "sent by queued SIGIO", SignalCodePrintOption::Sender); \ - ADD_SIGCODE(signo, signo, SI_TKILL, -6, "sent by tkill system call", SignalCodePrintOption::Sender); \ - ADD_SIGCODE(signo, signo, SI_DETHREAD, -7, "sent by execve() killing subsidiary threads", SignalCodePrintOption::Sender); \ - ADD_SIGCODE(signo, signo, SI_ASYNCNL, -60, "sent by glibc async name lookup completion", SignalCodePrintOption::Sender); +#define ADD_LINUX_SIGNAL(signo, name, ...) \ + AddSignal(signo, name, __VA_ARGS__); \ + ADD_SIGCODE(signo, signo, SI_QUEUE, -1, "sent by sigqueue", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_TIMER, -2, "sent by timer expiration", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_MESGQ, -3, \ + "sent by real time mesq state change", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_ASYNCIO, -4, "sent by AIO completion", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_SIGIO, -5, "sent by queued SIGIO", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_TKILL, -6, "sent by tkill system call", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_DETHREAD, -7, \ + "sent by execve() killing subsidiary threads", \ + SignalCodePrintOption::Sender); \ + ADD_SIGCODE(signo, signo, SI_ASYNCNL, -60, \ + "sent by glibc async name lookup completion", \ + SignalCodePrintOption::Sender); using namespace lldb_private; diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index ce0f65cd9f14c..907e009bc7b80 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -585,10 +585,10 @@ Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, if (data.GetAddressByteSize() == 8) offset += 4; - if (si_code < 0) { - sifields.kill.pid = data.GetU32(&offset); - sifields.kill.uid = data.GetU32(&offset); - } else if (unix_signals.GetShouldStop(si_signo)) { + if (si_code < 0) { + sifields.kill.pid = data.GetU32(&offset); + sifields.kill.uid = data.GetU32(&offset); + } else if (unix_signals.GetShouldStop(si_signo)) { // Not every stop signal has a valid address, but that will get resolved in // the unix_signals.GetSignalDescription() call below. // Instead of memcpy we call all these individually as the extractor will @@ -614,14 +614,17 @@ std::string ELFLinuxSigInfo::GetDescription( const lldb_private::UnixSignals &unix_signals) const { if (unix_signals.GetShouldStop(si_signo) && note_type == eNT_SIGINFO) { if (si_code < 0) - return unix_signals.GetSignalDescription(si_signo, si_code, std::nullopt, std::nullopt, std::nullopt, sifields.kill.pid, sifields.kill.uid); + return unix_signals.GetSignalDescription( + si_signo, si_code, std::nullopt, std::nullopt, std::nullopt, + sifields.kill.pid, sifields.kill.uid); else if (sifields.sigfault.bounds._addr_bnd._upper != 0) return unix_signals.GetSignalDescription( - si_signo, si_code, sifields.sigfault.si_addr, sifields.sigfault.bounds._addr_bnd._lower, + si_signo, si_code, sifields.sigfault.si_addr, + sifields.sigfault.bounds._addr_bnd._lower, sifields.sigfault.bounds._addr_bnd._upper); else return unix_signals.GetSignalDescription(si_signo, si_code, - sifields.sigfault.si_addr); + sifields.sigfault.si_addr); } // This looks weird, but there is an existing pattern where we don't pass a diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h index 2c254b4b522e9..40434543b7bb2 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -84,8 +84,8 @@ struct ELFLinuxSigInfo { int32_t si_code; union alignas(8) { struct alignas(8) { - uint32_t pid; /* sender's pid */ - uint32_t uid; /* sender's uid */ + uint32_t pid; /* sender's pid */ + uint32_t uid; /* sender's uid */ } kill; // Copied from siginfo_t so we don't have to include signal.h on non 'Nix // builds. Slight modifications to ensure no 32b vs 64b differences. diff --git a/lldb/source/Target/UnixSignals.cpp b/lldb/source/Target/UnixSignals.cpp index a5dbfd029410a..6113c6648817c 100644 --- a/lldb/source/Target/UnixSignals.cpp +++ b/lldb/source/Target/UnixSignals.cpp @@ -137,13 +137,11 @@ llvm::StringRef UnixSignals::GetSignalAsStringRef(int32_t signo) const { return pos->second.m_name; } -std::string -UnixSignals::GetSignalDescription(int32_t signo, std::optional code, - std::optional addr, - std::optional lower, - std::optional upper, - std::optional pid, - std::optional uid) const { +std::string UnixSignals::GetSignalDescription( + int32_t signo, std::optional code, + std::optional addr, std::optional lower, + std::optional upper, std::optional pid, + std::optional uid) const { std::string str; collection::const_iterator pos = m_signals.find(signo); diff --git a/lldb/unittests/Signals/UnixSignalsTest.cpp b/lldb/unittests/Signals/UnixSignalsTest.cpp index 825cc5ea6a782..582e441556067 100644 --- a/lldb/unittests/Signals/UnixSignalsTest.cpp +++ b/lldb/unittests/Signals/UnixSignalsTest.cpp @@ -27,7 +27,8 @@ class TestSignals : public UnixSignals { AddSignalCode(16, 2, "SIG16 with a fault address", SignalCodePrintOption::Address); AddSignalCode(16, 3, "bounds violation", SignalCodePrintOption::Bounds); - AddSignalCode(16, -6, "sent by tkill system call", SignalCodePrintOption::Sender); + AddSignalCode(16, -6, "sent by tkill system call", + SignalCodePrintOption::Sender); } }; @@ -126,9 +127,12 @@ TEST(UnixSignalsTest, GetAsString) { ASSERT_EQ("SIG16: SIG16 with a fault address", signals.GetSignalDescription(16, 2)); // TKill, but with no sender - ASSERT_EQ("SIG16: sent by tkill system call", signals.GetSignalDescription(16, -6, 0xCAFEF00D)); + ASSERT_EQ("SIG16: sent by tkill system call", + signals.GetSignalDescription(16, -6, 0xCAFEF00D)); // TKill, but with no sender - ASSERT_EQ("SIG16: sent by tkill system call (sender pid=912, uid=99)", signals.GetSignalDescription(16, -6, 0xCAFEF00D, std::nullopt, std::nullopt, 912, 99)); + ASSERT_EQ("SIG16: sent by tkill system call (sender pid=912, uid=99)", + signals.GetSignalDescription(16, -6, 0xCAFEF00D, std::nullopt, + std::nullopt, 912, 99)); const char *expected = "SIG16: bounds violation"; // Must pass all needed info to get full output. >From d8c2a04859e7c10617c15eacc02a303d66b83121 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Fri, 16 May 2025 14:56:06 -0700 Subject: [PATCH 5/8] Reconfigure the parsing to get the bytes and convert to value object, then parse that in thlinux signals --- lldb/include/lldb/Target/UnixSignals.h | 3 + .../Plugins/Process/Utility/LinuxSignals.cpp | 42 ++++++ .../Plugins/Process/Utility/LinuxSignals.h | 2 + .../Process/elf-core/ProcessElfCore.cpp | 19 ++- .../Process/elf-core/ThreadElfCore.cpp | 129 +++++------------- .../Plugins/Process/elf-core/ThreadElfCore.h | 69 ++-------- 6 files changed, 105 insertions(+), 159 deletions(-) diff --git a/lldb/include/lldb/Target/UnixSignals.h b/lldb/include/lldb/Target/UnixSignals.h index a1807d69f329b..9ae4048ed683d 100644 --- a/lldb/include/lldb/Target/UnixSignals.h +++ b/lldb/include/lldb/Target/UnixSignals.h @@ -15,6 +15,7 @@ #include #include "lldb/lldb-private.h" +#include "lldb/ValueObject/ValueObject.h" #include "llvm/Support/JSON.h" namespace lldb_private { @@ -31,6 +32,8 @@ class UnixSignals { llvm::StringRef GetSignalAsStringRef(int32_t signo) const; + virtual std::string GetSignalDescriptionFromSiginfo(lldb::ValueObjectSP siginfo_sp) const { return ""; }; + std::string GetSignalDescription(int32_t signo, std::optional code = std::nullopt, diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index 76c32e376eb4b..392675a265f5d 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -171,3 +171,45 @@ void LinuxSignals::Reset() { ADD_LINUX_SIGNAL(64, "SIGRTMAX", false, false, false, "real time signal 30"); // clang-format on } + +std::string LinuxSignals::GetSignalDescriptionFromSiginfo(lldb::ValueObjectSP siginfo_sp) const { + if (!siginfo_sp) + return ""; + + int code = siginfo_sp->GetChildMemberWithName("si_code")->GetValueAsSigned(0); + int signo = siginfo_sp->GetChildMemberWithName("si_signo")->GetValueAsSigned(-1); + // si_code = 0 is SI_NOINFO, we just want the description with nothing important + if (code == 0) + return GetSignalDescription(signo, code); + + lldb::ValueObjectSP sifields = siginfo_sp->GetChildMemberWithName("_sifields"); + // The negative si_codes are special and mean this signal was sent from user space + // not the kernel. These take precedence because they break some of the invariants + // around kernel sent signals. Such as SIGSEGV won't have an address. + if (code < 0) { + lldb::ValueObjectSP sikill = sifields->GetChildMemberWithName("_kill"); + uint32_t pid = sikill->GetChildMemberWithName("_pid")->GetValueAsUnsigned(-1); + uint32_t uid = sikill->GetChildMemberWithName("_uid")->GetValueAsUnsigned(-1); + return GetSignalDescription(signo, code, std::nullopt, std::nullopt, std::nullopt, pid, uid); + } + + switch (signo) { + case SIGILL: + case SIGFPE: + case SIGBUS: { + lldb::ValueObjectSP sigfault = sifields->GetChildMemberWithName("_sigfault"); + lldb::addr_t addr = sigfault->GetChildMemberWithName("_addr")->GetValueAsUnsigned(-1); + return GetSignalDescription(signo, code, addr); + } + case SIGSEGV: { + lldb::ValueObjectSP sigfault = sifields->GetChildMemberWithName("_sigfault"); + lldb::addr_t addr = sigfault->GetChildMemberWithName("_addr")->GetValueAsUnsigned(-1); + lldb::ValueObjectSP bounds = sigfault->GetChildMemberWithName("_addr_bnd"); + lldb::addr_t lower = bounds->GetChildMemberWithName("_lower")->GetValueAsUnsigned(-1); + lldb::addr_t upper = bounds->GetChildMemberWithName("_upper")->GetValueAsUnsigned(-1); + return GetSignalDescription(signo, code, addr, lower, upper); + } + default: + return GetSignalDescription(signo, code); + } +} diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.h b/lldb/source/Plugins/Process/Utility/LinuxSignals.h index 32c4744a96d04..414cfd531388f 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.h +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.h @@ -18,6 +18,8 @@ class LinuxSignals : public UnixSignals { public: LinuxSignals(); + std::string GetSignalDescriptionFromSiginfo(lldb::ValueObjectSP siginfo_sp) const override; + private: void Reset() override; }; diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 6635b15b669f1..dc3e9616dc9c0 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -232,7 +232,7 @@ Status ProcessElfCore::DoLoadCore() { bool prstatus_signal_found = false; // Check we found a signal in a SIGINFO note. for (const auto &thread_data : m_thread_data) { - if (thread_data.siginfo.si_signo != 0) + if (!thread_data.siginfo_bytes.empty()) siginfo_signal_found = true; if (thread_data.prstatus_sig != 0) prstatus_signal_found = true; @@ -242,10 +242,10 @@ Status ProcessElfCore::DoLoadCore() { // PRSTATUS note. if (prstatus_signal_found) { for (auto &thread_data : m_thread_data) - thread_data.siginfo.si_signo = thread_data.prstatus_sig; + thread_data.signo = thread_data.prstatus_sig; } else if (m_thread_data.size() > 0) { // If all else fails force the first thread to be SIGSTOP - m_thread_data.begin()->siginfo.si_signo = + m_thread_data.begin()->signo = GetUnixSignals()->GetSignalNumberFromName("SIGSTOP"); } } @@ -506,7 +506,7 @@ static void ParseFreeBSDPrStatus(ThreadData &thread_data, else offset += 16; - thread_data.siginfo.si_signo = data.GetU32(&offset); // pr_cursig + thread_data.signo = data.GetU32(&offset); // pr_cursig thread_data.tid = data.GetU32(&offset); // pr_pid if (lp64) offset += 4; @@ -589,7 +589,7 @@ static void ParseOpenBSDProcInfo(ThreadData &thread_data, return; offset += 4; - thread_data.siginfo.si_signo = data.GetU32(&offset); + thread_data.signo = data.GetU32(&offset); } llvm::Expected> @@ -827,7 +827,7 @@ llvm::Error ProcessElfCore::parseNetBSDNotes(llvm::ArrayRef notes) { // Signal targeted at the whole process. if (siglwp == 0) { for (auto &data : m_thread_data) - data.siginfo.si_signo = signo; + data.signo = signo; } // Signal destined for a particular LWP. else { @@ -835,7 +835,7 @@ llvm::Error ProcessElfCore::parseNetBSDNotes(llvm::ArrayRef notes) { for (auto &data : m_thread_data) { if (data.tid == siglwp) { - data.siginfo.si_signo = signo; + data.signo = signo; passed = true; break; } @@ -938,12 +938,9 @@ llvm::Error ProcessElfCore::parseLinuxNotes(llvm::ArrayRef notes) { break; } case ELF::NT_SIGINFO: { - const lldb_private::UnixSignals &unix_signals = *GetUnixSignals(); - ELFLinuxSigInfo siginfo; - Status status = siginfo.Parse(note.data, arch, unix_signals); + Status status = ELFLinuxSigInfo::Parse(note.data, arch, GetTarget().GetPlatform(), thread_data); if (status.Fail()) return status.ToError(); - thread_data.siginfo = siginfo; break; } case ELF::NT_FILE: { diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index 907e009bc7b80..766b9b6d331fb 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -52,7 +52,7 @@ using namespace lldb_private; ThreadElfCore::ThreadElfCore(Process &process, const ThreadData &td) : Thread(process, td.tid), m_thread_name(td.name), m_thread_reg_ctx_sp(), m_gpregset_data(td.gpregset), m_notes(td.notes), - m_siginfo(std::move(td.siginfo)) {} + m_siginfo_bytes(std::move(td.siginfo_bytes)), m_signo(td.signo) {} ThreadElfCore::~ThreadElfCore() { DestroyThread(); } @@ -243,6 +243,14 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { return reg_ctx_sp; } +llvm::Expected> ThreadElfCore::GetSiginfo(size_t max_size) const { + if (m_siginfo_bytes.empty()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "no siginfo note"); + + return llvm::MemoryBuffer::getMemBufferCopy(m_siginfo_bytes, "siginfo note bytes"); +} + bool ThreadElfCore::CalculateStopInfo() { ProcessSP process_sp(GetProcess()); if (!process_sp) @@ -252,15 +260,17 @@ bool ThreadElfCore::CalculateStopInfo() { if (!unix_signals_sp) return false; - const char *sig_description; - std::string description = m_siginfo.GetDescription(*unix_signals_sp); - if (description.empty()) - sig_description = nullptr; - else - sig_description = description.c_str(); - - SetStopInfo(StopInfo::CreateStopReasonWithSignal( - *this, m_siginfo.si_signo, sig_description, m_siginfo.si_code)); + lldb::ValueObjectSP siginfo = GetSiginfoValue(); + if (!siginfo || !siginfo->GetValueIsValid()) { + std::string description = unix_signals_sp->GetSignalDescription(m_signo, 0); + SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, m_signo, description.c_str(), 0)); + } else { + std::string description = unix_signals_sp->GetSignalDescriptionFromSiginfo(siginfo); + uint32_t signo = siginfo->GetChildMemberWithName("si_signo")->GetValueAsUnsigned(-1); + uint32_t code = siginfo->GetChildMemberWithName("si_code")->GetValueAsUnsigned(0); + SetStopInfo(StopInfo::CreateStopReasonWithSignal( + *this, signo, description.c_str(), code)); + } SetStopInfo(m_stop_info_sp); return true; @@ -544,91 +554,22 @@ ELFLinuxPrPsInfo::Populate(const lldb_private::ProcessInstanceInfo &info, return prpsinfo; } -// Parse SIGINFO from NOTE entry -ELFLinuxSigInfo::ELFLinuxSigInfo() { memset(this, 0, sizeof(ELFLinuxSigInfo)); } +Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, const lldb::PlatformSP platform_sp, ThreadData &thread_data) { + if (!platform_sp) + return Status::FromErrorString("No platform for arch."); + CompilerType type = platform_sp->GetSiginfoType(arch.GetTriple()); + if (!type.IsValid()) + return Status::FromErrorString("no siginfo_t for platform."); -size_t ELFLinuxSigInfo::GetSize(const lldb_private::ArchSpec &arch) { - if (arch.IsMIPS()) - return sizeof(ELFLinuxSigInfo); - switch (arch.GetCore()) { - case lldb_private::ArchSpec::eCore_x86_64_x86_64: - return sizeof(ELFLinuxSigInfo); - case lldb_private::ArchSpec::eCore_s390x_generic: - case lldb_private::ArchSpec::eCore_x86_32_i386: - case lldb_private::ArchSpec::eCore_x86_32_i486: - return 12; - default: - return 0; - } -} + auto type_size_or_err = type.GetByteSize(nullptr); + if (!type_size_or_err) + return Status::FromError(type_size_or_err.takeError()); -Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, - const lldb_private::UnixSignals &unix_signals) { - Status error; - uint64_t size = GetSize(arch); - if (size > data.GetByteSize()) { - error = Status::FromErrorStringWithFormat( - "NT_SIGINFO size should be %zu, but the remaining bytes are: %" PRIu64, - GetSize(arch), data.GetByteSize()); - return error; - } - - // Set that we've parsed the siginfo from a SIGINFO note. - note_type = eNT_SIGINFO; - // Parsing from a 32 bit ELF core file, and populating/reusing the structure - // properly, because the struct is for the 64 bit version - offset_t offset = 0; - si_signo = data.GetU32(&offset); - si_errno = data.GetU32(&offset); - si_code = data.GetU32(&offset); - // 64b ELF have a 4 byte pad. - if (data.GetAddressByteSize() == 8) - offset += 4; - - if (si_code < 0) { - sifields.kill.pid = data.GetU32(&offset); - sifields.kill.uid = data.GetU32(&offset); - } else if (unix_signals.GetShouldStop(si_signo)) { - // Not every stop signal has a valid address, but that will get resolved in - // the unix_signals.GetSignalDescription() call below. - // Instead of memcpy we call all these individually as the extractor will - // handle endianness for us. - sifields.sigfault.si_addr = data.GetAddress(&offset); - sifields.sigfault.si_addr_lsb = data.GetU16(&offset); - if (data.GetByteSize() - offset >= sizeof(sifields.sigfault.bounds)) { - sifields.sigfault.bounds._addr_bnd._lower = data.GetAddress(&offset); - sifields.sigfault.bounds._addr_bnd._upper = data.GetAddress(&offset); - sifields.sigfault.bounds._pkey = data.GetU32(&offset); - } else { - // Set these to 0 so we don't use bogus data for the description. - sifields.sigfault.bounds._addr_bnd._lower = 0; - sifields.sigfault.bounds._addr_bnd._upper = 0; - sifields.sigfault.bounds._pkey = 0; - } - } - - return error; -} - -std::string ELFLinuxSigInfo::GetDescription( - const lldb_private::UnixSignals &unix_signals) const { - if (unix_signals.GetShouldStop(si_signo) && note_type == eNT_SIGINFO) { - if (si_code < 0) - return unix_signals.GetSignalDescription( - si_signo, si_code, std::nullopt, std::nullopt, std::nullopt, - sifields.kill.pid, sifields.kill.uid); - else if (sifields.sigfault.bounds._addr_bnd._upper != 0) - return unix_signals.GetSignalDescription( - si_signo, si_code, sifields.sigfault.si_addr, - sifields.sigfault.bounds._addr_bnd._lower, - sifields.sigfault.bounds._addr_bnd._upper); - else - return unix_signals.GetSignalDescription(si_signo, si_code, - sifields.sigfault.si_addr); - } + if (data.GetByteSize() < *type_size_or_err) + return Status::FromErrorString("siginfo note byte size smaller than siginfo_t for platform."); - // This looks weird, but there is an existing pattern where we don't pass a - // description to keep up with that, we return empty here, and then the above - // function will set the description whether or not this is empty. - return std::string(); + lldb::offset_t offset = 0; + const char *bytes = static_cast(data.GetData(&offset, *type_size_or_err)); + thread_data.siginfo_bytes = llvm::StringRef(bytes, *type_size_or_err); + return Status(); } diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h index 40434543b7bb2..413719a1a26f4 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -12,6 +12,8 @@ #include "Plugins/Process/elf-core/RegisterUtilities.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataExtractor.h" +#include "lldb/ValueObject/ValueObject.h" +#include "lldb/Target/Platform.h" #include "llvm/ADT/DenseMap.h" #include #include @@ -77,57 +79,14 @@ struct ELFLinuxPrStatus { static_assert(sizeof(ELFLinuxPrStatus) == 112, "sizeof ELFLinuxPrStatus is not correct!"); -struct ELFLinuxSigInfo { - - int32_t si_signo; // Order matters for the first 3. - int32_t si_errno; - int32_t si_code; - union alignas(8) { - struct alignas(8) { - uint32_t pid; /* sender's pid */ - uint32_t uid; /* sender's uid */ - } kill; - // Copied from siginfo_t so we don't have to include signal.h on non 'Nix - // builds. Slight modifications to ensure no 32b vs 64b differences. - struct alignas(8) { - lldb::addr_t si_addr; /* faulting insn/memory ref. */ - int16_t si_addr_lsb; /* Valid LSB of the reported address. */ - union { - /* used when si_code=SEGV_BNDERR */ - struct { - lldb::addr_t _lower; - lldb::addr_t _upper; - } _addr_bnd; - /* used when si_code=SEGV_PKUERR */ - uint32_t _pkey; - } bounds; - - // We need this for all the generic signals. - } sigfault; - } sifields; - - enum SigInfoNoteType : uint8_t { eUnspecified, eNT_SIGINFO }; - SigInfoNoteType note_type; - - ELFLinuxSigInfo(); - - lldb_private::Status Parse(const lldb_private::DataExtractor &data, - const lldb_private::ArchSpec &arch, - const lldb_private::UnixSignals &unix_signals); - - std::string - GetDescription(const lldb_private::UnixSignals &unix_signals) const; - - // Return the bytesize of the structure - // 64 bit - just sizeof - // 32 bit - hardcoded because we are reusing the struct, but some of the - // members are smaller - - // so the layout is not the same - static size_t GetSize(const lldb_private::ArchSpec &arch); +class ELFLinuxSigInfo { +public: + static lldb_private::Status Parse(const lldb_private::DataExtractor &data, + const lldb_private::ArchSpec &arch, + const lldb::PlatformSP platform_sp, + ThreadData &thread_data); }; -static_assert(sizeof(ELFLinuxSigInfo) == 56, - "sizeof ELFLinuxSigInfo is not correct!"); // PRPSINFO structure's size differs based on architecture. // This is the layout in the x86-64 arch case. @@ -176,8 +135,9 @@ struct ThreadData { std::vector notes; lldb::tid_t tid; std::string name; - ELFLinuxSigInfo siginfo; - int prstatus_sig = 0; + llvm::StringRef siginfo_bytes; + int prstatus_sig; + int signo; }; class ThreadElfCore : public lldb_private::Thread { @@ -208,8 +168,7 @@ class ThreadElfCore : public lldb_private::Thread { m_thread_name.clear(); } - void CreateStopFromSigInfo(const ELFLinuxSigInfo &siginfo, - const lldb_private::UnixSignals &unix_signals); + llvm::Expected> GetSiginfo(size_t max_size) const override; protected: // Member variables. @@ -218,7 +177,9 @@ class ThreadElfCore : public lldb_private::Thread { lldb_private::DataExtractor m_gpregset_data; std::vector m_notes; - ELFLinuxSigInfo m_siginfo; + llvm::StringRef m_siginfo_bytes; + // Only used if no siginfo note. + int m_signo; bool CalculateStopInfo() override; }; >From f2b2f8d37029b8172eac844dc2f812d46556d2c8 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Fri, 16 May 2025 15:52:19 -0700 Subject: [PATCH 6/8] Refactor from testing, discovered that the compiler type generated signal differs from the linux definition --- .../Plugins/Process/Utility/LinuxSignals.cpp | 11 ++++++----- .../Plugins/Process/elf-core/ThreadElfCore.h | 19 ++++++++++--------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index 392675a265f5d..aef1b3f1d0a12 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -188,8 +188,8 @@ std::string LinuxSignals::GetSignalDescriptionFromSiginfo(lldb::ValueObjectSP si // around kernel sent signals. Such as SIGSEGV won't have an address. if (code < 0) { lldb::ValueObjectSP sikill = sifields->GetChildMemberWithName("_kill"); - uint32_t pid = sikill->GetChildMemberWithName("_pid")->GetValueAsUnsigned(-1); - uint32_t uid = sikill->GetChildMemberWithName("_uid")->GetValueAsUnsigned(-1); + uint32_t pid = sikill->GetChildMemberWithName("si_pid")->GetValueAsUnsigned(-1); + uint32_t uid = sikill->GetChildMemberWithName("si_uid")->GetValueAsUnsigned(-1); return GetSignalDescription(signo, code, std::nullopt, std::nullopt, std::nullopt, pid, uid); } @@ -198,13 +198,14 @@ std::string LinuxSignals::GetSignalDescriptionFromSiginfo(lldb::ValueObjectSP si case SIGFPE: case SIGBUS: { lldb::ValueObjectSP sigfault = sifields->GetChildMemberWithName("_sigfault"); - lldb::addr_t addr = sigfault->GetChildMemberWithName("_addr")->GetValueAsUnsigned(-1); + lldb::addr_t addr = sigfault->GetChildMemberWithName("si_addr")->GetValueAsUnsigned(-1); return GetSignalDescription(signo, code, addr); } case SIGSEGV: { lldb::ValueObjectSP sigfault = sifields->GetChildMemberWithName("_sigfault"); - lldb::addr_t addr = sigfault->GetChildMemberWithName("_addr")->GetValueAsUnsigned(-1); - lldb::ValueObjectSP bounds = sigfault->GetChildMemberWithName("_addr_bnd"); + lldb::addr_t addr = sigfault->GetChildMemberWithName("si_addr")->GetValueAsUnsigned(-1); + + lldb::ValueObjectSP bounds = sigfault->GetChildMemberWithName("_bounds")->GetChildMemberWithName("_addr_bnd"); lldb::addr_t lower = bounds->GetChildMemberWithName("_lower")->GetValueAsUnsigned(-1); lldb::addr_t upper = bounds->GetChildMemberWithName("_upper")->GetValueAsUnsigned(-1); return GetSignalDescription(signo, code, addr, lower, upper); diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h index 413719a1a26f4..8b5e593528125 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -79,6 +79,16 @@ struct ELFLinuxPrStatus { static_assert(sizeof(ELFLinuxPrStatus) == 112, "sizeof ELFLinuxPrStatus is not correct!"); +struct ThreadData { + lldb_private::DataExtractor gpregset; + std::vector notes; + lldb::tid_t tid; + std::string name; + llvm::StringRef siginfo_bytes; + int prstatus_sig; + int signo; +}; + class ELFLinuxSigInfo { public: static lldb_private::Status Parse(const lldb_private::DataExtractor &data, @@ -130,15 +140,6 @@ struct ELFLinuxPrPsInfo { static_assert(sizeof(ELFLinuxPrPsInfo) == 136, "sizeof ELFLinuxPrPsInfo is not correct!"); -struct ThreadData { - lldb_private::DataExtractor gpregset; - std::vector notes; - lldb::tid_t tid; - std::string name; - llvm::StringRef siginfo_bytes; - int prstatus_sig; - int signo; -}; class ThreadElfCore : public lldb_private::Thread { public: >From 12e725417075b09739da786417dac3898e7d4a35 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Fri, 16 May 2025 15:52:41 -0700 Subject: [PATCH 7/8] Run GCF --- lldb/include/lldb/Target/UnixSignals.h | 7 +- .../Plugins/Process/Utility/LinuxSignals.cpp | 72 +++++++++++-------- .../Plugins/Process/Utility/LinuxSignals.h | 3 +- .../Process/elf-core/ProcessElfCore.cpp | 3 +- .../Process/elf-core/ThreadElfCore.cpp | 32 ++++++--- .../Plugins/Process/elf-core/ThreadElfCore.h | 7 +- 6 files changed, 77 insertions(+), 47 deletions(-) diff --git a/lldb/include/lldb/Target/UnixSignals.h b/lldb/include/lldb/Target/UnixSignals.h index 9ae4048ed683d..53b718e917d25 100644 --- a/lldb/include/lldb/Target/UnixSignals.h +++ b/lldb/include/lldb/Target/UnixSignals.h @@ -14,8 +14,8 @@ #include #include -#include "lldb/lldb-private.h" #include "lldb/ValueObject/ValueObject.h" +#include "lldb/lldb-private.h" #include "llvm/Support/JSON.h" namespace lldb_private { @@ -32,7 +32,10 @@ class UnixSignals { llvm::StringRef GetSignalAsStringRef(int32_t signo) const; - virtual std::string GetSignalDescriptionFromSiginfo(lldb::ValueObjectSP siginfo_sp) const { return ""; }; + virtual std::string + GetSignalDescriptionFromSiginfo(lldb::ValueObjectSP siginfo_sp) const { + return ""; + }; std::string GetSignalDescription(int32_t signo, diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index aef1b3f1d0a12..06b8423000026 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -172,45 +172,61 @@ void LinuxSignals::Reset() { // clang-format on } -std::string LinuxSignals::GetSignalDescriptionFromSiginfo(lldb::ValueObjectSP siginfo_sp) const { +std::string LinuxSignals::GetSignalDescriptionFromSiginfo( + lldb::ValueObjectSP siginfo_sp) const { if (!siginfo_sp) return ""; int code = siginfo_sp->GetChildMemberWithName("si_code")->GetValueAsSigned(0); - int signo = siginfo_sp->GetChildMemberWithName("si_signo")->GetValueAsSigned(-1); - // si_code = 0 is SI_NOINFO, we just want the description with nothing important + int signo = + siginfo_sp->GetChildMemberWithName("si_signo")->GetValueAsSigned(-1); + // si_code = 0 is SI_NOINFO, we just want the description with nothing + // important if (code == 0) return GetSignalDescription(signo, code); - lldb::ValueObjectSP sifields = siginfo_sp->GetChildMemberWithName("_sifields"); - // The negative si_codes are special and mean this signal was sent from user space - // not the kernel. These take precedence because they break some of the invariants - // around kernel sent signals. Such as SIGSEGV won't have an address. + lldb::ValueObjectSP sifields = + siginfo_sp->GetChildMemberWithName("_sifields"); + // The negative si_codes are special and mean this signal was sent from user + // space not the kernel. These take precedence because they break some of the + // invariants around kernel sent signals. Such as SIGSEGV won't have an + // address. if (code < 0) { lldb::ValueObjectSP sikill = sifields->GetChildMemberWithName("_kill"); - uint32_t pid = sikill->GetChildMemberWithName("si_pid")->GetValueAsUnsigned(-1); - uint32_t uid = sikill->GetChildMemberWithName("si_uid")->GetValueAsUnsigned(-1); - return GetSignalDescription(signo, code, std::nullopt, std::nullopt, std::nullopt, pid, uid); + uint32_t pid = + sikill->GetChildMemberWithName("si_pid")->GetValueAsUnsigned(-1); + uint32_t uid = + sikill->GetChildMemberWithName("si_uid")->GetValueAsUnsigned(-1); + return GetSignalDescription(signo, code, std::nullopt, std::nullopt, + std::nullopt, pid, uid); } switch (signo) { - case SIGILL: - case SIGFPE: - case SIGBUS: { - lldb::ValueObjectSP sigfault = sifields->GetChildMemberWithName("_sigfault"); - lldb::addr_t addr = sigfault->GetChildMemberWithName("si_addr")->GetValueAsUnsigned(-1); - return GetSignalDescription(signo, code, addr); - } - case SIGSEGV: { - lldb::ValueObjectSP sigfault = sifields->GetChildMemberWithName("_sigfault"); - lldb::addr_t addr = sigfault->GetChildMemberWithName("si_addr")->GetValueAsUnsigned(-1); - - lldb::ValueObjectSP bounds = sigfault->GetChildMemberWithName("_bounds")->GetChildMemberWithName("_addr_bnd"); - lldb::addr_t lower = bounds->GetChildMemberWithName("_lower")->GetValueAsUnsigned(-1); - lldb::addr_t upper = bounds->GetChildMemberWithName("_upper")->GetValueAsUnsigned(-1); - return GetSignalDescription(signo, code, addr, lower, upper); - } - default: - return GetSignalDescription(signo, code); + case SIGILL: + case SIGFPE: + case SIGBUS: { + lldb::ValueObjectSP sigfault = + sifields->GetChildMemberWithName("_sigfault"); + lldb::addr_t addr = + sigfault->GetChildMemberWithName("si_addr")->GetValueAsUnsigned(-1); + return GetSignalDescription(signo, code, addr); + } + case SIGSEGV: { + lldb::ValueObjectSP sigfault = + sifields->GetChildMemberWithName("_sigfault"); + lldb::addr_t addr = + sigfault->GetChildMemberWithName("si_addr")->GetValueAsUnsigned(-1); + + lldb::ValueObjectSP bounds = + sigfault->GetChildMemberWithName("_bounds")->GetChildMemberWithName( + "_addr_bnd"); + lldb::addr_t lower = + bounds->GetChildMemberWithName("_lower")->GetValueAsUnsigned(-1); + lldb::addr_t upper = + bounds->GetChildMemberWithName("_upper")->GetValueAsUnsigned(-1); + return GetSignalDescription(signo, code, addr, lower, upper); + } + default: + return GetSignalDescription(signo, code); } } diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.h b/lldb/source/Plugins/Process/Utility/LinuxSignals.h index 414cfd531388f..fab8e4d0526a4 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.h +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.h @@ -18,7 +18,8 @@ class LinuxSignals : public UnixSignals { public: LinuxSignals(); - std::string GetSignalDescriptionFromSiginfo(lldb::ValueObjectSP siginfo_sp) const override; + std::string GetSignalDescriptionFromSiginfo( + lldb::ValueObjectSP siginfo_sp) const override; private: void Reset() override; diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index dc3e9616dc9c0..eda30c9c6f82b 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -938,7 +938,8 @@ llvm::Error ProcessElfCore::parseLinuxNotes(llvm::ArrayRef notes) { break; } case ELF::NT_SIGINFO: { - Status status = ELFLinuxSigInfo::Parse(note.data, arch, GetTarget().GetPlatform(), thread_data); + Status status = ELFLinuxSigInfo::Parse( + note.data, arch, GetTarget().GetPlatform(), thread_data); if (status.Fail()) return status.ToError(); break; diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index 766b9b6d331fb..32948d6b0de9e 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -243,12 +243,14 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { return reg_ctx_sp; } -llvm::Expected> ThreadElfCore::GetSiginfo(size_t max_size) const { +llvm::Expected> +ThreadElfCore::GetSiginfo(size_t max_size) const { if (m_siginfo_bytes.empty()) return llvm::createStringError(llvm::inconvertibleErrorCode(), - "no siginfo note"); + "no siginfo note"); - return llvm::MemoryBuffer::getMemBufferCopy(m_siginfo_bytes, "siginfo note bytes"); + return llvm::MemoryBuffer::getMemBufferCopy(m_siginfo_bytes, + "siginfo note bytes"); } bool ThreadElfCore::CalculateStopInfo() { @@ -263,13 +265,17 @@ bool ThreadElfCore::CalculateStopInfo() { lldb::ValueObjectSP siginfo = GetSiginfoValue(); if (!siginfo || !siginfo->GetValueIsValid()) { std::string description = unix_signals_sp->GetSignalDescription(m_signo, 0); - SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, m_signo, description.c_str(), 0)); + SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, m_signo, + description.c_str(), 0)); } else { - std::string description = unix_signals_sp->GetSignalDescriptionFromSiginfo(siginfo); - uint32_t signo = siginfo->GetChildMemberWithName("si_signo")->GetValueAsUnsigned(-1); - uint32_t code = siginfo->GetChildMemberWithName("si_code")->GetValueAsUnsigned(0); + std::string description = + unix_signals_sp->GetSignalDescriptionFromSiginfo(siginfo); + uint32_t signo = + siginfo->GetChildMemberWithName("si_signo")->GetValueAsUnsigned(-1); + uint32_t code = + siginfo->GetChildMemberWithName("si_code")->GetValueAsUnsigned(0); SetStopInfo(StopInfo::CreateStopReasonWithSignal( - *this, signo, description.c_str(), code)); + *this, signo, description.c_str(), code)); } SetStopInfo(m_stop_info_sp); @@ -554,7 +560,9 @@ ELFLinuxPrPsInfo::Populate(const lldb_private::ProcessInstanceInfo &info, return prpsinfo; } -Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, const lldb::PlatformSP platform_sp, ThreadData &thread_data) { +Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, + const lldb::PlatformSP platform_sp, + ThreadData &thread_data) { if (!platform_sp) return Status::FromErrorString("No platform for arch."); CompilerType type = platform_sp->GetSiginfoType(arch.GetTriple()); @@ -566,10 +574,12 @@ Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch, c return Status::FromError(type_size_or_err.takeError()); if (data.GetByteSize() < *type_size_or_err) - return Status::FromErrorString("siginfo note byte size smaller than siginfo_t for platform."); + return Status::FromErrorString( + "siginfo note byte size smaller than siginfo_t for platform."); lldb::offset_t offset = 0; - const char *bytes = static_cast(data.GetData(&offset, *type_size_or_err)); + const char *bytes = + static_cast(data.GetData(&offset, *type_size_or_err)); thread_data.siginfo_bytes = llvm::StringRef(bytes, *type_size_or_err); return Status(); } diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h index 8b5e593528125..2ab9b90f9cc17 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -10,10 +10,10 @@ #define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_THREADELFCORE_H #include "Plugins/Process/elf-core/RegisterUtilities.h" +#include "lldb/Target/Platform.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/ValueObject/ValueObject.h" -#include "lldb/Target/Platform.h" #include "llvm/ADT/DenseMap.h" #include #include @@ -97,7 +97,6 @@ class ELFLinuxSigInfo { ThreadData &thread_data); }; - // PRPSINFO structure's size differs based on architecture. // This is the layout in the x86-64 arch case. // In the i386 case we parse it manually and fill it again @@ -140,7 +139,6 @@ struct ELFLinuxPrPsInfo { static_assert(sizeof(ELFLinuxPrPsInfo) == 136, "sizeof ELFLinuxPrPsInfo is not correct!"); - class ThreadElfCore : public lldb_private::Thread { public: ThreadElfCore(lldb_private::Process &process, const ThreadData &td); @@ -169,7 +167,8 @@ class ThreadElfCore : public lldb_private::Thread { m_thread_name.clear(); } - llvm::Expected> GetSiginfo(size_t max_size) const override; + llvm::Expected> + GetSiginfo(size_t max_size) const override; protected: // Member variables. >From 330360d80c91a539184da8a9a0a449dfcae32a0f Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Sun, 18 May 2025 17:48:04 -0700 Subject: [PATCH 8/8] Set signo to 0 during initialization, fixes shell tests --- lldb/source/Plugins/Process/elf-core/ThreadElfCore.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h index 2ab9b90f9cc17..8a84ac718461f 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -85,8 +85,8 @@ struct ThreadData { lldb::tid_t tid; std::string name; llvm::StringRef siginfo_bytes; - int prstatus_sig; - int signo; + int prstatus_sig = 0; + int signo = 0; }; class ELFLinuxSigInfo { From lldb-commits at lists.llvm.org Sun May 18 18:00:41 2025 From: lldb-commits at lists.llvm.org (Jacob Lalonde via lldb-commits) Date: Sun, 18 May 2025 18:00:41 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB][Progress-On-Dap] Have indeterminate progress actually send events. (PR #140162) In-Reply-To: Message-ID: <682a82b9.170a0220.3c4a62.b847@mx.google.com> https://github.com/Jlalond updated https://github.com/llvm/llvm-project/pull/140162 >From 0673dc530a91cb2dd1bdd60dd5136d64e4ed48e8 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Thu, 15 May 2025 16:37:06 -0700 Subject: [PATCH 1/2] Have interderminate events actually broadcast to dap --- .../API/tools/lldb-dap/progress/TestDAP_Progress.py | 2 +- lldb/tools/lldb-dap/ProgressEvent.cpp | 11 +++++++---- lldb/tools/lldb-dap/ProgressEvent.h | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py b/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py index fee63655de0da..c87d2afe36821 100755 --- a/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py +++ b/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py @@ -81,7 +81,7 @@ def test(self): self.verify_progress_events( expected_title="Progress tester: Initial Indeterminate Detail", - expected_message="Step 1", + expected_message="Step 2", only_verify_first_update=True, ) diff --git a/lldb/tools/lldb-dap/ProgressEvent.cpp b/lldb/tools/lldb-dap/ProgressEvent.cpp index 6a4978c055e51..b6b62efb5f33c 100644 --- a/lldb/tools/lldb-dap/ProgressEvent.cpp +++ b/lldb/tools/lldb-dap/ProgressEvent.cpp @@ -77,16 +77,19 @@ ProgressEvent::Create(uint64_t progress_id, std::optional message, if (event.GetEventType() == progressStart && event.GetEventName().empty()) return std::nullopt; - if (prev_event && prev_event->EqualsForIDE(event)) + if (prev_event && prev_event->EqualsForIDE(event, total)) return std::nullopt; return event; } -bool ProgressEvent::EqualsForIDE(const ProgressEvent &other) const { +bool ProgressEvent::EqualsForIDE(const ProgressEvent &other, uint64_t total) const { return m_progress_id == other.m_progress_id && - m_event_type == other.m_event_type && - m_percentage == other.m_percentage; + m_event_type == other.m_event_type && + // If we check the percentage of a non-deterministic event + // we will basically never send the event, because N+1/Uint64_max + // will always be an infinitesimally small change. + (total != UINT64_MAX && m_percentage == other.m_percentage); } ProgressEventType ProgressEvent::GetEventType() const { return m_event_type; } diff --git a/lldb/tools/lldb-dap/ProgressEvent.h b/lldb/tools/lldb-dap/ProgressEvent.h index d1b9b9dd887cd..ab3487c1dbc3d 100644 --- a/lldb/tools/lldb-dap/ProgressEvent.h +++ b/lldb/tools/lldb-dap/ProgressEvent.h @@ -54,7 +54,7 @@ class ProgressEvent { /// \return /// \b true if two event messages would result in the same event for the /// IDE, e.g. same rounded percentage. - bool EqualsForIDE(const ProgressEvent &other) const; + bool EqualsForIDE(const ProgressEvent &other, uint64_t total) const; llvm::StringRef GetEventName() const; >From 4522493d9fa1032e68606daa0a619441abf2d1b7 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Thu, 15 May 2025 16:44:56 -0700 Subject: [PATCH 2/2] Format, add regex to test, and check if progress is nullopt instead of comparing total. --- lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py | 7 +++++-- lldb/tools/lldb-dap/ProgressEvent.cpp | 6 +++--- lldb/tools/lldb-dap/ProgressEvent.h | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py b/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py index c87d2afe36821..9fdcbd6162d46 100755 --- a/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py +++ b/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py @@ -7,6 +7,7 @@ import json import os import time +import re import lldbdap_testcase @@ -16,6 +17,7 @@ def verify_progress_events( self, expected_title, expected_message=None, + expected_message_regex=None, expected_not_in_message=None, only_verify_first_update=False, ): @@ -36,6 +38,8 @@ def verify_progress_events( continue if expected_message is not None: self.assertIn(expected_message, message) + if expected_message_regex is not None: + self.assertTrue(re.match(expected_message_regex, message)) if expected_not_in_message is not None: self.assertNotIn(expected_not_in_message, message) update_found = True @@ -81,8 +85,7 @@ def test(self): self.verify_progress_events( expected_title="Progress tester: Initial Indeterminate Detail", - expected_message="Step 2", - only_verify_first_update=True, + expected_message_regex=r"Step [0-9]+", ) # Test no details indeterminate. diff --git a/lldb/tools/lldb-dap/ProgressEvent.cpp b/lldb/tools/lldb-dap/ProgressEvent.cpp index b6b62efb5f33c..e70f393b797e4 100644 --- a/lldb/tools/lldb-dap/ProgressEvent.cpp +++ b/lldb/tools/lldb-dap/ProgressEvent.cpp @@ -83,13 +83,13 @@ ProgressEvent::Create(uint64_t progress_id, std::optional message, return event; } -bool ProgressEvent::EqualsForIDE(const ProgressEvent &other, uint64_t total) const { +bool ProgressEvent::EqualsForIDE(const ProgressEvent &other) const { return m_progress_id == other.m_progress_id && - m_event_type == other.m_event_type && + m_event_type == other.m_event_type && // If we check the percentage of a non-deterministic event // we will basically never send the event, because N+1/Uint64_max // will always be an infinitesimally small change. - (total != UINT64_MAX && m_percentage == other.m_percentage); + (m_percentage != std::nullopt && m_percentage == other.m_percentage); } ProgressEventType ProgressEvent::GetEventType() const { return m_event_type; } diff --git a/lldb/tools/lldb-dap/ProgressEvent.h b/lldb/tools/lldb-dap/ProgressEvent.h index ab3487c1dbc3d..d1b9b9dd887cd 100644 --- a/lldb/tools/lldb-dap/ProgressEvent.h +++ b/lldb/tools/lldb-dap/ProgressEvent.h @@ -54,7 +54,7 @@ class ProgressEvent { /// \return /// \b true if two event messages would result in the same event for the /// IDE, e.g. same rounded percentage. - bool EqualsForIDE(const ProgressEvent &other, uint64_t total) const; + bool EqualsForIDE(const ProgressEvent &other) const; llvm::StringRef GetEventName() const; From lldb-commits at lists.llvm.org Sun May 18 18:02:12 2025 From: lldb-commits at lists.llvm.org (Jacob Lalonde via lldb-commits) Date: Sun, 18 May 2025 18:02:12 -0700 (PDT) Subject: [Lldb-commits] [lldb] [LLDB][Progress-On-Dap] Have indeterminate progress actually send events. (PR #140162) In-Reply-To: Message-ID: <682a8314.170a0220.8baf5.df0e@mx.google.com> https://github.com/Jlalond updated https://github.com/llvm/llvm-project/pull/140162 >From 0673dc530a91cb2dd1bdd60dd5136d64e4ed48e8 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Thu, 15 May 2025 16:37:06 -0700 Subject: [PATCH 1/2] Have interderminate events actually broadcast to dap --- .../API/tools/lldb-dap/progress/TestDAP_Progress.py | 2 +- lldb/tools/lldb-dap/ProgressEvent.cpp | 11 +++++++---- lldb/tools/lldb-dap/ProgressEvent.h | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py b/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py index fee63655de0da..c87d2afe36821 100755 --- a/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py +++ b/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py @@ -81,7 +81,7 @@ def test(self): self.verify_progress_events( expected_title="Progress tester: Initial Indeterminate Detail", - expected_message="Step 1", + expected_message="Step 2", only_verify_first_update=True, ) diff --git a/lldb/tools/lldb-dap/ProgressEvent.cpp b/lldb/tools/lldb-dap/ProgressEvent.cpp index 6a4978c055e51..b6b62efb5f33c 100644 --- a/lldb/tools/lldb-dap/ProgressEvent.cpp +++ b/lldb/tools/lldb-dap/ProgressEvent.cpp @@ -77,16 +77,19 @@ ProgressEvent::Create(uint64_t progress_id, std::optional message, if (event.GetEventType() == progressStart && event.GetEventName().empty()) return std::nullopt; - if (prev_event && prev_event->EqualsForIDE(event)) + if (prev_event && prev_event->EqualsForIDE(event, total)) return std::nullopt; return event; } -bool ProgressEvent::EqualsForIDE(const ProgressEvent &other) const { +bool ProgressEvent::EqualsForIDE(const ProgressEvent &other, uint64_t total) const { return m_progress_id == other.m_progress_id && - m_event_type == other.m_event_type && - m_percentage == other.m_percentage; + m_event_type == other.m_event_type && + // If we check the percentage of a non-deterministic event + // we will basically never send the event, because N+1/Uint64_max + // will always be an infinitesimally small change. + (total != UINT64_MAX && m_percentage == other.m_percentage); } ProgressEventType ProgressEvent::GetEventType() const { return m_event_type; } diff --git a/lldb/tools/lldb-dap/ProgressEvent.h b/lldb/tools/lldb-dap/ProgressEvent.h index d1b9b9dd887cd..ab3487c1dbc3d 100644 --- a/lldb/tools/lldb-dap/ProgressEvent.h +++ b/lldb/tools/lldb-dap/ProgressEvent.h @@ -54,7 +54,7 @@ class ProgressEvent { /// \return /// \b true if two event messages would result in the same event for the /// IDE, e.g. same rounded percentage. - bool EqualsForIDE(const ProgressEvent &other) const; + bool EqualsForIDE(const ProgressEvent &other, uint64_t total) const; llvm::StringRef GetEventName() const; >From dabda3b2f3288c35d08cf2d4e4788927481222ff Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Thu, 15 May 2025 16:44:56 -0700 Subject: [PATCH 2/2] Format, add regex to test, and check if progress is nullopt instead of comparing total. --- lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py | 7 +++++-- lldb/tools/lldb-dap/ProgressEvent.cpp | 8 ++++---- lldb/tools/lldb-dap/ProgressEvent.h | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py b/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py index c87d2afe36821..9fdcbd6162d46 100755 --- a/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py +++ b/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py @@ -7,6 +7,7 @@ import json import os import time +import re import lldbdap_testcase @@ -16,6 +17,7 @@ def verify_progress_events( self, expected_title, expected_message=None, + expected_message_regex=None, expected_not_in_message=None, only_verify_first_update=False, ): @@ -36,6 +38,8 @@ def verify_progress_events( continue if expected_message is not None: self.assertIn(expected_message, message) + if expected_message_regex is not None: + self.assertTrue(re.match(expected_message_regex, message)) if expected_not_in_message is not None: self.assertNotIn(expected_not_in_message, message) update_found = True @@ -81,8 +85,7 @@ def test(self): self.verify_progress_events( expected_title="Progress tester: Initial Indeterminate Detail", - expected_message="Step 2", - only_verify_first_update=True, + expected_message_regex=r"Step [0-9]+", ) # Test no details indeterminate. diff --git a/lldb/tools/lldb-dap/ProgressEvent.cpp b/lldb/tools/lldb-dap/ProgressEvent.cpp index b6b62efb5f33c..8236e827d6775 100644 --- a/lldb/tools/lldb-dap/ProgressEvent.cpp +++ b/lldb/tools/lldb-dap/ProgressEvent.cpp @@ -77,19 +77,19 @@ ProgressEvent::Create(uint64_t progress_id, std::optional message, if (event.GetEventType() == progressStart && event.GetEventName().empty()) return std::nullopt; - if (prev_event && prev_event->EqualsForIDE(event, total)) + if (prev_event && prev_event->EqualsForIDE(event)) return std::nullopt; return event; } -bool ProgressEvent::EqualsForIDE(const ProgressEvent &other, uint64_t total) const { +bool ProgressEvent::EqualsForIDE(const ProgressEvent &other) const { return m_progress_id == other.m_progress_id && - m_event_type == other.m_event_type && + m_event_type == other.m_event_type && // If we check the percentage of a non-deterministic event // we will basically never send the event, because N+1/Uint64_max // will always be an infinitesimally small change. - (total != UINT64_MAX && m_percentage == other.m_percentage); + (m_percentage != std::nullopt && m_percentage == other.m_percentage); } ProgressEventType ProgressEvent::GetEventType() const { return m_event_type; } diff --git a/lldb/tools/lldb-dap/ProgressEvent.h b/lldb/tools/lldb-dap/ProgressEvent.h index ab3487c1dbc3d..d1b9b9dd887cd 100644 --- a/lldb/tools/lldb-dap/ProgressEvent.h +++ b/lldb/tools/lldb-dap/ProgressEvent.h @@ -54,7 +54,7 @@ class ProgressEvent { /// \return /// \b true if two event messages would result in the same event for the /// IDE, e.g. same rounded percentage. - bool EqualsForIDE(const ProgressEvent &other, uint64_t total) const; + bool EqualsForIDE(const ProgressEvent &other) const; llvm::StringRef GetEventName() const; From lldb-commits at lists.llvm.org Sun May 18 18:50:48 2025 From: lldb-commits at lists.llvm.org (John Harrison via lldb-commits) Date: Sun, 18 May 2025 18:50:48 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for FifoFiles (PR #140480) In-Reply-To: Message-ID: <682a8e78.170a0220.2a013f.8c95@mx.google.com> ================ @@ -0,0 +1,102 @@ +//===-- FifoFilesTest.cpp -------------------------------------------------===// +// +// 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 "FifoFiles.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include + +using namespace lldb_dap; +using namespace llvm; + +namespace { + +std::string MakeTempFifoPath() { + llvm::SmallString<128> temp_path; + llvm::sys::fs::createUniquePath("lldb-dap-fifo-%%%%%%", temp_path, + /*MakeAbsolute=*/true); + return temp_path.str().str(); +} + +} // namespace + +TEST(FifoFilesTest, CreateAndDestroyFifoFile) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + // File should exist. + EXPECT_TRUE(llvm::sys::fs::exists(fifo_path)); + + // Destructor should remove the file. + fifo->reset(); + EXPECT_FALSE(llvm::sys::fs::exists(fifo_path)); +} + +TEST(FifoFilesTest, SendAndReceiveJSON) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + FifoFileIO writer(fifo_path, "writer"); + FifoFileIO reader(fifo_path, "reader"); + + llvm::json::Object obj; + obj["foo"] = "bar"; + obj["num"] = 42; + + // Writer thread. + std::thread writer_thread([&]() { + EXPECT_THAT_ERROR(writer.SendJSON(llvm::json::Value(std::move(obj)), + std::chrono::milliseconds(500)), + llvm::Succeeded()); + }); + + // Reader thread. + std::thread reader_thread([&]() { + auto result = reader.ReadJSON(std::chrono::milliseconds(500)); + EXPECT_THAT_EXPECTED(result, llvm::Succeeded()); + auto *read_obj = result->getAsObject(); + + ASSERT_NE(read_obj, nullptr); + EXPECT_EQ((*read_obj)["foo"].getAsString(), "bar"); + EXPECT_EQ((*read_obj)["num"].getAsInteger(), 42); + }); + + writer_thread.join(); + reader_thread.join(); +} + +TEST(FifoFilesTest, ReadTimeout) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + FifoFileIO reader(fifo_path, "reader"); + + // No writer, should timeout. + auto result = reader.ReadJSON(std::chrono::milliseconds(100)); ---------------- ashgti wrote: Sounds reasonable to me https://github.com/llvm/llvm-project/pull/140480 From lldb-commits at lists.llvm.org Sun May 18 19:05:02 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sun, 18 May 2025 19:05:02 -0700 (PDT) Subject: [Lldb-commits] [lldb] eb467a0 - [lldb-dap] Add unit test for FifoFiles (#140480) Message-ID: <682a91ce.170a0220.fc659.205d@mx.google.com> Author: Jonas Devlieghere Date: 2025-05-18T19:04:59-07:00 New Revision: eb467a088bd9c5f2755cbc6152195670bf45ae0e URL: https://github.com/llvm/llvm-project/commit/eb467a088bd9c5f2755cbc6152195670bf45ae0e DIFF: https://github.com/llvm/llvm-project/commit/eb467a088bd9c5f2755cbc6152195670bf45ae0e.diff LOG: [lldb-dap] Add unit test for FifoFiles (#140480) Added: lldb/unittests/DAP/FifoFilesTest.cpp Modified: lldb/unittests/DAP/CMakeLists.txt Removed: ################################################################################ diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index 429a12e9fb505..cd421401f167b 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -1,5 +1,6 @@ add_lldb_unittest(DAPTests DAPTest.cpp + FifoFilesTest.cpp Handler/DisconnectTest.cpp JSONUtilsTest.cpp LLDBUtilsTest.cpp diff --git a/lldb/unittests/DAP/FifoFilesTest.cpp b/lldb/unittests/DAP/FifoFilesTest.cpp new file mode 100644 index 0000000000000..bbc1b608e91bd --- /dev/null +++ b/lldb/unittests/DAP/FifoFilesTest.cpp @@ -0,0 +1,102 @@ +//===-- FifoFilesTest.cpp -------------------------------------------------===// +// +// 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 "FifoFiles.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include + +using namespace lldb_dap; +using namespace llvm; + +namespace { + +std::string MakeTempFifoPath() { + llvm::SmallString<128> temp_path; + llvm::sys::fs::createUniquePath("lldb-dap-fifo-%%%%%%", temp_path, + /*MakeAbsolute=*/true); + return temp_path.str().str(); +} + +} // namespace + +TEST(FifoFilesTest, CreateAndDestroyFifoFile) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + // File should exist. + EXPECT_TRUE(llvm::sys::fs::exists(fifo_path)); + + // Destructor should remove the file. + fifo->reset(); + EXPECT_FALSE(llvm::sys::fs::exists(fifo_path)); +} + +TEST(FifoFilesTest, SendAndReceiveJSON) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + FifoFileIO writer(fifo_path, "writer"); + FifoFileIO reader(fifo_path, "reader"); + + llvm::json::Object obj; + obj["foo"] = "bar"; + obj["num"] = 42; + + // Writer thread. + std::thread writer_thread([&]() { + EXPECT_THAT_ERROR(writer.SendJSON(llvm::json::Value(std::move(obj)), + std::chrono::milliseconds(500)), + llvm::Succeeded()); + }); + + // Reader thread. + std::thread reader_thread([&]() { + auto result = reader.ReadJSON(std::chrono::milliseconds(500)); + EXPECT_THAT_EXPECTED(result, llvm::Succeeded()); + auto *read_obj = result->getAsObject(); + + ASSERT_NE(read_obj, nullptr); + EXPECT_EQ((*read_obj)["foo"].getAsString(), "bar"); + EXPECT_EQ((*read_obj)["num"].getAsInteger(), 42); + }); + + writer_thread.join(); + reader_thread.join(); +} + +TEST(FifoFilesTest, ReadTimeout) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + FifoFileIO reader(fifo_path, "reader"); + + // No writer, should timeout. + auto result = reader.ReadJSON(std::chrono::milliseconds(100)); + EXPECT_THAT_EXPECTED(result, llvm::Failed()); +} + +TEST(FifoFilesTest, WriteTimeout) { + std::string fifo_path = MakeTempFifoPath(); + auto fifo = CreateFifoFile(fifo_path); + EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded()); + + FifoFileIO writer(fifo_path, "writer"); + + // No reader, should timeout. + llvm::json::Object obj; + obj["foo"] = "bar"; + EXPECT_THAT_ERROR(writer.SendJSON(llvm::json::Value(std::move(obj)), + std::chrono::milliseconds(100)), + llvm::Failed()); +} From lldb-commits at lists.llvm.org Sun May 18 19:05:05 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sun, 18 May 2025 19:05:05 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Add unit test for FifoFiles (PR #140480) In-Reply-To: Message-ID: <682a91d1.170a0220.1619de.b61c@mx.google.com> https://github.com/JDevlieghere closed https://github.com/llvm/llvm-project/pull/140480 From lldb-commits at lists.llvm.org Sun May 18 19:10:26 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sun, 18 May 2025 19:10:26 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Migrate disassemble request to structured handler (PR #140482) In-Reply-To: Message-ID: <682a9312.a70a0220.2dfcc3.c601@mx.google.com> https://github.com/JDevlieghere commented: +1 on the unit test https://github.com/llvm/llvm-project/pull/140482 From lldb-commits at lists.llvm.org Sun May 18 19:10:26 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sun, 18 May 2025 19:10:26 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Migrate disassemble request to structured handler (PR #140482) In-Reply-To: Message-ID: <682a9312.170a0220.3cf339.0d62@mx.google.com> https://github.com/JDevlieghere edited https://github.com/llvm/llvm-project/pull/140482 From lldb-commits at lists.llvm.org Sun May 18 19:10:26 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sun, 18 May 2025 19:10:26 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb-dap] Migrate disassemble request to structured handler (PR #140482) In-Reply-To: Message-ID: <682a9312.050a0220.24a10b.c7a4@mx.google.com> ================ @@ -9,113 +9,34 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "Protocol/ProtocolRequests.h" +#include "Protocol/ProtocolTypes.h" #include "RequestHandler.h" #include "lldb/API/SBInstruction.h" #include "llvm/ADT/StringExtras.h" +using namespace lldb_dap::protocol; + namespace lldb_dap { -// "DisassembleRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Disassembles code stored at the provided -// location.\nClients should only call this request if the corresponding -// capability `supportsDisassembleRequest` is true.", "properties": { -// "command": { -// "type": "string", -// "enum": [ "disassemble" ] -// }, -// "arguments": { -// "$ref": "#/definitions/DisassembleArguments" -// } -// }, -// "required": [ "command", "arguments" ] -// }] -// }, -// "DisassembleArguments": { -// "type": "object", -// "description": "Arguments for `disassemble` request.", -// "properties": { -// "memoryReference": { -// "type": "string", -// "description": "Memory reference to the base location containing the -// instructions to disassemble." -// }, -// "offset": { -// "type": "integer", -// "description": "Offset (in bytes) to be applied to the reference -// location before disassembling. Can be negative." -// }, -// "instructionOffset": { -// "type": "integer", -// "description": "Offset (in instructions) to be applied after the byte -// offset (if any) before disassembling. Can be negative." -// }, -// "instructionCount": { -// "type": "integer", -// "description": "Number of instructions to disassemble starting at the -// specified location and offset.\nAn adapter must return exactly this -// number of instructions - any unavailable instructions should be -// replaced with an implementation-defined 'invalid instruction' value." -// }, -// "resolveSymbols": { -// "type": "boolean", -// "description": "If true, the adapter should attempt to resolve memory -// addresses and other values to symbolic names." -// } -// }, -// "required": [ "memoryReference", "instructionCount" ] -// }, -// "DisassembleResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to `disassemble` request.", -// "properties": { -// "body": { -// "type": "object", -// "properties": { -// "instructions": { -// "type": "array", -// "items": { -// "$ref": "#/definitions/DisassembledInstruction" -// }, -// "description": "The list of disassembled instructions." -// } -// }, -// "required": [ "instructions" ] -// } -// } -// }] -// } -void DisassembleRequestHandler::operator()( - const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - auto *arguments = request.getObject("arguments"); - - llvm::StringRef memoryReference = - GetString(arguments, "memoryReference").value_or(""); - auto addr_opt = DecodeMemoryReference(memoryReference); - if (!addr_opt.has_value()) { - response["success"] = false; - response["message"] = - "Malformed memory reference: " + memoryReference.str(); - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } - lldb::addr_t addr_ptr = *addr_opt; +/// Disassembles code stored at the provided location. +/// Clients should only call this request if the corresponding capability +/// `supportsDisassembleRequest` is true. +llvm::Expected +DisassembleRequestHandler::Run(const DisassembleArguments &args) const { + std::vector instructions; - addr_ptr += GetInteger(arguments, "instructionOffset").value_or(0); - lldb::SBAddress addr(addr_ptr, dap.target); - if (!addr.IsValid()) { - response["success"] = false; - response["message"] = "Memory reference not found in the current binary."; - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } + auto addr_opt = DecodeMemoryReference(args.memoryReference); ---------------- JDevlieghere wrote: I know this is existing code, but since you're touching it, let's use the actual type here. ([auto in llvm](https://llvm.org/docs/CodingStandards.html#use-auto-type-deduction-to-make-code-more-readable)) https://github.com/llvm/llvm-project/pull/140482 From lldb-commits at lists.llvm.org Sun May 18 19:11:43 2025 From: lldb-commits at lists.llvm.org (Jonas Devlieghere via lldb-commits) Date: Sun, 18 May 2025 19:11:43 -0700 (PDT) Subject: [Lldb-commits] [lldb] [lldb] Suppport testing with debug-python on Windows (PR #140443) In-Reply-To: Message-ID: <682a935f.170a0220.12161f.c2fd@mx.google.com> https://github.com/JDevlieghere approved this pull request. Makes sense https://github.com/llvm/llvm-project/pull/140443 From lldb-commits at lists.llvm.org Sun May 18 20:33:20 2025 From: lldb-commits at lists.llvm.org (Oliver Hunt via lldb-commits) Date: Sun, 18 May 2025 20:33:20 -0700 (PDT) Subject: [Lldb-commits] [lld] [lldb] [llvm] [NFC] Address more bit-field storage sizes (PR #140493) Message-ID: https://github.com/ojhunt created https://github.com/llvm/llvm-project/pull/140493 Follow on work from #139825 >From 6234ea2b59e49a9da1248875a9fc6ecf294483b4 Mon Sep 17 00:00:00 2001 From: Oliver Hunt Date: Sun, 18 May 2025 20:31:43 -0700 Subject: [PATCH] [NFC] Address more bit-field storage sizes Follow on work from #139825 --- lld/wasm/InputChunks.h | 6 +++--- lldb/source/Plugins/Language/ObjC/NSArray.cpp | 2 +- lldb/source/Plugins/Language/ObjC/NSDictionary.cpp | 6 +++--- lldb/source/Plugins/Language/ObjC/NSSet.cpp | 2 +- lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h | 2 +- llvm/include/llvm/Demangle/ItaniumDemangle.h | 1 + 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/lld/wasm/InputChunks.h b/lld/wasm/InputChunks.h index 1fe78d76631f1..4bae235b247c5 100644 --- a/lld/wasm/InputChunks.h +++ b/lld/wasm/InputChunks.h @@ -99,15 +99,15 @@ class InputChunk { // the beginning of the output section this chunk was assigned to. int32_t outSecOff = 0; - uint8_t sectionKind : 3; + uint32_t sectionKind : 3; // Signals that the section is part of the output. The garbage collector, // and COMDAT handling can set a sections' Live bit. // If GC is disabled, all sections start out as live by default. - unsigned live : 1; + uint32_t live : 1; // Signals the chunk was discarded by COMDAT handling. - unsigned discarded : 1; + uint32_t discarded : 1; protected: InputChunk(ObjFile *f, Kind k, StringRef name, uint32_t alignment = 0, diff --git a/lldb/source/Plugins/Language/ObjC/NSArray.cpp b/lldb/source/Plugins/Language/ObjC/NSArray.cpp index 25376e064879d..444286692994d 100644 --- a/lldb/source/Plugins/Language/ObjC/NSArray.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSArray.cpp @@ -101,7 +101,7 @@ namespace Foundation1010 { uint32_t _used; uint32_t _offset; uint32_t _size : 28; - uint64_t _priv1 : 4; + uint32_t _priv1 : 4; uint32_t _priv2; uint32_t _data; }; diff --git a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp index ef1c2c89fe125..4f5c54b2c077c 100644 --- a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp @@ -119,7 +119,7 @@ class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd { struct DataDescriptor_64 { uint64_t _used : 58; - uint32_t _szidx : 6; + uint64_t _szidx : 6; }; struct DictionaryItemDescriptor { @@ -273,7 +273,7 @@ namespace Foundation1100 { struct DataDescriptor_64 { uint64_t _used : 58; - uint32_t _kvo : 1; + uint64_t _kvo : 1; uint64_t _size; uint64_t _mutations; uint64_t _objs_addr; @@ -308,7 +308,7 @@ namespace Foundation1428 { struct DataDescriptor_64 { uint64_t _used : 58; - uint32_t _kvo : 1; + uint64_t _kvo : 1; uint64_t _size; uint64_t _buffer; uint64_t GetSize() { return _size; } diff --git a/lldb/source/Plugins/Language/ObjC/NSSet.cpp b/lldb/source/Plugins/Language/ObjC/NSSet.cpp index 7d814e656dc5f..bee6d5ceb41b6 100644 --- a/lldb/source/Plugins/Language/ObjC/NSSet.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSSet.cpp @@ -62,7 +62,7 @@ class NSSetISyntheticFrontEnd : public SyntheticChildrenFrontEnd { struct DataDescriptor_64 { uint64_t _used : 58; - uint32_t _szidx : 6; + uint64_t _szidx : 6; }; struct SetItemDescriptor { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h index 72aeb2743b1e2..022a64e3d7f6f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -189,7 +189,7 @@ class DWARFDebugInfoEntry { // If it is zero, then the DIE doesn't have children, // or the DWARF claimed it had children but the DIE // only contained a single NULL terminating child. - uint32_t m_sibling_idx : 31, m_has_children : 1; + uint64_t m_sibling_idx : 31, m_has_children : 1; uint16_t m_abbr_idx = 0; /// A copy of the DW_TAG value so we don't have to go through the compile /// unit abbrev table diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h index f4569850b093c..8041d5447095c 100644 --- a/llvm/include/llvm/Demangle/ItaniumDemangle.h +++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h @@ -19,6 +19,7 @@ #include "DemangleConfig.h" #include "StringViewExtras.h" #include "Utility.h" +#include "llvm/Support/Compiler.h" #include #include #include From lldb-commits at lists.llvm.org Sun May 18 20:33:54 2025 From: lldb-commits at lists.llvm.org (via lldb-commits) Date: Sun, 18 May 2025 20:33:54 -0700 (PDT) Subject: [Lldb-commits] [lld] [lldb] [llvm] [NFC] Address more bit-field storage sizes (PR #140493) In-Reply-To: Message-ID: <682aa6a2.170a0220.73a89.c045@mx.google.com> llvmbot wrote: @llvm/pr-subscribers-lld-wasm Author: Oliver Hunt (ojhunt)
Changes Follow on work from #139825 --- Full diff: https://github.com/llvm/llvm-project/pull/140493.diff 6 Files Affected: - (modified) lld/wasm/InputChunks.h (+3-3) - (modified) lldb/source/Plugins/Language/ObjC/NSArray.cpp (+1-1) - (modified) lldb/source/Plugins/Language/ObjC/NSDictionary.cpp (+3-3) - (modified) lldb/source/Plugins/Language/ObjC/NSSet.cpp (+1-1) - (modified) lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h (+1-1) - (modified) llvm/include/llvm/Demangle/ItaniumDemangle.h (+1) ``````````diff diff --git a/lld/wasm/InputChunks.h b/lld/wasm/InputChunks.h index 1fe78d76631f1..4bae235b247c5 100644 --- a/lld/wasm/InputChunks.h +++ b/lld/wasm/InputChunks.h @@ -99,15 +99,15 @@ class InputChunk { // the beginning of the output section this chunk was assigned to. int32_t outSecOff = 0; - uint8_t sectionKind : 3; + uint32_t sectionKind : 3; // Signals that the section is part of the output. The garbage collector, // and COMDAT handling can set a sections' Live bit. // If GC is disabled, all sections start out as live by default. - unsigned live : 1; + uint32_t live : 1; // Signals the chunk was discarded by COMDAT handling. - unsigned discarded : 1; + uint32_t discarded : 1; protected: InputChunk(ObjFile *f, Kind k, StringRef name, uint32_t alignment = 0, diff --git a/lldb/source/Plugins/Language/ObjC/NSArray.cpp b/lldb/source/Plugins/Language/ObjC/NSArray.cpp index 25376e064879d..444286692994d 100644 --- a/lldb/source/Plugins/Language/ObjC/NSArray.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSArray.cpp @@ -101,7 +101,7 @@ namespace Foundation1010 { uint32_t _used; uint32_t _offset; uint32_t _size : 28; - uint64_t _priv1 : 4; + uint32_t _priv1 : 4; uint32_t _priv2; uint32_t _data; }; diff --git a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp index ef1c2c89fe125..4f5c54b2c077c 100644 --- a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp @@ -119,7 +119,7 @@ class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd { struct DataDescriptor_64 { uint64_t _used : 58; - uint32_t _szidx : 6; + uint64_t _szidx : 6; }; struct DictionaryItemDescriptor { @@ -273,7 +273,7 @@ namespace Foundation1100 { struct DataDescriptor_64 { uint64_t _used : 58; - uint32_t _kvo : 1; + uint64_t _kvo : 1; uint64_t _size; uint64_t _mutations; uint64_t _objs_addr; @@ -308,7 +308,7 @@ namespace Foundation1428 { struct DataDescriptor_64 { uint64_t _used : 58; - uint32_t _kvo : 1; + uint64_t _kvo : 1; uint64_t _size; uint64_t _buffer; uint64_t GetSize() { return _size; } diff --git a/lldb/source/Plugins/Language/ObjC/NSSet.cpp b/lldb/source/Plugins/Language/ObjC/NSSet.cpp index 7d814e656dc5f..bee6d5ceb41b6 100644 --- a/lldb/source/Plugins/Language/ObjC/NSSet.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSSet.cpp @@ -62,7 +62,7 @@ class NSSetISyntheticFrontEnd : public SyntheticChildrenFrontEnd { struct DataDescriptor_64 { uint64_t _used : 58; - uint32_t _szidx : 6; + uint64_t _szidx : 6; }; struct SetItemDescriptor { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h index 72aeb2743b1e2..022a64e3d7f6f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -189,7 +189,7 @@ class DWARFDebugInfoEntry { // If it is zero, then the DIE doesn't have children, // or the DWARF claimed it had children but the DIE // only contained a single NULL terminating child. - uint32_t m_sibling_idx : 31, m_has_children : 1; + uint64_t m_sibling_idx : 31, m_has_children : 1; uint16_t m_abbr_idx = 0; /// A copy of the DW_TAG value so we don't have to go through the compile /// unit abbrev table diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h index f4569850b093c..8041d5447095c 100644 --- a/llvm/include/llvm/Demangle/ItaniumDemangle.h +++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h @@ -19,6 +19,7 @@ #include "DemangleConfig.h" #include "StringViewExtras.h" #include "Utility.h" +#include "llvm/Support/Compiler.h" #include #include #include ``````````
https://github.com/llvm/llvm-project/pull/140493 From lldb-commits at lists.llvm.org Sun May 18 20:34:26 2025 From: lldb-commits at lists.llvm.org (Oliver Hunt via lldb-commits) Date: Sun, 18 May 2025 20:34:26 -0700 (PDT) Subject: [Lldb-commits] [lld] [lldb] [NFC] Address more bit-field storage sizes (PR #140493) In-Reply-To: Message-ID: <682aa6c2.170a0220.375382.c1c2@mx.google.com> https://github.com/ojhunt updated https://github.com/llvm/llvm-project/pull/140493 >From 90e4c9d97eb84decea39cf28fbd22b99fcbccbda Mon Sep 17 00:00:00 2001 From: Oliver Hunt Date: Sun, 18 May 2025 20:31:43 -0700 Subject: [PATCH] [NFC] Address more bit-field storage sizes Follow on work from #139825 --- lld/wasm/InputChunks.h | 6 +++--- lldb/source/Plugins/Language/ObjC/NSArray.cpp | 2 +- lldb/source/Plugins/Language/ObjC/NSDictionary.cpp | 6 +++--- lldb/source/Plugins/Language/ObjC/NSSet.cpp | 2 +- lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lld/wasm/InputChunks.h b/lld/wasm/InputChunks.h index 1fe78d76631f1..4bae235b247c5 100644 --- a/lld/wasm/InputChunks.h +++ b/lld/wasm/InputChunks.h @@ -99,15 +99,15 @@ class InputChunk { // the beginning of the output section this chunk was assigned to. int32_t outSecOff = 0; - uint8_t sectionKind : 3; + uint32_t sectionKind : 3; // Signals that the section is part of the output. The garbage collector, // and COMDAT handling can set a sections' Live bit. // If GC is disabled, all sections start out as live by default. - unsigned live : 1; + uint32_t live : 1; // Signals the chunk was discarded by COMDAT handling. - unsigned discarded : 1; + uint32_t discarded : 1; protected: InputChunk(ObjFile *f, Kind k, StringRef name, uint32_t alignment = 0, diff --git a/lldb/source/Plugins/Language/ObjC/NSArray.cpp b/lldb/source/Plugins/Language/ObjC/NSArray.cpp index 25376e064879d..444286692994d 100644 --- a/lldb/source/Plugins/Language/ObjC/NSArray.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSArray.cpp @@ -101,7 +101,7 @@ namespace Foundation1010 { uint32_t _used; uint32_t _offset; uint32_t _size : 28; - uint64_t _priv1 : 4; + uint32_t _priv1 : 4; uint32_t _priv2; uint32_t _data; }; diff --git a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp index ef1c2c89fe125..4f5c54b2c077c 100644 --- a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp @@ -119,7 +119,7 @@ class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd { struct DataDescriptor_64 { uint64_t _used : 58; - uint32_t _szidx : 6; + uint64_t _szidx : 6; }; struct DictionaryItemDescriptor { @@ -273,7 +273,7 @@ namespace Foundation1100 { struct DataDescriptor_64 { uint64_t _used : 58; - uint32_t _kvo : 1; + uint64_t _kvo : 1; uint64_t _size; uint64_t _mutations; uint64_t _objs_addr; @@ -308,7 +308,7 @@ namespace Foundation1428 { struct DataDescriptor_64 { uint64_t _used : 58; - uint32_t _kvo : 1; + uint64_t _kvo : 1; uint64_t _size; uint64_t _buffer; uint64_t GetSize() { return _size; } diff --git a/lldb/source/Plugins/Language/ObjC/NSSet.cpp b/lldb/source/Plugins/Language/ObjC/NSSet.cpp index 7d814e656dc5f..bee6d5ceb41b6 100644 --- a/lldb/source/Plugins/Language/ObjC/NSSet.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSSet.cpp @@ -62,7 +62,7 @@ class NSSetISyntheticFrontEnd : public SyntheticChildrenFrontEnd { struct DataDescriptor_64 { uint64_t _used : 58; - uint32_t _szidx : 6; + uint64_t _szidx : 6; }; struct SetItemDescriptor { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h index 72aeb2743b1e2..022a64e3d7f6f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -189,7 +189,7 @@ class DWARFDebugInfoEntry { // If it is zero, then the DIE doesn't have children, // or the DWARF claimed it had children but the DIE // only contained a single NULL terminating child. - uint32_t m_sibling_idx : 31, m_has_children : 1; + uint64_t m_sibling_idx : 31, m_has_children : 1; uint16_t m_abbr_idx = 0; /// A copy of the DW_TAG value so we don't have to go through the compile /// unit abbrev table