summaryrefslogtreecommitdiff
path: root/lldb/source/Target
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Target')
-rw-r--r--lldb/source/Target/ABI.cpp52
-rw-r--r--lldb/source/Target/DynamicRegisterInfo.cpp819
-rw-r--r--lldb/source/Target/Language.cpp19
-rw-r--r--lldb/source/Target/ModuleCache.cpp2
-rw-r--r--lldb/source/Target/OperatingSystem.cpp3
-rw-r--r--lldb/source/Target/PathMappingList.cpp40
-rw-r--r--lldb/source/Target/Platform.cpp314
-rw-r--r--lldb/source/Target/Process.cpp352
-rw-r--r--lldb/source/Target/ProcessTrace.cpp11
-rw-r--r--lldb/source/Target/RegisterContext.cpp50
-rw-r--r--lldb/source/Target/RegisterContextUnwind.cpp19
-rw-r--r--lldb/source/Target/RemoteAwarePlatform.cpp25
-rw-r--r--lldb/source/Target/Statistics.cpp196
-rw-r--r--lldb/source/Target/StopInfo.cpp143
-rw-r--r--lldb/source/Target/Target.cpp198
-rw-r--r--lldb/source/Target/TargetProperties.td7
-rw-r--r--lldb/source/Target/Thread.cpp29
-rw-r--r--lldb/source/Target/ThreadPlan.cpp8
-rw-r--r--lldb/source/Target/ThreadPlanBase.cpp6
-rw-r--r--lldb/source/Target/ThreadPlanCallFunction.cpp4
-rw-r--r--lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp2
-rw-r--r--lldb/source/Target/ThreadPlanCallUserExpression.cpp6
-rw-r--r--lldb/source/Target/ThreadPlanPython.cpp2
-rw-r--r--lldb/source/Target/ThreadPlanStack.cpp40
-rw-r--r--lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp4
-rw-r--r--lldb/source/Target/Trace.cpp28
-rw-r--r--lldb/source/Target/TraceExporter.cpp5
-rw-r--r--lldb/source/Target/UnixSignals.cpp24
28 files changed, 1830 insertions, 578 deletions
diff --git a/lldb/source/Target/ABI.cpp b/lldb/source/Target/ABI.cpp
index c3342caf8742..6e8772cbd142 100644
--- a/lldb/source/Target/ABI.cpp
+++ b/lldb/source/Target/ABI.cpp
@@ -16,7 +16,7 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/Log.h"
-#include "llvm/Support/TargetRegistry.h"
+#include "llvm/MC/TargetRegistry.h"
#include <cctype>
using namespace lldb;
@@ -214,33 +214,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;
+void RegInfoBasedABI::AugmentRegisterInfo(
+ std::vector<DynamicRegisterInfo::Register> &regs) {
+ 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, abi_info))
- return;
+ RegisterInfo abi_info;
+ if (!GetRegisterInfoByName(info.name.GetStringRef(), abi_info))
+ continue;
- 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];
+ 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);
+void MCBasedABI::AugmentRegisterInfo(
+ std::vector<DynamicRegisterInfo::Register> &regs) {
+ for (DynamicRegisterInfo::Register &info : regs) {
+ uint32_t eh, dwarf;
+ std::tie(eh, dwarf) = GetEHAndDWARFNums(info.name.GetStringRef());
- 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);
+ 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/lldb/source/Target/DynamicRegisterInfo.cpp b/lldb/source/Target/DynamicRegisterInfo.cpp
new file mode 100644
index 000000000000..9f894f86aea8
--- /dev/null
+++ b/lldb/source/Target/DynamicRegisterInfo.cpp
@@ -0,0 +1,819 @@
+//===-- 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/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 &reg_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 = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_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(&reg_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> &&regs,
+ const ArchSpec &arch) {
+ assert(!m_finalized);
+
+ for (auto it : llvm::enumerate(regs)) {
+ uint32_t local_regnum = it.index();
+ const DynamicRegisterInfo::Register &reg = 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.begin(), pos->second.end());
+ 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 &reg : 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 &reg : 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 &reg : 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 &reg : 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 &reg : 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 &reg : 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 &reg : 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 &regnum_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 &reg : 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 &reg_info : m_regs)
+ if (reg_info.name == reg_name)
+ return &reg_info;
+ return nullptr;
+}
+
+void lldb_private::addSupplementaryRegister(
+ std::vector<DynamicRegisterInfo::Register> &regs,
+ 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/lldb/source/Target/Language.cpp b/lldb/source/Target/Language.cpp
index 7b35da5028ac..eee1ff1512d9 100644
--- a/lldb/source/Target/Language.cpp
+++ b/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;
}
}
diff --git a/lldb/source/Target/ModuleCache.cpp b/lldb/source/Target/ModuleCache.cpp
index dcdc0772b31a..7143fcd2707c 100644
--- a/lldb/source/Target/ModuleCache.cpp
+++ b/lldb/source/Target/ModuleCache.cpp
@@ -159,7 +159,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/lldb/source/Target/OperatingSystem.cpp b/lldb/source/Target/OperatingSystem.cpp
index 033a806460da..75762c05151d 100644
--- a/lldb/source/Target/OperatingSystem.cpp
+++ b/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/lldb/source/Target/PathMappingList.cpp b/lldb/source/Target/PathMappingList.cpp
index b660c310ef31..e49f6213cf27 100644
--- a/lldb/source/Target/PathMappingList.cpp
+++ b/lldb/source/Target/PathMappingList.cpp
@@ -30,11 +30,11 @@ 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() {}
@@ -59,8 +59,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 +78,8 @@ void PathMappingList::Append(const PathMappingList &rhs, bool notify) {
}
}
-void PathMappingList::Insert(ConstString path,
- ConstString replacement, uint32_t index,
- bool notify) {
+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 +92,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;
@@ -218,18 +216,22 @@ bool PathMappingList::ReverseRemapPath(const FileSpec &file, FileSpec &fixed) co
}
llvm::Optional<FileSpec> PathMappingList::FindFile(const FileSpec &orig_spec) const {
- if (auto remapped = RemapPath(orig_spec.GetPath(), /*only_if_exists=*/true))
+ // 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 +287,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/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp
index a77ecddfbab6..bd455310f08e 100644
--- a/lldb/source/Target/Platform.cpp
+++ b/lldb/source/Target/Platform.cpp
@@ -155,9 +155,9 @@ 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) {
@@ -294,8 +294,8 @@ PlatformSP Platform::Create(ConstString name, Status &error) {
if (name == g_host_platform_name)
return GetHostPlatform();
- create_callback =
- PluginManager::GetPlatformCreateCallbackForPluginName(name);
+ create_callback = PluginManager::GetPlatformCreateCallbackForPluginName(
+ name.GetStringRef());
if (create_callback)
platform_sp = create_callback(true, nullptr);
else
@@ -395,18 +395,10 @@ Platform::Platform(bool is_host)
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 +413,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 (llvm::Optional<std::string> s = GetOSBuildString())
+ strm.Format(" ({0})", *s);
strm.EOL();
}
@@ -447,8 +439,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 (llvm::Optional<std::string> s = GetOSKernelDescription())
+ strm.Format(" Kernel: {0}\n", *s);
}
llvm::VersionTuple Platform::GetOSVersion(Process *process) {
@@ -493,28 +485,16 @@ llvm::VersionTuple Platform::GetOSVersion(Process *process) {
return llvm::VersionTuple();
}
-bool Platform::GetOSBuildString(std::string &s) {
- s.clear();
-
+llvm::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) {
+llvm::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(
@@ -769,9 +749,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 +764,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,14 +777,13 @@ 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(); }
+ConstString Platform::GetName() { return ConstString(GetPluginName()); }
const char *Platform::GetHostname() {
if (IsHost())
@@ -856,6 +833,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 +844,8 @@ 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) {
+ for (const ArchSpec &arch : GetSupportedArchitectures()) {
+ arch_module_spec.GetArchitecture() = arch;
error = ModuleList::GetSharedModule(arch_module_spec, exe_module_sp,
module_search_paths_ptr, nullptr,
nullptr);
@@ -878,9 +855,74 @@ 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;
+ for (const ArchSpec &arch : GetSupportedArchitectures()) {
+ 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;
}
@@ -966,26 +1008,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;
}
@@ -1066,36 +1109,19 @@ Status Platform::KillProcess(const lldb::pid_t pid) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_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) {
+lldb::ProcessSP Platform::DebugProcess(ProcessLaunchInfo &launch_info,
+ Debugger &debugger, Target &target,
+ Status &error) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
- LLDB_LOGF(log, "Platform::%s entered (target %p)", __FUNCTION__,
- static_cast<void *>(target));
+ LLDB_LOG(log, "target = {0})", &target);
ProcessSP process_sp;
// Make sure we stop at the entry point
@@ -1117,7 +1143,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 +1161,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 +1175,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) {
@@ -1183,6 +1209,35 @@ Platform::GetPlatformForArchitecture(const ArchSpec &arch,
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;
+}
+
+bool Platform::GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) {
+ const auto &archs = GetSupportedArchitectures();
+ if (idx >= archs.size())
+ return false;
+ arch = archs[idx];
+ return true;
+}
+
+std::vector<ArchSpec> Platform::GetSupportedArchitectures() {
+ std::vector<ArchSpec> result;
+ ArchSpec arch;
+ for (uint32_t idx = 0; GetSupportedArchitectureAtIndex(idx, arch); ++idx)
+ result.push_back(arch);
+ return result;
+}
+
/// Lets a platform answer if it is compatible with a given
/// architecture and the target triple contained within.
bool Platform::IsCompatibleArchitecture(const ArchSpec &arch,
@@ -1191,26 +1246,13 @@ bool Platform::IsCompatibleArchitecture(const ArchSpec &arch,
// 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;
- }
+ auto match = exact_arch_match ? &ArchSpec::IsExactMatch
+ : &ArchSpec::IsCompatibleMatch;
+ for (const ArchSpec &platform_arch : GetSupportedArchitectures()) {
+ if ((arch.*match)(platform_arch)) {
+ if (compatible_arch_ptr)
+ *compatible_arch_ptr = platform_arch;
+ return true;
}
}
}
@@ -1225,7 +1267,7 @@ Status Platform::PutFile(const FileSpec &source, const FileSpec &destination,
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 +1282,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);
@@ -1517,12 +1559,13 @@ 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) {
+Status
+Platform::GetCachedExecutable(ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr) {
const auto platform_spec = module_spec.GetFileSpec();
- const auto error = LoadCachedExecutable(
- module_spec, module_sp, module_search_paths_ptr, remote_platform);
+ const auto error =
+ LoadCachedExecutable(module_spec, module_sp, module_search_paths_ptr);
if (error.Success()) {
module_spec.GetFileSpec() = module_sp->GetFileSpec();
module_spec.GetPlatformFileSpec() = platform_spec;
@@ -1531,15 +1574,17 @@ 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::LoadCachedExecutable(const ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr) {
+ return GetRemoteSharedModule(
+ module_spec, nullptr, module_sp,
+ [&](const ModuleSpec &spec) {
+ return ResolveRemoteExecutable(spec, module_sp,
+ module_search_paths_ptr);
+ },
+ nullptr);
}
Status Platform::GetRemoteSharedModule(const ModuleSpec &module_spec,
@@ -1568,9 +1613,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()) {
+ 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,8 +1663,8 @@ 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);
@@ -1663,7 +1707,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,7 +1748,7 @@ Status Platform::DownloadSymbolFile(const lldb::ModuleSP &module_sp,
}
FileSpec Platform::GetModuleCacheRoot() {
- auto dir_spec = GetGlobalPlatformProperties()->GetModuleCacheDirectory();
+ auto dir_spec = GetGlobalPlatformProperties().GetModuleCacheDirectory();
dir_spec.AppendPathComponent(GetName().AsCString());
return dir_spec;
}
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 8ecc66b592ea..84dc2b94a0eb 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -110,6 +110,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 +166,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 +347,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 +363,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);
@@ -481,12 +499,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() {
@@ -1278,6 +1296,17 @@ StateType Process::GetState() {
}
void Process::SetPublicState(StateType new_state, bool restarted) {
+ 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(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE |
LIBLLDB_LOG_PROCESS));
LLDB_LOGF(log, "Process::SetPublicState (state = %s, restarted = %i)",
@@ -1296,7 +1325,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",
@@ -1427,7 +1455,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();
@@ -1953,57 +1983,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,
@@ -2463,115 +2442,125 @@ Status Process::Launch(ProcessLaunchInfo &launch_info) {
m_process_input_reader.reset();
Module *exe_module = GetTarget().GetExecutableModulePointer();
- if (!exe_module) {
- error.SetErrorString("executable module does not exist");
- return error;
- }
- 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())) {
+ // 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) {
+ 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();
+
+ 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.Success()) {
- const bool restarted = false;
- SetPublicState(eStateLaunching, restarted);
- m_should_detach = false;
+ 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");
+ }
- 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");
+ 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;
- 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));
+ // 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();
+ 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();
+ DynamicLoader *dyld = GetDynamicLoader();
+ if (dyld)
+ dyld->DidLaunch();
- GetJITLoaders().DidLaunch();
+ GetJITLoaders().DidLaunch();
- SystemRuntime *system_runtime = GetSystemRuntime();
- if (system_runtime)
- system_runtime->DidLaunch();
+ SystemRuntime *system_runtime = GetSystemRuntime();
+ if (system_runtime)
+ system_runtime->DidLaunch();
- if (!m_os_up)
- LoadOperatingSystemPlugin(false);
+ 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();
+ // 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);
+ // 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.
+ // We are done with the launch hijack listener, and this stop should
+ // go to the public state listener:
+ RestoreProcessEvents();
+ SetPublicState(state, false);
- if (PrivateStateThreadIsValid())
- ResumePrivateStateThread();
- else
- StartPrivateStateThread();
+ if (PrivateStateThreadIsValid())
+ ResumePrivateStateThread();
+ else
+ StartPrivateStateThread();
- // 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.
+ // 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);
}
}
} else {
+ std::string local_exec_file_path = exe_spec_to_use.GetPath();
error.SetErrorStringWithFormat("file doesn't exist: '%s'",
- local_exec_file_path);
+ local_exec_file_path.c_str());
}
return error;
@@ -2625,12 +2614,16 @@ 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();
}
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>();
@@ -2916,13 +2909,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 +2924,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());
}
}
@@ -4310,8 +4299,8 @@ 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);
}
@@ -4328,11 +4317,11 @@ 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();
@@ -4376,7 +4365,6 @@ public:
}
m_is_running = false;
#endif
- terminal_state.Restore();
}
void Cancel() override {
@@ -4433,7 +4421,7 @@ 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};
@@ -4494,7 +4482,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.
@@ -4505,7 +4494,7 @@ public:
: m_thread_plan_sp(thread_plan_sp), m_already_reset(false) {
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,7 +4505,7 @@ 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);
}
}
@@ -4525,7 +4514,7 @@ private:
lldb::ThreadPlanSP m_thread_plan_sp;
bool m_already_reset;
bool m_private;
- bool m_is_master;
+ bool m_is_controlling;
bool m_okay_to_discard;
};
} // anonymous namespace
@@ -4676,11 +4665,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
@@ -5864,6 +5853,13 @@ Process::AdvanceAddressToNextBranchInstruction(Address default_stop_addr,
return retval;
}
+Status Process::GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) {
+ if (auto abi = GetABI())
+ load_addr = abi->FixDataAddress(load_addr);
+ return DoGetMemoryRegionInfo(load_addr, range_info);
+}
+
Status
Process::GetMemoryRegions(lldb_private::MemoryRegionInfos &region_list) {
@@ -5963,11 +5959,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);
}
}
@@ -6091,8 +6084,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/lldb/source/Target/ProcessTrace.cpp b/lldb/source/Target/ProcessTrace.cpp
index c878a2ac4eb9..41d5b01b61d8 100644
--- a/lldb/source/Target/ProcessTrace.cpp
+++ b/lldb/source/Target/ProcessTrace.cpp
@@ -19,12 +19,7 @@
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 +52,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"));
diff --git a/lldb/source/Target/RegisterContext.cpp b/lldb/source/Target/RegisterContext.cpp
index bd50a9486ef3..7364660650e8 100644
--- a/lldb/source/Target/RegisterContext.cpp
+++ b/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,
diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp
index 1ce21e6306e0..96b69640a3a3 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -893,13 +893,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)
diff --git a/lldb/source/Target/RemoteAwarePlatform.cpp b/lldb/source/Target/RemoteAwarePlatform.cpp
index b0c43ffa839e..eb39fc6db304 100644
--- a/lldb/source/Target/RemoteAwarePlatform.cpp
+++ b/lldb/source/Target/RemoteAwarePlatform.cpp
@@ -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
@@ -154,10 +153,10 @@ Status RemoteAwarePlatform::ResolveExecutable(
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",
@@ -332,18 +331,16 @@ bool RemoteAwarePlatform::GetRemoteOSVersion() {
return false;
}
-bool RemoteAwarePlatform::GetRemoteOSBuildString(std::string &s) {
+llvm::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 llvm::None;
}
-bool RemoteAwarePlatform::GetRemoteOSKernelDescription(std::string &s) {
+llvm::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 llvm::None;
}
ArchSpec RemoteAwarePlatform::GetRemoteSystemArchitecture() {
diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp
new file mode 100644
index 000000000000..1b205c533519
--- /dev/null
+++ b/lldb/source/Target/Statistics.cpp
@@ -0,0 +1,196 @@
+//===-- 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 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("debugInfoParseTime", debug_parse_time);
+ module.try_emplace("debugInfoIndexTime", debug_index_time);
+ module.try_emplace("debugInfoByteSize", (int64_t)debug_info_size);
+ return module;
+}
+
+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.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);
+
+ return target_metrics_json;
+}
+
+void TargetStats::SetLaunchOrAttachTime() {
+ m_launch_or_attach_time = StatsClock::now();
+ m_first_private_stop_time = llvm::None;
+}
+
+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();
+}
+
+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;
+ 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 size_t num_modules = Module::GetNumberAllocatedModules();
+ 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().count();
+ module_stat.symtab_index_time = module->GetSymtabIndexTime().count();
+ SymbolFile *sym_file = module->GetSymbolFile();
+ if (sym_file) {
+ 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();
+ }
+ 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;
+ json_modules.emplace_back(module_stat.ToJSON());
+ }
+
+ json::Object global_stats{
+ {"targets", std::move(json_targets)},
+ {"modules", std::move(json_modules)},
+ {"totalSymbolTableParseTime", symtab_parse_time},
+ {"totalSymbolTableIndexTime", symtab_index_time},
+ {"totalDebugInfoParseTime", debug_parse_time},
+ {"totalDebugInfoIndexTime", debug_index_time},
+ {"totalDebugInfoByteSize", debug_info_size},
+ };
+ return std::move(global_stats);
+}
diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index aeb97f1919eb..1de281b1761f 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -307,7 +307,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
@@ -425,7 +425,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 =
@@ -535,7 +535,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 &&
@@ -579,7 +579,7 @@ 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.
@@ -615,7 +615,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 +624,7 @@ public:
process_sp->AddPreResumeAction(SentryPreResumeAction, this);
}
}
-
+
void DoReenable() {
if (process_sp && watchpoint_sp) {
bool was_disabled = watchpoint_sp->IsDisabledDuringEphemeralMode();
@@ -637,13 +637,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();
@@ -724,14 +724,14 @@ protected:
// 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();
@@ -764,7 +764,7 @@ protected:
true, // stop_other_threads
new_plan_status));
if (new_plan_sp && new_plan_status.Success()) {
- new_plan_sp->SetIsMasterPlan(true);
+ new_plan_sp->SetIsControllingPlan(true);
new_plan_sp->SetOkayToDiscard(false);
new_plan_sp->SetPrivate(true);
}
@@ -889,12 +889,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())
@@ -1154,6 +1154,103 @@ protected:
bool m_performed_action;
};
+// StopInfoFork
+
+class StopInfoFork : public StopInfo {
+public:
+ StopInfoFork(Thread &thread, lldb::pid_t child_pid, lldb::tid_t child_tid)
+ : StopInfo(thread, child_pid), m_performed_action(false),
+ 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;
+
+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_performed_action(false),
+ 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;
+
+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), m_performed_action(false) {}
+
+ ~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;
+};
+
} // namespace lldb_private
StopInfoSP StopInfo::CreateStopReasonWithBreakpointSiteID(Thread &thread,
@@ -1175,6 +1272,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 +1301,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/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index 1f8e8c54fa9e..28575b50cf96 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -60,6 +60,7 @@
#include "lldb/Utility/Timer.h"
#include "llvm/ADT/ScopeExit.h"
+#include "llvm/ADT/SetVector.h"
#include <memory>
#include <mutex>
@@ -95,14 +96,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");
@@ -1022,7 +1019,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);
@@ -1400,6 +1397,7 @@ void Target::SetExecutableModule(ModuleSP &executable_sp,
ClearModules(false);
if (executable_sp) {
+ ElapsedTime elapsed(m_stats.GetCreateTime());
LLDB_SCOPED_TIMERF("Target::SetExecutableModule (executable = '%s')",
executable_sp->GetFileSpec().GetPath().c_str());
@@ -1906,6 +1904,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,
@@ -2231,7 +2291,10 @@ std::vector<TypeSystem *> 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.
+ llvm::SetVector<TypeSystem *> scratch_type_systems;
LanguageSet languages_for_expressions =
Language::GetLanguagesSupportingTypeSystemsForExpressions();
@@ -2247,10 +2310,10 @@ std::vector<TypeSystem *> Target::GetScratchTypeSystems(bool create_on_demand) {
"system available",
Language::GetNameForLanguageType(language));
else
- scratch_type_systems.emplace_back(&type_system_or_err.get());
+ scratch_type_systems.insert(&type_system_or_err.get());
}
- return scratch_type_systems;
+ return scratch_type_systems.takeVector();
}
PersistentExpressionState *
@@ -2345,35 +2408,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(GetLogIfAllCategoriesSet(LIBLLDB_LOG_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 +2449,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;
@@ -2445,6 +2497,10 @@ ExpressionResults Target::EvaluateExpression(
fixed_expression, ctx_obj);
}
+ if (execution_results == eExpressionCompleted)
+ m_stats.GetExpressionStats().NotifySuccess();
+ else
+ m_stats.GetExpressionStats().NotifyFailure();
return execution_results;
}
@@ -2768,12 +2824,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,6 +2964,7 @@ bool Target::SetSectionUnloaded(const lldb::SectionSP &section_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));
@@ -2936,17 +2993,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(
@@ -2993,7 +3042,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,
@@ -3119,6 +3168,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) {
@@ -3731,7 +3781,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
@@ -3781,7 +3831,7 @@ 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());
}
}
@@ -3985,6 +4035,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;
@@ -4249,16 +4338,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 +4514,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/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td
index 8f627ad0f1a8..063ba0a6c25a 100644
--- a/lldb/source/Target/TargetProperties.td
+++ b/lldb/source/Target/TargetProperties.td
@@ -163,9 +163,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.">;
@@ -239,6 +236,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 {
diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp
index b423f1b5f1fe..1b32331d98f7 100644
--- a/lldb/source/Target/Thread.cpp
+++ b/lldb/source/Target/Thread.cpp
@@ -55,12 +55,11 @@
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 +102,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;
@@ -845,7 +844,7 @@ 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());
+ (plan_ptr->IsControllingPlan() && !plan_ptr->OkayToDiscard());
} else
done_processing_current_plan = true;
@@ -883,11 +882,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 +905,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.
@@ -1215,7 +1214,7 @@ void Thread::DiscardThreadPlans(bool force) {
GetPlans().DiscardAllPlans();
return;
}
- GetPlans().DiscardConsultingMasterPlans();
+ GetPlans().DiscardConsultingControllingPlans();
}
Status Thread::UnwindInnermostExpression() {
@@ -1915,7 +1914,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 +1947,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???
@@ -1972,7 +1971,7 @@ Status Thread::StepOut() {
abort_other_plans, nullptr, first_instruction, stop_other_threads,
eVoteYes, eVoteNoOpinion, 0, 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???
diff --git a/lldb/source/Target/ThreadPlan.cpp b/lldb/source/Target/ThreadPlan.cpp
index 6b55f3912d11..3b42831f1fbf 100644
--- a/lldb/source/Target/ThreadPlan.cpp
+++ b/lldb/source/Target/ThreadPlan.cpp
@@ -26,8 +26,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());
}
@@ -149,10 +149,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() {
diff --git a/lldb/source/Target/ThreadPlanBase.cpp b/lldb/source/Target/ThreadPlanBase.cpp
index c6c4d97c1655..46ae9c32a0de 100644
--- a/lldb/source/Target/ThreadPlanBase.cpp
+++ b/lldb/source/Target/ThreadPlanBase.cpp
@@ -40,7 +40,7 @@ ThreadPlanBase::ThreadPlanBase(Thread &thread)
#endif
new_tracer_sp->EnableTracing(thread.GetTraceEnabledState());
SetThreadPlanTracer(new_tracer_sp);
- SetIsMasterPlan(true);
+ SetIsControllingPlan(true);
}
ThreadPlanBase::~ThreadPlanBase() = default;
@@ -90,8 +90,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/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp
index 3699a507d058..0336a9daf10a 100644
--- a/lldb/source/Target/ThreadPlanCallFunction.cpp
+++ b/lldb/source/Target/ThreadPlanCallFunction.cpp
@@ -33,7 +33,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);
@@ -209,7 +209,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) {
diff --git a/lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp b/lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp
index 7471e9b3d7ac..4bccf96d721b 100644
--- a/lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp
+++ b/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/lldb/source/Target/ThreadPlanCallUserExpression.cpp b/lldb/source/Target/ThreadPlanCallUserExpression.cpp
index 9dddd850b6ab..d833a4d7ed27 100644
--- a/lldb/source/Target/ThreadPlanCallUserExpression.cpp
+++ b/lldb/source/Target/ThreadPlanCallUserExpression.cpp
@@ -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,8 +59,8 @@ 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();
}
diff --git a/lldb/source/Target/ThreadPlanPython.cpp b/lldb/source/Target/ThreadPlanPython.cpp
index e83f0e9e715e..cd63d28a3934 100644
--- a/lldb/source/Target/ThreadPlanPython.cpp
+++ b/lldb/source/Target/ThreadPlanPython.cpp
@@ -31,7 +31,7 @@ ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name,
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);
}
diff --git a/lldb/source/Target/ThreadPlanStack.cpp b/lldb/source/Target/ThreadPlanStack.cpp
index d25602d25b91..f09583cc50cc 100644
--- a/lldb/source/Target/ThreadPlanStack.cpp
+++ b/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;
}
@@ -207,35 +213,35 @@ void ThreadPlanStack::DiscardAllPlans() {
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();
}
}
diff --git a/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp b/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp
index 965a7b3a9960..f007b0fa9371 100644
--- a/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp
+++ b/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp
@@ -124,9 +124,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();
diff --git a/lldb/source/Target/Trace.cpp b/lldb/source/Target/Trace.cpp
index 827f3264c096..38b3a7cb006d 100644
--- a/lldb/source/Target/Trace.cpp
+++ b/lldb/source/Target/Trace.cpp
@@ -67,30 +67,28 @@ Trace::FindPluginForPostMortemProcess(Debugger &debugger,
if (!json::fromJSON(trace_session_file, json_session, root))
return root.getError();
- ConstString plugin_name(json_session.trace.type);
- if (auto create_callback = PluginManager::GetTraceCreateCallback(plugin_name))
+ if (auto create_callback =
+ PluginManager::GetTraceCreateCallback(json_session.trace.type))
return create_callback(trace_session_file, session_file_dir, debugger);
return createInvalidPlugInError(json_session.trace.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;
@@ -108,23 +106,21 @@ Error Trace::Stop() {
if (!m_live_process)
return createStringError(inconvertibleErrorCode(),
"Tracing requires a live process.");
- return m_live_process->TraceStop(
- TraceStopRequest(GetPluginName().AsCString()));
+ 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 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 m_live_process->TraceGetState(GetPluginName());
}
Optional<size_t> Trace::GetLiveThreadBinaryDataSize(lldb::tid_t tid,
@@ -158,7 +154,7 @@ Trace::GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind) {
"Tracing data \"%s\" is not available for thread %" PRIu64 ".",
kind.data(), tid);
- TraceGetBinaryDataRequest request{GetPluginName().AsCString(), kind.str(),
+ TraceGetBinaryDataRequest request{GetPluginName().str(), kind.str(),
static_cast<int64_t>(tid), 0,
static_cast<int64_t>(*size)};
return m_live_process->TraceGetBinaryData(request);
@@ -175,8 +171,8 @@ Trace::GetLiveProcessBinaryData(llvm::StringRef kind) {
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)};
+ TraceGetBinaryDataRequest request{GetPluginName().str(), kind.str(), None, 0,
+ static_cast<int64_t>(*size)};
return m_live_process->TraceGetBinaryData(request);
}
diff --git a/lldb/source/Target/TraceExporter.cpp b/lldb/source/Target/TraceExporter.cpp
index 1a6571dba4a0..8c925aa495b0 100644
--- a/lldb/source/Target/TraceExporter.cpp
+++ b/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/lldb/source/Target/UnixSignals.cpp b/lldb/source/Target/UnixSignals.cpp
index 4ec2e25c7e3b..26ff0bbd3825 100644
--- a/lldb/source/Target/UnixSignals.cpp
+++ b/lldb/source/Target/UnixSignals.cpp
@@ -12,10 +12,10 @@
#include "Plugins/Process/Utility/MipsLinuxSignals.h"
#include "Plugins/Process/Utility/NetBSDSignals.h"
#include "lldb/Host/HostInfo.h"
-#include "lldb/Host/StringConvert.h"
#include "lldb/Utility/ArchSpec.h"
using namespace lldb_private;
+using namespace llvm;
UnixSignals::Signal::Signal(const char *name, bool default_suppress,
bool default_stop, bool default_notify,
@@ -156,9 +156,8 @@ int32_t UnixSignals::GetSignalNumberFromName(const char *name) const {
return pos->first;
}
- const int32_t signo =
- StringConvert::ToSInt32(name, LLDB_INVALID_SIGNAL_NUMBER, 0);
- if (signo != LLDB_INVALID_SIGNAL_NUMBER)
+ int32_t signo;
+ if (llvm::to_integer(name, signo))
return signo;
return LLDB_INVALID_SIGNAL_NUMBER;
}
@@ -314,3 +313,20 @@ UnixSignals::GetFilteredSignals(llvm::Optional<bool> should_suppress,
return result;
}
+
+void UnixSignals::IncrementSignalHitCount(int signo) {
+ collection::iterator pos = m_signals.find(signo);
+ if (pos != m_signals.end())
+ pos->second.m_hit_count += 1;
+}
+
+json::Value UnixSignals::GetHitCountStatistics() const {
+ json::Array json_signals;
+ for (const auto &pair: m_signals) {
+ if (pair.second.m_hit_count > 0)
+ json_signals.emplace_back(json::Object{
+ { pair.second.m_name.GetCString(), pair.second.m_hit_count }
+ });
+ }
+ return std::move(json_signals);
+}