diff options
author | Robert Nagy <robert@cvs.openbsd.org> | 2023-11-11 18:23:04 +0000 |
---|---|---|
committer | Robert Nagy <robert@cvs.openbsd.org> | 2023-11-11 18:23:04 +0000 |
commit | 2221bb63de5e226014553581f31eebd6138e896f (patch) | |
tree | c6e3a666dc3dd8d47518d97a8f6dd990afad2575 /gnu/llvm/lldb/source/Target | |
parent | 950826e4c0ae36922e713115fb137064590c6baa (diff) |
import lldb from LLVM-16.0.6
Diffstat (limited to 'gnu/llvm/lldb/source/Target')
54 files changed, 5217 insertions, 1884 deletions
diff --git a/gnu/llvm/lldb/source/Target/ABI.cpp b/gnu/llvm/lldb/source/Target/ABI.cpp index c3342caf874..86bf0118027 100644 --- a/gnu/llvm/lldb/source/Target/ABI.cpp +++ b/gnu/llvm/lldb/source/Target/ABI.cpp @@ -15,8 +15,9 @@ #include "lldb/Symbol/TypeSystem.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" -#include "llvm/Support/TargetRegistry.h" +#include "llvm/MC/TargetRegistry.h" #include <cctype> using namespace lldb; @@ -203,7 +204,7 @@ std::unique_ptr<llvm::MCRegisterInfo> ABI::MakeMCRegisterInfo(const ArchSpec &ar const llvm::Target *target = llvm::TargetRegistry::lookupTarget(triple, lookup_error); if (!target) { - LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS), + LLDB_LOG(GetLog(LLDBLog::Process), "Failed to create an llvm target for {0}: {1}", triple, lookup_error); return nullptr; @@ -214,33 +215,39 @@ std::unique_ptr<llvm::MCRegisterInfo> ABI::MakeMCRegisterInfo(const ArchSpec &ar return info_up; } -void RegInfoBasedABI::AugmentRegisterInfo(RegisterInfo &info) { - if (info.kinds[eRegisterKindEHFrame] != LLDB_INVALID_REGNUM && - info.kinds[eRegisterKindDWARF] != LLDB_INVALID_REGNUM) - return; - - RegisterInfo abi_info; - if (!GetRegisterInfoByName(info.name, abi_info)) - return; - - if (info.kinds[eRegisterKindEHFrame] == LLDB_INVALID_REGNUM) - info.kinds[eRegisterKindEHFrame] = abi_info.kinds[eRegisterKindEHFrame]; - if (info.kinds[eRegisterKindDWARF] == LLDB_INVALID_REGNUM) - info.kinds[eRegisterKindDWARF] = abi_info.kinds[eRegisterKindDWARF]; - if (info.kinds[eRegisterKindGeneric] == LLDB_INVALID_REGNUM) - info.kinds[eRegisterKindGeneric] = abi_info.kinds[eRegisterKindGeneric]; +void RegInfoBasedABI::AugmentRegisterInfo( + std::vector<DynamicRegisterInfo::Register> ®s) { + for (DynamicRegisterInfo::Register &info : regs) { + if (info.regnum_ehframe != LLDB_INVALID_REGNUM && + info.regnum_dwarf != LLDB_INVALID_REGNUM) + continue; + + RegisterInfo abi_info; + if (!GetRegisterInfoByName(info.name.GetStringRef(), abi_info)) + continue; + + if (info.regnum_ehframe == LLDB_INVALID_REGNUM) + info.regnum_ehframe = abi_info.kinds[eRegisterKindEHFrame]; + if (info.regnum_dwarf == LLDB_INVALID_REGNUM) + info.regnum_dwarf = abi_info.kinds[eRegisterKindDWARF]; + if (info.regnum_generic == LLDB_INVALID_REGNUM) + info.regnum_generic = abi_info.kinds[eRegisterKindGeneric]; + } } -void MCBasedABI::AugmentRegisterInfo(RegisterInfo &info) { - uint32_t eh, dwarf; - std::tie(eh, dwarf) = GetEHAndDWARFNums(info.name); - - if (info.kinds[eRegisterKindEHFrame] == LLDB_INVALID_REGNUM) - info.kinds[eRegisterKindEHFrame] = eh; - if (info.kinds[eRegisterKindDWARF] == LLDB_INVALID_REGNUM) - info.kinds[eRegisterKindDWARF] = dwarf; - if (info.kinds[eRegisterKindGeneric] == LLDB_INVALID_REGNUM) - info.kinds[eRegisterKindGeneric] = GetGenericNum(info.name); +void MCBasedABI::AugmentRegisterInfo( + std::vector<DynamicRegisterInfo::Register> ®s) { + for (DynamicRegisterInfo::Register &info : regs) { + uint32_t eh, dwarf; + std::tie(eh, dwarf) = GetEHAndDWARFNums(info.name.GetStringRef()); + + if (info.regnum_ehframe == LLDB_INVALID_REGNUM) + info.regnum_ehframe = eh; + if (info.regnum_dwarf == LLDB_INVALID_REGNUM) + info.regnum_dwarf = dwarf; + if (info.regnum_generic == LLDB_INVALID_REGNUM) + info.regnum_generic = GetGenericNum(info.name.GetStringRef()); + } } std::pair<uint32_t, uint32_t> diff --git a/gnu/llvm/lldb/source/Target/AssertFrameRecognizer.cpp b/gnu/llvm/lldb/source/Target/AssertFrameRecognizer.cpp index a2315b6d63c..5f4682bd5c1 100644 --- a/gnu/llvm/lldb/source/Target/AssertFrameRecognizer.cpp +++ b/gnu/llvm/lldb/source/Target/AssertFrameRecognizer.cpp @@ -1,3 +1,4 @@ +#include "lldb/Target/AssertFrameRecognizer.h" #include "lldb/Core/Module.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/SymbolContext.h" @@ -5,11 +6,7 @@ #include "lldb/Target/StackFrameList.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" - -#include "lldb/Utility/Log.h" -#include "lldb/Utility/Logging.h" - -#include "lldb/Target/AssertFrameRecognizer.h" +#include "lldb/Utility/LLDBLog.h" using namespace llvm; using namespace lldb; @@ -53,7 +50,7 @@ bool GetAbortLocation(llvm::Triple::OSType os, SymbolLocation &location) { location.symbols_are_regex = true; break; default: - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); + Log *log = GetLog(LLDBLog::Unwind); LLDB_LOG(log, "AssertFrameRecognizer::GetAbortLocation Unsupported OS"); return false; } @@ -83,7 +80,7 @@ bool GetAssertLocation(llvm::Triple::OSType os, SymbolLocation &location) { location.symbols.push_back(ConstString("__GI___assert_fail")); break; default: - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); + Log *log = GetLog(LLDBLog::Unwind); LLDB_LOG(log, "AssertFrameRecognizer::GetAssertLocation Unsupported OS"); return false; } @@ -151,7 +148,7 @@ AssertFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) { prev_frame_sp = thread_sp->GetStackFrameAtIndex(frame_index); if (!prev_frame_sp) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); + Log *log = GetLog(LLDBLog::Unwind); LLDB_LOG(log, "Abort Recognizer: Hit unwinding bound ({1} frames)!", frames_to_fetch); break; diff --git a/gnu/llvm/lldb/source/Target/CMakeLists.txt b/gnu/llvm/lldb/source/Target/CMakeLists.txt index 2405258bc41..c75a10cf61c 100644 --- a/gnu/llvm/lldb/source/Target/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Target/CMakeLists.txt @@ -9,6 +9,7 @@ lldb_tablegen(TargetPropertiesEnum.inc -gen-lldb-property-enum-defs add_lldb_library(lldbTarget ABI.cpp AssertFrameRecognizer.cpp + DynamicRegisterInfo.cpp ExecutionContext.cpp InstrumentationRuntime.cpp InstrumentationRuntimeStopInfo.cpp @@ -19,6 +20,7 @@ add_lldb_library(lldbTarget Memory.cpp MemoryHistory.cpp MemoryRegionInfo.cpp + MemoryTagMap.cpp ModuleCache.cpp OperatingSystem.cpp PathMappingList.cpp @@ -38,6 +40,7 @@ add_lldb_library(lldbTarget StackFrameList.cpp StackFrameRecognizer.cpp StackID.cpp + Statistics.cpp StopInfo.cpp StructuredDataPlugin.cpp SystemRuntime.cpp @@ -69,7 +72,7 @@ add_lldb_library(lldbTarget Trace.cpp TraceCursor.cpp TraceExporter.cpp - TraceInstructionDumper.cpp + TraceDumper.cpp UnixSignals.cpp UnwindAssembly.cpp UnwindLLDB.cpp diff --git a/gnu/llvm/lldb/source/Target/DynamicRegisterInfo.cpp b/gnu/llvm/lldb/source/Target/DynamicRegisterInfo.cpp new file mode 100644 index 00000000000..14c3faae38d --- /dev/null +++ b/gnu/llvm/lldb/source/Target/DynamicRegisterInfo.cpp @@ -0,0 +1,820 @@ +//===-- DynamicRegisterInfo.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/DynamicRegisterInfo.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/DataFormatters/FormatManager.h" +#include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RegularExpression.h" +#include "lldb/Utility/StringExtractor.h" +#include "lldb/Utility/StructuredData.h" + +using namespace lldb; +using namespace lldb_private; + +DynamicRegisterInfo::DynamicRegisterInfo( + const lldb_private::StructuredData::Dictionary &dict, + const lldb_private::ArchSpec &arch) { + SetRegisterInfo(dict, arch); +} + +DynamicRegisterInfo::DynamicRegisterInfo(DynamicRegisterInfo &&info) { + MoveFrom(std::move(info)); +} + +DynamicRegisterInfo & +DynamicRegisterInfo::operator=(DynamicRegisterInfo &&info) { + MoveFrom(std::move(info)); + return *this; +} + +void DynamicRegisterInfo::MoveFrom(DynamicRegisterInfo &&info) { + m_regs = std::move(info.m_regs); + m_sets = std::move(info.m_sets); + m_set_reg_nums = std::move(info.m_set_reg_nums); + m_set_names = std::move(info.m_set_names); + m_value_regs_map = std::move(info.m_value_regs_map); + m_invalidate_regs_map = std::move(info.m_invalidate_regs_map); + + m_reg_data_byte_size = info.m_reg_data_byte_size; + m_finalized = info.m_finalized; + + if (m_finalized) { + const size_t num_sets = m_sets.size(); + for (size_t set = 0; set < num_sets; ++set) + m_sets[set].registers = m_set_reg_nums[set].data(); + } + + info.Clear(); +} + +llvm::Expected<uint32_t> DynamicRegisterInfo::ByteOffsetFromSlice( + uint32_t index, llvm::StringRef slice_str, lldb::ByteOrder byte_order) { + // Slices use the following format: + // REGNAME[MSBIT:LSBIT] + // REGNAME - name of the register to grab a slice of + // MSBIT - the most significant bit at which the current register value + // starts at + // LSBIT - the least significant bit at which the current register value + // ends at + static llvm::Regex g_bitfield_regex( + "([A-Za-z_][A-Za-z0-9_]*)\\[([0-9]+):([0-9]+)\\]"); + llvm::SmallVector<llvm::StringRef, 4> matches; + if (!g_bitfield_regex.match(slice_str, &matches)) + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "failed to match against register bitfield regex (slice: %s)", + slice_str.str().c_str()); + + llvm::StringRef reg_name_str = matches[1]; + llvm::StringRef msbit_str = matches[2]; + llvm::StringRef lsbit_str = matches[3]; + uint32_t msbit; + uint32_t lsbit; + if (!llvm::to_integer(msbit_str, msbit) || + !llvm::to_integer(lsbit_str, lsbit)) + return llvm::createStringError( + llvm::inconvertibleErrorCode(), "msbit (%s) or lsbit (%s) are invalid", + msbit_str.str().c_str(), lsbit_str.str().c_str()); + + if (msbit <= lsbit) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "msbit (%u) must be greater than lsbit (%u)", + msbit, lsbit); + + const uint32_t msbyte = msbit / 8; + const uint32_t lsbyte = lsbit / 8; + + const RegisterInfo *containing_reg_info = GetRegisterInfo(reg_name_str); + if (!containing_reg_info) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "invalid concrete register \"%s\"", + reg_name_str.str().c_str()); + + const uint32_t max_bit = containing_reg_info->byte_size * 8; + + if (msbit > max_bit) + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "msbit (%u) must be less than the bitsize of the register \"%s\" (%u)", + msbit, reg_name_str.str().c_str(), max_bit); + if (lsbit > max_bit) + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "lsbit (%u) must be less than the bitsize of the register \"%s\" (%u)", + lsbit, reg_name_str.str().c_str(), max_bit); + + m_invalidate_regs_map[containing_reg_info->kinds[eRegisterKindLLDB]] + .push_back(index); + m_value_regs_map[index].push_back( + containing_reg_info->kinds[eRegisterKindLLDB]); + m_invalidate_regs_map[index].push_back( + containing_reg_info->kinds[eRegisterKindLLDB]); + + if (byte_order == eByteOrderLittle) + return containing_reg_info->byte_offset + lsbyte; + if (byte_order == eByteOrderBig) + return containing_reg_info->byte_offset + msbyte; + llvm_unreachable("Invalid byte order"); +} + +llvm::Expected<uint32_t> DynamicRegisterInfo::ByteOffsetFromComposite( + uint32_t index, StructuredData::Array &composite_reg_list, + lldb::ByteOrder byte_order) { + const size_t num_composite_regs = composite_reg_list.GetSize(); + if (num_composite_regs == 0) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "\"composite\" list is empty"); + + uint32_t composite_offset = UINT32_MAX; + for (uint32_t composite_idx = 0; composite_idx < num_composite_regs; + ++composite_idx) { + ConstString composite_reg_name; + if (!composite_reg_list.GetItemAtIndexAsString(composite_idx, + composite_reg_name, nullptr)) + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "\"composite\" list value is not a Python string at index %d", + composite_idx); + + const RegisterInfo *composite_reg_info = + GetRegisterInfo(composite_reg_name.GetStringRef()); + if (!composite_reg_info) + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "failed to find composite register by name: \"%s\"", + composite_reg_name.GetCString()); + + composite_offset = + std::min(composite_offset, composite_reg_info->byte_offset); + m_value_regs_map[index].push_back( + composite_reg_info->kinds[eRegisterKindLLDB]); + m_invalidate_regs_map[composite_reg_info->kinds[eRegisterKindLLDB]] + .push_back(index); + m_invalidate_regs_map[index].push_back( + composite_reg_info->kinds[eRegisterKindLLDB]); + } + + return composite_offset; +} + +llvm::Expected<uint32_t> DynamicRegisterInfo::ByteOffsetFromRegInfoDict( + uint32_t index, StructuredData::Dictionary ®_info_dict, + lldb::ByteOrder byte_order) { + uint32_t byte_offset; + if (reg_info_dict.GetValueForKeyAsInteger("offset", byte_offset)) + return byte_offset; + + // No offset for this register, see if the register has a value + // expression which indicates this register is part of another register. + // Value expressions are things like "rax[31:0]" which state that the + // current register's value is in a concrete register "rax" in bits 31:0. + // If there is a value expression we can calculate the offset + llvm::StringRef slice_str; + if (reg_info_dict.GetValueForKeyAsString("slice", slice_str, nullptr)) + return ByteOffsetFromSlice(index, slice_str, byte_order); + + StructuredData::Array *composite_reg_list; + if (reg_info_dict.GetValueForKeyAsArray("composite", composite_reg_list)) + return ByteOffsetFromComposite(index, *composite_reg_list, byte_order); + + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "insufficient data to calculate byte offset"); +} + +size_t +DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, + const ArchSpec &arch) { + Log *log = GetLog(LLDBLog::Object); + assert(!m_finalized); + StructuredData::Array *sets = nullptr; + if (dict.GetValueForKeyAsArray("sets", sets)) { + const uint32_t num_sets = sets->GetSize(); + for (uint32_t i = 0; i < num_sets; ++i) { + ConstString set_name; + if (sets->GetItemAtIndexAsString(i, set_name) && !set_name.IsEmpty()) { + m_sets.push_back({set_name.AsCString(), nullptr, 0, nullptr}); + } else { + Clear(); + printf("error: register sets must have valid names\n"); + return 0; + } + } + m_set_reg_nums.resize(m_sets.size()); + } + + StructuredData::Array *regs = nullptr; + if (!dict.GetValueForKeyAsArray("registers", regs)) + return 0; + + const ByteOrder byte_order = arch.GetByteOrder(); + + const uint32_t num_regs = regs->GetSize(); + // typedef std::map<std::string, std::vector<std::string> > + // InvalidateNameMap; + // InvalidateNameMap invalidate_map; + for (uint32_t i = 0; i < num_regs; ++i) { + StructuredData::Dictionary *reg_info_dict = nullptr; + if (!regs->GetItemAtIndexAsDictionary(i, reg_info_dict)) { + Clear(); + printf("error: items in the 'registers' array must be dictionaries\n"); + regs->DumpToStdout(); + return 0; + } + + // { 'name':'rcx' , 'bitsize' : 64, 'offset' : 16, + // 'encoding':'uint' , 'format':'hex' , 'set': 0, 'ehframe' : 2, + // 'dwarf' : 2, 'generic':'arg4', 'alt-name':'arg4', }, + RegisterInfo reg_info; + std::vector<uint32_t> value_regs; + std::vector<uint32_t> invalidate_regs; + memset(®_info, 0, sizeof(reg_info)); + + ConstString name_val; + ConstString alt_name_val; + if (!reg_info_dict->GetValueForKeyAsString("name", name_val, nullptr)) { + Clear(); + printf("error: registers must have valid names and offsets\n"); + reg_info_dict->DumpToStdout(); + return 0; + } + reg_info.name = name_val.GetCString(); + reg_info_dict->GetValueForKeyAsString("alt-name", alt_name_val, nullptr); + reg_info.alt_name = alt_name_val.GetCString(); + + llvm::Expected<uint32_t> byte_offset = + ByteOffsetFromRegInfoDict(i, *reg_info_dict, byte_order); + if (byte_offset) + reg_info.byte_offset = byte_offset.get(); + else { + LLDB_LOG_ERROR(log, byte_offset.takeError(), + "error while parsing register {1}: {0}", reg_info.name); + Clear(); + reg_info_dict->DumpToStdout(); + return 0; + } + + int64_t bitsize = 0; + if (!reg_info_dict->GetValueForKeyAsInteger("bitsize", bitsize)) { + Clear(); + printf("error: invalid or missing 'bitsize' key/value pair in register " + "dictionary\n"); + reg_info_dict->DumpToStdout(); + return 0; + } + + reg_info.byte_size = bitsize / 8; + + llvm::StringRef format_str; + if (reg_info_dict->GetValueForKeyAsString("format", format_str, nullptr)) { + if (OptionArgParser::ToFormat(format_str.str().c_str(), reg_info.format, + nullptr) + .Fail()) { + Clear(); + printf("error: invalid 'format' value in register dictionary\n"); + reg_info_dict->DumpToStdout(); + return 0; + } + } else { + reg_info_dict->GetValueForKeyAsInteger("format", reg_info.format, + eFormatHex); + } + + llvm::StringRef encoding_str; + if (reg_info_dict->GetValueForKeyAsString("encoding", encoding_str)) + reg_info.encoding = Args::StringToEncoding(encoding_str, eEncodingUint); + else + reg_info_dict->GetValueForKeyAsInteger("encoding", reg_info.encoding, + eEncodingUint); + + size_t set = 0; + if (!reg_info_dict->GetValueForKeyAsInteger<size_t>("set", set, -1) || + set >= m_sets.size()) { + Clear(); + printf("error: invalid 'set' value in register dictionary, valid values " + "are 0 - %i\n", + (int)set); + reg_info_dict->DumpToStdout(); + return 0; + } + + // Fill in the register numbers + reg_info.kinds[lldb::eRegisterKindLLDB] = i; + reg_info.kinds[lldb::eRegisterKindProcessPlugin] = i; + uint32_t eh_frame_regno = LLDB_INVALID_REGNUM; + reg_info_dict->GetValueForKeyAsInteger("gcc", eh_frame_regno, + LLDB_INVALID_REGNUM); + if (eh_frame_regno == LLDB_INVALID_REGNUM) + reg_info_dict->GetValueForKeyAsInteger("ehframe", eh_frame_regno, + LLDB_INVALID_REGNUM); + reg_info.kinds[lldb::eRegisterKindEHFrame] = eh_frame_regno; + reg_info_dict->GetValueForKeyAsInteger( + "dwarf", reg_info.kinds[lldb::eRegisterKindDWARF], LLDB_INVALID_REGNUM); + llvm::StringRef generic_str; + if (reg_info_dict->GetValueForKeyAsString("generic", generic_str)) + reg_info.kinds[lldb::eRegisterKindGeneric] = + Args::StringToGenericRegister(generic_str); + else + reg_info_dict->GetValueForKeyAsInteger( + "generic", reg_info.kinds[lldb::eRegisterKindGeneric], + LLDB_INVALID_REGNUM); + + // Check if this register invalidates any other register values when it is + // modified + StructuredData::Array *invalidate_reg_list = nullptr; + if (reg_info_dict->GetValueForKeyAsArray("invalidate-regs", + invalidate_reg_list)) { + const size_t num_regs = invalidate_reg_list->GetSize(); + if (num_regs > 0) { + for (uint32_t idx = 0; idx < num_regs; ++idx) { + ConstString invalidate_reg_name; + uint64_t invalidate_reg_num; + if (invalidate_reg_list->GetItemAtIndexAsString( + idx, invalidate_reg_name)) { + const RegisterInfo *invalidate_reg_info = + GetRegisterInfo(invalidate_reg_name.GetStringRef()); + if (invalidate_reg_info) { + m_invalidate_regs_map[i].push_back( + invalidate_reg_info->kinds[eRegisterKindLLDB]); + } else { + // TODO: print error invalid slice string that doesn't follow the + // format + printf("error: failed to find a 'invalidate-regs' register for " + "\"%s\" while parsing register \"%s\"\n", + invalidate_reg_name.GetCString(), reg_info.name); + } + } else if (invalidate_reg_list->GetItemAtIndexAsInteger( + idx, invalidate_reg_num)) { + if (invalidate_reg_num != UINT64_MAX) + m_invalidate_regs_map[i].push_back(invalidate_reg_num); + else + printf("error: 'invalidate-regs' list value wasn't a valid " + "integer\n"); + } else { + printf("error: 'invalidate-regs' list value wasn't a python string " + "or integer\n"); + } + } + } else { + printf("error: 'invalidate-regs' contained an empty list\n"); + } + } + + // Calculate the register offset + const size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size; + if (m_reg_data_byte_size < end_reg_offset) + m_reg_data_byte_size = end_reg_offset; + + m_regs.push_back(reg_info); + m_set_reg_nums[set].push_back(i); + } + Finalize(arch); + return m_regs.size(); +} + +size_t DynamicRegisterInfo::SetRegisterInfo( + std::vector<DynamicRegisterInfo::Register> &®s, + const ArchSpec &arch) { + assert(!m_finalized); + + for (auto it : llvm::enumerate(regs)) { + uint32_t local_regnum = it.index(); + const DynamicRegisterInfo::Register ® = it.value(); + + assert(reg.name); + assert(reg.set_name); + + if (!reg.value_regs.empty()) + m_value_regs_map[local_regnum] = std::move(reg.value_regs); + if (!reg.invalidate_regs.empty()) + m_invalidate_regs_map[local_regnum] = std::move(reg.invalidate_regs); + if (reg.value_reg_offset != 0) { + assert(reg.value_regs.size() == 1); + m_value_reg_offset_map[local_regnum] = reg.value_reg_offset; + } + + struct RegisterInfo reg_info { + reg.name.AsCString(), reg.alt_name.AsCString(), reg.byte_size, + reg.byte_offset, reg.encoding, reg.format, + {reg.regnum_ehframe, reg.regnum_dwarf, reg.regnum_generic, + reg.regnum_remote, local_regnum}, + // value_regs and invalidate_regs are filled by Finalize() + nullptr, nullptr + }; + + m_regs.push_back(reg_info); + + uint32_t set = GetRegisterSetIndexByName(reg.set_name, true); + assert(set < m_sets.size()); + assert(set < m_set_reg_nums.size()); + assert(set < m_set_names.size()); + m_set_reg_nums[set].push_back(local_regnum); + }; + + Finalize(arch); + return m_regs.size(); +} + +void DynamicRegisterInfo::Finalize(const ArchSpec &arch) { + if (m_finalized) + return; + + m_finalized = true; + const size_t num_sets = m_sets.size(); + for (size_t set = 0; set < num_sets; ++set) { + assert(m_sets.size() == m_set_reg_nums.size()); + m_sets[set].num_registers = m_set_reg_nums[set].size(); + m_sets[set].registers = m_set_reg_nums[set].data(); + } + + // make sure value_regs are terminated with LLDB_INVALID_REGNUM + + for (reg_to_regs_map::iterator pos = m_value_regs_map.begin(), + end = m_value_regs_map.end(); + pos != end; ++pos) { + if (pos->second.back() != LLDB_INVALID_REGNUM) + pos->second.push_back(LLDB_INVALID_REGNUM); + } + + // Now update all value_regs with each register info as needed + const size_t num_regs = m_regs.size(); + for (size_t i = 0; i < num_regs; ++i) { + if (m_value_regs_map.find(i) != m_value_regs_map.end()) + m_regs[i].value_regs = m_value_regs_map[i].data(); + else + m_regs[i].value_regs = nullptr; + } + + // Expand all invalidation dependencies + for (reg_to_regs_map::iterator pos = m_invalidate_regs_map.begin(), + end = m_invalidate_regs_map.end(); + pos != end; ++pos) { + const uint32_t reg_num = pos->first; + + if (m_regs[reg_num].value_regs) { + reg_num_collection extra_invalid_regs; + for (const uint32_t invalidate_reg_num : pos->second) { + reg_to_regs_map::iterator invalidate_pos = + m_invalidate_regs_map.find(invalidate_reg_num); + if (invalidate_pos != m_invalidate_regs_map.end()) { + for (const uint32_t concrete_invalidate_reg_num : + invalidate_pos->second) { + if (concrete_invalidate_reg_num != reg_num) + extra_invalid_regs.push_back(concrete_invalidate_reg_num); + } + } + } + pos->second.insert(pos->second.end(), extra_invalid_regs.begin(), + extra_invalid_regs.end()); + } + } + + // sort and unique all invalidate registers and make sure each is terminated + // with LLDB_INVALID_REGNUM + for (reg_to_regs_map::iterator pos = m_invalidate_regs_map.begin(), + end = m_invalidate_regs_map.end(); + 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()); + } + assert(!pos->second.empty()); + if (pos->second.back() != LLDB_INVALID_REGNUM) + pos->second.push_back(LLDB_INVALID_REGNUM); + } + + // Now update all invalidate_regs with each register info as needed + for (size_t i = 0; i < num_regs; ++i) { + if (m_invalidate_regs_map.find(i) != m_invalidate_regs_map.end()) + m_regs[i].invalidate_regs = m_invalidate_regs_map[i].data(); + else + m_regs[i].invalidate_regs = nullptr; + } + + // Check if we need to automatically set the generic registers in case they + // weren't set + bool generic_regs_specified = false; + for (const auto ® : m_regs) { + if (reg.kinds[eRegisterKindGeneric] != LLDB_INVALID_REGNUM) { + generic_regs_specified = true; + break; + } + } + + if (!generic_regs_specified) { + switch (arch.GetMachine()) { + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_32: + case llvm::Triple::aarch64_be: + for (auto ® : m_regs) { + if (strcmp(reg.name, "pc") == 0) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC; + else if ((strcmp(reg.name, "fp") == 0) || + (strcmp(reg.name, "x29") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; + else if ((strcmp(reg.name, "lr") == 0) || + (strcmp(reg.name, "x30") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA; + else if ((strcmp(reg.name, "sp") == 0) || + (strcmp(reg.name, "x31") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP; + else if (strcmp(reg.name, "cpsr") == 0) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS; + } + break; + + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + for (auto ® : m_regs) { + if ((strcmp(reg.name, "pc") == 0) || (strcmp(reg.name, "r15") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC; + else if ((strcmp(reg.name, "sp") == 0) || + (strcmp(reg.name, "r13") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP; + else if ((strcmp(reg.name, "lr") == 0) || + (strcmp(reg.name, "r14") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA; + else if ((strcmp(reg.name, "r7") == 0) && + arch.GetTriple().getVendor() == llvm::Triple::Apple) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; + else if ((strcmp(reg.name, "r11") == 0) && + arch.GetTriple().getVendor() != llvm::Triple::Apple) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; + else if (strcmp(reg.name, "fp") == 0) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; + else if (strcmp(reg.name, "cpsr") == 0) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS; + } + break; + + case llvm::Triple::x86: + for (auto ® : m_regs) { + if ((strcmp(reg.name, "eip") == 0) || (strcmp(reg.name, "pc") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC; + else if ((strcmp(reg.name, "esp") == 0) || + (strcmp(reg.name, "sp") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP; + else if ((strcmp(reg.name, "ebp") == 0) || + (strcmp(reg.name, "fp") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; + else if ((strcmp(reg.name, "eflags") == 0) || + (strcmp(reg.name, "flags") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS; + } + break; + + case llvm::Triple::x86_64: + for (auto ® : m_regs) { + if ((strcmp(reg.name, "rip") == 0) || (strcmp(reg.name, "pc") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC; + else if ((strcmp(reg.name, "rsp") == 0) || + (strcmp(reg.name, "sp") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP; + else if ((strcmp(reg.name, "rbp") == 0) || + (strcmp(reg.name, "fp") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; + else if ((strcmp(reg.name, "rflags") == 0) || + (strcmp(reg.name, "eflags") == 0) || + (strcmp(reg.name, "flags") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS; + } + break; + + default: + break; + } + } + + // At this stage call ConfigureOffsets to calculate register offsets for + // targets supporting dynamic offset calculation. It also calculates + // total byte size of register data. + ConfigureOffsets(); + + // Check if register info is reconfigurable + // AArch64 SVE register set has configurable register sizes + if (arch.GetTriple().isAArch64()) { + for (const auto ® : m_regs) { + if (strcmp(reg.name, "vg") == 0) { + m_is_reconfigurable = true; + break; + } + } + } +} + +void DynamicRegisterInfo::ConfigureOffsets() { + // We are going to create a map between remote (eRegisterKindProcessPlugin) + // and local (eRegisterKindLLDB) register numbers. This map will give us + // remote register numbers in increasing order for offset calculation. + std::map<uint32_t, uint32_t> remote_to_local_regnum_map; + for (const auto ® : m_regs) + remote_to_local_regnum_map[reg.kinds[eRegisterKindProcessPlugin]] = + reg.kinds[eRegisterKindLLDB]; + + // At this stage we manually calculate g/G packet offsets of all primary + // registers, only if target XML or qRegisterInfo packet did not send + // an offset explicitly. + uint32_t reg_offset = 0; + for (auto const ®num_pair : remote_to_local_regnum_map) { + if (m_regs[regnum_pair.second].byte_offset == LLDB_INVALID_INDEX32 && + m_regs[regnum_pair.second].value_regs == nullptr) { + m_regs[regnum_pair.second].byte_offset = reg_offset; + + reg_offset = m_regs[regnum_pair.second].byte_offset + + m_regs[regnum_pair.second].byte_size; + } + } + + // Now update all value_regs with each register info as needed + for (auto ® : m_regs) { + if (reg.value_regs != nullptr) { + // Assign a valid offset to all pseudo registers that have only a single + // parent register in value_regs list, if not assigned by stub. Pseudo + // registers with value_regs list populated will share same offset as + // that of their corresponding parent register. + if (reg.byte_offset == LLDB_INVALID_INDEX32) { + uint32_t value_regnum = reg.value_regs[0]; + if (value_regnum != LLDB_INVALID_INDEX32 && + reg.value_regs[1] == LLDB_INVALID_INDEX32) { + reg.byte_offset = + GetRegisterInfoAtIndex(value_regnum)->byte_offset; + auto it = m_value_reg_offset_map.find(reg.kinds[eRegisterKindLLDB]); + if (it != m_value_reg_offset_map.end()) + reg.byte_offset += it->second; + } + } + } + + reg_offset = reg.byte_offset + reg.byte_size; + if (m_reg_data_byte_size < reg_offset) + m_reg_data_byte_size = reg_offset; + } +} + +bool DynamicRegisterInfo::IsReconfigurable() { return m_is_reconfigurable; } + +size_t DynamicRegisterInfo::GetNumRegisters() const { return m_regs.size(); } + +size_t DynamicRegisterInfo::GetNumRegisterSets() const { return m_sets.size(); } + +size_t DynamicRegisterInfo::GetRegisterDataByteSize() const { + return m_reg_data_byte_size; +} + +const RegisterInfo * +DynamicRegisterInfo::GetRegisterInfoAtIndex(uint32_t i) const { + if (i < m_regs.size()) + return &m_regs[i]; + return nullptr; +} + +const RegisterInfo *DynamicRegisterInfo::GetRegisterInfo(uint32_t kind, + uint32_t num) const { + uint32_t reg_index = ConvertRegisterKindToRegisterNumber(kind, num); + if (reg_index != LLDB_INVALID_REGNUM) + return &m_regs[reg_index]; + return nullptr; +} + +const RegisterSet *DynamicRegisterInfo::GetRegisterSet(uint32_t i) const { + if (i < m_sets.size()) + return &m_sets[i]; + return nullptr; +} + +uint32_t +DynamicRegisterInfo::GetRegisterSetIndexByName(const ConstString &set_name, + bool can_create) { + name_collection::iterator pos, end = m_set_names.end(); + for (pos = m_set_names.begin(); pos != end; ++pos) { + if (*pos == set_name) + return std::distance(m_set_names.begin(), pos); + } + + m_set_names.push_back(set_name); + m_set_reg_nums.resize(m_set_reg_nums.size() + 1); + RegisterSet new_set = {set_name.AsCString(), nullptr, 0, nullptr}; + m_sets.push_back(new_set); + return m_sets.size() - 1; +} + +uint32_t +DynamicRegisterInfo::ConvertRegisterKindToRegisterNumber(uint32_t kind, + uint32_t num) const { + reg_collection::const_iterator pos, end = m_regs.end(); + for (pos = m_regs.begin(); pos != end; ++pos) { + if (pos->kinds[kind] == num) + return std::distance(m_regs.begin(), pos); + } + + return LLDB_INVALID_REGNUM; +} + +void DynamicRegisterInfo::Clear() { + m_regs.clear(); + m_sets.clear(); + m_set_reg_nums.clear(); + m_set_names.clear(); + m_value_regs_map.clear(); + m_invalidate_regs_map.clear(); + m_reg_data_byte_size = 0; + m_finalized = false; +} + +void DynamicRegisterInfo::Dump() const { + StreamFile s(stdout, false); + const size_t num_regs = m_regs.size(); + s.Printf("%p: DynamicRegisterInfo contains %" PRIu64 " registers:\n", + static_cast<const void *>(this), static_cast<uint64_t>(num_regs)); + for (size_t i = 0; i < num_regs; ++i) { + s.Printf("[%3" PRIu64 "] name = %-10s", (uint64_t)i, m_regs[i].name); + s.Printf(", size = %2u, offset = %4u, encoding = %u, format = %-10s", + m_regs[i].byte_size, m_regs[i].byte_offset, m_regs[i].encoding, + FormatManager::GetFormatAsCString(m_regs[i].format)); + if (m_regs[i].kinds[eRegisterKindProcessPlugin] != LLDB_INVALID_REGNUM) + s.Printf(", process plugin = %3u", + m_regs[i].kinds[eRegisterKindProcessPlugin]); + if (m_regs[i].kinds[eRegisterKindDWARF] != LLDB_INVALID_REGNUM) + s.Printf(", dwarf = %3u", m_regs[i].kinds[eRegisterKindDWARF]); + if (m_regs[i].kinds[eRegisterKindEHFrame] != LLDB_INVALID_REGNUM) + s.Printf(", ehframe = %3u", m_regs[i].kinds[eRegisterKindEHFrame]); + if (m_regs[i].kinds[eRegisterKindGeneric] != LLDB_INVALID_REGNUM) + s.Printf(", generic = %3u", m_regs[i].kinds[eRegisterKindGeneric]); + if (m_regs[i].alt_name) + s.Printf(", alt-name = %s", m_regs[i].alt_name); + if (m_regs[i].value_regs) { + s.Printf(", value_regs = [ "); + for (size_t j = 0; m_regs[i].value_regs[j] != LLDB_INVALID_REGNUM; ++j) { + s.Printf("%s ", m_regs[m_regs[i].value_regs[j]].name); + } + s.Printf("]"); + } + if (m_regs[i].invalidate_regs) { + s.Printf(", invalidate_regs = [ "); + for (size_t j = 0; m_regs[i].invalidate_regs[j] != LLDB_INVALID_REGNUM; + ++j) { + s.Printf("%s ", m_regs[m_regs[i].invalidate_regs[j]].name); + } + s.Printf("]"); + } + s.EOL(); + } + + const size_t num_sets = m_sets.size(); + s.Printf("%p: DynamicRegisterInfo contains %" PRIu64 " register sets:\n", + static_cast<const void *>(this), static_cast<uint64_t>(num_sets)); + for (size_t i = 0; i < num_sets; ++i) { + s.Printf("set[%" PRIu64 "] name = %s, regs = [", (uint64_t)i, + m_sets[i].name); + for (size_t idx = 0; idx < m_sets[i].num_registers; ++idx) { + s.Printf("%s ", m_regs[m_sets[i].registers[idx]].name); + } + s.Printf("]\n"); + } +} + +const lldb_private::RegisterInfo * +DynamicRegisterInfo::GetRegisterInfo(llvm::StringRef reg_name) const { + for (auto ®_info : m_regs) + if (reg_info.name == reg_name) + return ®_info; + return nullptr; +} + +void lldb_private::addSupplementaryRegister( + std::vector<DynamicRegisterInfo::Register> ®s, + DynamicRegisterInfo::Register new_reg_info) { + assert(!new_reg_info.value_regs.empty()); + const uint32_t reg_num = regs.size(); + regs.push_back(new_reg_info); + + std::map<uint32_t, std::vector<uint32_t>> new_invalidates; + for (uint32_t value_reg : new_reg_info.value_regs) { + // copy value_regs to invalidate_regs + new_invalidates[reg_num].push_back(value_reg); + + // copy invalidate_regs from the parent register + llvm::append_range(new_invalidates[reg_num], + regs[value_reg].invalidate_regs); + + // add reverse invalidate entries + for (uint32_t x : new_invalidates[reg_num]) + new_invalidates[x].push_back(reg_num); + } + + for (const auto &x : new_invalidates) + llvm::append_range(regs[x.first].invalidate_regs, x.second); +} diff --git a/gnu/llvm/lldb/source/Target/ExecutionContext.cpp b/gnu/llvm/lldb/source/Target/ExecutionContext.cpp index b5cf13582af..a5288b81cd1 100644 --- a/gnu/llvm/lldb/source/Target/ExecutionContext.cpp +++ b/gnu/llvm/lldb/source/Target/ExecutionContext.cpp @@ -19,9 +19,7 @@ using namespace lldb_private; ExecutionContext::ExecutionContext() : m_target_sp(), m_process_sp(), m_thread_sp(), m_frame_sp() {} -ExecutionContext::ExecutionContext(const ExecutionContext &rhs) - : m_target_sp(rhs.m_target_sp), m_process_sp(rhs.m_process_sp), - m_thread_sp(rhs.m_thread_sp), m_frame_sp(rhs.m_frame_sp) {} +ExecutionContext::ExecutionContext(const ExecutionContext &rhs) = default; ExecutionContext::ExecutionContext(const lldb::TargetSP &target_sp, bool get_process) @@ -398,28 +396,24 @@ ExecutionContextRef::ExecutionContextRef() : m_target_wp(), m_process_wp(), m_thread_wp(), m_stack_id() {} ExecutionContextRef::ExecutionContextRef(const ExecutionContext *exe_ctx) - : m_target_wp(), m_process_wp(), m_thread_wp(), - m_tid(LLDB_INVALID_THREAD_ID), m_stack_id() { + : m_target_wp(), m_process_wp(), m_thread_wp(), m_stack_id() { if (exe_ctx) *this = *exe_ctx; } ExecutionContextRef::ExecutionContextRef(const ExecutionContext &exe_ctx) - : m_target_wp(), m_process_wp(), m_thread_wp(), - m_tid(LLDB_INVALID_THREAD_ID), m_stack_id() { + : m_target_wp(), m_process_wp(), m_thread_wp(), m_stack_id() { *this = exe_ctx; } ExecutionContextRef::ExecutionContextRef(Target *target, bool adopt_selected) - : m_target_wp(), m_process_wp(), m_thread_wp(), - m_tid(LLDB_INVALID_THREAD_ID), m_stack_id() { + : m_target_wp(), m_process_wp(), m_thread_wp(), m_stack_id() { SetTargetPtr(target, adopt_selected); } ExecutionContextRef::ExecutionContextRef(const ExecutionContextRef &rhs) - : m_target_wp(rhs.m_target_wp), m_process_wp(rhs.m_process_wp), - m_thread_wp(rhs.m_thread_wp), m_tid(rhs.m_tid), - m_stack_id(rhs.m_stack_id) {} + + = default; ExecutionContextRef &ExecutionContextRef:: operator=(const ExecutionContextRef &rhs) { diff --git a/gnu/llvm/lldb/source/Target/JITLoaderList.cpp b/gnu/llvm/lldb/source/Target/JITLoaderList.cpp index 92e841b5c94..9158d0a5e54 100644 --- a/gnu/llvm/lldb/source/Target/JITLoaderList.cpp +++ b/gnu/llvm/lldb/source/Target/JITLoaderList.cpp @@ -24,9 +24,7 @@ void JITLoaderList::Append(const JITLoaderSP &jit_loader_sp) { void JITLoaderList::Remove(const JITLoaderSP &jit_loader_sp) { std::lock_guard<std::recursive_mutex> guard(m_jit_loaders_mutex); - m_jit_loaders_vec.erase(std::remove(m_jit_loaders_vec.begin(), - m_jit_loaders_vec.end(), jit_loader_sp), - m_jit_loaders_vec.end()); + llvm::erase_value(m_jit_loaders_vec, jit_loader_sp); } size_t JITLoaderList::GetSize() const { return m_jit_loaders_vec.size(); } diff --git a/gnu/llvm/lldb/source/Target/Language.cpp b/gnu/llvm/lldb/source/Target/Language.cpp index 7b35da5028a..892d2a86437 100644 --- a/gnu/llvm/lldb/source/Target/Language.cpp +++ b/gnu/llvm/lldb/source/Target/Language.cpp @@ -108,10 +108,21 @@ void Language::ForEach(std::function<bool(Language *)> callback) { } }); - std::lock_guard<std::mutex> guard(GetLanguagesMutex()); - LanguagesMap &map(GetLanguagesMap()); - for (const auto &entry : map) { - if (!callback(entry.second.get())) + // callback may call a method in Language that attempts to acquire the same + // lock (such as Language::ForEach or Language::FindPlugin). To avoid a + // deadlock, we do not use callback while holding the lock. + std::vector<Language *> loaded_plugins; + { + std::lock_guard<std::mutex> guard(GetLanguagesMutex()); + LanguagesMap &map(GetLanguagesMap()); + for (const auto &entry : map) { + if (entry.second) + loaded_plugins.push_back(entry.second.get()); + } + } + + for (auto *lang : loaded_plugins) { + if (!callback(lang)) break; } } @@ -133,7 +144,7 @@ Language::GetHardcodedSynthetics() { return {}; } -std::vector<ConstString> +std::vector<FormattersMatchCandidate> Language::GetPossibleFormattersMatches(ValueObject &valobj, lldb::DynamicValueType use_dynamic) { return {}; @@ -210,6 +221,17 @@ const char *Language::GetNameForLanguageType(LanguageType language) { return language_names[eLanguageTypeUnknown].name; } +void Language::PrintSupportedLanguagesForExpressions(Stream &s, + llvm::StringRef prefix, + llvm::StringRef suffix) { + auto supported = Language::GetLanguagesSupportingTypeSystemsForExpressions(); + for (size_t idx = 0; idx < num_languages; ++idx) { + auto const &lang = language_names[idx]; + if (supported[lang.type]) + s << prefix << lang.name << suffix; + } +} + void Language::PrintAllLanguages(Stream &s, const char *prefix, const char *suffix) { for (uint32_t i = 1; i < num_languages; i++) { @@ -417,6 +439,14 @@ bool Language::GetFormatterPrefixSuffix(ValueObject &valobj, return false; } +bool Language::DemangledNameContainsPath(llvm::StringRef path, + ConstString demangled) const { + // The base implementation does a simple contains comparision: + if (path.empty()) + return false; + return demangled.GetStringRef().contains(path); +} + DumpValueObjectOptions::DeclPrintingHelper Language::GetDeclPrintingHelper() { return nullptr; } diff --git a/gnu/llvm/lldb/source/Target/LanguageRuntime.cpp b/gnu/llvm/lldb/source/Target/LanguageRuntime.cpp index be878d69fa0..ce3646c8b05 100644 --- a/gnu/llvm/lldb/source/Target/LanguageRuntime.cpp +++ b/gnu/llvm/lldb/source/Target/LanguageRuntime.cpp @@ -104,8 +104,7 @@ public: ExceptionBreakpointResolver(lldb::LanguageType language, bool catch_bp, bool throw_bp) : BreakpointResolver(nullptr, BreakpointResolver::ExceptionResolver), - m_language(language), m_language_runtime(nullptr), m_catch_bp(catch_bp), - m_throw_bp(throw_bp) {} + m_language(language), m_catch_bp(catch_bp), m_throw_bp(throw_bp) {} ~ExceptionBreakpointResolver() override = default; @@ -195,7 +194,7 @@ protected: lldb::BreakpointResolverSP m_actual_resolver_sp; lldb::LanguageType m_language; - LanguageRuntime *m_language_runtime; + LanguageRuntime *m_language_runtime = nullptr; bool m_catch_bp; bool m_throw_bp; }; diff --git a/gnu/llvm/lldb/source/Target/Memory.cpp b/gnu/llvm/lldb/source/Target/Memory.cpp index 806e92aa4ed..d4dedeea7c2 100644 --- a/gnu/llvm/lldb/source/Target/Memory.cpp +++ b/gnu/llvm/lldb/source/Target/Memory.cpp @@ -9,6 +9,7 @@ #include "lldb/Target/Memory.h" #include "lldb/Target/Process.h" #include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RangeMap.h" #include "lldb/Utility/State.h" @@ -265,8 +266,8 @@ lldb::addr_t AllocatedBlock::ReserveBlock(uint32_t size) { // We must return something valid for zero bytes. if (size == 0) size = 1; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - + Log *log = GetLog(LLDBLog::Process); + const size_t free_count = m_free_blocks.GetSize(); for (size_t i=0; i<free_count; ++i) { @@ -321,7 +322,7 @@ bool AllocatedBlock::FreeBlock(addr_t addr) { m_reserved_blocks.RemoveEntryAtIndex(entry_idx); success = true; } - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGV(log, "({0}) (addr = {1:x}) => {2}", this, addr, success); return success; } @@ -331,9 +332,9 @@ AllocatedMemoryCache::AllocatedMemoryCache(Process &process) AllocatedMemoryCache::~AllocatedMemoryCache() = default; -void AllocatedMemoryCache::Clear() { +void AllocatedMemoryCache::Clear(bool deallocate_memory) { std::lock_guard<std::recursive_mutex> guard(m_mutex); - if (m_process.IsAlive()) { + if (m_process.IsAlive() && deallocate_memory) { PermissionsToBlockMap::iterator pos, end = m_memory_map.end(); for (pos = m_memory_map.begin(); pos != end; ++pos) m_process.DoDeallocateMemory(pos->second->GetBaseAddress()); @@ -351,7 +352,7 @@ AllocatedMemoryCache::AllocatePage(uint32_t byte_size, uint32_t permissions, addr_t addr = m_process.DoAllocateMemory(page_byte_size, permissions, error); - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); if (log) { LLDB_LOGF(log, "Process::DoAllocateMemory (byte_size = 0x%8.8" PRIx32 @@ -390,7 +391,7 @@ lldb::addr_t AllocatedMemoryCache::AllocateMemory(size_t byte_size, if (block_sp) addr = block_sp->ReserveBlock(byte_size); } - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "AllocatedMemoryCache::AllocateMemory (byte_size = 0x%8.8" PRIx32 ", permissions = %s) => 0x%16.16" PRIx64, @@ -410,7 +411,7 @@ bool AllocatedMemoryCache::DeallocateMemory(lldb::addr_t addr) { break; } } - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "AllocatedMemoryCache::DeallocateMemory (addr = 0x%16.16" PRIx64 ") => %i", diff --git a/gnu/llvm/lldb/source/Target/MemoryTagMap.cpp b/gnu/llvm/lldb/source/Target/MemoryTagMap.cpp new file mode 100644 index 00000000000..c5a7c85ac09 --- /dev/null +++ b/gnu/llvm/lldb/source/Target/MemoryTagMap.cpp @@ -0,0 +1,65 @@ +//===-- MemoryTagMap.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/MemoryTagMap.h" +#include <optional> + +using namespace lldb_private; + +MemoryTagMap::MemoryTagMap(const MemoryTagManager *manager) + : m_manager(manager) { + assert(m_manager && "valid tag manager required to construct a MemoryTagMap"); +} + +void MemoryTagMap::InsertTags(lldb::addr_t addr, + const std::vector<lldb::addr_t> tags) { + // We're assuming that addr has no non address bits and is granule aligned. + size_t granule_size = m_manager->GetGranuleSize(); + for (auto tag : tags) { + m_addr_to_tag[addr] = tag; + addr += granule_size; + } +} + +bool MemoryTagMap::Empty() const { return m_addr_to_tag.empty(); } + +std::vector<std::optional<lldb::addr_t>> +MemoryTagMap::GetTags(lldb::addr_t addr, size_t len) const { + // Addr and len might be unaligned + addr = m_manager->RemoveTagBits(addr); + MemoryTagManager::TagRange range(addr, len); + range = m_manager->ExpandToGranule(range); + + std::vector<std::optional<lldb::addr_t>> tags; + lldb::addr_t end_addr = range.GetRangeEnd(); + addr = range.GetRangeBase(); + bool got_valid_tags = false; + size_t granule_size = m_manager->GetGranuleSize(); + + for (; addr < end_addr; addr += granule_size) { + std::optional<lldb::addr_t> tag = GetTag(addr); + tags.push_back(tag); + if (tag) + got_valid_tags = true; + } + + // To save the caller checking if every item is std::nullopt, + // we return an empty vector if we got no tags at all. + if (got_valid_tags) + return tags; + return {}; +} + +std::optional<lldb::addr_t> MemoryTagMap::GetTag(lldb::addr_t addr) const { + // Here we assume that addr is granule aligned, just like when the tags + // were inserted. + auto found = m_addr_to_tag.find(addr); + if (found == m_addr_to_tag.end()) + return std::nullopt; + return found->second; +} diff --git a/gnu/llvm/lldb/source/Target/ModuleCache.cpp b/gnu/llvm/lldb/source/Target/ModuleCache.cpp index dcdc0772b31..29bd2b2394b 100644 --- a/gnu/llvm/lldb/source/Target/ModuleCache.cpp +++ b/gnu/llvm/lldb/source/Target/ModuleCache.cpp @@ -13,6 +13,7 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Host/File.h" #include "lldb/Host/LockFile.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FileUtilities.h" @@ -80,7 +81,7 @@ FileSpec GetSymbolFileSpec(const FileSpec &module_file_spec) { void DeleteExistingModule(const FileSpec &root_dir_spec, const FileSpec &sysroot_module_path_spec) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES)); + Log *log = GetLog(LLDBLog::Modules); UUID module_uuid; { auto module_sp = @@ -159,7 +160,7 @@ ModuleLock::ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid, m_file_spec = JoinPath(lock_dir_spec, uuid.GetAsString().c_str()); auto file = FileSystem::Instance().Open( - m_file_spec, File::eOpenOptionWrite | File::eOpenOptionCanCreate | + m_file_spec, File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate | File::eOpenOptionCloseOnExec); if (file) m_file_up = std::move(file.get()); diff --git a/gnu/llvm/lldb/source/Target/OperatingSystem.cpp b/gnu/llvm/lldb/source/Target/OperatingSystem.cpp index 033a806460d..75762c05151 100644 --- a/gnu/llvm/lldb/source/Target/OperatingSystem.cpp +++ b/gnu/llvm/lldb/source/Target/OperatingSystem.cpp @@ -17,10 +17,9 @@ OperatingSystem *OperatingSystem::FindPlugin(Process *process, const char *plugin_name) { OperatingSystemCreateInstance create_callback = nullptr; if (plugin_name) { - ConstString const_plugin_name(plugin_name); create_callback = PluginManager::GetOperatingSystemCreateCallbackForPluginName( - const_plugin_name); + plugin_name); if (create_callback) { std::unique_ptr<OperatingSystem> instance_up( create_callback(process, true)); diff --git a/gnu/llvm/lldb/source/Target/PathMappingList.cpp b/gnu/llvm/lldb/source/Target/PathMappingList.cpp index b660c310ef3..13bb50b362c 100644 --- a/gnu/llvm/lldb/source/Target/PathMappingList.cpp +++ b/gnu/llvm/lldb/source/Target/PathMappingList.cpp @@ -8,6 +8,7 @@ #include <climits> #include <cstring> +#include <optional> #include "lldb/Host/FileSystem.h" #include "lldb/Host/PosixApi.h" @@ -30,22 +31,20 @@ namespace { // with the raw path pair, which doesn't work anymore because the paths have // been normalized when the debug info was loaded. So we need to store // nomalized path pairs to ensure things match up. - ConstString NormalizePath(ConstString path) { - // If we use "path" to construct a FileSpec, it will normalize the path for - // us. We then grab the string and turn it back into a ConstString. - return ConstString(FileSpec(path.GetStringRef()).GetPath()); - } +std::string NormalizePath(llvm::StringRef path) { + // If we use "path" to construct a FileSpec, it will normalize the path for + // us. We then grab the string. + return FileSpec(path).GetPath(); +} } // PathMappingList constructor PathMappingList::PathMappingList() : m_pairs() {} PathMappingList::PathMappingList(ChangedCallback callback, void *callback_baton) - : m_pairs(), m_callback(callback), m_callback_baton(callback_baton), - m_mod_id(0) {} + : m_pairs(), m_callback(callback), m_callback_baton(callback_baton) {} PathMappingList::PathMappingList(const PathMappingList &rhs) - : m_pairs(rhs.m_pairs), m_callback(nullptr), m_callback_baton(nullptr), - m_mod_id(0) {} + : m_pairs(rhs.m_pairs) {} const PathMappingList &PathMappingList::operator=(const PathMappingList &rhs) { if (this != &rhs) { @@ -59,8 +58,8 @@ const PathMappingList &PathMappingList::operator=(const PathMappingList &rhs) { PathMappingList::~PathMappingList() = default; -void PathMappingList::Append(ConstString path, - ConstString replacement, bool notify) { +void PathMappingList::Append(llvm::StringRef path, llvm::StringRef replacement, + bool notify) { ++m_mod_id; m_pairs.emplace_back(pair(NormalizePath(path), NormalizePath(replacement))); if (notify && m_callback) @@ -78,9 +77,21 @@ void PathMappingList::Append(const PathMappingList &rhs, bool notify) { } } -void PathMappingList::Insert(ConstString path, - ConstString replacement, uint32_t index, - bool notify) { +bool PathMappingList::AppendUnique(llvm::StringRef path, + llvm::StringRef replacement, bool notify) { + auto normalized_path = NormalizePath(path); + auto normalized_replacement = NormalizePath(replacement); + for (const auto &pair : m_pairs) { + if (pair.first.GetStringRef().equals(normalized_path) && + pair.second.GetStringRef().equals(normalized_replacement)) + return false; + } + Append(path, replacement, notify); + return true; +} + +void PathMappingList::Insert(llvm::StringRef path, llvm::StringRef replacement, + uint32_t index, bool notify) { ++m_mod_id; iterator insert_iter; if (index >= m_pairs.size()) @@ -93,9 +104,8 @@ void PathMappingList::Insert(ConstString path, m_callback(*this, m_callback_baton); } -bool PathMappingList::Replace(ConstString path, - ConstString replacement, uint32_t index, - bool notify) { +bool PathMappingList::Replace(llvm::StringRef path, llvm::StringRef replacement, + uint32_t index, bool notify) { if (index >= m_pairs.size()) return false; ++m_mod_id; @@ -135,6 +145,16 @@ void PathMappingList::Dump(Stream *s, int pair_index) { } } +llvm::json::Value PathMappingList::ToJSON() { + llvm::json::Array entries; + for (const auto &pair : m_pairs) { + llvm::json::Array entry{pair.first.GetStringRef().str(), + pair.second.GetStringRef().str()}; + entries.emplace_back(std::move(entry)); + } + return entries; +} + void PathMappingList::Clear(bool notify) { if (!m_pairs.empty()) ++m_mod_id; @@ -145,7 +165,7 @@ void PathMappingList::Clear(bool notify) { bool PathMappingList::RemapPath(ConstString path, ConstString &new_path) const { - if (llvm::Optional<FileSpec> remapped = RemapPath(path.GetStringRef())) { + if (std::optional<FileSpec> remapped = RemapPath(path.GetStringRef())) { new_path.SetString(remapped->GetPath()); return true; } @@ -155,18 +175,17 @@ bool PathMappingList::RemapPath(ConstString path, /// Append components to path, applying style. static void AppendPathComponents(FileSpec &path, llvm::StringRef components, llvm::sys::path::Style style) { - auto component = llvm::sys::path::begin(components, style); - auto e = llvm::sys::path::end(components); - while (component != e && - llvm::sys::path::is_separator(*component->data(), style)) - ++component; - for (; component != e; ++component) - path.AppendPathComponent(*component); + auto component = llvm::sys::path::begin(components, style); + auto e = llvm::sys::path::end(components); + while (component != e && + llvm::sys::path::is_separator(*component->data(), style)) + ++component; + for (; component != e; ++component) + path.AppendPathComponent(*component); } -llvm::Optional<FileSpec> -PathMappingList::RemapPath(llvm::StringRef mapping_path, - bool only_if_exists) const { +std::optional<FileSpec> PathMappingList::RemapPath(llvm::StringRef mapping_path, + bool only_if_exists) const { if (m_pairs.empty() || mapping_path.empty()) return {}; LazyBool path_is_relative = eLazyBoolCalculate; @@ -192,7 +211,7 @@ PathMappingList::RemapPath(llvm::StringRef mapping_path, continue; } FileSpec remapped(it.second.GetStringRef()); - auto orig_style = FileSpec::GuessPathStyle(prefix).getValueOr( + auto orig_style = FileSpec::GuessPathStyle(prefix).value_or( llvm::sys::path::Style::native); AppendPathComponents(remapped, path, orig_style); if (!only_if_exists || FileSystem::Instance().Exists(remapped)) @@ -201,35 +220,42 @@ PathMappingList::RemapPath(llvm::StringRef mapping_path, return {}; } -bool PathMappingList::ReverseRemapPath(const FileSpec &file, FileSpec &fixed) const { +std::optional<llvm::StringRef> +PathMappingList::ReverseRemapPath(const FileSpec &file, FileSpec &fixed) const { std::string path = file.GetPath(); llvm::StringRef path_ref(path); for (const auto &it : m_pairs) { + llvm::StringRef removed_prefix = it.second.GetStringRef(); if (!path_ref.consume_front(it.second.GetStringRef())) continue; auto orig_file = it.first.GetStringRef(); - auto orig_style = FileSpec::GuessPathStyle(orig_file).getValueOr( + auto orig_style = FileSpec::GuessPathStyle(orig_file).value_or( llvm::sys::path::Style::native); fixed.SetFile(orig_file, orig_style); AppendPathComponents(fixed, path_ref, orig_style); - return true; + return removed_prefix; } - return false; + return std::nullopt; } -llvm::Optional<FileSpec> PathMappingList::FindFile(const FileSpec &orig_spec) const { - if (auto remapped = RemapPath(orig_spec.GetPath(), /*only_if_exists=*/true)) +std::optional<FileSpec> +PathMappingList::FindFile(const FileSpec &orig_spec) const { + // We must normalize the orig_spec again using the host's path style, + // otherwise there will be mismatch between the host and remote platform + // if they use different path styles. + if (auto remapped = RemapPath(NormalizePath(orig_spec.GetPath()), + /*only_if_exists=*/true)) return remapped; return {}; } -bool PathMappingList::Replace(ConstString path, - ConstString new_path, bool notify) { +bool PathMappingList::Replace(llvm::StringRef path, llvm::StringRef new_path, + bool notify) { uint32_t idx = FindIndexForPath(path); if (idx < m_pairs.size()) { ++m_mod_id; - m_pairs[idx].second = new_path; + m_pairs[idx].second = ConstString(new_path); if (notify && m_callback) m_callback(*this, m_callback_baton); return true; @@ -285,8 +311,8 @@ bool PathMappingList::GetPathsAtIndex(uint32_t idx, ConstString &path, return false; } -uint32_t PathMappingList::FindIndexForPath(ConstString orig_path) const { - const ConstString path = NormalizePath(orig_path); +uint32_t PathMappingList::FindIndexForPath(llvm::StringRef orig_path) const { + const ConstString path = ConstString(NormalizePath(orig_path)); const_iterator pos; const_iterator begin = m_pairs.begin(); const_iterator end = m_pairs.end(); diff --git a/gnu/llvm/lldb/source/Target/Platform.cpp b/gnu/llvm/lldb/source/Target/Platform.cpp index a77ecddfbab..1ddd7596280 100644 --- a/gnu/llvm/lldb/source/Target/Platform.cpp +++ b/gnu/llvm/lldb/source/Target/Platform.cpp @@ -10,6 +10,7 @@ #include <csignal> #include <fstream> #include <memory> +#include <optional> #include <vector> #include "lldb/Breakpoint/BreakpointIDList.h" @@ -19,6 +20,7 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/StreamFile.h" +#include "lldb/Host/FileCache.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" @@ -34,9 +36,11 @@ #include "lldb/Target/UnixSignals.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StructuredData.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" @@ -48,8 +52,6 @@ using namespace lldb; using namespace lldb_private; -static uint32_t g_initialize_count = 0; - // Use a singleton function for g_local_platform_sp to avoid init constructors // since LLDB is often part of a shared library static PlatformSP &GetHostPlatformSP() { @@ -134,41 +136,19 @@ void PlatformProperties::SetDefaultModuleCacheDirectory( /// or attaching to processes unless another platform is specified. PlatformSP Platform::GetHostPlatform() { return GetHostPlatformSP(); } -static std::vector<PlatformSP> &GetPlatformList() { - static std::vector<PlatformSP> g_platform_list; - return g_platform_list; -} - -static std::recursive_mutex &GetPlatformListMutex() { - static std::recursive_mutex g_mutex; - return g_mutex; -} - -void Platform::Initialize() { g_initialize_count++; } +void Platform::Initialize() {} -void Platform::Terminate() { - if (g_initialize_count > 0) { - if (--g_initialize_count == 0) { - std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); - GetPlatformList().clear(); - } - } -} +void Platform::Terminate() {} -const PlatformPropertiesSP &Platform::GetGlobalPlatformProperties() { - static const auto g_settings_sp(std::make_shared<PlatformProperties>()); - return g_settings_sp; +PlatformProperties &Platform::GetGlobalPlatformProperties() { + static PlatformProperties g_settings; + return g_settings; } void Platform::SetHostPlatform(const lldb::PlatformSP &platform_sp) { // The native platform should use its static void Platform::Initialize() // function to register itself as the native platform. GetHostPlatformSP() = platform_sp; - - if (platform_sp) { - std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); - GetPlatformList().push_back(platform_sp); - } } Status Platform::GetFileWithUUID(const FileSpec &platform_file, @@ -271,108 +251,15 @@ bool Platform::GetModuleSpec(const FileSpec &module_file_spec, module_spec); } -PlatformSP Platform::Find(ConstString name) { - if (name) { - static ConstString g_host_platform_name("host"); - if (name == g_host_platform_name) - return GetHostPlatform(); - - std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); - for (const auto &platform_sp : GetPlatformList()) { - if (platform_sp->GetName() == name) - return platform_sp; - } - } - return PlatformSP(); -} - -PlatformSP Platform::Create(ConstString name, Status &error) { - PlatformCreateInstance create_callback = nullptr; +PlatformSP Platform::Create(llvm::StringRef name) { lldb::PlatformSP platform_sp; - if (name) { - static ConstString g_host_platform_name("host"); - if (name == g_host_platform_name) - return GetHostPlatform(); - - create_callback = - PluginManager::GetPlatformCreateCallbackForPluginName(name); - if (create_callback) - platform_sp = create_callback(true, nullptr); - else - error.SetErrorStringWithFormat( - "unable to find a plug-in for the platform named \"%s\"", - name.GetCString()); - } else - error.SetErrorString("invalid platform name"); - - if (platform_sp) { - std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); - GetPlatformList().push_back(platform_sp); - } + if (name == GetHostPlatformName()) + return GetHostPlatform(); - return platform_sp; -} - -PlatformSP Platform::Create(const ArchSpec &arch, ArchSpec *platform_arch_ptr, - Status &error) { - lldb::PlatformSP platform_sp; - if (arch.IsValid()) { - // Scope for locker - { - // First try exact arch matches across all platforms already created - std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); - for (const auto &platform_sp : GetPlatformList()) { - if (platform_sp->IsCompatibleArchitecture(arch, true, - platform_arch_ptr)) - return platform_sp; - } - - // Next try compatible arch matches across all platforms already created - for (const auto &platform_sp : GetPlatformList()) { - if (platform_sp->IsCompatibleArchitecture(arch, false, - platform_arch_ptr)) - return platform_sp; - } - } - - PlatformCreateInstance create_callback; - // First try exact arch matches across all platform plug-ins - uint32_t idx; - for (idx = 0; (create_callback = - PluginManager::GetPlatformCreateCallbackAtIndex(idx)); - ++idx) { - if (create_callback) { - platform_sp = create_callback(false, &arch); - if (platform_sp && - platform_sp->IsCompatibleArchitecture(arch, true, - platform_arch_ptr)) { - std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); - GetPlatformList().push_back(platform_sp); - return platform_sp; - } - } - } - // Next try compatible arch matches across all platform plug-ins - for (idx = 0; (create_callback = - PluginManager::GetPlatformCreateCallbackAtIndex(idx)); - ++idx) { - if (create_callback) { - platform_sp = create_callback(false, &arch); - if (platform_sp && - platform_sp->IsCompatibleArchitecture(arch, false, - platform_arch_ptr)) { - std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); - GetPlatformList().push_back(platform_sp); - return platform_sp; - } - } - } - } else - error.SetErrorString("invalid platform name"); - if (platform_arch_ptr) - platform_arch_ptr->Clear(); - platform_sp.reset(); - return platform_sp; + if (PlatformCreateInstance create_callback = + PluginManager::GetPlatformCreateCallbackForPluginName(name)) + return create_callback(true, nullptr); + return nullptr; } ArchSpec Platform::GetAugmentedArchSpec(Platform *platform, llvm::StringRef triple) { @@ -384,29 +271,20 @@ ArchSpec Platform::GetAugmentedArchSpec(Platform *platform, llvm::StringRef trip /// Default Constructor Platform::Platform(bool is_host) : m_is_host(is_host), m_os_version_set_while_connected(false), - m_system_arch_set_while_connected(false), m_sdk_sysroot(), m_sdk_build(), - m_working_dir(), m_remote_url(), m_name(), m_system_arch(), m_mutex(), - m_max_uid_name_len(0), m_max_gid_name_len(0), m_supports_rsync(false), - m_rsync_opts(), m_rsync_prefix(), m_supports_ssh(false), m_ssh_opts(), + m_system_arch_set_while_connected(false), m_max_uid_name_len(0), + m_max_gid_name_len(0), m_supports_rsync(false), m_rsync_opts(), + m_rsync_prefix(), m_supports_ssh(false), m_ssh_opts(), m_ignores_remote_hostname(false), m_trap_handlers(), m_calculated_trap_handlers(false), m_module_cache(std::make_unique<ModuleCache>()) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + Log *log = GetLog(LLDBLog::Object); LLDB_LOGF(log, "%p Platform::Platform()", static_cast<void *>(this)); } -/// Destructor. -/// -/// The destructor is virtual since this class is designed to be -/// inherited from by the plug-in instance. -Platform::~Platform() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); - LLDB_LOGF(log, "%p Platform::~Platform()", static_cast<void *>(this)); -} +Platform::~Platform() = default; void Platform::GetStatus(Stream &strm) { - std::string s; - strm.Printf(" Platform: %s\n", GetPluginName().GetCString()); + strm.Format(" Platform: {0}\n", GetPluginName()); ArchSpec arch(GetSystemArchitecture()); if (arch.IsValid()) { @@ -421,8 +299,8 @@ void Platform::GetStatus(Stream &strm) { if (!os_version.empty()) { strm.Format("OS Version: {0}", os_version.getAsString()); - if (GetOSBuildString(s)) - strm.Printf(" (%s)", s.c_str()); + if (std::optional<std::string> s = GetOSBuildString()) + strm.Format(" ({0})", *s); strm.EOL(); } @@ -436,8 +314,11 @@ void Platform::GetStatus(Stream &strm) { strm.Printf(" Connected: %s\n", is_connected ? "yes" : "no"); } + if (GetSDKRootDirectory()) { + strm.Format(" Sysroot: {0}\n", GetSDKRootDirectory()); + } if (GetWorkingDirectory()) { - strm.Printf("WorkingDir: %s\n", GetWorkingDirectory().GetCString()); + strm.Printf("WorkingDir: %s\n", GetWorkingDirectory().GetPath().c_str()); } if (!IsConnected()) return; @@ -447,8 +328,8 @@ void Platform::GetStatus(Stream &strm) { if (!specific_info.empty()) strm.Printf("Platform-specific connection: %s\n", specific_info.c_str()); - if (GetOSKernelDescription(s)) - strm.Printf(" Kernel: %s\n", s.c_str()); + if (std::optional<std::string> s = GetOSKernelDescription()) + strm.Format(" Kernel: {0}\n", *s); } llvm::VersionTuple Platform::GetOSVersion(Process *process) { @@ -493,28 +374,16 @@ llvm::VersionTuple Platform::GetOSVersion(Process *process) { return llvm::VersionTuple(); } -bool Platform::GetOSBuildString(std::string &s) { - s.clear(); - +std::optional<std::string> Platform::GetOSBuildString() { if (IsHost()) -#if !defined(__linux__) - return HostInfo::GetOSBuildString(s); -#else - return false; -#endif - else - return GetRemoteOSBuildString(s); + return HostInfo::GetOSBuildString(); + return GetRemoteOSBuildString(); } -bool Platform::GetOSKernelDescription(std::string &s) { +std::optional<std::string> Platform::GetOSKernelDescription() { if (IsHost()) -#if !defined(__linux__) - return HostInfo::GetOSKernelDescription(s); -#else - return false; -#endif - else - return GetRemoteOSKernelDescription(s); + return HostInfo::GetOSKernelDescription(); + return GetRemoteOSKernelDescription(); } void Platform::AddClangModuleCompilationOptions( @@ -566,12 +435,13 @@ RecurseCopy_Callback(void *baton, llvm::sys::fs::file_type ft, // make the new directory and get in there FileSpec dst_dir = rc_baton->dst; if (!dst_dir.GetFilename()) - dst_dir.GetFilename() = src.GetLastPathComponent(); + dst_dir.SetFilename(src.GetLastPathComponent()); Status error = rc_baton->platform_ptr->MakeDirectory( dst_dir, lldb::eFilePermissionsDirectoryDefault); if (error.Fail()) { rc_baton->error.SetErrorStringWithFormat( - "unable to setup directory %s on remote end", dst_dir.GetCString()); + "unable to setup directory %s on remote end", + dst_dir.GetPath().c_str()); return FileSystem::eEnumerateDirectoryResultQuit; // got an error, bail out } @@ -581,7 +451,7 @@ RecurseCopy_Callback(void *baton, llvm::sys::fs::file_type ft, // Make a filespec that only fills in the directory of a FileSpec so when // we enumerate we can quickly fill in the filename for dst copies FileSpec recurse_dst; - recurse_dst.GetDirectory().SetCString(dst_dir.GetPath().c_str()); + recurse_dst.SetDirectory(dst_dir.GetPathAsConstString()); RecurseCopyBaton rc_baton2 = {recurse_dst, rc_baton->platform_ptr, Status()}; FileSystem::Instance().EnumerateDirectory(src_dir_path, true, true, true, @@ -597,7 +467,7 @@ RecurseCopy_Callback(void *baton, llvm::sys::fs::file_type ft, // copy the file and keep going FileSpec dst_file = rc_baton->dst; if (!dst_file.GetFilename()) - dst_file.GetFilename() = src.GetFilename(); + dst_file.SetFilename(src.GetFilename()); FileSpec src_resolved; @@ -619,7 +489,7 @@ RecurseCopy_Callback(void *baton, llvm::sys::fs::file_type ft, // copy the file and keep going FileSpec dst_file = rc_baton->dst; if (!dst_file.GetFilename()) - dst_file.GetFilename() = src.GetFilename(); + dst_file.SetFilename(src.GetFilename()); Status err = rc_baton->platform_ptr->PutFile(src, dst_file); if (err.Fail()) { rc_baton->error.SetErrorString(err.AsCString()); @@ -640,13 +510,13 @@ RecurseCopy_Callback(void *baton, llvm::sys::fs::file_type ft, Status Platform::Install(const FileSpec &src, const FileSpec &dst) { Status error; - Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + Log *log = GetLog(LLDBLog::Platform); LLDB_LOGF(log, "Platform::Install (src='%s', dst='%s')", src.GetPath().c_str(), dst.GetPath().c_str()); FileSpec fixed_dst(dst); if (!fixed_dst.GetFilename()) - fixed_dst.GetFilename() = src.GetFilename(); + fixed_dst.SetFilename(src.GetFilename()); FileSpec working_dir = GetWorkingDirectory(); @@ -654,7 +524,7 @@ Status Platform::Install(const FileSpec &src, const FileSpec &dst) { if (dst.GetDirectory()) { const char first_dst_dir_char = dst.GetDirectory().GetCString()[0]; if (first_dst_dir_char == '/' || first_dst_dir_char == '\\') { - fixed_dst.GetDirectory() = dst.GetDirectory(); + fixed_dst.SetDirectory(dst.GetDirectory()); } // If the fixed destination file doesn't have a directory yet, then we // must have a relative path. We will resolve this relative path against @@ -665,7 +535,7 @@ Status Platform::Install(const FileSpec &src, const FileSpec &dst) { if (working_dir) { relative_spec = working_dir; relative_spec.AppendPathComponent(dst.GetPath()); - fixed_dst.GetDirectory() = relative_spec.GetDirectory(); + fixed_dst.SetDirectory(relative_spec.GetDirectory()); } else { error.SetErrorStringWithFormat( "platform working directory must be valid for relative path '%s'", @@ -675,7 +545,7 @@ Status Platform::Install(const FileSpec &src, const FileSpec &dst) { } } else { if (working_dir) { - fixed_dst.GetDirectory().SetCString(working_dir.GetCString()); + fixed_dst.SetDirectory(working_dir.GetPathAsConstString()); } else { error.SetErrorStringWithFormat( "platform working directory must be valid for relative path '%s'", @@ -685,7 +555,7 @@ Status Platform::Install(const FileSpec &src, const FileSpec &dst) { } } else { if (working_dir) { - fixed_dst.GetDirectory().SetCString(working_dir.GetCString()); + fixed_dst.SetDirectory(working_dir.GetPathAsConstString()); } else { error.SetErrorStringWithFormat("platform working directory must be valid " "when destination directory is empty"); @@ -712,7 +582,7 @@ Status Platform::Install(const FileSpec &src, const FileSpec &dst) { // Make a filespec that only fills in the directory of a FileSpec so // when we enumerate we can quickly fill in the filename for dst copies FileSpec recurse_dst; - recurse_dst.GetDirectory().SetCString(fixed_dst.GetCString()); + recurse_dst.SetDirectory(fixed_dst.GetPathAsConstString()); std::string src_dir_path(src.GetPath()); RecurseCopyBaton baton = {recurse_dst, this, Status()}; FileSystem::Instance().EnumerateDirectory( @@ -750,7 +620,7 @@ Status Platform::Install(const FileSpec &src, const FileSpec &dst) { bool Platform::SetWorkingDirectory(const FileSpec &file_spec) { if (IsHost()) { - Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + Log *log = GetLog(LLDBLog::Platform); LLDB_LOG(log, "{0}", file_spec); if (std::error_code ec = llvm::sys::fs::set_current_path(file_spec.GetPath())) { LLDB_LOG(log, "error: {0}", ec.message()); @@ -769,9 +639,8 @@ Status Platform::MakeDirectory(const FileSpec &file_spec, return llvm::sys::fs::create_directory(file_spec.GetPath(), permissions); else { Status error; - error.SetErrorStringWithFormat("remote platform %s doesn't support %s", - GetPluginName().GetCString(), - LLVM_PRETTY_FUNCTION); + error.SetErrorStringWithFormatv("remote platform {0} doesn't support {1}", + GetPluginName(), LLVM_PRETTY_FUNCTION); return error; } } @@ -785,9 +654,8 @@ Status Platform::GetFilePermissions(const FileSpec &file_spec, return Status(Value.getError()); } else { Status error; - error.SetErrorStringWithFormat("remote platform %s doesn't support %s", - GetPluginName().GetCString(), - LLVM_PRETTY_FUNCTION); + error.SetErrorStringWithFormatv("remote platform {0} doesn't support {1}", + GetPluginName(), LLVM_PRETTY_FUNCTION); return error; } } @@ -799,22 +667,69 @@ Status Platform::SetFilePermissions(const FileSpec &file_spec, return llvm::sys::fs::setPermissions(file_spec.GetPath(), Perms); } else { Status error; - error.SetErrorStringWithFormat("remote platform %s doesn't support %s", - GetPluginName().GetCString(), - LLVM_PRETTY_FUNCTION); + error.SetErrorStringWithFormatv("remote platform {0} doesn't support {1}", + GetPluginName(), LLVM_PRETTY_FUNCTION); return error; } } -ConstString Platform::GetName() { return GetPluginName(); } +user_id_t Platform::OpenFile(const FileSpec &file_spec, + File::OpenOptions flags, uint32_t mode, + Status &error) { + if (IsHost()) + return FileCache::GetInstance().OpenFile(file_spec, flags, mode, error); + return UINT64_MAX; +} + +bool Platform::CloseFile(user_id_t fd, Status &error) { + if (IsHost()) + return FileCache::GetInstance().CloseFile(fd, error); + return false; +} + +user_id_t Platform::GetFileSize(const FileSpec &file_spec) { + if (!IsHost()) + return UINT64_MAX; + + uint64_t Size; + if (llvm::sys::fs::file_size(file_spec.GetPath(), Size)) + return 0; + return Size; +} + +uint64_t Platform::ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst, + uint64_t dst_len, Status &error) { + if (IsHost()) + return FileCache::GetInstance().ReadFile(fd, offset, dst, dst_len, error); + error.SetErrorStringWithFormatv( + "Platform::ReadFile() is not supported in the {0} platform", + GetPluginName()); + return -1; +} + +uint64_t Platform::WriteFile(lldb::user_id_t fd, uint64_t offset, + const void *src, uint64_t src_len, Status &error) { + if (IsHost()) + return FileCache::GetInstance().WriteFile(fd, offset, src, src_len, error); + error.SetErrorStringWithFormatv( + "Platform::WriteFile() is not supported in the {0} platform", + GetPluginName()); + return -1; +} + +UserIDResolver &Platform::GetUserIDResolver() { + if (IsHost()) + return HostInfo::GetUserIDResolver(); + return UserIDResolver::GetNoopResolver(); +} const char *Platform::GetHostname() { if (IsHost()) return "127.0.0.1"; - if (m_name.empty()) + if (m_hostname.empty()) return nullptr; - return m_name.c_str(); + return m_hostname.c_str(); } ConstString Platform::GetFullNameForDylib(ConstString basename) { @@ -822,9 +737,9 @@ ConstString Platform::GetFullNameForDylib(ConstString basename) { } bool Platform::SetRemoteWorkingDirectory(const FileSpec &working_dir) { - Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + Log *log = GetLog(LLDBLog::Platform); LLDB_LOGF(log, "Platform::SetRemoteWorkingDirectory('%s')", - working_dir.GetCString()); + working_dir.GetPath().c_str()); m_working_dir = working_dir; return true; } @@ -856,6 +771,7 @@ Platform::ResolveExecutable(const ModuleSpec &module_spec, lldb::ModuleSP &exe_module_sp, const FileSpecList *module_search_paths_ptr) { Status error; + if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) { if (module_spec.GetArchitecture().IsValid()) { error = ModuleList::GetSharedModule(module_spec, exe_module_sp, @@ -866,9 +782,10 @@ Platform::ResolveExecutable(const ModuleSpec &module_spec, // architectures that we should be using (in the correct order) and see // if we can find a match that way ModuleSpec arch_module_spec(module_spec); - for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( - idx, arch_module_spec.GetArchitecture()); - ++idx) { + ArchSpec process_host_arch; + for (const ArchSpec &arch : + GetSupportedArchitectures(process_host_arch)) { + arch_module_spec.GetArchitecture() = arch; error = ModuleList::GetSharedModule(arch_module_spec, exe_module_sp, module_search_paths_ptr, nullptr, nullptr); @@ -878,12 +795,78 @@ Platform::ResolveExecutable(const ModuleSpec &module_spec, } } } else { - error.SetErrorStringWithFormat("'%s' does not exist", - module_spec.GetFileSpec().GetPath().c_str()); + error.SetErrorStringWithFormat( + "'%s' does not exist", module_spec.GetFileSpec().GetPath().c_str()); } return error; } +Status +Platform::ResolveRemoteExecutable(const ModuleSpec &module_spec, + lldb::ModuleSP &exe_module_sp, + const FileSpecList *module_search_paths_ptr) { + Status error; + + // We may connect to a process and use the provided executable (Don't use + // local $PATH). + ModuleSpec resolved_module_spec(module_spec); + + // Resolve any executable within a bundle on MacOSX + Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec()); + + if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()) || + module_spec.GetUUID().IsValid()) { + if (resolved_module_spec.GetArchitecture().IsValid() || + resolved_module_spec.GetUUID().IsValid()) { + error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, + module_search_paths_ptr, nullptr, + nullptr); + + if (exe_module_sp && exe_module_sp->GetObjectFile()) + return error; + exe_module_sp.reset(); + } + // No valid architecture was specified or the exact arch wasn't found so + // ask the platform for the architectures that we should be using (in the + // correct order) and see if we can find a match that way + StreamString arch_names; + llvm::ListSeparator LS; + ArchSpec process_host_arch; + for (const ArchSpec &arch : GetSupportedArchitectures(process_host_arch)) { + resolved_module_spec.GetArchitecture() = arch; + error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, + module_search_paths_ptr, nullptr, + nullptr); + // Did we find an executable using one of the + if (error.Success()) { + if (exe_module_sp && exe_module_sp->GetObjectFile()) + break; + else + error.SetErrorToGenericError(); + } + + arch_names << LS << arch.GetArchitectureName(); + } + + if (error.Fail() || !exe_module_sp) { + if (FileSystem::Instance().Readable(resolved_module_spec.GetFileSpec())) { + error.SetErrorStringWithFormatv( + "'{0}' doesn't contain any '{1}' platform architectures: {2}", + resolved_module_spec.GetFileSpec(), GetPluginName(), + arch_names.GetData()); + } else { + error.SetErrorStringWithFormatv("'{0}' is not readable", + resolved_module_spec.GetFileSpec()); + } + } + } else { + error.SetErrorStringWithFormatv("'{0}' does not exist", + resolved_module_spec.GetFileSpec()); + } + + return error; +} + Status Platform::ResolveSymbolFile(Target &target, const ModuleSpec &sym_spec, FileSpec &sym_file) { Status error; @@ -947,7 +930,8 @@ ArchSpec Platform::GetAugmentedArchSpec(llvm::StringRef triple) { ArchSpec compatible_arch; ArchSpec raw_arch(triple); - if (!IsCompatibleArchitecture(raw_arch, false, &compatible_arch)) + if (!IsCompatibleArchitecture(raw_arch, {}, ArchSpec::CompatibleMatch, + &compatible_arch)) return raw_arch; if (!compatible_arch.IsValid()) @@ -966,26 +950,27 @@ ArchSpec Platform::GetAugmentedArchSpec(llvm::StringRef triple) { Status Platform::ConnectRemote(Args &args) { Status error; if (IsHost()) - error.SetErrorStringWithFormat("The currently selected platform (%s) is " - "the host platform and is always connected.", - GetPluginName().GetCString()); + error.SetErrorStringWithFormatv( + "The currently selected platform ({0}) is " + "the host platform and is always connected.", + GetPluginName()); else - error.SetErrorStringWithFormat( - "Platform::ConnectRemote() is not supported by %s", - GetPluginName().GetCString()); + error.SetErrorStringWithFormatv( + "Platform::ConnectRemote() is not supported by {0}", GetPluginName()); return error; } Status Platform::DisconnectRemote() { Status error; if (IsHost()) - error.SetErrorStringWithFormat("The currently selected platform (%s) is " - "the host platform and is always connected.", - GetPluginName().GetCString()); + error.SetErrorStringWithFormatv( + "The currently selected platform ({0}) is " + "the host platform and is always connected.", + GetPluginName()); else - error.SetErrorStringWithFormat( - "Platform::DisconnectRemote() is not supported by %s", - GetPluginName().GetCString()); + error.SetErrorStringWithFormatv( + "Platform::DisconnectRemote() is not supported by {0}", + GetPluginName()); return error; } @@ -1010,7 +995,7 @@ uint32_t Platform::FindProcesses(const ProcessInstanceInfoMatch &match_info, Status Platform::LaunchProcess(ProcessLaunchInfo &launch_info) { Status error; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + Log *log = GetLog(LLDBLog::Platform); LLDB_LOGF(log, "Platform::%s()", __FUNCTION__); // Take care of the host case so that each subclass can just call this @@ -1063,39 +1048,22 @@ Status Platform::ShellExpandArguments(ProcessLaunchInfo &launch_info) { } Status Platform::KillProcess(const lldb::pid_t pid) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + Log *log = GetLog(LLDBLog::Platform); LLDB_LOGF(log, "Platform::%s, pid %" PRIu64, __FUNCTION__, pid); - // Try to find a process plugin to handle this Kill request. If we can't, - // fall back to the default OS implementation. - size_t num_debuggers = Debugger::GetNumDebuggers(); - for (size_t didx = 0; didx < num_debuggers; ++didx) { - DebuggerSP debugger = Debugger::GetDebuggerAtIndex(didx); - lldb_private::TargetList &targets = debugger->GetTargetList(); - for (int tidx = 0; tidx < targets.GetNumTargets(); ++tidx) { - ProcessSP process = targets.GetTargetAtIndex(tidx)->GetProcessSP(); - if (process->GetID() == pid) - return process->Destroy(true); - } - } - if (!IsHost()) { return Status( - "base lldb_private::Platform class can't kill remote processes unless " - "they are controlled by a process plugin"); + "base lldb_private::Platform class can't kill remote processes"); } - Host::Kill(pid, SIGTERM); + Host::Kill(pid, SIGKILL); return Status(); } -lldb::ProcessSP -Platform::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, - Target *target, // Can be nullptr, if nullptr create a - // new target, else use existing one - Status &error) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); - LLDB_LOGF(log, "Platform::%s entered (target %p)", __FUNCTION__, - static_cast<void *>(target)); +lldb::ProcessSP Platform::DebugProcess(ProcessLaunchInfo &launch_info, + Debugger &debugger, Target &target, + Status &error) { + Log *log = GetLog(LLDBLog::Platform); + LLDB_LOG(log, "target = {0})", &target); ProcessSP process_sp; // Make sure we stop at the entry point @@ -1117,7 +1085,7 @@ Platform::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, filter_callback = get_filter_func(++i, iteration_complete)) { if (filter_callback) { // Give this ProcessLaunchInfo filter a chance to adjust the launch info. - error = (*filter_callback)(launch_info, target); + error = (*filter_callback)(launch_info, &target); if (!error.Success()) { LLDB_LOGF(log, "Platform::%s() StructuredDataPlugin launch " @@ -1135,10 +1103,10 @@ Platform::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, __FUNCTION__, launch_info.GetProcessID()); if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { ProcessAttachInfo attach_info(launch_info); - process_sp = Attach(attach_info, debugger, target, error); + process_sp = Attach(attach_info, debugger, &target, error); if (process_sp) { - LLDB_LOGF(log, "Platform::%s Attach() succeeded, Process plugin: %s", - __FUNCTION__, process_sp->GetPluginName().AsCString()); + LLDB_LOG(log, "Attach() succeeded, Process plugin: {0}", + process_sp->GetPluginName()); launch_info.SetHijackListener(attach_info.GetHijackListener()); // Since we attached to the process, it will think it needs to detach @@ -1149,7 +1117,7 @@ Platform::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, // If we didn't have any file actions, the pseudo terminal might have // been used where the secondary side was given as the file to open for - // stdin/out/err after we have already opened the master so we can + // stdin/out/err after we have already opened the primary so we can // read/write stdin/out/err. int pty_fd = launch_info.GetPTY().ReleasePrimaryFileDescriptor(); if (pty_fd != PseudoTerminal::invalid_fd) { @@ -1173,44 +1141,34 @@ Platform::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, return process_sp; } -lldb::PlatformSP -Platform::GetPlatformForArchitecture(const ArchSpec &arch, - ArchSpec *platform_arch_ptr) { - lldb::PlatformSP platform_sp; - Status error; - if (arch.IsValid()) - platform_sp = Platform::Create(arch, platform_arch_ptr, error); - return platform_sp; +std::vector<ArchSpec> +Platform::CreateArchList(llvm::ArrayRef<llvm::Triple::ArchType> archs, + llvm::Triple::OSType os) { + std::vector<ArchSpec> list; + for(auto arch : archs) { + llvm::Triple triple; + triple.setArch(arch); + triple.setOS(os); + list.push_back(ArchSpec(triple)); + } + return list; } /// Lets a platform answer if it is compatible with a given /// architecture and the target triple contained within. bool Platform::IsCompatibleArchitecture(const ArchSpec &arch, - bool exact_arch_match, + const ArchSpec &process_host_arch, + ArchSpec::MatchType match, ArchSpec *compatible_arch_ptr) { // If the architecture is invalid, we must answer true... if (arch.IsValid()) { ArchSpec platform_arch; - // Try for an exact architecture match first. - if (exact_arch_match) { - for (uint32_t arch_idx = 0; - GetSupportedArchitectureAtIndex(arch_idx, platform_arch); - ++arch_idx) { - if (arch.IsExactMatch(platform_arch)) { - if (compatible_arch_ptr) - *compatible_arch_ptr = platform_arch; - return true; - } - } - } else { - for (uint32_t arch_idx = 0; - GetSupportedArchitectureAtIndex(arch_idx, platform_arch); - ++arch_idx) { - if (arch.IsCompatibleMatch(platform_arch)) { - if (compatible_arch_ptr) - *compatible_arch_ptr = platform_arch; - return true; - } + for (const ArchSpec &platform_arch : + GetSupportedArchitectures(process_host_arch)) { + if (arch.IsMatch(platform_arch, match)) { + if (compatible_arch_ptr) + *compatible_arch_ptr = platform_arch; + return true; } } } @@ -1221,11 +1179,11 @@ bool Platform::IsCompatibleArchitecture(const ArchSpec &arch, Status Platform::PutFile(const FileSpec &source, const FileSpec &destination, uint32_t uid, uint32_t gid) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + Log *log = GetLog(LLDBLog::Platform); LLDB_LOGF(log, "[PutFile] Using block by block transfer....\n"); auto source_open_options = - File::eOpenOptionRead | File::eOpenOptionCloseOnExec; + File::eOpenOptionReadOnly | File::eOpenOptionCloseOnExec; namespace fs = llvm::sys::fs; if (fs::is_symlink_file(source.GetPath())) source_open_options |= File::eOpenOptionDontFollowSymlinks; @@ -1240,7 +1198,7 @@ Status Platform::PutFile(const FileSpec &source, const FileSpec &destination, permissions = lldb::eFilePermissionsFileDefault; lldb::user_id_t dest_file = OpenFile( - destination, File::eOpenOptionCanCreate | File::eOpenOptionWrite | + destination, File::eOpenOptionCanCreate | File::eOpenOptionWriteOnly | File::eOpenOptionTruncate | File::eOpenOptionCloseOnExec, permissions, error); LLDB_LOGF(log, "dest_file = %" PRIu64 "\n", dest_file); @@ -1249,7 +1207,7 @@ Status Platform::PutFile(const FileSpec &source, const FileSpec &destination, return error; if (dest_file == UINT64_MAX) return Status("unable to open target file"); - lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024 * 16, 0)); + lldb::WritableDataBufferSP buffer_sp(new DataBufferHeap(1024 * 16, 0)); uint64_t offset = 0; for (;;) { size_t bytes_read = buffer_sp->GetByteSize(); @@ -1288,17 +1246,21 @@ Status Platform::CreateSymlink(const FileSpec &src, // The name of the link is in src const FileSpec &dst) // The symlink points to dst { - Status error("unimplemented"); - return error; + if (IsHost()) + return FileSystem::Instance().Symlink(src, dst); + return Status("unimplemented"); } bool Platform::GetFileExists(const lldb_private::FileSpec &file_spec) { + if (IsHost()) + return FileSystem::Instance().Exists(file_spec); return false; } Status Platform::Unlink(const FileSpec &path) { - Status error("unimplemented"); - return error; + if (IsHost()) + return llvm::sys::fs::remove(path.GetPath()); + return Status("unimplemented"); } MmapArgList Platform::GetMmapArgumentList(const ArchSpec &arch, addr_t addr, @@ -1344,8 +1306,7 @@ lldb_private::Status Platform::RunShellCommand( if (IsHost()) return Host::RunShellCommand(shell, command, working_dir, status_ptr, signo_ptr, command_output, timeout); - else - return Status("unimplemented"); + return Status("unable to run a remote command without a platform"); } bool Platform::CalculateMD5(const FileSpec &file_spec, uint64_t &low, @@ -1397,7 +1358,7 @@ static constexpr OptionDefinition g_caching_option_table[] = { }; llvm::ArrayRef<OptionDefinition> OptionGroupPlatformRSync::GetDefinitions() { - return llvm::makeArrayRef(g_rsync_option_table); + return llvm::ArrayRef(g_rsync_option_table); } void OptionGroupPlatformRSync::OptionParsingStarting( @@ -1445,7 +1406,7 @@ Platform::SetThreadCreationBreakpoint(lldb_private::Target &target) { } llvm::ArrayRef<OptionDefinition> OptionGroupPlatformSSH::GetDefinitions() { - return llvm::makeArrayRef(g_ssh_option_table); + return llvm::ArrayRef(g_ssh_option_table); } void OptionGroupPlatformSSH::OptionParsingStarting( @@ -1478,7 +1439,7 @@ OptionGroupPlatformSSH::SetOptionValue(uint32_t option_idx, } llvm::ArrayRef<OptionDefinition> OptionGroupPlatformCaching::GetDefinitions() { - return llvm::makeArrayRef(g_caching_option_table); + return llvm::ArrayRef(g_caching_option_table); } void OptionGroupPlatformCaching::OptionParsingStarting( @@ -1504,7 +1465,11 @@ lldb_private::Status OptionGroupPlatformCaching::SetOptionValue( return error; } -Environment Platform::GetEnvironment() { return Environment(); } +Environment Platform::GetEnvironment() { + if (IsHost()) + return Host::GetEnvironment(); + return Environment(); +} const std::vector<ConstString> &Platform::GetTrapHandlerSymbolNames() { if (!m_calculated_trap_handlers) { @@ -1517,12 +1482,18 @@ const std::vector<ConstString> &Platform::GetTrapHandlerSymbolNames() { return m_trap_handlers; } -Status Platform::GetCachedExecutable( - ModuleSpec &module_spec, lldb::ModuleSP &module_sp, - const FileSpecList *module_search_paths_ptr, Platform &remote_platform) { - const auto platform_spec = module_spec.GetFileSpec(); - const auto error = LoadCachedExecutable( - module_spec, module_sp, module_search_paths_ptr, remote_platform); +Status +Platform::GetCachedExecutable(ModuleSpec &module_spec, + lldb::ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr) { + FileSpec platform_spec = module_spec.GetFileSpec(); + Status error = GetRemoteSharedModule( + module_spec, nullptr, module_sp, + [&](const ModuleSpec &spec) { + return ResolveRemoteExecutable(spec, module_sp, + module_search_paths_ptr); + }, + nullptr); if (error.Success()) { module_spec.GetFileSpec() = module_sp->GetFileSpec(); module_spec.GetPlatformFileSpec() = platform_spec; @@ -1531,17 +1502,6 @@ Status Platform::GetCachedExecutable( return error; } -Status Platform::LoadCachedExecutable( - const ModuleSpec &module_spec, lldb::ModuleSP &module_sp, - const FileSpecList *module_search_paths_ptr, Platform &remote_platform) { - return GetRemoteSharedModule(module_spec, nullptr, module_sp, - [&](const ModuleSpec &spec) { - return remote_platform.ResolveExecutable( - spec, module_sp, module_search_paths_ptr); - }, - nullptr); -} - Status Platform::GetRemoteSharedModule(const ModuleSpec &module_spec, Process *process, lldb::ModuleSP &module_sp, @@ -1549,8 +1509,10 @@ Status Platform::GetRemoteSharedModule(const ModuleSpec &module_spec, bool *did_create_ptr) { // Get module information from a target. ModuleSpec resolved_module_spec; + ArchSpec process_host_arch; bool got_module_spec = false; if (process) { + process_host_arch = process->GetSystemArchitecture(); // Try to get module information from the process if (process->GetModuleSpec(module_spec.GetFileSpec(), module_spec.GetArchitecture(), @@ -1568,9 +1530,8 @@ Status Platform::GetRemoteSharedModule(const ModuleSpec &module_spec, // architectures that we should be using (in the correct order) and see if // we can find a match that way ModuleSpec arch_module_spec(module_spec); - for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( - idx, arch_module_spec.GetArchitecture()); - ++idx) { + for (const ArchSpec &arch : GetSupportedArchitectures(process_host_arch)) { + arch_module_spec.GetArchitecture() = arch; error = ModuleList::GetSharedModule(arch_module_spec, module_sp, nullptr, nullptr, nullptr); // Did we find an executable using one of the @@ -1619,11 +1580,11 @@ Status Platform::GetRemoteSharedModule(const ModuleSpec &module_spec, bool Platform::GetCachedSharedModule(const ModuleSpec &module_spec, lldb::ModuleSP &module_sp, bool *did_create_ptr) { - if (IsHost() || !GetGlobalPlatformProperties()->GetUseModuleCache() || - !GetGlobalPlatformProperties()->GetModuleCacheDirectory()) + if (IsHost() || !GetGlobalPlatformProperties().GetUseModuleCache() || + !GetGlobalPlatformProperties().GetModuleCacheDirectory()) return false; - Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + Log *log = GetLog(LLDBLog::Platform); // Check local cache for a module. auto error = m_module_cache->GetAndPut( @@ -1663,7 +1624,7 @@ Status Platform::DownloadModuleSlice(const FileSpec &src_file_spec, return error; } - auto src_fd = OpenFile(src_file_spec, File::eOpenOptionRead, + auto src_fd = OpenFile(src_file_spec, File::eOpenOptionReadOnly, lldb::eFilePermissionsFileDefault, error); if (error.Fail()) { @@ -1704,8 +1665,8 @@ Status Platform::DownloadSymbolFile(const lldb::ModuleSP &module_sp, } FileSpec Platform::GetModuleCacheRoot() { - auto dir_spec = GetGlobalPlatformProperties()->GetModuleCacheDirectory(); - dir_spec.AppendPathComponent(GetName().AsCString()); + auto dir_spec = GetGlobalPlatformProperties().GetModuleCacheDirectory(); + dir_spec.AppendPathComponent(GetPluginName()); return dir_spec; } @@ -1812,25 +1773,21 @@ lldb::ProcessSP Platform::DoConnectProcess(llvm::StringRef connect_url, error.Clear(); if (!target) { - ArchSpec arch; - if (target && target->GetArchitecture().IsValid()) - arch = target->GetArchitecture(); - else - arch = Target::GetDefaultArchitecture(); + ArchSpec arch = Target::GetDefaultArchitecture(); - const char *triple = ""; - if (arch.IsValid()) - triple = arch.GetTriple().getTriple().c_str(); + const char *triple = + arch.IsValid() ? arch.GetTriple().getTriple().c_str() : ""; TargetSP new_target_sp; error = debugger.GetTargetList().CreateTarget( debugger, "", triple, eLoadDependentsNo, nullptr, new_target_sp); + target = new_target_sp.get(); + if (!target || error.Fail()) { + return nullptr; + } } - if (!target || error.Fail()) - return nullptr; - lldb::ProcessSP process_sp = target->CreateProcess(debugger.GetListener(), plugin_name, nullptr, true); @@ -1854,7 +1811,7 @@ lldb::ProcessSP Platform::DoConnectProcess(llvm::StringRef connect_url, if (synchronous) { EventSP event_sp; - process_sp->WaitForProcessToStop(llvm::None, &event_sp, true, listener_sp, + process_sp->WaitForProcessToStop(std::nullopt, &event_sp, true, listener_sp, nullptr); process_sp->RestoreProcessEvents(); bool pop_process_io_handler = false; @@ -1970,6 +1927,27 @@ size_t Platform::GetSoftwareBreakpointTrapOpcode(Target &target, trap_opcode_size = sizeof(g_i386_opcode); } break; + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: { + static const uint8_t g_riscv_opcode[] = {0x73, 0x00, 0x10, 0x00}; // ebreak + static const uint8_t g_riscv_opcode_c[] = {0x02, 0x90}; // c.ebreak + if (arch.GetFlags() & ArchSpec::eRISCV_rvc) { + trap_opcode = g_riscv_opcode_c; + trap_opcode_size = sizeof(g_riscv_opcode_c); + } else { + trap_opcode = g_riscv_opcode; + trap_opcode_size = sizeof(g_riscv_opcode); + } + } break; + + case llvm::Triple::loongarch32: + case llvm::Triple::loongarch64: { + static const uint8_t g_loongarch_opcode[] = {0x05, 0x00, 0x2a, + 0x00}; // break 0x5 + trap_opcode = g_loongarch_opcode; + trap_opcode_size = sizeof(g_loongarch_opcode); + } break; + default: return 0; } @@ -1980,3 +1958,157 @@ size_t Platform::GetSoftwareBreakpointTrapOpcode(Target &target, return 0; } + +CompilerType Platform::GetSiginfoType(const llvm::Triple& triple) { + return CompilerType(); +} + +Args Platform::GetExtraStartupCommands() { + return {}; +} + +PlatformSP PlatformList::GetOrCreate(llvm::StringRef name) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + for (const PlatformSP &platform_sp : m_platforms) { + if (platform_sp->GetName() == name) + return platform_sp; + } + return Create(name); +} + +PlatformSP PlatformList::GetOrCreate(const ArchSpec &arch, + const ArchSpec &process_host_arch, + ArchSpec *platform_arch_ptr, + Status &error) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + // First try exact arch matches across all platforms already created + for (const auto &platform_sp : m_platforms) { + if (platform_sp->IsCompatibleArchitecture( + arch, process_host_arch, ArchSpec::ExactMatch, platform_arch_ptr)) + return platform_sp; + } + + // Next try compatible arch matches across all platforms already created + for (const auto &platform_sp : m_platforms) { + if (platform_sp->IsCompatibleArchitecture(arch, process_host_arch, + ArchSpec::CompatibleMatch, + platform_arch_ptr)) + return platform_sp; + } + + PlatformCreateInstance create_callback; + // First try exact arch matches across all platform plug-ins + uint32_t idx; + for (idx = 0; + (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex(idx)); + ++idx) { + PlatformSP platform_sp = create_callback(false, &arch); + if (platform_sp && + platform_sp->IsCompatibleArchitecture( + arch, process_host_arch, ArchSpec::ExactMatch, platform_arch_ptr)) { + m_platforms.push_back(platform_sp); + return platform_sp; + } + } + // Next try compatible arch matches across all platform plug-ins + for (idx = 0; + (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex(idx)); + ++idx) { + PlatformSP platform_sp = create_callback(false, &arch); + if (platform_sp && platform_sp->IsCompatibleArchitecture( + arch, process_host_arch, ArchSpec::CompatibleMatch, + platform_arch_ptr)) { + m_platforms.push_back(platform_sp); + return platform_sp; + } + } + if (platform_arch_ptr) + platform_arch_ptr->Clear(); + return nullptr; +} + +PlatformSP PlatformList::GetOrCreate(const ArchSpec &arch, + const ArchSpec &process_host_arch, + ArchSpec *platform_arch_ptr) { + Status error; + if (arch.IsValid()) + return GetOrCreate(arch, process_host_arch, platform_arch_ptr, error); + return nullptr; +} + +PlatformSP PlatformList::GetOrCreate(llvm::ArrayRef<ArchSpec> archs, + const ArchSpec &process_host_arch, + std::vector<PlatformSP> &candidates) { + candidates.clear(); + candidates.reserve(archs.size()); + + if (archs.empty()) + return nullptr; + + PlatformSP host_platform_sp = Platform::GetHostPlatform(); + + // Prefer the selected platform if it matches at least one architecture. + if (m_selected_platform_sp) { + for (const ArchSpec &arch : archs) { + if (m_selected_platform_sp->IsCompatibleArchitecture( + arch, process_host_arch, ArchSpec::CompatibleMatch, nullptr)) + return m_selected_platform_sp; + } + } + + // Prefer the host platform if it matches at least one architecture. + if (host_platform_sp) { + for (const ArchSpec &arch : archs) { + if (host_platform_sp->IsCompatibleArchitecture( + arch, process_host_arch, ArchSpec::CompatibleMatch, nullptr)) + return host_platform_sp; + } + } + + // Collect a list of candidate platforms for the architectures. + for (const ArchSpec &arch : archs) { + if (PlatformSP platform = GetOrCreate(arch, process_host_arch, nullptr)) + candidates.push_back(platform); + } + + // The selected or host platform didn't match any of the architectures. If + // the same platform supports all architectures then that's the obvious next + // best thing. + if (candidates.size() == archs.size()) { + if (llvm::all_of(candidates, [&](const PlatformSP &p) -> bool { + return p->GetName() == candidates.front()->GetName(); + })) { + return candidates.front(); + } + } + + // At this point we either have no platforms that match the given + // architectures or multiple platforms with no good way to disambiguate + // between them. + return nullptr; +} + +PlatformSP PlatformList::Create(llvm::StringRef name) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + PlatformSP platform_sp = Platform::Create(name); + m_platforms.push_back(platform_sp); + return platform_sp; +} + +bool PlatformList::LoadPlatformBinaryAndSetup(Process *process, + lldb::addr_t addr, bool notify) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + + PlatformCreateInstance create_callback; + for (int idx = 0; + (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex(idx)); + ++idx) { + ArchSpec arch; + PlatformSP platform_sp = create_callback(true, &arch); + if (platform_sp) { + if (platform_sp->LoadPlatformBinaryAndSetup(process, addr, notify)) + return true; + } + } + return false; +} diff --git a/gnu/llvm/lldb/source/Target/Process.cpp b/gnu/llvm/lldb/source/Target/Process.cpp index 8ecc66b592e..e0cca0595ee 100644 --- a/gnu/llvm/lldb/source/Target/Process.cpp +++ b/gnu/llvm/lldb/source/Target/Process.cpp @@ -9,6 +9,7 @@ #include <atomic> #include <memory> #include <mutex> +#include <optional> #include "llvm/ADT/ScopeExit.h" #include "llvm/Support/ScopedPrinter.h" @@ -64,6 +65,7 @@ #include "lldb/Target/ThreadPlanStack.h" #include "lldb/Target/UnixSignals.h" #include "lldb/Utility/Event.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/NameMatches.h" #include "lldb/Utility/ProcessInfo.h" @@ -110,6 +112,19 @@ public: } }; +static constexpr OptionEnumValueElement g_follow_fork_mode_values[] = { + { + eFollowParent, + "parent", + "Continue tracing the parent process and detach the child.", + }, + { + eFollowChild, + "child", + "Trace the child process and detach the parent.", + }, +}; + #define LLDB_PROPERTIES_process #include "TargetProperties.inc" @@ -153,10 +168,10 @@ ProcessProperties::ProcessProperties(lldb_private::Process *process) m_collection_sp->Initialize(g_process_properties); m_collection_sp->AppendProperty( ConstString("thread"), ConstString("Settings specific to threads."), - true, Thread::GetGlobalProperties()->GetValueProperties()); + true, Thread::GetGlobalProperties().GetValueProperties()); } else { m_collection_sp = - OptionValueProperties::CreateLocalCopy(*Process::GetGlobalProperties()); + OptionValueProperties::CreateLocalCopy(Process::GetGlobalProperties()); m_collection_sp->SetValueChangedCallback( ePropertyPythonOSPluginPath, [this] { m_process->LoadOperatingSystemPlugin(true); }); @@ -334,6 +349,12 @@ void ProcessProperties::SetOSPluginReportsAllThreads(bool does_report) { nullptr, ePropertyOSPluginReportsAllThreads, does_report); } +FollowForkMode ProcessProperties::GetFollowForkMode() const { + const uint32_t idx = ePropertyFollowForkMode; + return (FollowForkMode)m_collection_sp->GetPropertyAtIndexAsEnumeration( + nullptr, idx, g_process_properties[idx].default_uint_value); +} + ProcessSP Process::FindPlugin(lldb::TargetSP target_sp, llvm::StringRef plugin_name, ListenerSP listener_sp, @@ -344,9 +365,8 @@ ProcessSP Process::FindPlugin(lldb::TargetSP target_sp, ProcessSP process_sp; ProcessCreateInstance create_callback = nullptr; if (!plugin_name.empty()) { - ConstString const_plugin_name(plugin_name); create_callback = - PluginManager::GetProcessCreateCallbackForPluginName(const_plugin_name); + PluginManager::GetProcessCreateCallbackForPluginName(plugin_name); if (create_callback) { process_sp = create_callback(target_sp, listener_sp, crash_file_path, can_connect); @@ -414,14 +434,15 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp, m_profile_data_comm_mutex(), m_profile_data(), m_iohandler_sync(0), m_memory_cache(*this), m_allocated_memory_cache(*this), m_should_detach(false), m_next_event_action_up(), m_public_run_lock(), - m_private_run_lock(), m_finalizing(false), + m_private_run_lock(), m_currently_handling_do_on_removals(false), + m_resume_requested(false), m_finalizing(false), m_clear_thread_plans_on_stop(false), m_force_next_event_delivery(false), m_last_broadcast_state(eStateInvalid), m_destroy_in_process(false), - m_can_interpret_function_calls(false), m_warnings_issued(), - m_run_thread_plan_lock(), m_can_jit(eCanJITDontKnow) { + m_can_interpret_function_calls(false), m_run_thread_plan_lock(), + m_can_jit(eCanJITDontKnow) { CheckInWithManager(); - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + Log *log = GetLog(LLDBLog::Object); LLDB_LOGF(log, "%p Process::Process()", static_cast<void *>(this)); if (!m_unix_signals_sp) @@ -471,7 +492,7 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp, } Process::~Process() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + Log *log = GetLog(LLDBLog::Object); LLDB_LOGF(log, "%p Process::~Process()", static_cast<void *>(this)); StopPrivateStateThread(); @@ -481,12 +502,12 @@ Process::~Process() { m_thread_list.Clear(); } -const ProcessPropertiesSP &Process::GetGlobalProperties() { +ProcessProperties &Process::GetGlobalProperties() { // NOTE: intentional leak so we don't crash if global destructor chain gets // called as other threads still use the result of this function - static ProcessPropertiesSP *g_settings_sp_ptr = - new ProcessPropertiesSP(new ProcessProperties(nullptr)); - return *g_settings_sp_ptr; + static ProcessProperties *g_settings_ptr = + new ProcessProperties(nullptr); + return *g_settings_ptr; } void Process::Finalize() { @@ -522,7 +543,7 @@ void Process::Finalize() { m_notifications.swap(empty_notifications); m_image_tokens.clear(); m_memory_cache.Clear(); - m_allocated_memory_cache.Clear(); + m_allocated_memory_cache.Clear(/*deallocate_memory=*/true); { std::lock_guard<std::recursive_mutex> guard(m_language_runtimes_mutex); m_language_runtimes.clear(); @@ -612,7 +633,7 @@ void Process::SyncIOHandler(uint32_t iohandler_id, auto Result = m_iohandler_sync.WaitForValueNotEqualTo(iohandler_id, timeout); - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); if (Result) { LLDB_LOG( log, @@ -639,7 +660,7 @@ StateType Process::WaitForProcessToStop(const Timeout<std::micro> &timeout, if (state == eStateDetached || state == eStateExited) return state; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOG(log, "timeout = {0}", timeout); if (!wait_always && StateIsStoppedState(state, true) && @@ -936,7 +957,7 @@ void Process::RestoreProcessEvents() { RestoreBroadcaster(); } StateType Process::GetStateChangedEvents(EventSP &event_sp, const Timeout<std::micro> &timeout, ListenerSP hijack_listener_sp) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOG(log, "timeout = {0}, event_sp)...", timeout); ListenerSP listener_sp = hijack_listener_sp; @@ -958,7 +979,7 @@ StateType Process::GetStateChangedEvents(EventSP &event_sp, } Event *Process::PeekAtStateChangedEvents() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "Process::%s...", __FUNCTION__); @@ -979,7 +1000,7 @@ Event *Process::PeekAtStateChangedEvents() { StateType Process::GetStateChangedEventsPrivate(EventSP &event_sp, const Timeout<std::micro> &timeout) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOG(log, "timeout = {0}, event_sp)...", timeout); StateType state = eStateInvalid; @@ -998,7 +1019,7 @@ Process::GetStateChangedEventsPrivate(EventSP &event_sp, bool Process::GetEventsPrivate(EventSP &event_sp, const Timeout<std::micro> &timeout, bool control_only) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOG(log, "timeout = {0}, event_sp)...", timeout); if (control_only) @@ -1032,8 +1053,7 @@ bool Process::SetExitStatus(int status, const char *cstr) { // Use a mutex to protect setting the exit status. std::lock_guard<std::mutex> guard(m_exit_status_mutex); - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE | - LIBLLDB_LOG_PROCESS)); + Log *log(GetLog(LLDBLog::State | LLDBLog::Process)); LLDB_LOGF( log, "Process::SetExitStatus (status=%i (0x%8.8x), description=%s%s%s)", status, status, cstr ? "\"" : "", cstr ? cstr : "NULL", cstr ? "\"" : ""); @@ -1088,7 +1108,7 @@ bool Process::SetProcessExitStatus( int signo, // Zero for no signal int exit_status // Exit value of process if signal is zero ) { - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "Process::SetProcessExitStatus (pid=%" PRIu64 ", exited=%i, signal=%i, exit_status=%i)\n", @@ -1274,12 +1294,25 @@ uint32_t Process::AssignIndexIDToThread(uint64_t thread_id) { } StateType Process::GetState() { - return m_public_state.GetValue(); + if (CurrentThreadIsPrivateStateThread()) + return m_private_state.GetValue(); + else + return m_public_state.GetValue(); } void Process::SetPublicState(StateType new_state, bool restarted) { - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE | - LIBLLDB_LOG_PROCESS)); + const bool new_state_is_stopped = StateIsStoppedState(new_state, false); + if (new_state_is_stopped) { + // This will only set the time if the public stop time has no value, so + // it is ok to call this multiple times. With a public stop we can't look + // at the stop ID because many private stops might have happened, so we + // can't check for a stop ID of zero. This allows the "statistics" command + // to dump the time it takes to reach somewhere in your code, like a + // breakpoint you set. + GetTarget().GetStatistics().SetFirstPublicStopTime(); + } + + Log *log(GetLog(LLDBLog::State | LLDBLog::Process)); LLDB_LOGF(log, "Process::SetPublicState (state = %s, restarted = %i)", StateAsCString(new_state), restarted); const StateType old_state = m_public_state.GetValue(); @@ -1296,7 +1329,6 @@ void Process::SetPublicState(StateType new_state, bool restarted) { m_public_run_lock.SetStopped(); } else { const bool old_state_is_stopped = StateIsStoppedState(old_state, false); - const bool new_state_is_stopped = StateIsStoppedState(new_state, false); if ((old_state_is_stopped != new_state_is_stopped)) { if (new_state_is_stopped && !restarted) { LLDB_LOGF(log, "Process::SetPublicState (%s) -- unlocking run lock", @@ -1309,8 +1341,7 @@ void Process::SetPublicState(StateType new_state, bool restarted) { } Status Process::Resume() { - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE | - LIBLLDB_LOG_PROCESS)); + Log *log(GetLog(LLDBLog::State | LLDBLog::Process)); LLDB_LOGF(log, "Process::Resume -- locking run lock"); if (!m_public_run_lock.TrySetRunning()) { Status error("Resume request failed - process still running."); @@ -1328,8 +1359,7 @@ Status Process::Resume() { static const char *g_resume_sync_name = "lldb.Process.ResumeSynchronous.hijack"; Status Process::ResumeSynchronous(Stream *stream) { - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE | - LIBLLDB_LOG_PROCESS)); + Log *log(GetLog(LLDBLog::State | LLDBLog::Process)); LLDB_LOGF(log, "Process::ResumeSynchronous -- locking run lock"); if (!m_public_run_lock.TrySetRunning()) { Status error("Resume request failed - process still running."); @@ -1343,8 +1373,8 @@ Status Process::ResumeSynchronous(Stream *stream) { Status error = PrivateResume(); if (error.Success()) { - StateType state = WaitForProcessToStop(llvm::None, nullptr, true, - listener_sp, stream); + StateType state = + WaitForProcessToStop(std::nullopt, nullptr, true, listener_sp, stream); const bool must_be_alive = false; // eStateExited is ok, so this must be false if (!StateIsStoppedState(state, must_be_alive)) @@ -1388,8 +1418,7 @@ void Process::SetPrivateState(StateType new_state) { if (m_finalizing) return; - Log *log(lldb_private::GetLogIfAnyCategoriesSet( - LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_UNWIND)); + Log *log(GetLog(LLDBLog::State | LLDBLog::Process | LLDBLog::Unwind)); bool state_changed = false; LLDB_LOGF(log, "Process::SetPrivateState (%s)", StateAsCString(new_state)); @@ -1427,7 +1456,9 @@ void Process::SetPrivateState(StateType new_state) { // before we get here. m_thread_list.DidStop(); - m_mod_id.BumpStopID(); + if (m_mod_id.BumpStopID() == 0) + GetTarget().GetStatistics().SetFirstPrivateStopTime(); + if (!m_mod_id.IsLastResumeForUserExpression()) m_mod_id.SetStopEventForLastNaturalStopID(event_sp); m_memory_cache.Clear(); @@ -1725,7 +1756,7 @@ size_t Process::GetSoftwareBreakpointTrapOpcode(BreakpointSite *bp_site) { Status Process::EnableSoftwareBreakpoint(BreakpointSite *bp_site) { Status error; assert(bp_site != nullptr); - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + Log *log = GetLog(LLDBLog::Breakpoints); const addr_t bp_addr = bp_site->GetLoadAddress(); LLDB_LOGF( log, "Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64, @@ -1801,7 +1832,7 @@ Status Process::EnableSoftwareBreakpoint(BreakpointSite *bp_site) { Status Process::DisableSoftwareBreakpoint(BreakpointSite *bp_site) { Status error; assert(bp_site != nullptr); - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + Log *log = GetLog(LLDBLog::Breakpoints); addr_t bp_addr = bp_site->GetLoadAddress(); lldb::user_id_t breakID = bp_site->GetID(); LLDB_LOGF(log, @@ -1893,6 +1924,9 @@ Status Process::DisableSoftwareBreakpoint(BreakpointSite *bp_site) { //#define VERIFY_MEMORY_READS size_t Process::ReadMemory(addr_t addr, void *buf, size_t size, Status &error) { + if (ABISP abi_sp = GetABI()) + addr = abi_sp->FixAnyAddress(addr); + error.Clear(); if (!GetDisableMemoryCache()) { #if defined(VERIFY_MEMORY_READS) @@ -1953,57 +1987,6 @@ size_t Process::ReadCStringFromMemory(addr_t addr, std::string &out_str, return out_str.size(); } -size_t Process::ReadStringFromMemory(addr_t addr, char *dst, size_t max_bytes, - Status &error, size_t type_width) { - size_t total_bytes_read = 0; - if (dst && max_bytes && type_width && max_bytes >= type_width) { - // Ensure a null terminator independent of the number of bytes that is - // read. - memset(dst, 0, max_bytes); - size_t bytes_left = max_bytes - type_width; - - const char terminator[4] = {'\0', '\0', '\0', '\0'}; - assert(sizeof(terminator) >= type_width && "Attempting to validate a " - "string with more than 4 bytes " - "per character!"); - - addr_t curr_addr = addr; - const size_t cache_line_size = m_memory_cache.GetMemoryCacheLineSize(); - char *curr_dst = dst; - - error.Clear(); - while (bytes_left > 0 && error.Success()) { - addr_t cache_line_bytes_left = - cache_line_size - (curr_addr % cache_line_size); - addr_t bytes_to_read = - std::min<addr_t>(bytes_left, cache_line_bytes_left); - size_t bytes_read = ReadMemory(curr_addr, curr_dst, bytes_to_read, error); - - if (bytes_read == 0) - break; - - // Search for a null terminator of correct size and alignment in - // bytes_read - size_t aligned_start = total_bytes_read - total_bytes_read % type_width; - for (size_t i = aligned_start; - i + type_width <= total_bytes_read + bytes_read; i += type_width) - if (::memcmp(&dst[i], terminator, type_width) == 0) { - error.Clear(); - return i; - } - - total_bytes_read += bytes_read; - curr_dst += bytes_read; - curr_addr += bytes_read; - bytes_left -= bytes_read; - } - } else { - if (max_bytes) - error.SetErrorString("invalid arguments"); - } - return total_bytes_read; -} - // Deprecated in favor of ReadStringFromMemory which has wchar support and // correct code to find null terminators. size_t Process::ReadCStringFromMemory(addr_t addr, char *dst, @@ -2056,6 +2039,9 @@ size_t Process::ReadMemoryFromInferior(addr_t addr, void *buf, size_t size, Status &error) { LLDB_SCOPED_TIMER(); + if (ABISP abi_sp = GetABI()) + addr = abi_sp->FixAnyAddress(addr); + if (buf == nullptr || size == 0) return 0; @@ -2138,6 +2124,9 @@ size_t Process::WriteMemoryPrivate(addr_t addr, const void *buf, size_t size, size_t Process::WriteMemory(addr_t addr, const void *buf, size_t size, Status &error) { + if (ABISP abi_sp = GetABI()) + addr = abi_sp->FixAnyAddress(addr); + #if defined(ENABLE_MEMORY_CACHING) m_memory_cache.Flush(addr, size); #endif @@ -2286,7 +2275,7 @@ addr_t Process::AllocateMemory(size_t size, uint32_t permissions, return m_allocated_memory_cache.AllocateMemory(size, permissions, error); #else addr_t allocated_addr = DoAllocateMemory(size, permissions, error); - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "Process::AllocateMemory(size=%" PRIu64 ", permissions=%s) => 0x%16.16" PRIx64 @@ -2310,7 +2299,7 @@ addr_t Process::CallocateMemory(size_t size, uint32_t permissions, bool Process::CanJIT() { if (m_can_jit == eCanJITDontKnow) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); Status err; uint64_t allocated_memory = AllocateMemory( @@ -2356,7 +2345,7 @@ Status Process::DeallocateMemory(addr_t ptr) { #else error = DoDeallocateMemory(ptr); - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "Process::DeallocateMemory(addr=0x%16.16" PRIx64 ") => err = %s (m_stop_id = %u, m_memory_id = %u)", @@ -2369,7 +2358,7 @@ Status Process::DeallocateMemory(addr_t ptr) { ModuleSP Process::ReadModuleFromMemory(const FileSpec &file_spec, lldb::addr_t header_addr, size_t size_to_read) { - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + Log *log = GetLog(LLDBLog::Host); if (log) { LLDB_LOGF(log, "Process::ReadModuleFromMemory reading %s binary from memory", @@ -2454,6 +2443,39 @@ void Process::LoadOperatingSystemPlugin(bool flush) { } Status Process::Launch(ProcessLaunchInfo &launch_info) { + StateType state_after_launch = eStateInvalid; + EventSP first_stop_event_sp; + Status status = + LaunchPrivate(launch_info, state_after_launch, first_stop_event_sp); + if (status.Fail()) + return status; + + if (state_after_launch != eStateStopped && + state_after_launch != eStateCrashed) + return Status(); + + // Note, the stop event was consumed above, but not handled. This + // was done to give DidLaunch a chance to run. The target is either + // stopped or crashed. Directly set the state. This is done to + // prevent a stop message with a bunch of spurious output on thread + // status, as well as not pop a ProcessIOHandler. + SetPublicState(state_after_launch, false); + + if (PrivateStateThreadIsValid()) + ResumePrivateStateThread(); + else + StartPrivateStateThread(); + + // Target was stopped at entry as was intended. Need to notify the + // listeners about it. + if (launch_info.GetFlags().Test(eLaunchFlagStopAtEntry)) + HandlePrivateEvent(first_stop_event_sp); + + return Status(); +} + +Status Process::LaunchPrivate(ProcessLaunchInfo &launch_info, StateType &state, + EventSP &event_sp) { Status error; m_abi_sp.reset(); m_dyld_up.reset(); @@ -2463,118 +2485,124 @@ Status Process::Launch(ProcessLaunchInfo &launch_info) { m_process_input_reader.reset(); Module *exe_module = GetTarget().GetExecutableModulePointer(); + + // The "remote executable path" is hooked up to the local Executable + // module. But we should be able to debug a remote process even if the + // executable module only exists on the remote. However, there needs to + // be a way to express this path, without actually having a module. + // The way to do that is to set the ExecutableFile in the LaunchInfo. + // Figure that out here: + + FileSpec exe_spec_to_use; if (!exe_module) { - error.SetErrorString("executable module does not exist"); - return error; - } + if (!launch_info.GetExecutableFile()) { + error.SetErrorString("executable module does not exist"); + return error; + } + exe_spec_to_use = launch_info.GetExecutableFile(); + } else + exe_spec_to_use = exe_module->GetFileSpec(); - char local_exec_file_path[PATH_MAX]; - char platform_exec_file_path[PATH_MAX]; - exe_module->GetFileSpec().GetPath(local_exec_file_path, - sizeof(local_exec_file_path)); - exe_module->GetPlatformFileSpec().GetPath(platform_exec_file_path, - sizeof(platform_exec_file_path)); - if (FileSystem::Instance().Exists(exe_module->GetFileSpec())) { + if (exe_module && FileSystem::Instance().Exists(exe_module->GetFileSpec())) { // Install anything that might need to be installed prior to launching. // For host systems, this will do nothing, but if we are connected to a // remote platform it will install any needed binaries error = GetTarget().Install(&launch_info); if (error.Fail()) return error; + } - // Listen and queue events that are broadcasted during the process launch. - ListenerSP listener_sp(Listener::MakeListener("LaunchEventHijack")); - HijackProcessEvents(listener_sp); - auto on_exit = llvm::make_scope_exit([this]() { RestoreProcessEvents(); }); + // Listen and queue events that are broadcasted during the process launch. + ListenerSP listener_sp(Listener::MakeListener("LaunchEventHijack")); + HijackProcessEvents(listener_sp); + auto on_exit = llvm::make_scope_exit([this]() { RestoreProcessEvents(); }); - if (PrivateStateThreadIsValid()) - PausePrivateStateThread(); + if (PrivateStateThreadIsValid()) + PausePrivateStateThread(); - error = WillLaunch(exe_module); - if (error.Success()) { - const bool restarted = false; - SetPublicState(eStateLaunching, restarted); - m_should_detach = false; + error = WillLaunch(exe_module); + if (error.Fail()) { + std::string local_exec_file_path = exe_spec_to_use.GetPath(); + return Status("file doesn't exist: '%s'", local_exec_file_path.c_str()); + } - if (m_public_run_lock.TrySetRunning()) { - // Now launch using these arguments. - error = DoLaunch(exe_module, launch_info); - } else { - // This shouldn't happen - error.SetErrorString("failed to acquire process run lock"); - } + const bool restarted = false; + SetPublicState(eStateLaunching, restarted); + m_should_detach = false; - if (error.Fail()) { - if (GetID() != LLDB_INVALID_PROCESS_ID) { - SetID(LLDB_INVALID_PROCESS_ID); - const char *error_string = error.AsCString(); - if (error_string == nullptr) - error_string = "launch failed"; - SetExitStatus(-1, error_string); - } - } else { - EventSP event_sp; - - // Now wait for the process to launch and return control to us, and then - // call DidLaunch: - StateType state = WaitForProcessStopPrivate(event_sp, seconds(10)); - - if (state == eStateInvalid || !event_sp) { - // We were able to launch the process, but we failed to catch the - // initial stop. - error.SetErrorString("failed to catch stop after launch"); - SetExitStatus(0, "failed to catch stop after launch"); - Destroy(false); - } else if (state == eStateStopped || state == eStateCrashed) { - DidLaunch(); - - DynamicLoader *dyld = GetDynamicLoader(); - if (dyld) - dyld->DidLaunch(); - - GetJITLoaders().DidLaunch(); - - SystemRuntime *system_runtime = GetSystemRuntime(); - if (system_runtime) - system_runtime->DidLaunch(); - - if (!m_os_up) - LoadOperatingSystemPlugin(false); - - // We successfully launched the process and stopped, now it the - // right time to set up signal filters before resuming. - UpdateAutomaticSignalFiltering(); - - // Note, the stop event was consumed above, but not handled. This - // was done to give DidLaunch a chance to run. The target is either - // stopped or crashed. Directly set the state. This is done to - // prevent a stop message with a bunch of spurious output on thread - // status, as well as not pop a ProcessIOHandler. - SetPublicState(state, false); - - if (PrivateStateThreadIsValid()) - ResumePrivateStateThread(); - else - StartPrivateStateThread(); + if (m_public_run_lock.TrySetRunning()) { + // Now launch using these arguments. + error = DoLaunch(exe_module, launch_info); + } else { + // This shouldn't happen + error.SetErrorString("failed to acquire process run lock"); + } - // Target was stopped at entry as was intended. Need to notify the - // listeners about it. - if (state == eStateStopped && - launch_info.GetFlags().Test(eLaunchFlagStopAtEntry)) - HandlePrivateEvent(event_sp); - } else if (state == eStateExited) { - // We exited while trying to launch somehow. Don't call DidLaunch - // as that's not likely to work, and return an invalid pid. - HandlePrivateEvent(event_sp); - } - } + if (error.Fail()) { + if (GetID() != LLDB_INVALID_PROCESS_ID) { + SetID(LLDB_INVALID_PROCESS_ID); + const char *error_string = error.AsCString(); + if (error_string == nullptr) + error_string = "launch failed"; + SetExitStatus(-1, error_string); } - } else { - error.SetErrorStringWithFormat("file doesn't exist: '%s'", - local_exec_file_path); + return error; } - return error; + // Now wait for the process to launch and return control to us, and then + // call DidLaunch: + state = WaitForProcessStopPrivate(event_sp, seconds(10)); + + if (state == eStateInvalid || !event_sp) { + // We were able to launch the process, but we failed to catch the + // initial stop. + error.SetErrorString("failed to catch stop after launch"); + SetExitStatus(0, error.AsCString()); + Destroy(false); + return error; + } + + if (state == eStateExited) { + // We exited while trying to launch somehow. Don't call DidLaunch + // as that's not likely to work, and return an invalid pid. + HandlePrivateEvent(event_sp); + return Status(); + } + + if (state == eStateStopped || state == eStateCrashed) { + DidLaunch(); + + // Now that we know the process type, update its signal responses from the + // ones stored in the Target: + if (m_unix_signals_sp) { + StreamSP warning_strm = GetTarget().GetDebugger().GetAsyncErrorStream(); + GetTarget().UpdateSignalsFromDummy(m_unix_signals_sp, warning_strm); + } + + DynamicLoader *dyld = GetDynamicLoader(); + if (dyld) + dyld->DidLaunch(); + + GetJITLoaders().DidLaunch(); + + SystemRuntime *system_runtime = GetSystemRuntime(); + if (system_runtime) + system_runtime->DidLaunch(); + + if (!m_os_up) + LoadOperatingSystemPlugin(false); + + // We successfully launched the process and stopped, now it the + // right time to set up signal filters before resuming. + UpdateAutomaticSignalFiltering(); + return Status(); + } + + return Status("Unexpected process state after the launch: %s, expected %s, " + "%s, %s or %s", + StateAsCString(state), StateAsCString(eStateInvalid), + StateAsCString(eStateExited), StateAsCString(eStateStopped), + StateAsCString(eStateCrashed)); } Status Process::LoadCore() { @@ -2609,10 +2637,10 @@ Status Process::LoadCore() { // Wait for a stopped event since we just posted one above... lldb::EventSP event_sp; StateType state = - WaitForProcessToStop(llvm::None, &event_sp, true, listener_sp); + WaitForProcessToStop(std::nullopt, &event_sp, true, listener_sp); if (!StateIsStoppedState(state, false)) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "Process::Halt() failed to stop, state is: %s", StateAsCString(state)); error.SetErrorString( @@ -2625,12 +2653,20 @@ Status Process::LoadCore() { DynamicLoader *Process::GetDynamicLoader() { if (!m_dyld_up) - m_dyld_up.reset(DynamicLoader::FindPlugin(this, nullptr)); + m_dyld_up.reset(DynamicLoader::FindPlugin(this, "")); return m_dyld_up.get(); } +void Process::SetDynamicLoader(DynamicLoaderUP dyld_up) { + m_dyld_up = std::move(dyld_up); +} + DataExtractor Process::GetAuxvData() { return DataExtractor(); } +llvm::Expected<bool> Process::SaveCore(llvm::StringRef outfile) { + return false; +} + JITLoaderList &Process::GetJITLoaders() { if (!m_jit_loaders_up) { m_jit_loaders_up = std::make_unique<JITLoaderList>(); @@ -2648,7 +2684,7 @@ SystemRuntime *Process::GetSystemRuntime() { Process::AttachCompletionHandler::AttachCompletionHandler(Process *process, uint32_t exec_count) : NextEventAction(process), m_exec_count(exec_count) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF( log, "Process::AttachCompletionHandler::%s process=%p, exec_count=%" PRIu32, @@ -2657,7 +2693,7 @@ Process::AttachCompletionHandler::AttachCompletionHandler(Process *process, Process::NextEventAction::EventActionResult Process::AttachCompletionHandler::PerformAction(lldb::EventSP &event_sp) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); StateType state = ProcessEventData::GetStateFromEvent(event_sp.get()); LLDB_LOGF(log, @@ -2728,6 +2764,19 @@ ListenerSP ProcessAttachInfo::GetListenerForProcess(Debugger &debugger) { return debugger.GetListener(); } +Status Process::WillLaunch(Module *module) { + return DoWillLaunch(module); +} + +Status Process::WillAttachToProcessWithID(lldb::pid_t pid) { + return DoWillAttachToProcessWithID(pid); +} + +Status Process::WillAttachToProcessWithName(const char *process_name, + bool wait_for_launch) { + return DoWillAttachToProcessWithName(process_name, wait_for_launch); +} + Status Process::Attach(ProcessAttachInfo &attach_info) { m_abi_sp.reset(); m_process_input_reader.reset(); @@ -2850,8 +2899,7 @@ Status Process::Attach(ProcessAttachInfo &attach_info) { } void Process::CompleteAttach() { - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | - LIBLLDB_LOG_TARGET)); + Log *log(GetLog(LLDBLog::Process | LLDBLog::Target)); LLDB_LOGF(log, "Process::%s()", __FUNCTION__); // Let the process subclass figure out at much as it can about the process @@ -2875,21 +2923,22 @@ void Process::CompleteAttach() { // switch architectures. PlatformSP platform_sp(GetTarget().GetPlatform()); assert(platform_sp); + ArchSpec process_host_arch = GetSystemArchitecture(); if (platform_sp) { const ArchSpec &target_arch = GetTarget().GetArchitecture(); - if (target_arch.IsValid() && - !platform_sp->IsCompatibleArchitecture(target_arch, false, nullptr)) { + if (target_arch.IsValid() && !platform_sp->IsCompatibleArchitecture( + target_arch, process_host_arch, + ArchSpec::CompatibleMatch, nullptr)) { ArchSpec platform_arch; - platform_sp = - platform_sp->GetPlatformForArchitecture(target_arch, &platform_arch); + platform_sp = GetTarget().GetDebugger().GetPlatformList().GetOrCreate( + target_arch, process_host_arch, &platform_arch); if (platform_sp) { GetTarget().SetPlatform(platform_sp); GetTarget().SetArchitecture(platform_arch); - LLDB_LOGF(log, - "Process::%s switching platform to %s and architecture " - "to %s based on info from attach", - __FUNCTION__, platform_sp->GetName().AsCString(""), - platform_arch.GetTriple().getTriple().c_str()); + LLDB_LOG(log, + "switching platform to {0} and architecture to {1} based on " + "info from attach", + platform_sp->GetName(), platform_arch.GetTriple().getTriple()); } } else if (!process_arch.IsValid()) { ProcessInstanceInfo process_info; @@ -2908,6 +2957,12 @@ void Process::CompleteAttach() { } } } + // Now that we know the process type, update its signal responses from the + // ones stored in the Target: + if (m_unix_signals_sp) { + StreamSP warning_strm = GetTarget().GetDebugger().GetAsyncErrorStream(); + GetTarget().UpdateSignalsFromDummy(m_unix_signals_sp, warning_strm); + } // We have completed the attach, now it is time to find the dynamic loader // plug-in @@ -2916,13 +2971,11 @@ void Process::CompleteAttach() { dyld->DidAttach(); if (log) { ModuleSP exe_module_sp = GetTarget().GetExecutableModule(); - LLDB_LOGF(log, - "Process::%s after DynamicLoader::DidAttach(), target " - "executable is %s (using %s plugin)", - __FUNCTION__, - exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str() - : "<none>", - dyld->GetPluginName().AsCString("<unnamed>")); + LLDB_LOG(log, + "after DynamicLoader::DidAttach(), target " + "executable is {0} (using {1} plugin)", + exe_module_sp ? exe_module_sp->GetFileSpec() : FileSpec(), + dyld->GetPluginName()); } } @@ -2933,13 +2986,11 @@ void Process::CompleteAttach() { system_runtime->DidAttach(); if (log) { ModuleSP exe_module_sp = GetTarget().GetExecutableModule(); - LLDB_LOGF(log, - "Process::%s after SystemRuntime::DidAttach(), target " - "executable is %s (using %s plugin)", - __FUNCTION__, - exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str() - : "<none>", - system_runtime->GetPluginName().AsCString("<unnamed>")); + LLDB_LOG(log, + "after SystemRuntime::DidAttach(), target " + "executable is {0} (using {1} plugin)", + exe_module_sp ? exe_module_sp->GetFileSpec() : FileSpec(), + system_runtime->GetPluginName()); } } @@ -2988,7 +3039,7 @@ Status Process::ConnectRemote(llvm::StringRef remote_url) { if (error.Success()) { if (GetID() != LLDB_INVALID_PROCESS_ID) { EventSP event_sp; - StateType state = WaitForProcessStopPrivate(event_sp, llvm::None); + StateType state = WaitForProcessStopPrivate(event_sp, std::nullopt); if (state == eStateStopped || state == eStateCrashed) { // If we attached and actually have a process on the other end, then @@ -3010,8 +3061,7 @@ Status Process::ConnectRemote(llvm::StringRef remote_url) { } Status Process::PrivateResume() { - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | - LIBLLDB_LOG_STEP)); + Log *log(GetLog(LLDBLog::Process | LLDBLog::Step)); LLDB_LOGF(log, "Process::PrivateResume() m_stop_id = %u, public state: %s " "private state: %s", @@ -3115,7 +3165,7 @@ Status Process::StopForDestroyOrDetach(lldb::EventSP &exit_event_sp) { // still need to interrupt. if (m_public_state.GetValue() == eStateRunning || m_private_state.GetValue() == eStateRunning) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "Process::%s() About to stop.", __FUNCTION__); ListenerSP listener_sp( @@ -3322,8 +3372,7 @@ bool Process::ShouldBroadcastEvent(Event *event_ptr) { const StateType state = Process::ProcessEventData::GetStateFromEvent(event_ptr); bool return_value = true; - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EVENTS | - LIBLLDB_LOG_PROCESS)); + Log *log(GetLog(LLDBLog::Events | LLDBLog::Process)); switch (state) { case eStateDetached: @@ -3334,7 +3383,7 @@ bool Process::ShouldBroadcastEvent(Event *event_ptr) { m_stdio_communication.Disconnect(); m_stdin_forward = false; - LLVM_FALLTHROUGH; + [[fallthrough]]; case eStateConnected: case eStateAttaching: case eStateLaunching: @@ -3474,7 +3523,7 @@ bool Process::ShouldBroadcastEvent(Event *event_ptr) { } bool Process::StartPrivateStateThread(bool is_secondary_thread) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS)); + Log *log = GetLog(LLDBLog::Events); bool already_running = PrivateStateThreadIsValid(); LLDB_LOGF(log, "Process::%s()%s ", __FUNCTION__, @@ -3505,15 +3554,15 @@ bool Process::StartPrivateStateThread(bool is_secondary_thread) { "<lldb.process.internal-state(pid=%" PRIu64 ")>", GetID()); } - // Create the private state thread, and start it running. - PrivateStateThreadArgs *args_ptr = - new PrivateStateThreadArgs(this, is_secondary_thread); llvm::Expected<HostThread> private_state_thread = - ThreadLauncher::LaunchThread(thread_name, Process::PrivateStateThread, - (void *)args_ptr, 8 * 1024 * 1024); + ThreadLauncher::LaunchThread( + thread_name, + [this, is_secondary_thread] { + return RunPrivateStateThread(is_secondary_thread); + }, + 8 * 1024 * 1024); if (!private_state_thread) { - LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST), - "failed to launch host thread: {}", + LLDB_LOG(GetLog(LLDBLog::Host), "failed to launch host thread: {}", llvm::toString(private_state_thread.takeError())); return false; } @@ -3536,7 +3585,7 @@ void Process::StopPrivateStateThread() { if (m_private_state_thread.IsJoinable()) ControlPrivateStateThread(eBroadcastInternalStateControlStop); else { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF( log, "Went to stop the private state thread, but it was already invalid."); @@ -3544,7 +3593,7 @@ void Process::StopPrivateStateThread() { } void Process::ControlPrivateStateThread(uint32_t signal) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); assert(signal == eBroadcastInternalStateControlStop || signal == eBroadcastInternalStateControlPause || @@ -3602,7 +3651,7 @@ void Process::SendAsyncInterrupt() { } void Process::HandlePrivateEvent(EventSP &event_sp) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); m_resume_requested = false; const StateType new_state = @@ -3726,18 +3775,10 @@ Status Process::HaltPrivate() { return error; } -thread_result_t Process::PrivateStateThread(void *arg) { - std::unique_ptr<PrivateStateThreadArgs> args_up( - static_cast<PrivateStateThreadArgs *>(arg)); - thread_result_t result = - args_up->process->RunPrivateStateThread(args_up->is_secondary_thread); - return result; -} - thread_result_t Process::RunPrivateStateThread(bool is_secondary_thread) { bool control_only = true; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "Process::%s (arg = %p, pid = %" PRIu64 ") thread starting...", __FUNCTION__, static_cast<void *>(this), GetID()); @@ -3745,7 +3786,7 @@ thread_result_t Process::RunPrivateStateThread(bool is_secondary_thread) { bool interrupt_requested = false; while (!exit_now) { EventSP event_sp; - GetEventsPrivate(event_sp, llvm::None, control_only); + GetEventsPrivate(event_sp, std::nullopt, control_only); if (event_sp->BroadcasterIs(&m_private_state_control_broadcaster)) { LLDB_LOGF(log, "Process::%s (arg = %p, pid = %" PRIu64 @@ -3865,8 +3906,7 @@ Process::ProcessEventData::ProcessEventData() : EventData(), m_process_wp() {} Process::ProcessEventData::ProcessEventData(const ProcessSP &process_sp, StateType state) - : EventData(), m_process_wp(), m_state(state), m_restarted(false), - m_update_state(0), m_interrupted(false) { + : EventData(), m_process_wp(), m_state(state) { if (process_sp) m_process_wp = process_sp; } @@ -3937,8 +3977,7 @@ bool Process::ProcessEventData::ShouldStop(Event *event_ptr, for (idx = 0; idx < not_suspended_thread_list.GetSize(); ++idx) { curr_thread_list = process_sp->GetThreadList(); if (curr_thread_list.GetSize() != num_threads) { - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP | - LIBLLDB_LOG_PROCESS)); + Log *log(GetLog(LLDBLog::Step | LLDBLog::Process)); LLDB_LOGF( log, "Number of threads changed from %u to %u while processing event.", @@ -3949,8 +3988,7 @@ bool Process::ProcessEventData::ShouldStop(Event *event_ptr, lldb::ThreadSP thread_sp = not_suspended_thread_list.GetThreadAtIndex(idx); if (thread_sp->GetIndexID() != thread_index_array[idx]) { - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP | - LIBLLDB_LOG_PROCESS)); + Log *log(GetLog(LLDBLog::Step | LLDBLog::Process)); LLDB_LOGF(log, "The thread at position %u changed from %u to %u while " "processing event.", @@ -4243,7 +4281,7 @@ size_t Process::GetAsyncProfileData(char *buf, size_t buf_size, Status &error) { std::string &one_profile_data = m_profile_data.front(); size_t bytes_available = one_profile_data.size(); if (bytes_available > 0) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "Process::GetProfileData (buf = %p, size = %" PRIu64 ")", static_cast<void *>(buf), static_cast<uint64_t>(buf_size)); if (bytes_available > buf_size) { @@ -4264,7 +4302,7 @@ size_t Process::GetSTDOUT(char *buf, size_t buf_size, Status &error) { std::lock_guard<std::recursive_mutex> guard(m_stdio_communication_mutex); size_t bytes_available = m_stdout_data.size(); if (bytes_available > 0) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "Process::GetSTDOUT (buf = %p, size = %" PRIu64 ")", static_cast<void *>(buf), static_cast<uint64_t>(buf_size)); if (bytes_available > buf_size) { @@ -4283,7 +4321,7 @@ size_t Process::GetSTDERR(char *buf, size_t buf_size, Status &error) { std::lock_guard<std::recursive_mutex> gaurd(m_stdio_communication_mutex); size_t bytes_available = m_stderr_data.size(); if (bytes_available > 0) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "Process::GetSTDERR (buf = %p, size = %" PRIu64 ")", static_cast<void *>(buf), static_cast<uint64_t>(buf_size)); if (bytes_available > buf_size) { @@ -4310,13 +4348,19 @@ public: : IOHandler(process->GetTarget().GetDebugger(), IOHandler::Type::ProcessIO), m_process(process), - m_read_file(GetInputFD(), File::eOpenOptionRead, false), - m_write_file(write_fd, File::eOpenOptionWrite, false) { + m_read_file(GetInputFD(), File::eOpenOptionReadOnly, false), + m_write_file(write_fd, File::eOpenOptionWriteOnly, false) { m_pipe.CreateNew(false); } ~IOHandlerProcessSTDIO() override = default; + void SetIsRunning(bool running) { + std::lock_guard<std::mutex> guard(m_mutex); + SetIsDone(!running); + m_is_running = running; + } + // Each IOHandler gets to run until it is done. It should read data from the // "in" and place output into "out" and "err and return when done. void Run() override { @@ -4328,58 +4372,60 @@ public: SetIsDone(false); const int read_fd = m_read_file.GetDescriptor(); - TerminalState terminal_state; - terminal_state.Save(read_fd, false); Terminal terminal(read_fd); - terminal.SetCanonical(false); - terminal.SetEcho(false); + TerminalState terminal_state(terminal, false); + // FIXME: error handling? + llvm::consumeError(terminal.SetCanonical(false)); + llvm::consumeError(terminal.SetEcho(false)); // FD_ZERO, FD_SET are not supported on windows #ifndef _WIN32 const int pipe_read_fd = m_pipe.GetReadFileDescriptor(); - m_is_running = true; - while (!GetIsDone()) { + SetIsRunning(true); + while (true) { + { + std::lock_guard<std::mutex> guard(m_mutex); + if (GetIsDone()) + break; + } + SelectHelper select_helper; select_helper.FDSetRead(read_fd); select_helper.FDSetRead(pipe_read_fd); Status error = select_helper.Select(); - if (error.Fail()) { - SetIsDone(true); - } else { - char ch = 0; - size_t n; - if (select_helper.FDIsSetRead(read_fd)) { - n = 1; - if (m_read_file.Read(&ch, n).Success() && n == 1) { - if (m_write_file.Write(&ch, n).Fail() || n != 1) - SetIsDone(true); - } else - SetIsDone(true); - } - if (select_helper.FDIsSetRead(pipe_read_fd)) { - size_t bytes_read; - // Consume the interrupt byte - Status error = m_pipe.Read(&ch, 1, bytes_read); - if (error.Success()) { - switch (ch) { - case 'q': - SetIsDone(true); - break; - case 'i': - if (StateIsRunningState(m_process->GetState())) - m_process->SendAsyncInterrupt(); - break; - } - } + if (error.Fail()) + break; + + char ch = 0; + size_t n; + if (select_helper.FDIsSetRead(read_fd)) { + n = 1; + if (m_read_file.Read(&ch, n).Success() && n == 1) { + if (m_write_file.Write(&ch, n).Fail() || n != 1) + break; + } else + break; + } + + if (select_helper.FDIsSetRead(pipe_read_fd)) { + size_t bytes_read; + // Consume the interrupt byte + Status error = m_pipe.Read(&ch, 1, bytes_read); + if (error.Success()) { + if (ch == 'q') + break; + if (ch == 'i') + if (StateIsRunningState(m_process->GetState())) + m_process->SendAsyncInterrupt(); } } } - m_is_running = false; + SetIsRunning(false); #endif - terminal_state.Restore(); } void Cancel() override { + std::lock_guard<std::mutex> guard(m_mutex); SetIsDone(true); // Only write to our pipe to cancel if we are in // IOHandlerProcessSTDIO::Run(). We can end up with a python command that @@ -4433,10 +4479,11 @@ public: protected: Process *m_process; NativeFile m_read_file; // Read from this file (usually actual STDIN for LLDB - NativeFile m_write_file; // Write to this file (usually the master pty for + NativeFile m_write_file; // Write to this file (usually the primary pty for // getting io to debuggee) Pipe m_pipe; - std::atomic<bool> m_is_running{false}; + std::mutex m_mutex; + bool m_is_running = false; }; void Process::SetSTDIOFileDescriptor(int fd) { @@ -4465,7 +4512,7 @@ bool Process::ProcessIOHandlerIsActive() { bool Process::PushProcessIOHandler() { IOHandlerSP io_handler_sp(m_process_input_reader); if (io_handler_sp) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "Process::%s pushing IO handler", __FUNCTION__); io_handler_sp->SetIsDone(false); @@ -4494,7 +4541,8 @@ void Process::SettingsInitialize() { Thread::SettingsInitialize(); } void Process::SettingsTerminate() { Thread::SettingsTerminate(); } namespace { -// RestorePlanState is used to record the "is private", "is master" and "okay +// RestorePlanState is used to record the "is private", "is controlling" and +// "okay // to discard" fields of the plan we are running, and reset it on Clean or on // destruction. It will only reset the state once, so you can call Clean and // then monkey with the state and it won't get reset on you again. @@ -4502,10 +4550,10 @@ namespace { class RestorePlanState { public: RestorePlanState(lldb::ThreadPlanSP thread_plan_sp) - : m_thread_plan_sp(thread_plan_sp), m_already_reset(false) { + : m_thread_plan_sp(thread_plan_sp) { if (m_thread_plan_sp) { m_private = m_thread_plan_sp->GetPrivate(); - m_is_master = m_thread_plan_sp->IsMasterPlan(); + m_is_controlling = m_thread_plan_sp->IsControllingPlan(); m_okay_to_discard = m_thread_plan_sp->OkayToDiscard(); } } @@ -4516,17 +4564,17 @@ public: if (!m_already_reset && m_thread_plan_sp) { m_already_reset = true; m_thread_plan_sp->SetPrivate(m_private); - m_thread_plan_sp->SetIsMasterPlan(m_is_master); + m_thread_plan_sp->SetIsControllingPlan(m_is_controlling); m_thread_plan_sp->SetOkayToDiscard(m_okay_to_discard); } } private: lldb::ThreadPlanSP m_thread_plan_sp; - bool m_already_reset; - bool m_private; - bool m_is_master; - bool m_okay_to_discard; + bool m_already_reset = false; + bool m_private = false; + bool m_is_controlling = false; + bool m_okay_to_discard = false; }; } // anonymous namespace @@ -4562,18 +4610,18 @@ GetExpressionTimeout(const EvaluateExpressionOptions &options, return GetOneThreadExpressionTimeout(options); if (!options.GetTimeout()) - return llvm::None; + return std::nullopt; else return *options.GetTimeout() - GetOneThreadExpressionTimeout(options); } -static llvm::Optional<ExpressionResults> +static std::optional<ExpressionResults> HandleStoppedEvent(lldb::tid_t thread_id, const ThreadPlanSP &thread_plan_sp, RestorePlanState &restorer, const EventSP &event_sp, EventSP &event_to_broadcast_sp, const EvaluateExpressionOptions &options, bool handle_interrupts) { - Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP | LIBLLDB_LOG_PROCESS); + Log *log = GetLog(LLDBLog::Step | LLDBLog::Process); ThreadSP thread_sp = thread_plan_sp->GetTarget() .GetProcessSP() @@ -4616,7 +4664,7 @@ HandleStoppedEvent(lldb::tid_t thread_id, const ThreadPlanSP &thread_plan_sp, if (!handle_interrupts && Process::ProcessEventData::GetInterruptedFromEvent(event_sp.get())) - return llvm::None; + return std::nullopt; LLDB_LOG(log, "thread plan did not successfully complete"); if (!options.DoesUnwindOnError()) @@ -4676,11 +4724,11 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx, thread_plan_sp->SetPrivate(false); - // The plans run with RunThreadPlan also need to be terminal master plans or - // when they are done we will end up asking the plan above us whether we + // The plans run with RunThreadPlan also need to be terminal controlling plans + // or when they are done we will end up asking the plan above us whether we // should stop, which may give the wrong answer. - thread_plan_sp->SetIsMasterPlan(true); + thread_plan_sp->SetIsControllingPlan(true); thread_plan_sp->SetOkayToDiscard(false); // If we are running some utility expression for LLDB, we now have to mark @@ -4741,8 +4789,7 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx, lldb::StateType old_state = eStateInvalid; lldb::ThreadPlanSP stopper_base_plan_sp; - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP | - LIBLLDB_LOG_PROCESS)); + Log *log(GetLog(LLDBLog::Step | LLDBLog::Process)); if (m_private_state_thread.EqualsThread(Host::GetCurrentThread())) { // Yikes, we are running on the private state thread! So we can't wait for // public events on this thread, since we are the thread that is generating @@ -5509,7 +5556,7 @@ size_t Process::GetThreadStatus(Stream &strm, stop_format); ++num_thread_infos_dumped; } else { - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "Process::GetThreadStatus - thread 0x" PRIu64 " vanished while running Thread::GetStatus."); } @@ -5597,7 +5644,7 @@ lldb::addr_t Process::GetDataAddressMask() { } void Process::DidExec() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "Process::%s()", __FUNCTION__); Target &target = GetTarget(); @@ -5610,7 +5657,9 @@ void Process::DidExec() { m_dyld_up.reset(); m_jit_loaders_up.reset(); m_image_tokens.clear(); - m_allocated_memory_cache.Clear(); + // After an exec, the inferior is a new process and these memory regions are + // no longer allocated. + m_allocated_memory_cache.Clear(/*deallocte_memory=*/false); { std::lock_guard<std::recursive_mutex> guard(m_language_runtimes_mutex); m_language_runtimes.clear(); @@ -5694,48 +5743,12 @@ void Process::ModulesDidLoad(ModuleList &module_list) { } } -void Process::PrintWarning(uint64_t warning_type, const void *repeat_key, - const char *fmt, ...) { - bool print_warning = true; - - StreamSP stream_sp = GetTarget().GetDebugger().GetAsyncOutputStream(); - if (!stream_sp) - return; - - if (repeat_key != nullptr) { - WarningsCollection::iterator it = m_warnings_issued.find(warning_type); - if (it == m_warnings_issued.end()) { - m_warnings_issued[warning_type] = WarningsPointerSet(); - m_warnings_issued[warning_type].insert(repeat_key); - } else { - if (it->second.find(repeat_key) != it->second.end()) { - print_warning = false; - } else { - it->second.insert(repeat_key); - } - } - } - - if (print_warning) { - va_list args; - va_start(args, fmt); - stream_sp->PrintfVarArg(fmt, args); - va_end(args); - } -} - void Process::PrintWarningOptimization(const SymbolContext &sc) { if (!GetWarningsOptimization()) return; - if (!sc.module_sp) + if (!sc.module_sp || !sc.function || !sc.function->GetIsOptimized()) return; - if (!sc.module_sp->GetFileSpec().GetFilename().IsEmpty() && sc.function && - sc.function->GetIsOptimized()) { - PrintWarning(Process::Warnings::eWarningsOptimization, sc.module_sp.get(), - "%s was compiled with optimization - stepping may behave " - "oddly; variables may not be available.\n", - sc.module_sp->GetFileSpec().GetFilename().GetCString()); - } + sc.module_sp->ReportWarningOptimization(GetTarget().GetDebugger().GetID()); } void Process::PrintWarningUnsupportedLanguage(const SymbolContext &sc) { @@ -5748,13 +5761,10 @@ void Process::PrintWarningUnsupportedLanguage(const SymbolContext &sc) { return; LanguageSet plugins = PluginManager::GetAllTypeSystemSupportedLanguagesForTypes(); - if (!plugins[language]) { - PrintWarning(Process::Warnings::eWarningsUnsupportedLanguage, - sc.module_sp.get(), - "This version of LLDB has no plugin for the language \"%s\". " - "Inspection of frame variables will be limited.\n", - Language::GetNameForLanguageType(language)); - } + if (plugins[language]) + return; + sc.module_sp->ReportWarningUnsupportedLanguage( + language, GetTarget().GetDebugger().GetID()); } bool Process::GetProcessInfo(ProcessInstanceInfo &info) { @@ -5864,12 +5874,18 @@ Process::AdvanceAddressToNextBranchInstruction(Address default_stop_addr, return retval; } -Status -Process::GetMemoryRegions(lldb_private::MemoryRegionInfos ®ion_list) { +Status Process::GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info) { + if (const lldb::ABISP &abi = GetABI()) + load_addr = abi->FixAnyAddress(load_addr); + return DoGetMemoryRegionInfo(load_addr, range_info); +} +Status Process::GetMemoryRegions(lldb_private::MemoryRegionInfos ®ion_list) { Status error; lldb::addr_t range_end = 0; + const lldb::ABISP &abi = GetABI(); region_list.clear(); do { @@ -5881,11 +5897,22 @@ Process::GetMemoryRegions(lldb_private::MemoryRegionInfos ®ion_list) { break; } + // We only check the end address, not start and end, because we assume that + // the start will not have non-address bits until the first unmappable + // region. We will have exited the loop by that point because the previous + // region, the last mappable region, will have non-address bits in its end + // address. range_end = region_info.GetRange().GetRangeEnd(); if (region_info.GetMapped() == MemoryRegionInfo::eYes) { region_list.push_back(std::move(region_info)); } - } while (range_end != LLDB_INVALID_ADDRESS); + } while ( + // For a process with no non-address bits, all address bits + // set means the end of memory. + range_end != LLDB_INVALID_ADDRESS && + // If we have non-address bits and some are set then the end + // is at or beyond the end of mappable memory. + !(abi && (abi->FixAnyAddress(range_end) != range_end))); return error; } @@ -5901,7 +5928,7 @@ Process::ConfigureStructuredData(ConstString type_name, void Process::MapSupportedStructuredDataPlugins( const StructuredData::Array &supported_type_names) { - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); // Bail out early if there are no type names to map. if (supported_type_names.GetSize() == 0) { @@ -5963,11 +5990,8 @@ void Process::MapSupportedStructuredDataPlugins( m_structured_data_plugin_map.insert( std::make_pair(type_name, plugin_sp)); names_to_remove.push_back(type_name); - LLDB_LOGF(log, - "Process::%s(): using plugin %s for type name " - "%s", - __FUNCTION__, plugin_sp->GetPluginName().GetCString(), - type_name.GetCString()); + LLDB_LOG(log, "using plugin {0} for type name {1}", + plugin_sp->GetPluginName(), type_name); } } @@ -6051,8 +6075,11 @@ bool Process::CallVoidArgVoidPtrReturn(const Address *address, llvm::consumeError(type_system_or_err.takeError()); return false; } + auto ts = *type_system_or_err; + if (!ts) + return false; CompilerType void_ptr_type = - type_system_or_err->GetBasicTypeFromAST(eBasicTypeVoid).GetPointerType(); + ts->GetBasicTypeFromAST(eBasicTypeVoid).GetPointerType(); lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallFunction( *thread, *address, void_ptr_type, llvm::ArrayRef<addr_t>(), options)); if (call_plan_sp) { @@ -6091,8 +6118,7 @@ llvm::Expected<const MemoryTagManager *> Process::GetMemoryTagManager() { if (!arch || !tag_manager) { return llvm::createStringError( llvm::inconvertibleErrorCode(), - "This architecture does not support memory tagging", - GetPluginName().GetCString()); + "This architecture does not support memory tagging"); } if (!SupportsMemoryTagging()) { diff --git a/gnu/llvm/lldb/source/Target/ProcessTrace.cpp b/gnu/llvm/lldb/source/Target/ProcessTrace.cpp index c878a2ac4eb..061af9e0e52 100644 --- a/gnu/llvm/lldb/source/Target/ProcessTrace.cpp +++ b/gnu/llvm/lldb/source/Target/ProcessTrace.cpp @@ -13,18 +13,14 @@ #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" +#include "lldb/Target/ABI.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" using namespace lldb; using namespace lldb_private; -ConstString ProcessTrace::GetPluginNameStatic() { - static ConstString g_name("trace"); - return g_name; -} - -const char *ProcessTrace::GetPluginDescriptionStatic() { +llvm::StringRef ProcessTrace::GetPluginDescriptionStatic() { return "Trace process plug-in."; } @@ -57,10 +53,6 @@ ProcessTrace::~ProcessTrace() { Finalize(); } -ConstString ProcessTrace::GetPluginName() { return GetPluginNameStatic(); } - -uint32_t ProcessTrace::GetPluginVersion() { return 1; } - void ProcessTrace::DidAttach(ArchSpec &process_arch) { ListenerSP listener_sp( Listener::MakeListener("lldb.process_trace.did_attach_listener")); @@ -71,7 +63,7 @@ void ProcessTrace::DidAttach(ArchSpec &process_arch) { SetPrivateState(eStateStopped); EventSP event_sp; - WaitForProcessToStop(llvm::None, &event_sp, true, listener_sp); + WaitForProcessToStop(std::nullopt, &event_sp, true, listener_sp); RestoreProcessEvents(); @@ -89,6 +81,9 @@ Status ProcessTrace::DoDestroy() { return Status(); } size_t ProcessTrace::ReadMemory(addr_t addr, void *buf, size_t size, Status &error) { + if (const ABISP &abi = GetABI()) + addr = abi->FixAnyAddress(addr); + // Don't allow the caching that lldb_private::Process::ReadMemory does since // we have it all cached in the trace files. return DoReadMemory(addr, buf, size, error); diff --git a/gnu/llvm/lldb/source/Target/RegisterContext.cpp b/gnu/llvm/lldb/source/Target/RegisterContext.cpp index bd50a9486ef..ee344b01c6b 100644 --- a/gnu/llvm/lldb/source/Target/RegisterContext.cpp +++ b/gnu/llvm/lldb/source/Target/RegisterContext.cpp @@ -54,6 +54,17 @@ RegisterContext::GetRegisterInfoByName(llvm::StringRef reg_name, if (reg_name.empty()) return nullptr; + // Generic register names take precedence over specific register names. + // For example, on x86 we want "sp" to refer to the complete RSP/ESP register + // rather than the 16-bit SP pseudo-register. + uint32_t generic_reg = Args::StringToGenericRegister(reg_name); + if (generic_reg != LLDB_INVALID_REGNUM) { + const RegisterInfo *reg_info = + GetRegisterInfo(eRegisterKindGeneric, generic_reg); + if (reg_info) + return reg_info; + } + const uint32_t num_registers = GetRegisterCount(); for (uint32_t reg = start_idx; reg < num_registers; ++reg) { const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); @@ -62,45 +73,8 @@ RegisterContext::GetRegisterInfoByName(llvm::StringRef reg_name, reg_name.equals_insensitive(reg_info->alt_name)) return reg_info; } - return nullptr; -} -uint32_t -RegisterContext::UpdateDynamicRegisterSize(const lldb_private::ArchSpec &arch, - RegisterInfo *reg_info) { - ExecutionContext exe_ctx(CalculateThread()); - - // In MIPS, the floating point registers size is depends on FR bit of SR - // register. if SR.FR == 1 then all floating point registers are 64 bits. - // else they are all 32 bits. - - int expr_result; - uint32_t addr_size = arch.GetAddressByteSize(); - const uint8_t *dwarf_opcode_ptr = reg_info->dynamic_size_dwarf_expr_bytes; - const size_t dwarf_opcode_len = reg_info->dynamic_size_dwarf_len; - - DataExtractor dwarf_data(dwarf_opcode_ptr, dwarf_opcode_len, - arch.GetByteOrder(), addr_size); - ModuleSP opcode_ctx; - DWARFExpression dwarf_expr(opcode_ctx, dwarf_data, nullptr); - Value result; - Status error; - if (dwarf_expr.Evaluate(&exe_ctx, this, opcode_ctx, dwarf_data, nullptr, - eRegisterKindDWARF, nullptr, nullptr, result, - &error)) { - expr_result = result.GetScalar().SInt(-1); - switch (expr_result) { - case 0: - return 4; - case 1: - return 8; - default: - return reg_info->byte_size; - } - } else { - printf("Error executing DwarfExpression::Evaluate %s\n", error.AsCString()); - return reg_info->byte_size; - } + return nullptr; } const RegisterInfo *RegisterContext::GetRegisterInfo(lldb::RegisterKind kind, @@ -383,7 +357,7 @@ Status RegisterContext::ReadRegisterValueFromMemory( // TODO: we might need to add a parameter to this function in case the byte // order of the memory data doesn't match the process. For now we are // assuming they are the same. - reg_value.SetFromMemoryData(reg_info, src, src_len, + reg_value.SetFromMemoryData(*reg_info, src, src_len, process_sp->GetByteOrder(), error); } else error.SetErrorString("invalid process"); @@ -394,37 +368,41 @@ Status RegisterContext::ReadRegisterValueFromMemory( Status RegisterContext::WriteRegisterValueToMemory( const RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, const RegisterValue ®_value) { - uint8_t dst[RegisterValue::kMaxRegisterByteSize]; - Status error; - ProcessSP process_sp(m_thread.GetProcess()); - if (process_sp) { - // TODO: we might need to add a parameter to this function in case the byte - // order of the memory data doesn't match the process. For now we are - // assuming they are the same. + if (!process_sp) { + error.SetErrorString("invalid process"); + return error; + } + + if (reg_info == nullptr) { + error.SetErrorString("Invalid register info argument."); + return error; + } - const uint32_t bytes_copied = reg_value.GetAsMemoryData( - reg_info, dst, dst_len, process_sp->GetByteOrder(), error); - - if (error.Success()) { - if (bytes_copied == 0) { - error.SetErrorString("byte copy failed."); - } else { - const uint32_t bytes_written = - process_sp->WriteMemory(dst_addr, dst, bytes_copied, error); - if (bytes_written != bytes_copied) { - if (error.Success()) { - // This might happen if we read _some_ bytes but not all - error.SetErrorStringWithFormat("only wrote %u of %u bytes", - bytes_written, bytes_copied); - } + // TODO: we might need to add a parameter to this function in case the byte + // order of the memory data doesn't match the process. For now we are + // assuming they are the same. + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + const uint32_t bytes_copied = reg_value.GetAsMemoryData( + *reg_info, dst, dst_len, process_sp->GetByteOrder(), error); + + if (error.Success()) { + if (bytes_copied == 0) { + error.SetErrorString("byte copy failed."); + } else { + const uint32_t bytes_written = + process_sp->WriteMemory(dst_addr, dst, bytes_copied, error); + if (bytes_written != bytes_copied) { + if (error.Success()) { + // This might happen if we read _some_ bytes but not all + error.SetErrorStringWithFormat("only wrote %u of %u bytes", + bytes_written, bytes_copied); } } } - } else - error.SetErrorString("invalid process"); + } return error; } diff --git a/gnu/llvm/lldb/source/Target/RegisterContextUnwind.cpp b/gnu/llvm/lldb/source/Target/RegisterContextUnwind.cpp index 1ce21e6306e..2da40ba2bf6 100644 --- a/gnu/llvm/lldb/source/Target/RegisterContextUnwind.cpp +++ b/gnu/llvm/lldb/source/Target/RegisterContextUnwind.cpp @@ -11,7 +11,7 @@ #include "lldb/Core/AddressRange.h" #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" -#include "lldb/Expression/DWARFExpression.h" +#include "lldb/Expression/DWARFExpressionList.h" #include "lldb/Symbol/ArmUnwindInfo.h" #include "lldb/Symbol/CallFrameInfo.h" #include "lldb/Symbol/DWARFCallFrameInfo.h" @@ -32,10 +32,11 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/VASPrintf.h" #include "lldb/lldb-private.h" - #include <memory> using namespace lldb; @@ -81,14 +82,13 @@ RegisterContextUnwind::RegisterContextUnwind(Thread &thread, } bool RegisterContextUnwind::IsUnwindPlanValidForCurrentPC( - lldb::UnwindPlanSP unwind_plan_sp, int &valid_pc_offset) { + lldb::UnwindPlanSP unwind_plan_sp) { if (!unwind_plan_sp) return false; // check if m_current_pc is valid if (unwind_plan_sp->PlanValidAtAddress(m_current_pc)) { // yes - current offset can be used as is - valid_pc_offset = m_current_offset; return true; } @@ -100,8 +100,6 @@ bool RegisterContextUnwind::IsUnwindPlanValidForCurrentPC( Address pc_minus_one(m_current_pc); pc_minus_one.SetOffset(m_current_pc.GetOffset() - 1); if (unwind_plan_sp->PlanValidAtAddress(pc_minus_one)) { - // *valid_pc_offset = m_current_offset - 1; - valid_pc_offset = m_current_pc.GetOffset() - 1; return true; } @@ -112,7 +110,7 @@ bool RegisterContextUnwind::IsUnwindPlanValidForCurrentPC( // zeroth frame or currently executing frame. void RegisterContextUnwind::InitializeZerothFrame() { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); + Log *log = GetLog(LLDBLog::Unwind); ExecutionContext exe_ctx(m_thread.shared_from_this()); RegisterContextSP reg_ctx_sp = m_thread.GetRegisterContext(); @@ -303,7 +301,7 @@ void RegisterContextUnwind::InitializeZerothFrame() { // RegisterContextUnwind "below" it to provide things like its current pc value. void RegisterContextUnwind::InitializeNonZerothFrame() { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); + Log *log = GetLog(LLDBLog::Unwind); if (IsFrameZero()) { m_frame_type = eNotAValidFrame; UnwindLogMsg("non-zeroth frame tests positive for IsFrameZero -- that " @@ -383,7 +381,7 @@ void RegisterContextUnwind::InitializeNonZerothFrame() { // symbol/function information - just stick in some reasonable defaults and // hope we can unwind past this frame. If we're above a trap handler, // we may be at a bogus address because we jumped through a bogus function - // pointer and trapped, so don't force the arch default unwind plan in that + // pointer and trapped, so don't force the arch default unwind plan in that // case. ModuleSP pc_module_sp(m_current_pc.GetModule()); if ((!m_current_pc.IsValid() || !pc_module_sp) && @@ -513,9 +511,12 @@ void RegisterContextUnwind::InitializeNonZerothFrame() { } else if (!addr_range.GetBaseAddress().IsValid() || addr_range.GetBaseAddress().GetSection() != m_current_pc.GetSection() || addr_range.GetBaseAddress().GetOffset() != m_current_pc.GetOffset()) { - // If our "current" pc isn't the start of a function, no need - // to decrement and recompute. - decr_pc_and_recompute_addr_range = false; + // If our "current" pc isn't the start of a function, decrement the pc + // if we're up the stack. + if (m_behaves_like_zeroth_frame) + decr_pc_and_recompute_addr_range = false; + else + decr_pc_and_recompute_addr_range = true; } else if (IsTrapHandlerSymbol(process, m_sym_ctx)) { // Signal dispatch may set the return address of the handler it calls to // point to the first byte of a return trampoline (like __kernel_rt_sigreturn), @@ -635,9 +636,9 @@ void RegisterContextUnwind::InitializeNonZerothFrame() { } } else { m_full_unwind_plan_sp = GetFullUnwindPlanForFrame(); - int valid_offset = -1; - if (IsUnwindPlanValidForCurrentPC(m_full_unwind_plan_sp, valid_offset)) { - active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset(valid_offset); + if (IsUnwindPlanValidForCurrentPC(m_full_unwind_plan_sp)) { + active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset( + m_current_offset_backed_up_one); row_register_kind = m_full_unwind_plan_sp->GetRegisterKind(); PropagateTrapHandlerFlagFromUnwindPlan(m_full_unwind_plan_sp); if (active_row.get() && log) { @@ -893,13 +894,22 @@ UnwindPlanSP RegisterContextUnwind::GetFullUnwindPlanForFrame() { return arch_default_unwind_plan_sp; } - // If we're in _sigtramp(), unwinding past this frame requires special - // knowledge. On Mac OS X this knowledge is properly encoded in the eh_frame - // section, so prefer that if available. On other platforms we may need to - // provide a platform-specific UnwindPlan which encodes the details of how to - // unwind out of sigtramp. if (m_frame_type == eTrapHandlerFrame && process) { m_fast_unwind_plan_sp.reset(); + + // On some platforms the unwind information for signal handlers is not + // present or correct. Give the platform plugins a chance to provide + // substitute plan. Otherwise, use eh_frame. + if (m_sym_ctx_valid) { + lldb::PlatformSP platform = process->GetTarget().GetPlatform(); + unwind_plan_sp = platform->GetTrapHandlerUnwindPlan( + process->GetTarget().GetArchitecture().GetTriple(), + GetSymbolOrFunctionName(m_sym_ctx)); + + if (unwind_plan_sp) + return unwind_plan_sp; + } + unwind_plan_sp = func_unwinders_sp->GetEHFrameUnwindPlan(process->GetTarget()); if (!unwind_plan_sp) @@ -997,8 +1007,7 @@ UnwindPlanSP RegisterContextUnwind::GetFullUnwindPlanForFrame() { unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite( process->GetTarget(), m_thread); } - int valid_offset = -1; - if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset)) { + if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp)) { UnwindLogMsgVerbose("frame uses %s for full UnwindPlan because this " "is the call-site unwind plan", unwind_plan_sp->GetSourceName().GetCString()); @@ -1037,7 +1046,7 @@ UnwindPlanSP RegisterContextUnwind::GetFullUnwindPlanForFrame() { } } - if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset)) { + if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp)) { UnwindLogMsgVerbose("frame uses %s for full UnwindPlan because we " "failed to find a call-site unwind plan that would work", unwind_plan_sp->GetSourceName().GetCString()); @@ -1238,7 +1247,7 @@ enum UnwindLLDB::RegisterSearchResult RegisterContextUnwind::SavedLocationForRegister( uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc) { RegisterNumber regnum(m_thread, eRegisterKindLLDB, lldb_regnum); - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); + Log *log = GetLog(LLDBLog::Unwind); // Have we already found this register location? if (!m_registers.empty()) { @@ -1277,7 +1286,7 @@ RegisterContextUnwind::SavedLocationForRegister( // 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 + // UnwindPlan has. If the full UnwindPlan says the register // location is Undefined, then it really is. if (active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind), unwindplan_regloc) && @@ -1303,7 +1312,8 @@ RegisterContextUnwind::SavedLocationForRegister( LLDB_REGNUM_GENERIC_PC); UnwindPlan::RowSP active_row = - m_full_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); + 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.get() && log) { @@ -1325,13 +1335,13 @@ RegisterContextUnwind::SavedLocationForRegister( 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 + // 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::RegisterLocation scratch; if (m_frame_type == eTrapHandlerFrame && - active_row->GetRegisterInfo + 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 " @@ -1500,7 +1510,7 @@ RegisterContextUnwind::SavedLocationForRegister( regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterFound; } else { - std::string unwindplan_name(""); + std::string unwindplan_name; if (m_full_unwind_plan_sp) { unwindplan_name += "via '"; unwindplan_name += m_full_unwind_plan_sp->GetSourceName().AsCString(); @@ -1515,7 +1525,7 @@ RegisterContextUnwind::SavedLocationForRegister( // unwindplan_regloc has valid contents about where to retrieve the register if (unwindplan_regloc.IsUnspecified()) { - lldb_private::UnwindLLDB::RegisterLocation new_regloc; + lldb_private::UnwindLLDB::RegisterLocation new_regloc = {}; new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterNotSaved; m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; UnwindLogMsg("save location for %s (%d) is unspecified, continue searching", @@ -1632,8 +1642,9 @@ RegisterContextUnwind::SavedLocationForRegister( process->GetByteOrder(), process->GetAddressByteSize()); ModuleSP opcode_ctx; - DWARFExpression dwarfexpr(opcode_ctx, dwarfdata, nullptr); - dwarfexpr.SetRegisterKind(unwindplan_registerkind); + DWARFExpressionList dwarfexpr(opcode_ctx, dwarfdata, nullptr); + dwarfexpr.GetMutableExpressionAtAddress()->SetRegisterKind( + unwindplan_registerkind); Value cfa_val = Scalar(m_cfa); cfa_val.SetValueType(Value::ValueType::LoadAddress); Value result; @@ -1720,7 +1731,7 @@ bool RegisterContextUnwind::TryFallbackUnwindPlan() { addr_t old_caller_pc_value = LLDB_INVALID_ADDRESS; addr_t new_caller_pc_value = LLDB_INVALID_ADDRESS; - UnwindLLDB::RegisterLocation regloc; + UnwindLLDB::RegisterLocation regloc = {}; if (SavedLocationForRegister(pc_regnum.GetAsKind(eRegisterKindLLDB), regloc) == UnwindLLDB::RegisterSearchResult::eRegisterFound) { @@ -1760,7 +1771,8 @@ bool RegisterContextUnwind::TryFallbackUnwindPlan() { m_full_unwind_plan_sp = m_fallback_unwind_plan_sp; UnwindPlan::RowSP active_row = - m_fallback_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); + m_fallback_unwind_plan_sp->GetRowForFunctionOffset( + m_current_offset_backed_up_one); if (active_row && active_row->GetCFAValue().GetValueType() != @@ -1995,8 +2007,9 @@ bool RegisterContextUnwind::ReadFrameAddress( process->GetByteOrder(), process->GetAddressByteSize()); ModuleSP opcode_ctx; - DWARFExpression dwarfexpr(opcode_ctx, dwarfdata, nullptr); - dwarfexpr.SetRegisterKind(row_register_kind); + DWARFExpressionList dwarfexpr(opcode_ctx, dwarfdata, nullptr); + dwarfexpr.GetMutableExpressionAtAddress()->SetRegisterKind( + row_register_kind); Value result; Status error; if (dwarfexpr.Evaluate(&exe_ctx, this, 0, nullptr, nullptr, result, @@ -2221,7 +2234,8 @@ bool RegisterContextUnwind::WriteRegister(const RegisterInfo *reg_info, } // Don't need to implement this one -bool RegisterContextUnwind::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) { +bool RegisterContextUnwind::ReadAllRegisterValues( + lldb::WritableDataBufferSP &data_sp) { return false; } @@ -2315,45 +2329,35 @@ bool RegisterContextUnwind::ReadPC(addr_t &pc) { } void RegisterContextUnwind::UnwindLogMsg(const char *fmt, ...) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); - if (log) { - va_list args; - va_start(args, fmt); - - char *logmsg; - if (vasprintf(&logmsg, fmt, args) == -1 || logmsg == nullptr) { - if (logmsg) - free(logmsg); - va_end(args); - return; - } - va_end(args); + Log *log = GetLog(LLDBLog::Unwind); + if (!log) + return; + + va_list args; + va_start(args, fmt); + llvm::SmallString<0> logmsg; + if (VASprintf(logmsg, fmt, args)) { LLDB_LOGF(log, "%*sth%d/fr%u %s", m_frame_number < 100 ? m_frame_number : 100, "", - m_thread.GetIndexID(), m_frame_number, logmsg); - free(logmsg); + m_thread.GetIndexID(), m_frame_number, logmsg.c_str()); } + va_end(args); } void RegisterContextUnwind::UnwindLogMsgVerbose(const char *fmt, ...) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); - if (log && log->GetVerbose()) { - va_list args; - va_start(args, fmt); - - char *logmsg; - if (vasprintf(&logmsg, fmt, args) == -1 || logmsg == nullptr) { - if (logmsg) - free(logmsg); - va_end(args); - return; - } - va_end(args); + Log *log = GetLog(LLDBLog::Unwind); + if (!log || !log->GetVerbose()) + return; + + va_list args; + va_start(args, fmt); + llvm::SmallString<0> logmsg; + if (VASprintf(logmsg, fmt, args)) { LLDB_LOGF(log, "%*sth%d/fr%u %s", m_frame_number < 100 ? m_frame_number : 100, "", - m_thread.GetIndexID(), m_frame_number, logmsg); - free(logmsg); + m_thread.GetIndexID(), m_frame_number, logmsg.c_str()); } + va_end(args); } diff --git a/gnu/llvm/lldb/source/Target/RemoteAwarePlatform.cpp b/gnu/llvm/lldb/source/Target/RemoteAwarePlatform.cpp index b0c43ffa839..0bd6c9251c8 100644 --- a/gnu/llvm/lldb/source/Target/RemoteAwarePlatform.cpp +++ b/gnu/llvm/lldb/source/Target/RemoteAwarePlatform.cpp @@ -10,11 +10,11 @@ #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" #include "lldb/Core/ModuleSpec.h" -#include "lldb/Host/FileCache.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Utility/StreamString.h" +#include <optional> using namespace lldb_private; using namespace lldb; @@ -72,8 +72,7 @@ Status RemoteAwarePlatform::ResolveExecutable( } else { if (m_remote_platform_sp) { return GetCachedExecutable(resolved_module_spec, exe_module_sp, - module_search_paths_ptr, - *m_remote_platform_sp); + module_search_paths_ptr); } // We may connect to a process and use the provided executable (Don't use @@ -132,9 +131,11 @@ Status RemoteAwarePlatform::ResolveExecutable( // architectures that we should be using (in the correct order) and see // if we can find a match that way StreamString arch_names; - for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( - idx, resolved_module_spec.GetArchitecture()); - ++idx) { + llvm::ListSeparator LS; + ArchSpec process_host_arch; + for (const ArchSpec &arch : + GetSupportedArchitectures(process_host_arch)) { + resolved_module_spec.GetArchitecture() = arch; error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, module_search_paths_ptr, nullptr, nullptr); // Did we find an executable using one of the @@ -145,19 +146,16 @@ Status RemoteAwarePlatform::ResolveExecutable( error.SetErrorToGenericError(); } - if (idx > 0) - arch_names.PutCString(", "); - arch_names.PutCString( - resolved_module_spec.GetArchitecture().GetArchitectureName()); + arch_names << LS << arch.GetArchitectureName(); } if (error.Fail() || !exe_module_sp) { if (FileSystem::Instance().Readable( resolved_module_spec.GetFileSpec())) { - error.SetErrorStringWithFormat( - "'%s' doesn't contain any '%s' platform architectures: %s", - resolved_module_spec.GetFileSpec().GetPath().c_str(), - GetPluginName().GetCString(), arch_names.GetData()); + error.SetErrorStringWithFormatv( + "'{0}' doesn't contain any '{1}' platform architectures: {2}", + resolved_module_spec.GetFileSpec(), GetPluginName(), + arch_names.GetData()); } else { error.SetErrorStringWithFormat( "'%s' is not readable", @@ -182,14 +180,12 @@ Status RemoteAwarePlatform::RunShellCommand( llvm::StringRef shell, llvm::StringRef command, const FileSpec &working_dir, int *status_ptr, int *signo_ptr, std::string *command_output, const Timeout<std::micro> &timeout) { - if (IsHost()) - return Host::RunShellCommand(shell, command, working_dir, status_ptr, - signo_ptr, command_output, timeout); if (m_remote_platform_sp) return m_remote_platform_sp->RunShellCommand(shell, command, working_dir, status_ptr, signo_ptr, command_output, timeout); - return Status("unable to run a remote command without a platform"); + return Platform::RunShellCommand(shell, command, working_dir, status_ptr, + signo_ptr, command_output, timeout); } Status RemoteAwarePlatform::MakeDirectory(const FileSpec &file_spec, @@ -218,16 +214,12 @@ Status RemoteAwarePlatform::SetFilePermissions(const FileSpec &file_spec, lldb::user_id_t RemoteAwarePlatform::OpenFile(const FileSpec &file_spec, File::OpenOptions flags, uint32_t mode, Status &error) { - if (IsHost()) - return FileCache::GetInstance().OpenFile(file_spec, flags, mode, error); if (m_remote_platform_sp) return m_remote_platform_sp->OpenFile(file_spec, flags, mode, error); return Platform::OpenFile(file_spec, flags, mode, error); } bool RemoteAwarePlatform::CloseFile(lldb::user_id_t fd, Status &error) { - if (IsHost()) - return FileCache::GetInstance().CloseFile(fd, error); if (m_remote_platform_sp) return m_remote_platform_sp->CloseFile(fd, error); return Platform::CloseFile(fd, error); @@ -236,8 +228,6 @@ bool RemoteAwarePlatform::CloseFile(lldb::user_id_t fd, Status &error) { uint64_t RemoteAwarePlatform::ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst, uint64_t dst_len, Status &error) { - if (IsHost()) - return FileCache::GetInstance().ReadFile(fd, offset, dst, dst_len, error); if (m_remote_platform_sp) return m_remote_platform_sp->ReadFile(fd, offset, dst, dst_len, error); return Platform::ReadFile(fd, offset, dst, dst_len, error); @@ -246,20 +236,12 @@ uint64_t RemoteAwarePlatform::ReadFile(lldb::user_id_t fd, uint64_t offset, uint64_t RemoteAwarePlatform::WriteFile(lldb::user_id_t fd, uint64_t offset, const void *src, uint64_t src_len, Status &error) { - if (IsHost()) - return FileCache::GetInstance().WriteFile(fd, offset, src, src_len, error); if (m_remote_platform_sp) return m_remote_platform_sp->WriteFile(fd, offset, src, src_len, error); return Platform::WriteFile(fd, offset, src, src_len, error); } lldb::user_id_t RemoteAwarePlatform::GetFileSize(const FileSpec &file_spec) { - if (IsHost()) { - uint64_t Size; - if (llvm::sys::fs::file_size(file_spec.GetPath(), Size)) - return 0; - return Size; - } if (m_remote_platform_sp) return m_remote_platform_sp->GetFileSize(file_spec); return Platform::GetFileSize(file_spec); @@ -267,24 +249,18 @@ lldb::user_id_t RemoteAwarePlatform::GetFileSize(const FileSpec &file_spec) { Status RemoteAwarePlatform::CreateSymlink(const FileSpec &src, const FileSpec &dst) { - if (IsHost()) - return FileSystem::Instance().Symlink(src, dst); if (m_remote_platform_sp) return m_remote_platform_sp->CreateSymlink(src, dst); return Platform::CreateSymlink(src, dst); } bool RemoteAwarePlatform::GetFileExists(const FileSpec &file_spec) { - if (IsHost()) - return FileSystem::Instance().Exists(file_spec); if (m_remote_platform_sp) return m_remote_platform_sp->GetFileExists(file_spec); return Platform::GetFileExists(file_spec); } Status RemoteAwarePlatform::Unlink(const FileSpec &file_spec) { - if (IsHost()) - return llvm::sys::fs::remove(file_spec.GetPath()); if (m_remote_platform_sp) return m_remote_platform_sp->Unlink(file_spec); return Platform::Unlink(file_spec); @@ -292,11 +268,9 @@ Status RemoteAwarePlatform::Unlink(const FileSpec &file_spec) { bool RemoteAwarePlatform::CalculateMD5(const FileSpec &file_spec, uint64_t &low, uint64_t &high) { - if (IsHost()) - return Platform::CalculateMD5(file_spec, low, high); if (m_remote_platform_sp) return m_remote_platform_sp->CalculateMD5(file_spec, low, high); - return false; + return Platform::CalculateMD5(file_spec, low, high); } FileSpec RemoteAwarePlatform::GetRemoteWorkingDirectory() { @@ -332,18 +306,16 @@ bool RemoteAwarePlatform::GetRemoteOSVersion() { return false; } -bool RemoteAwarePlatform::GetRemoteOSBuildString(std::string &s) { +std::optional<std::string> RemoteAwarePlatform::GetRemoteOSBuildString() { if (m_remote_platform_sp) - return m_remote_platform_sp->GetRemoteOSBuildString(s); - s.clear(); - return false; + return m_remote_platform_sp->GetRemoteOSBuildString(); + return std::nullopt; } -bool RemoteAwarePlatform::GetRemoteOSKernelDescription(std::string &s) { +std::optional<std::string> RemoteAwarePlatform::GetRemoteOSKernelDescription() { if (m_remote_platform_sp) - return m_remote_platform_sp->GetRemoteOSKernelDescription(s); - s.clear(); - return false; + return m_remote_platform_sp->GetRemoteOSKernelDescription(); + return std::nullopt; } ArchSpec RemoteAwarePlatform::GetRemoteSystemArchitecture() { @@ -353,55 +325,42 @@ ArchSpec RemoteAwarePlatform::GetRemoteSystemArchitecture() { } const char *RemoteAwarePlatform::GetHostname() { - if (IsHost()) - return Platform::GetHostname(); if (m_remote_platform_sp) return m_remote_platform_sp->GetHostname(); - return nullptr; + return Platform::GetHostname(); } UserIDResolver &RemoteAwarePlatform::GetUserIDResolver() { - if (IsHost()) - return HostInfo::GetUserIDResolver(); if (m_remote_platform_sp) return m_remote_platform_sp->GetUserIDResolver(); - return UserIDResolver::GetNoopResolver(); + return Platform::GetUserIDResolver(); } Environment RemoteAwarePlatform::GetEnvironment() { - if (IsRemote()) { - if (m_remote_platform_sp) - return m_remote_platform_sp->GetEnvironment(); - return Environment(); - } - return Host::GetEnvironment(); + if (m_remote_platform_sp) + return m_remote_platform_sp->GetEnvironment(); + return Platform::GetEnvironment(); } bool RemoteAwarePlatform::IsConnected() const { - if (IsHost()) - return true; - else if (m_remote_platform_sp) + if (m_remote_platform_sp) return m_remote_platform_sp->IsConnected(); - return false; + return Platform::IsConnected(); } bool RemoteAwarePlatform::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { - if (IsHost()) - return Platform::GetProcessInfo(pid, process_info); if (m_remote_platform_sp) return m_remote_platform_sp->GetProcessInfo(pid, process_info); - return false; + return Platform::GetProcessInfo(pid, process_info); } uint32_t RemoteAwarePlatform::FindProcesses(const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos) { - if (IsHost()) - return Platform::FindProcesses(match_info, process_infos); if (m_remote_platform_sp) return m_remote_platform_sp->FindProcesses(match_info, process_infos); - return 0; + return Platform::FindProcesses(match_info, process_infos); } lldb::ProcessSP RemoteAwarePlatform::ConnectProcess(llvm::StringRef connect_url, @@ -417,25 +376,15 @@ lldb::ProcessSP RemoteAwarePlatform::ConnectProcess(llvm::StringRef connect_url, } Status RemoteAwarePlatform::LaunchProcess(ProcessLaunchInfo &launch_info) { - Status error; - - if (IsHost()) { - error = Platform::LaunchProcess(launch_info); - } else { - if (m_remote_platform_sp) - error = m_remote_platform_sp->LaunchProcess(launch_info); - else - error.SetErrorString("the platform is not currently connected"); - } - return error; + if (m_remote_platform_sp) + return m_remote_platform_sp->LaunchProcess(launch_info); + return Platform::LaunchProcess(launch_info); } Status RemoteAwarePlatform::KillProcess(const lldb::pid_t pid) { - if (IsHost()) - return Platform::KillProcess(pid); if (m_remote_platform_sp) return m_remote_platform_sp->KillProcess(pid); - return Status("the platform is not currently connected"); + return Platform::KillProcess(pid); } size_t RemoteAwarePlatform::ConnectToWaitingProcesses(Debugger &debugger, diff --git a/gnu/llvm/lldb/source/Target/SectionLoadList.cpp b/gnu/llvm/lldb/source/Target/SectionLoadList.cpp index f1a626b0480..d4bf0573b22 100644 --- a/gnu/llvm/lldb/source/Target/SectionLoadList.cpp +++ b/gnu/llvm/lldb/source/Target/SectionLoadList.cpp @@ -13,6 +13,7 @@ #include "lldb/Symbol/Block.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/SymbolContext.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Stream.h" @@ -63,7 +64,7 @@ SectionLoadList::GetSectionLoadAddress(const lldb::SectionSP §ion) const { bool SectionLoadList::SetSectionLoadAddress(const lldb::SectionSP §ion, addr_t load_addr, bool warn_multiple) { - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + Log *log = GetLog(LLDBLog::DynamicLoader); ModuleSP module_sp(section->GetModule()); if (module_sp) { @@ -105,8 +106,8 @@ bool SectionLoadList::SetSectionLoadAddress(const lldb::SectionSP §ion, ModuleSP curr_module_sp(ats_pos->second->GetModule()); if (curr_module_sp) { module_sp->ReportWarning( - "address 0x%16.16" PRIx64 - " maps to more than one section: %s.%s and %s.%s", + "address {0:x16} maps to more than one section: {1}.{2} and " + "{3}.{4}", load_addr, module_sp->GetFileSpec().GetFilename().GetCString(), section->GetName().GetCString(), curr_module_sp->GetFileSpec().GetFilename().GetCString(), @@ -115,8 +116,18 @@ bool SectionLoadList::SetSectionLoadAddress(const lldb::SectionSP §ion, } } ats_pos->second = section; - } else + } else { + // Remove the old address->section entry, if + // there is one. + for (const auto &entry : m_addr_to_sect) { + if (entry.second == section) { + const auto &it_pos = m_addr_to_sect.find(entry.first); + m_addr_to_sect.erase(it_pos); + break; + } + } m_addr_to_sect[load_addr] = section; + } return true; // Changed } else { @@ -136,7 +147,7 @@ size_t SectionLoadList::SetSectionUnloaded(const lldb::SectionSP §ion_sp) { size_t unload_count = 0; if (section_sp) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + Log *log = GetLog(LLDBLog::DynamicLoader); if (log && log->GetVerbose()) { ModuleSP module_sp = section_sp->GetModule(); @@ -171,7 +182,7 @@ size_t SectionLoadList::SetSectionUnloaded(const lldb::SectionSP §ion_sp) { bool SectionLoadList::SetSectionUnloaded(const lldb::SectionSP §ion_sp, addr_t load_addr) { - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + Log *log = GetLog(LLDBLog::DynamicLoader); if (log && log->GetVerbose()) { ModuleSP module_sp = section_sp->GetModule(); diff --git a/gnu/llvm/lldb/source/Target/StackFrame.cpp b/gnu/llvm/lldb/source/Target/StackFrame.cpp index cba51d266c5..c04b58e8052 100644 --- a/gnu/llvm/lldb/source/Target/StackFrame.cpp +++ b/gnu/llvm/lldb/source/Target/StackFrame.cpp @@ -20,6 +20,7 @@ #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/SymbolContextScope.h" +#include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/Type.h" #include "lldb/Symbol/VariableList.h" #include "lldb/Target/ABI.h" @@ -29,6 +30,7 @@ #include "lldb/Target/StackFrameRecognizer.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RegisterValue.h" @@ -42,7 +44,7 @@ using namespace lldb_private; // The first bits in the flags are reserved for the SymbolContext::Scope bits // so we know if we have tried to look up information in our internal symbol // context (m_sc) already. -#define RESOLVED_FRAME_CODE_ADDR (uint32_t(eSymbolContextEverything + 1)) +#define RESOLVED_FRAME_CODE_ADDR (uint32_t(eSymbolContextLastItem) << 1) #define RESOLVED_FRAME_ID_SYMBOL_SCOPE (RESOLVED_FRAME_CODE_ADDR << 1) #define GOT_FRAME_BASE (RESOLVED_FRAME_ID_SYMBOL_SCOPE << 1) #define RESOLVED_VARIABLES (GOT_FRAME_BASE << 1) @@ -419,10 +421,12 @@ StackFrame::GetSymbolContext(SymbolContextItem resolve_scope) { return m_sc; } -VariableList *StackFrame::GetVariableList(bool get_file_globals) { +VariableList *StackFrame::GetVariableList(bool get_file_globals, + Status *error_ptr) { std::lock_guard<std::recursive_mutex> guard(m_mutex); if (m_flags.IsClear(RESOLVED_VARIABLES)) { m_flags.Set(RESOLVED_VARIABLES); + m_variable_list_sp = std::make_shared<VariableList>(); Block *frame_block = GetFrameBlock(); @@ -430,7 +434,6 @@ VariableList *StackFrame::GetVariableList(bool get_file_globals) { const bool get_child_variables = true; const bool can_create = true; const bool stop_if_child_block_is_inlined_function = true; - m_variable_list_sp = std::make_shared<VariableList>(); frame_block->AppendBlockVariables(can_create, get_child_variables, stop_if_child_block_is_inlined_function, [](Variable *v) { return true; }, @@ -454,6 +457,17 @@ VariableList *StackFrame::GetVariableList(bool get_file_globals) { } } + if (error_ptr && m_variable_list_sp->GetSize() == 0) { + // Check with the symbol file to check if there is an error for why we + // don't have variables that the user might need to know about. + GetSymbolContext(eSymbolContextEverything); + if (m_sc.module_sp) { + SymbolFile *sym_file = m_sc.module_sp->GetSymbolFile(); + if (sym_file) + *error_ptr = sym_file->GetFrameVariableError(*this); + } + } + return m_variable_list_sp.get(); } @@ -551,7 +565,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath( if (!var_sp && (options & eExpressionPathOptionsAllowDirectIVarAccess)) { // Check for direct ivars access which helps us with implicit access to - // ivars with the "this->" or "self->" + // ivars using "this" or "self". GetSymbolContext(eSymbolContextFunction | eSymbolContextBlock); lldb::LanguageType method_language = eLanguageTypeUnknown; bool is_instance_method = false; @@ -562,7 +576,13 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath( var_sp = variable_list->FindVariable(method_object_name); if (var_sp) { separator_idx = 0; - var_expr_storage = "->"; + if (Type *var_type = var_sp->GetType()) + if (auto compiler_type = var_type->GetForwardCompilerType()) + if (!compiler_type.IsPointerType()) + var_expr_storage = "."; + + if (var_expr_storage.empty()) + var_expr_storage = "->"; var_expr_storage += var_expr; var_expr = var_expr_storage; synthetically_added_instance_object = true; @@ -659,7 +679,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath( } var_expr = var_expr.drop_front(); // Remove the '-' - LLVM_FALLTHROUGH; + [[fallthrough]]; case '.': { var_expr = var_expr.drop_front(); // Remove the '.' or '>' separator_idx = var_expr.find_first_of(".-["); @@ -1080,7 +1100,7 @@ bool StackFrame::GetFrameBaseValue(Scalar &frame_base, Status *error_ptr) { ExecutionContext exe_ctx(shared_from_this()); Value expr_value; addr_t loclist_base_addr = LLDB_INVALID_ADDRESS; - if (m_sc.function->GetFrameBaseExpression().IsLocationList()) + if (!m_sc.function->GetFrameBaseExpression().IsAlwaysValidSingleExpr()) loclist_base_addr = m_sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress( exe_ctx.GetTargetPtr()); @@ -1109,7 +1129,7 @@ bool StackFrame::GetFrameBaseValue(Scalar &frame_base, Status *error_ptr) { return m_frame_base_error.Success(); } -DWARFExpression *StackFrame::GetFrameBaseExpression(Status *error_ptr) { +DWARFExpressionList *StackFrame::GetFrameBaseExpression(Status *error_ptr) { if (!m_sc.function) { if (error_ptr) { error_ptr->SetErrorString("No function in symbol context."); @@ -1138,26 +1158,34 @@ bool StackFrame::HasDebugInformation() { ValueObjectSP StackFrame::GetValueObjectForFrameVariable(const VariableSP &variable_sp, DynamicValueType use_dynamic) { - std::lock_guard<std::recursive_mutex> guard(m_mutex); ValueObjectSP valobj_sp; - if (IsHistorical()) { - return valobj_sp; - } - VariableList *var_list = GetVariableList(true); - if (var_list) { - // Make sure the variable is a frame variable - const uint32_t var_idx = var_list->FindIndexForVariable(variable_sp.get()); - const uint32_t num_variables = var_list->GetSize(); - if (var_idx < num_variables) { - valobj_sp = m_variable_list_value_objects.GetValueObjectAtIndex(var_idx); - if (!valobj_sp) { - if (m_variable_list_value_objects.GetSize() < num_variables) - m_variable_list_value_objects.Resize(num_variables); - valobj_sp = ValueObjectVariable::Create(this, variable_sp); - m_variable_list_value_objects.SetValueObjectAtIndex(var_idx, valobj_sp); + { // Scope for stack frame mutex. We need to drop this mutex before we figure + // out the dynamic value. That will require converting the StackID in the + // VO back to a StackFrame, which will in turn require locking the + // StackFrameList. If we still hold the StackFrame mutex, we could suffer + // lock inversion against the pattern of getting the StackFrameList and + // then the stack frame, which is fairly common. + std::lock_guard<std::recursive_mutex> guard(m_mutex); + if (IsHistorical()) { + return valobj_sp; + } + VariableList *var_list = GetVariableList(true, nullptr); + if (var_list) { + // Make sure the variable is a frame variable + const uint32_t var_idx = var_list->FindIndexForVariable(variable_sp.get()); + const uint32_t num_variables = var_list->GetSize(); + if (var_idx < num_variables) { + valobj_sp = m_variable_list_value_objects.GetValueObjectAtIndex(var_idx); + if (!valobj_sp) { + if (m_variable_list_value_objects.GetSize() < num_variables) + m_variable_list_value_objects.Resize(num_variables); + valobj_sp = ValueObjectVariable::Create(this, variable_sp); + m_variable_list_value_objects.SetValueObjectAtIndex(var_idx, + valobj_sp); + } } } - } + } // End of StackFrame mutex scope. if (use_dynamic != eNoDynamicValues && valobj_sp) { ValueObjectSP dynamic_sp = valobj_sp->GetDynamicValue(use_dynamic); if (dynamic_sp) @@ -1193,7 +1221,7 @@ lldb::LanguageType StackFrame::GuessLanguage() { LanguageType lang_type = GetLanguage(); if (lang_type == eLanguageTypeUnknown) { - SymbolContext sc = GetSymbolContext(eSymbolContextFunction + SymbolContext sc = GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol); if (sc.function) { lang_type = sc.function->GetMangled().GuessLanguage(); @@ -1336,14 +1364,15 @@ lldb::ValueObjectSP StackFrame::GuessValueForAddress(lldb::addr_t addr) { auto c_type_system_or_err = target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC); if (auto err = c_type_system_or_err.takeError()) { - LLDB_LOG_ERROR( - lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD), - std::move(err), "Unable to guess value for given address"); + LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), std::move(err), + "Unable to guess value for given address"); return ValueObjectSP(); } else { + auto ts = *c_type_system_or_err; + if (!ts) + return {}; CompilerType void_ptr_type = - c_type_system_or_err - ->GetBasicTypeFromAST(lldb::BasicType::eBasicTypeChar) + ts->GetBasicTypeFromAST(lldb::BasicType::eBasicTypeChar) .GetPointerType(); return ValueObjectMemory::Create(this, "", addr, void_ptr_type); } @@ -1384,7 +1413,7 @@ ValueObjectSP GetValueForOffset(StackFrame &frame, ValueObjectSP &parent, } int64_t child_offset = child_sp->GetByteOffset(); - int64_t child_size = child_sp->GetByteSize().getValueOr(0); + int64_t child_size = child_sp->GetByteSize().value_or(0); if (offset >= child_offset && offset < (child_offset + child_size)) { return GetValueForOffset(frame, child_sp, offset - child_offset); @@ -1411,14 +1440,14 @@ ValueObjectSP GetValueForDereferincingOffset(StackFrame &frame, Status error; ValueObjectSP pointee = base->Dereference(error); - + if (!pointee) { return ValueObjectSP(); } if (offset >= 0 && uint64_t(offset) >= pointee->GetByteSize()) { - int64_t index = offset / pointee->GetByteSize().getValueOr(1); - offset = offset % pointee->GetByteSize().getValueOr(1); + int64_t index = offset / pointee->GetByteSize().value_or(1); + offset = offset % pointee->GetByteSize().value_or(1); const bool can_create = true; pointee = base->GetSyntheticArrayMember(index, can_create); } @@ -1433,13 +1462,13 @@ ValueObjectSP GetValueForDereferincingOffset(StackFrame &frame, /// Attempt to reconstruct the ValueObject for the address contained in a /// given register plus an offset. /// -/// \params [in] frame +/// \param [in] frame /// The current stack frame. /// -/// \params [in] reg +/// \param [in] reg /// The register. /// -/// \params [in] offset +/// \param [in] offset /// The offset from the register. /// /// \param [in] disassembler @@ -1499,7 +1528,7 @@ lldb::ValueObjectSP DoGuessValueAt(StackFrame &frame, ConstString reg, Instruction::Operand::BuildRegister(reg)); for (VariableSP var_sp : variables) { - if (var_sp->LocationExpression().MatchesOperand(frame, op)) + if (var_sp->LocationExpressionList().MatchesOperand(frame, op)) return frame.GetValueObjectForFrameVariable(var_sp, eNoDynamicValues); } @@ -1684,7 +1713,7 @@ lldb::ValueObjectSP StackFrame::GuessValueForRegisterAndOffset(ConstString reg, } const bool get_file_globals = false; - VariableList *variables = GetVariableList(get_file_globals); + VariableList *variables = GetVariableList(get_file_globals, nullptr); if (!variables) { return ValueObjectSP(); @@ -1883,14 +1912,32 @@ bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool show_source, if (m_sc.comp_unit && m_sc.line_entry.IsValid()) { have_debuginfo = true; if (source_lines_before > 0 || source_lines_after > 0) { + uint32_t start_line = m_sc.line_entry.line; + if (!start_line && m_sc.function) { + FileSpec source_file; + m_sc.function->GetStartLineSourceInfo(source_file, start_line); + } + size_t num_lines = target->GetSourceManager().DisplaySourceLinesWithLineNumbers( - m_sc.line_entry.file, m_sc.line_entry.line, - m_sc.line_entry.column, source_lines_before, - source_lines_after, "->", &strm); + m_sc.line_entry.file, start_line, m_sc.line_entry.column, + source_lines_before, source_lines_after, "->", &strm); if (num_lines != 0) have_source = true; // TODO: Give here a one time warning if source file is missing. + if (!m_sc.line_entry.line) { + ConstString fn_name = m_sc.GetFunctionName(); + + if (!fn_name.IsEmpty()) + strm.Printf( + "Note: this address is compiler-generated code in function " + "%s that has no source code associated with it.", + fn_name.AsCString()); + else + strm.Printf("Note: this address is compiler-generated code that " + "has no source code associated with it."); + strm.EOL(); + } } } switch (disasm_display) { @@ -1900,12 +1947,12 @@ bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool show_source, case Debugger::eStopDisassemblyTypeNoDebugInfo: if (have_debuginfo) break; - LLVM_FALLTHROUGH; + [[fallthrough]]; case Debugger::eStopDisassemblyTypeNoSource: if (have_source) break; - LLVM_FALLTHROUGH; + [[fallthrough]]; case Debugger::eStopDisassemblyTypeAlways: if (target) { diff --git a/gnu/llvm/lldb/source/Target/StackFrameList.cpp b/gnu/llvm/lldb/source/Target/StackFrameList.cpp index 061500152a4..c782b506a9c 100644 --- a/gnu/llvm/lldb/source/Target/StackFrameList.cpp +++ b/gnu/llvm/lldb/source/Target/StackFrameList.cpp @@ -21,6 +21,7 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/Unwind.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "llvm/ADT/SmallPtrSet.h" @@ -65,7 +66,7 @@ uint32_t StackFrameList::GetCurrentInlinedDepth() { if (cur_pc != m_current_inlined_pc) { m_current_inlined_pc = LLDB_INVALID_ADDRESS; m_current_inlined_depth = UINT32_MAX; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (log && log->GetVerbose()) LLDB_LOGF( log, @@ -89,7 +90,7 @@ void StackFrameList::ResetCurrentInlinedDepth() { if (!m_frames[0]->IsInlined()) { m_current_inlined_depth = UINT32_MAX; m_current_inlined_pc = LLDB_INVALID_ADDRESS; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (log && log->GetVerbose()) LLDB_LOGF( log, @@ -167,7 +168,7 @@ void StackFrameList::ResetCurrentInlinedDepth() { break; } } - LLVM_FALLTHROUGH; + [[fallthrough]]; default: { // Otherwise, we should set ourselves at the container of the inlining, so // that the user can descend into them. So first we check whether we have @@ -187,7 +188,7 @@ void StackFrameList::ResetCurrentInlinedDepth() { } m_current_inlined_pc = curr_pc; m_current_inlined_depth = num_inlined_functions + 1; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (log && log->GetVerbose()) LLDB_LOGF(log, "ResetCurrentInlinedDepth: setting inlined " @@ -376,7 +377,7 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) { if (!next_reg_ctx_sp) return; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); StackFrame &prev_frame = *m_frames.back().get(); diff --git a/gnu/llvm/lldb/source/Target/StackFrameRecognizer.cpp b/gnu/llvm/lldb/source/Target/StackFrameRecognizer.cpp index 73d22d5bb4e..0ccb1ae9c03 100644 --- a/gnu/llvm/lldb/source/Target/StackFrameRecognizer.cpp +++ b/gnu/llvm/lldb/source/Target/StackFrameRecognizer.cpp @@ -77,7 +77,7 @@ void StackFrameRecognizerManager::ForEach( symbol_name = entry.symbol_regexp->GetText().str(); callback(entry.recognizer_id, entry.recognizer->GetName(), module_name, - llvm::makeArrayRef(ConstString(symbol_name)), true); + llvm::ArrayRef(ConstString(symbol_name)), true); } else { callback(entry.recognizer_id, entry.recognizer->GetName(), diff --git a/gnu/llvm/lldb/source/Target/Statistics.cpp b/gnu/llvm/lldb/source/Target/Statistics.cpp new file mode 100644 index 00000000000..c739ac7058c --- /dev/null +++ b/gnu/llvm/lldb/source/Target/Statistics.cpp @@ -0,0 +1,315 @@ +//===-- Statistics.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/Statistics.h" + +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Module.h" +#include "lldb/Symbol/SymbolFile.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/UnixSignals.h" + +using namespace lldb; +using namespace lldb_private; +using namespace llvm; + +static void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key, + const std::string &str) { + if (str.empty()) + return; + if (LLVM_LIKELY(llvm::json::isUTF8(str))) + obj.try_emplace(key, str); + else + obj.try_emplace(key, llvm::json::fixUTF8(str)); +} + +json::Value StatsSuccessFail::ToJSON() const { + return json::Object{{"successes", successes}, {"failures", failures}}; +} + +static double elapsed(const StatsTimepoint &start, const StatsTimepoint &end) { + StatsDuration::Duration elapsed = + end.time_since_epoch() - start.time_since_epoch(); + return elapsed.count(); +} + +void TargetStats::CollectStats(Target &target) { + m_module_identifiers.clear(); + for (ModuleSP module_sp : target.GetImages().Modules()) + m_module_identifiers.emplace_back((intptr_t)module_sp.get()); +} + +json::Value ModuleStats::ToJSON() const { + json::Object module; + EmplaceSafeString(module, "path", path); + EmplaceSafeString(module, "uuid", uuid); + EmplaceSafeString(module, "triple", triple); + module.try_emplace("identifier", identifier); + module.try_emplace("symbolTableParseTime", symtab_parse_time); + module.try_emplace("symbolTableIndexTime", symtab_index_time); + module.try_emplace("symbolTableLoadedFromCache", symtab_loaded_from_cache); + module.try_emplace("symbolTableSavedToCache", symtab_saved_to_cache); + module.try_emplace("debugInfoParseTime", debug_parse_time); + module.try_emplace("debugInfoIndexTime", debug_index_time); + module.try_emplace("debugInfoByteSize", (int64_t)debug_info_size); + module.try_emplace("debugInfoIndexLoadedFromCache", + debug_info_index_loaded_from_cache); + module.try_emplace("debugInfoIndexSavedToCache", + debug_info_index_saved_to_cache); + module.try_emplace("debugInfoEnabled", debug_info_enabled); + module.try_emplace("debugInfoHadVariableErrors", + debug_info_had_variable_errors); + module.try_emplace("debugInfoHadIncompleteTypes", + debug_info_had_incomplete_types); + module.try_emplace("symbolTableStripped", symtab_stripped); + if (!symfile_path.empty()) + module.try_emplace("symbolFilePath", symfile_path); + + if (!symfile_modules.empty()) { + json::Array symfile_ids; + for (const auto symfile_id: symfile_modules) + symfile_ids.emplace_back(symfile_id); + module.try_emplace("symbolFileModuleIdentifiers", std::move(symfile_ids)); + } + + if (!type_system_stats.empty()) { + json::Array type_systems; + for (const auto &entry : type_system_stats) { + json::Object obj; + obj.try_emplace(entry.first().str(), entry.second); + type_systems.emplace_back(std::move(obj)); + } + module.try_emplace("typeSystemInfo", std::move(type_systems)); + } + + return module; +} + +llvm::json::Value ConstStringStats::ToJSON() const { + json::Object obj; + obj.try_emplace<int64_t>("bytesTotal", stats.GetBytesTotal()); + obj.try_emplace<int64_t>("bytesUsed", stats.GetBytesUsed()); + obj.try_emplace<int64_t>("bytesUnused", stats.GetBytesUnused()); + return obj; +} + +json::Value TargetStats::ToJSON(Target &target) { + CollectStats(target); + + json::Array json_module_uuid_array; + for (auto module_identifier : m_module_identifiers) + json_module_uuid_array.emplace_back(module_identifier); + + json::Object target_metrics_json{ + {m_expr_eval.name, m_expr_eval.ToJSON()}, + {m_frame_var.name, m_frame_var.ToJSON()}, + {"moduleIdentifiers", std::move(json_module_uuid_array)}}; + + if (m_launch_or_attach_time && m_first_private_stop_time) { + double elapsed_time = + elapsed(*m_launch_or_attach_time, *m_first_private_stop_time); + target_metrics_json.try_emplace("launchOrAttachTime", elapsed_time); + } + if (m_launch_or_attach_time && m_first_public_stop_time) { + double elapsed_time = + elapsed(*m_launch_or_attach_time, *m_first_public_stop_time); + target_metrics_json.try_emplace("firstStopTime", elapsed_time); + } + target_metrics_json.try_emplace("targetCreateTime", + m_create_time.get().count()); + + json::Array breakpoints_array; + double totalBreakpointResolveTime = 0.0; + // Rport both the normal breakpoint list and the internal breakpoint list. + for (int i = 0; i < 2; ++i) { + BreakpointList &breakpoints = target.GetBreakpointList(i == 1); + std::unique_lock<std::recursive_mutex> lock; + breakpoints.GetListMutex(lock); + size_t num_breakpoints = breakpoints.GetSize(); + for (size_t i = 0; i < num_breakpoints; i++) { + Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get(); + breakpoints_array.push_back(bp->GetStatistics()); + totalBreakpointResolveTime += bp->GetResolveTime().count(); + } + } + + ProcessSP process_sp = target.GetProcessSP(); + if (process_sp) { + UnixSignalsSP unix_signals_sp = process_sp->GetUnixSignals(); + if (unix_signals_sp) + target_metrics_json.try_emplace("signals", + unix_signals_sp->GetHitCountStatistics()); + uint32_t stop_id = process_sp->GetStopID(); + target_metrics_json.try_emplace("stopCount", stop_id); + } + target_metrics_json.try_emplace("breakpoints", std::move(breakpoints_array)); + target_metrics_json.try_emplace("totalBreakpointResolveTime", + totalBreakpointResolveTime); + target_metrics_json.try_emplace("sourceMapDeduceCount", m_source_map_deduce_count); + + return target_metrics_json; +} + +void TargetStats::SetLaunchOrAttachTime() { + m_launch_or_attach_time = StatsClock::now(); + m_first_private_stop_time = std::nullopt; +} + +void TargetStats::SetFirstPrivateStopTime() { + // Launching and attaching has many paths depending on if synchronous mode + // was used or if we are stopping at the entry point or not. Only set the + // first stop time if it hasn't already been set. + if (!m_first_private_stop_time) + m_first_private_stop_time = StatsClock::now(); +} + +void TargetStats::SetFirstPublicStopTime() { + // Launching and attaching has many paths depending on if synchronous mode + // was used or if we are stopping at the entry point or not. Only set the + // first stop time if it hasn't already been set. + if (!m_first_public_stop_time) + m_first_public_stop_time = StatsClock::now(); +} + +void TargetStats::IncreaseSourceMapDeduceCount() { + ++m_source_map_deduce_count; +} + +bool DebuggerStats::g_collecting_stats = false; + +llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger, + Target *target) { + json::Array json_targets; + json::Array json_modules; + double symtab_parse_time = 0.0; + double symtab_index_time = 0.0; + double debug_parse_time = 0.0; + double debug_index_time = 0.0; + uint32_t symtabs_loaded = 0; + uint32_t symtabs_saved = 0; + uint32_t debug_index_loaded = 0; + uint32_t debug_index_saved = 0; + uint64_t debug_info_size = 0; + if (target) { + json_targets.emplace_back(target->ReportStatistics()); + } else { + for (const auto &target : debugger.GetTargetList().Targets()) + json_targets.emplace_back(target->ReportStatistics()); + } + std::vector<ModuleStats> modules; + std::lock_guard<std::recursive_mutex> guard( + Module::GetAllocationModuleCollectionMutex()); + const uint64_t num_modules = Module::GetNumberAllocatedModules(); + uint32_t num_debug_info_enabled_modules = 0; + uint32_t num_modules_has_debug_info = 0; + uint32_t num_modules_with_variable_errors = 0; + uint32_t num_modules_with_incomplete_types = 0; + uint32_t num_stripped_modules = 0; + for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) { + Module *module = Module::GetAllocatedModuleAtIndex(image_idx); + ModuleStats module_stat; + module_stat.identifier = (intptr_t)module; + module_stat.path = module->GetFileSpec().GetPath(); + if (ConstString object_name = module->GetObjectName()) { + module_stat.path.append(1, '('); + module_stat.path.append(object_name.GetStringRef().str()); + module_stat.path.append(1, ')'); + } + module_stat.uuid = module->GetUUID().GetAsString(); + module_stat.triple = module->GetArchitecture().GetTriple().str(); + module_stat.symtab_parse_time = module->GetSymtabParseTime().get().count(); + module_stat.symtab_index_time = module->GetSymtabIndexTime().get().count(); + Symtab *symtab = module->GetSymtab(); + if (symtab) { + module_stat.symtab_loaded_from_cache = symtab->GetWasLoadedFromCache(); + if (module_stat.symtab_loaded_from_cache) + ++symtabs_loaded; + module_stat.symtab_saved_to_cache = symtab->GetWasSavedToCache(); + if (module_stat.symtab_saved_to_cache) + ++symtabs_saved; + } + SymbolFile *sym_file = module->GetSymbolFile(); + if (sym_file) { + + if (sym_file->GetObjectFile() != module->GetObjectFile()) + module_stat.symfile_path = + sym_file->GetObjectFile()->GetFileSpec().GetPath(); + module_stat.debug_index_time = sym_file->GetDebugInfoIndexTime().count(); + module_stat.debug_parse_time = sym_file->GetDebugInfoParseTime().count(); + module_stat.debug_info_size = sym_file->GetDebugInfoSize(); + module_stat.debug_info_index_loaded_from_cache = + sym_file->GetDebugInfoIndexWasLoadedFromCache(); + if (module_stat.debug_info_index_loaded_from_cache) + ++debug_index_loaded; + module_stat.debug_info_index_saved_to_cache = + sym_file->GetDebugInfoIndexWasSavedToCache(); + if (module_stat.debug_info_index_saved_to_cache) + ++debug_index_saved; + ModuleList symbol_modules = sym_file->GetDebugInfoModules(); + for (const auto &symbol_module: symbol_modules.Modules()) + module_stat.symfile_modules.push_back((intptr_t)symbol_module.get()); + module_stat.symtab_stripped = module->GetObjectFile()->IsStripped(); + if (module_stat.symtab_stripped) + ++num_stripped_modules; + module_stat.debug_info_enabled = sym_file->GetLoadDebugInfoEnabled() && + module_stat.debug_info_size > 0; + module_stat.debug_info_had_variable_errors = + sym_file->GetDebugInfoHadFrameVariableErrors(); + if (module_stat.debug_info_enabled) + ++num_debug_info_enabled_modules; + if (module_stat.debug_info_size > 0) + ++num_modules_has_debug_info; + if (module_stat.debug_info_had_variable_errors) + ++num_modules_with_variable_errors; + } + symtab_parse_time += module_stat.symtab_parse_time; + symtab_index_time += module_stat.symtab_index_time; + debug_parse_time += module_stat.debug_parse_time; + debug_index_time += module_stat.debug_index_time; + debug_info_size += module_stat.debug_info_size; + module->ForEachTypeSystem([&](lldb::TypeSystemSP ts) { + if (auto stats = ts->ReportStatistics()) + module_stat.type_system_stats.insert({ts->GetPluginName(), *stats}); + if (ts->GetHasForcefullyCompletedTypes()) + module_stat.debug_info_had_incomplete_types = true; + return true; + }); + if (module_stat.debug_info_had_incomplete_types) + ++num_modules_with_incomplete_types; + + json_modules.emplace_back(module_stat.ToJSON()); + } + + ConstStringStats const_string_stats; + json::Object json_memory{ + {"strings", const_string_stats.ToJSON()}, + }; + + json::Object global_stats{ + {"targets", std::move(json_targets)}, + {"modules", std::move(json_modules)}, + {"memory", std::move(json_memory)}, + {"totalSymbolTableParseTime", symtab_parse_time}, + {"totalSymbolTableIndexTime", symtab_index_time}, + {"totalSymbolTablesLoadedFromCache", symtabs_loaded}, + {"totalSymbolTablesSavedToCache", symtabs_saved}, + {"totalDebugInfoParseTime", debug_parse_time}, + {"totalDebugInfoIndexTime", debug_index_time}, + {"totalDebugInfoIndexLoadedFromCache", debug_index_loaded}, + {"totalDebugInfoIndexSavedToCache", debug_index_saved}, + {"totalDebugInfoByteSize", debug_info_size}, + {"totalModuleCount", num_modules}, + {"totalModuleCountHasDebugInfo", num_modules_has_debug_info}, + {"totalModuleCountWithVariableErrors", num_modules_with_variable_errors}, + {"totalModuleCountWithIncompleteTypes", num_modules_with_incomplete_types}, + {"totalDebugInfoEnabled", num_debug_info_enabled_modules}, + {"totalSymbolTableStripped", num_stripped_modules}, + }; + return std::move(global_stats); +} diff --git a/gnu/llvm/lldb/source/Target/StopInfo.cpp b/gnu/llvm/lldb/source/Target/StopInfo.cpp index aeb97f1919e..225234c0ffb 100644 --- a/gnu/llvm/lldb/source/Target/StopInfo.cpp +++ b/gnu/llvm/lldb/source/Target/StopInfo.cpp @@ -20,7 +20,9 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlan.h" +#include "lldb/Target/ThreadPlanStepInstruction.h" #include "lldb/Target/UnixSignals.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" @@ -87,7 +89,7 @@ public: : StopInfo(thread, break_id), m_should_stop(false), m_should_stop_is_valid(false), m_should_perform_action(true), m_address(LLDB_INVALID_ADDRESS), m_break_id(LLDB_INVALID_BREAK_ID), - m_was_one_shot(false) { + m_was_all_internal(false), m_was_one_shot(false) { StoreBPInfo(); } @@ -95,7 +97,7 @@ public: : StopInfo(thread, break_id), m_should_stop(should_stop), m_should_stop_is_valid(true), m_should_perform_action(true), m_address(LLDB_INVALID_ADDRESS), m_break_id(LLDB_INVALID_BREAK_ID), - m_was_one_shot(false) { + m_was_all_internal(false), m_was_one_shot(false) { StoreBPInfo(); } @@ -107,11 +109,22 @@ public: BreakpointSiteSP bp_site_sp( thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value)); if (bp_site_sp) { - if (bp_site_sp->GetNumberOfOwners() == 1) { + uint32_t num_owners = bp_site_sp->GetNumberOfOwners(); + if (num_owners == 1) { BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(0); if (bp_loc_sp) { - m_break_id = bp_loc_sp->GetBreakpoint().GetID(); - m_was_one_shot = bp_loc_sp->GetBreakpoint().IsOneShot(); + Breakpoint & bkpt = bp_loc_sp->GetBreakpoint(); + m_break_id = bkpt.GetID(); + m_was_one_shot = bkpt.IsOneShot(); + m_was_all_internal = bkpt.IsInternal(); + } + } else { + m_was_all_internal = true; + for (uint32_t i = 0; i < num_owners; i++) { + if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal()) { + m_was_all_internal = false; + break; + } } } m_address = bp_site_sp->GetLoadAddress(); @@ -145,7 +158,7 @@ public: bp_site_sp->BumpHitCounts(); m_should_stop = bp_site_sp->ShouldStop(&context); } else { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "Process::%s could not find breakpoint site id: %" PRId64 @@ -162,23 +175,7 @@ public: } bool DoShouldNotify(Event *event_ptr) override { - ThreadSP thread_sp(m_thread_wp.lock()); - if (thread_sp) { - BreakpointSiteSP bp_site_sp( - thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value)); - if (bp_site_sp) { - bool all_internal = true; - - for (uint32_t i = 0; i < bp_site_sp->GetNumberOfOwners(); i++) { - if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal()) { - all_internal = false; - break; - } - } - return !all_internal; - } - } - return true; + return !m_was_all_internal; } const char *GetDescription() override { @@ -264,8 +261,7 @@ protected: ThreadSP thread_sp(m_thread_wp.lock()); if (thread_sp) { - Log *log = lldb_private::GetLogIfAnyCategoriesSet( - LIBLLDB_LOG_BREAKPOINTS | LIBLLDB_LOG_STEP); + Log *log = GetLog(LLDBLog::Breakpoints | LLDBLog::Step); if (!thread_sp->IsValid()) { // This shouldn't ever happen, but just in case, don't do more harm. @@ -280,7 +276,13 @@ protected: BreakpointSiteSP bp_site_sp( thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value)); std::unordered_set<break_id_t> precondition_breakpoints; - + // Breakpoints that fail their condition check are not considered to + // have been hit. If the only locations at this site have failed their + // conditions, we should change the stop-info to none. Otherwise, if we + // hit another breakpoint on a different thread which does stop, users + // will see a breakpont hit with a failed condition, which is wrong. + // Use this variable to tell us if that is true. + bool actually_hit_any_locations = false; if (bp_site_sp) { // Let's copy the owners list out of the site and store them in a local // list. That way if one of the breakpoint actions changes the site, @@ -290,6 +292,8 @@ protected: if (num_owners == 0) { m_should_stop = true; + actually_hit_any_locations = true; // We're going to stop, don't + // change the stop info. } else { // We go through each location, and test first its precondition - // this overrides everything. Note, we only do this once per @@ -307,7 +311,7 @@ protected: // There's one other complication here. We may have run an async // breakpoint callback that said we should stop. We only want to - // override that if another breakpoint action says we shouldn't + // override that if another breakpoint action says we shouldn't // stop. If nobody else has an opinion, then we should stop if the // async callback says we should. An example of this is the async // shared library load notification breakpoint and the setting @@ -358,28 +362,21 @@ protected: " not running commands to avoid recursion."); bool ignoring_breakpoints = process->GetIgnoreBreakpointsInExpressions(); - if (ignoring_breakpoints) { - m_should_stop = false; - // Internal breakpoints will always stop. - for (size_t j = 0; j < num_owners; j++) { - lldb::BreakpointLocationSP bp_loc_sp = - bp_site_sp->GetOwnerAtIndex(j); - if (bp_loc_sp->GetBreakpoint().IsInternal()) { - m_should_stop = true; - break; - } - } - } else { - m_should_stop = true; + // Internal breakpoints should be allowed to do their job, we + // can make sure they don't do anything that would cause recursive + // command execution: + if (!m_was_all_internal) { + m_should_stop = !ignoring_breakpoints; + LLDB_LOGF(log, + "StopInfoBreakpoint::PerformAction - in expression, " + "continuing: %s.", + m_should_stop ? "true" : "false"); + Debugger::ReportWarning( + "hit breakpoint while running function, skipping commands " + "and conditions to prevent recursion", + process->GetTarget().GetDebugger().GetID()); + return; } - LLDB_LOGF(log, - "StopInfoBreakpoint::PerformAction - in expression, " - "continuing: %s.", - m_should_stop ? "true" : "false"); - process->GetTarget().GetDebugger().GetAsyncOutputStream()->Printf( - "Warning: hit breakpoint while running function, skipping " - "commands and conditions to prevent recursion.\n"); - return; } StoppointCallbackContext context(event_ptr, exe_ctx, false); @@ -425,7 +422,7 @@ protected: } internal_breakpoint = bp_loc_sp->GetBreakpoint().IsInternal(); - + // First run the precondition, but since the precondition is per // breakpoint, only run it once per breakpoint. std::pair<std::unordered_set<break_id_t>::iterator, bool> result = @@ -444,27 +441,31 @@ protected: // should stop, then we'll run the callback for the breakpoint. If // the callback says we shouldn't stop that will win. - if (bp_loc_sp->GetConditionText() != nullptr) { + if (bp_loc_sp->GetConditionText() == nullptr) + actually_hit_any_locations = true; + else { Status condition_error; bool condition_says_stop = bp_loc_sp->ConditionSaysStop(exe_ctx, condition_error); if (!condition_error.Success()) { - Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger(); - StreamSP error_sp = debugger.GetAsyncErrorStream(); - error_sp->Printf("Stopped due to an error evaluating condition " - "of breakpoint "); - bp_loc_sp->GetDescription(error_sp.get(), - eDescriptionLevelBrief); - error_sp->Printf(": \"%s\"", bp_loc_sp->GetConditionText()); - error_sp->EOL(); + // If the condition fails to evaluate, we are going to stop + // at it, so the location was hit. + actually_hit_any_locations = true; const char *err_str = - condition_error.AsCString("<Unknown Error>"); + condition_error.AsCString("<unknown error>"); LLDB_LOGF(log, "Error evaluating condition: \"%s\"\n", err_str); - error_sp->PutCString(err_str); - error_sp->EOL(); - error_sp->Flush(); + StreamString strm; + strm << "stopped due to an error evaluating condition of " + "breakpoint "; + bp_loc_sp->GetDescription(&strm, eDescriptionLevelBrief); + strm << ": \"" << bp_loc_sp->GetConditionText() << "\"\n"; + strm << err_str; + + Debugger::ReportError( + strm.GetString().str(), + exe_ctx.GetTargetRef().GetDebugger().GetID()); } else { LLDB_LOGF(log, "Condition evaluated for breakpoint %s on thread " @@ -472,7 +473,9 @@ protected: loc_desc.GetData(), static_cast<unsigned long long>(thread_sp->GetID()), condition_says_stop); - if (!condition_says_stop) { + if (condition_says_stop) + actually_hit_any_locations = true; + else { // We don't want to increment the hit count of breakpoints if // the condition fails. We've already bumped it by the time // we get here, so undo the bump: @@ -535,7 +538,7 @@ protected: else actually_said_continue = true; } - + // If we are going to stop for this breakpoint, then remove the // breakpoint. if (callback_says_stop && bp_loc_sp && @@ -564,8 +567,8 @@ protected: } else { m_should_stop = true; m_should_stop_is_valid = true; - Log *log_process( - lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + actually_hit_any_locations = true; + Log *log_process(GetLog(LLDBLog::Process)); LLDB_LOGF(log_process, "Process::%s could not find breakpoint site id: %" PRId64 @@ -579,11 +582,17 @@ protected: // Override should_stop decision when we have completed step plan // additionally to the breakpoint m_should_stop = true; - + // We know we're stopping for a completed plan and we don't want to // show the breakpoint stop, so compute the public stop info immediately // here. thread_sp->CalculatePublicStopInfo(); + } else if (!actually_hit_any_locations) { + // In the end, we didn't actually have any locations that passed their + // "was I hit" checks. So say we aren't stopped. + GetThread()->ResetStopInfo(); + LLDB_LOGF(log, "Process::%s all locations failed condition checks.", + __FUNCTION__); } LLDB_LOGF(log, @@ -604,6 +613,7 @@ private: // in case somebody deletes it between the time the StopInfo is made and the // description is asked for. lldb::break_id_t m_break_id; + bool m_was_all_internal; bool m_was_one_shot; }; @@ -615,7 +625,7 @@ public: // performing watchpoint actions. class WatchpointSentry { public: - WatchpointSentry(ProcessSP p_sp, WatchpointSP w_sp) : process_sp(p_sp), + WatchpointSentry(ProcessSP p_sp, WatchpointSP w_sp) : process_sp(p_sp), watchpoint_sp(w_sp) { if (process_sp && watchpoint_sp) { const bool notify = false; @@ -624,7 +634,7 @@ public: process_sp->AddPreResumeAction(SentryPreResumeAction, this); } } - + void DoReenable() { if (process_sp && watchpoint_sp) { bool was_disabled = watchpoint_sp->IsDisabledDuringEphemeralMode(); @@ -637,13 +647,13 @@ public: } } } - + ~WatchpointSentry() { DoReenable(); if (process_sp) process_sp->ClearPreResumeAction(SentryPreResumeAction, this); } - + static bool SentryPreResumeAction(void *sentry_void) { WatchpointSentry *sentry = (WatchpointSentry *) sentry_void; sentry->DoReenable(); @@ -657,8 +667,7 @@ public: StopInfoWatchpoint(Thread &thread, break_id_t watch_id, lldb::addr_t watch_hit_addr) - : StopInfo(thread, watch_id), m_should_stop(false), - m_should_stop_is_valid(false), m_watch_hit_addr(watch_hit_addr) {} + : StopInfo(thread, watch_id), m_watch_hit_addr(watch_hit_addr) {} ~StopInfoWatchpoint() override = default; @@ -674,39 +683,184 @@ public: } protected: + using StopInfoWatchpointSP = std::shared_ptr<StopInfoWatchpoint>; + // This plan is used to orchestrate stepping over the watchpoint for + // architectures (e.g. ARM) that report the watch before running the watched + // access. This is the sort of job you have to defer to the thread plans, + // if you try to do it directly in the stop info and there are other threads + // that needed to process this stop you will have yanked control away from + // them and they won't behave correctly. + class ThreadPlanStepOverWatchpoint : public ThreadPlanStepInstruction { + public: + ThreadPlanStepOverWatchpoint(Thread &thread, + StopInfoWatchpointSP stop_info_sp, + WatchpointSP watch_sp) + : ThreadPlanStepInstruction(thread, false, true, eVoteNoOpinion, + eVoteNoOpinion), + m_stop_info_sp(stop_info_sp), m_watch_sp(watch_sp) { + assert(watch_sp); + m_watch_index = watch_sp->GetHardwareIndex(); + } + + bool DoWillResume(lldb::StateType resume_state, + bool current_plan) override { + if (resume_state == eStateSuspended) + return true; + + if (!m_did_disable_wp) { + GetThread().GetProcess()->DisableWatchpoint(m_watch_sp.get(), false); + m_did_disable_wp = true; + } + return true; + } + + bool DoPlanExplainsStop(Event *event_ptr) override { + if (ThreadPlanStepInstruction::DoPlanExplainsStop(event_ptr)) + return true; + StopInfoSP stop_info_sp = GetThread().GetPrivateStopInfo(); + // lldb-server resets the stop info for threads that didn't get to run, + // so we might have not gotten to run, but still have a watchpoint stop + // reason, in which case this will indeed be for us. + if (stop_info_sp + && stop_info_sp->GetStopReason() == eStopReasonWatchpoint) + return true; + return false; + } + + void DidPop() override { + // Don't artifically keep the watchpoint alive. + m_watch_sp.reset(); + } + + bool ShouldStop(Event *event_ptr) override { + bool should_stop = ThreadPlanStepInstruction::ShouldStop(event_ptr); + bool plan_done = MischiefManaged(); + if (plan_done) { + m_stop_info_sp->SetStepOverPlanComplete(); + GetThread().SetStopInfo(m_stop_info_sp); + ResetWatchpoint(); + } + return should_stop; + } + + bool ShouldRunBeforePublicStop() override { + return true; + } + + protected: + void ResetWatchpoint() { + if (!m_did_disable_wp) + return; + m_did_disable_wp = true; + GetThread().GetProcess()->EnableWatchpoint(m_watch_sp.get(), true); + m_watch_sp->SetHardwareIndex(m_watch_index); + } + + private: + StopInfoWatchpointSP m_stop_info_sp; + WatchpointSP m_watch_sp; + uint32_t m_watch_index = LLDB_INVALID_INDEX32; + bool m_did_disable_wp = false; + }; + bool ShouldStopSynchronous(Event *event_ptr) override { - // ShouldStop() method is idempotent and should not affect hit count. See - // Process::RunPrivateStateThread()->Process()->HandlePrivateEvent() - // -->Process()::ShouldBroadcastEvent()->ThreadList::ShouldStop()-> - // Thread::ShouldStop()->ThreadPlanBase::ShouldStop()-> - // StopInfoWatchpoint::ShouldStop() and - // Event::DoOnRemoval()->Process::ProcessEventData::DoOnRemoval()-> - // StopInfoWatchpoint::PerformAction(). + // If we are running our step-over the watchpoint plan, stop if it's done + // and continue if it's not: if (m_should_stop_is_valid) return m_should_stop; + // If we are running our step over plan, then stop here and let the regular + // ShouldStop figure out what we should do: Otherwise, give our plan + // more time to get run: + if (m_using_step_over_plan) + return m_step_over_plan_complete; + + Log *log = GetLog(LLDBLog::Process); ThreadSP thread_sp(m_thread_wp.lock()); - if (thread_sp) { - WatchpointSP wp_sp( - thread_sp->CalculateTarget()->GetWatchpointList().FindByID( - GetValue())); - if (wp_sp) { - // Check if we should stop at a watchpoint. - ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0)); - StoppointCallbackContext context(event_ptr, exe_ctx, true); - m_should_stop = wp_sp->ShouldStop(&context); - } else { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + assert(thread_sp); + + if (thread_sp->GetTemporaryResumeState() == eStateSuspended) { + // This is the second firing of a watchpoint so don't process it again. + LLDB_LOG(log, "We didn't run but stopped with a StopInfoWatchpoint, we " + "have already handled this one, don't do it again."); + m_should_stop = false; + m_should_stop_is_valid = true; + return m_should_stop; + } + + WatchpointSP wp_sp( + thread_sp->CalculateTarget()->GetWatchpointList().FindByID(GetValue())); + // If we can no longer find the watchpoint, we just have to stop: + if (!wp_sp) { - LLDB_LOGF(log, - "Process::%s could not find watchpoint location id: %" PRId64 - "...", - __FUNCTION__, GetValue()); + LLDB_LOGF(log, + "Process::%s could not find watchpoint location id: %" PRId64 + "...", + __FUNCTION__, GetValue()); + + m_should_stop = true; + m_should_stop_is_valid = true; + return true; + } + + ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0)); + StoppointCallbackContext context(event_ptr, exe_ctx, true); + m_should_stop = wp_sp->ShouldStop(&context); + if (!m_should_stop) { + // This won't happen at present because we only allow one watchpoint per + // watched range. So we won't stop at a watched address with a disabled + // watchpoint. If we start allowing overlapping watchpoints, then we + // will have to make watchpoints be real "WatchpointSite" and delegate to + // all the watchpoints sharing the site. In that case, the code below + // would be the right thing to do. + m_should_stop_is_valid = true; + return m_should_stop; + } + // If this is a system where we need to execute the watchpoint by hand + // after the hit, queue a thread plan to do that, and then say not to stop. + // Otherwise, let the async action figure out whether the watchpoint should + // stop + + ProcessSP process_sp = exe_ctx.GetProcessSP(); + uint32_t num; + bool wp_triggers_after; + + if (!process_sp->GetWatchpointSupportInfo(num, wp_triggers_after) + .Success()) { + m_should_stop_is_valid = true; + m_should_stop = true; + return m_should_stop; + } + + if (!wp_triggers_after) { + // We have to step over the watchpoint before we know what to do: + StopInfoWatchpointSP me_as_siwp_sp + = std::static_pointer_cast<StopInfoWatchpoint>(shared_from_this()); + ThreadPlanSP step_over_wp_sp(new ThreadPlanStepOverWatchpoint( + *(thread_sp.get()), me_as_siwp_sp, wp_sp)); + Status error; + error = thread_sp->QueueThreadPlan(step_over_wp_sp, false); + // If we couldn't push the thread plan, just stop here: + if (!error.Success()) { + LLDB_LOGF(log, "Could not push our step over watchpoint plan: %s", + error.AsCString()); m_should_stop = true; + m_should_stop_is_valid = true; + return true; + } else { + // Otherwise, don't set m_should_stop, we don't know that yet. Just + // say we should continue, and tell the thread we really should do so: + thread_sp->SetShouldRunBeforePublicStop(true); + m_using_step_over_plan = true; + return false; } + } else { + // We didn't have to do anything special + m_should_stop_is_valid = true; + return m_should_stop; } - m_should_stop_is_valid = true; + return m_should_stop; } @@ -719,71 +873,26 @@ protected: } void PerformAction(Event *event_ptr) override { - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS); + Log *log = GetLog(LLDBLog::Watchpoints); // We're going to calculate if we should stop or not in some way during the // course of this code. Also by default we're going to stop, so set that // here. m_should_stop = true; - + ThreadSP thread_sp(m_thread_wp.lock()); if (thread_sp) { WatchpointSP wp_sp( thread_sp->CalculateTarget()->GetWatchpointList().FindByID( - GetValue())); + GetValue())); if (wp_sp) { - ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0)); - ProcessSP process_sp = exe_ctx.GetProcessSP(); - - { - // check if this process is running on an architecture where - // watchpoints trigger before the associated instruction runs. if so, - // disable the WP, single-step and then re-enable the watchpoint - if (process_sp) { - uint32_t num; - bool wp_triggers_after; - - if (process_sp->GetWatchpointSupportInfo(num, wp_triggers_after) - .Success()) { - if (!wp_triggers_after) { - // We need to preserve the watch_index before watchpoint is - // disable. Since Watchpoint::SetEnabled will clear the watch - // index. This will fix TestWatchpointIter failure - Watchpoint *wp = wp_sp.get(); - uint32_t watch_index = wp->GetHardwareIndex(); - process_sp->DisableWatchpoint(wp, false); - StopInfoSP stored_stop_info_sp = thread_sp->GetStopInfo(); - assert(stored_stop_info_sp.get() == this); - - Status new_plan_status; - ThreadPlanSP new_plan_sp( - thread_sp->QueueThreadPlanForStepSingleInstruction( - false, // step-over - false, // abort_other_plans - true, // stop_other_threads - new_plan_status)); - if (new_plan_sp && new_plan_status.Success()) { - new_plan_sp->SetIsMasterPlan(true); - new_plan_sp->SetOkayToDiscard(false); - new_plan_sp->SetPrivate(true); - } - process_sp->GetThreadList().SetSelectedThreadByID( - thread_sp->GetID()); - process_sp->ResumeSynchronous(nullptr); - process_sp->GetThreadList().SetSelectedThreadByID( - thread_sp->GetID()); - thread_sp->SetStopInfo(stored_stop_info_sp); - process_sp->EnableWatchpoint(wp, false); - wp->SetHardwareIndex(watch_index); - } - } - } - } - // This sentry object makes sure the current watchpoint is disabled // while performing watchpoint actions, and it is then enabled after we // are finished. + ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0)); + ProcessSP process_sp = exe_ctx.GetProcessSP(); + WatchpointSentry sentry(process_sp, wp_sp); /* @@ -809,18 +918,10 @@ protected: } } - // TODO: This condition should be checked in the synchronous part of the - // watchpoint code - // (Watchpoint::ShouldStop), so that we avoid pulling an event even if - // the watchpoint fails the ignore count condition. It is moved here - // temporarily, because for archs with - // watchpoint_exceptions_received=before, the code in the previous - // lines takes care of moving the inferior to next PC. We have to check - // the ignore count condition after this is done, otherwise we will hit - // same watchpoint multiple times until we pass ignore condition, but - // we won't actually be ignoring them. - if (wp_sp->GetHitCount() <= wp_sp->GetIgnoreCount()) + if (wp_sp->GetHitCount() <= wp_sp->GetIgnoreCount()) { m_should_stop = false; + m_should_stop_is_valid = true; + } Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger(); @@ -843,10 +944,9 @@ protected: Scalar scalar_value; if (result_value_sp->ResolveValue(scalar_value)) { if (scalar_value.ULongLong(1) == 0) { - // We have been vetoed. This takes precedence over querying - // the watchpoint whether it should stop (aka ignore count - // and friends). See also StopInfoWatchpoint::ShouldStop() - // as well as Process::ProcessEventData::DoOnRemoval(). + // The condition failed, which we consider "not having hit + // the watchpoint" so undo the hit count here. + wp_sp->UndoHitCount(); m_should_stop = false; } else m_should_stop = true; @@ -861,20 +961,18 @@ protected: } } } else { - StreamSP error_sp = debugger.GetAsyncErrorStream(); - error_sp->Printf( - "Stopped due to an error evaluating condition of watchpoint "); - wp_sp->GetDescription(error_sp.get(), eDescriptionLevelBrief); - error_sp->Printf(": \"%s\"", wp_sp->GetConditionText()); - error_sp->EOL(); - const char *err_str = error.AsCString("<Unknown Error>"); + const char *err_str = error.AsCString("<unknown error>"); LLDB_LOGF(log, "Error evaluating condition: \"%s\"\n", err_str); - error_sp->PutCString(err_str); - error_sp->EOL(); - error_sp->Flush(); - // If the condition fails to be parsed or run, we should stop. - m_should_stop = true; + StreamString strm; + strm << "stopped due to an error evaluating condition of " + "watchpoint "; + wp_sp->GetDescription(&strm, eDescriptionLevelBrief); + strm << ": \"" << wp_sp->GetConditionText() << "\"\n"; + strm << err_str; + + Debugger::ReportError(strm.GetString().str(), + exe_ctx.GetTargetRef().GetDebugger().GetID()); } } @@ -889,12 +987,12 @@ protected: bool old_async = debugger.GetAsyncExecution(); debugger.SetAsyncExecution(true); - + StoppointCallbackContext context(event_ptr, exe_ctx, false); bool stop_requested = wp_sp->InvokeCallback(&context); - + debugger.SetAsyncExecution(old_async); - + // Also make sure that the callback hasn't continued the target. If // it did, when we'll set m_should_stop to false and get out of here. if (HasTargetRunSinceMe()) @@ -917,8 +1015,7 @@ protected: } } else { - Log *log_process( - lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log_process(GetLog(LLDBLog::Process)); LLDB_LOGF(log_process, "Process::%s could not find watchpoint id: %" PRId64 "...", @@ -933,9 +1030,16 @@ protected: } private: - bool m_should_stop; - bool m_should_stop_is_valid; + void SetStepOverPlanComplete() { + assert(m_using_step_over_plan); + m_step_over_plan_complete = true; + } + + bool m_should_stop = false; + bool m_should_stop_is_valid = false; lldb::addr_t m_watch_hit_addr; + bool m_step_over_plan_complete = false; + bool m_using_step_over_plan = false; }; // StopInfoUnixSignal @@ -1124,8 +1228,7 @@ private: class StopInfoExec : public StopInfo { public: - StopInfoExec(Thread &thread) - : StopInfo(thread, LLDB_INVALID_UID), m_performed_action(false) {} + StopInfoExec(Thread &thread) : StopInfo(thread, LLDB_INVALID_UID) {} ~StopInfoExec() override = default; @@ -1151,7 +1254,103 @@ protected: thread_sp->GetProcess()->DidExec(); } - bool m_performed_action; + bool m_performed_action = false; +}; + +// StopInfoFork + +class StopInfoFork : public StopInfo { +public: + StopInfoFork(Thread &thread, lldb::pid_t child_pid, lldb::tid_t child_tid) + : StopInfo(thread, child_pid), m_child_pid(child_pid), + m_child_tid(child_tid) {} + + ~StopInfoFork() override = default; + + bool ShouldStop(Event *event_ptr) override { return false; } + + StopReason GetStopReason() const override { return eStopReasonFork; } + + const char *GetDescription() override { return "fork"; } + +protected: + void PerformAction(Event *event_ptr) override { + // Only perform the action once + if (m_performed_action) + return; + m_performed_action = true; + ThreadSP thread_sp(m_thread_wp.lock()); + if (thread_sp) + thread_sp->GetProcess()->DidFork(m_child_pid, m_child_tid); + } + + bool m_performed_action = false; + +private: + lldb::pid_t m_child_pid; + lldb::tid_t m_child_tid; +}; + +// StopInfoVFork + +class StopInfoVFork : public StopInfo { +public: + StopInfoVFork(Thread &thread, lldb::pid_t child_pid, lldb::tid_t child_tid) + : StopInfo(thread, child_pid), m_child_pid(child_pid), + m_child_tid(child_tid) {} + + ~StopInfoVFork() override = default; + + bool ShouldStop(Event *event_ptr) override { return false; } + + StopReason GetStopReason() const override { return eStopReasonVFork; } + + const char *GetDescription() override { return "vfork"; } + +protected: + void PerformAction(Event *event_ptr) override { + // Only perform the action once + if (m_performed_action) + return; + m_performed_action = true; + ThreadSP thread_sp(m_thread_wp.lock()); + if (thread_sp) + thread_sp->GetProcess()->DidVFork(m_child_pid, m_child_tid); + } + + bool m_performed_action = false; + +private: + lldb::pid_t m_child_pid; + lldb::tid_t m_child_tid; +}; + +// StopInfoVForkDone + +class StopInfoVForkDone : public StopInfo { +public: + StopInfoVForkDone(Thread &thread) : StopInfo(thread, 0) {} + + ~StopInfoVForkDone() override = default; + + bool ShouldStop(Event *event_ptr) override { return false; } + + StopReason GetStopReason() const override { return eStopReasonVForkDone; } + + const char *GetDescription() override { return "vforkdone"; } + +protected: + void PerformAction(Event *event_ptr) override { + // Only perform the action once + if (m_performed_action) + return; + m_performed_action = true; + ThreadSP thread_sp(m_thread_wp.lock()); + if (thread_sp) + thread_sp->GetProcess()->DidVForkDone(); + } + + bool m_performed_action = false; }; } // namespace lldb_private @@ -1175,6 +1374,7 @@ StopInfo::CreateStopReasonWithWatchpointID(Thread &thread, break_id_t watch_id, StopInfoSP StopInfo::CreateStopReasonWithSignal(Thread &thread, int signo, const char *description) { + thread.GetProcess()->GetUnixSignals()->IncrementSignalHitCount(signo); return StopInfoSP(new StopInfoUnixSignal(thread, signo, description)); } @@ -1203,6 +1403,23 @@ StopInfoSP StopInfo::CreateStopReasonWithExec(Thread &thread) { return StopInfoSP(new StopInfoExec(thread)); } +StopInfoSP StopInfo::CreateStopReasonFork(Thread &thread, + lldb::pid_t child_pid, + lldb::tid_t child_tid) { + return StopInfoSP(new StopInfoFork(thread, child_pid, child_tid)); +} + + +StopInfoSP StopInfo::CreateStopReasonVFork(Thread &thread, + lldb::pid_t child_pid, + lldb::tid_t child_tid) { + return StopInfoSP(new StopInfoVFork(thread, child_pid, child_tid)); +} + +StopInfoSP StopInfo::CreateStopReasonVForkDone(Thread &thread) { + return StopInfoSP(new StopInfoVForkDone(thread)); +} + ValueObjectSP StopInfo::GetReturnValueObject(StopInfoSP &stop_info_sp) { if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonPlanComplete) { diff --git a/gnu/llvm/lldb/source/Target/Target.cpp b/gnu/llvm/lldb/source/Target/Target.cpp index 1f8e8c54fa9..fd0cf0a5361 100644 --- a/gnu/llvm/lldb/source/Target/Target.cpp +++ b/gnu/llvm/lldb/source/Target/Target.cpp @@ -26,6 +26,7 @@ #include "lldb/Core/StreamFile.h" #include "lldb/Core/StructuredDataImpl.h" #include "lldb/Core/ValueObject.h" +#include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/ExpressionVariable.h" #include "lldb/Expression/REPL.h" @@ -51,18 +52,22 @@ #include "lldb/Target/SystemRuntime.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadSpec.h" +#include "lldb/Target/UnixSignals.h" #include "lldb/Utility/Event.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" #include "llvm/ADT/ScopeExit.h" +#include "llvm/ADT/SetVector.h" #include <memory> #include <mutex> +#include <optional> using namespace lldb; using namespace lldb_private; @@ -95,14 +100,10 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch, m_watchpoint_list(), m_process_sp(), m_search_filter_sp(), m_image_search_paths(ImageSearchPathsChanged, this), m_source_manager_up(), m_stop_hooks(), m_stop_hook_next_id(0), - m_latest_stop_hook_id(0), - m_valid(true), m_suppress_stop_hooks(false), + m_latest_stop_hook_id(0), m_valid(true), m_suppress_stop_hooks(false), m_is_dummy_target(is_dummy_target), m_frame_recognizer_manager_up( - std::make_unique<StackFrameRecognizerManager>()), - m_stats_storage(static_cast<int>(StatisticKind::StatisticMax)) - -{ + std::make_unique<StackFrameRecognizerManager>()) { SetEventName(eBroadcastBitBreakpointChanged, "breakpoint-changed"); SetEventName(eBroadcastBitModulesLoaded, "modules-loaded"); SetEventName(eBroadcastBitModulesUnloaded, "modules-unloaded"); @@ -111,10 +112,10 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch, CheckInWithManager(); - LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT), - "{0} Target::Target()", static_cast<void *>(this)); + LLDB_LOG(GetLog(LLDBLog::Object), "{0} Target::Target()", + static_cast<void *>(this)); if (target_arch.IsValid()) { - LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TARGET), + LLDB_LOG(GetLog(LLDBLog::Target), "Target::Target created with architecture {0} ({1})", target_arch.GetArchitectureName(), target_arch.GetTriple().getTriple().c_str()); @@ -124,7 +125,7 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch, } Target::~Target() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + Log *log = GetLog(LLDBLog::Object); LLDB_LOG(log, "{0} Target::~Target()", static_cast<void *>(this)); DeleteCurrentProcess(); } @@ -141,14 +142,14 @@ void Target::PrimeFromDummyTarget(Target &target) { AddBreakpoint(std::move(new_bp), false); } - for (auto bp_name_entry : target.m_breakpoint_names) { - - BreakpointName *new_bp_name = new BreakpointName(*bp_name_entry.second); - AddBreakpointName(new_bp_name); + for (const auto &bp_name_entry : target.m_breakpoint_names) { + AddBreakpointName(std::make_unique<BreakpointName>(*bp_name_entry.second)); } m_frame_recognizer_manager_up = std::make_unique<StackFrameRecognizerManager>( *target.m_frame_recognizer_manager_up); + + m_dummy_signals = target.m_dummy_signals; } void Target::Dump(Stream *s, lldb::DescriptionLevel description_level) { @@ -176,6 +177,7 @@ void Target::CleanupProcess() { // clean up needs some help from the process. m_breakpoint_list.ClearAllBreakpointSites(); m_internal_breakpoint_list.ClearAllBreakpointSites(); + ResetBreakpointHitCounts(); // Disable watchpoints just on the debugger side. std::unique_lock<std::recursive_mutex> lock; this->GetWatchpointList().GetListMutex(lock); @@ -187,6 +189,8 @@ void Target::CleanupProcess() { void Target::DeleteCurrentProcess() { if (m_process_sp) { + // We dispose any active tracing sessions on the current process + m_trace_sp.reset(); m_section_load_history.Clear(); if (m_process_sp->IsAlive()) m_process_sp->Destroy(false); @@ -215,17 +219,20 @@ const lldb::ProcessSP &Target::GetProcessSP() const { return m_process_sp; } lldb::REPLSP Target::GetREPL(Status &err, lldb::LanguageType language, const char *repl_options, bool can_create) { + if (language == eLanguageTypeUnknown) + language = m_debugger.GetREPLLanguage(); + if (language == eLanguageTypeUnknown) { LanguageSet repl_languages = Language::GetLanguagesSupportingREPLs(); if (auto single_lang = repl_languages.GetSingularLanguage()) { language = *single_lang; } else if (repl_languages.Empty()) { - err.SetErrorStringWithFormat( + err.SetErrorString( "LLDB isn't configured with REPL support for any languages."); return REPLSP(); } else { - err.SetErrorStringWithFormat( + err.SetErrorString( "Multiple possible REPL languages. Please specify a language."); return REPLSP(); } @@ -278,12 +285,26 @@ void Target::Destroy() { m_breakpoint_list.RemoveAll(notify); m_internal_breakpoint_list.RemoveAll(notify); m_last_created_breakpoint.reset(); + m_watchpoint_list.RemoveAll(notify); m_last_created_watchpoint.reset(); m_search_filter_sp.reset(); m_image_search_paths.Clear(notify); m_stop_hooks.clear(); m_stop_hook_next_id = 0; m_suppress_stop_hooks = false; + Args signal_args; + ClearDummySignals(signal_args); +} + +llvm::StringRef Target::GetABIName() const { + lldb::ABISP abi_sp; + if (m_process_sp) + abi_sp = m_process_sp->GetABI(); + if (!abi_sp) + abi_sp = ABI::FindPlugin(ProcessSP(), GetArchitecture()); + if (abi_sp) + return abi_sp->GetPluginName(); + return {}; } BreakpointList &Target::GetBreakpointList(bool internal) { @@ -336,7 +357,9 @@ BreakpointSP Target::CreateBreakpoint(const FileSpecList *containingModules, bool hardware, LazyBool move_to_nearest_code) { FileSpec remapped_file; - if (!GetSourcePathMap().ReverseRemapPath(file, remapped_file)) + std::optional<llvm::StringRef> removed_prefix_opt = + GetSourcePathMap().ReverseRemapPath(file, remapped_file); + if (!removed_prefix_opt) remapped_file = file; if (check_inlines == eLazyBoolCalculate) { @@ -380,7 +403,7 @@ BreakpointSP Target::CreateBreakpoint(const FileSpecList *containingModules, return nullptr; BreakpointResolverSP resolver_sp(new BreakpointResolverFileLine( - nullptr, offset, skip_prologue, location_spec)); + nullptr, offset, skip_prologue, location_spec, removed_prefix_opt)); return CreateBreakpoint(filter_sp, resolver_sp, internal, hardware, true); } @@ -619,12 +642,8 @@ lldb::BreakpointSP Target::CreateScriptedBreakpoint( shared_from_this()); } - StructuredDataImpl *extra_args_impl = new StructuredDataImpl(); - if (extra_args_sp) - extra_args_impl->SetObjectSP(extra_args_sp); - BreakpointResolverSP resolver_sp(new BreakpointResolverScripted( - nullptr, class_name, depth, extra_args_impl)); + nullptr, class_name, depth, StructuredDataImpl(extra_args_sp))); return CreateBreakpoint(filter_sp, resolver_sp, internal, false, true); } @@ -651,7 +670,7 @@ void Target::AddBreakpoint(lldb::BreakpointSP bp_sp, bool internal) { else m_breakpoint_list.Add(bp_sp, true); - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + Log *log = GetLog(LLDBLog::Breakpoints); if (log) { StreamString s; bp_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose); @@ -692,8 +711,9 @@ void Target::AddNameToBreakpoint(BreakpointSP &bp_sp, const char *name, bp_sp->AddName(name); } -void Target::AddBreakpointName(BreakpointName *bp_name) { - m_breakpoint_names.insert(std::make_pair(bp_name->GetName(), bp_name)); +void Target::AddBreakpointName(std::unique_ptr<BreakpointName> bp_name) { + m_breakpoint_names.insert( + std::make_pair(bp_name->GetName(), std::move(bp_name))); } BreakpointName *Target::FindBreakpointName(ConstString name, bool can_create, @@ -703,19 +723,20 @@ BreakpointName *Target::FindBreakpointName(ConstString name, bool can_create, return nullptr; BreakpointNameList::iterator iter = m_breakpoint_names.find(name); - if (iter == m_breakpoint_names.end()) { - if (!can_create) { - error.SetErrorStringWithFormat("Breakpoint name \"%s\" doesn't exist and " - "can_create is false.", - name.AsCString()); - return nullptr; - } + if (iter != m_breakpoint_names.end()) { + return iter->second.get(); + } - iter = m_breakpoint_names - .insert(std::make_pair(name, new BreakpointName(name))) - .first; + if (!can_create) { + error.SetErrorStringWithFormat("Breakpoint name \"%s\" doesn't exist and " + "can_create is false.", + name.AsCString()); + return nullptr; } - return (iter->second); + + return m_breakpoint_names + .insert(std::make_pair(name, std::make_unique<BreakpointName>(name))) + .first->second.get(); } void Target::DeleteBreakpointName(ConstString name) { @@ -747,8 +768,7 @@ void Target::ApplyNameToBreakpoints(BreakpointName &bp_name) { m_breakpoint_list.FindBreakpointsByName(bp_name.GetName().AsCString()); if (!expected_vector) { - LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS), - "invalid breakpoint name: {}", + LLDB_LOG(GetLog(LLDBLog::Breakpoints), "invalid breakpoint name: {}", llvm::toString(expected_vector.takeError())); return; } @@ -759,10 +779,10 @@ void Target::ApplyNameToBreakpoints(BreakpointName &bp_name) { void Target::GetBreakpointNames(std::vector<std::string> &names) { names.clear(); - for (auto bp_name : m_breakpoint_names) { - names.push_back(bp_name.first.AsCString()); + for (const auto& bp_name_entry : m_breakpoint_names) { + names.push_back(bp_name_entry.first.AsCString()); } - llvm::sort(names.begin(), names.end()); + llvm::sort(names); } bool Target::ProcessIsValid() { @@ -793,7 +813,7 @@ static bool CheckIfWatchpointsSupported(Target *target, Status &error) { WatchpointSP Target::CreateWatchpoint(lldb::addr_t addr, size_t size, const CompilerType *type, uint32_t kind, Status &error) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + Log *log = GetLog(LLDBLog::Watchpoints); LLDB_LOGF(log, "Target::%s (addr = 0x%8.8" PRIx64 " size = %" PRIu64 " type = %u)\n", @@ -877,7 +897,7 @@ WatchpointSP Target::CreateWatchpoint(lldb::addr_t addr, size_t size, } void Target::RemoveAllowedBreakpoints() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + Log *log = GetLog(LLDBLog::Breakpoints); LLDB_LOGF(log, "Target::%s \n", __FUNCTION__); m_breakpoint_list.RemoveAllowed(true); @@ -886,7 +906,7 @@ void Target::RemoveAllowedBreakpoints() { } void Target::RemoveAllBreakpoints(bool internal_also) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + Log *log = GetLog(LLDBLog::Breakpoints); LLDB_LOGF(log, "Target::%s (internal_also = %s)\n", __FUNCTION__, internal_also ? "yes" : "no"); @@ -898,7 +918,7 @@ void Target::RemoveAllBreakpoints(bool internal_also) { } void Target::DisableAllBreakpoints(bool internal_also) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + Log *log = GetLog(LLDBLog::Breakpoints); LLDB_LOGF(log, "Target::%s (internal_also = %s)\n", __FUNCTION__, internal_also ? "yes" : "no"); @@ -908,14 +928,14 @@ void Target::DisableAllBreakpoints(bool internal_also) { } void Target::DisableAllowedBreakpoints() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + Log *log = GetLog(LLDBLog::Breakpoints); LLDB_LOGF(log, "Target::%s", __FUNCTION__); m_breakpoint_list.SetEnabledAllowed(false); } void Target::EnableAllBreakpoints(bool internal_also) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + Log *log = GetLog(LLDBLog::Breakpoints); LLDB_LOGF(log, "Target::%s (internal_also = %s)\n", __FUNCTION__, internal_also ? "yes" : "no"); @@ -925,14 +945,14 @@ void Target::EnableAllBreakpoints(bool internal_also) { } void Target::EnableAllowedBreakpoints() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + Log *log = GetLog(LLDBLog::Breakpoints); LLDB_LOGF(log, "Target::%s", __FUNCTION__); m_breakpoint_list.SetEnabledAllowed(true); } bool Target::RemoveBreakpointByID(break_id_t break_id) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + Log *log = GetLog(LLDBLog::Breakpoints); LLDB_LOGF(log, "Target::%s (break_id = %i, internal = %s)\n", __FUNCTION__, break_id, LLDB_BREAK_ID_IS_INTERNAL(break_id) ? "yes" : "no"); @@ -952,7 +972,7 @@ bool Target::RemoveBreakpointByID(break_id_t break_id) { } bool Target::DisableBreakpointByID(break_id_t break_id) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + Log *log = GetLog(LLDBLog::Breakpoints); LLDB_LOGF(log, "Target::%s (break_id = %i, internal = %s)\n", __FUNCTION__, break_id, LLDB_BREAK_ID_IS_INTERNAL(break_id) ? "yes" : "no"); @@ -970,7 +990,7 @@ bool Target::DisableBreakpointByID(break_id_t break_id) { } bool Target::EnableBreakpointByID(break_id_t break_id) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + Log *log = GetLog(LLDBLog::Breakpoints); LLDB_LOGF(log, "Target::%s (break_id = %i, internal = %s)\n", __FUNCTION__, break_id, LLDB_BREAK_ID_IS_INTERNAL(break_id) ? "yes" : "no"); @@ -988,6 +1008,10 @@ bool Target::EnableBreakpointByID(break_id_t break_id) { return false; } +void Target::ResetBreakpointHitCounts() { + GetBreakpointList().ResetHitCounts(); +} + Status Target::SerializeBreakpointsToFile(const FileSpec &file, const BreakpointIDList &bp_ids, bool append) { @@ -1022,7 +1046,7 @@ Status Target::SerializeBreakpointsToFile(const FileSpec &file, } StreamFile out_file(path.c_str(), - File::eOpenOptionTruncate | File::eOpenOptionWrite | + File::eOpenOptionTruncate | File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate | File::eOpenOptionCloseOnExec, lldb::eFilePermissionsFileDefault); @@ -1148,7 +1172,7 @@ Status Target::CreateBreakpointsFromFile(const FileSpec &file, // Assumption: Caller holds the list mutex lock for m_watchpoint_list for end // to end operations. bool Target::RemoveAllWatchpoints(bool end_to_end) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + Log *log = GetLog(LLDBLog::Watchpoints); LLDB_LOGF(log, "Target::%s\n", __FUNCTION__); if (!end_to_end) { @@ -1177,7 +1201,7 @@ bool Target::RemoveAllWatchpoints(bool end_to_end) { // Assumption: Caller holds the list mutex lock for m_watchpoint_list for end // to end operations. bool Target::DisableAllWatchpoints(bool end_to_end) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + Log *log = GetLog(LLDBLog::Watchpoints); LLDB_LOGF(log, "Target::%s\n", __FUNCTION__); if (!end_to_end) { @@ -1204,7 +1228,7 @@ bool Target::DisableAllWatchpoints(bool end_to_end) { // Assumption: Caller holds the list mutex lock for m_watchpoint_list for end // to end operations. bool Target::EnableAllWatchpoints(bool end_to_end) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + Log *log = GetLog(LLDBLog::Watchpoints); LLDB_LOGF(log, "Target::%s\n", __FUNCTION__); if (!end_to_end) { @@ -1230,7 +1254,7 @@ bool Target::EnableAllWatchpoints(bool end_to_end) { // Assumption: Caller holds the list mutex lock for m_watchpoint_list. bool Target::ClearAllWatchpointHitCounts() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + Log *log = GetLog(LLDBLog::Watchpoints); LLDB_LOGF(log, "Target::%s\n", __FUNCTION__); for (WatchpointSP wp_sp : m_watchpoint_list.Watchpoints()) { @@ -1244,7 +1268,7 @@ bool Target::ClearAllWatchpointHitCounts() { // Assumption: Caller holds the list mutex lock for m_watchpoint_list. bool Target::ClearAllWatchpointHistoricValues() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + Log *log = GetLog(LLDBLog::Watchpoints); LLDB_LOGF(log, "Target::%s\n", __FUNCTION__); for (WatchpointSP wp_sp : m_watchpoint_list.Watchpoints()) { @@ -1259,7 +1283,7 @@ bool Target::ClearAllWatchpointHistoricValues() { // Assumption: Caller holds the list mutex lock for m_watchpoint_list during // these operations. bool Target::IgnoreAllWatchpoints(uint32_t ignore_count) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + Log *log = GetLog(LLDBLog::Watchpoints); LLDB_LOGF(log, "Target::%s\n", __FUNCTION__); if (!ProcessIsValid()) @@ -1276,7 +1300,7 @@ bool Target::IgnoreAllWatchpoints(uint32_t ignore_count) { // Assumption: Caller holds the list mutex lock for m_watchpoint_list. bool Target::DisableWatchpointByID(lldb::watch_id_t watch_id) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + Log *log = GetLog(LLDBLog::Watchpoints); LLDB_LOGF(log, "Target::%s (watch_id = %i)\n", __FUNCTION__, watch_id); if (!ProcessIsValid()) @@ -1295,7 +1319,7 @@ bool Target::DisableWatchpointByID(lldb::watch_id_t watch_id) { // Assumption: Caller holds the list mutex lock for m_watchpoint_list. bool Target::EnableWatchpointByID(lldb::watch_id_t watch_id) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + Log *log = GetLog(LLDBLog::Watchpoints); LLDB_LOGF(log, "Target::%s (watch_id = %i)\n", __FUNCTION__, watch_id); if (!ProcessIsValid()) @@ -1314,7 +1338,7 @@ bool Target::EnableWatchpointByID(lldb::watch_id_t watch_id) { // Assumption: Caller holds the list mutex lock for m_watchpoint_list. bool Target::RemoveWatchpointByID(lldb::watch_id_t watch_id) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + Log *log = GetLog(LLDBLog::Watchpoints); LLDB_LOGF(log, "Target::%s (watch_id = %i)\n", __FUNCTION__, watch_id); WatchpointSP watch_to_remove_sp = m_watchpoint_list.FindByID(watch_id); @@ -1331,7 +1355,7 @@ bool Target::RemoveWatchpointByID(lldb::watch_id_t watch_id) { // Assumption: Caller holds the list mutex lock for m_watchpoint_list. bool Target::IgnoreWatchpointByID(lldb::watch_id_t watch_id, uint32_t ignore_count) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + Log *log = GetLog(LLDBLog::Watchpoints); LLDB_LOGF(log, "Target::%s (watch_id = %i)\n", __FUNCTION__, watch_id); if (!ProcessIsValid()) @@ -1396,10 +1420,11 @@ void Target::DidExec() { void Target::SetExecutableModule(ModuleSP &executable_sp, LoadDependentFiles load_dependent_files) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TARGET)); + Log *log = GetLog(LLDBLog::Target); ClearModules(false); if (executable_sp) { + ElapsedTime elapsed(m_stats.GetCreateTime()); LLDB_SCOPED_TIMERF("Target::SetExecutableModule (executable = '%s')", executable_sp->GetFileSpec().GetPath().c_str()); @@ -1412,7 +1437,8 @@ void Target::SetExecutableModule(ModuleSP &executable_sp, if (!m_arch.GetSpec().IsValid()) { m_arch = executable_sp->GetArchitecture(); LLDB_LOG(log, - "setting architecture to {0} ({1}) based on executable file", + "Target::SetExecutableModule setting architecture to {0} ({1}) " + "based on executable file", m_arch.GetSpec().GetArchitectureName(), m_arch.GetSpec().GetTriple().getTriple()); } @@ -1459,8 +1485,9 @@ void Target::SetExecutableModule(ModuleSP &executable_sp, } } -bool Target::SetArchitecture(const ArchSpec &arch_spec, bool set_platform) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TARGET)); +bool Target::SetArchitecture(const ArchSpec &arch_spec, bool set_platform, + bool merge) { + Log *log = GetLog(LLDBLog::Target); bool missing_local_arch = !m_arch.GetSpec().IsValid(); bool replace_local_arch = true; bool compatible_local_arch = false; @@ -1472,12 +1499,12 @@ bool Target::SetArchitecture(const ArchSpec &arch_spec, bool set_platform) { if (set_platform) { if (other.IsValid()) { auto platform_sp = GetPlatform(); - if (!platform_sp || - !platform_sp->IsCompatibleArchitecture(other, false, nullptr)) { + if (!platform_sp || !platform_sp->IsCompatibleArchitecture( + other, {}, ArchSpec::CompatibleMatch, nullptr)) { ArchSpec platform_arch; - auto arch_platform_sp = - Platform::GetPlatformForArchitecture(other, &platform_arch); - if (arch_platform_sp) { + if (PlatformSP arch_platform_sp = + GetDebugger().GetPlatformList().GetOrCreate(other, {}, + &platform_arch)) { SetPlatform(arch_platform_sp); if (platform_arch.IsValid()) other = platform_arch; @@ -1487,7 +1514,7 @@ bool Target::SetArchitecture(const ArchSpec &arch_spec, bool set_platform) { } if (!missing_local_arch) { - if (m_arch.GetSpec().IsCompatibleMatch(arch_spec)) { + if (merge && m_arch.GetSpec().IsCompatibleMatch(arch_spec)) { other.MergeFrom(m_arch.GetSpec()); if (m_arch.GetSpec().IsCompatibleMatch(other)) { @@ -1511,7 +1538,9 @@ bool Target::SetArchitecture(const ArchSpec &arch_spec, bool set_platform) { // specified if (replace_local_arch) m_arch = other; - LLDB_LOG(log, "set architecture to {0} ({1})", + LLDB_LOG(log, + "Target::SetArchitecture merging compatible arch; arch " + "is now {0} ({1})", m_arch.GetSpec().GetArchitectureName(), m_arch.GetSpec().GetTriple().getTriple()); return true; @@ -1519,9 +1548,13 @@ bool Target::SetArchitecture(const ArchSpec &arch_spec, bool set_platform) { // If we have an executable file, try to reset the executable to the desired // architecture - LLDB_LOGF(log, "Target::SetArchitecture changing architecture to %s (%s)", - arch_spec.GetArchitectureName(), - arch_spec.GetTriple().getTriple().c_str()); + LLDB_LOGF( + log, + "Target::SetArchitecture changing architecture to %s (%s) from %s (%s)", + arch_spec.GetArchitectureName(), + arch_spec.GetTriple().getTriple().c_str(), + m_arch.GetSpec().GetArchitectureName(), + m_arch.GetSpec().GetTriple().getTriple().c_str()); m_arch = other; ModuleSP executable_sp = GetExecutableModule(); @@ -1548,7 +1581,7 @@ bool Target::SetArchitecture(const ArchSpec &arch_spec, bool set_platform) { } bool Target::MergeArchitecture(const ArchSpec &arch_spec) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TARGET)); + Log *log = GetLog(LLDBLog::Target); if (arch_spec.IsValid()) { if (m_arch.GetSpec().IsCompatibleMatch(arch_spec)) { // The current target arch is compatible with "arch_spec", see if we can @@ -1645,11 +1678,39 @@ void Target::SymbolsDidLoad(ModuleList &module_list) { void Target::ModulesDidUnload(ModuleList &module_list, bool delete_locations) { if (m_valid && module_list.GetSize()) { UnloadModuleSections(module_list); + BroadcastEvent(eBroadcastBitModulesUnloaded, + new TargetEventData(this->shared_from_this(), module_list)); m_breakpoint_list.UpdateBreakpoints(module_list, false, delete_locations); m_internal_breakpoint_list.UpdateBreakpoints(module_list, false, delete_locations); - BroadcastEvent(eBroadcastBitModulesUnloaded, - new TargetEventData(this->shared_from_this(), module_list)); + + // If a module was torn down it will have torn down the 'TypeSystemClang's + // that we used as source 'ASTContext's for the persistent variables in + // the current target. Those would now be unsafe to access because the + // 'DeclOrigin' are now possibly stale. Thus clear all persistent + // variables. We only want to flush 'TypeSystem's if the module being + // unloaded was capable of describing a source type. JITted module unloads + // happen frequently for Objective-C utility functions or the REPL and rely + // on the persistent variables to stick around. + const bool should_flush_type_systems = + module_list.AnyOf([](lldb_private::Module &module) { + auto *object_file = module.GetObjectFile(); + + if (!object_file) + return false; + + auto type = object_file->GetType(); + + // eTypeExecutable: when debugged binary was rebuilt + // eTypeSharedLibrary: if dylib was re-loaded + return module.FileHasChanged() && + (type == ObjectFile::eTypeObjectFile || + type == ObjectFile::eTypeExecutable || + type == ObjectFile::eTypeSharedLibrary); + }); + + if (should_flush_type_systems) + m_scratch_type_system_map.Clear(); } } @@ -1687,7 +1748,6 @@ bool Target::ModuleIsExcludedForUnconstrainedSearches( size_t Target::ReadMemoryFromFileCache(const Address &addr, void *dst, size_t dst_len, Status &error) { - LLDB_SCOPED_TIMER(); SectionSP section_sp(addr.GetSection()); if (section_sp) { // If the contents of this section are encrypted, the on-disk file is @@ -1723,6 +1783,12 @@ size_t Target::ReadMemory(const Address &addr, void *dst, size_t dst_len, lldb::addr_t *load_addr_ptr) { error.Clear(); + Address fixed_addr = addr; + if (ProcessIsValid()) + if (const ABISP &abi = m_process_sp->GetABI()) + fixed_addr.SetLoadAddress(abi->FixAnyAddress(addr.GetLoadAddress(this)), + this); + // if we end up reading this from process memory, we will fill this with the // actual load address if (load_addr_ptr) @@ -1733,26 +1799,28 @@ size_t Target::ReadMemory(const Address &addr, void *dst, size_t dst_len, addr_t load_addr = LLDB_INVALID_ADDRESS; addr_t file_addr = LLDB_INVALID_ADDRESS; Address resolved_addr; - if (!addr.IsSectionOffset()) { + if (!fixed_addr.IsSectionOffset()) { SectionLoadList §ion_load_list = GetSectionLoadList(); if (section_load_list.IsEmpty()) { // No sections are loaded, so we must assume we are not running yet and // anything we are given is a file address. - file_addr = addr.GetOffset(); // "addr" doesn't have a section, so its - // offset is the file address + file_addr = + fixed_addr.GetOffset(); // "fixed_addr" doesn't have a section, so + // its offset is the file address m_images.ResolveFileAddress(file_addr, resolved_addr); } else { // We have at least one section loaded. This can be because we have // manually loaded some sections with "target modules load ..." or // because we have have a live process that has sections loaded through // the dynamic loader - load_addr = addr.GetOffset(); // "addr" doesn't have a section, so its - // offset is the load address + load_addr = + fixed_addr.GetOffset(); // "fixed_addr" doesn't have a section, so + // its offset is the load address section_load_list.ResolveLoadAddress(load_addr, resolved_addr); } } if (!resolved_addr.IsValid()) - resolved_addr = addr; + resolved_addr = fixed_addr; // If we read from the file cache but can't get as many bytes as requested, // we keep the result around in this buffer, in case this result is the @@ -1832,13 +1900,14 @@ size_t Target::ReadMemory(const Address &addr, void *dst, size_t dst_len, } size_t Target::ReadCStringFromMemory(const Address &addr, std::string &out_str, - Status &error) { + Status &error, bool force_live_memory) { char buf[256]; out_str.clear(); addr_t curr_addr = addr.GetLoadAddress(this); Address address(addr); while (true) { - size_t length = ReadCStringFromMemory(address, buf, sizeof(buf), error); + size_t length = ReadCStringFromMemory(address, buf, sizeof(buf), error, + force_live_memory); if (length == 0) break; out_str.append(buf, length); @@ -1854,7 +1923,8 @@ size_t Target::ReadCStringFromMemory(const Address &addr, std::string &out_str, } size_t Target::ReadCStringFromMemory(const Address &addr, char *dst, - size_t dst_max_len, Status &result_error) { + size_t dst_max_len, Status &result_error, + bool force_live_memory) { size_t total_cstr_len = 0; if (dst && dst_max_len) { result_error.Clear(); @@ -1877,8 +1947,8 @@ size_t Target::ReadCStringFromMemory(const Address &addr, char *dst, cache_line_size - (curr_addr % cache_line_size); addr_t bytes_to_read = std::min<addr_t>(bytes_left, cache_line_bytes_left); - size_t bytes_read = - ReadMemory(address, curr_dst, bytes_to_read, error, true); + size_t bytes_read = ReadMemory(address, curr_dst, bytes_to_read, error, + force_live_memory); if (bytes_read == 0) { result_error = error; @@ -1906,6 +1976,68 @@ size_t Target::ReadCStringFromMemory(const Address &addr, char *dst, return total_cstr_len; } +addr_t Target::GetReasonableReadSize(const Address &addr) { + addr_t load_addr = addr.GetLoadAddress(this); + if (load_addr != LLDB_INVALID_ADDRESS && m_process_sp) { + // Avoid crossing cache line boundaries. + addr_t cache_line_size = m_process_sp->GetMemoryCacheLineSize(); + return cache_line_size - (load_addr % cache_line_size); + } + + // The read is going to go to the file cache, so we can just pick a largish + // value. + return 0x1000; +} + +size_t Target::ReadStringFromMemory(const Address &addr, char *dst, + size_t max_bytes, Status &error, + size_t type_width, bool force_live_memory) { + if (!dst || !max_bytes || !type_width || max_bytes < type_width) + return 0; + + size_t total_bytes_read = 0; + + // Ensure a null terminator independent of the number of bytes that is + // read. + memset(dst, 0, max_bytes); + size_t bytes_left = max_bytes - type_width; + + const char terminator[4] = {'\0', '\0', '\0', '\0'}; + assert(sizeof(terminator) >= type_width && "Attempting to validate a " + "string with more than 4 bytes " + "per character!"); + + Address address = addr; + char *curr_dst = dst; + + error.Clear(); + while (bytes_left > 0 && error.Success()) { + addr_t bytes_to_read = + std::min<addr_t>(bytes_left, GetReasonableReadSize(address)); + size_t bytes_read = + ReadMemory(address, curr_dst, bytes_to_read, error, force_live_memory); + + if (bytes_read == 0) + break; + + // Search for a null terminator of correct size and alignment in + // bytes_read + size_t aligned_start = total_bytes_read - total_bytes_read % type_width; + for (size_t i = aligned_start; + i + type_width <= total_bytes_read + bytes_read; i += type_width) + if (::memcmp(&dst[i], terminator, type_width) == 0) { + error.Clear(); + return i; + } + + total_bytes_read += bytes_read; + curr_dst += bytes_read; + address.Slide(bytes_read); + bytes_left -= bytes_read; + } + return total_bytes_read; +} + size_t Target::ReadScalarIntegerFromMemory(const Address &addr, uint32_t byte_size, bool is_signed, Scalar &scalar, Status &error, @@ -1999,11 +2131,12 @@ ModuleSP Target::GetOrCreateModule(const ModuleSpec &module_spec, bool notify, // a suitable image. if (m_image_search_paths.GetSize()) { ModuleSpec transformed_spec(module_spec); + ConstString transformed_dir; if (m_image_search_paths.RemapPath( - module_spec.GetFileSpec().GetDirectory(), - transformed_spec.GetFileSpec().GetDirectory())) { - transformed_spec.GetFileSpec().GetFilename() = - module_spec.GetFileSpec().GetFilename(); + module_spec.GetFileSpec().GetDirectory(), transformed_dir)) { + transformed_spec.GetFileSpec().SetDirectory(transformed_dir); + transformed_spec.GetFileSpec().SetFilename( + module_spec.GetFileSpec().GetFilename()); error = ModuleList::GetSharedModule(transformed_spec, module_sp, &search_paths, &old_modules, &did_create_module); @@ -2126,8 +2259,7 @@ ModuleSP Target::GetOrCreateModule(const ModuleSpec &module_spec, bool notify, // In the meantime, just log that this has happened; just // above we called ReplaceModule on the first one, and Remove // on the rest. - if (Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_TARGET | - LIBLLDB_LOG_MODULES)) { + if (Log *log = GetLog(LLDBLog::Target | LLDBLog::Modules)) { StreamString message; auto dump = [&message](Module &dump_module) -> void { UUID dump_uuid = dump_module.GetUUID(); @@ -2198,7 +2330,7 @@ void Target::ImageSearchPathsChanged(const PathMappingList &path_list, target->SetExecutableModule(exe_module_sp, eLoadDependentsYes); } -llvm::Expected<TypeSystem &> +llvm::Expected<lldb::TypeSystemSP> Target::GetScratchTypeSystemForLanguage(lldb::LanguageType language, bool create_on_demand) { if (!m_valid) @@ -2227,11 +2359,15 @@ Target::GetScratchTypeSystemForLanguage(lldb::LanguageType language, create_on_demand); } -std::vector<TypeSystem *> Target::GetScratchTypeSystems(bool create_on_demand) { +std::vector<lldb::TypeSystemSP> +Target::GetScratchTypeSystems(bool create_on_demand) { if (!m_valid) return {}; - std::vector<TypeSystem *> scratch_type_systems; + // Some TypeSystem instances are associated with several LanguageTypes so + // they will show up several times in the loop below. The SetVector filters + // out all duplicates as they serve no use for the caller. + std::vector<lldb::TypeSystemSP> scratch_type_systems; LanguageSet languages_for_expressions = Language::GetLanguagesSupportingTypeSystemsForExpressions(); @@ -2241,15 +2377,21 @@ std::vector<TypeSystem *> Target::GetScratchTypeSystems(bool create_on_demand) { auto type_system_or_err = GetScratchTypeSystemForLanguage(language, create_on_demand); if (!type_system_or_err) - LLDB_LOG_ERROR(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_TARGET), - type_system_or_err.takeError(), + LLDB_LOG_ERROR(GetLog(LLDBLog::Target), type_system_or_err.takeError(), "Language '{}' has expression support but no scratch type " "system available", Language::GetNameForLanguageType(language)); else - scratch_type_systems.emplace_back(&type_system_or_err.get()); - } - + if (auto ts = *type_system_or_err) + scratch_type_systems.push_back(ts); + } + std::sort(scratch_type_systems.begin(), scratch_type_systems.end(), + [](lldb::TypeSystemSP a, lldb::TypeSystemSP b) { + return a.get() <= b.get(); + }); + scratch_type_systems.erase( + std::unique(scratch_type_systems.begin(), scratch_type_systems.end()), + scratch_type_systems.end()); return scratch_type_systems; } @@ -2258,14 +2400,19 @@ Target::GetPersistentExpressionStateForLanguage(lldb::LanguageType language) { auto type_system_or_err = GetScratchTypeSystemForLanguage(language, true); if (auto err = type_system_or_err.takeError()) { - LLDB_LOG_ERROR(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_TARGET), - std::move(err), + LLDB_LOG_ERROR(GetLog(LLDBLog::Target), std::move(err), "Unable to get persistent expression state for language {}", Language::GetNameForLanguageType(language)); return nullptr; } - return type_system_or_err->GetPersistentExpressionState(); + if (auto ts = *type_system_or_err) + return ts->GetPersistentExpressionState(); + + LLDB_LOG(GetLog(LLDBLog::Target), + "Unable to get persistent expression state for language {}", + Language::GetNameForLanguageType(language)); + return nullptr; } UserExpression *Target::GetUserExpressionForLanguage( @@ -2282,8 +2429,16 @@ UserExpression *Target::GetUserExpressionForLanguage( return nullptr; } - auto *user_expr = type_system_or_err->GetUserExpression( - expr, prefix, language, desired_type, options, ctx_obj); + auto ts = *type_system_or_err; + if (!ts) { + error.SetErrorStringWithFormat( + "Type system for language %s is no longer live", + Language::GetNameForLanguageType(language)); + return nullptr; + } + + auto *user_expr = ts->GetUserExpression(expr, prefix, language, desired_type, + options, ctx_obj); if (!user_expr) error.SetErrorStringWithFormat( "Could not create an expression for language %s", @@ -2304,9 +2459,15 @@ FunctionCaller *Target::GetFunctionCallerForLanguage( llvm::toString(std::move(err)).c_str()); return nullptr; } - - auto *persistent_fn = type_system_or_err->GetFunctionCaller( - return_type, function_address, arg_value_list, name); + auto ts = *type_system_or_err; + if (!ts) { + error.SetErrorStringWithFormat( + "Type system for language %s is no longer live", + Language::GetNameForLanguageType(language)); + return nullptr; + } + auto *persistent_fn = ts->GetFunctionCaller(return_type, function_address, + arg_value_list, name); if (!persistent_fn) error.SetErrorStringWithFormat( "Could not create an expression for language %s", @@ -2322,10 +2483,15 @@ Target::CreateUtilityFunction(std::string expression, std::string name, auto type_system_or_err = GetScratchTypeSystemForLanguage(language); if (!type_system_or_err) return type_system_or_err.takeError(); - + auto ts = *type_system_or_err; + if (!ts) + return llvm::make_error<llvm::StringError>( + llvm::StringRef("Type system for language ") + + Language::GetNameForLanguageType(language) + + llvm::StringRef(" is no longer live"), + llvm::inconvertibleErrorCode()); std::unique_ptr<UtilityFunction> utility_fn = - type_system_or_err->CreateUtilityFunction(std::move(expression), - std::move(name)); + ts->CreateUtilityFunction(std::move(expression), std::move(name)); if (!utility_fn) return llvm::make_error<llvm::StringError>( llvm::StringRef("Could not create an expression for language") + @@ -2345,35 +2511,22 @@ void Target::SettingsInitialize() { Process::SettingsInitialize(); } void Target::SettingsTerminate() { Process::SettingsTerminate(); } FileSpecList Target::GetDefaultExecutableSearchPaths() { - TargetPropertiesSP properties_sp(Target::GetGlobalProperties()); - if (properties_sp) - return properties_sp->GetExecutableSearchPaths(); - return FileSpecList(); + return Target::GetGlobalProperties().GetExecutableSearchPaths(); } FileSpecList Target::GetDefaultDebugFileSearchPaths() { - TargetPropertiesSP properties_sp(Target::GetGlobalProperties()); - if (properties_sp) - return properties_sp->GetDebugFileSearchPaths(); - return FileSpecList(); + return Target::GetGlobalProperties().GetDebugFileSearchPaths(); } ArchSpec Target::GetDefaultArchitecture() { - TargetPropertiesSP properties_sp(Target::GetGlobalProperties()); - if (properties_sp) - return properties_sp->GetDefaultArchitecture(); - return ArchSpec(); + return Target::GetGlobalProperties().GetDefaultArchitecture(); } void Target::SetDefaultArchitecture(const ArchSpec &arch) { - TargetPropertiesSP properties_sp(Target::GetGlobalProperties()); - if (properties_sp) { - LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TARGET), - "Target::SetDefaultArchitecture setting target's " - "default architecture to {0} ({1})", - arch.GetArchitectureName(), arch.GetTriple().getTriple()); - return properties_sp->SetDefaultArchitecture(arch); - } + LLDB_LOG(GetLog(LLDBLog::Target), + "setting target's default architecture to {0} ({1})", + arch.GetArchitectureName(), arch.GetTriple().getTriple()); + Target::GetGlobalProperties().SetDefaultArchitecture(arch); } Target *Target::GetTargetFromContexts(const ExecutionContext *exe_ctx_ptr, @@ -2399,8 +2552,10 @@ ExpressionResults Target::EvaluateExpression( ExpressionResults execution_results = eExpressionSetupError; - if (expr.empty()) + if (expr.empty()) { + m_stats.GetExpressionStats().NotifyFailure(); return execution_results; + } // We shouldn't run stop hooks in expressions. bool old_suppress_value = m_suppress_stop_hooks; @@ -2427,11 +2582,16 @@ ExpressionResults Target::EvaluateExpression( auto type_system_or_err = GetScratchTypeSystemForLanguage(eLanguageTypeC); if (auto err = type_system_or_err.takeError()) { - LLDB_LOG_ERROR(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_TARGET), - std::move(err), "Unable to get scratch type system"); + LLDB_LOG_ERROR(GetLog(LLDBLog::Target), std::move(err), + "Unable to get scratch type system"); } else { - persistent_var_sp = - type_system_or_err->GetPersistentExpressionState()->GetVariable(expr); + auto ts = *type_system_or_err; + if (!ts) + LLDB_LOG_ERROR(GetLog(LLDBLog::Target), std::move(err), + "Scratch type system is no longer live"); + else + persistent_var_sp = + ts->GetPersistentExpressionState()->GetVariable(expr); } } if (persistent_var_sp) { @@ -2443,17 +2603,28 @@ ExpressionResults Target::EvaluateExpression( execution_results = UserExpression::Evaluate(exe_ctx, options, expr, prefix, result_valobj_sp, error, fixed_expression, ctx_obj); + // Pass up the error by wrapping it inside an error result. + if (error.Fail() && !result_valobj_sp) + result_valobj_sp = ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), error); } + if (execution_results == eExpressionCompleted) + m_stats.GetExpressionStats().NotifySuccess(); + else + m_stats.GetExpressionStats().NotifyFailure(); return execution_results; } lldb::ExpressionVariableSP Target::GetPersistentVariable(ConstString name) { lldb::ExpressionVariableSP variable_sp; m_scratch_type_system_map.ForEach( - [name, &variable_sp](TypeSystem *type_system) -> bool { + [name, &variable_sp](TypeSystemSP type_system) -> bool { + auto ts = type_system.get(); + if (!ts) + return true; if (PersistentExpressionState *persistent_state = - type_system->GetPersistentExpressionState()) { + ts->GetPersistentExpressionState()) { variable_sp = persistent_state->GetVariable(name); if (variable_sp) @@ -2468,9 +2639,13 @@ lldb::addr_t Target::GetPersistentSymbol(ConstString name) { lldb::addr_t address = LLDB_INVALID_ADDRESS; m_scratch_type_system_map.ForEach( - [name, &address](TypeSystem *type_system) -> bool { + [name, &address](lldb::TypeSystemSP type_system) -> bool { + auto ts = type_system.get(); + if (!ts) + return true; + if (PersistentExpressionState *persistent_state = - type_system->GetPersistentExpressionState()) { + ts->GetPersistentExpressionState()) { address = persistent_state->LookupSymbol(name); if (address != LLDB_INVALID_ADDRESS) return false; // Stop iterating the ForEach @@ -2754,7 +2929,7 @@ bool Target::RunStopHooks() { // We only compute should_stop against the hook results if a hook got to run // which is why we have to do this conjoint test. if ((hooks_ran && !should_stop) || auto_continue) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); Status error = m_process_sp->PrivateResume(); if (error.Success()) { LLDB_LOG(log, "Resuming from RunStopHooks"); @@ -2768,12 +2943,12 @@ bool Target::RunStopHooks() { return false; } -const TargetPropertiesSP &Target::GetGlobalProperties() { +TargetProperties &Target::GetGlobalProperties() { // NOTE: intentional leak so we don't crash if global destructor chain gets // called as other threads still use the result of this function - static TargetPropertiesSP *g_settings_sp_ptr = - new TargetPropertiesSP(new TargetProperties(nullptr)); - return *g_settings_sp_ptr; + static TargetProperties *g_settings_ptr = + new TargetProperties(nullptr); + return *g_settings_ptr; } Status Target::Install(ProcessLaunchInfo *launch_info) { @@ -2908,8 +3083,9 @@ bool Target::SetSectionUnloaded(const lldb::SectionSP §ion_sp, void Target::ClearAllLoadedSections() { m_section_load_history.Clear(); } Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { + m_stats.SetLaunchOrAttachTime(); Status error; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TARGET)); + Log *log = GetLog(LLDBLog::Target); LLDB_LOGF(log, "Target::%s() called for %s", __FUNCTION__, launch_info.GetExecutableFile().GetPath().c_str()); @@ -2936,17 +3112,9 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { launch_info.GetFlags().Set(eLaunchFlagDebug); if (launch_info.IsScriptedProcess()) { - TargetPropertiesSP properties_sp = GetGlobalProperties(); - - if (!properties_sp) { - LLDB_LOGF(log, "Target::%s Couldn't fetch target global properties.", - __FUNCTION__); - return error; - } - // Only copy scripted process launch options. - ProcessLaunchInfo &default_launch_info = - const_cast<ProcessLaunchInfo &>(properties_sp->GetProcessLaunchInfo()); + ProcessLaunchInfo &default_launch_info = const_cast<ProcessLaunchInfo &>( + GetGlobalProperties().GetProcessLaunchInfo()); default_launch_info.SetProcessPluginName("ScriptedProcess"); default_launch_info.SetScriptedProcessClassName( @@ -2979,6 +3147,14 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { if (!launch_info.GetArchitecture().IsValid()) launch_info.GetArchitecture() = GetArchitecture(); + // Hijacking events of the process to be created to be sure that all events + // until the first stop are intercepted (in case if platform doesn't define + // its own hijacking listener or if the process is created by the target + // manually, without the platform). + if (!launch_info.GetHijackListener()) + launch_info.SetHijackListener( + Listener::MakeListener("lldb.Target.Launch.hijack")); + // If we're not already connected to the process, and if we have a platform // that can launch a process for debugging, go ahead and do that here. if (state != eStateConnected && platform_sp && @@ -2993,7 +3169,7 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { DeleteCurrentProcess(); m_process_sp = - GetPlatform()->DebugProcess(launch_info, debugger, this, error); + GetPlatform()->DebugProcess(launch_info, debugger, *this, error); } else { LLDB_LOGF(log, @@ -3010,8 +3186,10 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { } // Since we didn't have a platform launch the process, launch it here. - if (m_process_sp) + if (m_process_sp) { + m_process_sp->HijackProcessEvents(launch_info.GetHijackListener()); error = m_process_sp->Launch(launch_info); + } } if (!m_process_sp && error.Success()) @@ -3020,35 +3198,35 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { if (!error.Success()) return error; - auto at_exit = - llvm::make_scope_exit([&]() { m_process_sp->RestoreProcessEvents(); }); + bool rebroadcast_first_stop = + !synchronous_execution && + launch_info.GetFlags().Test(eLaunchFlagStopAtEntry); - if (!synchronous_execution && - launch_info.GetFlags().Test(eLaunchFlagStopAtEntry)) - return error; + assert(launch_info.GetHijackListener()); + + EventSP first_stop_event_sp; + state = m_process_sp->WaitForProcessToStop(std::nullopt, &first_stop_event_sp, + rebroadcast_first_stop, + launch_info.GetHijackListener()); + m_process_sp->RestoreProcessEvents(); - ListenerSP hijack_listener_sp(launch_info.GetHijackListener()); - if (!hijack_listener_sp) { - hijack_listener_sp = Listener::MakeListener("lldb.Target.Launch.hijack"); - launch_info.SetHijackListener(hijack_listener_sp); - m_process_sp->HijackProcessEvents(hijack_listener_sp); + if (rebroadcast_first_stop) { + assert(first_stop_event_sp); + m_process_sp->BroadcastEvent(first_stop_event_sp); + return error; } - switch (m_process_sp->WaitForProcessToStop(llvm::None, nullptr, false, - hijack_listener_sp, nullptr)) { + switch (state) { case eStateStopped: { if (launch_info.GetFlags().Test(eLaunchFlagStopAtEntry)) break; - if (synchronous_execution) { + if (synchronous_execution) // Now we have handled the stop-from-attach, and we are just // switching to a synchronous resume. So we should switch to the // SyncResume hijacker. - m_process_sp->RestoreProcessEvents(); m_process_sp->ResumeSynchronous(stream); - } else { - m_process_sp->RestoreProcessEvents(); + else error = m_process_sp->PrivateResume(); - } if (!error.Success()) { Status error2; error2.SetErrorStringWithFormat( @@ -3119,6 +3297,7 @@ llvm::Expected<TraceSP> Target::GetTraceOrCreate() { } Status Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) { + m_stats.SetLaunchOrAttachTime(); auto state = eStateInvalid; auto process_sp = GetProcessSP(); if (process_sp) { @@ -3136,8 +3315,8 @@ Status Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) { // the process to attach to by default if (!attach_info.ProcessInfoSpecified()) { if (old_exec_module_sp) - attach_info.GetExecutableFile().GetFilename() = - old_exec_module_sp->GetPlatformFileSpec().GetFilename(); + attach_info.GetExecutableFile().SetFilename( + old_exec_module_sp->GetPlatformFileSpec().GetFilename()); if (!attach_info.ProcessInfoSpecified()) { return Status("no process specified, create a target with a file, or " @@ -3182,8 +3361,9 @@ Status Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) { if (async) { process_sp->RestoreProcessEvents(); } else { - state = process_sp->WaitForProcessToStop( - llvm::None, nullptr, false, attach_info.GetHijackListener(), stream); + state = process_sp->WaitForProcessToStop(std::nullopt, nullptr, false, + attach_info.GetHijackListener(), + stream); process_sp->RestoreProcessEvents(); if (state != eStateStopped) { @@ -3201,7 +3381,7 @@ Status Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) { } void Target::FinalizeFileActions(ProcessLaunchInfo &info) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); // Finalize the file actions, and if none were given, default to opening up a // pseudo terminal @@ -3271,8 +3451,7 @@ void Target::FinalizeFileActions(ProcessLaunchInfo &info) { err_file_spec); } - if (default_to_use_pty && - (!in_file_spec || !out_file_spec || !err_file_spec)) { + if (default_to_use_pty) { llvm::Error Err = info.SetUpPtyRedirection(); LLDB_LOG_ERROR(log, std::move(Err), "SetUpPtyRedirection failed: {0}"); } @@ -3280,6 +3459,130 @@ void Target::FinalizeFileActions(ProcessLaunchInfo &info) { } } +void Target::AddDummySignal(llvm::StringRef name, LazyBool pass, LazyBool notify, + LazyBool stop) { + if (name.empty()) + return; + // Don't add a signal if all the actions are trivial: + if (pass == eLazyBoolCalculate && notify == eLazyBoolCalculate + && stop == eLazyBoolCalculate) + return; + + auto& elem = m_dummy_signals[name]; + elem.pass = pass; + elem.notify = notify; + elem.stop = stop; +} + +bool Target::UpdateSignalFromDummy(UnixSignalsSP signals_sp, + const DummySignalElement &elem) { + if (!signals_sp) + return false; + + int32_t signo + = signals_sp->GetSignalNumberFromName(elem.first().str().c_str()); + if (signo == LLDB_INVALID_SIGNAL_NUMBER) + return false; + + if (elem.second.pass == eLazyBoolYes) + signals_sp->SetShouldSuppress(signo, false); + else if (elem.second.pass == eLazyBoolNo) + signals_sp->SetShouldSuppress(signo, true); + + if (elem.second.notify == eLazyBoolYes) + signals_sp->SetShouldNotify(signo, true); + else if (elem.second.notify == eLazyBoolNo) + signals_sp->SetShouldNotify(signo, false); + + if (elem.second.stop == eLazyBoolYes) + signals_sp->SetShouldStop(signo, true); + else if (elem.second.stop == eLazyBoolNo) + signals_sp->SetShouldStop(signo, false); + return true; +} + +bool Target::ResetSignalFromDummy(UnixSignalsSP signals_sp, + const DummySignalElement &elem) { + if (!signals_sp) + return false; + int32_t signo + = signals_sp->GetSignalNumberFromName(elem.first().str().c_str()); + if (signo == LLDB_INVALID_SIGNAL_NUMBER) + return false; + bool do_pass = elem.second.pass != eLazyBoolCalculate; + bool do_stop = elem.second.stop != eLazyBoolCalculate; + bool do_notify = elem.second.notify != eLazyBoolCalculate; + signals_sp->ResetSignal(signo, do_stop, do_notify, do_pass); + return true; +} + +void Target::UpdateSignalsFromDummy(UnixSignalsSP signals_sp, + StreamSP warning_stream_sp) { + if (!signals_sp) + return; + + for (const auto &elem : m_dummy_signals) { + if (!UpdateSignalFromDummy(signals_sp, elem)) + warning_stream_sp->Printf("Target signal '%s' not found in process\n", + elem.first().str().c_str()); + } +} + +void Target::ClearDummySignals(Args &signal_names) { + ProcessSP process_sp = GetProcessSP(); + // The simplest case, delete them all with no process to update. + if (signal_names.GetArgumentCount() == 0 && !process_sp) { + m_dummy_signals.clear(); + return; + } + UnixSignalsSP signals_sp; + if (process_sp) + signals_sp = process_sp->GetUnixSignals(); + + for (const Args::ArgEntry &entry : signal_names) { + const char *signal_name = entry.c_str(); + auto elem = m_dummy_signals.find(signal_name); + // If we didn't find it go on. + // FIXME: Should I pipe error handling through here? + if (elem == m_dummy_signals.end()) { + continue; + } + if (signals_sp) + ResetSignalFromDummy(signals_sp, *elem); + m_dummy_signals.erase(elem); + } +} + +void Target::PrintDummySignals(Stream &strm, Args &signal_args) { + strm.Printf("NAME PASS STOP NOTIFY\n"); + strm.Printf("=========== ======= ======= =======\n"); + + auto str_for_lazy = [] (LazyBool lazy) -> const char * { + switch (lazy) { + case eLazyBoolCalculate: return "not set"; + case eLazyBoolYes: return "true "; + case eLazyBoolNo: return "false "; + } + llvm_unreachable("Fully covered switch above!"); + }; + size_t num_args = signal_args.GetArgumentCount(); + for (const auto &elem : m_dummy_signals) { + bool print_it = false; + for (size_t idx = 0; idx < num_args; idx++) { + if (elem.first() == signal_args.GetArgumentAtIndex(idx)) { + print_it = true; + break; + } + } + if (print_it) { + strm.Printf("%-11s ", elem.first().str().c_str()); + strm.Printf("%s %s %s\n", str_for_lazy(elem.second.pass), + str_for_lazy(elem.second.stop), + str_for_lazy(elem.second.notify)); + } + } +} + // Target::StopHook Target::StopHook::StopHook(lldb::TargetSP target_sp, lldb::user_id_t uid) : UserID(uid), m_target_sp(target_sp), m_specifier_sp(), @@ -3435,11 +3738,7 @@ Status Target::StopHookScripted::SetScriptCallback( } m_class_name = class_name; - - m_extra_args = new StructuredDataImpl(); - - if (extra_args_sp) - m_extra_args->SetObjectSP(extra_args_sp); + m_extra_args.SetObjectSP(extra_args_sp); m_implementation_sp = script_interp->CreateScriptedStopHook( GetTarget(), m_class_name.c_str(), m_extra_args, error); @@ -3477,9 +3776,9 @@ void Target::StopHookScripted::GetSubclassDescription( // Now print the extra args: // FIXME: We should use StructuredData.GetDescription on the m_extra_args // but that seems to rely on some printing plugin that doesn't exist. - if (!m_extra_args->IsValid()) + if (!m_extra_args.IsValid()) return; - StructuredData::ObjectSP object_sp = m_extra_args->GetObjectSP(); + StructuredData::ObjectSP object_sp = m_extra_args.GetObjectSP(); if (!object_sp || !object_sp->IsValid()) return; @@ -3599,6 +3898,22 @@ static constexpr OptionEnumValueElement g_import_std_module_value_types[] = { }, }; +static constexpr OptionEnumValueElement + g_dynamic_class_info_helper_value_types[] = { + { + eDynamicClassInfoHelperAuto, + "auto", + "Automatically determine the most appropriate method for the " + "target OS.", + }, + {eDynamicClassInfoHelperRealizedClassesStruct, "RealizedClassesStruct", + "Prefer using the realized classes struct."}, + {eDynamicClassInfoHelperCopyRealizedClassList, "CopyRealizedClassList", + "Prefer using the CopyRealizedClassList API."}, + {eDynamicClassInfoHelperGetRealizedClassList, "GetRealizedClassList", + "Prefer using the GetRealizedClassList API."}, +}; + static constexpr OptionEnumValueElement g_hex_immediate_style_values[] = { { Disassembler::eHexStyleC, @@ -3731,7 +4046,7 @@ TargetProperties::TargetProperties(Target *target) : Properties(), m_launch_info(), m_target(target) { if (target) { m_collection_sp = - OptionValueProperties::CreateLocalCopy(*Target::GetGlobalProperties()); + OptionValueProperties::CreateLocalCopy(Target::GetGlobalProperties()); // Set callbacks to update launch_info whenever "settins set" updated any // of these properties @@ -3761,6 +4076,8 @@ TargetProperties::TargetProperties(Target *target) m_collection_sp->SetValueChangedCallback( ePropertyDisableSTDIO, [this] { DisableSTDIOValueChangedCallback(); }); + m_collection_sp->SetValueChangedCallback( + ePropertySaveObjectsDir, [this] { CheckJITObjectsDir(); }); m_experimental_properties_up = std::make_unique<TargetExperimentalProperties>(); m_collection_sp->AppendProperty( @@ -3781,7 +4098,9 @@ TargetProperties::TargetProperties(Target *target) true, m_experimental_properties_up->GetValueProperties()); m_collection_sp->AppendProperty( ConstString("process"), ConstString("Settings specific to processes."), - true, Process::GetGlobalProperties()->GetValueProperties()); + true, Process::GetGlobalProperties().GetValueProperties()); + m_collection_sp->SetValueChangedCallback( + ePropertySaveObjectsDir, [this] { CheckJITObjectsDir(); }); } } @@ -3985,6 +4304,45 @@ Environment TargetProperties::GetEnvironment() const { return ComputeEnvironment(); } +Environment TargetProperties::GetInheritedEnvironment() const { + Environment environment; + + if (m_target == nullptr) + return environment; + + if (!m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, ePropertyInheritEnv, + g_target_properties[ePropertyInheritEnv].default_uint_value != 0)) + return environment; + + PlatformSP platform_sp = m_target->GetPlatform(); + if (platform_sp == nullptr) + return environment; + + Environment platform_environment = platform_sp->GetEnvironment(); + for (const auto &KV : platform_environment) + environment[KV.first()] = KV.second; + + Args property_unset_environment; + m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, ePropertyUnsetEnvVars, + property_unset_environment); + for (const auto &var : property_unset_environment) + environment.erase(var.ref()); + + return environment; +} + +Environment TargetProperties::GetTargetEnvironment() const { + Args property_environment; + m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, ePropertyEnvVars, + property_environment); + Environment environment; + for (const auto &KV : Environment(property_environment)) + environment[KV.first()] = KV.second; + + return environment; +} + void TargetProperties::SetEnvironment(Environment env) { // TODO: Get rid of the Args intermediate step const uint32_t idx = ePropertyEnvVars; @@ -4006,6 +4364,12 @@ PathMappingList &TargetProperties::GetSourcePathMap() const { return option_value->GetCurrentValue(); } +bool TargetProperties::GetAutoSourceMapRelative() const { + const uint32_t idx = ePropertyAutoSourceMapRelative; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_target_properties[idx].default_uint_value != 0); +} + void TargetProperties::AppendExecutableSearchPaths(const FileSpec &dir) { const uint32_t idx = ePropertyExecutableSearchPaths; OptionValueFileSpecList *option_value = @@ -4054,6 +4418,13 @@ ImportStdModule TargetProperties::GetImportStdModule() const { nullptr, idx, g_target_properties[idx].default_uint_value); } +DynamicClassInfoHelper TargetProperties::GetDynamicClassInfoHelper() const { + const uint32_t idx = ePropertyDynamicClassInfoHelper; + return (DynamicClassInfoHelper) + m_collection_sp->GetPropertyAtIndexAsEnumeration( + nullptr, idx, g_target_properties[idx].default_uint_value); +} + bool TargetProperties::GetEnableAutoApplyFixIts() const { const uint32_t idx = ePropertyAutoApplyFixIts; return m_collection_sp->GetPropertyAtIndexAsBoolean( @@ -4072,10 +4443,42 @@ bool TargetProperties::GetEnableNotifyAboutFixIts() const { nullptr, idx, g_target_properties[idx].default_uint_value != 0); } -bool TargetProperties::GetEnableSaveObjects() const { - const uint32_t idx = ePropertySaveObjects; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); +FileSpec TargetProperties::GetSaveJITObjectsDir() const { + const uint32_t idx = ePropertySaveObjectsDir; + return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx); +} + +void TargetProperties::CheckJITObjectsDir() { + FileSpec new_dir = GetSaveJITObjectsDir(); + if (!new_dir) + return; + + const FileSystem &instance = FileSystem::Instance(); + bool exists = instance.Exists(new_dir); + bool is_directory = instance.IsDirectory(new_dir); + std::string path = new_dir.GetPath(true); + bool writable = llvm::sys::fs::can_write(path); + if (exists && is_directory && writable) + return; + + m_collection_sp->GetPropertyAtIndex(nullptr, true, ePropertySaveObjectsDir) + ->GetValue() + ->Clear(); + + std::string buffer; + llvm::raw_string_ostream os(buffer); + os << "JIT object dir '" << path << "' "; + if (!exists) + os << "does not exist"; + else if (!is_directory) + os << "is not a directory"; + else if (!writable) + os << "is not writable"; + + std::optional<lldb::user_id_t> debugger_id; + if (m_target) + debugger_id = m_target->GetDebugger().GetID(); + Debugger::ReportError(os.str(), debugger_id); } bool TargetProperties::GetEnableSyntheticValue() const { @@ -4096,6 +4499,15 @@ uint32_t TargetProperties::GetMaximumNumberOfChildrenToDisplay() const { nullptr, idx, g_target_properties[idx].default_uint_value); } +std::pair<uint32_t, bool> +TargetProperties::GetMaximumDepthOfChildrenToDisplay() const { + const uint32_t idx = ePropertyMaxChildrenDepth; + auto *option_value = + m_collection_sp->GetPropertyAtIndexAsOptionValueUInt64(nullptr, idx); + bool is_default = !option_value->OptionWasSet(); + return {option_value->GetCurrentValue(), is_default}; +} + uint32_t TargetProperties::GetMaximumSizeOfStringSummary() const { const uint32_t idx = ePropertyMaxSummaryLength; return m_collection_sp->GetPropertyAtIndexAsSInt64( @@ -4249,16 +4661,6 @@ void TargetProperties::SetDisplayRecognizedArguments(bool b) { m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); } -bool TargetProperties::GetNonStopModeEnabled() const { - const uint32_t idx = ePropertyNonStopModeEnabled; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, false); -} - -void TargetProperties::SetNonStopModeEnabled(bool b) { - const uint32_t idx = ePropertyNonStopModeEnabled; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); -} - const ProcessLaunchInfo &TargetProperties::GetProcessLaunchInfo() const { return m_launch_info; } @@ -4435,3 +4837,6 @@ std::recursive_mutex &Target::GetAPIMutex() { else return m_mutex; } + +/// Get metrics associated with this target in JSON format. +llvm::json::Value Target::ReportStatistics() { return m_stats.ToJSON(*this); } diff --git a/gnu/llvm/lldb/source/Target/TargetList.cpp b/gnu/llvm/lldb/source/Target/TargetList.cpp index 595799cfc92..8ce2ae8c289 100644 --- a/gnu/llvm/lldb/source/Target/TargetList.cpp +++ b/gnu/llvm/lldb/source/Target/TargetList.cpp @@ -79,8 +79,9 @@ Status TargetList::CreateTargetInternal( const OptionGroupPlatform *platform_options, TargetSP &target_sp) { Status error; + PlatformList &platform_list = debugger.GetPlatformList(); // Let's start by looking at the selected platform. - PlatformSP platform_sp = debugger.GetPlatformList().GetSelectedPlatform(); + PlatformSP platform_sp = platform_list.GetSelectedPlatform(); // This variable corresponds to the architecture specified by the triple // string. If that string was empty the currently selected platform will @@ -120,6 +121,14 @@ Status TargetList::CreateTargetInternal( if (!user_exe_path.empty()) { ModuleSpec module_spec(FileSpec(user_exe_path, FileSpec::Style::native)); FileSystem::Instance().Resolve(module_spec.GetFileSpec()); + + // Try to resolve the exe based on PATH and/or platform-specific suffixes, + // but only if using the host platform. + if (platform_sp->IsHost() && + !FileSystem::Instance().Exists(module_spec.GetFileSpec())) + FileSystem::Instance().ResolveExecutableLocation( + module_spec.GetFileSpec()); + // Resolve the executable in case we are given a path to a application // bundle like a .app bundle on MacOSX. Host::ResolveExecutableInBundle(module_spec.GetFileSpec()); @@ -171,80 +180,30 @@ Status TargetList::CreateTargetInternal( } else { // Fat binary. No architecture specified, check if there is // only one platform for all of the architectures. - PlatformSP host_platform_sp = Platform::GetHostPlatform(); - std::vector<PlatformSP> platforms; - for (size_t i = 0; i < num_specs; ++i) { - ModuleSpec module_spec; - if (module_specs.GetModuleSpecAtIndex(i, module_spec)) { - // First consider the platform specified by the user, if any, and - // the selected platform otherwise. - if (platform_sp) { - if (platform_sp->IsCompatibleArchitecture( - module_spec.GetArchitecture(), false, nullptr)) { - platforms.push_back(platform_sp); - continue; - } - } - - // Now consider the host platform if it is different from the - // specified/selected platform. - if (host_platform_sp && - (!platform_sp || - host_platform_sp->GetName() != platform_sp->GetName())) { - if (host_platform_sp->IsCompatibleArchitecture( - module_spec.GetArchitecture(), false, nullptr)) { - platforms.push_back(host_platform_sp); - continue; - } - } - - // Finally find a platform that matches the architecture in the - // executable file. - PlatformSP fallback_platform_sp( - Platform::GetPlatformForArchitecture( - module_spec.GetArchitecture(), nullptr)); - if (fallback_platform_sp) { - platforms.push_back(fallback_platform_sp); - } - } - } - - Platform *platform_ptr = nullptr; - bool more_than_one_platforms = false; - for (const auto &the_platform_sp : platforms) { - if (platform_ptr) { - if (platform_ptr->GetName() != the_platform_sp->GetName()) { - more_than_one_platforms = true; - platform_ptr = nullptr; - break; - } - } else { - platform_ptr = the_platform_sp.get(); - } - } - - if (platform_ptr) { - // All platforms for all modules in the executable match, so we can - // select this platform. - platform_sp = platforms.front(); - } else if (!more_than_one_platforms) { - // No platforms claim to support this file. + std::vector<PlatformSP> candidates; + std::vector<ArchSpec> archs; + for (const ModuleSpec &spec : module_specs.ModuleSpecs()) + archs.push_back(spec.GetArchitecture()); + if (PlatformSP platform_for_archs_sp = + platform_list.GetOrCreate(archs, {}, candidates)) { + platform_sp = platform_for_archs_sp; + } else if (candidates.empty()) { error.SetErrorString("no matching platforms found for this file"); return error; } else { // More than one platform claims to support this file. StreamString error_strm; - std::set<Platform *> platform_set; + std::set<llvm::StringRef> platform_set; error_strm.Printf( "more than one platform supports this executable ("); - for (const auto &the_platform_sp : platforms) { - if (platform_set.find(the_platform_sp.get()) == - platform_set.end()) { - if (!platform_set.empty()) - error_strm.PutCString(", "); - error_strm.PutCString(the_platform_sp->GetName().GetCString()); - platform_set.insert(the_platform_sp.get()); - } + for (const auto &candidate : candidates) { + llvm::StringRef platform_name = candidate->GetName(); + if (platform_set.count(platform_name)) + continue; + if (!platform_set.empty()) + error_strm.PutCString(", "); + error_strm.PutCString(platform_name); + platform_set.insert(platform_name); } error_strm.Printf("), specify an architecture to disambiguate"); error.SetErrorString(error_strm.GetString()); @@ -257,20 +216,22 @@ Status TargetList::CreateTargetInternal( // If we have a valid architecture, make sure the current platform is // compatible with that architecture. if (!prefer_platform_arch && arch.IsValid()) { - if (!platform_sp->IsCompatibleArchitecture(arch, false, nullptr)) { - platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch); + if (!platform_sp->IsCompatibleArchitecture( + arch, {}, ArchSpec::CompatibleMatch, nullptr)) { + platform_sp = platform_list.GetOrCreate(arch, {}, &platform_arch); if (platform_sp) - debugger.GetPlatformList().SetSelectedPlatform(platform_sp); + platform_list.SetSelectedPlatform(platform_sp); } } else if (platform_arch.IsValid()) { // If "arch" isn't valid, yet "platform_arch" is, it means we have an // executable file with a single architecture which should be used. ArchSpec fixed_platform_arch; - if (!platform_sp->IsCompatibleArchitecture(platform_arch, false, nullptr)) { - platform_sp = Platform::GetPlatformForArchitecture(platform_arch, - &fixed_platform_arch); + if (!platform_sp->IsCompatibleArchitecture( + platform_arch, {}, ArchSpec::CompatibleMatch, nullptr)) { + platform_sp = + platform_list.GetOrCreate(platform_arch, {}, &fixed_platform_arch); if (platform_sp) - debugger.GetPlatformList().SetSelectedPlatform(platform_sp); + platform_list.SetSelectedPlatform(platform_sp); } } @@ -297,9 +258,10 @@ Status TargetList::CreateTargetInternal(Debugger &debugger, ArchSpec arch(specified_arch); if (arch.IsValid()) { - if (!platform_sp || - !platform_sp->IsCompatibleArchitecture(arch, false, nullptr)) - platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch); + if (!platform_sp || !platform_sp->IsCompatibleArchitecture( + arch, {}, ArchSpec::CompatibleMatch, nullptr)) + platform_sp = + debugger.GetPlatformList().GetOrCreate(specified_arch, {}, &arch); } if (!platform_sp) @@ -394,7 +356,7 @@ Status TargetList::CreateTargetInternal(Debugger &debugger, } if (file.GetDirectory()) { FileSpec file_dir; - file_dir.GetDirectory() = file.GetDirectory(); + file_dir.SetDirectory(file.GetDirectory()); target_sp->AppendExecutableSearchPaths(file_dir); } @@ -549,8 +511,7 @@ uint32_t TargetList::GetIndexOfTarget(lldb::TargetSP target_sp) const { } void TargetList::AddTargetInternal(TargetSP target_sp, bool do_select) { - lldbassert(std::find(m_target_list.begin(), m_target_list.end(), target_sp) == - m_target_list.end() && + lldbassert(!llvm::is_contained(m_target_list, target_sp) && "target already exists it the list"); m_target_list.push_back(std::move(target_sp)); if (do_select) diff --git a/gnu/llvm/lldb/source/Target/TargetProperties.td b/gnu/llvm/lldb/source/Target/TargetProperties.td index 8f627ad0f1a..202304174bc 100644 --- a/gnu/llvm/lldb/source/Target/TargetProperties.td +++ b/gnu/llvm/lldb/source/Target/TargetProperties.td @@ -37,6 +37,9 @@ let Definition = "target" in { def SourceMap: Property<"source-map", "PathMap">, DefaultStringValue<"">, Desc<"Source path remappings apply substitutions to the paths of source files, typically needed to debug from a different host than the one that built the target. The source-map property consists of an array of pairs, the first element is a path prefix, and the second is its replacement. The syntax is `prefix1 replacement1 prefix2 replacement2...`. The pairs are checked in order, the first prefix that matches is used, and that prefix is substituted with the replacement. A common pattern is to use source-map in conjunction with the clang -fdebug-prefix-map flag. In the build, use `-fdebug-prefix-map=/path/to/build_dir=.` to rewrite the host specific build directory to `.`. Then for debugging, use `settings set target.source-map . /path/to/local_dir` to convert `.` to a valid local path.">; + def AutoSourceMapRelative: Property<"auto-source-map-relative", "Boolean">, + DefaultTrue, + Desc<"Automatically deduce source path mappings based on source file breakpoint resolution. It only deduces source mapping if source file breakpoint request is using full path and if the debug info contains relative paths.">; def ExecutableSearchPaths: Property<"exec-search-paths", "FileSpecList">, DefaultStringValue<"">, Desc<"Executable search paths to use when locating executable files whose paths don't match the local file system.">; @@ -54,6 +57,10 @@ let Definition = "target" in { EnumValues<"OptionEnumValues(g_import_std_module_value_types)">, Desc<"Import the 'std' C++ module to improve expression parsing involving " " C++ standard library types.">; + def DynamicClassInfoHelper: Property<"objc-dynamic-class-extractor", "Enum">, + DefaultEnumValue<"eDynamicClassInfoHelperAuto">, + EnumValues<"OptionEnumValues(g_dynamic_class_info_helper_value_types)">, + Desc<"Configure how LLDB parses dynamic Objective-C class metadata. By default LLDB will choose the most appropriate method for the target OS.">; def AutoApplyFixIts: Property<"auto-apply-fixits", "Boolean">, DefaultTrue, Desc<"Automatically apply fix-it hints to expressions.">; @@ -63,15 +70,18 @@ let Definition = "target" in { def NotifyAboutFixIts: Property<"notify-about-fixits", "Boolean">, DefaultTrue, Desc<"Print the fixed expression text.">; - def SaveObjects: Property<"save-jit-objects", "Boolean">, - DefaultFalse, - Desc<"Save intermediate object files generated by the LLVM JIT">; + def SaveObjectsDir: Property<"save-jit-objects-dir", "FileSpec">, + DefaultStringValue<"">, + Desc<"If specified, the directory to save intermediate object files generated by the LLVM JIT">; def MaxZeroPaddingInFloatFormat: Property<"max-zero-padding-in-float-format", "UInt64">, DefaultUnsignedValue<6>, Desc<"The maximum number of zeroes to insert when displaying a very small float before falling back to scientific notation.">; def MaxChildrenCount: Property<"max-children-count", "SInt64">, DefaultUnsignedValue<256>, Desc<"Maximum number of children to expand in any level of depth.">; + def MaxChildrenDepth: Property<"max-children-depth", "UInt64">, + DefaultUnsignedValue<0xFFFFFFFF>, + Desc<"Maximum depth to expand children.">; def MaxSummaryLength: Property<"max-string-summary-length", "SInt64">, DefaultUnsignedValue<1024>, Desc<"Maximum number of characters to show when using %s in summary strings.">; @@ -163,9 +173,6 @@ let Definition = "target" in { def DisplayRecognizedArguments: Property<"display-recognized-arguments", "Boolean">, DefaultFalse, Desc<"Show recognized arguments in variable listings by default.">; - def NonStopModeEnabled: Property<"non-stop-mode", "Boolean">, - DefaultFalse, - Desc<"Disable lock-step debugging, instead control threads independently.">; def RequireHardwareBreakpoints: Property<"require-hardware-breakpoint", "Boolean">, DefaultFalse, Desc<"Require all breakpoints to be hardware breakpoints.">; @@ -226,7 +233,7 @@ let Definition = "process" in { def StopOnExec: Property<"stop-on-exec", "Boolean">, Global, DefaultTrue, - Desc<"If true, stop when a shared library is loaded or unloaded.">; + Desc<"If true, stop when the inferior exec's.">; def UtilityExpressionTimeout: Property<"utility-expression-timeout", "UInt64">, DefaultUnsignedValue<15>, Desc<"The time in seconds to wait for LLDB-internal utility expressions.">; @@ -239,6 +246,10 @@ let Definition = "process" in { def VirtualAddressableBits: Property<"virtual-addressable-bits", "UInt64">, DefaultUnsignedValue<0>, Desc<"The number of bits used for addressing. If the value is 39, then bits 0..38 are used for addressing. The default value of 0 means unspecified.">; + def FollowForkMode: Property<"follow-fork-mode", "Enum">, + DefaultEnumValue<"eFollowParent">, + EnumValues<"OptionEnumValues(g_follow_fork_mode_values)">, + Desc<"Debugger's behavior upon fork or vfork.">; } let Definition = "platform" in { @@ -273,6 +284,6 @@ let Definition = "thread" in { DefaultFalse, Desc<"If true, this thread will single-step and log execution.">; def MaxBacktraceDepth: Property<"max-backtrace-depth", "UInt64">, - DefaultUnsignedValue<300000>, + DefaultUnsignedValue<600000>, Desc<"Maximum number of frames to backtrace.">; } diff --git a/gnu/llvm/lldb/source/Target/Thread.cpp b/gnu/llvm/lldb/source/Target/Thread.cpp index b423f1b5f1f..d620f746339 100644 --- a/gnu/llvm/lldb/source/Target/Thread.cpp +++ b/gnu/llvm/lldb/source/Target/Thread.cpp @@ -13,6 +13,7 @@ #include "lldb/Core/Module.h" #include "lldb/Core/StructuredDataImpl.h" #include "lldb/Core/ValueObject.h" +#include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Host/Host.h" #include "lldb/Interpreter/OptionValueFileSpecList.h" #include "lldb/Interpreter/OptionValueProperties.h" @@ -43,6 +44,7 @@ #include "lldb/Target/ThreadPlanStepUntil.h" #include "lldb/Target/ThreadSpec.h" #include "lldb/Target/UnwindLLDB.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/State.h" @@ -51,16 +53,16 @@ #include "lldb/lldb-enumerations.h" #include <memory> +#include <optional> using namespace lldb; using namespace lldb_private; -const ThreadPropertiesSP &Thread::GetGlobalProperties() { +ThreadProperties &Thread::GetGlobalProperties() { // NOTE: intentional leak so we don't crash if global destructor chain gets // called as other threads still use the result of this function - static ThreadPropertiesSP *g_settings_sp_ptr = - new ThreadPropertiesSP(new ThreadProperties(true)); - return *g_settings_sp_ptr; + static ThreadProperties *g_settings_ptr = new ThreadProperties(true); + return *g_settings_ptr; } #define LLDB_PROPERTIES_thread @@ -103,7 +105,7 @@ ThreadProperties::ThreadProperties(bool is_global) : Properties() { m_collection_sp->Initialize(g_thread_properties); } else m_collection_sp = - OptionValueProperties::CreateLocalCopy(*Thread::GetGlobalProperties()); + OptionValueProperties::CreateLocalCopy(Thread::GetGlobalProperties()); } ThreadProperties::~ThreadProperties() = default; @@ -220,6 +222,7 @@ Thread::Thread(Process &process, lldb::tid_t tid, bool use_invalid_index_id) Thread::GetStaticBroadcasterClass().AsCString()), m_process_wp(process.shared_from_this()), m_stop_info_sp(), m_stop_info_stop_id(0), m_stop_info_override_stop_id(0), + m_should_run_before_public_stop(false), m_index_id(use_invalid_index_id ? LLDB_INVALID_INDEX32 : process.GetNextThreadIndexID(tid)), m_reg_context_sp(), m_state(eStateUnloaded), m_state_mutex(), @@ -229,7 +232,7 @@ Thread::Thread(Process &process, lldb::tid_t tid, bool use_invalid_index_id) m_unwinder_up(), m_destroy_called(false), m_override_should_notify(eLazyBoolCalculate), m_extended_info_fetched(false), m_extended_info() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + Log *log = GetLog(LLDBLog::Object); LLDB_LOGF(log, "%p Thread::Thread(tid = 0x%4.4" PRIx64 ")", static_cast<void *>(this), GetID()); @@ -237,7 +240,7 @@ Thread::Thread(Process &process, lldb::tid_t tid, bool use_invalid_index_id) } Thread::~Thread() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + Log *log = GetLog(LLDBLog::Object); LLDB_LOGF(log, "%p Thread::~Thread(tid = 0x%4.4" PRIx64 ")", static_cast<void *>(this), GetID()); /// If you hit this assert, it means your derived class forgot to call @@ -368,7 +371,10 @@ void Thread::CalculatePublicStopInfo() { SetStopInfo(GetStopInfo()); } -lldb::StopInfoSP Thread::GetPrivateStopInfo() { +lldb::StopInfoSP Thread::GetPrivateStopInfo(bool calculate) { + if (!calculate) + return m_stop_info_sp; + if (m_destroy_called) return m_stop_info_sp; @@ -376,9 +382,15 @@ lldb::StopInfoSP Thread::GetPrivateStopInfo() { if (process_sp) { const uint32_t process_stop_id = process_sp->GetStopID(); if (m_stop_info_stop_id != process_stop_id) { + // We preserve the old stop info for a variety of reasons: + // 1) Someone has already updated it by the time we get here + // 2) We didn't get to execute the breakpoint instruction we stopped at + // 3) This is a virtual step so we didn't actually run + // 4) If this thread wasn't allowed to run the last time round. if (m_stop_info_sp) { if (m_stop_info_sp->IsValid() || IsStillAtLastBreakpointHit() || - GetCurrentPlan()->IsVirtualStep()) + GetCurrentPlan()->IsVirtualStep() + || GetTemporaryResumeState() == eStateSuspended) SetStopInfo(m_stop_info_sp); else m_stop_info_sp.reset(); @@ -446,7 +458,7 @@ void Thread::SetStopInfo(const lldb::StopInfoSP &stop_info_sp) { m_stop_info_stop_id = process_sp->GetStopID(); else m_stop_info_stop_id = UINT32_MAX; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); LLDB_LOGF(log, "%p: tid = 0x%" PRIx64 ": stop info = %s (stop_id = %u)", static_cast<void *>(this), GetID(), stop_info_sp ? stop_info_sp->GetDescription() : "<NULL>", @@ -472,9 +484,7 @@ void Thread::SetStopInfoToNothing() { StopInfo::CreateStopReasonWithSignal(*this, LLDB_INVALID_SIGNAL_NUMBER)); } -bool Thread::ThreadStoppedForAReason(void) { - return (bool)GetPrivateStopInfo(); -} +bool Thread::ThreadStoppedForAReason() { return (bool)GetPrivateStopInfo(); } bool Thread::CheckpointThreadState(ThreadStateCheckpoint &saved_state) { saved_state.register_backup_sp.reset(); @@ -579,7 +589,7 @@ std::string Thread::GetStopDescriptionRaw() { } void Thread::SelectMostRelevantFrame() { - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD); + Log *log = GetLog(LLDBLog::Thread); auto frames_list_sp = GetStackFrameList(); @@ -724,7 +734,11 @@ bool Thread::ShouldResume(StateType resume_state) { return need_to_resume; } -void Thread::DidResume() { SetResumeSignal(LLDB_INVALID_SIGNAL_NUMBER); } +void Thread::DidResume() { + SetResumeSignal(LLDB_INVALID_SIGNAL_NUMBER); + // This will get recomputed each time when we stop. + SetShouldRunBeforePublicStop(false); +} void Thread::DidStop() { SetState(eStateStopped); } @@ -733,7 +747,7 @@ bool Thread::ShouldStop(Event *event_ptr) { bool should_stop = true; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (GetResumeState() == eStateSuspended) { LLDB_LOGF(log, @@ -764,6 +778,9 @@ bool Thread::ShouldStop(Event *event_ptr) { : LLDB_INVALID_ADDRESS); return false; } + + // Clear the "must run me before stop" if it was set: + SetShouldRunBeforePublicStop(false); if (log) { LLDB_LOGF(log, @@ -845,10 +862,15 @@ bool Thread::ShouldStop(Event *event_ptr) { // we're done, otherwise we forward this to the next plan in the // stack below. done_processing_current_plan = - (plan_ptr->IsMasterPlan() && !plan_ptr->OkayToDiscard()); - } else + (plan_ptr->IsControllingPlan() && !plan_ptr->OkayToDiscard()); + } else { + bool should_force_run = plan_ptr->ShouldRunBeforePublicStop(); + if (should_force_run) { + SetShouldRunBeforePublicStop(true); + should_stop = false; + } done_processing_current_plan = true; - + } break; } } @@ -883,11 +905,11 @@ bool Thread::ShouldStop(Event *event_ptr) { current_plan->GetName()); } - // If a Master Plan wants to stop, we let it. Otherwise, see if the - // plan's parent wants to stop. + // If a Controlling Plan wants to stop, we let it. Otherwise, see if + // the plan's parent wants to stop. PopPlan(); - if (should_stop && current_plan->IsMasterPlan() && + if (should_stop && current_plan->IsControllingPlan() && !current_plan->OkayToDiscard()) { break; } @@ -906,8 +928,8 @@ bool Thread::ShouldStop(Event *event_ptr) { should_stop = false; } - // One other potential problem is that we set up a master plan, then stop in - // before it is complete - for instance by hitting a breakpoint during a + // One other potential problem is that we set up a controlling plan, then stop + // in before it is complete - for instance by hitting a breakpoint during a // step-over - then do some step/finish/etc operations that wind up past the // end point condition of the initial plan. We don't want to strand the // original plan on the stack, This code clears stale plans off the stack. @@ -958,7 +980,7 @@ Vote Thread::ShouldReportStop(Event *event_ptr) { StateType thread_state = GetResumeState(); StateType temp_thread_state = GetTemporaryResumeState(); - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (thread_state == eStateSuspended || thread_state == eStateInvalid) { LLDB_LOGF(log, @@ -990,7 +1012,7 @@ Vote Thread::ShouldReportStop(Event *event_ptr) { // the last plan, regardless of whether it is private or not. LLDB_LOGF(log, "Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 - ": returning vote for complete stack's back plan", + ": returning vote for complete stack's back plan", GetID()); return GetPlans().GetCompletedPlan(false)->ShouldReportStop(event_ptr); } else { @@ -1022,7 +1044,7 @@ Vote Thread::ShouldReportRun(Event *event_ptr) { return eVoteNoOpinion; } - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (GetPlans().AnyCompletedPlans()) { // Pass skip_private = false to GetCompletedPlan, since we want to ask // the last plan, regardless of whether it is private or not. @@ -1063,13 +1085,13 @@ ThreadPlanStack &Thread::GetPlans() const { // queries GetDescription makes, and only assert if you try to run the thread. if (!m_null_plan_stack_up) m_null_plan_stack_up = std::make_unique<ThreadPlanStack>(*this, true); - return *(m_null_plan_stack_up.get()); + return *m_null_plan_stack_up; } void Thread::PushPlan(ThreadPlanSP thread_plan_sp) { assert(thread_plan_sp && "Don't push an empty thread plan."); - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (log) { StreamString s; thread_plan_sp->GetDescription(&s, lldb::eDescriptionLevelFull); @@ -1082,7 +1104,7 @@ void Thread::PushPlan(ThreadPlanSP thread_plan_sp) { } void Thread::PopPlan() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); ThreadPlanSP popped_plan_sp = GetPlans().PopPlan(); if (log) { LLDB_LOGF(log, "Popping plan: \"%s\", tid = 0x%4.4" PRIx64 ".", @@ -1091,8 +1113,8 @@ void Thread::PopPlan() { } void Thread::DiscardPlan() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - ThreadPlanSP discarded_plan_sp = GetPlans().PopPlan(); + Log *log = GetLog(LLDBLog::Step); + ThreadPlanSP discarded_plan_sp = GetPlans().DiscardPlan(); LLDB_LOGF(log, "Discarding plan: \"%s\", tid = 0x%4.4" PRIx64 ".", discarded_plan_sp->GetName(), @@ -1194,7 +1216,7 @@ void Thread::DiscardThreadPlansUpToPlan(lldb::ThreadPlanSP &up_to_plan_sp) { } void Thread::DiscardThreadPlansUpToPlan(ThreadPlan *up_to_plan_ptr) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); LLDB_LOGF(log, "Discarding thread plans for thread tid = 0x%4.4" PRIx64 ", up to %p", @@ -1203,7 +1225,7 @@ void Thread::DiscardThreadPlansUpToPlan(ThreadPlan *up_to_plan_ptr) { } void Thread::DiscardThreadPlans(bool force) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (log) { LLDB_LOGF(log, "Discarding thread plans for thread (tid = 0x%4.4" PRIx64 @@ -1215,7 +1237,7 @@ void Thread::DiscardThreadPlans(bool force) { GetPlans().DiscardAllPlans(); return; } - GetPlans().DiscardConsultingMasterPlans(); + GetPlans().DiscardConsultingControllingPlans(); } Status Thread::UnwindInnermostExpression() { @@ -1371,15 +1393,9 @@ lldb::ThreadPlanSP Thread::QueueThreadPlanForStepScripted( bool abort_other_plans, const char *class_name, StructuredData::ObjectSP extra_args_sp, bool stop_other_threads, Status &status) { - - StructuredDataImpl *extra_args_impl = nullptr; - if (extra_args_sp) { - extra_args_impl = new StructuredDataImpl(); - extra_args_impl->SetObjectSP(extra_args_sp); - } - ThreadPlanSP thread_plan_sp(new ThreadPlanPython(*this, class_name, - extra_args_impl)); + ThreadPlanSP thread_plan_sp(new ThreadPlanPython( + *this, class_name, StructuredDataImpl(extra_args_sp))); thread_plan_sp->SetStopOthers(stop_other_threads); status = QueueThreadPlan(thread_plan_sp, abort_other_plans); return thread_plan_sp; @@ -1648,6 +1664,10 @@ addr_t Thread::GetThreadLocalData(const ModuleSP module, bool Thread::SafeToCallFunctions() { Process *process = GetProcess().get(); if (process) { + DynamicLoader *loader = GetProcess()->GetDynamicLoader(); + if (loader && loader->IsFullyInitialized() == false) + return false; + SystemRuntime *runtime = process->GetSystemRuntime(); if (runtime) { return runtime->SafeToCallFunctionsOnThisThread(shared_from_this()); @@ -1915,7 +1935,7 @@ Status Thread::StepIn(bool source_step, false, abort_other_plans, run_mode, error); } - new_plan_sp->SetIsMasterPlan(true); + new_plan_sp->SetIsControllingPlan(true); new_plan_sp->SetOkayToDiscard(false); // Why do we need to set the current thread by ID here??? @@ -1948,7 +1968,7 @@ Status Thread::StepOver(bool source_step, true, abort_other_plans, run_mode, error); } - new_plan_sp->SetIsMasterPlan(true); + new_plan_sp->SetIsControllingPlan(true); new_plan_sp->SetOkayToDiscard(false); // Why do we need to set the current thread by ID here??? @@ -1960,7 +1980,7 @@ Status Thread::StepOver(bool source_step, return error; } -Status Thread::StepOut() { +Status Thread::StepOut(uint32_t frame_idx) { Status error; Process *process = GetProcess().get(); if (StateIsStoppedState(process->GetState(), true)) { @@ -1970,9 +1990,9 @@ Status Thread::StepOut() { ThreadPlanSP new_plan_sp(QueueThreadPlanForStepOut( abort_other_plans, nullptr, first_instruction, stop_other_threads, - eVoteYes, eVoteNoOpinion, 0, error)); + eVoteYes, eVoteNoOpinion, frame_idx, error)); - new_plan_sp->SetIsMasterPlan(true); + new_plan_sp->SetIsControllingPlan(true); new_plan_sp->SetOkayToDiscard(false); // Why do we need to set the current thread by ID here??? @@ -2014,3 +2034,27 @@ ThreadSP Thread::GetCurrentExceptionBacktrace() { return ThreadSP(); } + +lldb::ValueObjectSP Thread::GetSiginfoValue() { + ProcessSP process_sp = GetProcess(); + assert(process_sp); + Target &target = process_sp->GetTarget(); + PlatformSP platform_sp = target.GetPlatform(); + assert(platform_sp); + ArchSpec arch = target.GetArchitecture(); + + CompilerType type = platform_sp->GetSiginfoType(arch.GetTriple()); + if (!type.IsValid()) + return ValueObjectConstResult::Create(&target, Status("no siginfo_t for the platform")); + + std::optional<uint64_t> type_size = type.GetByteSize(nullptr); + assert(type_size); + llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> data = + GetSiginfo(*type_size); + if (!data) + return ValueObjectConstResult::Create(&target, Status(data.takeError())); + + DataExtractor data_extractor{data.get()->getBufferStart(), data.get()->getBufferSize(), + process_sp->GetByteOrder(), arch.GetAddressByteSize()}; + return ValueObjectConstResult::Create(&target, type, ConstString("__lldb_siginfo"), data_extractor); +} diff --git a/gnu/llvm/lldb/source/Target/ThreadCollection.cpp b/gnu/llvm/lldb/source/Target/ThreadCollection.cpp index 8c2309795a4..45ce2fd318b 100644 --- a/gnu/llvm/lldb/source/Target/ThreadCollection.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadCollection.cpp @@ -34,10 +34,10 @@ void ThreadCollection::AddThreadSortedByIndexID(const ThreadSP &thread_sp) { m_threads.push_back(thread_sp); else { m_threads.insert( - std::upper_bound(m_threads.begin(), m_threads.end(), thread_sp, - [](const ThreadSP &lhs, const ThreadSP &rhs) -> bool { - return lhs->GetIndexID() < rhs->GetIndexID(); - }), + llvm::upper_bound(m_threads, thread_sp, + [](const ThreadSP &lhs, const ThreadSP &rhs) -> bool { + return lhs->GetIndexID() < rhs->GetIndexID(); + }), thread_sp); } } diff --git a/gnu/llvm/lldb/source/Target/ThreadList.cpp b/gnu/llvm/lldb/source/Target/ThreadList.cpp index df2cc8ef632..006c8648be5 100644 --- a/gnu/llvm/lldb/source/Target/ThreadList.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadList.cpp @@ -16,6 +16,7 @@ #include "lldb/Target/ThreadList.h" #include "lldb/Target/ThreadPlan.h" #include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/State.h" @@ -225,7 +226,7 @@ ThreadSP ThreadList::FindThreadByIndexID(uint32_t index_id, bool can_update) { bool ThreadList::ShouldStop(Event *event_ptr) { // Running events should never stop, obviously... - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); // The ShouldStop method of the threads can do a whole lot of work, figuring // out whether the thread plan conditions are met. So we don't want to keep @@ -244,14 +245,17 @@ bool ThreadList::ShouldStop(Event *event_ptr) { for (lldb::ThreadSP thread_sp : m_threads) { // This is an optimization... If we didn't let a thread run in between // the previous stop and this one, we shouldn't have to consult it for - // ShouldStop. So just leave it off the list we are going to inspect. On - // Linux, if a thread-specific conditional breakpoint was hit, it won't + // ShouldStop. So just leave it off the list we are going to inspect. + // If the thread didn't run but had work to do before declaring a public + // stop, then also include it. + // On Linux, if a thread-specific conditional breakpoint was hit, it won't // necessarily be the thread that hit the breakpoint itself that // evaluates the conditional expression, so the thread that hit the // breakpoint could still be asked to stop, even though it hasn't been // allowed to run since the previous stop. if (thread_sp->GetTemporaryResumeState() != eStateSuspended || - thread_sp->IsStillAtLastBreakpointHit()) + thread_sp->IsStillAtLastBreakpointHit() + || thread_sp->ShouldRunBeforePublicStop()) threads_copy.push_back(thread_sp); } @@ -299,6 +303,10 @@ bool ThreadList::ShouldStop(Event *event_ptr) { thread_sp->GetStopInfo(); } + // If a thread needs to finish some job that can be done just on this thread + // before broadcastion the stop, it will signal that by returning true for + // ShouldRunBeforePublicStop. This variable gathers the results from that. + bool a_thread_needs_to_run = false; for (pos = threads_copy.begin(); pos != end; ++pos) { ThreadSP thread_sp(*pos); @@ -328,11 +336,23 @@ bool ThreadList::ShouldStop(Event *event_ptr) { did_anybody_stop_for_a_reason |= thread_sp->ThreadStoppedForAReason(); const bool thread_should_stop = thread_sp->ShouldStop(event_ptr); + if (thread_should_stop) should_stop |= true; + else { + bool this_thread_forces_run = thread_sp->ShouldRunBeforePublicStop(); + a_thread_needs_to_run |= this_thread_forces_run; + if (this_thread_forces_run) + LLDB_LOG(log, + "ThreadList::{0} thread: {1:x}, " + "says it needs to run before public stop.", + __FUNCTION__, thread_sp->GetID()); + } } - if (!should_stop && !did_anybody_stop_for_a_reason) { + if (a_thread_needs_to_run) { + should_stop = false; + } else if (!should_stop && !did_anybody_stop_for_a_reason) { should_stop = true; LLDB_LOGF(log, "ThreadList::%s we stopped but no threads had a stop reason, " @@ -360,16 +380,24 @@ Vote ThreadList::ShouldReportStop(Event *event_ptr) { m_process->UpdateThreadListIfNeeded(); collection::iterator pos, end = m_threads.end(); - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); LLDB_LOGF(log, "ThreadList::%s %" PRIu64 " threads", __FUNCTION__, (uint64_t)m_threads.size()); // Run through the threads and ask whether we should report this event. For // stopping, a YES vote wins over everything. A NO vote wins over NO - // opinion. + // opinion. The exception is if a thread has work it needs to force before + // a public stop, which overrides everyone else's opinion: for (pos = m_threads.begin(); pos != end; ++pos) { ThreadSP thread_sp(*pos); + if (thread_sp->ShouldRunBeforePublicStop()) { + LLDB_LOG(log, "Thread {0:x} has private business to complete, overrode " + "the should report stop.", thread_sp->GetID()); + result = eVoteNo; + break; + } + const Vote vote = thread_sp->ShouldReportStop(event_ptr); switch (vote) { case eVoteNoOpinion: @@ -416,7 +444,7 @@ Vote ThreadList::ShouldReportRun(Event *event_ptr) { // Run through the threads and ask whether we should report this event. The // rule is NO vote wins over everything, a YES vote wins over no opinion. - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); for (pos = m_threads.begin(); pos != end; ++pos) { if ((*pos)->GetResumeState() != eStateSuspended) { @@ -460,7 +488,7 @@ void ThreadList::RefreshStateAfterStop() { m_process->UpdateThreadListIfNeeded(); - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (log && log->GetVerbose()) LLDB_LOGF(log, "Turning off notification of new threads while single stepping " @@ -514,13 +542,13 @@ bool ThreadList::WillResume() { } if (wants_solo_run) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (log && log->GetVerbose()) LLDB_LOGF(log, "Turning on notification of new threads while single " "stepping a thread."); m_process->StartNoticingNewThreads(); } else { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (log && log->GetVerbose()) LLDB_LOGF(log, "Turning off notification of new threads while single " "stepping a thread."); @@ -549,7 +577,13 @@ bool ThreadList::WillResume() { run_me_only_list.SetStopID(m_process->GetStopID()); - bool run_only_current_thread = false; + // One or more threads might want to "Stop Others". We want to handle all + // those requests first. And if there is a thread that wanted to "resume + // before a public stop", let it get the first crack: + // There are two special kinds of thread that have priority for "StopOthers": + // a "ShouldRunBeforePublicStop thread, or the currently selected thread. If + // we find one satisfying that critereon, put it here. + ThreadSP stop_others_thread_sp; for (pos = m_threads.begin(); pos != end; ++pos) { ThreadSP thread_sp(*pos); @@ -561,17 +595,16 @@ bool ThreadList::WillResume() { // You can't say "stop others" and also want yourself to be suspended. assert(thread_sp->GetCurrentPlan()->RunState() != eStateSuspended); + run_me_only_list.AddThread(thread_sp); - if (thread_sp == GetSelectedThread()) { - // If the currently selected thread wants to run on its own, always let - // it. - run_only_current_thread = true; - run_me_only_list.Clear(); - run_me_only_list.AddThread(thread_sp); + if (thread_sp == GetSelectedThread()) + stop_others_thread_sp = thread_sp; + + if (thread_sp->ShouldRunBeforePublicStop()) { + // This takes precedence, so if we find one of these, service it: + stop_others_thread_sp = thread_sp; break; } - - run_me_only_list.AddThread(thread_sp); } } @@ -592,8 +625,8 @@ bool ThreadList::WillResume() { } else { ThreadSP thread_to_run; - if (run_only_current_thread) { - thread_to_run = GetSelectedThread(); + if (stop_others_thread_sp) { + thread_to_run = stop_others_thread_sp; } else if (run_me_only_list.GetSize(false) == 1) { thread_to_run = run_me_only_list.GetThreadAtIndex(0); } else { @@ -606,6 +639,9 @@ bool ThreadList::WillResume() { for (pos = m_threads.begin(); pos != end; ++pos) { ThreadSP thread_sp(*pos); if (thread_sp == thread_to_run) { + // Note, a thread might be able to fulfil it's plan w/o actually + // resuming. An example of this is a step that changes the current + // inlined function depth w/o moving the PC. Check that here: if (!thread_sp->ShouldResume(thread_sp->GetCurrentPlan()->RunState())) need_to_resume = false; } else @@ -623,7 +659,7 @@ void ThreadList::DidResume() { // Don't clear out threads that aren't going to get a chance to run, rather // leave their state for the next time around. ThreadSP thread_sp(*pos); - if (thread_sp->GetResumeState() != eStateSuspended) + if (thread_sp->GetTemporaryResumeState() != eStateSuspended) thread_sp->DidResume(); } } diff --git a/gnu/llvm/lldb/source/Target/ThreadPlan.cpp b/gnu/llvm/lldb/source/Target/ThreadPlan.cpp index 6b55f3912d1..9913ecb591f 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlan.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlan.cpp @@ -12,6 +12,7 @@ #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/State.h" @@ -26,8 +27,8 @@ ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, m_takes_iteration_count(false), m_could_not_resolve_hw_bp(false), m_thread(&thread), m_kind(kind), m_name(name), m_plan_complete_mutex(), m_cached_plan_explains_stop(eLazyBoolCalculate), m_plan_complete(false), - m_plan_private(false), m_okay_to_discard(true), m_is_master_plan(false), - m_plan_succeeded(true) { + m_plan_private(false), m_okay_to_discard(true), + m_is_controlling_plan(false), m_plan_succeeded(true) { SetID(GetNextID()); } @@ -76,7 +77,7 @@ bool ThreadPlan::MischiefManaged() { } Vote ThreadPlan::ShouldReportStop(Event *event_ptr) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (m_report_stop_vote == eVoteNoOpinion) { ThreadPlan *prev_plan = GetPreviousPlan(); @@ -116,7 +117,7 @@ bool ThreadPlan::WillResume(StateType resume_state, bool current_plan) { m_cached_plan_explains_stop = eLazyBoolCalculate; if (current_plan) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (log) { RegisterContext *reg_ctx = GetThread().GetRegisterContext().get(); @@ -149,10 +150,10 @@ lldb::user_id_t ThreadPlan::GetNextID() { void ThreadPlan::DidPush() {} -void ThreadPlan::WillPop() {} +void ThreadPlan::DidPop() {} bool ThreadPlan::OkayToDiscard() { - return IsMasterPlan() ? m_okay_to_discard : true; + return IsControllingPlan() ? m_okay_to_discard : true; } lldb::StateType ThreadPlan::RunState() { @@ -195,7 +196,7 @@ bool ThreadPlanNull::ValidatePlan(Stream *error) { ", ptid = 0x%" PRIx64 ")", LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #else - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); if (log) log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", @@ -211,7 +212,7 @@ bool ThreadPlanNull::ShouldStop(Event *event_ptr) { ", ptid = 0x%" PRIx64 ")", LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #else - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); if (log) log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", @@ -227,7 +228,7 @@ bool ThreadPlanNull::WillStop() { ", ptid = 0x%" PRIx64 ")", LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #else - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); if (log) log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", @@ -243,7 +244,7 @@ bool ThreadPlanNull::DoPlanExplainsStop(Event *event_ptr) { ", ptid = 0x%" PRIx64 ")", LLVM_PRETTY_FUNCTION, GetThread().GetID(), GetThread().GetProtocolID()); #else - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); if (log) log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", @@ -261,7 +262,7 @@ bool ThreadPlanNull::MischiefManaged() { ", ptid = 0x%" PRIx64 ")", LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #else - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); if (log) log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", @@ -278,7 +279,7 @@ lldb::StateType ThreadPlanNull::GetPlanRunState() { ", ptid = 0x%" PRIx64 ")", LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #else - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); if (log) log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanBase.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanBase.cpp index c6c4d97c165..dfd2157e70d 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanBase.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanBase.cpp @@ -16,6 +16,7 @@ #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StopInfo.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Stream.h" @@ -40,7 +41,7 @@ ThreadPlanBase::ThreadPlanBase(Thread &thread) #endif new_tracer_sp->EnableTracing(thread.GetTraceEnabledState()); SetThreadPlanTracer(new_tracer_sp); - SetIsMasterPlan(true); + SetIsControllingPlan(true); } ThreadPlanBase::~ThreadPlanBase() = default; @@ -73,7 +74,7 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) { m_report_stop_vote = eVoteYes; m_report_run_vote = eVoteYes; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); StopInfoSP stop_info_sp = GetPrivateStopInfo(); if (stop_info_sp) { @@ -90,8 +91,8 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) { case eStopReasonWatchpoint: if (stop_info_sp->ShouldStopSynchronous(event_ptr)) { // If we are going to stop for a breakpoint, then unship the other - // plans at this point. Don't force the discard, however, so Master - // plans can stay in place if they want to. + // plans at this point. Don't force the discard, however, so + // Controlling plans can stay in place if they want to. LLDB_LOGF( log, "Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanCallFunction.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanCallFunction.cpp index 3699a507d05..7e9bb963bb5 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanCallFunction.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanCallFunction.cpp @@ -21,6 +21,7 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlanRunToAddress.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Stream.h" @@ -33,7 +34,7 @@ using namespace lldb_private; bool ThreadPlanCallFunction::ConstructorSetup( Thread &thread, ABI *&abi, lldb::addr_t &start_load_addr, lldb::addr_t &function_load_addr) { - SetIsMasterPlan(true); + SetIsControllingPlan(true); SetOkayToDiscard(false); SetPrivate(true); @@ -46,7 +47,7 @@ bool ThreadPlanCallFunction::ConstructorSetup( if (!abi) return false; - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); SetBreakpoints(); @@ -103,7 +104,10 @@ ThreadPlanCallFunction::ThreadPlanCallFunction( 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_start_addr(), m_function_sp(0), m_subplan_sp(), + m_cxx_language_runtime(nullptr), m_objc_language_runtime(nullptr), + m_stored_thread_state(), m_real_stop_info_sp(), m_constructor_errors(), + m_return_valobj_sp(), 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) { @@ -133,7 +137,10 @@ ThreadPlanCallFunction::ThreadPlanCallFunction( 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_start_addr(), m_function_sp(0), m_subplan_sp(), + m_cxx_language_runtime(nullptr), m_objc_language_runtime(nullptr), + m_stored_thread_state(), m_real_stop_info_sp(), m_constructor_errors(), + m_return_valobj_sp(), 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(CompilerType()) {} @@ -143,7 +150,7 @@ ThreadPlanCallFunction::~ThreadPlanCallFunction() { } void ThreadPlanCallFunction::ReportRegisterState(const char *message) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (log && log->GetVerbose()) { StreamString strm; RegisterContext *reg_ctx = GetThread().GetRegisterContext().get(); @@ -166,7 +173,7 @@ void ThreadPlanCallFunction::ReportRegisterState(const char *message) { } void ThreadPlanCallFunction::DoTakedown(bool success) { - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (!m_valid) { // Don't call DoTakedown if we were never valid to begin with. @@ -209,7 +216,7 @@ void ThreadPlanCallFunction::DoTakedown(bool success) { } } -void ThreadPlanCallFunction::WillPop() { DoTakedown(PlanSucceeded()); } +void ThreadPlanCallFunction::DidPop() { DoTakedown(PlanSucceeded()); } void ThreadPlanCallFunction::GetDescription(Stream *s, DescriptionLevel level) { if (level == eDescriptionLevelBrief) { @@ -242,8 +249,7 @@ Vote ThreadPlanCallFunction::ShouldReportStop(Event *event_ptr) { } bool ThreadPlanCallFunction::DoPlanExplainsStop(Event *event_ptr) { - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP | - LIBLLDB_LOG_PROCESS)); + Log *log(GetLog(LLDBLog::Step | LLDBLog::Process)); m_real_stop_info_sp = GetPrivateStopInfo(); // If our subplan knows why we stopped, even if it's done (which would @@ -382,7 +388,7 @@ void ThreadPlanCallFunction::DidPush() { bool ThreadPlanCallFunction::WillStop() { return true; } bool ThreadPlanCallFunction::MischiefManaged() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (IsPlanComplete()) { LLDB_LOGF(log, "ThreadPlanCallFunction(%p): Completed call function plan.", @@ -433,7 +439,7 @@ bool ThreadPlanCallFunction::BreakpointsExplainStop() { (m_objc_language_runtime && m_objc_language_runtime->ExceptionBreakpointsExplainStop( stop_info_sp))) { - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); LLDB_LOGF(log, "ThreadPlanCallFunction::BreakpointsExplainStop - Hit an " "exception breakpoint, setting plan complete."); diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp index 7471e9b3d7a..4bccf96d721 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp @@ -18,7 +18,7 @@ ThreadPlanCallOnFunctionExit::ThreadPlanCallOnFunctionExit( ), m_callback(callback) { // We are not a user-generated plan. - SetIsMasterPlan(false); + SetIsControllingPlan(false); } void ThreadPlanCallOnFunctionExit::DidPush() { diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanCallUserExpression.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanCallUserExpression.cpp index 9dddd850b6a..65758599dce 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanCallUserExpression.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanCallUserExpression.cpp @@ -8,7 +8,6 @@ #include "lldb/Target/ThreadPlanCallUserExpression.h" - #include "lldb/Breakpoint/Breakpoint.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Address.h" @@ -23,6 +22,7 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlanRunToAddress.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Stream.h" @@ -39,7 +39,7 @@ ThreadPlanCallUserExpression::ThreadPlanCallUserExpression( m_user_expression_sp(user_expression_sp) { // User expressions are generally "User generated" so we should set them up // to stop when done. - SetIsMasterPlan(true); + SetIsControllingPlan(true); SetOkayToDiscard(false); } @@ -59,14 +59,14 @@ void ThreadPlanCallUserExpression::DidPush() { m_user_expression_sp->WillStartExecuting(); } -void ThreadPlanCallUserExpression::WillPop() { - ThreadPlanCallFunction::WillPop(); +void ThreadPlanCallUserExpression::DidPop() { + ThreadPlanCallFunction::DidPop(); if (m_user_expression_sp) m_user_expression_sp.reset(); } bool ThreadPlanCallUserExpression::MischiefManaged() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (IsPlanComplete()) { LLDB_LOGF(log, "ThreadPlanCallFunction(%p): Completed call function plan.", diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanPython.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanPython.cpp index e83f0e9e715..bc2a7a02e99 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanPython.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanPython.cpp @@ -17,6 +17,7 @@ #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlan.h" #include "lldb/Target/ThreadPlanPython.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/State.h" @@ -26,21 +27,16 @@ using namespace lldb_private; // ThreadPlanPython ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name, - StructuredDataImpl *args_data) + const StructuredDataImpl &args_data) : ThreadPlan(ThreadPlan::eKindPython, "Python based Thread Plan", thread, eVoteNoOpinion, eVoteNoOpinion), m_class_name(class_name), m_args_data(args_data), m_did_push(false), m_stop_others(false) { - SetIsMasterPlan(true); + SetIsControllingPlan(true); SetOkayToDiscard(true); SetPrivate(false); } -ThreadPlanPython::~ThreadPlanPython() { - // FIXME, do I need to decrement the ref count on this implementation object - // to make it go away? -} - bool ThreadPlanPython::ValidatePlan(Stream *error) { if (!m_did_push) return true; @@ -75,7 +71,7 @@ void ThreadPlanPython::DidPush() { } bool ThreadPlanPython::ShouldStop(Event *event_ptr) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, m_class_name.c_str()); @@ -94,7 +90,7 @@ bool ThreadPlanPython::ShouldStop(Event *event_ptr) { } bool ThreadPlanPython::IsPlanStale() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, m_class_name.c_str()); @@ -113,7 +109,7 @@ bool ThreadPlanPython::IsPlanStale() { } bool ThreadPlanPython::DoPlanExplainsStop(Event *event_ptr) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, m_class_name.c_str()); @@ -132,7 +128,7 @@ bool ThreadPlanPython::DoPlanExplainsStop(Event *event_ptr) { } bool ThreadPlanPython::MischiefManaged() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, m_class_name.c_str()); bool mischief_managed = true; @@ -147,7 +143,7 @@ bool ThreadPlanPython::MischiefManaged() { } lldb::StateType ThreadPlanPython::GetPlanRunState() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, m_class_name.c_str()); lldb::StateType run_state = eStateRunning; @@ -169,7 +165,7 @@ void ThreadPlanPython::GetDescription(Stream *s, lldb::DescriptionLevel level) { } bool ThreadPlanPython::WillStop() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, m_class_name.c_str()); return true; diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanRunToAddress.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanRunToAddress.cpp index cb4a58b1cf2..a2ac8c3d096 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanRunToAddress.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanRunToAddress.cpp @@ -11,6 +11,7 @@ #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Stream.h" @@ -169,7 +170,7 @@ StateType ThreadPlanRunToAddress::GetPlanRunState() { return eStateRunning; } bool ThreadPlanRunToAddress::WillStop() { return true; } bool ThreadPlanRunToAddress::MischiefManaged() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (AtOurAddress()) { // Remove the breakpoint diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanShouldStopHere.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanShouldStopHere.cpp index 7774e027c05..e72f8d8f51a 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanShouldStopHere.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanShouldStopHere.cpp @@ -10,6 +10,7 @@ #include "lldb/Symbol/Symbol.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" using namespace lldb; @@ -41,7 +42,7 @@ bool ThreadPlanShouldStopHere::InvokeShouldStopHereCallback( if (m_callbacks.should_stop_here_callback) { should_stop_here = m_callbacks.should_stop_here_callback( m_owner, m_flags, operation, status, m_baton); - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (log) { lldb::addr_t current_addr = m_owner->GetThread().GetRegisterContext()->GetPC(0); @@ -62,7 +63,7 @@ bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback( if (!frame) return true; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if ((operation == eFrameCompareOlder && flags.Test(eStepOutAvoidNoDebug)) || (operation == eFrameCompareYounger && flags.Test(eStepInAvoidNoDebug)) || @@ -98,7 +99,7 @@ ThreadPlanSP ThreadPlanShouldStopHere::DefaultStepFromHereCallback( ThreadPlanSP return_plan_sp; // If we are stepping through code at line number 0, then we need to step // over this range. Otherwise we will step out. - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); if (!frame) diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanStack.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanStack.cpp index d25602d25b9..15729314290 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanStack.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanStack.cpp @@ -150,10 +150,13 @@ lldb::ThreadPlanSP ThreadPlanStack::PopPlan() { std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); assert(m_plans.size() > 1 && "Can't pop the base thread plan"); - lldb::ThreadPlanSP plan_sp = std::move(m_plans.back()); - m_completed_plans.push_back(plan_sp); - plan_sp->WillPop(); + // Note that moving the top element of the vector would leave it in an + // undefined state, and break the guarantee that the stack's thread plans are + // all valid. + lldb::ThreadPlanSP plan_sp = m_plans.back(); m_plans.pop_back(); + m_completed_plans.push_back(plan_sp); + plan_sp->DidPop(); return plan_sp; } @@ -161,10 +164,13 @@ lldb::ThreadPlanSP ThreadPlanStack::DiscardPlan() { std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); assert(m_plans.size() > 1 && "Can't discard the base thread plan"); - lldb::ThreadPlanSP plan_sp = std::move(m_plans.back()); - m_discarded_plans.push_back(plan_sp); - plan_sp->WillPop(); + // Note that moving the top element of the vector would leave it in an + // undefined state, and break the guarantee that the stack's thread plans are + // all valid. + lldb::ThreadPlanSP plan_sp = m_plans.back(); m_plans.pop_back(); + m_discarded_plans.push_back(plan_sp); + plan_sp->DidPop(); return plan_sp; } @@ -204,38 +210,37 @@ void ThreadPlanStack::DiscardAllPlans() { for (int i = stack_size - 1; i > 0; i--) { DiscardPlan(); } - return; } -void ThreadPlanStack::DiscardConsultingMasterPlans() { +void ThreadPlanStack::DiscardConsultingControllingPlans() { std::lock_guard<std::recursive_mutex> guard(m_stack_mutex); while (true) { - int master_plan_idx; + int controlling_plan_idx; bool discard = true; - // Find the first master plan, see if it wants discarding, and if yes + // Find the first controlling plan, see if it wants discarding, and if yes // discard up to it. - for (master_plan_idx = m_plans.size() - 1; master_plan_idx >= 0; - master_plan_idx--) { - if (m_plans[master_plan_idx]->IsMasterPlan()) { - discard = m_plans[master_plan_idx]->OkayToDiscard(); + for (controlling_plan_idx = m_plans.size() - 1; controlling_plan_idx >= 0; + controlling_plan_idx--) { + if (m_plans[controlling_plan_idx]->IsControllingPlan()) { + discard = m_plans[controlling_plan_idx]->OkayToDiscard(); break; } } - // If the master plan doesn't want to get discarded, then we're done. + // If the controlling plan doesn't want to get discarded, then we're done. if (!discard) return; // First pop all the dependent plans: - for (int i = m_plans.size() - 1; i > master_plan_idx; i--) { + for (int i = m_plans.size() - 1; i > controlling_plan_idx; i--) { DiscardPlan(); } - // Now discard the master plan itself. + // Now discard the controlling plan itself. // The bottom-most plan never gets discarded. "OkayToDiscard" for it // means discard it's dependent plans, but not it... - if (master_plan_idx > 0) { + if (controlling_plan_idx > 0) { DiscardPlan(); } } @@ -395,12 +400,13 @@ void ThreadPlanStackMap::Update(ThreadList ¤t_threads, bool delete_missing, bool check_for_new) { + std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex); // Now find all the new threads and add them to the map: if (check_for_new) { for (auto thread : current_threads.Threads()) { lldb::tid_t cur_tid = thread->GetID(); if (!Find(cur_tid)) { - AddThread(*thread.get()); + AddThread(*thread); thread->QueueBasePlan(true); } } @@ -429,6 +435,7 @@ void ThreadPlanStackMap::DumpPlans(Stream &strm, lldb::DescriptionLevel desc_level, bool internal, bool condense_if_trivial, bool skip_unreported) { + std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex); for (auto &elem : m_plans_list) { lldb::tid_t tid = elem.first; uint32_t index_id = 0; @@ -465,6 +472,7 @@ bool ThreadPlanStackMap::DumpPlansForTID(Stream &strm, lldb::tid_t tid, bool internal, bool condense_if_trivial, bool skip_unreported) { + std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex); uint32_t index_id = 0; ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); @@ -504,6 +512,7 @@ bool ThreadPlanStackMap::DumpPlansForTID(Stream &strm, lldb::tid_t tid, bool ThreadPlanStackMap::PrunePlansForTID(lldb::tid_t tid) { // We only remove the plans for unreported TID's. + std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex); ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); if (thread_sp) return false; diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanStepInRange.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanStepInRange.cpp index 69b4b918d46..17f2100b804 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanStepInRange.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanStepInRange.cpp @@ -18,6 +18,7 @@ #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlanStepOut.h" #include "lldb/Target/ThreadPlanStepThrough.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Stream.h" @@ -125,7 +126,7 @@ void ThreadPlanStepInRange::GetDescription(Stream *s, } bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (log) { StreamString s; @@ -269,7 +270,7 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { if (bytes_to_skip != 0) { func_start_address.Slide(bytes_to_skip); - log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP); + log = GetLog(LLDBLog::Step); LLDB_LOGF(log, "Pushing past prologue "); m_sub_plan_sp = thread.QueueThreadPlanForRunToAddress( @@ -339,17 +340,13 @@ bool ThreadPlanStepInRange::FrameMatchesAvoidCriteria() { sc.GetFunctionName(Mangled::ePreferDemangledWithoutArguments) .GetCString(); if (frame_function_name) { - llvm::SmallVector<llvm::StringRef, 2> matches; - bool return_value = - avoid_regexp_to_use->Execute(frame_function_name, &matches); - if (return_value && matches.size() > 1) { - std::string match = matches[1].str(); - LLDB_LOGF(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP), - "Stepping out of function \"%s\" because it matches " - "the avoid regexp \"%s\" - match substring: \"%s\".", + bool return_value = avoid_regexp_to_use->Execute(frame_function_name); + if (return_value) { + LLDB_LOGF(GetLog(LLDBLog::Step), + "Stepping out of function \"%s\" because it matches the " + "avoid regexp \"%s\".", frame_function_name, - avoid_regexp_to_use->GetText().str().c_str(), - match.c_str()); + avoid_regexp_to_use->GetText().str().c_str()); } return return_value; } @@ -363,7 +360,7 @@ bool ThreadPlanStepInRange::DefaultShouldStopHereCallback( Status &status, void *baton) { bool should_stop_here = true; StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); // First see if the ThreadPlanShouldStopHere default implementation thinks we // should get out of here: @@ -445,7 +442,7 @@ bool ThreadPlanStepInRange::DoPlanExplainsStop(Event *event_ptr) { return_value = true; } } else if (IsUsuallyUnexplainedStopReason(reason)) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (log) log->PutCString("ThreadPlanStepInRange got asked if it explains the " "stop for some reason other than step."); @@ -468,7 +465,7 @@ bool ThreadPlanStepInRange::DoWillResume(lldb::StateType resume_state, // See if we are about to step over a virtual inlined call. bool step_without_resume = thread.DecrementCurrentInlinedDepth(); if (step_without_resume) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); LLDB_LOGF(log, "ThreadPlanStepInRange::DoWillResume: returning false, " "inline_depth: %d", diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanStepInstruction.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanStepInstruction.cpp index e34e41e8bce..42bee79c42b 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanStepInstruction.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanStepInstruction.cpp @@ -9,9 +9,9 @@ #include "lldb/Target/ThreadPlanStepInstruction.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" -#include "lldb/Target/RegisterContext.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Stream.h" @@ -96,7 +96,7 @@ bool ThreadPlanStepInstruction::DoPlanExplainsStop(Event *event_ptr) { } bool ThreadPlanStepInstruction::IsPlanStale() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); Thread &thread = GetThread(); StackID cur_frame_id = thread.GetStackFrameAtIndex(0)->GetStackID(); if (cur_frame_id == m_stack_id) { @@ -128,7 +128,7 @@ bool ThreadPlanStepInstruction::IsPlanStale() { bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) { Thread &thread = GetThread(); if (m_step_over) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); StackFrameSP cur_frame_sp = thread.GetStackFrameAtIndex(0); if (!cur_frame_sp) { LLDB_LOGF( @@ -244,7 +244,7 @@ bool ThreadPlanStepInstruction::WillStop() { return true; } bool ThreadPlanStepInstruction::MischiefManaged() { if (IsPlanComplete()) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); LLDB_LOGF(log, "Completed single instruction step plan."); ThreadPlan::MischiefManaged(); return true; diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanStepOut.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanStepOut.cpp index 86ccac2ec49..7bf1d2a8b57 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanStepOut.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanStepOut.cpp @@ -21,6 +21,7 @@ #include "lldb/Target/Target.h" #include "lldb/Target/ThreadPlanStepOverRange.h" #include "lldb/Target/ThreadPlanStepThrough.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include <memory> @@ -43,7 +44,7 @@ ThreadPlanStepOut::ThreadPlanStepOut( m_return_addr(LLDB_INVALID_ADDRESS), m_stop_others(stop_others), m_immediate_step_from_function(nullptr), m_calculate_return_value(gather_return_value) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); SetFlagsToDefault(); SetupAvoidNoDebug(step_out_avoids_code_without_debug_info); @@ -423,7 +424,7 @@ bool ThreadPlanStepOut::MischiefManaged() { // reason and we're now stopping for some other reason altogether, then // we're done with this step out operation. - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (log) LLDB_LOGF(log, "Completed step out plan."); if (m_return_bp_id != LLDB_INVALID_BREAK_ID) { @@ -447,7 +448,7 @@ bool ThreadPlanStepOut::QueueInlinedStepPlan(bool queue_now) { if (!immediate_return_from_sp) return false; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (log) { StreamString s; immediate_return_from_sp->Dump(&s, true, false); diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp index 965a7b3a996..f88a2b89593 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp @@ -10,6 +10,7 @@ #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Stream.h" @@ -51,7 +52,7 @@ bool ThreadPlanStepOverBreakpoint::DoPlanExplainsStop(Event *event_ptr) { if (stop_info_sp) { StopReason reason = stop_info_sp->GetStopReason(); - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); LLDB_LOG(log, "Step over breakpoint stopped for reason: {0}.", Thread::StopReasonAsString(reason)); @@ -124,9 +125,7 @@ bool ThreadPlanStepOverBreakpoint::WillStop() { return true; } -void ThreadPlanStepOverBreakpoint::WillPop() { - ReenableBreakpointSite(); -} +void ThreadPlanStepOverBreakpoint::DidPop() { ReenableBreakpointSite(); } bool ThreadPlanStepOverBreakpoint::MischiefManaged() { lldb::addr_t pc_addr = GetThread().GetRegisterContext()->GetPC(); @@ -136,7 +135,7 @@ bool ThreadPlanStepOverBreakpoint::MischiefManaged() { // didn't get a chance to run. return false; } else { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); LLDB_LOGF(log, "Completed step over breakpoint plan."); // Otherwise, re-enable the breakpoint we were stepping over, and we're // done. diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanStepOverRange.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanStepOverRange.cpp index 1bf3d5352c5..b1cb070e0a3 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanStepOverRange.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanStepOverRange.cpp @@ -17,6 +17,7 @@ #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlanStepOut.h" #include "lldb/Target/ThreadPlanStepThrough.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Stream.h" @@ -124,7 +125,7 @@ bool ThreadPlanStepOverRange::IsEquivalentContext( } bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); Thread &thread = GetThread(); if (log) { @@ -341,7 +342,7 @@ bool ThreadPlanStepOverRange::DoPlanExplainsStop(Event *event_ptr) { // breakpoint. Note, unlike the step in range plan, we don't mark ourselves // complete if we hit an unexplained breakpoint/crash. - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); StopInfoSP stop_info_sp = GetPrivateStopInfo(); bool return_value; @@ -375,7 +376,7 @@ bool ThreadPlanStepOverRange::DoWillResume(lldb::StateType resume_state, // step over that. bool in_inlined_stack = thread.DecrementCurrentInlinedDepth(); if (in_inlined_stack) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); LLDB_LOGF(log, "ThreadPlanStepInRange::DoWillResume: adjusting range to " "the frame at inlined depth %d.", diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanStepRange.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanStepRange.cpp index 896e647bbb5..0d5144d7a46 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanStepRange.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanStepRange.cpp @@ -19,6 +19,7 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlanRunToAddress.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Stream.h" @@ -65,7 +66,7 @@ bool ThreadPlanStepRange::ValidatePlan(Stream *error) { } Vote ThreadPlanStepRange::ShouldReportStop(Event *event_ptr) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); const Vote vote = IsPlanComplete() ? eVoteYes : eVoteNo; LLDB_LOGF(log, "ThreadPlanStepRange::ShouldReportStop() returning vote %i\n", @@ -98,7 +99,7 @@ void ThreadPlanStepRange::DumpRanges(Stream *s) { } bool ThreadPlanStepRange::InRange() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); bool ret_value = false; Thread &thread = GetThread(); lldb::addr_t pc_load_addr = thread.GetRegisterContext()->GetPC(); @@ -293,7 +294,7 @@ InstructionList *ThreadPlanStepRange::GetInstructionsForAddress( void ThreadPlanStepRange::ClearNextBranchBreakpoint() { if (m_next_branch_bp_sp) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); LLDB_LOGF(log, "Removing next branch breakpoint: %d.", m_next_branch_bp_sp->GetID()); GetTarget().RemoveBreakpointByID(m_next_branch_bp_sp->GetID()); @@ -307,7 +308,7 @@ bool ThreadPlanStepRange::SetNextBranchBreakpoint() { if (m_next_branch_bp_sp) return true; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); // Stepping through ranges using breakpoints doesn't work yet, but with this // off we fall back to instruction single stepping. if (!m_use_fast_step) @@ -386,7 +387,7 @@ bool ThreadPlanStepRange::SetNextBranchBreakpoint() { bool ThreadPlanStepRange::NextRangeBreakpointExplainsStop( lldb::StopInfoSP stop_info_sp) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (!m_next_branch_bp_sp) return false; @@ -453,7 +454,7 @@ bool ThreadPlanStepRange::MischiefManaged() { } if (done) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); LLDB_LOGF(log, "Completed step through range plan."); ClearNextBranchBreakpoint(); ThreadPlan::MischiefManaged(); @@ -464,7 +465,7 @@ bool ThreadPlanStepRange::MischiefManaged() { } bool ThreadPlanStepRange::IsPlanStale() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); FrameComparison frame_order = CompareCurrentFrameToStartFrame(); if (frame_order == eFrameCompareOlder) { diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanStepThrough.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanStepThrough.cpp index 6fc0312222f..e15635e4070 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanStepThrough.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanStepThrough.cpp @@ -13,6 +13,7 @@ #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Target.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Stream.h" @@ -60,7 +61,7 @@ ThreadPlanStepThrough::ThreadPlanStepThrough(Thread &thread, m_backstop_bkpt_id = return_bp->GetID(); return_bp->SetBreakpointKind("step-through-backstop"); } - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (log) { LLDB_LOGF(log, "Setting backstop breakpoint %d at address: 0x%" PRIx64, m_backstop_bkpt_id, m_backstop_addr); @@ -94,7 +95,7 @@ void ThreadPlanStepThrough::LookForPlanToStepThroughFromCurrentPC() { } } - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (log) { lldb::addr_t current_address = GetThread().GetRegisterContext()->GetPC(0); if (m_sub_plan_sp) { @@ -227,7 +228,7 @@ void ThreadPlanStepThrough::ClearBackstopBreakpoint() { } bool ThreadPlanStepThrough::MischiefManaged() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (!IsPlanComplete()) { return false; @@ -252,7 +253,7 @@ bool ThreadPlanStepThrough::HitOurBackstopBreakpoint() { StackID cur_frame_zero_id = thread.GetStackFrameAtIndex(0)->GetStackID(); if (cur_frame_zero_id == m_return_stack_id) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (log) log->PutCString("ThreadPlanStepThrough hit backstop breakpoint."); return true; diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanStepUntil.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanStepUntil.cpp index 650fa624cd5..f63e97d3c40 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanStepUntil.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanStepUntil.cpp @@ -14,6 +14,7 @@ #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" using namespace lldb; @@ -315,7 +316,7 @@ bool ThreadPlanStepUntil::MischiefManaged() { // here. bool done = false; if (IsPlanComplete()) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); LLDB_LOGF(log, "Completed step until plan."); Clear(); diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanTracer.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanTracer.cpp index 754ce655729..82927ef6487 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanTracer.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanTracer.cpp @@ -25,6 +25,7 @@ #include "lldb/Target/ThreadPlan.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/State.h" @@ -35,11 +36,11 @@ using namespace lldb_private; ThreadPlanTracer::ThreadPlanTracer(Thread &thread, lldb::StreamSP &stream_sp) : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()), - m_enabled(false), m_stream_sp(stream_sp) {} + m_enabled(false), m_stream_sp(stream_sp), m_thread(nullptr) {} ThreadPlanTracer::ThreadPlanTracer(Thread &thread) : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()), - m_enabled(false), m_stream_sp() {} + m_enabled(false), m_stream_sp(), m_thread(nullptr) {} Stream *ThreadPlanTracer::GetLogStream() { if (m_stream_sp) @@ -106,15 +107,13 @@ TypeFromUser ThreadPlanAssemblyTracer::GetIntPointerType() { auto type_system_or_err = target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC); if (auto err = type_system_or_err.takeError()) { - LLDB_LOG_ERROR( - lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_TYPES), - std::move(err), - "Unable to get integer pointer type from TypeSystem"); + LLDB_LOG_ERROR(GetLog(LLDBLog::Types), std::move(err), + "Unable to get integer pointer type from TypeSystem"); } else { - m_intptr_type = TypeFromUser( - type_system_or_err->GetBuiltinTypeForEncodingAndBitSize( - eEncodingUint, - target_sp->GetArchitecture().GetAddressByteSize() * 8)); + if (auto ts = *type_system_or_err) + m_intptr_type = TypeFromUser(ts->GetBuiltinTypeForEncodingAndBitSize( + eEncodingUint, + target_sp->GetArchitecture().GetAddressByteSize() * 8)); } } } @@ -171,13 +170,14 @@ void ThreadPlanAssemblyTracer::Log() { if (instruction_list.GetSize()) { const bool show_bytes = true; const bool show_address = true; + const bool show_control_flow_kind = true; Instruction *instruction = instruction_list.GetInstructionAtIndex(0).get(); const FormatEntity::Entry *disassemble_format = m_process.GetTarget().GetDebugger().GetDisassemblyFormat(); instruction->Dump(stream, max_opcode_byte_size, show_address, - show_bytes, nullptr, nullptr, nullptr, - disassemble_format, 0); + show_bytes, show_control_flow_kind, nullptr, nullptr, + nullptr, disassemble_format, 0); } } } diff --git a/gnu/llvm/lldb/source/Target/Trace.cpp b/gnu/llvm/lldb/source/Target/Trace.cpp index 827f3264c09..1ffd617a80f 100644 --- a/gnu/llvm/lldb/source/Target/Trace.cpp +++ b/gnu/llvm/lldb/source/Target/Trace.cpp @@ -17,40 +17,74 @@ #include "lldb/Target/Process.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Stream.h" +#include <optional> using namespace lldb; using namespace lldb_private; using namespace llvm; -// Helper structs used to extract the type of a trace session json without -// having to parse the entire object. +// Helper structs used to extract the type of a JSON trace bundle description +// object without having to parse the entire object. -struct JSONSimplePluginSettings { +struct JSONSimpleTraceBundleDescription { std::string type; }; -struct JSONSimpleTraceSession { - JSONSimplePluginSettings trace; -}; - namespace llvm { namespace json { -bool fromJSON(const Value &value, JSONSimplePluginSettings &plugin_settings, +bool fromJSON(const Value &value, JSONSimpleTraceBundleDescription &bundle, Path path) { json::ObjectMapper o(value, path); - return o && o.map("type", plugin_settings.type); -} - -bool fromJSON(const Value &value, JSONSimpleTraceSession &session, Path path) { - json::ObjectMapper o(value, path); - return o && o.map("trace", session.trace); + return o && o.map("type", bundle.type); } } // namespace json } // namespace llvm +/// Helper functions for fetching data in maps and returning Optionals or +/// pointers instead of iterators for simplicity. It's worth mentioning that the +/// Optionals version can't return the inner data by reference because of +/// limitations in move constructors. +/// \{ +template <typename K, typename V> +static std::optional<V> Lookup(DenseMap<K, V> &map, K k) { + auto it = map.find(k); + if (it == map.end()) + return std::nullopt; + return it->second; +} + +template <typename K, typename V> +static V *LookupAsPtr(DenseMap<K, V> &map, K k) { + auto it = map.find(k); + if (it == map.end()) + return nullptr; + return &it->second; +} + +/// Similar to the methods above but it looks for an item in a map of maps. +template <typename K1, typename K2, typename V> +static std::optional<V> Lookup(DenseMap<K1, DenseMap<K2, V>> &map, K1 k1, + K2 k2) { + auto it = map.find(k1); + if (it == map.end()) + return std::nullopt; + return Lookup(it->second, k2); +} + +/// Similar to the methods above but it looks for an item in a map of maps. +template <typename K1, typename K2, typename V> +static V *LookupAsPtr(DenseMap<K1, DenseMap<K2, V>> &map, K1 k1, K2 k2) { + auto it = map.find(k1); + if (it == map.end()) + return nullptr; + return LookupAsPtr(it->second, k2); +} +/// \} + static Error createInvalidPlugInError(StringRef plugin_name) { return createStringError( std::errc::invalid_argument, @@ -59,38 +93,59 @@ static Error createInvalidPlugInError(StringRef plugin_name) { } Expected<lldb::TraceSP> -Trace::FindPluginForPostMortemProcess(Debugger &debugger, - const json::Value &trace_session_file, - StringRef session_file_dir) { - JSONSimpleTraceSession json_session; - json::Path::Root root("traceSession"); - if (!json::fromJSON(trace_session_file, json_session, root)) +Trace::LoadPostMortemTraceFromFile(Debugger &debugger, + const FileSpec &trace_description_file) { + + auto buffer_or_error = + MemoryBuffer::getFile(trace_description_file.GetPath()); + if (!buffer_or_error) { + return createStringError(std::errc::invalid_argument, + "could not open input file: %s - %s.", + trace_description_file.GetPath().c_str(), + buffer_or_error.getError().message().c_str()); + } + + Expected<json::Value> session_file = + json::parse(buffer_or_error.get()->getBuffer().str()); + if (!session_file) { + return session_file.takeError(); + } + + return Trace::FindPluginForPostMortemProcess( + debugger, *session_file, + trace_description_file.GetDirectory().AsCString()); +} + +Expected<lldb::TraceSP> Trace::FindPluginForPostMortemProcess( + Debugger &debugger, const json::Value &trace_bundle_description, + StringRef bundle_dir) { + JSONSimpleTraceBundleDescription json_bundle; + json::Path::Root root("traceBundle"); + if (!json::fromJSON(trace_bundle_description, json_bundle, root)) return root.getError(); - ConstString plugin_name(json_session.trace.type); - if (auto create_callback = PluginManager::GetTraceCreateCallback(plugin_name)) - return create_callback(trace_session_file, session_file_dir, debugger); + if (auto create_callback = + PluginManager::GetTraceCreateCallback(json_bundle.type)) + return create_callback(trace_bundle_description, bundle_dir, debugger); - return createInvalidPlugInError(json_session.trace.type); + return createInvalidPlugInError(json_bundle.type); } -Expected<lldb::TraceSP> -Trace::FindPluginForLiveProcess(llvm::StringRef plugin_name, Process &process) { +Expected<lldb::TraceSP> Trace::FindPluginForLiveProcess(llvm::StringRef name, + Process &process) { if (!process.IsLiveDebugSession()) return createStringError(inconvertibleErrorCode(), "Can't trace non-live processes"); - ConstString name(plugin_name); if (auto create_callback = PluginManager::GetTraceCreateCallbackForLiveProcess(name)) return create_callback(process); - return createInvalidPlugInError(plugin_name); + return createInvalidPlugInError(name); } Expected<StringRef> Trace::FindPluginSchema(StringRef name) { - ConstString plugin_name(name); - StringRef schema = PluginManager::GetTraceSchema(plugin_name); + StringRef schema = PluginManager::GetTraceSchema(name); if (!schema.empty()) return schema; @@ -99,123 +154,377 @@ Expected<StringRef> Trace::FindPluginSchema(StringRef name) { Error Trace::Start(const llvm::json::Value &request) { if (!m_live_process) - return createStringError(inconvertibleErrorCode(), - "Tracing requires a live process."); + return createStringError( + inconvertibleErrorCode(), + "Attempted to start tracing without a live process."); return m_live_process->TraceStart(request); } Error Trace::Stop() { if (!m_live_process) - return createStringError(inconvertibleErrorCode(), - "Tracing requires a live process."); - return m_live_process->TraceStop( - TraceStopRequest(GetPluginName().AsCString())); + return createStringError( + inconvertibleErrorCode(), + "Attempted to stop tracing without a live process."); + return m_live_process->TraceStop(TraceStopRequest(GetPluginName())); } Error Trace::Stop(llvm::ArrayRef<lldb::tid_t> tids) { if (!m_live_process) - return createStringError(inconvertibleErrorCode(), - "Tracing requires a live process."); - return m_live_process->TraceStop( - TraceStopRequest(GetPluginName().AsCString(), tids)); + return createStringError( + inconvertibleErrorCode(), + "Attempted to stop tracing without a live process."); + return m_live_process->TraceStop(TraceStopRequest(GetPluginName(), tids)); } Expected<std::string> Trace::GetLiveProcessState() { if (!m_live_process) - return createStringError(inconvertibleErrorCode(), - "Tracing requires a live process."); - return m_live_process->TraceGetState(GetPluginName().AsCString()); + return createStringError( + inconvertibleErrorCode(), + "Attempted to fetch live trace information without a live process."); + return m_live_process->TraceGetState(GetPluginName()); } -Optional<size_t> Trace::GetLiveThreadBinaryDataSize(lldb::tid_t tid, - llvm::StringRef kind) { - auto it = m_live_thread_data.find(tid); - if (it == m_live_thread_data.end()) - return None; - std::unordered_map<std::string, size_t> &single_thread_data = it->second; - auto single_thread_data_it = single_thread_data.find(kind.str()); - if (single_thread_data_it == single_thread_data.end()) - return None; - return single_thread_data_it->second; +std::optional<uint64_t> +Trace::GetLiveThreadBinaryDataSize(lldb::tid_t tid, llvm::StringRef kind) { + Storage &storage = GetUpdatedStorage(); + return Lookup(storage.live_thread_data, tid, ConstString(kind)); } -Optional<size_t> Trace::GetLiveProcessBinaryDataSize(llvm::StringRef kind) { - auto data_it = m_live_process_data.find(kind.str()); - if (data_it == m_live_process_data.end()) - return None; - return data_it->second; +std::optional<uint64_t> Trace::GetLiveCpuBinaryDataSize(lldb::cpu_id_t cpu_id, + llvm::StringRef kind) { + Storage &storage = GetUpdatedStorage(); + return Lookup(storage.live_cpu_data_sizes, cpu_id, ConstString(kind)); } -Expected<ArrayRef<uint8_t>> -Trace::GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind) { +std::optional<uint64_t> +Trace::GetLiveProcessBinaryDataSize(llvm::StringRef kind) { + Storage &storage = GetUpdatedStorage(); + return Lookup(storage.live_process_data, ConstString(kind)); +} + +Expected<std::vector<uint8_t>> +Trace::GetLiveTraceBinaryData(const TraceGetBinaryDataRequest &request, + uint64_t expected_size) { if (!m_live_process) - return createStringError(inconvertibleErrorCode(), - "Tracing requires a live process."); - llvm::Optional<size_t> size = GetLiveThreadBinaryDataSize(tid, kind); + return createStringError( + inconvertibleErrorCode(), + formatv("Attempted to fetch live trace data without a live process. " + "Data kind = {0}, tid = {1}, cpu id = {2}.", + request.kind, request.tid, request.cpu_id)); + + Expected<std::vector<uint8_t>> data = + m_live_process->TraceGetBinaryData(request); + + if (!data) + return data.takeError(); + + if (data->size() != expected_size) + return createStringError( + inconvertibleErrorCode(), + formatv("Got incomplete live trace data. Data kind = {0}, expected " + "size = {1}, actual size = {2}, tid = {3}, cpu id = {4}", + request.kind, expected_size, data->size(), request.tid, + request.cpu_id)); + + return data; +} + +Expected<std::vector<uint8_t>> +Trace::GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind) { + std::optional<uint64_t> size = GetLiveThreadBinaryDataSize(tid, kind); if (!size) return createStringError( inconvertibleErrorCode(), "Tracing data \"%s\" is not available for thread %" PRIu64 ".", kind.data(), tid); - TraceGetBinaryDataRequest request{GetPluginName().AsCString(), kind.str(), - static_cast<int64_t>(tid), 0, - static_cast<int64_t>(*size)}; + TraceGetBinaryDataRequest request{GetPluginName().str(), kind.str(), tid, + /*cpu_id=*/std::nullopt}; + return GetLiveTraceBinaryData(request, *size); +} + +Expected<std::vector<uint8_t>> +Trace::GetLiveCpuBinaryData(lldb::cpu_id_t cpu_id, llvm::StringRef kind) { + if (!m_live_process) + return createStringError( + inconvertibleErrorCode(), + "Attempted to fetch live cpu data without a live process."); + std::optional<uint64_t> size = GetLiveCpuBinaryDataSize(cpu_id, kind); + if (!size) + return createStringError( + inconvertibleErrorCode(), + "Tracing data \"%s\" is not available for cpu_id %" PRIu64 ".", + kind.data(), cpu_id); + + TraceGetBinaryDataRequest request{GetPluginName().str(), kind.str(), + /*tid=*/std::nullopt, cpu_id}; return m_live_process->TraceGetBinaryData(request); } -Expected<ArrayRef<uint8_t>> +Expected<std::vector<uint8_t>> Trace::GetLiveProcessBinaryData(llvm::StringRef kind) { - if (!m_live_process) - return createStringError(inconvertibleErrorCode(), - "Tracing requires a live process."); - llvm::Optional<size_t> size = GetLiveProcessBinaryDataSize(kind); + std::optional<uint64_t> size = GetLiveProcessBinaryDataSize(kind); if (!size) return createStringError( inconvertibleErrorCode(), "Tracing data \"%s\" is not available for the process.", kind.data()); - TraceGetBinaryDataRequest request{GetPluginName().AsCString(), kind.str(), - None, 0, static_cast<int64_t>(*size)}; - return m_live_process->TraceGetBinaryData(request); + TraceGetBinaryDataRequest request{GetPluginName().str(), kind.str(), + /*tid=*/std::nullopt, + /*cpu_id*/ std::nullopt}; + return GetLiveTraceBinaryData(request, *size); } -void Trace::RefreshLiveProcessState() { +Trace::Storage &Trace::GetUpdatedStorage() { + RefreshLiveProcessState(); + return m_storage; +} + +const char *Trace::RefreshLiveProcessState() { if (!m_live_process) - return; + return nullptr; uint32_t new_stop_id = m_live_process->GetStopID(); if (new_stop_id == m_stop_id) - return; + return nullptr; - m_stop_id = new_stop_id; - m_live_thread_data.clear(); + Log *log = GetLog(LLDBLog::Target); + LLDB_LOG(log, "Trace::RefreshLiveProcessState invoked"); - Expected<std::string> json_string = GetLiveProcessState(); - if (!json_string) { - DoRefreshLiveProcessState(json_string.takeError()); - return; - } - Expected<TraceGetStateResponse> live_process_state = - json::parse<TraceGetStateResponse>(*json_string, "TraceGetStateResponse"); - if (!live_process_state) { - DoRefreshLiveProcessState(live_process_state.takeError()); - return; + m_stop_id = new_stop_id; + m_storage = Trace::Storage(); + + auto do_refresh = [&]() -> Error { + Expected<std::string> json_string = GetLiveProcessState(); + if (!json_string) + return json_string.takeError(); + + Expected<TraceGetStateResponse> live_process_state = + json::parse<TraceGetStateResponse>(*json_string, + "TraceGetStateResponse"); + if (!live_process_state) + return live_process_state.takeError(); + + if (live_process_state->warnings) { + for (std::string &warning : *live_process_state->warnings) + LLDB_LOG(log, "== Warning when fetching the trace state: {0}", warning); + } + + for (const TraceThreadState &thread_state : + live_process_state->traced_threads) { + for (const TraceBinaryData &item : thread_state.binary_data) + m_storage.live_thread_data[thread_state.tid].insert( + {ConstString(item.kind), item.size}); + } + + LLDB_LOG(log, "== Found {0} threads being traced", + live_process_state->traced_threads.size()); + + if (live_process_state->cpus) { + m_storage.cpus.emplace(); + for (const TraceCpuState &cpu_state : *live_process_state->cpus) { + m_storage.cpus->push_back(cpu_state.id); + for (const TraceBinaryData &item : cpu_state.binary_data) + m_storage.live_cpu_data_sizes[cpu_state.id].insert( + {ConstString(item.kind), item.size}); + } + LLDB_LOG(log, "== Found {0} cpu cpus being traced", + live_process_state->cpus->size()); + } + + for (const TraceBinaryData &item : live_process_state->process_binary_data) + m_storage.live_process_data.insert({ConstString(item.kind), item.size}); + + return DoRefreshLiveProcessState(std::move(*live_process_state), + *json_string); + }; + + if (Error err = do_refresh()) { + m_storage.live_refresh_error = toString(std::move(err)); + return m_storage.live_refresh_error->c_str(); } - for (const TraceThreadState &thread_state : - live_process_state->tracedThreads) { - for (const TraceBinaryData &item : thread_state.binaryData) - m_live_thread_data[thread_state.tid][item.kind] = item.size; - } + return nullptr; +} + +Trace::Trace(ArrayRef<ProcessSP> postmortem_processes, + std::optional<std::vector<lldb::cpu_id_t>> postmortem_cpus) { + for (ProcessSP process_sp : postmortem_processes) + m_storage.postmortem_processes.push_back(process_sp.get()); + m_storage.cpus = postmortem_cpus; +} - for (const TraceBinaryData &item : live_process_state->processBinaryData) - m_live_process_data[item.kind] = item.size; +Process *Trace::GetLiveProcess() { return m_live_process; } - DoRefreshLiveProcessState(std::move(live_process_state)); +ArrayRef<Process *> Trace::GetPostMortemProcesses() { + return m_storage.postmortem_processes; +} + +std::vector<Process *> Trace::GetAllProcesses() { + if (Process *proc = GetLiveProcess()) + return {proc}; + return GetPostMortemProcesses(); } uint32_t Trace::GetStopID() { RefreshLiveProcessState(); return m_stop_id; } + +llvm::Expected<FileSpec> +Trace::GetPostMortemThreadDataFile(lldb::tid_t tid, llvm::StringRef kind) { + Storage &storage = GetUpdatedStorage(); + if (std::optional<FileSpec> file = + Lookup(storage.postmortem_thread_data, tid, ConstString(kind))) + return *file; + else + return createStringError( + inconvertibleErrorCode(), + formatv("The thread with tid={0} doesn't have the tracing data {1}", + tid, kind)); +} + +llvm::Expected<FileSpec> Trace::GetPostMortemCpuDataFile(lldb::cpu_id_t cpu_id, + llvm::StringRef kind) { + Storage &storage = GetUpdatedStorage(); + if (std::optional<FileSpec> file = + Lookup(storage.postmortem_cpu_data, cpu_id, ConstString(kind))) + return *file; + else + return createStringError( + inconvertibleErrorCode(), + formatv("The cpu with id={0} doesn't have the tracing data {1}", cpu_id, + kind)); +} + +void Trace::SetPostMortemThreadDataFile(lldb::tid_t tid, llvm::StringRef kind, + FileSpec file_spec) { + Storage &storage = GetUpdatedStorage(); + storage.postmortem_thread_data[tid].insert({ConstString(kind), file_spec}); +} + +void Trace::SetPostMortemCpuDataFile(lldb::cpu_id_t cpu_id, + llvm::StringRef kind, FileSpec file_spec) { + Storage &storage = GetUpdatedStorage(); + storage.postmortem_cpu_data[cpu_id].insert({ConstString(kind), file_spec}); +} + +llvm::Error +Trace::OnLiveThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind, + OnBinaryDataReadCallback callback) { + Expected<std::vector<uint8_t>> data = GetLiveThreadBinaryData(tid, kind); + if (!data) + return data.takeError(); + return callback(*data); +} + +llvm::Error Trace::OnLiveCpuBinaryDataRead(lldb::cpu_id_t cpu_id, + llvm::StringRef kind, + OnBinaryDataReadCallback callback) { + Storage &storage = GetUpdatedStorage(); + if (std::vector<uint8_t> *cpu_data = + LookupAsPtr(storage.live_cpu_data, cpu_id, ConstString(kind))) + return callback(*cpu_data); + + Expected<std::vector<uint8_t>> data = GetLiveCpuBinaryData(cpu_id, kind); + if (!data) + return data.takeError(); + auto it = storage.live_cpu_data[cpu_id].insert( + {ConstString(kind), std::move(*data)}); + return callback(it.first->second); +} + +llvm::Error Trace::OnDataFileRead(FileSpec file, + OnBinaryDataReadCallback callback) { + ErrorOr<std::unique_ptr<MemoryBuffer>> trace_or_error = + MemoryBuffer::getFile(file.GetPath()); + if (std::error_code err = trace_or_error.getError()) + return createStringError( + inconvertibleErrorCode(), "Failed fetching trace-related file %s. %s", + file.GetPath().c_str(), toString(errorCodeToError(err)).c_str()); + + MemoryBuffer &data = **trace_or_error; + ArrayRef<uint8_t> array_ref( + reinterpret_cast<const uint8_t *>(data.getBufferStart()), + data.getBufferSize()); + return callback(array_ref); +} + +llvm::Error +Trace::OnPostMortemThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind, + OnBinaryDataReadCallback callback) { + if (Expected<FileSpec> file = GetPostMortemThreadDataFile(tid, kind)) + return OnDataFileRead(*file, callback); + else + return file.takeError(); +} + +llvm::Error +Trace::OnPostMortemCpuBinaryDataRead(lldb::cpu_id_t cpu_id, + llvm::StringRef kind, + OnBinaryDataReadCallback callback) { + if (Expected<FileSpec> file = GetPostMortemCpuDataFile(cpu_id, kind)) + return OnDataFileRead(*file, callback); + else + return file.takeError(); +} + +llvm::Error Trace::OnThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind, + OnBinaryDataReadCallback callback) { + if (m_live_process) + return OnLiveThreadBinaryDataRead(tid, kind, callback); + else + return OnPostMortemThreadBinaryDataRead(tid, kind, callback); +} + +llvm::Error +Trace::OnAllCpusBinaryDataRead(llvm::StringRef kind, + OnCpusBinaryDataReadCallback callback) { + DenseMap<cpu_id_t, ArrayRef<uint8_t>> buffers; + Storage &storage = GetUpdatedStorage(); + if (!storage.cpus) + return Error::success(); + + std::function<Error(std::vector<cpu_id_t>::iterator)> process_cpu = + [&](std::vector<cpu_id_t>::iterator cpu_id) -> Error { + if (cpu_id == storage.cpus->end()) + return callback(buffers); + + return OnCpuBinaryDataRead(*cpu_id, kind, + [&](ArrayRef<uint8_t> data) -> Error { + buffers.try_emplace(*cpu_id, data); + auto next_id = cpu_id; + next_id++; + return process_cpu(next_id); + }); + }; + return process_cpu(storage.cpus->begin()); +} + +llvm::Error Trace::OnCpuBinaryDataRead(lldb::cpu_id_t cpu_id, + llvm::StringRef kind, + OnBinaryDataReadCallback callback) { + if (m_live_process) + return OnLiveCpuBinaryDataRead(cpu_id, kind, callback); + else + return OnPostMortemCpuBinaryDataRead(cpu_id, kind, callback); +} + +ArrayRef<lldb::cpu_id_t> Trace::GetTracedCpus() { + Storage &storage = GetUpdatedStorage(); + if (storage.cpus) + return *storage.cpus; + return {}; +} + +std::vector<Process *> Trace::GetTracedProcesses() { + std::vector<Process *> processes; + Storage &storage = GetUpdatedStorage(); + + for (Process *proc : storage.postmortem_processes) + processes.push_back(proc); + + if (m_live_process) + processes.push_back(m_live_process); + return processes; +} diff --git a/gnu/llvm/lldb/source/Target/TraceCursor.cpp b/gnu/llvm/lldb/source/Target/TraceCursor.cpp index d0f69642cb9..b85cc750a8a 100644 --- a/gnu/llvm/lldb/source/Target/TraceCursor.cpp +++ b/gnu/llvm/lldb/source/Target/TraceCursor.cpp @@ -9,6 +9,7 @@ #include "lldb/Target/TraceCursor.h" #include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Trace.h" using namespace lldb; using namespace lldb_private; @@ -21,15 +22,38 @@ ExecutionContextRef &TraceCursor::GetExecutionContextRef() { return m_exe_ctx_ref; } -void TraceCursor::SetGranularity( - lldb::TraceInstructionControlFlowType granularity) { - m_granularity = granularity; +void TraceCursor::SetForwards(bool forwards) { m_forwards = forwards; } + +bool TraceCursor::IsForwards() const { return m_forwards; } + +bool TraceCursor::IsError() const { + return GetItemKind() == lldb::eTraceItemKindError; } -void TraceCursor::SetIgnoreErrors(bool ignore_errors) { - m_ignore_errors = ignore_errors; +bool TraceCursor::IsEvent() const { + return GetItemKind() == lldb::eTraceItemKindEvent; } -void TraceCursor::SetForwards(bool forwards) { m_forwards = forwards; } +bool TraceCursor::IsInstruction() const { + return GetItemKind() == lldb::eTraceItemKindInstruction; +} -bool TraceCursor::IsForwards() const { return m_forwards; } +const char *TraceCursor::GetEventTypeAsString() const { + return EventKindToString(GetEventType()); +} + +const char *TraceCursor::EventKindToString(lldb::TraceEvent event_kind) { + switch (event_kind) { + case lldb::eTraceEventDisabledHW: + return "hardware disabled tracing"; + case lldb::eTraceEventDisabledSW: + return "software disabled tracing"; + case lldb::eTraceEventCPUChanged: + return "CPU core changed"; + case lldb::eTraceEventHWClockTick: + return "HW clock tick"; + case lldb::eTraceEventSyncPoint: + return "trace synchronization point"; + } + llvm_unreachable("Fully covered switch above"); +} diff --git a/gnu/llvm/lldb/source/Target/TraceDumper.cpp b/gnu/llvm/lldb/source/Target/TraceDumper.cpp new file mode 100644 index 00000000000..d059d443805 --- /dev/null +++ b/gnu/llvm/lldb/source/Target/TraceDumper.cpp @@ -0,0 +1,913 @@ +//===-- TraceDumper.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/TraceDumper.h" +#include "lldb/Core/Module.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" +#include <optional> + +using namespace lldb; +using namespace lldb_private; +using namespace llvm; + +/// \return +/// The given string or \b std::nullopt if it's empty. +static std::optional<const char *> ToOptionalString(const char *s) { + if (!s) + return std::nullopt; + return s; +} + +static const char *GetModuleName(const SymbolContext &sc) { + if (!sc.module_sp) + return nullptr; + return sc.module_sp->GetFileSpec().GetFilename().AsCString(); +} + +/// \return +/// The module name (basename if the module is a file, or the actual name if +/// it's a virtual module), or \b nullptr if no name nor module was found. +static const char *GetModuleName(const TraceDumper::TraceItem &item) { + if (!item.symbol_info) + return nullptr; + return GetModuleName(item.symbol_info->sc); +} + +// This custom LineEntry validator is neded because some line_entries have +// 0 as line, which is meaningless. Notice that LineEntry::IsValid only +// checks that line is not LLDB_INVALID_LINE_NUMBER, i.e. UINT32_MAX. +static bool IsLineEntryValid(const LineEntry &line_entry) { + return line_entry.IsValid() && line_entry.line > 0; +} + +/// \return +/// \b true if the provided line entries match line, column and source file. +/// This function assumes that the line entries are valid. +static bool FileLineAndColumnMatches(const LineEntry &a, const LineEntry &b) { + if (a.line != b.line) + return false; + if (a.column != b.column) + return false; + return a.file == b.file; +} + +/// Compare the symbol contexts of the provided \a SymbolInfo +/// objects. +/// +/// \return +/// \a true if both instructions belong to the same scope level analized +/// in the following order: +/// - module +/// - symbol +/// - function +/// - inlined function +/// - source line info +static bool +IsSameInstructionSymbolContext(const TraceDumper::SymbolInfo &prev_insn, + const TraceDumper::SymbolInfo &insn, + bool check_source_line_info = true) { + // module checks + if (insn.sc.module_sp != prev_insn.sc.module_sp) + return false; + + // symbol checks + if (insn.sc.symbol != prev_insn.sc.symbol) + return false; + + // function checks + if (!insn.sc.function && !prev_insn.sc.function) + return true; // This means two dangling instruction in the same module. We + // can assume they are part of the same unnamed symbol + else if (insn.sc.function != prev_insn.sc.function) + return false; + + Block *inline_block_a = + insn.sc.block ? insn.sc.block->GetContainingInlinedBlock() : nullptr; + Block *inline_block_b = prev_insn.sc.block + ? prev_insn.sc.block->GetContainingInlinedBlock() + : nullptr; + if (inline_block_a != inline_block_b) + return false; + + // line entry checks + if (!check_source_line_info) + return true; + + const bool curr_line_valid = IsLineEntryValid(insn.sc.line_entry); + const bool prev_line_valid = IsLineEntryValid(prev_insn.sc.line_entry); + if (curr_line_valid && prev_line_valid) + return FileLineAndColumnMatches(insn.sc.line_entry, + prev_insn.sc.line_entry); + return curr_line_valid == prev_line_valid; +} + +class OutputWriterCLI : public TraceDumper::OutputWriter { +public: + OutputWriterCLI(Stream &s, const TraceDumperOptions &options, Thread &thread) + : m_s(s), m_options(options) { + m_s.Format("thread #{0}: tid = {1}\n", thread.GetIndexID(), thread.GetID()); + }; + + void NoMoreData() override { m_s << " no more data\n"; } + + void FunctionCallForest( + const std::vector<TraceDumper::FunctionCallUP> &forest) override { + for (size_t i = 0; i < forest.size(); i++) { + m_s.Format("\n[call tree #{0}]\n", i); + DumpFunctionCallTree(*forest[i]); + } + } + + void TraceItem(const TraceDumper::TraceItem &item) override { + if (item.symbol_info) { + if (!item.prev_symbol_info || + !IsSameInstructionSymbolContext(*item.prev_symbol_info, + *item.symbol_info)) { + m_s << " "; + const char *module_name = GetModuleName(item); + if (!module_name) + m_s << "(none)"; + else if (!item.symbol_info->sc.function && !item.symbol_info->sc.symbol) + m_s.Format("{0}`(none)", module_name); + else + item.symbol_info->sc.DumpStopContext( + &m_s, item.symbol_info->exe_ctx.GetTargetPtr(), + item.symbol_info->address, + /*show_fullpaths=*/false, + /*show_module=*/true, /*show_inlined_frames=*/false, + /*show_function_arguments=*/true, + /*show_function_name=*/true); + m_s << "\n"; + } + } + + if (item.error && !m_was_prev_instruction_an_error) + m_s << " ...missing instructions\n"; + + m_s.Format(" {0}: ", item.id); + + if (m_options.show_timestamps) { + m_s.Format("[{0}] ", item.timestamp + ? formatv("{0:3} ns", *item.timestamp).str() + : "unavailable"); + } + + if (item.event) { + m_s << "(event) " << TraceCursor::EventKindToString(*item.event); + switch (*item.event) { + case eTraceEventCPUChanged: + m_s.Format(" [new CPU={0}]", + item.cpu_id ? std::to_string(*item.cpu_id) : "unavailable"); + break; + case eTraceEventHWClockTick: + m_s.Format(" [{0}]", item.hw_clock ? std::to_string(*item.hw_clock) + : "unavailable"); + break; + case eTraceEventDisabledHW: + case eTraceEventDisabledSW: + break; + case eTraceEventSyncPoint: + m_s.Format(" [{0}]", item.sync_point_metadata); + break; + } + } else if (item.error) { + m_s << "(error) " << *item.error; + } else { + m_s.Format("{0:x+16}", item.load_address); + if (item.symbol_info && item.symbol_info->instruction) { + m_s << " "; + item.symbol_info->instruction->Dump( + &m_s, /*max_opcode_byte_size=*/0, + /*show_address=*/false, + /*show_bytes=*/false, m_options.show_control_flow_kind, + &item.symbol_info->exe_ctx, &item.symbol_info->sc, + /*prev_sym_ctx=*/nullptr, + /*disassembly_addr_format=*/nullptr, + /*max_address_text_size=*/0); + } + } + + m_was_prev_instruction_an_error = (bool)item.error; + m_s << "\n"; + } + +private: + void + DumpSegmentContext(const TraceDumper::FunctionCall::TracedSegment &segment) { + if (segment.GetOwningCall().IsError()) { + m_s << "<tracing errors>"; + return; + } + + const SymbolContext &first_sc = segment.GetFirstInstructionSymbolInfo().sc; + first_sc.DumpStopContext( + &m_s, segment.GetFirstInstructionSymbolInfo().exe_ctx.GetTargetPtr(), + segment.GetFirstInstructionSymbolInfo().address, + /*show_fullpaths=*/false, + /*show_module=*/true, /*show_inlined_frames=*/false, + /*show_function_arguments=*/true, + /*show_function_name=*/true); + m_s << " to "; + const SymbolContext &last_sc = segment.GetLastInstructionSymbolInfo().sc; + if (IsLineEntryValid(first_sc.line_entry) && + IsLineEntryValid(last_sc.line_entry)) { + m_s.Format("{0}:{1}", last_sc.line_entry.line, last_sc.line_entry.column); + } else { + last_sc.DumpStopContext( + &m_s, segment.GetFirstInstructionSymbolInfo().exe_ctx.GetTargetPtr(), + segment.GetLastInstructionSymbolInfo().address, + /*show_fullpaths=*/false, + /*show_module=*/false, /*show_inlined_frames=*/false, + /*show_function_arguments=*/false, + /*show_function_name=*/false); + } + } + + void DumpUntracedContext(const TraceDumper::FunctionCall &function_call) { + if (function_call.IsError()) { + m_s << "tracing error"; + } + const SymbolContext &sc = function_call.GetSymbolInfo().sc; + + const char *module_name = GetModuleName(sc); + if (!module_name) + m_s << "(none)"; + else if (!sc.function && !sc.symbol) + m_s << module_name << "`(none)"; + else + m_s << module_name << "`" << sc.GetFunctionName().AsCString(); + } + + void DumpFunctionCallTree(const TraceDumper::FunctionCall &function_call) { + if (function_call.GetUntracedPrefixSegment()) { + m_s.Indent(); + DumpUntracedContext(function_call); + m_s << "\n"; + + m_s.IndentMore(); + DumpFunctionCallTree(function_call.GetUntracedPrefixSegment()->GetNestedCall()); + m_s.IndentLess(); + } + + for (const TraceDumper::FunctionCall::TracedSegment &segment : + function_call.GetTracedSegments()) { + m_s.Indent(); + DumpSegmentContext(segment); + m_s.Format(" [{0}, {1}]\n", segment.GetFirstInstructionID(), + segment.GetLastInstructionID()); + + segment.IfNestedCall([&](const TraceDumper::FunctionCall &nested_call) { + m_s.IndentMore(); + DumpFunctionCallTree(nested_call); + m_s.IndentLess(); + }); + } + } + + Stream &m_s; + TraceDumperOptions m_options; + bool m_was_prev_instruction_an_error = false; +}; + +class OutputWriterJSON : public TraceDumper::OutputWriter { + /* schema: + error_message: string + | { + "event": string, + "id": decimal, + "tsc"?: string decimal, + "cpuId"? decimal, + } | { + "error": string, + "id": decimal, + "tsc"?: string decimal, + | { + "loadAddress": string decimal, + "id": decimal, + "hwClock"?: string decimal, + "syncPointMetadata"?: string, + "timestamp_ns"?: string decimal, + "module"?: string, + "symbol"?: string, + "line"?: decimal, + "column"?: decimal, + "source"?: string, + "mnemonic"?: string, + "controlFlowKind"?: string, + } + */ +public: + OutputWriterJSON(Stream &s, const TraceDumperOptions &options) + : m_s(s), m_options(options), + m_j(m_s.AsRawOstream(), + /*IndentSize=*/options.pretty_print_json ? 2 : 0) { + m_j.arrayBegin(); + }; + + ~OutputWriterJSON() { m_j.arrayEnd(); } + + void FunctionCallForest( + const std::vector<TraceDumper::FunctionCallUP> &forest) override { + for (size_t i = 0; i < forest.size(); i++) { + m_j.object([&] { DumpFunctionCallTree(*forest[i]); }); + } + } + + void DumpFunctionCallTree(const TraceDumper::FunctionCall &function_call) { + if (function_call.GetUntracedPrefixSegment()) { + m_j.attributeObject("untracedPrefixSegment", [&] { + m_j.attributeObject("nestedCall", [&] { + DumpFunctionCallTree( + function_call.GetUntracedPrefixSegment()->GetNestedCall()); + }); + }); + } + + if (!function_call.GetTracedSegments().empty()) { + m_j.attributeArray("tracedSegments", [&] { + for (const TraceDumper::FunctionCall::TracedSegment &segment : + function_call.GetTracedSegments()) { + m_j.object([&] { + m_j.attribute("firstInstructionId", + std::to_string(segment.GetFirstInstructionID())); + m_j.attribute("lastInstructionId", + std::to_string(segment.GetLastInstructionID())); + segment.IfNestedCall( + [&](const TraceDumper::FunctionCall &nested_call) { + m_j.attributeObject( + "nestedCall", [&] { DumpFunctionCallTree(nested_call); }); + }); + }); + } + }); + } + } + + void DumpEvent(const TraceDumper::TraceItem &item) { + m_j.attribute("event", TraceCursor::EventKindToString(*item.event)); + switch (*item.event) { + case eTraceEventCPUChanged: + m_j.attribute("cpuId", item.cpu_id); + break; + case eTraceEventHWClockTick: + m_j.attribute("hwClock", item.hw_clock); + break; + case eTraceEventDisabledHW: + case eTraceEventDisabledSW: + break; + case eTraceEventSyncPoint: + m_j.attribute("syncPointMetadata", item.sync_point_metadata); + break; + } + } + + void DumpInstruction(const TraceDumper::TraceItem &item) { + m_j.attribute("loadAddress", formatv("{0:x}", item.load_address)); + if (item.symbol_info) { + m_j.attribute("module", ToOptionalString(GetModuleName(item))); + m_j.attribute( + "symbol", + ToOptionalString(item.symbol_info->sc.GetFunctionName().AsCString())); + + if (lldb::InstructionSP instruction = item.symbol_info->instruction) { + ExecutionContext exe_ctx = item.symbol_info->exe_ctx; + m_j.attribute("mnemonic", + ToOptionalString(instruction->GetMnemonic(&exe_ctx))); + if (m_options.show_control_flow_kind) { + lldb::InstructionControlFlowKind instruction_control_flow_kind = + instruction->GetControlFlowKind(&exe_ctx); + m_j.attribute("controlFlowKind", + ToOptionalString( + Instruction::GetNameForInstructionControlFlowKind( + instruction_control_flow_kind))); + } + } + + if (IsLineEntryValid(item.symbol_info->sc.line_entry)) { + m_j.attribute( + "source", + ToOptionalString( + item.symbol_info->sc.line_entry.file.GetPath().c_str())); + m_j.attribute("line", item.symbol_info->sc.line_entry.line); + m_j.attribute("column", item.symbol_info->sc.line_entry.column); + } + } + } + + void TraceItem(const TraceDumper::TraceItem &item) override { + m_j.object([&] { + m_j.attribute("id", item.id); + if (m_options.show_timestamps) + m_j.attribute("timestamp_ns", item.timestamp + ? std::optional<std::string>( + std::to_string(*item.timestamp)) + : std::nullopt); + + if (item.event) { + DumpEvent(item); + } else if (item.error) { + m_j.attribute("error", *item.error); + } else { + DumpInstruction(item); + } + }); + } + +private: + Stream &m_s; + TraceDumperOptions m_options; + json::OStream m_j; +}; + +static std::unique_ptr<TraceDumper::OutputWriter> +CreateWriter(Stream &s, const TraceDumperOptions &options, Thread &thread) { + if (options.json) + return std::unique_ptr<TraceDumper::OutputWriter>( + new OutputWriterJSON(s, options)); + else + return std::unique_ptr<TraceDumper::OutputWriter>( + new OutputWriterCLI(s, options, thread)); +} + +TraceDumper::TraceDumper(lldb::TraceCursorSP cursor_sp, Stream &s, + const TraceDumperOptions &options) + : m_cursor_sp(std::move(cursor_sp)), m_options(options), + m_writer_up(CreateWriter( + s, m_options, *m_cursor_sp->GetExecutionContextRef().GetThreadSP())) { + + if (m_options.id) + m_cursor_sp->GoToId(*m_options.id); + else if (m_options.forwards) + m_cursor_sp->Seek(0, lldb::eTraceCursorSeekTypeBeginning); + else + m_cursor_sp->Seek(0, lldb::eTraceCursorSeekTypeEnd); + + m_cursor_sp->SetForwards(m_options.forwards); + if (m_options.skip) { + m_cursor_sp->Seek((m_options.forwards ? 1 : -1) * *m_options.skip, + lldb::eTraceCursorSeekTypeCurrent); + } +} + +TraceDumper::TraceItem TraceDumper::CreatRawTraceItem() { + TraceItem item = {}; + item.id = m_cursor_sp->GetId(); + + if (m_options.show_timestamps) + item.timestamp = m_cursor_sp->GetWallClockTime(); + return item; +} + +/// Find the symbol context for the given address reusing the previous +/// instruction's symbol context when possible. +static SymbolContext +CalculateSymbolContext(const Address &address, + const SymbolContext &prev_symbol_context) { + AddressRange range; + if (prev_symbol_context.GetAddressRange(eSymbolContextEverything, 0, + /*inline_block_range*/ true, range) && + range.Contains(address)) + return prev_symbol_context; + + SymbolContext sc; + address.CalculateSymbolContext(&sc, eSymbolContextEverything); + return sc; +} + +/// Find the disassembler for the given address reusing the previous +/// instruction's disassembler when possible. +static std::tuple<DisassemblerSP, InstructionSP> +CalculateDisass(const TraceDumper::SymbolInfo &symbol_info, + const TraceDumper::SymbolInfo &prev_symbol_info, + const ExecutionContext &exe_ctx) { + if (prev_symbol_info.disassembler) { + if (InstructionSP instruction = + prev_symbol_info.disassembler->GetInstructionList() + .GetInstructionAtAddress(symbol_info.address)) + return std::make_tuple(prev_symbol_info.disassembler, instruction); + } + + if (symbol_info.sc.function) { + if (DisassemblerSP disassembler = + symbol_info.sc.function->GetInstructions(exe_ctx, nullptr)) { + if (InstructionSP instruction = + disassembler->GetInstructionList().GetInstructionAtAddress( + symbol_info.address)) + return std::make_tuple(disassembler, instruction); + } + } + // We fallback to a single instruction disassembler + Target &target = exe_ctx.GetTargetRef(); + const ArchSpec arch = target.GetArchitecture(); + AddressRange range(symbol_info.address, arch.GetMaximumOpcodeByteSize()); + DisassemblerSP disassembler = + Disassembler::DisassembleRange(arch, /*plugin_name*/ nullptr, + /*flavor*/ nullptr, target, range); + return std::make_tuple( + disassembler, + disassembler ? disassembler->GetInstructionList().GetInstructionAtAddress( + symbol_info.address) + : InstructionSP()); +} + +static TraceDumper::SymbolInfo +CalculateSymbolInfo(const ExecutionContext &exe_ctx, lldb::addr_t load_address, + const TraceDumper::SymbolInfo &prev_symbol_info) { + TraceDumper::SymbolInfo symbol_info; + symbol_info.exe_ctx = exe_ctx; + symbol_info.address.SetLoadAddress(load_address, exe_ctx.GetTargetPtr()); + symbol_info.sc = + CalculateSymbolContext(symbol_info.address, prev_symbol_info.sc); + std::tie(symbol_info.disassembler, symbol_info.instruction) = + CalculateDisass(symbol_info, prev_symbol_info, exe_ctx); + return symbol_info; +} + +std::optional<lldb::user_id_t> TraceDumper::DumpInstructions(size_t count) { + ThreadSP thread_sp = m_cursor_sp->GetExecutionContextRef().GetThreadSP(); + + SymbolInfo prev_symbol_info; + std::optional<lldb::user_id_t> last_id; + + ExecutionContext exe_ctx; + thread_sp->GetProcess()->GetTarget().CalculateExecutionContext(exe_ctx); + + for (size_t insn_seen = 0; insn_seen < count && m_cursor_sp->HasValue(); + m_cursor_sp->Next()) { + + last_id = m_cursor_sp->GetId(); + TraceItem item = CreatRawTraceItem(); + + if (m_cursor_sp->IsEvent() && m_options.show_events) { + item.event = m_cursor_sp->GetEventType(); + switch (*item.event) { + case eTraceEventCPUChanged: + item.cpu_id = m_cursor_sp->GetCPU(); + break; + case eTraceEventHWClockTick: + item.hw_clock = m_cursor_sp->GetHWClock(); + break; + case eTraceEventDisabledHW: + case eTraceEventDisabledSW: + break; + case eTraceEventSyncPoint: + item.sync_point_metadata = m_cursor_sp->GetSyncPointMetadata(); + break; + } + m_writer_up->TraceItem(item); + } else if (m_cursor_sp->IsError()) { + item.error = m_cursor_sp->GetError(); + m_writer_up->TraceItem(item); + } else if (m_cursor_sp->IsInstruction() && !m_options.only_events) { + insn_seen++; + item.load_address = m_cursor_sp->GetLoadAddress(); + + if (!m_options.raw) { + SymbolInfo symbol_info = + CalculateSymbolInfo(exe_ctx, item.load_address, prev_symbol_info); + item.prev_symbol_info = prev_symbol_info; + item.symbol_info = symbol_info; + prev_symbol_info = symbol_info; + } + m_writer_up->TraceItem(item); + } + } + if (!m_cursor_sp->HasValue()) + m_writer_up->NoMoreData(); + return last_id; +} + +void TraceDumper::FunctionCall::TracedSegment::AppendInsn( + const TraceCursorSP &cursor_sp, + const TraceDumper::SymbolInfo &symbol_info) { + m_last_insn_id = cursor_sp->GetId(); + m_last_symbol_info = symbol_info; +} + +lldb::user_id_t +TraceDumper::FunctionCall::TracedSegment::GetFirstInstructionID() const { + return m_first_insn_id; +} + +lldb::user_id_t +TraceDumper::FunctionCall::TracedSegment::GetLastInstructionID() const { + return m_last_insn_id; +} + +void TraceDumper::FunctionCall::TracedSegment::IfNestedCall( + std::function<void(const FunctionCall &function_call)> callback) const { + if (m_nested_call) + callback(*m_nested_call); +} + +const TraceDumper::FunctionCall & +TraceDumper::FunctionCall::TracedSegment::GetOwningCall() const { + return m_owning_call; +} + +TraceDumper::FunctionCall & +TraceDumper::FunctionCall::TracedSegment::CreateNestedCall( + const TraceCursorSP &cursor_sp, + const TraceDumper::SymbolInfo &symbol_info) { + m_nested_call = std::make_unique<FunctionCall>(cursor_sp, symbol_info); + m_nested_call->SetParentCall(m_owning_call); + return *m_nested_call; +} + +const TraceDumper::SymbolInfo & +TraceDumper::FunctionCall::TracedSegment::GetFirstInstructionSymbolInfo() + const { + return m_first_symbol_info; +} + +const TraceDumper::SymbolInfo & +TraceDumper::FunctionCall::TracedSegment::GetLastInstructionSymbolInfo() const { + return m_last_symbol_info; +} + +const TraceDumper::FunctionCall & +TraceDumper::FunctionCall::UntracedPrefixSegment::GetNestedCall() const { + return *m_nested_call; +} + +TraceDumper::FunctionCall::FunctionCall( + const TraceCursorSP &cursor_sp, + const TraceDumper::SymbolInfo &symbol_info) { + m_is_error = cursor_sp->IsError(); + AppendSegment(cursor_sp, symbol_info); +} + +void TraceDumper::FunctionCall::AppendSegment( + const TraceCursorSP &cursor_sp, + const TraceDumper::SymbolInfo &symbol_info) { + m_traced_segments.emplace_back(cursor_sp, symbol_info, *this); +} + +const TraceDumper::SymbolInfo & +TraceDumper::FunctionCall::GetSymbolInfo() const { + return m_traced_segments.back().GetLastInstructionSymbolInfo(); +} + +bool TraceDumper::FunctionCall::IsError() const { return m_is_error; } + +const std::deque<TraceDumper::FunctionCall::TracedSegment> & +TraceDumper::FunctionCall::GetTracedSegments() const { + return m_traced_segments; +} + +TraceDumper::FunctionCall::TracedSegment & +TraceDumper::FunctionCall::GetLastTracedSegment() { + return m_traced_segments.back(); +} + +const std::optional<TraceDumper::FunctionCall::UntracedPrefixSegment> & +TraceDumper::FunctionCall::GetUntracedPrefixSegment() const { + return m_untraced_prefix_segment; +} + +void TraceDumper::FunctionCall::SetUntracedPrefixSegment( + TraceDumper::FunctionCallUP &&nested_call) { + m_untraced_prefix_segment.emplace(std::move(nested_call)); +} + +TraceDumper::FunctionCall *TraceDumper::FunctionCall::GetParentCall() const { + return m_parent_call; +} + +void TraceDumper::FunctionCall::SetParentCall( + TraceDumper::FunctionCall &parent_call) { + m_parent_call = &parent_call; +} + +/// Given an instruction that happens after a return, find the ancestor function +/// call that owns it. If this ancestor doesn't exist, create a new ancestor and +/// make it the root of the tree. +/// +/// \param[in] last_function_call +/// The function call that performs the return. +/// +/// \param[in] symbol_info +/// The symbol information of the instruction after the return. +/// +/// \param[in] cursor_sp +/// The cursor pointing to the instruction after the return. +/// +/// \param[in,out] roots +/// The object owning the roots. It might be modified if a new root needs to +/// be created. +/// +/// \return +/// A reference to the function call that owns the new instruction +static TraceDumper::FunctionCall &AppendReturnedInstructionToFunctionCallForest( + TraceDumper::FunctionCall &last_function_call, + const TraceDumper::SymbolInfo &symbol_info, const TraceCursorSP &cursor_sp, + std::vector<TraceDumper::FunctionCallUP> &roots) { + + // We omit the current node because we can't return to itself. + TraceDumper::FunctionCall *ancestor = last_function_call.GetParentCall(); + + for (; ancestor; ancestor = ancestor->GetParentCall()) { + // This loop traverses the tree until it finds a call that we can return to. + if (IsSameInstructionSymbolContext(ancestor->GetSymbolInfo(), symbol_info, + /*check_source_line_info=*/false)) { + // We returned to this symbol, so we are assuming we are returning there + // Note: If this is not robust enough, we should actually check if we + // returning to the instruction that follows the last instruction from + // that call, as that's the behavior of CALL instructions. + ancestor->AppendSegment(cursor_sp, symbol_info); + return *ancestor; + } + } + + // We didn't find the call we were looking for, so we now create a synthetic + // one that will contain the new instruction in its first traced segment. + TraceDumper::FunctionCallUP new_root = + std::make_unique<TraceDumper::FunctionCall>(cursor_sp, symbol_info); + // This new root will own the previous root through an untraced prefix segment. + new_root->SetUntracedPrefixSegment(std::move(roots.back())); + roots.pop_back(); + // We update the roots container to point to the new root + roots.emplace_back(std::move(new_root)); + return *roots.back(); +} + +/// Append an instruction to a function call forest. The new instruction might +/// be appended to the current segment, to a new nest call, or return to an +/// ancestor call. +/// +/// \param[in] exe_ctx +/// The exeuction context of the traced thread. +/// +/// \param[in] last_function_call +/// The chronologically most recent function call before the new instruction. +/// +/// \param[in] prev_symbol_info +/// The symbol information of the previous instruction in the trace. +/// +/// \param[in] symbol_info +/// The symbol information of the new instruction. +/// +/// \param[in] cursor_sp +/// The cursor pointing to the new instruction. +/// +/// \param[in,out] roots +/// The object owning the roots. It might be modified if a new root needs to +/// be created. +/// +/// \return +/// A reference to the function call that owns the new instruction. +static TraceDumper::FunctionCall &AppendInstructionToFunctionCallForest( + const ExecutionContext &exe_ctx, + TraceDumper::FunctionCall *last_function_call, + const TraceDumper::SymbolInfo &prev_symbol_info, + const TraceDumper::SymbolInfo &symbol_info, const TraceCursorSP &cursor_sp, + std::vector<TraceDumper::FunctionCallUP> &roots) { + if (!last_function_call || last_function_call->IsError()) { + // We create a brand new root + roots.emplace_back( + std::make_unique<TraceDumper::FunctionCall>(cursor_sp, symbol_info)); + return *roots.back(); + } + + AddressRange range; + if (symbol_info.sc.GetAddressRange( + eSymbolContextBlock | eSymbolContextFunction | eSymbolContextSymbol, + 0, /*inline_block_range*/ true, range)) { + if (range.GetBaseAddress() == symbol_info.address) { + // Our instruction is the first instruction of a function. This has + // to be a call. This should also identify if a trampoline or the linker + // is making a call using a non-CALL instruction. + return last_function_call->GetLastTracedSegment().CreateNestedCall( + cursor_sp, symbol_info); + } + } + if (IsSameInstructionSymbolContext(prev_symbol_info, symbol_info, + /*check_source_line_info=*/false)) { + // We are still in the same function. This can't be a call because otherwise + // we would be in the first instruction of the symbol. + last_function_call->GetLastTracedSegment().AppendInsn(cursor_sp, + symbol_info); + return *last_function_call; + } + // Now we are in a different symbol. Let's see if this is a return or a + // call + const InstructionSP &insn = last_function_call->GetLastTracedSegment() + .GetLastInstructionSymbolInfo() + .instruction; + InstructionControlFlowKind insn_kind = + insn ? insn->GetControlFlowKind(&exe_ctx) + : eInstructionControlFlowKindOther; + + switch (insn_kind) { + case lldb::eInstructionControlFlowKindCall: + case lldb::eInstructionControlFlowKindFarCall: { + // This is a regular call + return last_function_call->GetLastTracedSegment().CreateNestedCall( + cursor_sp, symbol_info); + } + case lldb::eInstructionControlFlowKindFarReturn: + case lldb::eInstructionControlFlowKindReturn: { + // We should have caught most trampolines and linker functions earlier, so + // let's assume this is a regular return. + return AppendReturnedInstructionToFunctionCallForest( + *last_function_call, symbol_info, cursor_sp, roots); + } + default: + // we changed symbols not using a call or return and we are not in the + // beginning of a symbol, so this should be something very artificial + // or maybe a jump to some label in the middle of it section. + + // We first check if it's a return from an inline method + if (prev_symbol_info.sc.block && + prev_symbol_info.sc.block->GetContainingInlinedBlock()) { + return AppendReturnedInstructionToFunctionCallForest( + *last_function_call, symbol_info, cursor_sp, roots); + } + // Now We assume it's a call. We should revisit this in the future. + // Ideally we should be able to decide whether to create a new tree, + // or go deeper or higher in the stack. + return last_function_call->GetLastTracedSegment().CreateNestedCall( + cursor_sp, symbol_info); + } +} + +/// Append an error to a function call forest. The new error might be appended +/// to the current segment if it contains errors or will create a new root. +/// +/// \param[in] last_function_call +/// The chronologically most recent function call before the new error. +/// +/// \param[in] cursor_sp +/// The cursor pointing to the new error. +/// +/// \param[in,out] roots +/// The object owning the roots. It might be modified if a new root needs to +/// be created. +/// +/// \return +/// A reference to the function call that owns the new error. +TraceDumper::FunctionCall &AppendErrorToFunctionCallForest( + TraceDumper::FunctionCall *last_function_call, TraceCursorSP &cursor_sp, + std::vector<TraceDumper::FunctionCallUP> &roots) { + if (last_function_call && last_function_call->IsError()) { + last_function_call->GetLastTracedSegment().AppendInsn( + cursor_sp, TraceDumper::SymbolInfo{}); + return *last_function_call; + } else { + roots.emplace_back(std::make_unique<TraceDumper::FunctionCall>( + cursor_sp, TraceDumper::SymbolInfo{})); + return *roots.back(); + } +} + +static std::vector<TraceDumper::FunctionCallUP> +CreateFunctionCallForest(TraceCursorSP &cursor_sp, + const ExecutionContext &exe_ctx) { + + std::vector<TraceDumper::FunctionCallUP> roots; + TraceDumper::SymbolInfo prev_symbol_info; + + TraceDumper::FunctionCall *last_function_call = nullptr; + + for (; cursor_sp->HasValue(); cursor_sp->Next()) { + if (cursor_sp->IsError()) { + last_function_call = &AppendErrorToFunctionCallForest(last_function_call, + cursor_sp, roots); + prev_symbol_info = {}; + } else if (cursor_sp->IsInstruction()) { + TraceDumper::SymbolInfo symbol_info = CalculateSymbolInfo( + exe_ctx, cursor_sp->GetLoadAddress(), prev_symbol_info); + + last_function_call = &AppendInstructionToFunctionCallForest( + exe_ctx, last_function_call, prev_symbol_info, symbol_info, cursor_sp, + roots); + prev_symbol_info = symbol_info; + } else if (cursor_sp->GetEventType() == eTraceEventCPUChanged) { + // TODO: In case of a CPU change, we create a new root because we haven't + // investigated yet if a call tree can safely continue or if interrupts + // could have polluted the original call tree. + last_function_call = nullptr; + prev_symbol_info = {}; + } + } + + return roots; +} + +void TraceDumper::DumpFunctionCalls() { + ThreadSP thread_sp = m_cursor_sp->GetExecutionContextRef().GetThreadSP(); + ExecutionContext exe_ctx; + thread_sp->GetProcess()->GetTarget().CalculateExecutionContext(exe_ctx); + + m_writer_up->FunctionCallForest( + CreateFunctionCallForest(m_cursor_sp, exe_ctx)); +} diff --git a/gnu/llvm/lldb/source/Target/TraceExporter.cpp b/gnu/llvm/lldb/source/Target/TraceExporter.cpp index 1a6571dba4a..8c925aa495b 100644 --- a/gnu/llvm/lldb/source/Target/TraceExporter.cpp +++ b/gnu/llvm/lldb/source/Target/TraceExporter.cpp @@ -22,11 +22,10 @@ static Error createInvalidPlugInError(StringRef plugin_name) { } Expected<lldb::TraceExporterUP> -TraceExporter::FindPlugin(llvm::StringRef plugin_name) { - ConstString name(plugin_name); +TraceExporter::FindPlugin(llvm::StringRef name) { if (auto create_callback = PluginManager::GetTraceExporterCreateCallback(name)) return create_callback(); - return createInvalidPlugInError(plugin_name); + return createInvalidPlugInError(name); } diff --git a/gnu/llvm/lldb/source/Target/UnwindLLDB.cpp b/gnu/llvm/lldb/source/Target/UnwindLLDB.cpp index 047147112f3..1d8bf2f88ae 100644 --- a/gnu/llvm/lldb/source/Target/UnwindLLDB.cpp +++ b/gnu/llvm/lldb/source/Target/UnwindLLDB.cpp @@ -17,6 +17,7 @@ #include "lldb/Target/RegisterContextUnwind.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" using namespace lldb; @@ -101,7 +102,7 @@ bool UnwindLLDB::AddFirstFrame() { return true; unwind_done: - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); + Log *log = GetLog(LLDBLog::Unwind); if (log) { LLDB_LOGF(log, "th%d Unwind of this thread is complete.", m_thread.GetIndexID()); @@ -119,7 +120,7 @@ UnwindLLDB::CursorSP UnwindLLDB::GetOneMoreFrame(ABI *abi) { if (m_unwind_complete) return nullptr; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); + Log *log = GetLog(LLDBLog::Unwind); CursorSP prev_frame = m_frames.back(); uint32_t cur_idx = m_frames.size(); @@ -312,11 +313,10 @@ void UnwindLLDB::UpdateUnwindPlanForFirstFrameIfInvalid(ABI *abi) { // Restore status after calling AddOneMoreFrame m_unwind_complete = old_m_unwind_complete; m_candidate_frame = old_m_candidate_frame; - return; } bool UnwindLLDB::AddOneMoreFrame(ABI *abi) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); + Log *log = GetLog(LLDBLog::Unwind); // Frame zero is a little different if (m_frames.empty()) |