diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2022-07-24 15:03:44 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2022-07-24 15:03:44 +0000 |
| commit | 4b4fe385e49bd883fd183b5f21c1ea486c722e61 (patch) | |
| tree | c3d8fdb355c9c73e57723718c22103aaf7d15aa6 /lldb/source/Plugins | |
| parent | 1f917f69ff07f09b6dbb670971f57f8efe718b84 (diff) | |
Diffstat (limited to 'lldb/source/Plugins')
45 files changed, 837 insertions, 221 deletions
diff --git a/lldb/source/Plugins/ABI/X86/ABIX86.cpp b/lldb/source/Plugins/ABI/X86/ABIX86.cpp index 2cd653fe2c5e..ee568310d387 100644 --- a/lldb/source/Plugins/ABI/X86/ABIX86.cpp +++ b/lldb/source/Plugins/ABI/X86/ABIX86.cpp @@ -100,8 +100,8 @@ addCombinedRegisters(std::vector<DynamicRegisterInfo::Register> ®s, if (regdata1->subreg_name != regdata2->subreg_name) continue; - uint32_t base_index1 = regdata1->base_index.getValue(); - uint32_t base_index2 = regdata2->base_index.getValue(); + uint32_t base_index1 = regdata1->base_index.value(); + uint32_t base_index2 = regdata2->base_index.value(); if (regs[base_index1].byte_size != base_size || regs[base_index2].byte_size != base_size) continue; diff --git a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp index a774d5b61cfe..fb404e985f80 100644 --- a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp +++ b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp @@ -1379,13 +1379,13 @@ const char *DisassemblerLLVMC::SymbolLookup(uint64_t value, uint64_t *type_ptr, // then this is a pc-relative address calculation. if (*type_ptr == LLVMDisassembler_ReferenceType_In_ARM64_ADDXri && m_adrp_insn && m_adrp_address == pc - 4 && - (m_adrp_insn.getValue() & 0x1f) == ((value >> 5) & 0x1f)) { + (m_adrp_insn.value() & 0x1f) == ((value >> 5) & 0x1f)) { uint32_t addxri_inst; uint64_t adrp_imm, addxri_imm; // Get immlo and immhi bits, OR them together to get the ADRP imm // value. - adrp_imm = ((m_adrp_insn.getValue() & 0x00ffffe0) >> 3) | - ((m_adrp_insn.getValue() >> 29) & 0x3); + adrp_imm = ((m_adrp_insn.value() & 0x00ffffe0) >> 3) | + ((m_adrp_insn.value() >> 29) & 0x3); // if high bit of immhi after right-shifting set, sign extend if (adrp_imm & (1ULL << 20)) adrp_imm |= ~((1ULL << 21) - 1); diff --git a/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp b/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp index 5e2a866adb22..5dbbd209bd9b 100644 --- a/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp +++ b/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp @@ -49,6 +49,10 @@ HexagonDYLDRendezvous::HexagonDYLDRendezvous(Process *process) : m_process(process), m_rendezvous_addr(LLDB_INVALID_ADDRESS), m_current(), m_previous(), m_soentries(), m_added_soentries(), m_removed_soentries() { m_thread_info.valid = false; + m_thread_info.dtv_offset = 0; + m_thread_info.dtv_slot_size = 0; + m_thread_info.modid_offset = 0; + m_thread_info.tls_offset = 0; // Cache a copy of the executable path if (m_process) { diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp index 7a1ac7870547..799ae29e2841 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp @@ -197,6 +197,27 @@ bool ASTResultSynthesizer::SynthesizeObjCMethodResult( return ret; } +/// Returns true if LLDB can take the address of the given lvalue for the sake +/// of capturing the expression result. Returns false if LLDB should instead +/// store the expression result in a result variable. +static bool CanTakeAddressOfLValue(const Expr *lvalue_expr) { + assert(lvalue_expr->getValueKind() == VK_LValue && + "lvalue_expr not a lvalue"); + + QualType qt = lvalue_expr->getType(); + // If the lvalue has const-qualified non-volatile integral or enum type, then + // the underlying value might come from a const static data member as + // described in C++11 [class.static.data]p3. If that's the case, then the + // value might not have an address if the user didn't also define the member + // in a namespace scope. Taking the address would cause that LLDB later fails + // to link the expression, so those lvalues should be stored in a result + // variable. + if (qt->isIntegralOrEnumerationType() && qt.isConstQualified() && + !qt.isVolatileQualified()) + return false; + return true; +} + bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body, DeclContext *DC) { Log *log = GetLog(LLDBLog::Expressions); @@ -265,6 +286,10 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body, // - During dematerialization, $0 is marked up as a load address with value // equal to the contents of the structure entry. // + // - Note: if we cannot take an address of the resulting Lvalue (e.g. it's + // a static const member without an out-of-class definition), then we + // follow the Rvalue route. + // // For Rvalues // // - In AST result synthesis the expression E is transformed into an @@ -304,7 +329,7 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body, clang::VarDecl *result_decl = nullptr; - if (is_lvalue) { + if (is_lvalue && CanTakeAddressOfLValue(last_expr)) { IdentifierInfo *result_ptr_id; if (expr_type->isFunctionType()) diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index 1bf29efb0bee..f8443d608ac3 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -1430,10 +1430,9 @@ static bool ImportOffsetMap(llvm::DenseMap<const D *, O> &destination_map, std::vector<PairType> sorted_items; sorted_items.reserve(source_map.size()); sorted_items.assign(source_map.begin(), source_map.end()); - llvm::sort(sorted_items.begin(), sorted_items.end(), - [](const PairType &lhs, const PairType &rhs) { - return lhs.second < rhs.second; - }); + llvm::sort(sorted_items, [](const PairType &lhs, const PairType &rhs) { + return lhs.second < rhs.second; + }); for (const auto &item : sorted_items) { DeclFromUser<D> user_decl(const_cast<D *>(item.first)); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index 4305a9982343..6ba03dad98d1 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -9,10 +9,13 @@ #include "ClangExpressionDeclMap.h" #include "ClangASTSource.h" +#include "ClangExpressionUtil.h" +#include "ClangExpressionVariable.h" #include "ClangModulesDeclVendor.h" #include "ClangPersistentVariables.h" #include "ClangUtil.h" +#include "NameSearchContext.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Address.h" #include "lldb/Core/Module.h" @@ -44,6 +47,7 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" +#include "lldb/lldb-private-types.h" #include "lldb/lldb-private.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -62,6 +66,24 @@ using namespace clang; static const char *g_lldb_local_vars_namespace_cstr = "$__lldb_local_vars"; +namespace { +/// A lambda is represented by Clang as an artifical class whose +/// members are the lambda captures. If we capture a 'this' pointer, +/// the artifical class will contain a member variable named 'this'. +/// The function returns a ValueObject for the captured 'this' if such +/// member exists. If no 'this' was captured, return a nullptr. +lldb::ValueObjectSP GetCapturedThisValueObject(StackFrame *frame) { + assert(frame); + + if (auto thisValSP = frame->FindVariable(ConstString("this"))) + if (auto thisThisValSP = + thisValSP->GetChildMemberWithName(ConstString("this"), true)) + return thisThisValSP; + + return nullptr; +} +} // namespace + ClangExpressionDeclMap::ClangExpressionDeclMap( bool keep_result_in_memory, Materializer::PersistentVariableDelegate *result_delegate, @@ -394,6 +416,10 @@ bool ClangExpressionDeclMap::AddValueToStruct(const NamedDecl *decl, else if (parser_vars->m_lldb_var) offset = m_parser_vars->m_materializer->AddVariable( parser_vars->m_lldb_var, err); + else if (parser_vars->m_lldb_valobj_provider) { + offset = m_parser_vars->m_materializer->AddValueObject( + name, parser_vars->m_lldb_valobj_provider, err); + } } if (!err.Success()) @@ -795,6 +821,28 @@ void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context) { TypeSystemClang::DeclContextGetAsCXXMethodDecl(function_decl_ctx); if (method_decl) { + if (auto capturedThis = GetCapturedThisValueObject(frame)) { + // We're inside a lambda and we captured a 'this'. + // Import the outer class's AST instead of the + // (unnamed) lambda structure AST so unqualified + // member lookups are understood by the Clang parser. + // + // If we're in a lambda which didn't capture 'this', + // $__lldb_class will correspond to the lambda closure + // AST and references to captures will resolve like + // regular member varaiable accesses do. + TypeFromUser pointee_type = + capturedThis->GetCompilerType().GetPointeeType(); + + LLDB_LOG(log, + " CEDM::FEVD Adding captured type ({0} for" + " $__lldb_class: {1}", + capturedThis->GetTypeName(), capturedThis->GetName()); + + AddContextClassType(context, pointee_type); + return; + } + clang::CXXRecordDecl *class_decl = method_decl->getParent(); QualType class_qual_type(class_decl->getTypeForDecl(), 0); @@ -1053,6 +1101,30 @@ bool ClangExpressionDeclMap::LookupLocalVariable( context.m_found_variable = true; } } + + // We're in a local_var_lookup but haven't found any local variables + // so far. When performing a variable lookup from within the context of + // a lambda, we count the lambda captures as local variables. Thus, + // see if we captured any variables with the requested 'name'. + if (!variable_found) { + auto find_capture = [](ConstString varname, + StackFrame *frame) -> ValueObjectSP { + if (auto lambda = ClangExpressionUtil::GetLambdaValueObject(frame)) { + if (auto capture = lambda->GetChildMemberWithName(varname, true)) { + return capture; + } + } + + return nullptr; + }; + + if (auto capture = find_capture(name, frame)) { + variable_found = true; + context.m_found_variable = true; + AddOneVariable(context, std::move(capture), std::move(find_capture)); + } + } + return variable_found; } @@ -1493,25 +1565,15 @@ bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var, return true; } -void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, - VariableSP var, - ValueObjectSP valobj) { - assert(m_parser_vars.get()); - - Log *log = GetLog(LLDBLog::Expressions); - - TypeFromUser ut; - TypeFromParser pt; - Value var_location; - - if (!GetVariableValue(var, var_location, &ut, &pt)) - return; - +ClangExpressionVariable::ParserVars * +ClangExpressionDeclMap::AddExpressionVariable(NameSearchContext &context, + TypeFromParser const &pt, + ValueObjectSP valobj) { clang::QualType parser_opaque_type = QualType::getFromOpaquePtr(pt.GetOpaqueQualType()); if (parser_opaque_type.isNull()) - return; + return nullptr; if (const clang::Type *parser_type = parser_opaque_type.getTypePtr()) { if (const TagType *tag_type = dyn_cast<TagType>(parser_type)) @@ -1538,16 +1600,89 @@ void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, entity->EnableParserVars(GetParserID()); ClangExpressionVariable::ParserVars *parser_vars = entity->GetParserVars(GetParserID()); + parser_vars->m_named_decl = var_decl; - parser_vars->m_llvm_value = nullptr; - parser_vars->m_lldb_value = var_location; - parser_vars->m_lldb_var = var; if (is_reference) entity->m_flags |= ClangExpressionVariable::EVTypeIsReference; + return parser_vars; +} + +void ClangExpressionDeclMap::AddOneVariable( + NameSearchContext &context, ValueObjectSP valobj, + ValueObjectProviderTy valobj_provider) { + assert(m_parser_vars.get()); + assert(valobj); + + Log *log = GetLog(LLDBLog::Expressions); + + Value var_location = valobj->GetValue(); + + TypeFromUser user_type = valobj->GetCompilerType(); + + TypeSystemClang *clang_ast = + llvm::dyn_cast_or_null<TypeSystemClang>(user_type.GetTypeSystem()); + + if (!clang_ast) { + LLDB_LOG(log, "Skipped a definition because it has no Clang AST"); + return; + } + + TypeFromParser parser_type = GuardedCopyType(user_type); + + if (!parser_type) { + LLDB_LOG(log, + "Couldn't copy a variable's type into the parser's AST context"); + + return; + } + + if (var_location.GetContextType() == Value::ContextType::Invalid) + var_location.SetCompilerType(parser_type); + + ClangExpressionVariable::ParserVars *parser_vars = + AddExpressionVariable(context, parser_type, valobj); + + if (!parser_vars) + return; + + LLDB_LOG(log, " CEDM::FEVD Found variable {0}, returned\n{1} (original {2})", + context.m_decl_name, ClangUtil::DumpDecl(parser_vars->m_named_decl), + ClangUtil::ToString(user_type)); + + parser_vars->m_llvm_value = nullptr; + parser_vars->m_lldb_value = std::move(var_location); + parser_vars->m_lldb_valobj_provider = std::move(valobj_provider); +} + +void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, + VariableSP var, + ValueObjectSP valobj) { + assert(m_parser_vars.get()); + + Log *log = GetLog(LLDBLog::Expressions); + + TypeFromUser ut; + TypeFromParser pt; + Value var_location; + + if (!GetVariableValue(var, var_location, &ut, &pt)) + return; + + ClangExpressionVariable::ParserVars *parser_vars = + AddExpressionVariable(context, pt, std::move(valobj)); + + if (!parser_vars) + return; + LLDB_LOG(log, " CEDM::FEVD Found variable {0}, returned\n{1} (original {2})", - decl_name, ClangUtil::DumpDecl(var_decl), ClangUtil::ToString(ut)); + context.m_decl_name, ClangUtil::DumpDecl(parser_vars->m_named_decl), + ClangUtil::ToString(ut)); + + parser_vars->m_llvm_value = nullptr; + parser_vars->m_lldb_value = var_location; + parser_vars->m_lldb_var = var; } void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h index f968f859cc72..bf7646ccaedf 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h @@ -531,6 +531,23 @@ private: TypeFromParser *parser_type = nullptr); /// Use the NameSearchContext to generate a Decl for the given LLDB + /// ValueObject, and put it in the list of found entities. + /// + /// Helper function used by the other AddOneVariable APIs. + /// + /// \param[in,out] context + /// The NameSearchContext to use when constructing the Decl. + /// + /// \param[in] pt + /// The CompilerType of the variable we're adding a Decl for. + /// + /// \param[in] var + /// The LLDB ValueObject that needs a Decl. + ClangExpressionVariable::ParserVars * + AddExpressionVariable(NameSearchContext &context, TypeFromParser const &pt, + lldb::ValueObjectSP valobj); + + /// Use the NameSearchContext to generate a Decl for the given LLDB /// Variable, and put it in the Tuple list. /// /// \param[in] context @@ -544,6 +561,20 @@ private: void AddOneVariable(NameSearchContext &context, lldb::VariableSP var, lldb::ValueObjectSP valobj); + /// Use the NameSearchContext to generate a Decl for the given ValueObject + /// and put it in the list of found entities. + /// + /// \param[in,out] context + /// The NameSearchContext to use when constructing the Decl. + /// + /// \param[in] valobj + /// The ValueObject that needs a Decl. + /// + /// \param[in] valobj_provider Callback that fetches a ValueObjectSP + /// from the specified frame + void AddOneVariable(NameSearchContext &context, lldb::ValueObjectSP valobj, + ValueObjectProviderTy valobj_provider); + /// Use the NameSearchContext to generate a Decl for the given persistent /// variable, and put it in the list of found entities. /// diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp index 5168f637c443..56c00b35ba11 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp @@ -8,6 +8,8 @@ #include "ClangExpressionSourceCode.h" +#include "ClangExpressionUtil.h" + #include "clang/Basic/CharInfo.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" @@ -27,6 +29,7 @@ #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" #include "lldb/Utility/StreamString.h" +#include "lldb/lldb-forward.h" using namespace lldb_private; @@ -200,6 +203,34 @@ public: return m_tokens.find(token) != m_tokens.end(); } }; + +// If we're evaluating from inside a lambda that captures a 'this' pointer, +// add a "using" declaration to 'stream' for each capture used in the +// expression (tokenized by 'verifier'). +// +// If no 'this' capture exists, generate no using declarations. Instead +// capture lookups will get resolved by the same mechanism as class member +// variable lookup. That's because Clang generates an unnamed structure +// representing the lambda closure whose members are the captured variables. +void AddLambdaCaptureDecls(StreamString &stream, StackFrame *frame, + TokenVerifier const &verifier) { + assert(frame); + + if (auto thisValSP = ClangExpressionUtil::GetLambdaValueObject(frame)) { + uint32_t numChildren = thisValSP->GetNumChildren(); + for (uint32_t i = 0; i < numChildren; ++i) { + auto childVal = thisValSP->GetChildAtIndex(i, true); + ConstString childName(childVal ? childVal->GetName() : ConstString("")); + + if (!childName.IsEmpty() && verifier.hasToken(childName.GetStringRef()) && + childName != "this") { + stream.Printf("using $__lldb_local_vars::%s;\n", + childName.GetCString()); + } + } + } +} + } // namespace TokenVerifier::TokenVerifier(std::string body) { @@ -264,16 +295,24 @@ TokenVerifier::TokenVerifier(std::string body) { } } -void ClangExpressionSourceCode::AddLocalVariableDecls( - const lldb::VariableListSP &var_list_sp, StreamString &stream, - const std::string &expr) const { +void ClangExpressionSourceCode::AddLocalVariableDecls(StreamString &stream, + const std::string &expr, + StackFrame *frame) const { + assert(frame); TokenVerifier tokens(expr); + lldb::VariableListSP var_list_sp = frame->GetInScopeVariableList(false, true); + for (size_t i = 0; i < var_list_sp->GetSize(); i++) { lldb::VariableSP var_sp = var_list_sp->GetVariableAtIndex(i); ConstString var_name = var_sp->GetName(); + if (var_name == "this" && m_wrap_kind == WrapKind::CppMemberFunction) { + AddLambdaCaptureDecls(stream, frame, tokens); + + continue; + } // We can check for .block_descriptor w/o checking for langauge since this // is not a valid identifier in either C or C++. @@ -288,9 +327,6 @@ void ClangExpressionSourceCode::AddLocalVariableDecls( if ((var_name == "self" || var_name == "_cmd") && is_objc) continue; - if (var_name == "this" && m_wrap_kind == WrapKind::CppMemberFunction) - continue; - stream.Printf("using $__lldb_local_vars::%s;\n", var_name.AsCString()); } } @@ -376,10 +412,8 @@ bool ClangExpressionSourceCode::GetText( if (add_locals) if (target->GetInjectLocalVariables(&exe_ctx)) { - lldb::VariableListSP var_list_sp = - frame->GetInScopeVariableList(false, true); - AddLocalVariableDecls(var_list_sp, lldb_local_var_decls, - force_add_all_locals ? "" : m_body); + AddLocalVariableDecls(lldb_local_var_decls, + force_add_all_locals ? "" : m_body, frame); } } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h index 54ae837fb30f..f721bb2f319e 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h @@ -78,9 +78,19 @@ protected: Wrapping wrap, WrapKind wrap_kind); private: - void AddLocalVariableDecls(const lldb::VariableListSP &var_list_sp, - StreamString &stream, - const std::string &expr) const; + /// Writes "using" declarations for local variables into the specified stream. + /// + /// Behaviour is undefined if 'frame == nullptr'. + /// + /// \param[out] stream Stream that this function generates "using" + /// declarations into. + /// + /// \param[in] expr Expression source that we're evaluating. + /// + /// \param[in] frame StackFrame which carries information about the local + /// variables that we're generating "using" declarations for. + void AddLocalVariableDecls(StreamString &stream, const std::string &expr, + StackFrame *frame) const; /// String marking the start of the user expression. std::string m_start_marker; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.cpp new file mode 100644 index 000000000000..9b490e1c036e --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.cpp @@ -0,0 +1,27 @@ +//===-- ClangExpressionUtil.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 "ClangExpressionUtil.h" + +#include "lldb/Core/ValueObject.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Utility/ConstString.h" + +namespace lldb_private { +namespace ClangExpressionUtil { +lldb::ValueObjectSP GetLambdaValueObject(StackFrame *frame) { + assert(frame); + + if (auto this_val_sp = frame->FindVariable(ConstString("this"))) + if (this_val_sp->GetChildMemberWithName(ConstString("this"), true)) + return this_val_sp; + + return nullptr; +} +} // namespace ClangExpressionUtil +} // namespace lldb_private diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.h new file mode 100644 index 000000000000..fb8b857256c0 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.h @@ -0,0 +1,30 @@ +//===-- ClangExpressionUtil.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_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONUTIL_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONUTIL_H + +#include "lldb/lldb-private.h" + +namespace lldb_private { +namespace ClangExpressionUtil { +/// Returns a ValueObject for the lambda class in the current frame +/// +/// To represent a lambda, Clang generates an artificial class +/// whose members are the captures and whose operator() is the +/// lambda implementation. If we capture a 'this' pointer, +/// the artifical class will contain a member variable named 'this'. +/// +/// This method returns the 'this' pointer to the artificial lambda +/// class if a real 'this' was captured. Otherwise, returns nullptr. +lldb::ValueObjectSP GetLambdaValueObject(StackFrame *frame); + +} // namespace ClangExpressionUtil +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONHELPER_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h index 7bb68e78373f..c7d9e05269fa 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h @@ -116,7 +116,7 @@ public: /// The following values should not live beyond parsing class ParserVars { public: - ParserVars() : m_lldb_value(), m_lldb_var() {} + ParserVars() = default; const clang::NamedDecl *m_named_decl = nullptr; ///< The Decl corresponding to this variable @@ -129,6 +129,12 @@ public: const lldb_private::Symbol *m_lldb_sym = nullptr; ///< The original symbol for this /// variable, if it was a symbol + + /// Callback that provides a ValueObject for the + /// specified frame. Used by the materializer for + /// re-fetching ValueObjects when materializing + /// ivars. + ValueObjectProviderTy m_lldb_valobj_provider; }; private: diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp index 78b8bf11220a..7145e7804e68 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -872,6 +872,34 @@ bool ClangUserExpression::Complete(ExecutionContext &exe_ctx, return true; } +lldb::addr_t ClangUserExpression::GetCppObjectPointer( + lldb::StackFrameSP frame_sp, ConstString &object_name, Status &err) { + auto valobj_sp = + GetObjectPointerValueObject(std::move(frame_sp), object_name, err); + + // We're inside a C++ class method. This could potentially be an unnamed + // lambda structure. If the lambda captured a "this", that should be + // the object pointer. + if (auto thisChildSP = + valobj_sp->GetChildMemberWithName(ConstString("this"), true)) { + valobj_sp = thisChildSP; + } + + if (!err.Success() || !valobj_sp.get()) + return LLDB_INVALID_ADDRESS; + + lldb::addr_t ret = valobj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); + + if (ret == LLDB_INVALID_ADDRESS) { + err.SetErrorStringWithFormat( + "Couldn't load '%s' because its value couldn't be evaluated", + object_name.AsCString()); + return LLDB_INVALID_ADDRESS; + } + + return ret; +} + bool ClangUserExpression::AddArguments(ExecutionContext &exe_ctx, std::vector<lldb::addr_t> &args, lldb::addr_t struct_address, @@ -906,8 +934,14 @@ bool ClangUserExpression::AddArguments(ExecutionContext &exe_ctx, address_type != eAddressTypeLoad) object_ptr_error.SetErrorString("Can't get context object's " "debuggee address"); - } else - object_ptr = GetObjectPointer(frame_sp, object_name, object_ptr_error); + } else { + if (m_in_cplusplus_method) { + object_ptr = + GetCppObjectPointer(frame_sp, object_name, object_ptr_error); + } else { + object_ptr = GetObjectPointer(frame_sp, object_name, object_ptr_error); + } + } if (!object_ptr_error.Success()) { exe_ctx.GetTargetRef().GetDebugger().GetAsyncOutputStream()->Printf( diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h index 30cdd2f3e990..4d5458f1807d 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h @@ -198,6 +198,10 @@ private: ExecutionContext &exe_ctx, std::vector<std::string> modules_to_import, bool for_completion); + + lldb::addr_t GetCppObjectPointer(lldb::StackFrameSP frame, + ConstString &object_name, Status &err); + /// Defines how the current expression should be wrapped. ClangExpressionSourceCode::WrapKind GetWrapKind() const; bool SetupPersistentState(DiagnosticManager &diagnostic_manager, diff --git a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h index 8b167dd347ad..c877724a9d30 100644 --- a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h +++ b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h @@ -91,7 +91,8 @@ public: EmulateInstructionARM(const ArchSpec &arch) : EmulateInstruction(arch), m_arm_isa(0), m_opcode_mode(eModeInvalid), - m_opcode_cpsr(0), m_it_session(), m_ignore_conditions(false) { + m_opcode_cpsr(0), m_new_inst_cpsr(0), m_it_session(), + m_ignore_conditions(false) { SetArchitecture(arch); } diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index 89bee3e000c0..23ce1654fb83 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -218,10 +218,10 @@ void CPlusPlusLanguage::MethodName::Parse() { } else { CPlusPlusNameParser parser(m_full.GetStringRef()); if (auto function = parser.ParseAsFunctionDefinition()) { - m_basename = function.getValue().name.basename; - m_context = function.getValue().name.context; - m_arguments = function.getValue().arguments; - m_qualifiers = function.getValue().qualifiers; + m_basename = function.value().name.basename; + m_context = function.value().name.context; + m_arguments = function.value().arguments; + m_qualifiers = function.value().qualifiers; m_parse_error = false; } else { m_parse_error = true; @@ -329,8 +329,8 @@ bool CPlusPlusLanguage::ExtractContextAndIdentifier( CPlusPlusNameParser parser(name); if (auto full_name = parser.ParseAsFullName()) { - identifier = full_name.getValue().basename; - context = full_name.getValue().context; + identifier = full_name.value().basename; + context = full_name.value().context; return true; } return false; @@ -409,12 +409,12 @@ protected: private: /// Input character until which we have constructed the respective output /// already. - const char *Written; + const char *Written = ""; llvm::SmallString<128> Result; /// Whether we have performed any substitutions. - bool Substituted; + bool Substituted = false; const char *currentParserPos() const { return this->First; } @@ -909,7 +909,7 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { cpp_category_sp, lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator, "std::map iterator synthetic children", - ConstString("^std::__[[:alnum:]]+::__map_iterator<.+>$"), stl_synth_flags, + ConstString("^std::__[[:alnum:]]+::__map_(const_)?iterator<.+>$"), stl_synth_flags, true); AddCXXSynthetic( diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp index eca36fff18f8..a9a4e98775d9 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp @@ -55,8 +55,8 @@ Optional<ParsedName> CPlusPlusNameParser::ParseAsFullName() { if (HasMoreTokens()) return None; ParsedName result; - result.basename = GetTextForRange(name_ranges.getValue().basename_range); - result.context = GetTextForRange(name_ranges.getValue().context_range); + result.basename = GetTextForRange(name_ranges.value().basename_range); + result.context = GetTextForRange(name_ranges.value().context_range); return result; } @@ -125,8 +125,8 @@ CPlusPlusNameParser::ParseFunctionImpl(bool expect_return_type) { size_t end_position = GetCurrentPosition(); ParsedFunction result; - result.name.basename = GetTextForRange(maybe_name.getValue().basename_range); - result.name.context = GetTextForRange(maybe_name.getValue().context_range); + result.name.basename = GetTextForRange(maybe_name.value().basename_range); + result.name.context = GetTextForRange(maybe_name.value().context_range); result.arguments = GetTextForRange(Range(argument_start, qualifiers_start)); result.qualifiers = GetTextForRange(Range(qualifiers_start, end_position)); start_position.Remove(); @@ -617,9 +617,9 @@ CPlusPlusNameParser::ParseFullNameImpl() { ParsedNameRanges result; if (last_coloncolon_position) { result.context_range = Range(start_position.GetSavedPosition(), - last_coloncolon_position.getValue()); + last_coloncolon_position.value()); result.basename_range = - Range(last_coloncolon_position.getValue() + 1, GetCurrentPosition()); + Range(last_coloncolon_position.value() + 1, GetCurrentPosition()); } else { result.basename_range = Range(start_position.GetSavedPosition(), GetCurrentPosition()); diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp index 9f5624de4e63..a1953a1c7a22 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp @@ -119,16 +119,16 @@ protected: AbstractListFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) {} - size_t m_count; - ValueObject *m_head; + size_t m_count = 0; + ValueObject *m_head = nullptr; static constexpr bool g_use_loop_detect = true; - size_t m_loop_detected; // The number of elements that have had loop detection - // run over them. + size_t m_loop_detected = 0; // The number of elements that have had loop + // detection run over them. ListEntry m_slow_runner; // Used for loop detection ListEntry m_fast_runner; // Used for loop detection - size_t m_list_capping_size; + size_t m_list_capping_size = 0; CompilerType m_element_type; std::map<size_t, ListIterator> m_iterators; diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp index 4aae524e3701..ca6f92d003ad 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp @@ -165,8 +165,8 @@ private: } MapEntry m_entry; - size_t m_max_depth; - bool m_error; + size_t m_max_depth = 0; + bool m_error = false; }; namespace lldb_private { diff --git a/lldb/source/Plugins/Language/ObjC/CFBasicHash.h b/lldb/source/Plugins/Language/ObjC/CFBasicHash.h index fd30f5f7845f..f850c50342a3 100644 --- a/lldb/source/Plugins/Language/ObjC/CFBasicHash.h +++ b/lldb/source/Plugins/Language/ObjC/CFBasicHash.h @@ -68,7 +68,7 @@ private: ExecutionContextRef m_exe_ctx_ref; bool m_mutable = true; bool m_multi = false; - HashType m_type; + HashType m_type = HashType::set; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp index 2c6998451ad6..e5e62b534560 100644 --- a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp @@ -137,7 +137,7 @@ private: lldb::ByteOrder m_order = lldb::eByteOrderInvalid; DataDescriptor_32 *m_data_32 = nullptr; DataDescriptor_64 *m_data_64 = nullptr; - lldb::addr_t m_data_ptr; + lldb::addr_t m_data_ptr = LLDB_INVALID_ADDRESS; CompilerType m_pair_type; std::vector<DictionaryItemDescriptor> m_children; }; diff --git a/lldb/source/Plugins/Language/ObjC/NSError.cpp b/lldb/source/Plugins/Language/ObjC/NSError.cpp index 937c7204d3c4..4f237824c4b0 100644 --- a/lldb/source/Plugins/Language/ObjC/NSError.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSError.cpp @@ -177,7 +177,7 @@ private: // values to leak if the latter, then I need to store a SharedPointer to it - // so that it only goes away when everyone else in the cluster goes away oh // joy! - ValueObject *m_child_ptr; + ValueObject *m_child_ptr = nullptr; ValueObjectSP m_child_sp; }; diff --git a/lldb/source/Plugins/Language/ObjC/NSSet.cpp b/lldb/source/Plugins/Language/ObjC/NSSet.cpp index 0a6b445d97c8..b5c8e849abcc 100644 --- a/lldb/source/Plugins/Language/ObjC/NSSet.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSSet.cpp @@ -76,7 +76,7 @@ private: uint8_t m_ptr_size = 8; DataDescriptor_32 *m_data_32 = nullptr; DataDescriptor_64 *m_data_64 = nullptr; - lldb::addr_t m_data_ptr; + lldb::addr_t m_data_ptr = LLDB_INVALID_ADDRESS; std::vector<SetItemDescriptor> m_children; }; diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h index 7ba957940ae7..0c6eccab9f27 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h @@ -347,12 +347,12 @@ public: private: ConstString m_name; - uint8_t m_pointer_size; - bool m_valid; - uint64_t m_info_bits; - uint64_t m_value_bits; - int64_t m_value_bits_signed; - uint64_t m_payload; + uint8_t m_pointer_size = 0; + bool m_valid = false; + uint64_t m_info_bits = 0; + uint64_t m_value_bits = 0; + int64_t m_value_bits_signed = 0; + uint64_t m_payload = 0; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp index f9ccaf0115a2..18e1d12ef980 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp @@ -578,7 +578,8 @@ AppleObjCTrampolineHandler::AppleObjCTrampolineHandler( : m_process_wp(), m_objc_module_sp(objc_module_sp), m_impl_fn_addr(LLDB_INVALID_ADDRESS), m_impl_stret_fn_addr(LLDB_INVALID_ADDRESS), - m_msg_forward_addr(LLDB_INVALID_ADDRESS) { + m_msg_forward_addr(LLDB_INVALID_ADDRESS), + m_msg_forward_stret_addr(LLDB_INVALID_ADDRESS) { if (process_sp) m_process_wp = process_sp; // Look up the known resolution functions: @@ -780,10 +781,8 @@ AppleObjCTrampolineHandler::FindDispatchFunction(lldb::addr_t addr) { return nullptr; } -void -AppleObjCTrampolineHandler::ForEachDispatchFunction( - std::function<void(lldb::addr_t, - const DispatchFunction &)> callback) { +void AppleObjCTrampolineHandler::ForEachDispatchFunction( + std::function<void(lldb::addr_t, const DispatchFunction &)> callback) { for (auto elem : m_msgSend_map) { callback(elem.first, g_dispatch_functions[elem.second]); } diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp index bc8e43764af6..0c032f8a7c88 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp @@ -4163,7 +4163,7 @@ public: int m_kernel_types = RSReduceBreakpointResolver::eKernelTypeAll; llvm::StringRef m_reduce_name; RSCoordinate m_coord; - bool m_have_coord; + bool m_have_coord = false; }; Options *GetOptions() override { return &m_options; } @@ -4268,7 +4268,7 @@ public: } RSCoordinate m_coord; - bool m_have_coord; + bool m_have_coord = false; }; bool DoExecute(Args &command, CommandReturnObject &result) override { diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h index 4ddf996dedb2..bc460706fd29 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h @@ -171,7 +171,8 @@ struct RSReductionDescriptor { llvm::StringRef halter_name = ".") : m_module(module), m_reduce_name(name), m_init_name(init_name), m_accum_name(accum_name), m_comb_name(comb_name), - m_outc_name(outc_name), m_halter_name(halter_name) { + m_outc_name(outc_name), m_halter_name(halter_name), m_accum_sig(0), + m_accum_data_size(0), m_comb_name_generated(false) { // TODO Check whether the combiner is an autogenerated name, and track // this } diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index f9fb36890d5a..122298d87bf8 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -1607,7 +1607,7 @@ lldb::user_id_t ObjectFileELF::GetSectionIndexByName(const char *name) { } static SectionType GetSectionTypeFromName(llvm::StringRef Name) { - if (Name.consume_front(".debug_") || Name.consume_front(".zdebug_")) { + if (Name.consume_front(".debug_")) { return llvm::StringSwitch<SectionType>(Name) .Case("abbrev", eSectionTypeDWARFDebugAbbrev) .Case("abbrev.dwo", eSectionTypeDWARFDebugAbbrevDwo) @@ -3365,8 +3365,7 @@ size_t ObjectFileELF::ReadSectionData(Section *section, return section->GetObjectFile()->ReadSectionData(section, section_data); size_t result = ObjectFile::ReadSectionData(section, section_data); - if (result == 0 || !llvm::object::Decompressor::isCompressedELFSection( - section->Get(), section->GetName().GetStringRef())) + if (result == 0 || !(section->Get() & llvm::ELF::SHF_COMPRESSED)) return result; auto Decompressor = llvm::object::Decompressor::create( diff --git a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp index 516bcb21b019..acb131b8a775 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp +++ b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp @@ -349,6 +349,7 @@ llvm::support::ulittle64_t read_register_u64(RegisterContext *reg_ctx, lldb_private::minidump::MinidumpContext_x86_64 GetThreadContext_64(RegisterContext *reg_ctx) { lldb_private::minidump::MinidumpContext_x86_64 thread_context; + thread_context.p1_home = {}; thread_context.context_flags = static_cast<uint32_t>( lldb_private::minidump::MinidumpContext_x86_64_Flags::x86_64_Flag | lldb_private::minidump::MinidumpContext_x86_64_Flags::Control | diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp index 67e03ff1ea39..40f70e8a0a75 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp @@ -444,6 +444,7 @@ RegisterContextPOSIX_x86::RegisterContextPOSIX_x86( } ::memset(&m_fpr, 0, sizeof(FPR)); + ::memset(&m_ymm_set, 0, sizeof(YMM)); m_fpr_type = eNotValid; } diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp index 579ac6e36d0b..4db7abe603d4 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp @@ -396,15 +396,11 @@ bool RegisterInfoPOSIX_arm64::IsSVERegVG(unsigned reg) const { } bool RegisterInfoPOSIX_arm64::IsPAuthReg(unsigned reg) const { - return std::find(pauth_regnum_collection.begin(), - pauth_regnum_collection.end(), - reg) != pauth_regnum_collection.end(); + return llvm::is_contained(pauth_regnum_collection, reg); } bool RegisterInfoPOSIX_arm64::IsMTEReg(unsigned reg) const { - return std::find(m_mte_regnum_collection.begin(), - m_mte_regnum_collection.end(), - reg) != m_mte_regnum_collection.end(); + return llvm::is_contained(m_mte_regnum_collection, reg); } uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEZ0() const { return sve_z0; } diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index e5461c1899ec..755b8220c49e 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -67,8 +67,8 @@ GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name, m_packet_timeout(1), #endif m_echo_number(0), m_supports_qEcho(eLazyBoolCalculate), m_history(512), - m_send_acks(true), m_compression_type(CompressionType::None), - m_listen_url() { + m_send_acks(true), m_is_platform(false), + m_compression_type(CompressionType::None), m_listen_url() { } // Destructor @@ -1266,7 +1266,7 @@ GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client, GDBRemoteCommunication::ScopedTimeout::ScopedTimeout( GDBRemoteCommunication &gdb_comm, std::chrono::seconds timeout) - : m_gdb_comm(gdb_comm), m_timeout_modified(false) { + : m_gdb_comm(gdb_comm), m_saved_timeout(0), m_timeout_modified(false) { auto curr_timeout = gdb_comm.GetPacketTimeout(); // Only update the timeout if the timeout is greater than the current // timeout. If the current timeout is larger, then just use that. diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 63174ef55219..5804c13fe7b6 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -246,6 +246,9 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { StringExtractorGDBRemote::eServerPacketType_QNonStop, &GDBRemoteCommunicationServerLLGS::Handle_QNonStop); RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vStdio, + &GDBRemoteCommunicationServerLLGS::Handle_vStdio); + RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_vStopped, &GDBRemoteCommunicationServerLLGS::Handle_vStopped); RegisterMemberFunctionHandler( @@ -290,7 +293,9 @@ Status GDBRemoteCommunicationServerLLGS::LaunchProcess() { if (!process_or) return Status(process_or.takeError()); m_continue_process = m_current_process = process_or->get(); - m_debugged_processes[m_current_process->GetID()] = std::move(*process_or); + m_debugged_processes.emplace( + m_current_process->GetID(), + DebuggedProcess{std::move(*process_or), DebuggedProcess::Flag{}}); } SetEnabledExtensions(*m_current_process); @@ -361,7 +366,9 @@ Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) { return status; } m_continue_process = m_current_process = process_or->get(); - m_debugged_processes[m_current_process->GetID()] = std::move(*process_or); + m_debugged_processes.emplace( + m_current_process->GetID(), + DebuggedProcess{std::move(*process_or), DebuggedProcess::Flag{}}); SetEnabledExtensions(*m_current_process); // Setup stdout/stderr mapping from inferior. @@ -489,12 +496,14 @@ GDBRemoteCommunicationServerLLGS::SendWResponse( *wait_status); // If the process was killed through vKill, return "OK". - if (m_vkilled_processes.find(process->GetID()) != m_vkilled_processes.end()) + if (bool(m_debugged_processes.at(process->GetID()).flags & + DebuggedProcess::Flag::vkilled)) return SendOKResponse(); StreamGDBRemote response; response.Format("{0:g}", *wait_status); - if (bool(m_extensions_supported & NativeProcessProtocol::Extension::multiprocess)) + if (bool(m_extensions_supported & + NativeProcessProtocol::Extension::multiprocess)) response.Format(";process:{0:x-}", process->GetID()); if (m_non_stop) return SendNotificationPacketNoLock("Stop", m_stop_notification_queue, @@ -1016,9 +1025,11 @@ void GDBRemoteCommunicationServerLLGS::EnqueueStopReplyPackets( return; for (NativeThreadProtocol &listed_thread : m_current_process->Threads()) { - if (listed_thread.GetID() != thread_to_skip) - m_stop_notification_queue.push_back( - PrepareStopReplyPacketForThread(listed_thread).GetString().str()); + if (listed_thread.GetID() != thread_to_skip) { + StreamString stop_reply = PrepareStopReplyPacketForThread(listed_thread); + if (!stop_reply.Empty()) + m_stop_notification_queue.push_back(stop_reply.GetString().str()); + } } } @@ -1045,14 +1056,14 @@ void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Exited( lldb::pid_t pid = process->GetID(); m_mainloop.AddPendingCallback([this, pid](MainLoopBase &loop) { - m_debugged_processes.erase(pid); - auto vkill_it = m_vkilled_processes.find(pid); - if (vkill_it != m_vkilled_processes.end()) - m_vkilled_processes.erase(vkill_it); + auto find_it = m_debugged_processes.find(pid); + assert(find_it != m_debugged_processes.end()); + bool vkilled = bool(find_it->second.flags & DebuggedProcess::Flag::vkilled); + m_debugged_processes.erase(find_it); // Terminate the main loop only if vKill has not been used. // When running in non-stop mode, wait for the vStopped to clear // the notification queue. - else if (m_debugged_processes.empty() && !m_non_stop) { + if (m_debugged_processes.empty() && !m_non_stop && !vkilled) { // Close the pipe to the inferior terminal i/o if we launched it and set // one up. MaybeCloseInferiorTerminalConnection(); @@ -1071,23 +1082,13 @@ void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Stopped( Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); - // Send the stop reason unless this is the stop after the launch or attach. - switch (m_inferior_prev_state) { - case eStateLaunching: - case eStateAttaching: - // Don't send anything per debugserver behavior. - break; - default: - // In all other cases, send the stop reason. - PacketResult result = SendStopReasonForState( - *process, StateType::eStateStopped, /*force_synchronous=*/false); - if (result != PacketResult::Success) { - LLDB_LOGF(log, - "GDBRemoteCommunicationServerLLGS::%s failed to send stop " - "notification for PID %" PRIu64 ", state: eStateExited", - __FUNCTION__, process->GetID()); - } - break; + PacketResult result = SendStopReasonForState( + *process, StateType::eStateStopped, /*force_synchronous=*/false); + if (result != PacketResult::Success) { + LLDB_LOGF(log, + "GDBRemoteCommunicationServerLLGS::%s failed to send stop " + "notification for PID %" PRIu64 ", state: eStateExited", + __FUNCTION__, process->GetID()); } } @@ -1112,14 +1113,16 @@ void GDBRemoteCommunicationServerLLGS::ProcessStateChanged( SendProcessOutput(); // Then stop the forwarding, so that any late output (see llvm.org/pr25652) // does not interfere with our protocol. - StopSTDIOForwarding(); + if (!m_non_stop) + StopSTDIOForwarding(); HandleInferiorState_Stopped(process); break; case StateType::eStateExited: // Same as above SendProcessOutput(); - StopSTDIOForwarding(); + if (!m_non_stop) + StopSTDIOForwarding(); HandleInferiorState_Exited(process); break; @@ -1132,9 +1135,6 @@ void GDBRemoteCommunicationServerLLGS::ProcessStateChanged( } break; } - - // Remember the previous state reported to us. - m_inferior_prev_state = state; } void GDBRemoteCommunicationServerLLGS::DidExec(NativeProcessProtocol *process) { @@ -1147,7 +1147,9 @@ void GDBRemoteCommunicationServerLLGS::NewSubprocess( lldb::pid_t child_pid = child_process->GetID(); assert(child_pid != LLDB_INVALID_PROCESS_ID); assert(m_debugged_processes.find(child_pid) == m_debugged_processes.end()); - m_debugged_processes[child_pid] = std::move(child_process); + m_debugged_processes.emplace( + child_pid, + DebuggedProcess{std::move(child_process), DebuggedProcess::Flag{}}); } void GDBRemoteCommunicationServerLLGS::DataAvailableCallback() { @@ -1197,6 +1199,9 @@ GDBRemoteCommunicationServerLLGS::SendONotification(const char *buffer, response.PutChar('O'); response.PutBytesAsRawHex8(buffer, len); + if (m_non_stop) + return SendNotificationPacketNoLock("Stdio", m_stdio_notification_queue, + response.GetString()); return SendPacketNoLock(response.GetString()); } @@ -1422,7 +1427,8 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_k(StringExtractorGDBRemote &packet) { Log *log = GetLog(LLDBLog::Process); - StopSTDIOForwarding(); + if (!m_non_stop) + StopSTDIOForwarding(); if (m_debugged_processes.empty()) { LLDB_LOG(log, "No debugged process found."); @@ -1432,7 +1438,7 @@ GDBRemoteCommunicationServerLLGS::Handle_k(StringExtractorGDBRemote &packet) { for (auto it = m_debugged_processes.begin(); it != m_debugged_processes.end(); ++it) { LLDB_LOG(log, "Killing process {0}", it->first); - Status error = it->second->Kill(); + Status error = it->second.process_up->Kill(); if (error.Fail()) LLDB_LOG(log, "Failed to kill debugged process {0}: {1}", it->first, error); @@ -1448,7 +1454,8 @@ GDBRemoteCommunicationServerLLGS::Handle_k(StringExtractorGDBRemote &packet) { GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_vKill( StringExtractorGDBRemote &packet) { - StopSTDIOForwarding(); + if (!m_non_stop) + StopSTDIOForwarding(); packet.SetFilePos(6); // vKill; uint32_t pid = packet.GetU32(LLDB_INVALID_PROCESS_ID, 16); @@ -1460,12 +1467,12 @@ GDBRemoteCommunicationServerLLGS::Handle_vKill( if (it == m_debugged_processes.end()) return SendErrorResponse(42); - Status error = it->second->Kill(); + Status error = it->second.process_up->Kill(); if (error.Fail()) return SendErrorResponse(error.ToError()); // OK response is sent when the process dies. - m_vkilled_processes.insert(pid); + it->second.flags |= DebuggedProcess::Flag::vkilled; return PacketResult::Success; } @@ -1518,6 +1525,30 @@ GDBRemoteCommunicationServerLLGS::Handle_QListThreadsInStopReply( } GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::ResumeProcess( + NativeProcessProtocol &process, const ResumeActionList &actions) { + Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread); + + // In non-stop protocol mode, the process could be running already. + // We do not support resuming threads independently, so just error out. + if (!process.CanResume()) { + LLDB_LOG(log, "process {0} cannot be resumed (state={1})", process.GetID(), + process.GetState()); + return SendErrorResponse(0x37); + } + + Status error = process.Resume(actions); + if (error.Fail()) { + LLDB_LOG(log, "process {0} failed to resume: {1}", process.GetID(), error); + return SendErrorResponse(GDBRemoteServerError::eErrorResume); + } + + LLDB_LOG(log, "process {0} resumed", process.GetID()); + + return PacketResult::Success; +} + +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_C(StringExtractorGDBRemote &packet) { Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread); LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); @@ -1552,6 +1583,14 @@ GDBRemoteCommunicationServerLLGS::Handle_C(StringExtractorGDBRemote &packet) { packet, "unexpected content after $C{signal-number}"); } + // In non-stop protocol mode, the process could be running already. + // We do not support resuming threads independently, so just error out. + if (!m_continue_process->CanResume()) { + LLDB_LOG(log, "process cannot be resumed (state={0})", + m_continue_process->GetState()); + return SendErrorResponse(0x37); + } + ResumeActionList resume_actions(StateType::eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); Status error; @@ -1585,14 +1624,11 @@ GDBRemoteCommunicationServerLLGS::Handle_C(StringExtractorGDBRemote &packet) { } } - // Resume the threads. - error = m_continue_process->Resume(resume_actions); - if (error.Fail()) { - LLDB_LOG(log, "failed to resume threads for process {0}: {1}", - m_continue_process->GetID(), error); - - return SendErrorResponse(0x38); - } + // NB: this checks CanResume() twice but using a single code path for + // resuming still seems worth it. + PacketResult resume_res = ResumeProcess(*m_continue_process, resume_actions); + if (resume_res != PacketResult::Success) + return resume_res; // Don't send an "OK" packet, except in non-stop mode; // otherwise, the response is the stopped/exited message. @@ -1627,14 +1663,9 @@ GDBRemoteCommunicationServerLLGS::Handle_c(StringExtractorGDBRemote &packet) { ResumeActionList actions(StateType::eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); - Status error = m_continue_process->Resume(actions); - if (error.Fail()) { - LLDB_LOG(log, "c failed for process {0}: {1}", m_continue_process->GetID(), - error); - return SendErrorResponse(GDBRemoteServerError::eErrorResume); - } - - LLDB_LOG(log, "continued process {0}", m_continue_process->GetID()); + PacketResult resume_res = ResumeProcess(*m_continue_process, actions); + if (resume_res != PacketResult::Success) + return resume_res; return SendContinueSuccessResponse(); } @@ -1648,6 +1679,18 @@ GDBRemoteCommunicationServerLLGS::Handle_vCont_actions( return SendPacketNoLock(response.GetString()); } +static bool ResumeActionListStopsAllThreads(ResumeActionList &actions) { + // We're doing a stop-all if and only if our only action is a "t" for all + // threads. + if (const ResumeAction *default_action = + actions.GetActionForThread(LLDB_INVALID_THREAD_ID, false)) { + if (default_action->state == eStateSuspended && actions.GetSize() == 1) + return true; + } + + return false; +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_vCont( StringExtractorGDBRemote &packet) { @@ -1669,9 +1712,6 @@ GDBRemoteCommunicationServerLLGS::Handle_vCont( // Move past the ';', then do a simple 's'. packet.SetFilePos(packet.GetFilePos() + 1); return Handle_s(packet); - } else if (m_non_stop && ::strcmp(packet.Peek(), ";t") == 0) { - // TODO: add full support for "t" action - return SendOKResponse(); } std::unordered_map<lldb::pid_t, ResumeActionList> thread_actions; @@ -1738,6 +1778,12 @@ GDBRemoteCommunicationServerLLGS::Handle_vCont( tid = pid_tid->second; } + if (thread_action.state == eStateSuspended && + tid != StringExtractorGDBRemote::AllThreads) { + return SendIllFormedResponse( + packet, "'t' action not supported for individual threads"); + } + if (pid == StringExtractorGDBRemote::AllProcesses) { if (m_debugged_processes.size() > 1) return SendIllFormedResponse( @@ -1770,13 +1816,43 @@ GDBRemoteCommunicationServerLLGS::Handle_vCont( return SendErrorResponse(GDBRemoteServerError::eErrorResume); } - Status error = process_it->second->Resume(x.second); - if (error.Fail()) { - LLDB_LOG(log, "vCont failed for process {0}: {1}", x.first, error); - return SendErrorResponse(GDBRemoteServerError::eErrorResume); - } + // There are four possible scenarios here. These are: + // 1. vCont on a stopped process that resumes at least one thread. + // In this case, we call Resume(). + // 2. vCont on a stopped process that leaves all threads suspended. + // A no-op. + // 3. vCont on a running process that requests suspending all + // running threads. In this case, we call Interrupt(). + // 4. vCont on a running process that requests suspending a subset + // of running threads or resuming a subset of suspended threads. + // Since we do not support full nonstop mode, this is unsupported + // and we return an error. - LLDB_LOG(log, "continued process {0}", x.first); + assert(process_it->second.process_up); + if (ResumeActionListStopsAllThreads(x.second)) { + if (process_it->second.process_up->IsRunning()) { + assert(m_non_stop); + + Status error = process_it->second.process_up->Interrupt(); + if (error.Fail()) { + LLDB_LOG(log, "vCont failed to halt process {0}: {1}", x.first, + error); + return SendErrorResponse(GDBRemoteServerError::eErrorResume); + } + + LLDB_LOG(log, "halted process {0}", x.first); + + // hack to avoid enabling stdio forwarding after stop + // TODO: remove this when we improve stdio forwarding for nonstop + assert(thread_actions.size() == 1); + return SendOKResponse(); + } + } else { + PacketResult resume_res = + ResumeProcess(*process_it->second.process_up, x.second); + if (resume_res != PacketResult::Success) + return resume_res; + } } return SendContinueSuccessResponse(); @@ -1815,9 +1891,11 @@ GDBRemoteCommunicationServerLLGS::Handle_stop_reason( // the current thread (for clients that don't actually support multiple // stop reasons). NativeThreadProtocol *thread = m_current_process->GetCurrentThread(); - if (thread) - m_stop_notification_queue.push_back( - PrepareStopReplyPacketForThread(*thread).GetString().str()); + if (thread) { + StreamString stop_reply = PrepareStopReplyPacketForThread(*thread); + if (!stop_reply.Empty()) + m_stop_notification_queue.push_back(stop_reply.GetString().str()); + } EnqueueStopReplyPackets(thread ? thread->GetID() : LLDB_INVALID_THREAD_ID); } @@ -1845,6 +1923,20 @@ GDBRemoteCommunicationServerLLGS::SendStopReasonForState( bool force_synchronous) { Log *log = GetLog(LLDBLog::Process); + if (m_disabling_non_stop) { + // Check if we are waiting for any more processes to stop. If we are, + // do not send the OK response yet. + for (const auto &it : m_debugged_processes) { + if (it.second.process_up->IsRunning()) + return PacketResult::Success; + } + + // If all expected processes were stopped after a QNonStop:0 request, + // send the OK response. + m_disabling_non_stop = false; + return SendOKResponse(); + } + switch (process_state) { case eStateAttaching: case eStateLaunching: @@ -1998,7 +2090,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo( StreamGDBRemote response; for (auto &pid_ptr : m_debugged_processes) - AddProcessThreads(response, *pid_ptr.second, had_any); + AddProcessThreads(response, *pid_ptr.second.process_up, had_any); if (!had_any) return SendOKResponse(); @@ -2284,7 +2376,8 @@ GDBRemoteCommunicationServerLLGS::Handle_H(StringExtractorGDBRemote &packet) { // Ensure we have the given thread when not specifying -1 (all threads) or 0 // (any thread). if (tid != LLDB_INVALID_THREAD_ID && tid != 0) { - NativeThreadProtocol *thread = new_process_it->second->GetThreadByID(tid); + NativeThreadProtocol *thread = + new_process_it->second.process_up->GetThreadByID(tid); if (!thread) { LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s failed, tid %" PRIu64 @@ -2297,12 +2390,12 @@ GDBRemoteCommunicationServerLLGS::Handle_H(StringExtractorGDBRemote &packet) { // Now switch the given process and thread type. switch (h_variant) { case 'g': - m_current_process = new_process_it->second.get(); + m_current_process = new_process_it->second.process_up.get(); SetCurrentThreadID(tid); break; case 'c': - m_continue_process = new_process_it->second.get(); + m_continue_process = new_process_it->second.process_up.get(); SetContinueThreadID(tid); break; @@ -2944,15 +3037,10 @@ GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { // All other threads stop while we're single stepping a thread. actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0); - Status error = m_continue_process->Resume(actions); - if (error.Fail()) { - LLDB_LOGF(log, - "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " tid %" PRIu64 " Resume() failed with error: %s", - __FUNCTION__, m_continue_process->GetID(), tid, - error.AsCString()); - return SendErrorResponse(0x49); - } + + PacketResult resume_res = ResumeProcess(*m_continue_process, actions); + if (resume_res != PacketResult::Success) + return resume_res; // No response here, unless in non-stop mode. // Otherwise, the stop or exit will come from the resulting action. @@ -3440,7 +3528,8 @@ GDBRemoteCommunicationServerLLGS::Handle_vRun( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) { Log *log = GetLog(LLDBLog::Process); - StopSTDIOForwarding(); + if (!m_non_stop) + StopSTDIOForwarding(); lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; @@ -3466,12 +3555,12 @@ GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) { LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s detaching %" PRId64, __FUNCTION__, it->first); - if (llvm::Error e = it->second->Detach().ToError()) + if (llvm::Error e = it->second.process_up->Detach().ToError()) detach_error = llvm::joinErrors(std::move(detach_error), std::move(e)); else { - if (it->second.get() == m_current_process) + if (it->second.process_up.get() == m_current_process) m_current_process = nullptr; - if (it->second.get() == m_continue_process) + if (it->second.process_up.get() == m_continue_process) m_continue_process = nullptr; it = m_debugged_processes.erase(it); detached = true; @@ -3833,13 +3922,38 @@ GDBRemoteCommunicationServerLLGS::Handle_qSaveCore( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_QNonStop( StringExtractorGDBRemote &packet) { + Log *log = GetLog(LLDBLog::Process); + StringRef packet_str{packet.GetStringRef()}; assert(packet_str.startswith("QNonStop:")); packet_str.consume_front("QNonStop:"); if (packet_str == "0") { + if (m_non_stop) + StopSTDIOForwarding(); + for (auto &process_it : m_debugged_processes) { + if (process_it.second.process_up->IsRunning()) { + assert(m_non_stop); + Status error = process_it.second.process_up->Interrupt(); + if (error.Fail()) { + LLDB_LOG(log, + "while disabling nonstop, failed to halt process {0}: {1}", + process_it.first, error); + return SendErrorResponse(0x41); + } + // we must not send stop reasons after QNonStop + m_disabling_non_stop = true; + } + } + m_stdio_notification_queue.clear(); + m_stop_notification_queue.clear(); m_non_stop = false; - // TODO: stop all threads + // If we are stopping anything, defer sending the OK response until we're + // done. + if (m_disabling_non_stop) + return PacketResult::Success; } else if (packet_str == "1") { + if (!m_non_stop) + StartSTDIOForwarding(); m_non_stop = true; } else return SendErrorResponse(Status("Invalid QNonStop packet")); @@ -3847,26 +3961,38 @@ GDBRemoteCommunicationServerLLGS::Handle_QNonStop( } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_vStopped( - StringExtractorGDBRemote &packet) { +GDBRemoteCommunicationServerLLGS::HandleNotificationAck( + std::deque<std::string> &queue) { // Per the protocol, the first message put into the queue is sent - // immediately. However, it remains the queue until the client ACKs - // it via vStopped -- then we pop it and send the next message. - // The process repeats until the last message in the queue is ACK-ed, - // in which case the vStopped packet sends an OK response. - - if (m_stop_notification_queue.empty()) + // immediately. However, it remains the queue until the client ACKs it -- + // then we pop it and send the next message. The process repeats until + // the last message in the queue is ACK-ed, in which case the packet sends + // an OK response. + if (queue.empty()) return SendErrorResponse(Status("No pending notification to ack")); - m_stop_notification_queue.pop_front(); - if (!m_stop_notification_queue.empty()) - return SendPacketNoLock(m_stop_notification_queue.front()); + queue.pop_front(); + if (!queue.empty()) + return SendPacketNoLock(queue.front()); + return SendOKResponse(); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_vStdio( + StringExtractorGDBRemote &packet) { + return HandleNotificationAck(m_stdio_notification_queue); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_vStopped( + StringExtractorGDBRemote &packet) { + PacketResult ret = HandleNotificationAck(m_stop_notification_queue); // If this was the last notification and all the processes exited, // terminate the server. - if (m_debugged_processes.empty()) { + if (m_stop_notification_queue.empty() && m_debugged_processes.empty()) { m_exit_now = true; m_mainloop.RequestTermination(); } - return SendOKResponse(); + return ret; } GDBRemoteCommunication::PacketResult @@ -3907,7 +4033,7 @@ GDBRemoteCommunicationServerLLGS::Handle_T(StringExtractorGDBRemote &packet) { return SendErrorResponse(1); // Check the thread ID - if (!new_process_it->second->GetThreadByID(tid)) + if (!new_process_it->second.process_up->GetThreadByID(tid)) return SendErrorResponse(2); return SendOKResponse(); @@ -4108,7 +4234,7 @@ std::vector<std::string> GDBRemoteCommunicationServerLLGS::HandleFeatures( ret.push_back("vfork-events+"); for (auto &x : m_debugged_processes) - SetEnabledExtensions(*x.second); + SetEnabledExtensions(*x.second.process_up); return ret; } @@ -4121,9 +4247,10 @@ void GDBRemoteCommunicationServerLLGS::SetEnabledExtensions( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::SendContinueSuccessResponse() { - // TODO: how to handle forwarding in non-stop mode? + if (m_non_stop) + return SendOKResponse(); StartSTDIOForwarding(); - return m_non_stop ? SendOKResponse() : PacketResult::Success; + return PacketResult::Success; } void GDBRemoteCommunicationServerLLGS::AppendThreadIDToResponse( diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index 5187a953f957..1165b60ac762 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -85,6 +85,17 @@ public: Status InitializeConnection(std::unique_ptr<Connection> connection); + struct DebuggedProcess { + enum class Flag { + vkilled = (1u << 0), + + LLVM_MARK_AS_BITMASK_ENUM(vkilled) + }; + + std::unique_ptr<NativeProcessProtocol> process_up; + Flag flags; + }; + protected: MainLoop &m_mainloop; MainLoop::ReadHandleUP m_network_handle_up; @@ -94,14 +105,11 @@ protected: NativeProcessProtocol *m_current_process; NativeProcessProtocol *m_continue_process; std::recursive_mutex m_debugged_process_mutex; - std::unordered_map<lldb::pid_t, std::unique_ptr<NativeProcessProtocol>> - m_debugged_processes; - std::unordered_set<lldb::pid_t> m_vkilled_processes; + std::unordered_map<lldb::pid_t, DebuggedProcess> m_debugged_processes; Communication m_stdio_communication; MainLoop::ReadHandleUP m_stdio_handle_up; - lldb::StateType m_inferior_prev_state = lldb::StateType::eStateInvalid; llvm::StringMap<std::unique_ptr<llvm::MemoryBuffer>> m_xfer_buffer_map; std::mutex m_saved_registers_mutex; std::unordered_map<uint32_t, lldb::DataBufferSP> m_saved_registers_map; @@ -109,6 +117,8 @@ protected: bool m_thread_suffix_supported = false; bool m_list_threads_in_stop_reply = false; bool m_non_stop = false; + bool m_disabling_non_stop = false; + std::deque<std::string> m_stdio_notification_queue; std::deque<std::string> m_stop_notification_queue; NativeProcessProtocol::Extension m_extensions_supported = {}; @@ -147,6 +157,9 @@ protected: PacketResult Handle_QListThreadsInStopReply(StringExtractorGDBRemote &packet); + PacketResult ResumeProcess(NativeProcessProtocol &process, + const ResumeActionList &actions); + PacketResult Handle_C(StringExtractorGDBRemote &packet); PacketResult Handle_c(StringExtractorGDBRemote &packet); @@ -236,6 +249,10 @@ protected: PacketResult Handle_QNonStop(StringExtractorGDBRemote &packet); + PacketResult HandleNotificationAck(std::deque<std::string> &queue); + + PacketResult Handle_vStdio(StringExtractorGDBRemote &packet); + PacketResult Handle_vStopped(StringExtractorGDBRemote &packet); PacketResult Handle_vCtrlC(StringExtractorGDBRemote &packet); diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index fe6a3f9ed6c1..5f18706f67e5 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -5307,8 +5307,11 @@ void ProcessGDBRemote::DidFork(lldb::pid_t child_pid, lldb::tid_t child_tid) { // Hardware breakpoints/watchpoints are not inherited implicitly, // so we need to readd them if we're following child. - if (GetFollowForkMode() == eFollowChild) + if (GetFollowForkMode() == eFollowChild) { DidForkSwitchHardwareTraps(true); + // Update our PID + SetID(child_pid); + } } void ProcessGDBRemote::DidVFork(lldb::pid_t child_pid, lldb::tid_t child_tid) { @@ -5361,6 +5364,11 @@ void ProcessGDBRemote::DidVFork(lldb::pid_t child_pid, lldb::tid_t child_tid) { error.AsCString() ? error.AsCString() : "<unknown error>"); return; } + + if (GetFollowForkMode() == eFollowChild) { + // Update our PID + SetID(child_pid); + } } void ProcessGDBRemote::DidVForkDone() { diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 53e2bcaccafb..a21adcfbdbd6 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -2637,7 +2637,7 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule( .SetSetLLDBGlobals(false); if (!pathname || !pathname[0]) { - error.SetErrorString("invalid pathname"); + error.SetErrorString("empty path"); return false; } @@ -2707,14 +2707,14 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule( // if not a valid file of any sort, check if it might be a filename still // dot can't be used but / and \ can, and if either is found, reject if (strchr(pathname, '\\') || strchr(pathname, '/')) { - error.SetErrorString("invalid pathname"); + error.SetErrorStringWithFormatv("invalid pathname '{0}'", pathname); return false; } // Not a filename, probably a package of some sort, let it go through. possible_package = true; } else if (is_directory(st) || is_regular_file(st)) { if (module_file.GetDirectory().IsEmpty()) { - error.SetErrorString("invalid directory name"); + error.SetErrorStringWithFormatv("invalid directory name '{0}'", pathname); return false; } if (llvm::Error e = diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 4b9354371bda..10dc8d1fb7c3 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -2390,6 +2390,7 @@ struct MemberAttributes { uint64_t data_bit_offset = UINT64_MAX; AccessType accessibility = eAccessNone; llvm::Optional<uint64_t> byte_size; + llvm::Optional<DWARFFormValue> const_value_form; DWARFFormValue encoding_form; /// Indicates the byte offset of the word from the base address of the /// structure. @@ -2436,6 +2437,9 @@ MemberAttributes::MemberAttributes(const DWARFDIE &die, case DW_AT_byte_size: byte_size = form_value.Unsigned(); break; + case DW_AT_const_value: + const_value_form = form_value; + break; case DW_AT_data_bit_offset: data_bit_offset = form_value.Unsigned(); break; @@ -2587,12 +2591,65 @@ void DWARFASTParserClang::ParseObjCProperty( propAttrs.prop_getter_name, propAttrs.prop_attributes, &metadata)); } +llvm::Expected<llvm::APInt> DWARFASTParserClang::ExtractIntFromFormValue( + const CompilerType &int_type, const DWARFFormValue &form_value) const { + clang::QualType qt = ClangUtil::GetQualType(int_type); + assert(qt->isIntegralOrEnumerationType()); + TypeSystemClang &ts = *llvm::cast<TypeSystemClang>(int_type.GetTypeSystem()); + clang::ASTContext &ast = ts.getASTContext(); + + const unsigned type_bits = ast.getIntWidth(qt); + const bool is_unsigned = qt->isUnsignedIntegerType(); + + // The maximum int size supported at the moment by this function. Limited + // by the uint64_t return type of DWARFFormValue::Signed/Unsigned. + constexpr std::size_t max_bit_size = 64; + + // For values bigger than 64 bit (e.g. __int128_t values), + // DWARFFormValue's Signed/Unsigned functions will return wrong results so + // emit an error for now. + if (type_bits > max_bit_size) { + auto msg = llvm::formatv("Can only parse integers with up to {0} bits, but " + "given integer has {1} bits.", + max_bit_size, type_bits); + return llvm::createStringError(llvm::inconvertibleErrorCode(), msg.str()); + } + + // Construct an APInt with the maximum bit size and the given integer. + llvm::APInt result(max_bit_size, form_value.Unsigned(), !is_unsigned); + + // Calculate how many bits are required to represent the input value. + // For unsigned types, take the number of active bits in the APInt. + // For signed types, ask APInt how many bits are required to represent the + // signed integer. + const unsigned required_bits = + is_unsigned ? result.getActiveBits() : result.getMinSignedBits(); + + // If the input value doesn't fit into the integer type, return an error. + if (required_bits > type_bits) { + std::string value_as_str = is_unsigned + ? std::to_string(form_value.Unsigned()) + : std::to_string(form_value.Signed()); + auto msg = llvm::formatv("Can't store {0} value {1} in integer with {2} " + "bits.", + (is_unsigned ? "unsigned" : "signed"), + value_as_str, type_bits); + return llvm::createStringError(llvm::inconvertibleErrorCode(), msg.str()); + } + + // Trim the result to the bit width our the int type. + if (result.getBitWidth() > type_bits) + result = result.trunc(type_bits); + return result; +} + void DWARFASTParserClang::ParseSingleMember( const DWARFDIE &die, const DWARFDIE &parent_die, const lldb_private::CompilerType &class_clang_type, lldb::AccessType default_accessibility, lldb_private::ClangASTImporter::LayoutInfo &layout_info, FieldInfo &last_field_info) { + Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups); // This function can only parse DW_TAG_member. assert(die.Tag() == DW_TAG_member); @@ -2623,9 +2680,27 @@ void DWARFASTParserClang::ParseSingleMember( if (var_type) { if (attrs.accessibility == eAccessNone) attrs.accessibility = eAccessPublic; - TypeSystemClang::AddVariableToRecordType( - class_clang_type, attrs.name, var_type->GetForwardCompilerType(), - attrs.accessibility); + CompilerType ct = var_type->GetForwardCompilerType(); + clang::VarDecl *v = TypeSystemClang::AddVariableToRecordType( + class_clang_type, attrs.name, ct, attrs.accessibility); + if (!v) { + LLDB_LOG(log, "Failed to add variable to the record type"); + return; + } + + bool unused; + // TODO: Support float/double static members as well. + if (!attrs.const_value_form || !ct.IsIntegerOrEnumerationType(unused)) + return; + llvm::Expected<llvm::APInt> const_value_or_err = + ExtractIntFromFormValue(ct, *attrs.const_value_form); + if (!const_value_or_err) { + LLDB_LOG_ERROR(log, const_value_or_err.takeError(), + "Failed to add const value to variable {1}: {0}", + v->getQualifiedNameAsString()); + return; + } + TypeSystemClang::SetIntegerInitializerForVariable(v, *const_value_or_err); } return; } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h index f97c0c470ab0..733ffa230f1e 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -68,6 +68,22 @@ public: lldb_private::ClangASTImporter &GetClangASTImporter(); + /// Extracts an value for a given Clang integer type from a DWARFFormValue. + /// + /// \param int_type The Clang type that defines the bit size and signedness + /// of the integer that should be extracted. Has to be either + /// an integer type or an enum type. For enum types the + /// underlying integer type will be considered as the + /// expected integer type that should be extracted. + /// \param form_value The DWARFFormValue that contains the integer value. + /// \return An APInt containing the same integer value as the given + /// DWARFFormValue with the bit width of the given integer type. + /// Returns an error if the value in the DWARFFormValue does not fit + /// into the given integer type or the integer type isn't supported. + llvm::Expected<llvm::APInt> + ExtractIntFromFormValue(const lldb_private::CompilerType &int_type, + const DWARFFormValue &form_value) const; + protected: /// Protected typedefs and members. /// @{ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index cbc24b1550c7..8ee709db9cdb 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -3475,10 +3475,9 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, if (use_type_size_for_value && type_sp->GetType()) { DWARFExpression *location = location_list.GetMutableExpressionAtAddress(); - location->UpdateValue( - const_value_form.Unsigned(), - type_sp->GetType()->GetByteSize(nullptr).getValueOr(0), - die.GetCU()->GetAddressByteSize()); + location->UpdateValue(const_value_form.Unsigned(), + type_sp->GetType()->GetByteSize(nullptr).value_or(0), + die.GetCU()->GetAddressByteSize()); } return std::make_shared<Variable>( diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp index 6dcce738b79f..25425f914088 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -816,6 +816,40 @@ clang::QualType PdbAstBuilder::CreatePointerType(const PointerRecord &pointer) { clang::QualType class_type = GetOrCreateType(mpi.ContainingType); if (class_type.isNull()) return {}; + if (clang::TagDecl *tag = class_type->getAsTagDecl()) { + clang::MSInheritanceAttr::Spelling spelling; + switch (mpi.Representation) { + case llvm::codeview::PointerToMemberRepresentation::SingleInheritanceData: + case llvm::codeview::PointerToMemberRepresentation:: + SingleInheritanceFunction: + spelling = + clang::MSInheritanceAttr::Spelling::Keyword_single_inheritance; + break; + case llvm::codeview::PointerToMemberRepresentation:: + MultipleInheritanceData: + case llvm::codeview::PointerToMemberRepresentation:: + MultipleInheritanceFunction: + spelling = + clang::MSInheritanceAttr::Spelling::Keyword_multiple_inheritance; + break; + case llvm::codeview::PointerToMemberRepresentation:: + VirtualInheritanceData: + case llvm::codeview::PointerToMemberRepresentation:: + VirtualInheritanceFunction: + spelling = + clang::MSInheritanceAttr::Spelling::Keyword_virtual_inheritance; + break; + case llvm::codeview::PointerToMemberRepresentation::Unknown: + spelling = + clang::MSInheritanceAttr::Spelling::Keyword_unspecified_inheritance; + break; + default: + spelling = clang::MSInheritanceAttr::Spelling::SpellingNotCalculated; + break; + } + tag->addAttr(clang::MSInheritanceAttr::CreateImplicit( + m_clang.getASTContext(), spelling)); + } return m_clang.getASTContext().getMemberPointerType( pointee_type, class_type.getTypePtr()); } diff --git a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp index 91eafdaa11bc..dd28292c1daf 100644 --- a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp +++ b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp @@ -11,6 +11,7 @@ #include "TraceIntelPT.h" #include "TraceIntelPTConstants.h" #include "lldb/Host/OptionParser.h" +#include "lldb/Interpreter/CommandOptionArgumentTable.h" #include "lldb/Target/Process.h" #include "lldb/Target/Trace.h" diff --git a/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.cpp b/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.cpp index 194cc7459027..384abd2166df 100644 --- a/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.cpp +++ b/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.cpp @@ -10,6 +10,7 @@ #include "../common/TraceHTR.h" #include "lldb/Host/OptionParser.h" +#include "lldb/Interpreter/CommandOptionArgumentTable.h" #include "lldb/Target/Process.h" #include "lldb/Target/Trace.h" diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index e0f646b15641..c6eb693bba6b 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -7538,7 +7538,7 @@ void TypeSystemClang::SetIntegerInitializerForVariable( "only integer or enum types supported"); // If the variable is an enum type, take the underlying integer type as // the type of the integer literal. - if (const EnumType *enum_type = llvm::dyn_cast<EnumType>(qt.getTypePtr())) { + if (const EnumType *enum_type = qt->getAs<EnumType>()) { const EnumDecl *enum_decl = enum_type->getDecl(); qt = enum_decl->getIntegerType(); } diff --git a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h index 97cb04e51408..796e7e50a8b9 100644 --- a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h +++ b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h @@ -64,8 +64,8 @@ private: lldb_private::EmulateInstruction *inst_emulator) : UnwindAssembly(arch), m_inst_emulator_up(inst_emulator), m_range_ptr(nullptr), m_unwind_plan_ptr(nullptr), m_curr_row(), - m_cfa_reg_info(), m_fp_is_cfa(false), m_register_values(), - m_pushed_regs(), m_curr_row_modified(false), + m_initial_sp(0), m_cfa_reg_info(), m_fp_is_cfa(false), + m_register_values(), m_pushed_regs(), m_curr_row_modified(false), m_forward_branch_offset(0) { if (m_inst_emulator_up.get()) { m_inst_emulator_up->SetBaton(this); diff --git a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp index 36e7b90cad24..92eec139e07c 100644 --- a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp +++ b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp @@ -24,11 +24,12 @@ x86AssemblyInspectionEngine::x86AssemblyInspectionEngine(const ArchSpec &arch) : m_cur_insn(nullptr), m_machine_ip_regnum(LLDB_INVALID_REGNUM), m_machine_sp_regnum(LLDB_INVALID_REGNUM), m_machine_fp_regnum(LLDB_INVALID_REGNUM), + m_machine_alt_fp_regnum(LLDB_INVALID_REGNUM), m_lldb_ip_regnum(LLDB_INVALID_REGNUM), m_lldb_sp_regnum(LLDB_INVALID_REGNUM), m_lldb_fp_regnum(LLDB_INVALID_REGNUM), - - m_reg_map(), m_arch(arch), m_cpu(k_cpu_unspecified), m_wordsize(-1), + m_lldb_alt_fp_regnum(LLDB_INVALID_REGNUM), m_reg_map(), m_arch(arch), + m_cpu(k_cpu_unspecified), m_wordsize(-1), m_register_map_initialized(false), m_disasm_context() { m_disasm_context = ::LLVMCreateDisasm(arch.GetTriple().getTriple().c_str(), nullptr, |
