diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2023-07-26 19:03:47 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2023-07-26 19:04:23 +0000 |
| commit | 7fa27ce4a07f19b07799a767fc29416f3b625afb (patch) | |
| tree | 27825c83636c4de341eb09a74f49f5d38a15d165 /lldb/source/Target | |
| parent | e3b557809604d036af6e00c60f012c2025b59a5e (diff) | |
Diffstat (limited to 'lldb/source/Target')
23 files changed, 1531 insertions, 801 deletions
diff --git a/lldb/source/Target/DynamicRegisterInfo.cpp b/lldb/source/Target/DynamicRegisterInfo.cpp index 14c3faae38df..d577e20b3740 100644 --- a/lldb/source/Target/DynamicRegisterInfo.cpp +++ b/lldb/source/Target/DynamicRegisterInfo.cpp @@ -20,10 +20,17 @@ using namespace lldb; using namespace lldb_private; -DynamicRegisterInfo::DynamicRegisterInfo( - const lldb_private::StructuredData::Dictionary &dict, - const lldb_private::ArchSpec &arch) { - SetRegisterInfo(dict, arch); +std::unique_ptr<DynamicRegisterInfo> +DynamicRegisterInfo::Create(const StructuredData::Dictionary &dict, + const ArchSpec &arch) { + auto dyn_reg_info = std::make_unique<DynamicRegisterInfo>(); + if (!dyn_reg_info) + return nullptr; + + if (dyn_reg_info->SetRegisterInfo(dict, arch) == 0) + return nullptr; + + return dyn_reg_info; } DynamicRegisterInfo::DynamicRegisterInfo(DynamicRegisterInfo &&info) { @@ -238,17 +245,20 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, std::vector<uint32_t> invalidate_regs; memset(®_info, 0, sizeof(reg_info)); - ConstString name_val; - ConstString alt_name_val; - if (!reg_info_dict->GetValueForKeyAsString("name", name_val, nullptr)) { + llvm::StringRef name_val; + if (!reg_info_dict->GetValueForKeyAsString("name", name_val)) { 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(); + reg_info.name = ConstString(name_val).GetCString(); + + llvm::StringRef alt_name_val; + if (reg_info_dict->GetValueForKeyAsString("alt-name", alt_name_val)) + reg_info.alt_name = ConstString(alt_name_val).GetCString(); + else + reg_info.alt_name = nullptr; llvm::Expected<uint32_t> byte_offset = ByteOffsetFromRegInfoDict(i, *reg_info_dict, byte_order); @@ -262,7 +272,7 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, return 0; } - int64_t bitsize = 0; + uint64_t bitsize = 0; if (!reg_info_dict->GetValueForKeyAsInteger("bitsize", bitsize)) { Clear(); printf("error: invalid or missing 'bitsize' key/value pair in register " @@ -296,7 +306,7 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, eEncodingUint); size_t set = 0; - if (!reg_info_dict->GetValueForKeyAsInteger<size_t>("set", set, -1) || + if (!reg_info_dict->GetValueForKeyAsInteger("set", set) || set >= m_sets.size()) { Clear(); printf("error: invalid 'set' value in register dictionary, valid values " @@ -407,7 +417,7 @@ size_t DynamicRegisterInfo::SetRegisterInfo( {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 + nullptr, nullptr, reg.flags_type }; m_regs.push_back(reg_info); diff --git a/lldb/source/Target/ExecutionContext.cpp b/lldb/source/Target/ExecutionContext.cpp index a5288b81cd17..b1563d9ceb71 100644 --- a/lldb/source/Target/ExecutionContext.cpp +++ b/lldb/source/Target/ExecutionContext.cpp @@ -85,7 +85,8 @@ ExecutionContext::ExecutionContext(Target *t, if (m_process_sp) { m_thread_sp = m_process_sp->GetThreadList().GetSelectedThread(); if (m_thread_sp) - m_frame_sp = m_thread_sp->GetSelectedFrame(); + m_frame_sp = + m_thread_sp->GetSelectedFrame(DoNoSelectMostRelevantFrame); } } } @@ -517,7 +518,8 @@ void ExecutionContextRef::SetTargetPtr(Target *target, bool adopt_selected) { if (thread_sp) { SetThreadSP(thread_sp); - lldb::StackFrameSP frame_sp(thread_sp->GetSelectedFrame()); + lldb::StackFrameSP frame_sp( + thread_sp->GetSelectedFrame(DoNoSelectMostRelevantFrame)); if (!frame_sp) frame_sp = thread_sp->GetStackFrameAtIndex(0); if (frame_sp) diff --git a/lldb/source/Target/Language.cpp b/lldb/source/Target/Language.cpp index 892d2a86437e..78785352676d 100644 --- a/lldb/source/Target/Language.cpp +++ b/lldb/source/Target/Language.cpp @@ -194,9 +194,27 @@ struct language_name_pair language_names[] = { {"c++14", eLanguageTypeC_plus_plus_14}, {"fortran03", eLanguageTypeFortran03}, {"fortran08", eLanguageTypeFortran08}, + {"renderscript", eLanguageTypeRenderScript}, + {"bliss", eLanguageTypeBLISS}, + {"kotlin", eLanguageTypeKotlin}, + {"zig", eLanguageTypeZig}, + {"crystal", eLanguageTypeCrystal}, + {"<invalid language>", + static_cast<LanguageType>( + 0x0029)}, // Not yet taken by any language in the DWARF spec + // and thus has no entry in LanguageType + {"c++17", eLanguageTypeC_plus_plus_17}, + {"c++20", eLanguageTypeC_plus_plus_20}, + {"c17", eLanguageTypeC17}, + {"fortran18", eLanguageTypeFortran18}, + {"ada2005", eLanguageTypeAda2005}, + {"ada2012", eLanguageTypeAda2012}, + {"HIP", eLanguageTypeHIP}, + {"assembly", eLanguageTypeAssembly}, + {"c-sharp", eLanguageTypeC_sharp}, + {"mojo", eLanguageTypeMojo}, // Vendor Extensions {"assembler", eLanguageTypeMipsAssembler}, - {"renderscript", eLanguageTypeExtRenderScript}, // Now synonyms, in arbitrary order {"objc", eLanguageTypeObjC}, {"objc++", eLanguageTypeObjC_plus_plus}, @@ -253,6 +271,8 @@ bool Language::LanguageIsCPlusPlus(LanguageType language) { case eLanguageTypeC_plus_plus_03: case eLanguageTypeC_plus_plus_11: case eLanguageTypeC_plus_plus_14: + case eLanguageTypeC_plus_plus_17: + case eLanguageTypeC_plus_plus_20: case eLanguageTypeObjC_plus_plus: return true; default: @@ -292,6 +312,8 @@ bool Language::LanguageIsCFamily(LanguageType language) { case eLanguageTypeC_plus_plus_03: case eLanguageTypeC_plus_plus_11: case eLanguageTypeC_plus_plus_14: + case eLanguageTypeC_plus_plus_17: + case eLanguageTypeC_plus_plus_20: case eLanguageTypeObjC_plus_plus: case eLanguageTypeObjC: return true; @@ -315,6 +337,8 @@ LanguageType Language::GetPrimaryLanguage(LanguageType language) { case eLanguageTypeC_plus_plus_03: case eLanguageTypeC_plus_plus_11: case eLanguageTypeC_plus_plus_14: + case eLanguageTypeC_plus_plus_17: + case eLanguageTypeC_plus_plus_20: return eLanguageTypeC_plus_plus; case eLanguageTypeC: case eLanguageTypeC89: @@ -350,7 +374,6 @@ LanguageType Language::GetPrimaryLanguage(LanguageType language) { case eLanguageTypeJulia: case eLanguageTypeDylan: case eLanguageTypeMipsAssembler: - case eLanguageTypeExtRenderScript: case eLanguageTypeUnknown: default: return language; @@ -432,19 +455,17 @@ bool Language::ImageListTypeScavenger::Find_Impl( return result; } -bool Language::GetFormatterPrefixSuffix(ValueObject &valobj, - ConstString type_hint, - std::string &prefix, - std::string &suffix) { - return false; +std::pair<llvm::StringRef, llvm::StringRef> +Language::GetFormatterPrefixSuffix(llvm::StringRef type_hint) { + return std::pair<llvm::StringRef, llvm::StringRef>(); } -bool Language::DemangledNameContainsPath(llvm::StringRef path, +bool Language::DemangledNameContainsPath(llvm::StringRef path, ConstString demangled) const { // The base implementation does a simple contains comparision: if (path.empty()) return false; - return demangled.GetStringRef().contains(path); + return demangled.GetStringRef().contains(path); } DumpValueObjectOptions::DeclPrintingHelper Language::GetDeclPrintingHelper() { diff --git a/lldb/source/Target/Memory.cpp b/lldb/source/Target/Memory.cpp index d4dedeea7c2c..45786415d23b 100644 --- a/lldb/source/Target/Memory.cpp +++ b/lldb/source/Target/Memory.cpp @@ -123,18 +123,55 @@ bool MemoryCache::RemoveInvalidRange(lldb::addr_t base_addr, return false; } +lldb::DataBufferSP MemoryCache::GetL2CacheLine(lldb::addr_t line_base_addr, + Status &error) { + // This function assumes that the address given is aligned correctly. + assert((line_base_addr % m_L2_cache_line_byte_size) == 0); + + std::lock_guard<std::recursive_mutex> guard(m_mutex); + auto pos = m_L2_cache.find(line_base_addr); + if (pos != m_L2_cache.end()) + return pos->second; + + auto data_buffer_heap_sp = + std::make_shared<DataBufferHeap>(m_L2_cache_line_byte_size, 0); + size_t process_bytes_read = m_process.ReadMemoryFromInferior( + line_base_addr, data_buffer_heap_sp->GetBytes(), + data_buffer_heap_sp->GetByteSize(), error); + + // If we failed a read, not much we can do. + if (process_bytes_read == 0) + return lldb::DataBufferSP(); + + // If we didn't get a complete read, we can still cache what we did get. + if (process_bytes_read < m_L2_cache_line_byte_size) + data_buffer_heap_sp->SetByteSize(process_bytes_read); + + m_L2_cache[line_base_addr] = data_buffer_heap_sp; + return data_buffer_heap_sp; +} + size_t MemoryCache::Read(addr_t addr, void *dst, size_t dst_len, Status &error) { - size_t bytes_left = dst_len; - - // Check the L1 cache for a range that contain the entire memory read. If we - // find a range in the L1 cache that does, we use it. Else we fall back to - // reading memory in m_L2_cache_line_byte_size byte sized chunks. The L1 - // cache contains chunks of memory that are not required to be - // m_L2_cache_line_byte_size bytes in size, so we don't try anything tricky - // when reading from them (no partial reads from the L1 cache). + if (!dst || dst_len == 0) + return 0; std::lock_guard<std::recursive_mutex> guard(m_mutex); + // FIXME: We should do a more thorough check to make sure that we're not + // overlapping with any invalid ranges (e.g. Read 0x100 - 0x200 but there's an + // invalid range 0x180 - 0x280). `FindEntryThatContains` has an implementation + // that takes a range, but it only checks to see if the argument is contained + // by an existing invalid range. It cannot check if the argument contains + // invalid ranges and cannot check for overlaps. + if (m_invalid_ranges.FindEntryThatContains(addr)) { + error.SetErrorStringWithFormat("memory read failed for 0x%" PRIx64, addr); + return 0; + } + + // Check the L1 cache for a range that contains the entire memory read. + // L1 cache contains chunks of memory that are not required to be the size of + // an L2 cache line. We avoid trying to do partial reads from the L1 cache to + // simplify the implementation. if (!m_L1_cache.empty()) { AddrRange read_range(addr, dst_len); BlockMap::iterator pos = m_L1_cache.upper_bound(addr); @@ -149,105 +186,82 @@ size_t MemoryCache::Read(addr_t addr, void *dst, size_t dst_len, } } - // If this memory read request is larger than the cache line size, then we - // (1) try to read as much of it at once as possible, and (2) don't add the - // data to the memory cache. We don't want to split a big read up into more - // separate reads than necessary, and with a large memory read request, it is - // unlikely that the caller function will ask for the next - // 4 bytes after the large memory read - so there's little benefit to saving - // it in the cache. - if (dst && dst_len > m_L2_cache_line_byte_size) { + // If the size of the read is greater than the size of an L2 cache line, we'll + // just read from the inferior. If that read is successful, we'll cache what + // we read in the L1 cache for future use. + if (dst_len > m_L2_cache_line_byte_size) { size_t bytes_read = m_process.ReadMemoryFromInferior(addr, dst, dst_len, error); - // Add this non block sized range to the L1 cache if we actually read - // anything if (bytes_read > 0) AddL1CacheData(addr, dst, bytes_read); return bytes_read; } - if (dst && bytes_left > 0) { - const uint32_t cache_line_byte_size = m_L2_cache_line_byte_size; - uint8_t *dst_buf = (uint8_t *)dst; - addr_t curr_addr = addr - (addr % cache_line_byte_size); - addr_t cache_offset = addr - curr_addr; - - while (bytes_left > 0) { - if (m_invalid_ranges.FindEntryThatContains(curr_addr)) { - error.SetErrorStringWithFormat("memory read failed for 0x%" PRIx64, - curr_addr); - return dst_len - bytes_left; - } - - BlockMap::const_iterator pos = m_L2_cache.find(curr_addr); - BlockMap::const_iterator end = m_L2_cache.end(); - - if (pos != end) { - size_t curr_read_size = cache_line_byte_size - cache_offset; - if (curr_read_size > bytes_left) - curr_read_size = bytes_left; + // If the size of the read fits inside one L2 cache line, we'll try reading + // from the L2 cache. Note that if the range of memory we're reading sits + // between two contiguous cache lines, we'll touch two cache lines instead of + // just one. - memcpy(dst_buf + dst_len - bytes_left, - pos->second->GetBytes() + cache_offset, curr_read_size); + // We're going to have all of our loads and reads be cache line aligned. + addr_t cache_line_offset = addr % m_L2_cache_line_byte_size; + addr_t cache_line_base_addr = addr - cache_line_offset; + DataBufferSP first_cache_line = GetL2CacheLine(cache_line_base_addr, error); + // If we get nothing, then the read to the inferior likely failed. Nothing to + // do here. + if (!first_cache_line) + return 0; - bytes_left -= curr_read_size; - curr_addr += curr_read_size + cache_offset; - cache_offset = 0; + // If the cache line was not filled out completely and the offset is greater + // than what we have available, we can't do anything further here. + if (cache_line_offset >= first_cache_line->GetByteSize()) + return 0; - if (bytes_left > 0) { - // Get sequential cache page hits - for (++pos; (pos != end) && (bytes_left > 0); ++pos) { - assert((curr_addr % cache_line_byte_size) == 0); + uint8_t *dst_buf = (uint8_t *)dst; + size_t bytes_left = dst_len; + size_t read_size = first_cache_line->GetByteSize() - cache_line_offset; + if (read_size > bytes_left) + read_size = bytes_left; - if (pos->first != curr_addr) - break; + memcpy(dst_buf + dst_len - bytes_left, + first_cache_line->GetBytes() + cache_line_offset, read_size); + bytes_left -= read_size; - curr_read_size = pos->second->GetByteSize(); - if (curr_read_size > bytes_left) - curr_read_size = bytes_left; + // If the cache line was not filled out completely and we still have data to + // read, we can't do anything further. + if (first_cache_line->GetByteSize() < m_L2_cache_line_byte_size && + bytes_left > 0) + return dst_len - bytes_left; - memcpy(dst_buf + dst_len - bytes_left, pos->second->GetBytes(), - curr_read_size); + // We'll hit this scenario if our read straddles two cache lines. + if (bytes_left > 0) { + cache_line_base_addr += m_L2_cache_line_byte_size; - bytes_left -= curr_read_size; - curr_addr += curr_read_size; + // FIXME: Until we are able to more thoroughly check for invalid ranges, we + // will have to check the second line to see if it is in an invalid range as + // well. See the check near the beginning of the function for more details. + if (m_invalid_ranges.FindEntryThatContains(cache_line_base_addr)) { + error.SetErrorStringWithFormat("memory read failed for 0x%" PRIx64, + cache_line_base_addr); + return dst_len - bytes_left; + } - // We have a cache page that succeeded to read some bytes but not - // an entire page. If this happens, we must cap off how much data - // we are able to read... - if (pos->second->GetByteSize() != cache_line_byte_size) - return dst_len - bytes_left; - } - } - } + DataBufferSP second_cache_line = + GetL2CacheLine(cache_line_base_addr, error); + if (!second_cache_line) + return dst_len - bytes_left; - // We need to read from the process + read_size = bytes_left; + if (read_size > second_cache_line->GetByteSize()) + read_size = second_cache_line->GetByteSize(); - if (bytes_left > 0) { - assert((curr_addr % cache_line_byte_size) == 0); - std::unique_ptr<DataBufferHeap> data_buffer_heap_up( - new DataBufferHeap(cache_line_byte_size, 0)); - size_t process_bytes_read = m_process.ReadMemoryFromInferior( - curr_addr, data_buffer_heap_up->GetBytes(), - data_buffer_heap_up->GetByteSize(), error); - if (process_bytes_read == 0) - return dst_len - bytes_left; + memcpy(dst_buf + dst_len - bytes_left, second_cache_line->GetBytes(), + read_size); + bytes_left -= read_size; - if (process_bytes_read != cache_line_byte_size) { - if (process_bytes_read < data_buffer_heap_up->GetByteSize()) { - dst_len -= data_buffer_heap_up->GetByteSize() - process_bytes_read; - bytes_left = process_bytes_read; - } - data_buffer_heap_up->SetByteSize(process_bytes_read); - } - m_L2_cache[curr_addr] = DataBufferSP(data_buffer_heap_up.release()); - // We have read data and put it into the cache, continue through the - // loop again to get the data out of the cache... - } - } + return dst_len - bytes_left; } - return dst_len - bytes_left; + return dst_len; } AllocatedBlock::AllocatedBlock(lldb::addr_t addr, uint32_t byte_size, diff --git a/lldb/source/Target/PathMappingList.cpp b/lldb/source/Target/PathMappingList.cpp index 13bb50b362c6..c369018122a5 100644 --- a/lldb/source/Target/PathMappingList.cpp +++ b/lldb/source/Target/PathMappingList.cpp @@ -48,6 +48,7 @@ PathMappingList::PathMappingList(const PathMappingList &rhs) const PathMappingList &PathMappingList::operator=(const PathMappingList &rhs) { if (this != &rhs) { + std::scoped_lock<std::recursive_mutex, std::recursive_mutex> locks(m_mutex, rhs.m_mutex); m_pairs = rhs.m_pairs; m_callback = nullptr; m_callback_baton = nullptr; @@ -60,6 +61,7 @@ PathMappingList::~PathMappingList() = default; void PathMappingList::Append(llvm::StringRef path, llvm::StringRef replacement, bool notify) { + std::lock_guard<std::recursive_mutex> lock(m_mutex); ++m_mod_id; m_pairs.emplace_back(pair(NormalizePath(path), NormalizePath(replacement))); if (notify && m_callback) @@ -67,6 +69,7 @@ void PathMappingList::Append(llvm::StringRef path, llvm::StringRef replacement, } void PathMappingList::Append(const PathMappingList &rhs, bool notify) { + std::scoped_lock<std::recursive_mutex, std::recursive_mutex> locks(m_mutex, rhs.m_mutex); ++m_mod_id; if (!rhs.m_pairs.empty()) { const_iterator pos, end = rhs.m_pairs.end(); @@ -81,6 +84,7 @@ bool PathMappingList::AppendUnique(llvm::StringRef path, llvm::StringRef replacement, bool notify) { auto normalized_path = NormalizePath(path); auto normalized_replacement = NormalizePath(replacement); + std::lock_guard<std::recursive_mutex> lock(m_mutex); for (const auto &pair : m_pairs) { if (pair.first.GetStringRef().equals(normalized_path) && pair.second.GetStringRef().equals(normalized_replacement)) @@ -92,6 +96,7 @@ bool PathMappingList::AppendUnique(llvm::StringRef path, void PathMappingList::Insert(llvm::StringRef path, llvm::StringRef replacement, uint32_t index, bool notify) { + std::lock_guard<std::recursive_mutex> lock(m_mutex); ++m_mod_id; iterator insert_iter; if (index >= m_pairs.size()) @@ -106,6 +111,7 @@ void PathMappingList::Insert(llvm::StringRef path, llvm::StringRef replacement, bool PathMappingList::Replace(llvm::StringRef path, llvm::StringRef replacement, uint32_t index, bool notify) { + std::lock_guard<std::recursive_mutex> lock(m_mutex); if (index >= m_pairs.size()) return false; ++m_mod_id; @@ -116,6 +122,7 @@ bool PathMappingList::Replace(llvm::StringRef path, llvm::StringRef replacement, } bool PathMappingList::Remove(size_t index, bool notify) { + std::lock_guard<std::recursive_mutex> lock(m_mutex); if (index >= m_pairs.size()) return false; @@ -130,6 +137,7 @@ bool PathMappingList::Remove(size_t index, bool notify) { // For clients which do not need the pair index dumped, pass a pair_index >= 0 // to only dump the indicated pair. void PathMappingList::Dump(Stream *s, int pair_index) { + std::lock_guard<std::recursive_mutex> lock(m_mutex); unsigned int numPairs = m_pairs.size(); if (pair_index < 0) { @@ -147,6 +155,7 @@ void PathMappingList::Dump(Stream *s, int pair_index) { llvm::json::Value PathMappingList::ToJSON() { llvm::json::Array entries; + std::lock_guard<std::recursive_mutex> lock(m_mutex); for (const auto &pair : m_pairs) { llvm::json::Array entry{pair.first.GetStringRef().str(), pair.second.GetStringRef().str()}; @@ -156,6 +165,7 @@ llvm::json::Value PathMappingList::ToJSON() { } void PathMappingList::Clear(bool notify) { + std::lock_guard<std::recursive_mutex> lock(m_mutex); if (!m_pairs.empty()) ++m_mod_id; m_pairs.clear(); @@ -186,6 +196,7 @@ static void AppendPathComponents(FileSpec &path, llvm::StringRef components, std::optional<FileSpec> PathMappingList::RemapPath(llvm::StringRef mapping_path, bool only_if_exists) const { + std::lock_guard<std::recursive_mutex> lock(m_mutex); if (m_pairs.empty() || mapping_path.empty()) return {}; LazyBool path_is_relative = eLazyBoolCalculate; @@ -224,6 +235,7 @@ std::optional<llvm::StringRef> PathMappingList::ReverseRemapPath(const FileSpec &file, FileSpec &fixed) const { std::string path = file.GetPath(); llvm::StringRef path_ref(path); + std::lock_guard<std::recursive_mutex> lock(m_mutex); for (const auto &it : m_pairs) { llvm::StringRef removed_prefix = it.second.GetStringRef(); if (!path_ref.consume_front(it.second.GetStringRef())) @@ -252,6 +264,7 @@ PathMappingList::FindFile(const FileSpec &orig_spec) const { bool PathMappingList::Replace(llvm::StringRef path, llvm::StringRef new_path, bool notify) { + std::lock_guard<std::recursive_mutex> lock(m_mutex); uint32_t idx = FindIndexForPath(path); if (idx < m_pairs.size()) { ++m_mod_id; @@ -264,6 +277,7 @@ bool PathMappingList::Replace(llvm::StringRef path, llvm::StringRef new_path, } bool PathMappingList::Remove(ConstString path, bool notify) { + std::lock_guard<std::recursive_mutex> lock(m_mutex); iterator pos = FindIteratorForPath(path); if (pos != m_pairs.end()) { ++m_mod_id; @@ -277,6 +291,7 @@ bool PathMappingList::Remove(ConstString path, bool notify) { PathMappingList::const_iterator PathMappingList::FindIteratorForPath(ConstString path) const { + std::lock_guard<std::recursive_mutex> lock(m_mutex); const_iterator pos; const_iterator begin = m_pairs.begin(); const_iterator end = m_pairs.end(); @@ -290,6 +305,7 @@ PathMappingList::FindIteratorForPath(ConstString path) const { PathMappingList::iterator PathMappingList::FindIteratorForPath(ConstString path) { + std::lock_guard<std::recursive_mutex> lock(m_mutex); iterator pos; iterator begin = m_pairs.begin(); iterator end = m_pairs.end(); @@ -303,6 +319,7 @@ PathMappingList::FindIteratorForPath(ConstString path) { bool PathMappingList::GetPathsAtIndex(uint32_t idx, ConstString &path, ConstString &new_path) const { + std::lock_guard<std::recursive_mutex> lock(m_mutex); if (idx < m_pairs.size()) { path = m_pairs[idx].first; new_path = m_pairs[idx].second; @@ -313,6 +330,7 @@ bool PathMappingList::GetPathsAtIndex(uint32_t idx, ConstString &path, uint32_t PathMappingList::FindIndexForPath(llvm::StringRef orig_path) const { const ConstString path = ConstString(NormalizePath(orig_path)); + std::lock_guard<std::recursive_mutex> lock(m_mutex); 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 1ddd7596280e..11a123fb6d58 100644 --- a/lldb/source/Target/Platform.cpp +++ b/lldb/source/Target/Platform.cpp @@ -99,29 +99,27 @@ PlatformProperties::PlatformProperties() { bool PlatformProperties::GetUseModuleCache() const { const auto idx = ePropertyUseModuleCache; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_platform_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_platform_properties[idx].default_uint_value != 0); } bool PlatformProperties::SetUseModuleCache(bool use_module_cache) { - return m_collection_sp->SetPropertyAtIndexAsBoolean( - nullptr, ePropertyUseModuleCache, use_module_cache); + return SetPropertyAtIndex(ePropertyUseModuleCache, use_module_cache); } FileSpec PlatformProperties::GetModuleCacheDirectory() const { - return m_collection_sp->GetPropertyAtIndexAsFileSpec( - nullptr, ePropertyModuleCacheDirectory); + return GetPropertyAtIndexAs<FileSpec>(ePropertyModuleCacheDirectory, {}); } bool PlatformProperties::SetModuleCacheDirectory(const FileSpec &dir_spec) { - return m_collection_sp->SetPropertyAtIndexAsFileSpec( - nullptr, ePropertyModuleCacheDirectory, dir_spec); + return m_collection_sp->SetPropertyAtIndex(ePropertyModuleCacheDirectory, + dir_spec); } void PlatformProperties::SetDefaultModuleCacheDirectory( const FileSpec &dir_spec) { auto f_spec_opt = m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpec( - nullptr, false, ePropertyModuleCacheDirectory); + ePropertyModuleCacheDirectory); assert(f_spec_opt); f_spec_opt->SetDefaultValue(dir_spec); } @@ -160,7 +158,7 @@ Status Platform::GetFileWithUUID(const FileSpec &platform_file, FileSpecList Platform::LocateExecutableScriptingResources(Target *target, Module &module, - Stream *feedback_stream) { + Stream &feedback_stream) { return FileSpecList(); } @@ -212,11 +210,10 @@ Status Platform::GetSharedModule( Status error(eErrorTypeGeneric); ModuleSpec resolved_spec; // Check if we have sysroot set. - if (m_sdk_sysroot) { + if (!m_sdk_sysroot.empty()) { // Prepend sysroot to module spec. resolved_spec = spec; - resolved_spec.GetFileSpec().PrependPathComponent( - m_sdk_sysroot.GetStringRef()); + resolved_spec.GetFileSpec().PrependPathComponent(m_sdk_sysroot); // Try to get shared module with resolved spec. error = ModuleList::GetSharedModule(resolved_spec, module_sp, module_search_paths_ptr, old_modules, @@ -314,9 +311,9 @@ void Platform::GetStatus(Stream &strm) { strm.Printf(" Connected: %s\n", is_connected ? "yes" : "no"); } - if (GetSDKRootDirectory()) { - strm.Format(" Sysroot: {0}\n", GetSDKRootDirectory()); - } + if (const std::string &sdk_root = GetSDKRootDirectory(); !sdk_root.empty()) + strm.Format(" Sysroot: {0}\n", sdk_root); + if (GetWorkingDirectory()) { strm.Printf("WorkingDir: %s\n", GetWorkingDirectory().GetPath().c_str()); } @@ -435,7 +432,7 @@ RecurseCopy_Callback(void *baton, llvm::sys::fs::file_type ft, // make the new directory and get in there FileSpec dst_dir = rc_baton->dst; if (!dst_dir.GetFilename()) - dst_dir.SetFilename(src.GetLastPathComponent()); + dst_dir.SetFilename(src.GetFilename()); Status error = rc_baton->platform_ptr->MakeDirectory( dst_dir, lldb::eFilePermissionsDirectoryDefault); if (error.Fail()) { @@ -1063,7 +1060,7 @@ lldb::ProcessSP Platform::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, Target &target, Status &error) { Log *log = GetLog(LLDBLog::Platform); - LLDB_LOG(log, "target = {0})", &target); + LLDB_LOG(log, "target = {0}", &target); ProcessSP process_sp; // Make sure we stop at the entry point @@ -1633,7 +1630,7 @@ Status Platform::DownloadModuleSlice(const FileSpec &src_file_spec, return error; } - std::vector<char> buffer(1024); + std::vector<char> buffer(512 * 1024); auto offset = src_offset; uint64_t total_bytes_read = 0; while (total_bytes_read < src_size) { @@ -1815,8 +1812,9 @@ lldb::ProcessSP Platform::DoConnectProcess(llvm::StringRef connect_url, nullptr); process_sp->RestoreProcessEvents(); bool pop_process_io_handler = false; - Process::HandleProcessStateChangedEvent(event_sp, stream, - pop_process_io_handler); + // This is a user-level stop, so we allow recognizers to select frames. + Process::HandleProcessStateChangedEvent( + event_sp, stream, SelectMostRelevantFrame, pop_process_io_handler); } return process_sp; @@ -1895,6 +1893,12 @@ size_t Platform::GetSoftwareBreakpointTrapOpcode(Target &target, trap_opcode_size = sizeof(g_hex_opcode); } break; + case llvm::Triple::msp430: { + static const uint8_t g_msp430_opcode[] = {0x43, 0x43}; + trap_opcode = g_msp430_opcode; + trap_opcode_size = sizeof(g_msp430_opcode); + } break; + case llvm::Triple::systemz: { static const uint8_t g_hex_opcode[] = {0x00, 0x01}; trap_opcode = g_hex_opcode; @@ -1967,6 +1971,14 @@ Args Platform::GetExtraStartupCommands() { return {}; } +void Platform::SetLocateModuleCallback(LocateModuleCallback callback) { + m_locate_module_callback = callback; +} + +Platform::LocateModuleCallback Platform::GetLocateModuleCallback() const { + return m_locate_module_callback; +} + PlatformSP PlatformList::GetOrCreate(llvm::StringRef name) { std::lock_guard<std::recursive_mutex> guard(m_mutex); for (const PlatformSP &platform_sp : m_platforms) { diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index e0cca0595ee3..05ddbbd146a2 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -92,9 +92,9 @@ class ProcessOptionValueProperties public: ProcessOptionValueProperties(ConstString name) : Cloneable(name) {} - const Property *GetPropertyAtIndex(const ExecutionContext *exe_ctx, - bool will_modify, - uint32_t idx) const override { + const Property * + GetPropertyAtIndex(size_t idx, + const ExecutionContext *exe_ctx) const override { // When getting the value for a key from the process options, we will // always try and grab the setting from the current process if there is // one. Else we just use the one from this instance. @@ -167,8 +167,8 @@ ProcessProperties::ProcessProperties(lldb_private::Process *process) std::make_shared<ProcessOptionValueProperties>(ConstString("process")); m_collection_sp->Initialize(g_process_properties); m_collection_sp->AppendProperty( - ConstString("thread"), ConstString("Settings specific to threads."), - true, Thread::GetGlobalProperties().GetValueProperties()); + "thread", "Settings specific to threads.", true, + Thread::GetGlobalProperties().GetValueProperties()); } else { m_collection_sp = OptionValueProperties::CreateLocalCopy(Process::GetGlobalProperties()); @@ -180,9 +180,9 @@ ProcessProperties::ProcessProperties(lldb_private::Process *process) m_experimental_properties_up = std::make_unique<ProcessExperimentalProperties>(); m_collection_sp->AppendProperty( - ConstString(Properties::GetExperimentalSettingsName()), - ConstString("Experimental settings - setting these won't produce " - "errors if the setting is not present."), + Properties::GetExperimentalSettingsName(), + "Experimental settings - setting these won't produce " + "errors if the setting is not present.", true, m_experimental_properties_up->GetValueProperties()); } @@ -190,169 +190,183 @@ ProcessProperties::~ProcessProperties() = default; bool ProcessProperties::GetDisableMemoryCache() const { const uint32_t idx = ePropertyDisableMemCache; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_process_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_process_properties[idx].default_uint_value != 0); } uint64_t ProcessProperties::GetMemoryCacheLineSize() const { const uint32_t idx = ePropertyMemCacheLineSize; - return m_collection_sp->GetPropertyAtIndexAsUInt64( - nullptr, idx, g_process_properties[idx].default_uint_value); + return GetPropertyAtIndexAs<uint64_t>( + idx, g_process_properties[idx].default_uint_value); } Args ProcessProperties::GetExtraStartupCommands() const { Args args; const uint32_t idx = ePropertyExtraStartCommand; - m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, idx, args); + m_collection_sp->GetPropertyAtIndexAsArgs(idx, args); return args; } void ProcessProperties::SetExtraStartupCommands(const Args &args) { const uint32_t idx = ePropertyExtraStartCommand; - m_collection_sp->SetPropertyAtIndexFromArgs(nullptr, idx, args); + m_collection_sp->SetPropertyAtIndexFromArgs(idx, args); } FileSpec ProcessProperties::GetPythonOSPluginPath() const { const uint32_t idx = ePropertyPythonOSPluginPath; - return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx); + return GetPropertyAtIndexAs<FileSpec>(idx, {}); } uint32_t ProcessProperties::GetVirtualAddressableBits() const { const uint32_t idx = ePropertyVirtualAddressableBits; - return m_collection_sp->GetPropertyAtIndexAsUInt64( - nullptr, idx, g_process_properties[idx].default_uint_value); + return GetPropertyAtIndexAs<uint64_t>( + idx, g_process_properties[idx].default_uint_value); } void ProcessProperties::SetVirtualAddressableBits(uint32_t bits) { const uint32_t idx = ePropertyVirtualAddressableBits; - m_collection_sp->SetPropertyAtIndexAsUInt64(nullptr, idx, bits); + SetPropertyAtIndex(idx, static_cast<uint64_t>(bits)); } + +uint32_t ProcessProperties::GetHighmemVirtualAddressableBits() const { + const uint32_t idx = ePropertyHighmemVirtualAddressableBits; + return GetPropertyAtIndexAs<uint64_t>( + idx, g_process_properties[idx].default_uint_value); +} + +void ProcessProperties::SetHighmemVirtualAddressableBits(uint32_t bits) { + const uint32_t idx = ePropertyHighmemVirtualAddressableBits; + SetPropertyAtIndex(idx, static_cast<uint64_t>(bits)); +} + void ProcessProperties::SetPythonOSPluginPath(const FileSpec &file) { const uint32_t idx = ePropertyPythonOSPluginPath; - m_collection_sp->SetPropertyAtIndexAsFileSpec(nullptr, idx, file); + SetPropertyAtIndex(idx, file); } bool ProcessProperties::GetIgnoreBreakpointsInExpressions() const { const uint32_t idx = ePropertyIgnoreBreakpointsInExpressions; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_process_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_process_properties[idx].default_uint_value != 0); } void ProcessProperties::SetIgnoreBreakpointsInExpressions(bool ignore) { const uint32_t idx = ePropertyIgnoreBreakpointsInExpressions; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, ignore); + SetPropertyAtIndex(idx, ignore); } bool ProcessProperties::GetUnwindOnErrorInExpressions() const { const uint32_t idx = ePropertyUnwindOnErrorInExpressions; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_process_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_process_properties[idx].default_uint_value != 0); } void ProcessProperties::SetUnwindOnErrorInExpressions(bool ignore) { const uint32_t idx = ePropertyUnwindOnErrorInExpressions; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, ignore); + SetPropertyAtIndex(idx, ignore); } bool ProcessProperties::GetStopOnSharedLibraryEvents() const { const uint32_t idx = ePropertyStopOnSharedLibraryEvents; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_process_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_process_properties[idx].default_uint_value != 0); } void ProcessProperties::SetStopOnSharedLibraryEvents(bool stop) { const uint32_t idx = ePropertyStopOnSharedLibraryEvents; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, stop); + SetPropertyAtIndex(idx, stop); } bool ProcessProperties::GetDisableLangRuntimeUnwindPlans() const { const uint32_t idx = ePropertyDisableLangRuntimeUnwindPlans; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_process_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_process_properties[idx].default_uint_value != 0); } void ProcessProperties::SetDisableLangRuntimeUnwindPlans(bool disable) { const uint32_t idx = ePropertyDisableLangRuntimeUnwindPlans; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, disable); + SetPropertyAtIndex(idx, disable); m_process->Flush(); } bool ProcessProperties::GetDetachKeepsStopped() const { const uint32_t idx = ePropertyDetachKeepsStopped; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_process_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_process_properties[idx].default_uint_value != 0); } void ProcessProperties::SetDetachKeepsStopped(bool stop) { const uint32_t idx = ePropertyDetachKeepsStopped; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, stop); + SetPropertyAtIndex(idx, stop); } bool ProcessProperties::GetWarningsOptimization() const { const uint32_t idx = ePropertyWarningOptimization; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_process_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_process_properties[idx].default_uint_value != 0); } bool ProcessProperties::GetWarningsUnsupportedLanguage() const { const uint32_t idx = ePropertyWarningUnsupportedLanguage; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_process_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_process_properties[idx].default_uint_value != 0); } bool ProcessProperties::GetStopOnExec() const { const uint32_t idx = ePropertyStopOnExec; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_process_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_process_properties[idx].default_uint_value != 0); } std::chrono::seconds ProcessProperties::GetUtilityExpressionTimeout() const { const uint32_t idx = ePropertyUtilityExpressionTimeout; - uint64_t value = m_collection_sp->GetPropertyAtIndexAsUInt64( - nullptr, idx, g_process_properties[idx].default_uint_value); + uint64_t value = GetPropertyAtIndexAs<uint64_t>( + idx, g_process_properties[idx].default_uint_value); return std::chrono::seconds(value); } std::chrono::seconds ProcessProperties::GetInterruptTimeout() const { const uint32_t idx = ePropertyInterruptTimeout; - uint64_t value = m_collection_sp->GetPropertyAtIndexAsUInt64( - nullptr, idx, g_process_properties[idx].default_uint_value); + uint64_t value = GetPropertyAtIndexAs<uint64_t>( + idx, g_process_properties[idx].default_uint_value); return std::chrono::seconds(value); } bool ProcessProperties::GetSteppingRunsAllThreads() const { const uint32_t idx = ePropertySteppingRunsAllThreads; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_process_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_process_properties[idx].default_uint_value != 0); } bool ProcessProperties::GetOSPluginReportsAllThreads() const { const bool fail_value = true; const Property *exp_property = - m_collection_sp->GetPropertyAtIndex(nullptr, true, ePropertyExperimental); + m_collection_sp->GetPropertyAtIndex(ePropertyExperimental); OptionValueProperties *exp_values = exp_property->GetValue()->GetAsProperties(); if (!exp_values) return fail_value; - return exp_values->GetPropertyAtIndexAsBoolean( - nullptr, ePropertyOSPluginReportsAllThreads, fail_value); + return exp_values + ->GetPropertyAtIndexAs<bool>(ePropertyOSPluginReportsAllThreads) + .value_or(fail_value); } void ProcessProperties::SetOSPluginReportsAllThreads(bool does_report) { const Property *exp_property = - m_collection_sp->GetPropertyAtIndex(nullptr, true, ePropertyExperimental); + m_collection_sp->GetPropertyAtIndex(ePropertyExperimental); OptionValueProperties *exp_values = exp_property->GetValue()->GetAsProperties(); if (exp_values) - exp_values->SetPropertyAtIndexAsBoolean( - nullptr, ePropertyOSPluginReportsAllThreads, does_report); + exp_values->SetPropertyAtIndex(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); + return GetPropertyAtIndexAs<FollowForkMode>( + idx, static_cast<FollowForkMode>( + g_process_properties[idx].default_uint_value)); } ProcessSP Process::FindPlugin(lldb::TargetSP target_sp, @@ -402,8 +416,7 @@ ConstString &Process::GetStaticBroadcasterClass() { } Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp) - : Process(target_sp, listener_sp, - UnixSignals::Create(HostInfo::GetArchitecture())) { + : Process(target_sp, listener_sp, UnixSignals::CreateForHost()) { // This constructor just delegates to the full Process constructor, // defaulting to using the Host's UnixSignals. } @@ -480,13 +493,12 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp, // Allow the platform to override the default cache line size OptionValueSP value_sp = - m_collection_sp - ->GetPropertyAtIndex(nullptr, true, ePropertyMemCacheLineSize) + m_collection_sp->GetPropertyAtIndex(ePropertyMemCacheLineSize) ->GetValue(); - uint32_t platform_cache_line_size = + uint64_t platform_cache_line_size = target_sp->GetPlatform()->GetDefaultMemoryCacheLineSize(); if (!value_sp->OptionWasSet() && platform_cache_line_size != 0) - value_sp->SetUInt64Value(platform_cache_line_size); + value_sp->SetValueAs(platform_cache_line_size); RegisterAssertFrameRecognizer(this); } @@ -645,10 +657,10 @@ void Process::SyncIOHandler(uint32_t iohandler_id, } } -StateType Process::WaitForProcessToStop(const Timeout<std::micro> &timeout, - EventSP *event_sp_ptr, bool wait_always, - ListenerSP hijack_listener_sp, - Stream *stream, bool use_run_lock) { +StateType Process::WaitForProcessToStop( + const Timeout<std::micro> &timeout, EventSP *event_sp_ptr, bool wait_always, + ListenerSP hijack_listener_sp, Stream *stream, bool use_run_lock, + SelectMostRelevant select_most_relevant) { // We can't just wait for a "stopped" event, because the stopped event may // have restarted the target. We have to actually check each event, and in // the case of a stopped event check the restarted flag on the event. @@ -683,8 +695,8 @@ StateType Process::WaitForProcessToStop(const Timeout<std::micro> &timeout, *event_sp_ptr = event_sp; bool pop_process_io_handler = (hijack_listener_sp.get() != nullptr); - Process::HandleProcessStateChangedEvent(event_sp, stream, - pop_process_io_handler); + Process::HandleProcessStateChangedEvent( + event_sp, stream, select_most_relevant, pop_process_io_handler); switch (state) { case eStateCrashed: @@ -713,9 +725,10 @@ StateType Process::WaitForProcessToStop(const Timeout<std::micro> &timeout, return state; } -bool Process::HandleProcessStateChangedEvent(const EventSP &event_sp, - Stream *stream, - bool &pop_process_io_handler) { +bool Process::HandleProcessStateChangedEvent( + const EventSP &event_sp, Stream *stream, + SelectMostRelevant select_most_relevant, + bool &pop_process_io_handler) { const bool handle_pop = pop_process_io_handler; pop_process_io_handler = false; @@ -897,7 +910,8 @@ bool Process::HandleProcessStateChangedEvent(const EventSP &event_sp, return false; const bool only_threads_with_stop_reason = true; - const uint32_t start_frame = thread_sp->GetSelectedFrameIndex(); + const uint32_t start_frame = + thread_sp->GetSelectedFrameIndex(select_most_relevant); const uint32_t num_frames = 1; const uint32_t num_frames_with_source = 1; const bool stop_format = true; @@ -1054,14 +1068,16 @@ bool Process::SetExitStatus(int status, const char *cstr) { std::lock_guard<std::mutex> guard(m_exit_status_mutex); Log *log(GetLog(LLDBLog::State | LLDBLog::Process)); - LLDB_LOGF( - log, "Process::SetExitStatus (status=%i (0x%8.8x), description=%s%s%s)", - status, status, cstr ? "\"" : "", cstr ? cstr : "NULL", cstr ? "\"" : ""); + LLDB_LOGF(log, "(plugin = %s status=%i (0x%8.8x), description=%s%s%s)", + GetPluginName().data(), status, status, cstr ? "\"" : "", + cstr ? cstr : "NULL", cstr ? "\"" : ""); // We were already in the exited state if (m_private_state.GetValue() == eStateExited) { - LLDB_LOGF(log, "Process::SetExitStatus () ignoring exit status because " - "state was already set to eStateExited"); + LLDB_LOGF(log, + "(plugin = %s) ignoring exit status because state was already set " + "to eStateExited", + GetPluginName().data()); return false; } @@ -1313,8 +1329,8 @@ void Process::SetPublicState(StateType new_state, bool restarted) { } Log *log(GetLog(LLDBLog::State | LLDBLog::Process)); - LLDB_LOGF(log, "Process::SetPublicState (state = %s, restarted = %i)", - StateAsCString(new_state), restarted); + LLDB_LOGF(log, "(plugin = %s, state = %s, restarted = %i)", + GetPluginName().data(), StateAsCString(new_state), restarted); const StateType old_state = m_public_state.GetValue(); m_public_state.SetValue(new_state); @@ -1324,15 +1340,15 @@ void Process::SetPublicState(StateType new_state, bool restarted) { if (!StateChangedIsExternallyHijacked()) { if (new_state == eStateDetached) { LLDB_LOGF(log, - "Process::SetPublicState (%s) -- unlocking run lock for detach", - StateAsCString(new_state)); + "(plugin = %s, state = %s) -- unlocking run lock for detach", + GetPluginName().data(), StateAsCString(new_state)); m_public_run_lock.SetStopped(); } else { const bool old_state_is_stopped = StateIsStoppedState(old_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", - StateAsCString(new_state)); + LLDB_LOGF(log, "(plugin = %s, state = %s) -- unlocking run lock", + GetPluginName().data(), StateAsCString(new_state)); m_public_run_lock.SetStopped(); } } @@ -1342,10 +1358,11 @@ void Process::SetPublicState(StateType new_state, bool restarted) { Status Process::Resume() { Log *log(GetLog(LLDBLog::State | LLDBLog::Process)); - LLDB_LOGF(log, "Process::Resume -- locking run lock"); + LLDB_LOGF(log, "(plugin = %s) -- locking run lock", GetPluginName().data()); if (!m_public_run_lock.TrySetRunning()) { Status error("Resume request failed - process still running."); - LLDB_LOGF(log, "Process::Resume: -- TrySetRunning failed, not resuming."); + LLDB_LOGF(log, "(plugin = %s) -- TrySetRunning failed, not resuming.", + GetPluginName().data()); return error; } Status error = PrivateResume(); @@ -1356,8 +1373,6 @@ Status Process::Resume() { return error; } -static const char *g_resume_sync_name = "lldb.Process.ResumeSynchronous.hijack"; - Status Process::ResumeSynchronous(Stream *stream) { Log *log(GetLog(LLDBLog::State | LLDBLog::Process)); LLDB_LOGF(log, "Process::ResumeSynchronous -- locking run lock"); @@ -1368,13 +1383,14 @@ Status Process::ResumeSynchronous(Stream *stream) { } ListenerSP listener_sp( - Listener::MakeListener(g_resume_sync_name)); + Listener::MakeListener(ResumeSynchronousHijackListenerName.data())); HijackProcessEvents(listener_sp); Status error = PrivateResume(); if (error.Success()) { StateType state = - WaitForProcessToStop(std::nullopt, nullptr, true, listener_sp, stream); + WaitForProcessToStop(std::nullopt, nullptr, true, listener_sp, stream, + true /* use_run_lock */, SelectMostRelevantFrame); const bool must_be_alive = false; // eStateExited is ok, so this must be false if (!StateIsStoppedState(state, must_be_alive)) @@ -1394,9 +1410,8 @@ Status Process::ResumeSynchronous(Stream *stream) { bool Process::StateChangedIsExternallyHijacked() { if (IsHijackedForEvent(eBroadcastBitStateChanged)) { - const char *hijacking_name = GetHijackingListenerName(); - if (hijacking_name && - strcmp(hijacking_name, g_resume_sync_name)) + llvm::StringRef hijacking_name = GetHijackingListenerName(); + if (!hijacking_name.starts_with("lldb.internal")) return true; } return false; @@ -1404,9 +1419,8 @@ bool Process::StateChangedIsExternallyHijacked() { bool Process::StateChangedIsHijackedForSynchronousResume() { if (IsHijackedForEvent(eBroadcastBitStateChanged)) { - const char *hijacking_name = GetHijackingListenerName(); - if (hijacking_name && - strcmp(hijacking_name, g_resume_sync_name) == 0) + llvm::StringRef hijacking_name = GetHijackingListenerName(); + if (hijacking_name == ResumeSynchronousHijackListenerName) return true; } return false; @@ -1421,7 +1435,8 @@ void Process::SetPrivateState(StateType new_state) { Log *log(GetLog(LLDBLog::State | LLDBLog::Process | LLDBLog::Unwind)); bool state_changed = false; - LLDB_LOGF(log, "Process::SetPrivateState (%s)", StateAsCString(new_state)); + LLDB_LOGF(log, "(plugin = %s, state = %s)", GetPluginName().data(), + StateAsCString(new_state)); std::lock_guard<std::recursive_mutex> thread_guard(m_thread_list.GetMutex()); std::lock_guard<std::recursive_mutex> guard(m_private_state.GetMutex()); @@ -1462,15 +1477,15 @@ void Process::SetPrivateState(StateType new_state) { if (!m_mod_id.IsLastResumeForUserExpression()) m_mod_id.SetStopEventForLastNaturalStopID(event_sp); m_memory_cache.Clear(); - LLDB_LOGF(log, "Process::SetPrivateState (%s) stop_id = %u", - StateAsCString(new_state), m_mod_id.GetStopID()); + LLDB_LOGF(log, "(plugin = %s, state = %s, stop_id = %u", + GetPluginName().data(), StateAsCString(new_state), + m_mod_id.GetStopID()); } m_private_state_broadcaster.BroadcastEvent(event_sp); } else { - LLDB_LOGF(log, - "Process::SetPrivateState (%s) state didn't change. Ignoring...", - StateAsCString(new_state)); + LLDB_LOGF(log, "(plugin = %s, state = %s) state didn't change. Ignoring...", + GetPluginName().data(), StateAsCString(new_state)); } } @@ -2355,6 +2370,23 @@ Status Process::DeallocateMemory(addr_t ptr) { return error; } +bool Process::GetWatchpointReportedAfter() { + if (std::optional<bool> subclass_override = DoGetWatchpointReportedAfter()) + return *subclass_override; + + bool reported_after = true; + const ArchSpec &arch = GetTarget().GetArchitecture(); + if (!arch.IsValid()) + return reported_after; + llvm::Triple triple = arch.GetTriple(); + + if (triple.isMIPS() || triple.isPPC64() || triple.isRISCV() || + triple.isAArch64() || triple.isArmMClass() || triple.isARM()) + reported_after = false; + + return reported_after; +} + ModuleSP Process::ReadModuleFromMemory(const FileSpec &file_spec, lldb::addr_t header_addr, size_t size_to_read) { @@ -2435,6 +2467,7 @@ Process::WaitForProcessStopPrivate(EventSP &event_sp, } void Process::LoadOperatingSystemPlugin(bool flush) { + std::lock_guard<std::recursive_mutex> guard(m_thread_mutex); if (flush) m_thread_list.Clear(); m_os_up.reset(OperatingSystem::FindPlugin(this, nullptr)); @@ -2495,7 +2528,7 @@ Status Process::LaunchPrivate(ProcessLaunchInfo &launch_info, StateType &state, FileSpec exe_spec_to_use; if (!exe_module) { - if (!launch_info.GetExecutableFile()) { + if (!launch_info.GetExecutableFile() && !launch_info.IsScriptedProcess()) { error.SetErrorString("executable module does not exist"); return error; } @@ -2637,7 +2670,8 @@ Status Process::LoadCore() { // Wait for a stopped event since we just posted one above... lldb::EventSP event_sp; StateType state = - WaitForProcessToStop(std::nullopt, &event_sp, true, listener_sp); + WaitForProcessToStop(std::nullopt, &event_sp, true, listener_sp, + nullptr, true, SelectMostRelevantFrame); if (!StateIsStoppedState(state, false)) { Log *log = GetLog(LLDBLog::Process); @@ -3142,9 +3176,13 @@ Status Process::Halt(bool clear_thread_plans, bool use_run_lock) { } // Wait for the process halt timeout seconds for the process to stop. - StateType state = - WaitForProcessToStop(GetInterruptTimeout(), &event_sp, true, - halt_listener_sp, nullptr, use_run_lock); + // If we are going to use the run lock, that means we're stopping out to the + // user, so we should also select the most relevant frame. + SelectMostRelevant select_most_relevant = + use_run_lock ? SelectMostRelevantFrame : DoNoSelectMostRelevantFrame; + StateType state = WaitForProcessToStop(GetInterruptTimeout(), &event_sp, true, + halt_listener_sp, nullptr, + use_run_lock, select_most_relevant); RestoreProcessEvents(); if (state == eStateInvalid || !event_sp) { @@ -3352,7 +3390,7 @@ Status Process::Signal(int signal) { void Process::SetUnixSignals(UnixSignalsSP &&signals_sp) { assert(signals_sp && "null signals_sp"); - m_unix_signals_sp = signals_sp; + m_unix_signals_sp = std::move(signals_sp); } const lldb::UnixSignalsSP &Process::GetUnixSignals() { @@ -3562,8 +3600,8 @@ bool Process::StartPrivateStateThread(bool is_secondary_thread) { }, 8 * 1024 * 1024); if (!private_state_thread) { - LLDB_LOG(GetLog(LLDBLog::Host), "failed to launch host thread: {}", - llvm::toString(private_state_thread.takeError())); + LLDB_LOG_ERROR(GetLog(LLDBLog::Host), private_state_thread.takeError(), + "failed to launch host thread: {0}"); return false; } @@ -3913,12 +3951,11 @@ Process::ProcessEventData::ProcessEventData(const ProcessSP &process_sp, Process::ProcessEventData::~ProcessEventData() = default; -ConstString Process::ProcessEventData::GetFlavorString() { - static ConstString g_flavor("Process::ProcessEventData"); - return g_flavor; +llvm::StringRef Process::ProcessEventData::GetFlavorString() { + return "Process::ProcessEventData"; } -ConstString Process::ProcessEventData::GetFlavor() const { +llvm::StringRef Process::ProcessEventData::GetFlavor() const { return ProcessEventData::GetFlavorString(); } @@ -4265,7 +4302,7 @@ void Process::BroadcastStructuredData(const StructuredData::ObjectSP &object_sp, } StructuredDataPluginSP -Process::GetStructuredDataPlugin(ConstString type_name) const { +Process::GetStructuredDataPlugin(llvm::StringRef type_name) const { auto find_it = m_structured_data_plugin_map.find(type_name); if (find_it != m_structured_data_plugin_map.end()) return find_it->second; @@ -4745,10 +4782,11 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx, // Save the thread & frame from the exe_ctx for restoration after we run const uint32_t thread_idx_id = thread->GetIndexID(); - StackFrameSP selected_frame_sp = thread->GetSelectedFrame(); + StackFrameSP selected_frame_sp = + thread->GetSelectedFrame(DoNoSelectMostRelevantFrame); if (!selected_frame_sp) { thread->SetSelectedFrame(nullptr); - selected_frame_sp = thread->GetSelectedFrame(); + selected_frame_sp = thread->GetSelectedFrame(DoNoSelectMostRelevantFrame); if (!selected_frame_sp) { diagnostic_manager.Printf( eDiagnosticSeverityError, @@ -4780,7 +4818,9 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx, StackID selected_stack_id; if (selected_thread_sp) { selected_tid = selected_thread_sp->GetIndexID(); - selected_stack_id = selected_thread_sp->GetSelectedFrame()->GetStackID(); + selected_stack_id = + selected_thread_sp->GetSelectedFrame(DoNoSelectMostRelevantFrame) + ->GetStackID(); } else { selected_tid = LLDB_INVALID_THREAD_ID; } @@ -5624,25 +5664,75 @@ void Process::Flush() { } lldb::addr_t Process::GetCodeAddressMask() { - if (m_code_address_mask == 0) { - if (uint32_t number_of_addressable_bits = GetVirtualAddressableBits()) { - lldb::addr_t address_mask = ~((1ULL << number_of_addressable_bits) - 1); - SetCodeAddressMask(address_mask); - } - } + if (uint32_t num_bits_setting = GetVirtualAddressableBits()) + return ~((1ULL << num_bits_setting) - 1); + return m_code_address_mask; } lldb::addr_t Process::GetDataAddressMask() { - if (m_data_address_mask == 0) { - if (uint32_t number_of_addressable_bits = GetVirtualAddressableBits()) { - lldb::addr_t address_mask = ~((1ULL << number_of_addressable_bits) - 1); - SetDataAddressMask(address_mask); - } - } + if (uint32_t num_bits_setting = GetVirtualAddressableBits()) + return ~((1ULL << num_bits_setting) - 1); + return m_data_address_mask; } +lldb::addr_t Process::GetHighmemCodeAddressMask() { + if (uint32_t num_bits_setting = GetHighmemVirtualAddressableBits()) + return ~((1ULL << num_bits_setting) - 1); + return GetCodeAddressMask(); +} + +lldb::addr_t Process::GetHighmemDataAddressMask() { + if (uint32_t num_bits_setting = GetHighmemVirtualAddressableBits()) + return ~((1ULL << num_bits_setting) - 1); + return GetDataAddressMask(); +} + +void Process::SetCodeAddressMask(lldb::addr_t code_address_mask) { + LLDB_LOG(GetLog(LLDBLog::Process), + "Setting Process code address mask to {0:x}", code_address_mask); + m_code_address_mask = code_address_mask; +} + +void Process::SetDataAddressMask(lldb::addr_t data_address_mask) { + LLDB_LOG(GetLog(LLDBLog::Process), + "Setting Process data address mask to {0:x}", data_address_mask); + m_data_address_mask = data_address_mask; +} + +void Process::SetHighmemCodeAddressMask(lldb::addr_t code_address_mask) { + LLDB_LOG(GetLog(LLDBLog::Process), + "Setting Process highmem code address mask to {0:x}", + code_address_mask); + m_highmem_code_address_mask = code_address_mask; +} + +void Process::SetHighmemDataAddressMask(lldb::addr_t data_address_mask) { + LLDB_LOG(GetLog(LLDBLog::Process), + "Setting Process highmem data address mask to {0:x}", + data_address_mask); + m_highmem_data_address_mask = data_address_mask; +} + +addr_t Process::FixCodeAddress(addr_t addr) { + if (ABISP abi_sp = GetABI()) + addr = abi_sp->FixCodeAddress(addr); + return addr; +} + +addr_t Process::FixDataAddress(addr_t addr) { + if (ABISP abi_sp = GetABI()) + addr = abi_sp->FixDataAddress(addr); + return addr; +} + +addr_t Process::FixAnyAddress(addr_t addr) { + if (ABISP abi_sp = GetABI()) + addr = abi_sp->FixAnyAddress(addr); + return addr; +} + void Process::DidExec() { Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "Process::%s()", __FUNCTION__); @@ -5737,7 +5827,7 @@ void Process::ModulesDidLoad(ModuleList &module_list) { LoadOperatingSystemPlugin(false); // Inform the structured-data plugins of the modified modules. - for (auto pair : m_structured_data_plugin_map) { + for (auto &pair : m_structured_data_plugin_map) { if (pair.second) pair.second->ModulesDidLoad(*this, module_list); } @@ -5918,7 +6008,7 @@ Status Process::GetMemoryRegions(lldb_private::MemoryRegionInfos ®ion_list) { } Status -Process::ConfigureStructuredData(ConstString type_name, +Process::ConfigureStructuredData(llvm::StringRef type_name, const StructuredData::ObjectSP &config_sp) { // If you get this, the Process-derived class needs to implement a method to // enable an already-reported asynchronous structured data feature. See @@ -5932,34 +6022,29 @@ void Process::MapSupportedStructuredDataPlugins( // Bail out early if there are no type names to map. if (supported_type_names.GetSize() == 0) { - LLDB_LOGF(log, "Process::%s(): no structured data types supported", - __FUNCTION__); + LLDB_LOG(log, "no structured data types supported"); return; } - // Convert StructuredData type names to ConstString instances. - std::set<ConstString> const_type_names; + // These StringRefs are backed by the input parameter. + std::set<llvm::StringRef> type_names; - LLDB_LOGF(log, - "Process::%s(): the process supports the following async " - "structured data types:", - __FUNCTION__); + LLDB_LOG(log, + "the process supports the following async structured data types:"); supported_type_names.ForEach( - [&const_type_names, &log](StructuredData::Object *object) { - if (!object) { - // Invalid - shouldn't be null objects in the array. + [&type_names, &log](StructuredData::Object *object) { + // There shouldn't be null objects in the array. + if (!object) return false; - } - auto type_name = object->GetAsString(); - if (!type_name) { - // Invalid format - all type names should be strings. + // All type names should be strings. + const llvm::StringRef type_name = object->GetStringValue(); + if (type_name.empty()) return false; - } - const_type_names.insert(ConstString(type_name->GetValue())); - LLDB_LOG(log, "- {0}", type_name->GetValue()); + type_names.insert(type_name); + LLDB_LOG(log, "- {0}", type_name); return true; }); @@ -5968,10 +6053,10 @@ void Process::MapSupportedStructuredDataPlugins( // we've consumed all the type names. // FIXME: should we return an error if there are type names nobody // supports? - for (uint32_t plugin_index = 0; !const_type_names.empty(); plugin_index++) { + for (uint32_t plugin_index = 0; !type_names.empty(); plugin_index++) { auto create_instance = - PluginManager::GetStructuredDataPluginCreateCallbackAtIndex( - plugin_index); + PluginManager::GetStructuredDataPluginCreateCallbackAtIndex( + plugin_index); if (!create_instance) break; @@ -5984,8 +6069,8 @@ void Process::MapSupportedStructuredDataPlugins( } // For any of the remaining type names, map any that this plugin supports. - std::vector<ConstString> names_to_remove; - for (auto &type_name : const_type_names) { + std::vector<llvm::StringRef> names_to_remove; + for (llvm::StringRef type_name : type_names) { if (plugin_sp->SupportsStructuredDataType(type_name)) { m_structured_data_plugin_map.insert( std::make_pair(type_name, plugin_sp)); @@ -5996,8 +6081,8 @@ void Process::MapSupportedStructuredDataPlugins( } // Remove the type names that were consumed by this plugin. - for (auto &type_name : names_to_remove) - const_type_names.erase(type_name); + for (llvm::StringRef type_name : names_to_remove) + type_names.erase(type_name); } } @@ -6014,7 +6099,7 @@ bool Process::RouteAsyncStructuredData( return false; // Grab the async structured type name (i.e. the feature/plugin name). - ConstString type_name; + llvm::StringRef type_name; if (!dictionary->GetValueForKeyAsString("type", type_name)) return false; diff --git a/lldb/source/Target/RegisterContext.cpp b/lldb/source/Target/RegisterContext.cpp index ee344b01c6b8..7236a45bff3b 100644 --- a/lldb/source/Target/RegisterContext.cpp +++ b/lldb/source/Target/RegisterContext.cpp @@ -320,11 +320,6 @@ Status RegisterContext::ReadRegisterValueFromMemory( // |AABB| Address contents // |AABB0000| Register contents [on little-endian hardware] // |0000AABB| Register contents [on big-endian hardware] - if (src_len > RegisterValue::kMaxRegisterByteSize) { - error.SetErrorString("register too small to receive memory data"); - return error; - } - const uint32_t dst_len = reg_info->byte_size; if (src_len > dst_len) { @@ -336,11 +331,11 @@ Status RegisterContext::ReadRegisterValueFromMemory( ProcessSP process_sp(m_thread.GetProcess()); if (process_sp) { - uint8_t src[RegisterValue::kMaxRegisterByteSize]; + RegisterValue::BytesContainer src(src_len); // Read the memory const uint32_t bytes_read = - process_sp->ReadMemory(src_addr, src, src_len, error); + process_sp->ReadMemory(src_addr, src.data(), src_len, error); // Make sure the memory read succeeded... if (bytes_read != src_len) { @@ -357,7 +352,7 @@ Status RegisterContext::ReadRegisterValueFromMemory( // TODO: we might need to add a parameter to this function in case the byte // order of the memory data doesn't match the process. For now we are // assuming they are the same. - reg_value.SetFromMemoryData(*reg_info, src, src_len, + reg_value.SetFromMemoryData(*reg_info, src.data(), src_len, process_sp->GetByteOrder(), error); } else error.SetErrorString("invalid process"); @@ -384,16 +379,16 @@ Status RegisterContext::WriteRegisterValueToMemory( // TODO: we might need to add a parameter to this function in case the byte // order of the memory data doesn't match the process. For now we are // assuming they are the same. - uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + RegisterValue::BytesContainer dst(dst_len); const uint32_t bytes_copied = reg_value.GetAsMemoryData( - *reg_info, dst, dst_len, process_sp->GetByteOrder(), error); + *reg_info, dst.data(), dst_len, process_sp->GetByteOrder(), error); if (error.Success()) { if (bytes_copied == 0) { error.SetErrorString("byte copy failed."); } else { const uint32_t bytes_written = - process_sp->WriteMemory(dst_addr, dst, bytes_copied, error); + process_sp->WriteMemory(dst_addr, dst.data(), bytes_copied, error); if (bytes_written != bytes_copied) { if (error.Success()) { // This might happen if we read _some_ bytes but not all diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index 2da40ba2bf61..242c7d3f6b94 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -37,6 +37,8 @@ #include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/VASPrintf.h" #include "lldb/lldb-private.h" + +#include <cassert> #include <memory> using namespace lldb; @@ -135,9 +137,8 @@ void RegisterContextUnwind::InitializeZerothFrame() { // (which would be a no-op in frame 0 where we get it from the register set, // but still a good idea to make the call here for other ABIs that may // exist.) - ABI *abi = process->GetABI().get(); - if (abi) - current_pc = abi->FixCodeAddress(current_pc); + if (ABISP abi_sp = process->GetABI()) + current_pc = abi_sp->FixCodeAddress(current_pc); UnwindPlanSP lang_runtime_plan_sp = LanguageRuntime::GetRuntimeUnwindPlan( m_thread, this, m_behaves_like_zeroth_frame); @@ -289,6 +290,13 @@ void RegisterContextUnwind::InitializeZerothFrame() { } else ReadFrameAddress(row_register_kind, active_row->GetAFAValue(), m_afa); + if (m_cfa == LLDB_INVALID_ADDRESS && m_afa == LLDB_INVALID_ADDRESS) { + UnwindLogMsg( + "could not read CFA or AFA values for first frame, not valid."); + m_frame_type = eNotAValidFrame; + return; + } + UnwindLogMsg("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64 " afa is 0x%" PRIx64 " using %s UnwindPlan", (uint64_t)m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()), @@ -346,17 +354,23 @@ void RegisterContextUnwind::InitializeNonZerothFrame() { // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs // this will strip bit zero in case we read a PC from memory or from the LR. - ABI *abi = process->GetABI().get(); - if (abi) - pc = abi->FixCodeAddress(pc); + ABISP abi_sp = process->GetABI(); + if (abi_sp) + pc = abi_sp->FixCodeAddress(pc); if (log) { UnwindLogMsg("pc = 0x%" PRIx64, pc); addr_t reg_val; - if (ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, reg_val)) + if (ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, reg_val)) { + if (abi_sp) + reg_val = abi_sp->FixDataAddress(reg_val); UnwindLogMsg("fp = 0x%" PRIx64, reg_val); - if (ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, reg_val)) + } + if (ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, reg_val)) { + if (abi_sp) + reg_val = abi_sp->FixDataAddress(reg_val); UnwindLogMsg("sp = 0x%" PRIx64, reg_val); + } } // A pc of 0x0 means it's the end of the stack crawl unless we're above a trap @@ -415,11 +429,11 @@ void RegisterContextUnwind::InitializeNonZerothFrame() { } } - if (abi) { + if (abi_sp) { m_fast_unwind_plan_sp.reset(); m_full_unwind_plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric); - abi->CreateDefaultUnwindPlan(*m_full_unwind_plan_sp); + abi_sp->CreateDefaultUnwindPlan(*m_full_unwind_plan_sp); if (m_frame_type != eSkipFrame) // don't override eSkipFrame { m_frame_type = eNormalFrame; @@ -1742,8 +1756,8 @@ bool RegisterContextUnwind::TryFallbackUnwindPlan() { if (ReadRegisterValueFromRegisterLocation(regloc, reg_info, reg_value)) { old_caller_pc_value = reg_value.GetAsUInt64(); if (ProcessSP process_sp = m_thread.GetProcess()) { - if (ABISP abi = process_sp->GetABI()) - old_caller_pc_value = abi->FixCodeAddress(old_caller_pc_value); + if (ABISP abi_sp = process_sp->GetABI()) + old_caller_pc_value = abi_sp->FixCodeAddress(old_caller_pc_value); } } } @@ -1802,8 +1816,8 @@ bool RegisterContextUnwind::TryFallbackUnwindPlan() { reg_value)) { new_caller_pc_value = reg_value.GetAsUInt64(); if (ProcessSP process_sp = m_thread.GetProcess()) { - if (ABISP abi = process_sp->GetABI()) - new_caller_pc_value = abi->FixCodeAddress(new_caller_pc_value); + if (ABISP abi_sp = process_sp->GetABI()) + new_caller_pc_value = abi_sp->FixCodeAddress(new_caller_pc_value); } } } @@ -1944,6 +1958,7 @@ bool RegisterContextUnwind::ReadFrameAddress( address = LLDB_INVALID_ADDRESS; addr_t cfa_reg_contents; + ABISP abi_sp = m_thread.GetProcess()->GetABI(); switch (fa.GetValueType()) { case UnwindPlan::Row::FAValue::isRegisterDereferenced: { @@ -1954,11 +1969,13 @@ bool RegisterContextUnwind::ReadFrameAddress( GetRegisterInfoAtIndex(cfa_reg.GetAsKind(eRegisterKindLLDB)); RegisterValue reg_value; if (reg_info) { + if (abi_sp) + cfa_reg_contents = abi_sp->FixDataAddress(cfa_reg_contents); Status error = ReadRegisterValueFromMemory( reg_info, cfa_reg_contents, reg_info->byte_size, reg_value); if (error.Success()) { address = reg_value.GetAsUInt64(); - if (ABISP abi_sp = m_thread.GetProcess()->GetABI()) + if (abi_sp) address = abi_sp->FixCodeAddress(address); UnwindLogMsg( "CFA value via dereferencing reg %s (%d): reg has val 0x%" PRIx64 @@ -1980,6 +1997,8 @@ bool RegisterContextUnwind::ReadFrameAddress( RegisterNumber cfa_reg(m_thread, row_register_kind, fa.GetRegisterNumber()); if (ReadGPRValue(cfa_reg, cfa_reg_contents)) { + if (abi_sp) + cfa_reg_contents = abi_sp->FixDataAddress(cfa_reg_contents); if (cfa_reg_contents == LLDB_INVALID_ADDRESS || cfa_reg_contents == 0 || cfa_reg_contents == 1) { UnwindLogMsg( @@ -2067,6 +2086,8 @@ lldb::addr_t RegisterContextUnwind::GetReturnAddressHint(int32_t plan_offset) { return LLDB_INVALID_ADDRESS; if (!m_sym_ctx.module_sp || !m_sym_ctx.symbol) return LLDB_INVALID_ADDRESS; + if (ABISP abi_sp = m_thread.GetProcess()->GetABI()) + hint = abi_sp->FixCodeAddress(hint); hint += plan_offset; @@ -2116,28 +2137,46 @@ bool RegisterContextUnwind::ReadGPRValue(lldb::RegisterKind register_kind, } const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum); + assert(reg_info); + if (!reg_info) { + UnwindLogMsg( + "Could not find RegisterInfo definition for lldb register number %d", + lldb_regnum); + return false; + } + + uint32_t generic_regnum = LLDB_INVALID_REGNUM; + if (register_kind == eRegisterKindGeneric) + generic_regnum = regnum; + else + m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds( + register_kind, regnum, eRegisterKindGeneric, generic_regnum); + ABISP abi_sp = m_thread.GetProcess()->GetABI(); + RegisterValue reg_value; // if this is frame 0 (currently executing frame), get the requested reg // contents from the actual thread registers if (IsFrameZero()) { if (m_thread.GetRegisterContext()->ReadRegister(reg_info, reg_value)) { value = reg_value.GetAsUInt64(); + if (abi_sp && generic_regnum != LLDB_INVALID_REGNUM) { + if (generic_regnum == LLDB_REGNUM_GENERIC_PC || + generic_regnum == LLDB_REGNUM_GENERIC_RA) + value = abi_sp->FixCodeAddress(value); + if (generic_regnum == LLDB_REGNUM_GENERIC_SP || + generic_regnum == LLDB_REGNUM_GENERIC_FP) + value = abi_sp->FixDataAddress(value); + } return true; } return false; } bool pc_register = false; - uint32_t generic_regnum; - if (register_kind == eRegisterKindGeneric && - (regnum == LLDB_REGNUM_GENERIC_PC || regnum == LLDB_REGNUM_GENERIC_RA)) { + if (generic_regnum != LLDB_INVALID_REGNUM && + (generic_regnum == LLDB_REGNUM_GENERIC_PC || + generic_regnum == LLDB_REGNUM_GENERIC_RA)) pc_register = true; - } else if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds( - register_kind, regnum, eRegisterKindGeneric, generic_regnum) && - (generic_regnum == LLDB_REGNUM_GENERIC_PC || - generic_regnum == LLDB_REGNUM_GENERIC_RA)) { - pc_register = true; - } lldb_private::UnwindLLDB::RegisterLocation regloc; if (!m_parent_unwind.SearchForSavedLocationForRegister( @@ -2147,9 +2186,8 @@ bool RegisterContextUnwind::ReadGPRValue(lldb::RegisterKind register_kind, if (ReadRegisterValueFromRegisterLocation(regloc, reg_info, reg_value)) { value = reg_value.GetAsUInt64(); if (pc_register) { - if (ProcessSP process_sp = m_thread.GetProcess()) { - if (ABISP abi = process_sp->GetABI()) - value = abi->FixCodeAddress(value); + if (ABISP abi_sp = m_thread.GetProcess()->GetABI()) { + value = abi_sp->FixCodeAddress(value); } } return true; @@ -2198,10 +2236,8 @@ bool RegisterContextUnwind::ReadRegister(const RegisterInfo *reg_info, if (is_pc_regnum && value.GetType() == RegisterValue::eTypeUInt64) { addr_t reg_value = value.GetAsUInt64(LLDB_INVALID_ADDRESS); if (reg_value != LLDB_INVALID_ADDRESS) { - if(ProcessSP process_sp = m_thread.GetProcess()) { - if (ABISP abi = process_sp->GetABI()) - value = abi->FixCodeAddress(reg_value); - } + if (ABISP abi_sp = m_thread.GetProcess()->GetABI()) + value = abi_sp->FixCodeAddress(reg_value); } } } @@ -2283,9 +2319,8 @@ bool RegisterContextUnwind::GetStartPC(addr_t &start_pc) { ProcessSP process_sp (m_thread.GetProcess()); if (process_sp) { - ABI *abi = process_sp->GetABI().get(); - if (abi) - start_pc = abi->FixCodeAddress(start_pc); + if (ABISP abi_sp = process_sp->GetABI()) + start_pc = abi_sp->FixCodeAddress(start_pc); } } return read_successfully; @@ -2313,13 +2348,8 @@ bool RegisterContextUnwind::ReadPC(addr_t &pc) { // through a NULL pointer -- we want to be able to unwind past that frame // to help find the bug. - ProcessSP process_sp (m_thread.GetProcess()); - if (process_sp) - { - ABI *abi = process_sp->GetABI().get(); - if (abi) - pc = abi->FixCodeAddress(pc); - } + if (ABISP abi_sp = m_thread.GetProcess()->GetABI()) + pc = abi_sp->FixCodeAddress(pc); return !(m_all_registers_available == false && above_trap_handler == false && (pc == 0 || pc == 1)); diff --git a/lldb/source/Target/RegisterFlags.cpp b/lldb/source/Target/RegisterFlags.cpp new file mode 100644 index 000000000000..06fb45d777ec --- /dev/null +++ b/lldb/source/Target/RegisterFlags.cpp @@ -0,0 +1,177 @@ +//===-- RegisterFlags.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/RegisterFlags.h" +#include "lldb/Utility/StreamString.h" + +#include <numeric> +#include <optional> + +using namespace lldb_private; + +void RegisterFlags::Field::log(Log *log) const { + LLDB_LOG(log, " Name: \"{0}\" Start: {1} End: {2}", m_name.c_str(), m_start, + m_end); +} + +bool RegisterFlags::Field::Overlaps(const Field &other) const { + unsigned overlap_start = std::max(GetStart(), other.GetStart()); + unsigned overlap_end = std::min(GetEnd(), other.GetEnd()); + return overlap_start <= overlap_end; +} + +unsigned RegisterFlags::Field::PaddingDistance(const Field &other) const { + assert(!Overlaps(other) && + "Cannot get padding distance for overlapping fields."); + assert((other < (*this)) && "Expected fields in MSB to LSB order."); + + // If they don't overlap they are either next to each other or separated + // by some number of bits. + + // Where left will be the MSB and right will be the LSB. + unsigned lhs_start = GetStart(); + unsigned rhs_end = other.GetStart() + other.GetSizeInBits() - 1; + + if (*this < other) { + lhs_start = other.GetStart(); + rhs_end = GetStart() + GetSizeInBits() - 1; + } + + return lhs_start - rhs_end - 1; +} + +RegisterFlags::RegisterFlags(std::string id, unsigned size, + const std::vector<Field> &fields) + : m_id(std::move(id)), m_size(size) { + // We expect that the XML processor will discard anything describing flags but + // with no fields. + assert(fields.size() && "Some fields must be provided."); + + // We expect that these are unsorted but do not overlap. + // They could fill the register but may have gaps. + std::vector<Field> provided_fields = fields; + m_fields.reserve(provided_fields.size()); + + // ProcessGDBRemote should have sorted these in descending order already. + assert(std::is_sorted(provided_fields.rbegin(), provided_fields.rend())); + + // Build a new list of fields that includes anonymous (empty name) fields + // wherever there is a gap. This will simplify processing later. + std::optional<Field> previous_field; + unsigned register_msb = (size * 8) - 1; + for (auto field : provided_fields) { + if (previous_field) { + unsigned padding = previous_field->PaddingDistance(field); + if (padding) { + // -1 to end just before the previous field. + unsigned end = previous_field->GetStart() - 1; + // +1 because if you want to pad 1 bit you want to start and end + // on the same bit. + m_fields.push_back(Field("", field.GetEnd() + 1, end)); + } + } else { + // This is the first field. Check that it starts at the register's MSB. + if (field.GetEnd() != register_msb) + m_fields.push_back(Field("", field.GetEnd() + 1, register_msb)); + } + m_fields.push_back(field); + previous_field = field; + } + + // The last field may not extend all the way to bit 0. + if (previous_field && previous_field->GetStart() != 0) + m_fields.push_back(Field("", 0, previous_field->GetStart() - 1)); +} + +void RegisterFlags::log(Log *log) const { + LLDB_LOG(log, "ID: \"{0}\" Size: {1}", m_id.c_str(), m_size); + for (const Field &field : m_fields) + field.log(log); +} + +static StreamString FormatCell(const StreamString &content, + unsigned column_width) { + unsigned pad = column_width - content.GetString().size(); + std::string pad_l; + std::string pad_r; + if (pad) { + pad_l = std::string(pad / 2, ' '); + pad_r = std::string((pad / 2) + (pad % 2), ' '); + } + + StreamString aligned; + aligned.Printf("|%s%s%s", pad_l.c_str(), content.GetString().data(), + pad_r.c_str()); + return aligned; +} + +static void EmitTable(std::string &out, std::array<std::string, 3> &table) { + // Close the table. + for (std::string &line : table) + line += '|'; + + out += std::accumulate(table.begin() + 1, table.end(), table.front(), + [](std::string lhs, const auto &rhs) { + return std::move(lhs) + "\n" + rhs; + }); +} + +std::string RegisterFlags::AsTable(uint32_t max_width) const { + std::string table; + // position / gridline / name + std::array<std::string, 3> lines; + uint32_t current_width = 0; + + for (const RegisterFlags::Field &field : m_fields) { + StreamString position; + if (field.GetEnd() == field.GetStart()) + position.Printf(" %d ", field.GetEnd()); + else + position.Printf(" %d-%d ", field.GetEnd(), field.GetStart()); + + StreamString name; + name.Printf(" %s ", field.GetName().c_str()); + + unsigned column_width = position.GetString().size(); + unsigned name_width = name.GetString().size(); + if (name_width > column_width) + column_width = name_width; + + // If the next column would overflow and we have already formatted at least + // one column, put out what we have and move to a new table on the next line + // (+1 here because we need to cap the ends with '|'). If this is the first + // column, just let it overflow and we'll wrap next time around. There's not + // much we can do with a very small terminal. + if (current_width && ((current_width + column_width + 1) >= max_width)) { + EmitTable(table, lines); + // Blank line between each. + table += "\n\n"; + + for (std::string &line : lines) + line.clear(); + current_width = 0; + } + + StreamString aligned_position = FormatCell(position, column_width); + lines[0] += aligned_position.GetString(); + StreamString grid; + grid << '|' << std::string(column_width, '-'); + lines[1] += grid.GetString(); + StreamString aligned_name = FormatCell(name, column_width); + lines[2] += aligned_name.GetString(); + + // +1 for the left side '|'. + current_width += column_width + 1; + } + + // If we didn't overflow and still have table to print out. + if (lines[0].size()) + EmitTable(table, lines); + + return table; +} diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp index c04b58e80523..11ada92348ec 100644 --- a/lldb/source/Target/StackFrame.cpp +++ b/lldb/source/Target/StackFrame.cpp @@ -567,26 +567,21 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath( // Check for direct ivars access which helps us with implicit access to // ivars using "this" or "self". GetSymbolContext(eSymbolContextFunction | eSymbolContextBlock); - lldb::LanguageType method_language = eLanguageTypeUnknown; - bool is_instance_method = false; - ConstString method_object_name; - if (m_sc.GetFunctionMethodInfo(method_language, is_instance_method, - method_object_name)) { - if (is_instance_method && method_object_name) { - var_sp = variable_list->FindVariable(method_object_name); - if (var_sp) { - separator_idx = 0; - if (Type *var_type = var_sp->GetType()) - if (auto compiler_type = var_type->GetForwardCompilerType()) - if (!compiler_type.IsPointerType()) - var_expr_storage = "."; + llvm::StringRef instance_var_name = m_sc.GetInstanceVariableName(); + if (!instance_var_name.empty()) { + var_sp = variable_list->FindVariable(ConstString(instance_var_name)); + if (var_sp) { + separator_idx = 0; + if (Type *var_type = var_sp->GetType()) + if (auto compiler_type = var_type->GetForwardCompilerType()) + if (!compiler_type.IsPointerType()) + var_expr_storage = "."; - if (var_expr_storage.empty()) - var_expr_storage = "->"; - var_expr_storage += var_expr; - var_expr = var_expr_storage; - synthetically_added_instance_object = true; - } + if (var_expr_storage.empty()) + var_expr_storage = "->"; + var_expr_storage += var_expr; + var_expr = var_expr_storage; + synthetically_added_instance_object = true; } } } @@ -609,7 +604,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath( valobj_sp = GetValueObjectForFrameVariable(variable_sp, use_dynamic); if (!valobj_sp) return valobj_sp; - valobj_sp = valobj_sp->GetChildMemberWithName(name_const_string, true); + valobj_sp = valobj_sp->GetChildMemberWithName(name_const_string); if (valobj_sp) break; } @@ -710,13 +705,13 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath( return ValueObjectSP(); } } - child_valobj_sp = valobj_sp->GetChildMemberWithName(child_name, true); + child_valobj_sp = valobj_sp->GetChildMemberWithName(child_name); if (!child_valobj_sp) { if (!no_synth_child) { child_valobj_sp = valobj_sp->GetSyntheticValue(); if (child_valobj_sp) child_valobj_sp = - child_valobj_sp->GetChildMemberWithName(child_name, true); + child_valobj_sp->GetChildMemberWithName(child_name); } if (no_synth_child || !child_valobj_sp) { @@ -819,7 +814,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath( // extract bit low out of it. reading array item low would be done by // saying arr[low], without a deref * sign Status error; - ValueObjectSP temp(valobj_sp->GetChildAtIndex(0, true)); + ValueObjectSP temp(valobj_sp->GetChildAtIndex(0)); if (error.Fail()) { valobj_sp->GetExpressionPath(var_expr_path_strm); error.SetErrorStringWithFormat( @@ -873,7 +868,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath( valobj_sp->GetTypeName().AsCString("<invalid type>"), var_expr_path_strm.GetData()); } else { - child_valobj_sp = synthetic->GetChildAtIndex(child_index, true); + child_valobj_sp = synthetic->GetChildAtIndex(child_index); if (!child_valobj_sp) { valobj_sp->GetExpressionPath(var_expr_path_strm); error.SetErrorStringWithFormat( @@ -899,7 +894,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath( nullptr, nullptr, &is_incomplete_array)) { // Pass false to dynamic_value here so we can tell the difference // between no dynamic value and no member of this type... - child_valobj_sp = valobj_sp->GetChildAtIndex(child_index, true); + child_valobj_sp = valobj_sp->GetChildAtIndex(child_index); if (!child_valobj_sp && (is_incomplete_array || !no_synth_child)) child_valobj_sp = valobj_sp->GetSyntheticArrayMember(child_index, true); @@ -945,7 +940,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath( valobj_sp->GetTypeName().AsCString("<invalid type>"), var_expr_path_strm.GetData()); } else { - child_valobj_sp = synthetic->GetChildAtIndex(child_index, true); + child_valobj_sp = synthetic->GetChildAtIndex(child_index); if (!child_valobj_sp) { valobj_sp->GetExpressionPath(var_expr_path_strm); error.SetErrorStringWithFormat( @@ -1017,7 +1012,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath( // extract bits low thru high out of it. reading array items low thru // high would be done by saying arr[low-high], without a deref * sign Status error; - ValueObjectSP temp(valobj_sp->GetChildAtIndex(0, true)); + ValueObjectSP temp(valobj_sp->GetChildAtIndex(0)); if (error.Fail()) { valobj_sp->GetExpressionPath(var_expr_path_strm); error.SetErrorStringWithFormat( @@ -1365,7 +1360,7 @@ lldb::ValueObjectSP StackFrame::GuessValueForAddress(lldb::addr_t addr) { target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC); if (auto err = c_type_system_or_err.takeError()) { LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), std::move(err), - "Unable to guess value for given address"); + "Unable to guess value for given address: {0}"); return ValueObjectSP(); } else { auto ts = *c_type_system_or_err; @@ -1405,8 +1400,7 @@ ValueObjectSP GetValueForOffset(StackFrame &frame, ValueObjectSP &parent, } for (int ci = 0, ce = parent->GetNumChildren(); ci != ce; ++ci) { - const bool can_create = true; - ValueObjectSP child_sp = parent->GetChildAtIndex(ci, can_create); + ValueObjectSP child_sp = parent->GetChildAtIndex(ci); if (!child_sp) { return ValueObjectSP(); diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp index c782b506a9cb..2841f512439a 100644 --- a/lldb/source/Target/StackFrameList.cpp +++ b/lldb/source/Target/StackFrameList.cpp @@ -9,6 +9,7 @@ #include "lldb/Target/StackFrameList.h" #include "lldb/Breakpoint/Breakpoint.h" #include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Core/Debugger.h" #include "lldb/Core/SourceManager.h" #include "lldb/Core/StreamFile.h" #include "lldb/Symbol/Block.h" @@ -17,6 +18,7 @@ #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StackFrame.h" +#include "lldb/Target/StackFrameRecognizer.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" @@ -37,7 +39,7 @@ StackFrameList::StackFrameList(Thread &thread, const lldb::StackFrameListSP &prev_frames_sp, bool show_inline_frames) : m_thread(thread), m_prev_frames_sp(prev_frames_sp), m_mutex(), m_frames(), - m_selected_frame_idx(0), m_concrete_frames_fetched(0), + m_selected_frame_idx(), m_concrete_frames_fetched(0), m_current_inlined_depth(UINT32_MAX), m_current_inlined_pc(LLDB_INVALID_ADDRESS), m_show_inlined_frames(show_inline_frames) { @@ -83,8 +85,8 @@ void StackFrameList::ResetCurrentInlinedDepth() { return; std::lock_guard<std::recursive_mutex> guard(m_mutex); - - GetFramesUpTo(0); + + GetFramesUpTo(0, DoNotAllowInterruption); if (m_frames.empty()) return; if (!m_frames[0]->IsInlined()) { @@ -251,7 +253,7 @@ struct CallDescriptor { using CallSequence = std::vector<CallDescriptor>; /// Find the unique path through the call graph from \p begin (with return PC -/// \p return_pc) to \p end. On success this path is stored into \p path, and +/// \p return_pc) to \p end. On success this path is stored into \p path, and /// on failure \p path is unchanged. static void FindInterveningFrames(Function &begin, Function &end, ExecutionContext &exe_ctx, Target &target, @@ -434,21 +436,23 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) { next_frame.SetFrameIndex(m_frames.size()); } -void StackFrameList::GetFramesUpTo(uint32_t end_idx) { +bool StackFrameList::GetFramesUpTo(uint32_t end_idx, + InterruptionControl allow_interrupt) { // Do not fetch frames for an invalid thread. + bool was_interrupted = false; if (!m_thread.IsValid()) - return; + return false; // We've already gotten more frames than asked for, or we've already finished // unwinding, return. if (m_frames.size() > end_idx || GetAllFramesFetched()) - return; + return false; Unwind &unwinder = m_thread.GetUnwinder(); if (!m_show_inlined_frames) { GetOnlyConcreteFramesUpTo(end_idx, unwinder); - return; + return false; } #if defined(DEBUG_STACK_FRAMES) @@ -470,6 +474,7 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) { } StackFrameSP unwind_frame_sp; + Debugger &dbg = m_thread.GetProcess()->GetTarget().GetDebugger(); do { uint32_t idx = m_concrete_frames_fetched++; lldb::addr_t pc = LLDB_INVALID_ADDRESS; @@ -502,6 +507,15 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) { cfa = unwind_frame_sp->m_id.GetCallFrameAddress(); } } else { + // Check for interruption when building the frames. + // Do the check in idx > 0 so that we'll always create a 0th frame. + if (allow_interrupt + && INTERRUPT_REQUESTED(dbg, "Interrupted having fetched {0} frames", + m_frames.size())) { + was_interrupted = true; + break; + } + const bool success = unwinder.GetFrameInfoAtIndex(idx, cfa, pc, behaves_like_zeroth_frame); if (!success) { @@ -614,14 +628,19 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) { Dump(&s); s.EOL(); #endif + // Don't report interrupted if we happen to have gotten all the frames: + if (!GetAllFramesFetched()) + return was_interrupted; + return false; } uint32_t StackFrameList::GetNumFrames(bool can_create) { std::lock_guard<std::recursive_mutex> guard(m_mutex); - if (can_create) - GetFramesUpTo(UINT32_MAX); - + if (can_create) { + // Don't allow interrupt or we might not return the correct count + GetFramesUpTo(UINT32_MAX, DoNotAllowInterruption); + } return GetVisibleStackFrameIndex(m_frames.size()); } @@ -662,7 +681,13 @@ StackFrameSP StackFrameList::GetFrameAtIndex(uint32_t idx) { // GetFramesUpTo will fill m_frames with as many frames as you asked for, if // there are that many. If there weren't then you asked for too many frames. - GetFramesUpTo(idx); + // GetFramesUpTo returns true if interrupted: + if (GetFramesUpTo(idx)) { + Log *log = GetLog(LLDBLog::Thread); + LLDB_LOG(log, "GetFrameAtIndex was interrupted"); + return {}; + } + if (idx < m_frames.size()) { if (m_show_inlined_frames) { // When inline frames are enabled we actually create all the frames in @@ -772,9 +797,52 @@ bool StackFrameList::SetFrameAtIndex(uint32_t idx, StackFrameSP &frame_sp) { return false; // resize failed, out of memory? } -uint32_t StackFrameList::GetSelectedFrameIndex() const { +void StackFrameList::SelectMostRelevantFrame() { + // Don't call into the frame recognizers on the private state thread as + // they can cause code to run in the target, and that can cause deadlocks + // when fetching stop events for the expression. + if (m_thread.GetProcess()->CurrentThreadIsPrivateStateThread()) + return; + + Log *log = GetLog(LLDBLog::Thread); + + // Only the top frame should be recognized. + StackFrameSP frame_sp = GetFrameAtIndex(0); + if (!frame_sp) { + LLDB_LOG(log, "Failed to construct Frame #0"); + return; + } + + RecognizedStackFrameSP recognized_frame_sp = frame_sp->GetRecognizedFrame(); + + if (!recognized_frame_sp) { + LLDB_LOG(log, "Frame #0 not recognized"); + return; + } + + if (StackFrameSP most_relevant_frame_sp = + recognized_frame_sp->GetMostRelevantFrame()) { + LLDB_LOG(log, "Found most relevant frame at index {0}", + most_relevant_frame_sp->GetFrameIndex()); + SetSelectedFrame(most_relevant_frame_sp.get()); + } else { + LLDB_LOG(log, "No relevant frame!"); + } +} + +uint32_t StackFrameList::GetSelectedFrameIndex( + SelectMostRelevant select_most_relevant) { std::lock_guard<std::recursive_mutex> guard(m_mutex); - return m_selected_frame_idx; + if (!m_selected_frame_idx && select_most_relevant) + SelectMostRelevantFrame(); + if (!m_selected_frame_idx) { + // If we aren't selecting the most relevant frame, and the selected frame + // isn't set, then don't force a selection here, just return 0. + if (!select_most_relevant) + return 0; + m_selected_frame_idx = 0; + } + return *m_selected_frame_idx; } uint32_t StackFrameList::SetSelectedFrame(lldb_private::StackFrame *frame) { @@ -783,17 +851,19 @@ uint32_t StackFrameList::SetSelectedFrame(lldb_private::StackFrame *frame) { const_iterator begin = m_frames.begin(); const_iterator end = m_frames.end(); m_selected_frame_idx = 0; + for (pos = begin; pos != end; ++pos) { if (pos->get() == frame) { m_selected_frame_idx = std::distance(begin, pos); uint32_t inlined_depth = GetCurrentInlinedDepth(); if (inlined_depth != UINT32_MAX) - m_selected_frame_idx -= inlined_depth; + m_selected_frame_idx = *m_selected_frame_idx - inlined_depth; break; } } + SetDefaultFileAndLineToSelectedFrame(); - return m_selected_frame_idx; + return *m_selected_frame_idx; } bool StackFrameList::SetSelectedFrameByIndex(uint32_t idx) { @@ -809,7 +879,8 @@ bool StackFrameList::SetSelectedFrameByIndex(uint32_t idx) { void StackFrameList::SetDefaultFileAndLineToSelectedFrame() { if (m_thread.GetID() == m_thread.GetProcess()->GetThreadList().GetSelectedThread()->GetID()) { - StackFrameSP frame_sp(GetFrameAtIndex(GetSelectedFrameIndex())); + StackFrameSP frame_sp( + GetFrameAtIndex(GetSelectedFrameIndex(DoNoSelectMostRelevantFrame))); if (frame_sp) { SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextLineEntry); if (sc.line_entry.file) @@ -821,10 +892,16 @@ void StackFrameList::SetDefaultFileAndLineToSelectedFrame() { // The thread has been run, reset the number stack frames to zero so we can // determine how many frames we have lazily. +// Note, we don't actually re-use StackFrameLists, we always make a new +// StackFrameList every time we stop, and then copy frame information frame +// by frame from the old to the new StackFrameList. So the comment above, +// does not describe how StackFrameLists are currently used. +// Clear is currently only used to clear the list in the destructor. void StackFrameList::Clear() { std::lock_guard<std::recursive_mutex> guard(m_mutex); m_frames.clear(); m_concrete_frames_fetched = 0; + m_selected_frame_idx.reset(); } lldb::StackFrameSP @@ -863,7 +940,8 @@ size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame, else last_frame = first_frame + num_frames; - StackFrameSP selected_frame_sp = m_thread.GetSelectedFrame(); + StackFrameSP selected_frame_sp = + m_thread.GetSelectedFrame(DoNoSelectMostRelevantFrame); const char *unselected_marker = nullptr; std::string buffer; if (selected_frame_marker) { @@ -884,6 +962,14 @@ size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame, else marker = unselected_marker; } + // Check for interruption here. If we're fetching arguments, this loop + // can go slowly: + Debugger &dbg = m_thread.GetProcess()->GetTarget().GetDebugger(); + if (INTERRUPT_REQUESTED(dbg, + "Interrupted dumping stack for thread {0:hex} with {1} shown.", + m_thread.GetID(), num_frames_displayed)) + break; + if (!frame_sp->GetStatus(strm, show_frame_info, num_frames_with_source > (first_frame - frame_idx), diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp index 225234c0ffba..efc8fd269ac2 100644 --- a/lldb/source/Target/StopInfo.cpp +++ b/lldb/source/Target/StopInfo.cpp @@ -256,7 +256,7 @@ protected: if (!m_should_perform_action) return; m_should_perform_action = false; - bool internal_breakpoint = true; + bool all_stopping_locs_internal = true; ThreadSP thread_sp(m_thread_wp.lock()); @@ -332,7 +332,7 @@ protected: ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0)); Process *process = exe_ctx.GetProcessPtr(); - if (process->GetModIDRef().IsLastResumeForUserExpression()) { + if (process->GetModIDRef().IsRunningExpression()) { // If we are in the middle of evaluating an expression, don't run // asynchronous breakpoint commands or expressions. That could // lead to infinite recursion if the command or condition re-calls @@ -421,8 +421,6 @@ protected: continue; } - 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 = @@ -509,7 +507,7 @@ protected: loc_desc.GetData()); // We want this stop reported, so you will know we auto-continued // but only for external breakpoints: - if (!internal_breakpoint) + if (!bp_loc_sp->GetBreakpoint().IsInternal()) thread_sp->SetShouldReportStop(eVoteYes); auto_continue_says_stop = false; } @@ -539,6 +537,9 @@ protected: actually_said_continue = true; } + if (m_should_stop && !bp_loc_sp->GetBreakpoint().IsInternal()) + all_stopping_locs_internal = false; + // If we are going to stop for this breakpoint, then remove the // breakpoint. if (callback_says_stop && bp_loc_sp && @@ -576,7 +577,7 @@ protected: __FUNCTION__, m_value); } - if ((!m_should_stop || internal_breakpoint) && + if ((!m_should_stop || all_stopping_locs_internal) && thread_sp->CompletedPlanOverridesBreakpoint()) { // Override should_stop decision when we have completed step plan @@ -665,9 +666,8 @@ public: WatchpointSP watchpoint_sp; }; - StopInfoWatchpoint(Thread &thread, break_id_t watch_id, - lldb::addr_t watch_hit_addr) - : StopInfo(thread, watch_id), m_watch_hit_addr(watch_hit_addr) {} + StopInfoWatchpoint(Thread &thread, break_id_t watch_id, bool silently_skip_wp) + : StopInfo(thread, watch_id), m_silently_skip_wp(silently_skip_wp) {} ~StopInfoWatchpoint() override = default; @@ -822,22 +822,19 @@ protected: // stop ProcessSP process_sp = exe_ctx.GetProcessSP(); - uint32_t num; - bool wp_triggers_after; + bool wp_triggers_after = process_sp->GetWatchpointReportedAfter(); - if (!process_sp->GetWatchpointSupportInfo(num, wp_triggers_after) - .Success()) { - m_should_stop_is_valid = true; - m_should_stop = true; - return m_should_stop; - } - if (!wp_triggers_after) { // We have to step over the watchpoint before we know what to do: StopInfoWatchpointSP me_as_siwp_sp = std::static_pointer_cast<StopInfoWatchpoint>(shared_from_this()); ThreadPlanSP step_over_wp_sp(new ThreadPlanStepOverWatchpoint( *(thread_sp.get()), me_as_siwp_sp, wp_sp)); + // When this plan is done we want to stop, so set this as a Controlling + // plan. + step_over_wp_sp->SetIsControllingPlan(true); + step_over_wp_sp->SetOkayToDiscard(false); + Status error; error = thread_sp->QueueThreadPlan(step_over_wp_sp, false); // If we couldn't push the thread plan, just stop here: @@ -895,27 +892,9 @@ protected: WatchpointSentry sentry(process_sp, wp_sp); - /* - * MIPS: Last 3bits of the watchpoint address are masked by the kernel. - * For example: - * 'n' is at 0x120010d00 and 'm' is 0x120010d04. When a watchpoint is - * set at 'm', then - * watch exception is generated even when 'n' is read/written. To handle - * this case, - * server emulates the instruction at PC and finds the base address of - * the load/store - * instruction and appends it in the description of the stop-info - * packet. If watchpoint - * is not set on this address by user then this do not stop. - */ - if (m_watch_hit_addr != LLDB_INVALID_ADDRESS) { - WatchpointSP wp_hit_sp = - thread_sp->CalculateTarget()->GetWatchpointList().FindByAddress( - m_watch_hit_addr); - if (!wp_hit_sp) { - m_should_stop = false; - wp_sp->IncrementFalseAlarmsAndReviseHitCount(); - } + if (m_silently_skip_wp) { + m_should_stop = false; + wp_sp->UndoHitCount(); } if (wp_sp->GetHitCount() <= wp_sp->GetIgnoreCount()) { @@ -1037,7 +1016,17 @@ private: bool m_should_stop = false; bool m_should_stop_is_valid = false; - lldb::addr_t m_watch_hit_addr; + // A false watchpoint hit has happened - + // the thread stopped with a watchpoint + // hit notification, but the watched region + // was not actually accessed (as determined + // by the gdb stub we're talking to). + // Continue past this watchpoint without + // notifying the user; on some targets this + // may mean disable wp, instruction step, + // re-enable wp, continue. + // On others, just continue. + bool m_silently_skip_wp = false; bool m_step_over_plan_complete = false; bool m_using_step_over_plan = false; }; @@ -1046,8 +1035,9 @@ private: class StopInfoUnixSignal : public StopInfo { public: - StopInfoUnixSignal(Thread &thread, int signo, const char *description) - : StopInfo(thread, signo) { + StopInfoUnixSignal(Thread &thread, int signo, const char *description, + std::optional<int> code) + : StopInfo(thread, signo), m_code(code) { SetDescription(description); } @@ -1102,19 +1092,26 @@ public: if (m_description.empty()) { ThreadSP thread_sp(m_thread_wp.lock()); if (thread_sp) { + UnixSignalsSP unix_signals = thread_sp->GetProcess()->GetUnixSignals(); StreamString strm; - const char *signal_name = - thread_sp->GetProcess()->GetUnixSignals()->GetSignalAsCString( - m_value); - if (signal_name) - strm.Printf("signal %s", signal_name); + strm << "signal "; + + std::string signal_name = + unix_signals->GetSignalDescription(m_value, m_code); + if (signal_name.size()) + strm << signal_name; else - strm.Printf("signal %" PRIi64, m_value); + strm.Printf("%" PRIi64, m_value); + m_description = std::string(strm.GetString()); } } return m_description.c_str(); } + +private: + // In siginfo_t terms, if m_value is si_signo, m_code is si_code. + std::optional<int> m_code; }; // StopInfoTrace @@ -1366,16 +1363,18 @@ StopInfoSP StopInfo::CreateStopReasonWithBreakpointSiteID(Thread &thread, return StopInfoSP(new StopInfoBreakpoint(thread, break_id, should_stop)); } -StopInfoSP -StopInfo::CreateStopReasonWithWatchpointID(Thread &thread, break_id_t watch_id, - lldb::addr_t watch_hit_addr) { - return StopInfoSP(new StopInfoWatchpoint(thread, watch_id, watch_hit_addr)); +StopInfoSP StopInfo::CreateStopReasonWithWatchpointID(Thread &thread, + break_id_t watch_id, + bool silently_continue) { + return StopInfoSP( + new StopInfoWatchpoint(thread, watch_id, silently_continue)); } StopInfoSP StopInfo::CreateStopReasonWithSignal(Thread &thread, int signo, - const char *description) { + const char *description, + std::optional<int> code) { thread.GetProcess()->GetUnixSignals()->IncrementSignalHitCount(signo); - return StopInfoSP(new StopInfoUnixSignal(thread, signo, description)); + return StopInfoSP(new StopInfoUnixSignal(thread, signo, description, code)); } StopInfoSP StopInfo::CreateStopReasonToTrace(Thread &thread) { @@ -1457,7 +1456,8 @@ StopInfo::GetCrashingDereference(StopInfoSP &stop_info_sp, return ValueObjectSP(); } - StackFrameSP frame_sp = thread_sp->GetSelectedFrame(); + StackFrameSP frame_sp = + thread_sp->GetSelectedFrame(DoNoSelectMostRelevantFrame); if (!frame_sp) { return ValueObjectSP(); diff --git a/lldb/source/Target/StructuredDataPlugin.cpp b/lldb/source/Target/StructuredDataPlugin.cpp index 20ed26a1a99a..1b5894b5df4b 100644 --- a/lldb/source/Target/StructuredDataPlugin.cpp +++ b/lldb/source/Target/StructuredDataPlugin.cpp @@ -32,7 +32,7 @@ StructuredDataPlugin::StructuredDataPlugin(const ProcessWP &process_wp) StructuredDataPlugin::~StructuredDataPlugin() = default; -bool StructuredDataPlugin::GetEnabled(ConstString type_name) const { +bool StructuredDataPlugin::GetEnabled(llvm::StringRef type_name) const { // By default, plugins are always enabled. Plugin authors should override // this if there is an enabled/disabled state for their plugin. return true; diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index fd0cf0a5361d..f0c57ef83c4a 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -46,6 +46,7 @@ #include "lldb/Target/Language.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/Process.h" +#include "lldb/Target/RegisterTypeBuilder.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/StackFrameRecognizer.h" @@ -68,6 +69,7 @@ #include <memory> #include <mutex> #include <optional> +#include <sstream> using namespace lldb; using namespace lldb_private; @@ -292,6 +294,7 @@ void Target::Destroy() { m_stop_hooks.clear(); m_stop_hook_next_id = 0; m_suppress_stop_hooks = false; + m_repl_map.clear(); Args signal_args; ClearDummySignals(signal_args); } @@ -790,19 +793,18 @@ bool Target::ProcessIsValid() { } static bool CheckIfWatchpointsSupported(Target *target, Status &error) { - uint32_t num_supported_hardware_watchpoints; - Status rc = target->GetProcessSP()->GetWatchpointSupportInfo( - num_supported_hardware_watchpoints); + std::optional<uint32_t> num_supported_hardware_watchpoints = + target->GetProcessSP()->GetWatchpointSlotCount(); // If unable to determine the # of watchpoints available, // assume they are supported. - if (rc.Fail()) + if (!num_supported_hardware_watchpoints) return true; if (num_supported_hardware_watchpoints == 0) { error.SetErrorStringWithFormat( "Target supports (%u) hardware watchpoint slots.\n", - num_supported_hardware_watchpoints); + *num_supported_hardware_watchpoints); return false; } return true; @@ -1391,8 +1393,8 @@ static void LoadScriptingResourceForModule(const ModuleSP &module_sp, Target *target) { Status error; StreamString feedback_stream; - if (module_sp && !module_sp->LoadScriptingResourceInTarget( - target, error, &feedback_stream)) { + if (module_sp && !module_sp->LoadScriptingResourceInTarget(target, error, + feedback_stream)) { if (error.AsCString()) target->GetDebugger().GetErrorStream().Printf( "unable to load scripting data for module %s - error reported was " @@ -2127,19 +2129,46 @@ ModuleSP Target::GetOrCreateModule(const ModuleSpec &module_spec, bool notify, // of the library bool did_create_module = false; FileSpecList search_paths = GetExecutableSearchPaths(); - // If there are image search path entries, try to use them first to acquire - // a suitable image. - if (m_image_search_paths.GetSize()) { - ModuleSpec transformed_spec(module_spec); - ConstString transformed_dir; - if (m_image_search_paths.RemapPath( - module_spec.GetFileSpec().GetDirectory(), transformed_dir)) { - transformed_spec.GetFileSpec().SetDirectory(transformed_dir); - transformed_spec.GetFileSpec().SetFilename( - module_spec.GetFileSpec().GetFilename()); - error = ModuleList::GetSharedModule(transformed_spec, module_sp, - &search_paths, &old_modules, - &did_create_module); + FileSpec symbol_file_spec; + + // Call locate module callback if set. This allows users to implement their + // own module cache system. For example, to leverage build system artifacts, + // to bypass pulling files from remote platform, or to search symbol files + // from symbol servers. + CallLocateModuleCallbackIfSet(module_spec, module_sp, symbol_file_spec, + did_create_module); + + // The result of this CallLocateModuleCallbackIfSet is one of the following. + // 1. module_sp:loaded, symbol_file_spec:set + // The callback found a module file and a symbol file for the + // module_spec. We will call module_sp->SetSymbolFileFileSpec with + // the symbol_file_spec later. + // 2. module_sp:loaded, symbol_file_spec:empty + // The callback only found a module file for the module_spec. + // 3. module_sp:empty, symbol_file_spec:set + // The callback only found a symbol file for the module. We continue + // to find a module file for this module_spec and we will call + // module_sp->SetSymbolFileFileSpec with the symbol_file_spec later. + // 4. module_sp:empty, symbol_file_spec:empty + // The callback is not set. Or the callback did not find any module + // files nor any symbol files. Or the callback failed, or something + // went wrong. We continue to find a module file for this module_spec. + + if (!module_sp) { + // If there are image search path entries, try to use them to acquire a + // suitable image. + if (m_image_search_paths.GetSize()) { + ModuleSpec transformed_spec(module_spec); + ConstString transformed_dir; + if (m_image_search_paths.RemapPath( + module_spec.GetFileSpec().GetDirectory(), transformed_dir)) { + transformed_spec.GetFileSpec().SetDirectory(transformed_dir); + transformed_spec.GetFileSpec().SetFilename( + module_spec.GetFileSpec().GetFilename()); + error = ModuleList::GetSharedModule(transformed_spec, module_sp, + &search_paths, &old_modules, + &did_create_module); + } } } @@ -2230,11 +2259,15 @@ ModuleSP Target::GetOrCreateModule(const ModuleSpec &module_spec, bool notify, }); } + // If the locate module callback had found a symbol file, set it to the + // module_sp before preloading symbols. + if (symbol_file_spec) + module_sp->SetSymbolFileFileSpec(symbol_file_spec); + // Preload symbols outside of any lock, so hopefully we can do this for // each library in parallel. if (GetPreloadSymbols()) module_sp->PreloadSymbols(); - llvm::SmallVector<ModuleSP, 1> replaced_modules; for (ModuleSP &old_module_sp : old_modules) { if (m_images.GetIndexForModule(old_module_sp.get()) != @@ -2269,7 +2302,7 @@ ModuleSP Target::GetOrCreateModule(const ModuleSpec &module_spec, bool notify, message << " (uuid "; if (dump_uuid.IsValid()) - dump_uuid.Dump(&message); + dump_uuid.Dump(message); else message << "not specified"; @@ -2305,6 +2338,113 @@ ModuleSP Target::GetOrCreateModule(const ModuleSpec &module_spec, bool notify, return module_sp; } +void Target::CallLocateModuleCallbackIfSet(const ModuleSpec &module_spec, + lldb::ModuleSP &module_sp, + FileSpec &symbol_file_spec, + bool &did_create_module) { + if (!m_platform_sp) + return; + + Platform::LocateModuleCallback locate_module_callback = + m_platform_sp->GetLocateModuleCallback(); + if (!locate_module_callback) + return; + + FileSpec module_file_spec; + Status error = + locate_module_callback(module_spec, module_file_spec, symbol_file_spec); + + // Locate module callback is set and called. Check the error. + Log *log = GetLog(LLDBLog::Target); + if (error.Fail()) { + LLDB_LOGF(log, "%s: locate module callback failed: %s", + LLVM_PRETTY_FUNCTION, error.AsCString()); + return; + } + + // The locate module callback was succeeded. It should returned + // 1. a combination of a module file and a symbol file. + // 2. or only a module file. + // 3. or only a symbol file. For example, a breakpad symbol text file. + // + // Check the module_file_spec and symbol_file_spec values. + // 1. module:empty symbol:empty -> Invalid + // 2. module:exists symbol:exists -> Success + // 3. module:exists symbol:empty -> Success + // 4. module:empty symbol:exists -> Success + if (!module_file_spec && !symbol_file_spec) { + // This is '1. module:empty symbol:empty -> Invalid'. + LLDB_LOGF(log, + "%s: locate module callback did not set both " + "module_file_spec and symbol_file_spec", + LLVM_PRETTY_FUNCTION); + return; + } + + // The module file should exist. + if (module_file_spec && !FileSystem::Instance().Exists(module_file_spec)) { + LLDB_LOGF(log, + "%s: locate module callback set a non-existent file to " + "module_file_spec: %s", + LLVM_PRETTY_FUNCTION, module_file_spec.GetPath().c_str()); + // Clear symbol_file_spec for the error. + symbol_file_spec.Clear(); + return; + } + + // The symbol file should exist. + if (symbol_file_spec && !FileSystem::Instance().Exists(symbol_file_spec)) { + LLDB_LOGF(log, + "%s: locate module callback set a non-existent file to " + "symbol_file_spec: %s", + LLVM_PRETTY_FUNCTION, symbol_file_spec.GetPath().c_str()); + // Clear symbol_file_spec for the error. + symbol_file_spec.Clear(); + return; + } + + if (!module_file_spec && symbol_file_spec) { + // This is '4. module:empty symbol:exists -> Success'. + // The locate module callback returned only a symbol file. For example, + // a breakpad symbol text file. GetOrCreateModule will use this returned + // symbol_file_spec. + LLDB_LOGF(log, "%s: locate module callback succeeded: symbol=%s", + LLVM_PRETTY_FUNCTION, symbol_file_spec.GetPath().c_str()); + return; + } + + // The locate module callback returned + // - '2. module:exists symbol:exists -> Success' + // - a combination of a module file and a symbol file. + // - Or '3. module:exists symbol:empty -> Success' + // - only a module file. + // Load the module file. + auto cached_module_spec(module_spec); + cached_module_spec.GetUUID().Clear(); // Clear UUID since it may contain md5 + // content hash instead of real UUID. + cached_module_spec.GetFileSpec() = module_file_spec; + cached_module_spec.GetPlatformFileSpec() = module_spec.GetFileSpec(); + cached_module_spec.SetObjectOffset(0); + + error = ModuleList::GetSharedModule(cached_module_spec, module_sp, nullptr, + nullptr, &did_create_module, false); + if (error.Success() && module_sp) { + // Succeeded to load the module file. + LLDB_LOGF(log, "%s: locate module callback succeeded: module=%s symbol=%s", + LLVM_PRETTY_FUNCTION, module_file_spec.GetPath().c_str(), + symbol_file_spec.GetPath().c_str()); + } else { + LLDB_LOGF(log, + "%s: locate module callback succeeded but failed to load: " + "module=%s symbol=%s", + LLVM_PRETTY_FUNCTION, module_file_spec.GetPath().c_str(), + symbol_file_spec.GetPath().c_str()); + // Clear module_sp and symbol_file_spec for the error. + module_sp.reset(); + symbol_file_spec.Clear(); + } +} + TargetSP Target::CalculateTarget() { return shared_from_this(); } ProcessSP Target::CalculateProcess() { return m_process_sp; } @@ -2359,6 +2499,14 @@ Target::GetScratchTypeSystemForLanguage(lldb::LanguageType language, create_on_demand); } +CompilerType Target::GetRegisterType(const std::string &name, + const lldb_private::RegisterFlags &flags, + uint32_t byte_size) { + RegisterTypeBuilderSP provider = PluginManager::GetRegisterTypeBuilder(*this); + assert(provider); + return provider->GetRegisterType(name, flags, byte_size); +} + std::vector<lldb::TypeSystemSP> Target::GetScratchTypeSystems(bool create_on_demand) { if (!m_valid) @@ -2377,18 +2525,17 @@ Target::GetScratchTypeSystems(bool create_on_demand) { auto type_system_or_err = GetScratchTypeSystemForLanguage(language, create_on_demand); if (!type_system_or_err) - LLDB_LOG_ERROR(GetLog(LLDBLog::Target), type_system_or_err.takeError(), - "Language '{}' has expression support but no scratch type " - "system available", - Language::GetNameForLanguageType(language)); + LLDB_LOG_ERROR( + GetLog(LLDBLog::Target), type_system_or_err.takeError(), + "Language '{1}' has expression support but no scratch type " + "system available: {0}", + Language::GetNameForLanguageType(language)); else if (auto ts = *type_system_or_err) scratch_type_systems.push_back(ts); } - std::sort(scratch_type_systems.begin(), scratch_type_systems.end(), - [](lldb::TypeSystemSP a, lldb::TypeSystemSP b) { - return a.get() <= b.get(); - }); + + std::sort(scratch_type_systems.begin(), scratch_type_systems.end()); scratch_type_systems.erase( std::unique(scratch_type_systems.begin(), scratch_type_systems.end()), scratch_type_systems.end()); @@ -2400,9 +2547,10 @@ Target::GetPersistentExpressionStateForLanguage(lldb::LanguageType language) { auto type_system_or_err = GetScratchTypeSystemForLanguage(language, true); if (auto err = type_system_or_err.takeError()) { - LLDB_LOG_ERROR(GetLog(LLDBLog::Target), std::move(err), - "Unable to get persistent expression state for language {}", - Language::GetNameForLanguageType(language)); + LLDB_LOG_ERROR( + GetLog(LLDBLog::Target), std::move(err), + "Unable to get persistent expression state for language {1}: {0}", + Language::GetNameForLanguageType(language)); return nullptr; } @@ -2410,7 +2558,7 @@ Target::GetPersistentExpressionStateForLanguage(lldb::LanguageType language) { return ts->GetPersistentExpressionState(); LLDB_LOG(GetLog(LLDBLog::Target), - "Unable to get persistent expression state for language {}", + "Unable to get persistent expression state for language {1}: {0}", Language::GetNameForLanguageType(language)); return nullptr; } @@ -2529,6 +2677,27 @@ void Target::SetDefaultArchitecture(const ArchSpec &arch) { Target::GetGlobalProperties().SetDefaultArchitecture(arch); } +llvm::Error Target::SetLabel(llvm::StringRef label) { + size_t n = LLDB_INVALID_INDEX32; + if (llvm::to_integer(label, n)) + return llvm::make_error<llvm::StringError>( + "Cannot use integer as target label.", llvm::inconvertibleErrorCode()); + TargetList &targets = GetDebugger().GetTargetList(); + for (size_t i = 0; i < targets.GetNumTargets(); i++) { + TargetSP target_sp = targets.GetTargetAtIndex(i); + if (target_sp && target_sp->GetLabel() == label) { + return llvm::make_error<llvm::StringError>( + llvm::formatv( + "Cannot use label '{0}' since it's set in target #{1}.", label, + i), + llvm::inconvertibleErrorCode()); + } + } + + m_label = label.str(); + return llvm::Error::success(); +} + Target *Target::GetTargetFromContexts(const ExecutionContext *exe_ctx_ptr, const SymbolContext *sc_ptr) { // The target can either exist in the "process" of ExecutionContext, or in @@ -2588,7 +2757,7 @@ ExpressionResults Target::EvaluateExpression( auto ts = *type_system_or_err; if (!ts) LLDB_LOG_ERROR(GetLog(LLDBLog::Target), std::move(err), - "Scratch type system is no longer live"); + "Scratch type system is no longer live: {0}"); else persistent_var_sp = ts->GetPersistentExpressionState()->GetVariable(expr); @@ -2863,7 +3032,7 @@ bool Target::RunStopHooks() { if (print_hook_header && !any_thread_matched) { StreamString s; - cur_hook_sp->GetDescription(&s, eDescriptionLevelBrief); + cur_hook_sp->GetDescription(s, eDescriptionLevelBrief); if (s.GetSize() != 0) output_sp->Printf("\n- Hook %" PRIu64 " (%s)\n", cur_hook_sp->GetID(), s.GetData()); @@ -3082,6 +3251,17 @@ bool Target::SetSectionUnloaded(const lldb::SectionSP §ion_sp, void Target::ClearAllLoadedSections() { m_section_load_history.Clear(); } +void Target::SaveScriptedLaunchInfo(lldb_private::ProcessInfo &process_info) { + if (process_info.IsScriptedProcess()) { + // Only copy scripted process launch options. + ProcessLaunchInfo &default_launch_info = const_cast<ProcessLaunchInfo &>( + GetGlobalProperties().GetProcessLaunchInfo()); + default_launch_info.SetProcessPluginName("ScriptedProcess"); + default_launch_info.SetScriptedMetadata(process_info.GetScriptedMetadata()); + SetProcessLaunchInfo(default_launch_info); + } +} + Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { m_stats.SetLaunchOrAttachTime(); Status error; @@ -3111,19 +3291,7 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { launch_info.GetFlags().Set(eLaunchFlagDebug); - if (launch_info.IsScriptedProcess()) { - // Only copy scripted process launch options. - ProcessLaunchInfo &default_launch_info = const_cast<ProcessLaunchInfo &>( - GetGlobalProperties().GetProcessLaunchInfo()); - - default_launch_info.SetProcessPluginName("ScriptedProcess"); - default_launch_info.SetScriptedProcessClassName( - launch_info.GetScriptedProcessClassName()); - default_launch_info.SetScriptedProcessDictionarySP( - launch_info.GetScriptedProcessDictionarySP()); - - SetProcessLaunchInfo(launch_info); - } + SaveScriptedLaunchInfo(launch_info); // Get the value of synchronous execution here. If you wait till after you // have started to run, then you could have hit a breakpoint, whose command @@ -3152,8 +3320,8 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { // its own hijacking listener or if the process is created by the target // manually, without the platform). if (!launch_info.GetHijackListener()) - launch_info.SetHijackListener( - Listener::MakeListener("lldb.Target.Launch.hijack")); + launch_info.SetHijackListener(Listener::MakeListener( + Process::LaunchSynchronousHijackListenerName.data())); // If we're not already connected to the process, and if we have a platform // that can launch a process for debugging, go ahead and do that here. @@ -3181,13 +3349,14 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { assert(m_process_sp); } else { // Use a Process plugin to construct the process. - const char *plugin_name = launch_info.GetProcessPluginName(); - CreateProcess(launch_info.GetListener(), plugin_name, nullptr, false); + CreateProcess(launch_info.GetListener(), + launch_info.GetProcessPluginName(), nullptr, false); } // Since we didn't have a platform launch the process, launch it here. if (m_process_sp) { m_process_sp->HijackProcessEvents(launch_info.GetHijackListener()); + m_process_sp->SetShadowListener(launch_info.GetShadowListener()); error = m_process_sp->Launch(launch_info); } } @@ -3226,7 +3395,7 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { // SyncResume hijacker. m_process_sp->ResumeSynchronous(stream); else - error = m_process_sp->PrivateResume(); + error = m_process_sp->Resume(); if (!error.Success()) { Status error2; error2.SetErrorStringWithFormat( @@ -3329,26 +3498,27 @@ Status Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) { ListenerSP hijack_listener_sp; const bool async = attach_info.GetAsync(); if (!async) { - hijack_listener_sp = - Listener::MakeListener("lldb.Target.Attach.attach.hijack"); + hijack_listener_sp = Listener::MakeListener( + Process::AttachSynchronousHijackListenerName.data()); attach_info.SetHijackListener(hijack_listener_sp); } Status error; if (state != eStateConnected && platform_sp != nullptr && - platform_sp->CanDebugProcess()) { + platform_sp->CanDebugProcess() && !attach_info.IsScriptedProcess()) { SetPlatform(platform_sp); process_sp = platform_sp->Attach(attach_info, GetDebugger(), this, error); } else { if (state != eStateConnected) { - const char *plugin_name = attach_info.GetProcessPluginName(); + SaveScriptedLaunchInfo(attach_info); + llvm::StringRef plugin_name = attach_info.GetProcessPluginName(); process_sp = CreateProcess(attach_info.GetListenerForProcess(GetDebugger()), plugin_name, nullptr, false); - if (process_sp == nullptr) { - error.SetErrorStringWithFormat( - "failed to create process using plugin %s", - (plugin_name) ? plugin_name : "null"); + if (!process_sp) { + error.SetErrorStringWithFormatv( + "failed to create process using plugin '{0}'", + plugin_name.empty() ? "<empty>" : plugin_name); return error; } } @@ -3361,9 +3531,10 @@ Status Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) { if (async) { process_sp->RestoreProcessEvents(); } else { - state = process_sp->WaitForProcessToStop(std::nullopt, nullptr, false, - attach_info.GetHijackListener(), - stream); + // We are stopping all the way out to the user, so update selected frames. + state = process_sp->WaitForProcessToStop( + std::nullopt, nullptr, false, attach_info.GetHijackListener(), stream, + true, SelectMostRelevantFrame); process_sp->RestoreProcessEvents(); if (state != eStateStopped) { @@ -3620,7 +3791,7 @@ bool Target::StopHook::ExecutionContextPasses(const ExecutionContext &exc_ctx) { return will_run; } -void Target::StopHook::GetDescription(Stream *s, +void Target::StopHook::GetDescription(Stream &s, lldb::DescriptionLevel level) const { // For brief descriptions, only print the subclass description: @@ -3629,55 +3800,55 @@ void Target::StopHook::GetDescription(Stream *s, return; } - unsigned indent_level = s->GetIndentLevel(); + unsigned indent_level = s.GetIndentLevel(); - s->SetIndentLevel(indent_level + 2); + s.SetIndentLevel(indent_level + 2); - s->Printf("Hook: %" PRIu64 "\n", GetID()); + s.Printf("Hook: %" PRIu64 "\n", GetID()); if (m_active) - s->Indent("State: enabled\n"); + s.Indent("State: enabled\n"); else - s->Indent("State: disabled\n"); + s.Indent("State: disabled\n"); if (m_auto_continue) - s->Indent("AutoContinue on\n"); + s.Indent("AutoContinue on\n"); if (m_specifier_sp) { - s->Indent(); - s->PutCString("Specifier:\n"); - s->SetIndentLevel(indent_level + 4); - m_specifier_sp->GetDescription(s, level); - s->SetIndentLevel(indent_level + 2); + s.Indent(); + s.PutCString("Specifier:\n"); + s.SetIndentLevel(indent_level + 4); + m_specifier_sp->GetDescription(&s, level); + s.SetIndentLevel(indent_level + 2); } if (m_thread_spec_up) { StreamString tmp; - s->Indent("Thread:\n"); + s.Indent("Thread:\n"); m_thread_spec_up->GetDescription(&tmp, level); - s->SetIndentLevel(indent_level + 4); - s->Indent(tmp.GetString()); - s->PutCString("\n"); - s->SetIndentLevel(indent_level + 2); + s.SetIndentLevel(indent_level + 4); + s.Indent(tmp.GetString()); + s.PutCString("\n"); + s.SetIndentLevel(indent_level + 2); } GetSubclassDescription(s, level); } void Target::StopHookCommandLine::GetSubclassDescription( - Stream *s, lldb::DescriptionLevel level) const { + Stream &s, lldb::DescriptionLevel level) const { // The brief description just prints the first command. if (level == eDescriptionLevelBrief) { if (m_commands.GetSize() == 1) - s->PutCString(m_commands.GetStringAtIndex(0)); + s.PutCString(m_commands.GetStringAtIndex(0)); return; } - s->Indent("Commands: \n"); - s->SetIndentLevel(s->GetIndentLevel() + 4); + s.Indent("Commands: \n"); + s.SetIndentLevel(s.GetIndentLevel() + 4); uint32_t num_commands = m_commands.GetSize(); for (uint32_t i = 0; i < num_commands; i++) { - s->Indent(m_commands.GetStringAtIndex(i)); - s->PutCString("\n"); + s.Indent(m_commands.GetStringAtIndex(i)); + s.PutCString("\n"); } - s->SetIndentLevel(s->GetIndentLevel() - 4); + s.SetIndentLevel(s.GetIndentLevel() - 4); } // Target::StopHookCommandLine @@ -3765,13 +3936,13 @@ Target::StopHookScripted::HandleStop(ExecutionContext &exc_ctx, } void Target::StopHookScripted::GetSubclassDescription( - Stream *s, lldb::DescriptionLevel level) const { + Stream &s, lldb::DescriptionLevel level) const { if (level == eDescriptionLevelBrief) { - s->PutCString(m_class_name); + s.PutCString(m_class_name); return; } - s->Indent("Class:"); - s->Printf("%s\n", m_class_name.c_str()); + s.Indent("Class:"); + s.Printf("%s\n", m_class_name.c_str()); // Now print the extra args: // FIXME: We should use StructuredData.GetDescription on the m_extra_args @@ -3790,20 +3961,20 @@ void Target::StopHookScripted::GetSubclassDescription( if (num_keys == 0) return; - s->Indent("Args:\n"); - s->SetIndentLevel(s->GetIndentLevel() + 4); + s.Indent("Args:\n"); + s.SetIndentLevel(s.GetIndentLevel() + 4); auto print_one_element = [&s](ConstString key, StructuredData::Object *object) { - s->Indent(); - s->Printf("%s : %s\n", key.GetCString(), + s.Indent(); + s.Printf("%s : %s\n", key.GetCString(), object->GetStringValue().str().c_str()); return true; }; as_dict->ForEach(print_one_element); - s->SetIndentLevel(s->GetIndentLevel() - 4); + s.SetIndentLevel(s.GetIndentLevel() - 4); } static constexpr OptionEnumValueElement g_dynamic_value_types[] = { @@ -3998,9 +4169,9 @@ class TargetOptionValueProperties public: TargetOptionValueProperties(ConstString name) : Cloneable(name) {} - const Property *GetPropertyAtIndex(const ExecutionContext *exe_ctx, - bool will_modify, - uint32_t idx) const override { + const Property * + GetPropertyAtIndex(size_t idx, + const ExecutionContext *exe_ctx = nullptr) const override { // When getting the value for a key from the target options, we will always // try and grab the setting from the current target if there is one. Else // we just use the one from this instance. @@ -4081,9 +4252,9 @@ TargetProperties::TargetProperties(Target *target) m_experimental_properties_up = std::make_unique<TargetExperimentalProperties>(); m_collection_sp->AppendProperty( - ConstString(Properties::GetExperimentalSettingsName()), - ConstString("Experimental settings - setting these won't produce " - "errors if the setting is not present."), + Properties::GetExperimentalSettingsName(), + "Experimental settings - setting these won't produce " + "errors if the setting is not present.", true, m_experimental_properties_up->GetValueProperties()); } else { m_collection_sp = @@ -4092,13 +4263,13 @@ TargetProperties::TargetProperties(Target *target) m_experimental_properties_up = std::make_unique<TargetExperimentalProperties>(); m_collection_sp->AppendProperty( - ConstString(Properties::GetExperimentalSettingsName()), - ConstString("Experimental settings - setting these won't produce " - "errors if the setting is not present."), + Properties::GetExperimentalSettingsName(), + "Experimental settings - setting these won't produce " + "errors if the setting is not present.", true, m_experimental_properties_up->GetValueProperties()); m_collection_sp->AppendProperty( - ConstString("process"), ConstString("Settings specific to processes."), - true, Process::GetGlobalProperties().GetValueProperties()); + "process", "Settings specific to processes.", true, + Process::GetGlobalProperties().GetValueProperties()); m_collection_sp->SetValueChangedCallback( ePropertySaveObjectsDir, [this] { CheckJITObjectsDir(); }); } @@ -4121,13 +4292,14 @@ void TargetProperties::UpdateLaunchInfoFromProperties() { bool TargetProperties::GetInjectLocalVariables( ExecutionContext *exe_ctx) const { - const Property *exp_property = m_collection_sp->GetPropertyAtIndex( - exe_ctx, false, ePropertyExperimental); + const Property *exp_property = + m_collection_sp->GetPropertyAtIndex(ePropertyExperimental, exe_ctx); OptionValueProperties *exp_values = exp_property->GetValue()->GetAsProperties(); if (exp_values) - return exp_values->GetPropertyAtIndexAsBoolean( - exe_ctx, ePropertyInjectLocalVars, true); + return exp_values + ->GetPropertyAtIndexAs<bool>(ePropertyInjectLocalVars, exe_ctx) + .value_or(true); else return true; } @@ -4135,100 +4307,98 @@ bool TargetProperties::GetInjectLocalVariables( void TargetProperties::SetInjectLocalVariables(ExecutionContext *exe_ctx, bool b) { const Property *exp_property = - m_collection_sp->GetPropertyAtIndex(exe_ctx, true, ePropertyExperimental); + m_collection_sp->GetPropertyAtIndex(ePropertyExperimental, exe_ctx); OptionValueProperties *exp_values = exp_property->GetValue()->GetAsProperties(); if (exp_values) - exp_values->SetPropertyAtIndexAsBoolean(exe_ctx, ePropertyInjectLocalVars, - true); + exp_values->SetPropertyAtIndex(ePropertyInjectLocalVars, true, exe_ctx); } ArchSpec TargetProperties::GetDefaultArchitecture() const { - OptionValueArch *value = m_collection_sp->GetPropertyAtIndexAsOptionValueArch( - nullptr, ePropertyDefaultArch); - if (value) - return value->GetCurrentValue(); - return ArchSpec(); + const uint32_t idx = ePropertyDefaultArch; + return GetPropertyAtIndexAs<ArchSpec>(idx, {}); } void TargetProperties::SetDefaultArchitecture(const ArchSpec &arch) { - OptionValueArch *value = m_collection_sp->GetPropertyAtIndexAsOptionValueArch( - nullptr, ePropertyDefaultArch); - if (value) - return value->SetCurrentValue(arch, true); + const uint32_t idx = ePropertyDefaultArch; + SetPropertyAtIndex(idx, arch); } bool TargetProperties::GetMoveToNearestCode() const { const uint32_t idx = ePropertyMoveToNearestCode; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_target_properties[idx].default_uint_value != 0); } lldb::DynamicValueType TargetProperties::GetPreferDynamicValue() const { const uint32_t idx = ePropertyPreferDynamic; - return (lldb::DynamicValueType) - m_collection_sp->GetPropertyAtIndexAsEnumeration( - nullptr, idx, g_target_properties[idx].default_uint_value); + return GetPropertyAtIndexAs<lldb::DynamicValueType>( + idx, static_cast<lldb::DynamicValueType>( + g_target_properties[idx].default_uint_value)); } bool TargetProperties::SetPreferDynamicValue(lldb::DynamicValueType d) { const uint32_t idx = ePropertyPreferDynamic; - return m_collection_sp->SetPropertyAtIndexAsEnumeration(nullptr, idx, d); + return SetPropertyAtIndex(idx, d); } bool TargetProperties::GetPreloadSymbols() const { + if (INTERRUPT_REQUESTED(m_target->GetDebugger(), + "Interrupted checking preload symbols")) { + return false; + } const uint32_t idx = ePropertyPreloadSymbols; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_target_properties[idx].default_uint_value != 0); } void TargetProperties::SetPreloadSymbols(bool b) { const uint32_t idx = ePropertyPreloadSymbols; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); + SetPropertyAtIndex(idx, b); } bool TargetProperties::GetDisableASLR() const { const uint32_t idx = ePropertyDisableASLR; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_target_properties[idx].default_uint_value != 0); } void TargetProperties::SetDisableASLR(bool b) { const uint32_t idx = ePropertyDisableASLR; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); + SetPropertyAtIndex(idx, b); } bool TargetProperties::GetInheritTCC() const { const uint32_t idx = ePropertyInheritTCC; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_target_properties[idx].default_uint_value != 0); } void TargetProperties::SetInheritTCC(bool b) { const uint32_t idx = ePropertyInheritTCC; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); + SetPropertyAtIndex(idx, b); } bool TargetProperties::GetDetachOnError() const { const uint32_t idx = ePropertyDetachOnError; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_target_properties[idx].default_uint_value != 0); } void TargetProperties::SetDetachOnError(bool b) { const uint32_t idx = ePropertyDetachOnError; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); + SetPropertyAtIndex(idx, b); } bool TargetProperties::GetDisableSTDIO() const { const uint32_t idx = ePropertyDisableSTDIO; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_target_properties[idx].default_uint_value != 0); } void TargetProperties::SetDisableSTDIO(bool b) { const uint32_t idx = ePropertyDisableSTDIO; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); + SetPropertyAtIndex(idx, b); } const char *TargetProperties::GetDisassemblyFlavor() const { @@ -4236,38 +4406,41 @@ const char *TargetProperties::GetDisassemblyFlavor() const { const char *return_value; x86DisassemblyFlavor flavor_value = - (x86DisassemblyFlavor)m_collection_sp->GetPropertyAtIndexAsEnumeration( - nullptr, idx, g_target_properties[idx].default_uint_value); + GetPropertyAtIndexAs<x86DisassemblyFlavor>( + idx, static_cast<x86DisassemblyFlavor>( + g_target_properties[idx].default_uint_value)); + return_value = g_x86_dis_flavor_value_types[flavor_value].string_value; return return_value; } InlineStrategy TargetProperties::GetInlineStrategy() const { const uint32_t idx = ePropertyInlineStrategy; - return (InlineStrategy)m_collection_sp->GetPropertyAtIndexAsEnumeration( - nullptr, idx, g_target_properties[idx].default_uint_value); + return GetPropertyAtIndexAs<InlineStrategy>( + idx, + static_cast<InlineStrategy>(g_target_properties[idx].default_uint_value)); } llvm::StringRef TargetProperties::GetArg0() const { const uint32_t idx = ePropertyArg0; - return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, - llvm::StringRef()); + return GetPropertyAtIndexAs<llvm::StringRef>( + idx, g_target_properties[idx].default_cstr_value); } void TargetProperties::SetArg0(llvm::StringRef arg) { const uint32_t idx = ePropertyArg0; - m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, arg); + SetPropertyAtIndex(idx, arg); m_launch_info.SetArg0(arg); } bool TargetProperties::GetRunArguments(Args &args) const { const uint32_t idx = ePropertyRunArgs; - return m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, idx, args); + return m_collection_sp->GetPropertyAtIndexAsArgs(idx, args); } void TargetProperties::SetRunArguments(const Args &args) { const uint32_t idx = ePropertyRunArgs; - m_collection_sp->SetPropertyAtIndexFromArgs(nullptr, idx, args); + m_collection_sp->SetPropertyAtIndexFromArgs(idx, args); m_launch_info.GetArguments() = args; } @@ -4275,8 +4448,8 @@ Environment TargetProperties::ComputeEnvironment() const { Environment env; if (m_target && - m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, ePropertyInheritEnv, + GetPropertyAtIndexAs<bool>( + ePropertyInheritEnv, g_target_properties[ePropertyInheritEnv].default_uint_value != 0)) { if (auto platform_sp = m_target->GetPlatform()) { Environment platform_env = platform_sp->GetEnvironment(); @@ -4286,14 +4459,13 @@ Environment TargetProperties::ComputeEnvironment() const { } Args property_unset_env; - m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, ePropertyUnsetEnvVars, + m_collection_sp->GetPropertyAtIndexAsArgs(ePropertyUnsetEnvVars, property_unset_env); for (const auto &var : property_unset_env) env.erase(var.ref()); Args property_env; - m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, ePropertyEnvVars, - property_env); + m_collection_sp->GetPropertyAtIndexAsArgs(ePropertyEnvVars, property_env); for (const auto &KV : Environment(property_env)) env[KV.first()] = KV.second; @@ -4310,8 +4482,8 @@ Environment TargetProperties::GetInheritedEnvironment() const { if (m_target == nullptr) return environment; - if (!m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, ePropertyInheritEnv, + if (!GetPropertyAtIndexAs<bool>( + ePropertyInheritEnv, g_target_properties[ePropertyInheritEnv].default_uint_value != 0)) return environment; @@ -4324,7 +4496,7 @@ Environment TargetProperties::GetInheritedEnvironment() const { environment[KV.first()] = KV.second; Args property_unset_environment; - m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, ePropertyUnsetEnvVars, + m_collection_sp->GetPropertyAtIndexAsArgs(ePropertyUnsetEnvVars, property_unset_environment); for (const auto &var : property_unset_environment) environment.erase(var.ref()); @@ -4334,7 +4506,7 @@ Environment TargetProperties::GetInheritedEnvironment() const { Environment TargetProperties::GetTargetEnvironment() const { Args property_environment; - m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, ePropertyEnvVars, + m_collection_sp->GetPropertyAtIndexAsArgs(ePropertyEnvVars, property_environment); Environment environment; for (const auto &KV : Environment(property_environment)) @@ -4346,106 +4518,93 @@ Environment TargetProperties::GetTargetEnvironment() const { void TargetProperties::SetEnvironment(Environment env) { // TODO: Get rid of the Args intermediate step const uint32_t idx = ePropertyEnvVars; - m_collection_sp->SetPropertyAtIndexFromArgs(nullptr, idx, Args(env)); + m_collection_sp->SetPropertyAtIndexFromArgs(idx, Args(env)); } bool TargetProperties::GetSkipPrologue() const { const uint32_t idx = ePropertySkipPrologue; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_target_properties[idx].default_uint_value != 0); } PathMappingList &TargetProperties::GetSourcePathMap() const { const uint32_t idx = ePropertySourceMap; OptionValuePathMappings *option_value = - m_collection_sp->GetPropertyAtIndexAsOptionValuePathMappings(nullptr, - false, idx); + m_collection_sp->GetPropertyAtIndexAsOptionValuePathMappings(idx); assert(option_value); return option_value->GetCurrentValue(); } bool TargetProperties::GetAutoSourceMapRelative() const { const uint32_t idx = ePropertyAutoSourceMapRelative; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_target_properties[idx].default_uint_value != 0); } void TargetProperties::AppendExecutableSearchPaths(const FileSpec &dir) { const uint32_t idx = ePropertyExecutableSearchPaths; OptionValueFileSpecList *option_value = - m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList(nullptr, - false, idx); + m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList(idx); assert(option_value); option_value->AppendCurrentValue(dir); } FileSpecList TargetProperties::GetExecutableSearchPaths() { const uint32_t idx = ePropertyExecutableSearchPaths; - const OptionValueFileSpecList *option_value = - m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList(nullptr, - false, idx); - assert(option_value); - return option_value->GetCurrentValue(); + return GetPropertyAtIndexAs<FileSpecList>(idx, {}); } FileSpecList TargetProperties::GetDebugFileSearchPaths() { const uint32_t idx = ePropertyDebugFileSearchPaths; - const OptionValueFileSpecList *option_value = - m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList(nullptr, - false, idx); - assert(option_value); - return option_value->GetCurrentValue(); + return GetPropertyAtIndexAs<FileSpecList>(idx, {}); } FileSpecList TargetProperties::GetClangModuleSearchPaths() { const uint32_t idx = ePropertyClangModuleSearchPaths; - const OptionValueFileSpecList *option_value = - m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList(nullptr, - false, idx); - assert(option_value); - return option_value->GetCurrentValue(); + return GetPropertyAtIndexAs<FileSpecList>(idx, {}); } bool TargetProperties::GetEnableAutoImportClangModules() const { const uint32_t idx = ePropertyAutoImportClangModules; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_target_properties[idx].default_uint_value != 0); } ImportStdModule TargetProperties::GetImportStdModule() const { const uint32_t idx = ePropertyImportStdModule; - return (ImportStdModule)m_collection_sp->GetPropertyAtIndexAsEnumeration( - nullptr, idx, g_target_properties[idx].default_uint_value); + return GetPropertyAtIndexAs<ImportStdModule>( + idx, static_cast<ImportStdModule>( + g_target_properties[idx].default_uint_value)); } DynamicClassInfoHelper TargetProperties::GetDynamicClassInfoHelper() const { const uint32_t idx = ePropertyDynamicClassInfoHelper; - return (DynamicClassInfoHelper) - m_collection_sp->GetPropertyAtIndexAsEnumeration( - nullptr, idx, g_target_properties[idx].default_uint_value); + return GetPropertyAtIndexAs<DynamicClassInfoHelper>( + idx, static_cast<DynamicClassInfoHelper>( + g_target_properties[idx].default_uint_value)); } bool TargetProperties::GetEnableAutoApplyFixIts() const { const uint32_t idx = ePropertyAutoApplyFixIts; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_target_properties[idx].default_uint_value != 0); } uint64_t TargetProperties::GetNumberOfRetriesWithFixits() const { const uint32_t idx = ePropertyRetriesWithFixIts; - return m_collection_sp->GetPropertyAtIndexAsUInt64( - nullptr, idx, g_target_properties[idx].default_uint_value); + return GetPropertyAtIndexAs<uint64_t>( + idx, g_target_properties[idx].default_uint_value); } bool TargetProperties::GetEnableNotifyAboutFixIts() const { const uint32_t idx = ePropertyNotifyAboutFixIts; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_target_properties[idx].default_uint_value != 0); } FileSpec TargetProperties::GetSaveJITObjectsDir() const { const uint32_t idx = ePropertySaveObjectsDir; - return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx); + return GetPropertyAtIndexAs<FileSpec>(idx, {}); } void TargetProperties::CheckJITObjectsDir() { @@ -4461,7 +4620,7 @@ void TargetProperties::CheckJITObjectsDir() { if (exists && is_directory && writable) return; - m_collection_sp->GetPropertyAtIndex(nullptr, true, ePropertySaveObjectsDir) + m_collection_sp->GetPropertyAtIndex(ePropertySaveObjectsDir) ->GetValue() ->Clear(); @@ -4483,87 +4642,82 @@ void TargetProperties::CheckJITObjectsDir() { bool TargetProperties::GetEnableSyntheticValue() const { const uint32_t idx = ePropertyEnableSynthetic; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_target_properties[idx].default_uint_value != 0); } uint32_t TargetProperties::GetMaxZeroPaddingInFloatFormat() const { const uint32_t idx = ePropertyMaxZeroPaddingInFloatFormat; - return m_collection_sp->GetPropertyAtIndexAsUInt64( - nullptr, idx, g_target_properties[idx].default_uint_value); + return GetPropertyAtIndexAs<uint64_t>( + idx, g_target_properties[idx].default_uint_value); } uint32_t TargetProperties::GetMaximumNumberOfChildrenToDisplay() const { const uint32_t idx = ePropertyMaxChildrenCount; - return m_collection_sp->GetPropertyAtIndexAsSInt64( - nullptr, idx, g_target_properties[idx].default_uint_value); + return GetPropertyAtIndexAs<int64_t>( + idx, g_target_properties[idx].default_uint_value); } std::pair<uint32_t, bool> TargetProperties::GetMaximumDepthOfChildrenToDisplay() const { const uint32_t idx = ePropertyMaxChildrenDepth; auto *option_value = - m_collection_sp->GetPropertyAtIndexAsOptionValueUInt64(nullptr, idx); + m_collection_sp->GetPropertyAtIndexAsOptionValueUInt64(idx); bool is_default = !option_value->OptionWasSet(); return {option_value->GetCurrentValue(), is_default}; } uint32_t TargetProperties::GetMaximumSizeOfStringSummary() const { const uint32_t idx = ePropertyMaxSummaryLength; - return m_collection_sp->GetPropertyAtIndexAsSInt64( - nullptr, idx, g_target_properties[idx].default_uint_value); + return GetPropertyAtIndexAs<uint64_t>( + idx, g_target_properties[idx].default_uint_value); } uint32_t TargetProperties::GetMaximumMemReadSize() const { const uint32_t idx = ePropertyMaxMemReadSize; - return m_collection_sp->GetPropertyAtIndexAsSInt64( - nullptr, idx, g_target_properties[idx].default_uint_value); + return GetPropertyAtIndexAs<uint64_t>( + idx, g_target_properties[idx].default_uint_value); } FileSpec TargetProperties::GetStandardInputPath() const { const uint32_t idx = ePropertyInputPath; - return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx); + return GetPropertyAtIndexAs<FileSpec>(idx, {}); } void TargetProperties::SetStandardInputPath(llvm::StringRef path) { const uint32_t idx = ePropertyInputPath; - m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, path); + SetPropertyAtIndex(idx, path); } FileSpec TargetProperties::GetStandardOutputPath() const { const uint32_t idx = ePropertyOutputPath; - return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx); + return GetPropertyAtIndexAs<FileSpec>(idx, {}); } void TargetProperties::SetStandardOutputPath(llvm::StringRef path) { const uint32_t idx = ePropertyOutputPath; - m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, path); + SetPropertyAtIndex(idx, path); } FileSpec TargetProperties::GetStandardErrorPath() const { const uint32_t idx = ePropertyErrorPath; - return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx); + return GetPropertyAtIndexAs<FileSpec>(idx, {}); } void TargetProperties::SetStandardErrorPath(llvm::StringRef path) { const uint32_t idx = ePropertyErrorPath; - m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, path); + SetPropertyAtIndex(idx, path); } LanguageType TargetProperties::GetLanguage() const { - OptionValueLanguage *value = - m_collection_sp->GetPropertyAtIndexAsOptionValueLanguage( - nullptr, ePropertyLanguage); - if (value) - return value->GetCurrentValue(); - return LanguageType(); + const uint32_t idx = ePropertyLanguage; + return GetPropertyAtIndexAs<LanguageType>(idx, {}); } llvm::StringRef TargetProperties::GetExpressionPrefixContents() { const uint32_t idx = ePropertyExprPrefix; OptionValueFileSpec *file = - m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpec(nullptr, false, - idx); + m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpec(idx); if (file) { DataBufferSP data_sp(file->GetFileContents()); if (data_sp) @@ -4576,89 +4730,110 @@ llvm::StringRef TargetProperties::GetExpressionPrefixContents() { uint64_t TargetProperties::GetExprErrorLimit() const { const uint32_t idx = ePropertyExprErrorLimit; - return m_collection_sp->GetPropertyAtIndexAsUInt64( - nullptr, idx, g_target_properties[idx].default_uint_value); + return GetPropertyAtIndexAs<uint64_t>( + idx, g_target_properties[idx].default_uint_value); +} + +uint64_t TargetProperties::GetExprAllocAddress() const { + const uint32_t idx = ePropertyExprAllocAddress; + return GetPropertyAtIndexAs<uint64_t>( + idx, g_target_properties[idx].default_uint_value); +} + +uint64_t TargetProperties::GetExprAllocSize() const { + const uint32_t idx = ePropertyExprAllocSize; + return GetPropertyAtIndexAs<uint64_t>( + idx, g_target_properties[idx].default_uint_value); +} + +uint64_t TargetProperties::GetExprAllocAlign() const { + const uint32_t idx = ePropertyExprAllocAlign; + return GetPropertyAtIndexAs<uint64_t>( + idx, g_target_properties[idx].default_uint_value); } bool TargetProperties::GetBreakpointsConsultPlatformAvoidList() { const uint32_t idx = ePropertyBreakpointUseAvoidList; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_target_properties[idx].default_uint_value != 0); } bool TargetProperties::GetUseHexImmediates() const { const uint32_t idx = ePropertyUseHexImmediates; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_target_properties[idx].default_uint_value != 0); } bool TargetProperties::GetUseFastStepping() const { const uint32_t idx = ePropertyUseFastStepping; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_target_properties[idx].default_uint_value != 0); } bool TargetProperties::GetDisplayExpressionsInCrashlogs() const { const uint32_t idx = ePropertyDisplayExpressionsInCrashlogs; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_target_properties[idx].default_uint_value != 0); } LoadScriptFromSymFile TargetProperties::GetLoadScriptFromSymbolFile() const { const uint32_t idx = ePropertyLoadScriptFromSymbolFile; - return (LoadScriptFromSymFile) - m_collection_sp->GetPropertyAtIndexAsEnumeration( - nullptr, idx, g_target_properties[idx].default_uint_value); + return GetPropertyAtIndexAs<LoadScriptFromSymFile>( + idx, static_cast<LoadScriptFromSymFile>( + g_target_properties[idx].default_uint_value)); } LoadCWDlldbinitFile TargetProperties::GetLoadCWDlldbinitFile() const { const uint32_t idx = ePropertyLoadCWDlldbinitFile; - return (LoadCWDlldbinitFile)m_collection_sp->GetPropertyAtIndexAsEnumeration( - nullptr, idx, g_target_properties[idx].default_uint_value); + return GetPropertyAtIndexAs<LoadCWDlldbinitFile>( + idx, static_cast<LoadCWDlldbinitFile>( + g_target_properties[idx].default_uint_value)); } Disassembler::HexImmediateStyle TargetProperties::GetHexImmediateStyle() const { const uint32_t idx = ePropertyHexImmediateStyle; - return (Disassembler::HexImmediateStyle) - m_collection_sp->GetPropertyAtIndexAsEnumeration( - nullptr, idx, g_target_properties[idx].default_uint_value); + return GetPropertyAtIndexAs<Disassembler::HexImmediateStyle>( + idx, static_cast<Disassembler::HexImmediateStyle>( + g_target_properties[idx].default_uint_value)); } MemoryModuleLoadLevel TargetProperties::GetMemoryModuleLoadLevel() const { const uint32_t idx = ePropertyMemoryModuleLoadLevel; - return (MemoryModuleLoadLevel) - m_collection_sp->GetPropertyAtIndexAsEnumeration( - nullptr, idx, g_target_properties[idx].default_uint_value); + return GetPropertyAtIndexAs<MemoryModuleLoadLevel>( + idx, static_cast<MemoryModuleLoadLevel>( + g_target_properties[idx].default_uint_value)); } bool TargetProperties::GetUserSpecifiedTrapHandlerNames(Args &args) const { const uint32_t idx = ePropertyTrapHandlerNames; - return m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, idx, args); + return m_collection_sp->GetPropertyAtIndexAsArgs(idx, args); } void TargetProperties::SetUserSpecifiedTrapHandlerNames(const Args &args) { const uint32_t idx = ePropertyTrapHandlerNames; - m_collection_sp->SetPropertyAtIndexFromArgs(nullptr, idx, args); + m_collection_sp->SetPropertyAtIndexFromArgs(idx, args); } bool TargetProperties::GetDisplayRuntimeSupportValues() const { const uint32_t idx = ePropertyDisplayRuntimeSupportValues; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, false); + return GetPropertyAtIndexAs<bool>( + idx, g_target_properties[idx].default_uint_value != 0); } void TargetProperties::SetDisplayRuntimeSupportValues(bool b) { const uint32_t idx = ePropertyDisplayRuntimeSupportValues; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); + SetPropertyAtIndex(idx, b); } bool TargetProperties::GetDisplayRecognizedArguments() const { const uint32_t idx = ePropertyDisplayRecognizedArguments; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, false); + return GetPropertyAtIndexAs<bool>( + idx, g_target_properties[idx].default_uint_value != 0); } void TargetProperties::SetDisplayRecognizedArguments(bool b) { const uint32_t idx = ePropertyDisplayRecognizedArguments; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); + SetPropertyAtIndex(idx, b); } const ProcessLaunchInfo &TargetProperties::GetProcessLaunchInfo() const { @@ -4695,19 +4870,19 @@ void TargetProperties::SetProcessLaunchInfo( bool TargetProperties::GetRequireHardwareBreakpoints() const { const uint32_t idx = ePropertyRequireHardwareBreakpoints; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_target_properties[idx].default_uint_value != 0); } void TargetProperties::SetRequireHardwareBreakpoints(bool b) { const uint32_t idx = ePropertyRequireHardwareBreakpoints; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); + m_collection_sp->SetPropertyAtIndex(idx, b); } bool TargetProperties::GetAutoInstallMainExecutable() const { const uint32_t idx = ePropertyAutoInstallMainExecutable; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_target_properties[idx].default_uint_value != 0); } void TargetProperties::Arg0ValueChangedCallback() { @@ -4769,13 +4944,13 @@ void TargetProperties::DisableSTDIOValueChangedCallback() { bool TargetProperties::GetDebugUtilityExpression() const { const uint32_t idx = ePropertyDebugUtilityExpression; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_target_properties[idx].default_uint_value != 0); } void TargetProperties::SetDebugUtilityExpression(bool debug) { const uint32_t idx = ePropertyDebugUtilityExpression; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, debug); + SetPropertyAtIndex(idx, debug); } // Target::TargetEventData @@ -4789,9 +4964,8 @@ Target::TargetEventData::TargetEventData(const lldb::TargetSP &target_sp, Target::TargetEventData::~TargetEventData() = default; -ConstString Target::TargetEventData::GetFlavorString() { - static ConstString g_flavor("Target::TargetEventData"); - return g_flavor; +llvm::StringRef Target::TargetEventData::GetFlavorString() { + return "Target::TargetEventData"; } void Target::TargetEventData::Dump(Stream *s) const { diff --git a/lldb/source/Target/TargetList.cpp b/lldb/source/Target/TargetList.cpp index 8ce2ae8c2898..cb198e388011 100644 --- a/lldb/source/Target/TargetList.cpp +++ b/lldb/source/Target/TargetList.cpp @@ -325,6 +325,7 @@ Status TargetList::CreateTargetInternal(Debugger &debugger, return error; } target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target)); + debugger.GetTargetList().RegisterInProcessTarget(target_sp); target_sp->SetExecutableModule(exe_module_sp, load_dependent_files); if (user_exe_path_is_bundle) exe_module_sp->GetFileSpec().GetPath(resolved_bundle_exe_path, @@ -336,6 +337,7 @@ Status TargetList::CreateTargetInternal(Debugger &debugger, // No file was specified, just create an empty target with any arch if a // valid arch was specified target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target)); + debugger.GetTargetList().RegisterInProcessTarget(target_sp); } if (!target_sp) @@ -489,7 +491,7 @@ uint32_t TargetList::SignalIfRunning(lldb::pid_t pid, int signo) { return num_signals_sent; } -int TargetList::GetNumTargets() const { +size_t TargetList::GetNumTargets() const { std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); return m_target_list.size(); } @@ -513,6 +515,7 @@ uint32_t TargetList::GetIndexOfTarget(lldb::TargetSP target_sp) const { void TargetList::AddTargetInternal(TargetSP target_sp, bool do_select) { lldbassert(!llvm::is_contained(m_target_list, target_sp) && "target already exists it the list"); + UnregisterInProcessTarget(target_sp); m_target_list.push_back(std::move(target_sp)); if (do_select) SetSelectedTargetInternal(m_target_list.size() - 1); @@ -540,3 +543,36 @@ lldb::TargetSP TargetList::GetSelectedTarget() { m_selected_target_idx = 0; return GetTargetAtIndex(m_selected_target_idx); } + +bool TargetList::AnyTargetContainsModule(Module &module) { + std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); + for (const auto &target_sp : m_target_list) { + if (target_sp->GetImages().FindModule(&module)) + return true; + } + for (const auto &target_sp: m_in_process_target_list) { + if (target_sp->GetImages().FindModule(&module)) + return true; + } + return false; +} + + void TargetList::RegisterInProcessTarget(TargetSP target_sp) { + std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); + [[maybe_unused]] bool was_added; + std::tie(std::ignore, was_added) = + m_in_process_target_list.insert(target_sp); + assert(was_added && "Target pointer was left in the in-process map"); + } + + void TargetList::UnregisterInProcessTarget(TargetSP target_sp) { + std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); + [[maybe_unused]] bool was_present = + m_in_process_target_list.erase(target_sp); + assert(was_present && "Target pointer being removed was not registered"); + } + + bool TargetList::IsTargetInProcess(TargetSP target_sp) { + std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); + return m_in_process_target_list.count(target_sp) == 1; + } diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td index 202304174bc1..19ea505af656 100644 --- a/lldb/source/Target/TargetProperties.td +++ b/lldb/source/Target/TargetProperties.td @@ -24,6 +24,15 @@ let Definition = "target" in { DefaultUnsignedValue<5>, Desc<"The maximum amount of errors to emit while parsing an expression. " "A value of 0 means to always continue parsing if possible.">; + def ExprAllocAddress: Property<"expr-alloc-address", "UInt64">, + DefaultUnsignedValue<0>, + Desc<"Start address within the process address space of memory allocation for expression evaluation.">; + def ExprAllocSize: Property<"expr-alloc-size", "UInt64">, + DefaultUnsignedValue<0>, + Desc<"Amount of memory in bytes to allocate for expression evaluation.">; + def ExprAllocAlign: Property<"expr-alloc-align", "UInt64">, + DefaultUnsignedValue<0>, + Desc<"Alignment for each memory allocation for expression evaluation.">; def PreferDynamic: Property<"prefer-dynamic-value", "Enum">, DefaultEnumValue<"eDynamicDontRunTarget">, EnumValues<"OptionEnumValues(g_dynamic_value_types)">, @@ -216,7 +225,7 @@ let Definition = "process" in { def DisableLangRuntimeUnwindPlans: Property<"disable-language-runtime-unwindplans", "Boolean">, Global, DefaultFalse, - Desc<"If true, LanguageRuntime plugins' UnwindPlans will not be used when backtracing.">; + Desc<"If true, language runtime augmented/overidden backtraces will not be used when printing a stack trace.">; def DetachKeepsStopped: Property<"detach-keeps-stopped", "Boolean">, Global, DefaultFalse, @@ -246,6 +255,9 @@ 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 HighmemVirtualAddressableBits: Property<"highmem-virtual-addressable-bits", "UInt64">, + DefaultUnsignedValue<0>, + Desc<"The number of bits used for addressing high memory, when it differs from low memory in the same Process. When this is non-zero, target.process.virtual-addressable-bits will be the value for low memory (0x000... addresses) and this setting will be the value for high memory (0xfff... addresses). When this is zero, target.process.virtual-addressable-bits applies to all addresses. It is very uncommon to use this setting.">; def FollowForkMode: Property<"follow-fork-mode", "Enum">, DefaultEnumValue<"eFollowParent">, EnumValues<"OptionEnumValues(g_follow_fork_mode_values)">, diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index d620f746339e..ec4ffcbd9205 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -78,9 +78,9 @@ class ThreadOptionValueProperties public: ThreadOptionValueProperties(ConstString name) : Cloneable(name) {} - const Property *GetPropertyAtIndex(const ExecutionContext *exe_ctx, - bool will_modify, - uint32_t idx) const override { + const Property * + GetPropertyAtIndex(size_t idx, + const ExecutionContext *exe_ctx) const override { // When getting the value for a key from the thread options, we will always // try and grab the setting from the current thread if there is one. Else // we just use the one from this instance. @@ -112,47 +112,42 @@ ThreadProperties::~ThreadProperties() = default; const RegularExpression *ThreadProperties::GetSymbolsToAvoidRegexp() { const uint32_t idx = ePropertyStepAvoidRegex; - return m_collection_sp->GetPropertyAtIndexAsOptionValueRegex(nullptr, idx); + return GetPropertyAtIndexAs<const RegularExpression *>(idx); } FileSpecList ThreadProperties::GetLibrariesToAvoid() const { const uint32_t idx = ePropertyStepAvoidLibraries; - const OptionValueFileSpecList *option_value = - m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList(nullptr, - false, idx); - assert(option_value); - return option_value->GetCurrentValue(); + return GetPropertyAtIndexAs<FileSpecList>(idx, {}); } bool ThreadProperties::GetTraceEnabledState() const { const uint32_t idx = ePropertyEnableThreadTrace; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_thread_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_thread_properties[idx].default_uint_value != 0); } bool ThreadProperties::GetStepInAvoidsNoDebug() const { const uint32_t idx = ePropertyStepInAvoidsNoDebug; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_thread_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_thread_properties[idx].default_uint_value != 0); } bool ThreadProperties::GetStepOutAvoidsNoDebug() const { const uint32_t idx = ePropertyStepOutAvoidsNoDebug; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_thread_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_thread_properties[idx].default_uint_value != 0); } uint64_t ThreadProperties::GetMaxBacktraceDepth() const { const uint32_t idx = ePropertyMaxBacktraceDepth; - return m_collection_sp->GetPropertyAtIndexAsUInt64( - nullptr, idx, g_thread_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<uint64_t>( + idx, g_thread_properties[idx].default_uint_value); } // Thread Event Data -ConstString Thread::ThreadEventData::GetFlavorString() { - static ConstString g_flavor("Thread::ThreadEventData"); - return g_flavor; +llvm::StringRef Thread::ThreadEventData::GetFlavorString() { + return "Thread::ThreadEventData"; } Thread::ThreadEventData::ThreadEventData(const lldb::ThreadSP thread_sp) @@ -264,10 +259,11 @@ void Thread::BroadcastSelectedFrameChange(StackID &new_frame_id) { new ThreadEventData(this->shared_from_this(), new_frame_id)); } -lldb::StackFrameSP Thread::GetSelectedFrame() { +lldb::StackFrameSP +Thread::GetSelectedFrame(SelectMostRelevant select_most_relevant) { StackFrameListSP stack_frame_list_sp(GetStackFrameList()); StackFrameSP frame_sp = stack_frame_list_sp->GetFrameAtIndex( - stack_frame_list_sp->GetSelectedFrameIndex()); + stack_frame_list_sp->GetSelectedFrameIndex(select_most_relevant)); FrameSelectedCallback(frame_sp.get()); return frame_sp; } @@ -298,15 +294,22 @@ bool Thread::SetSelectedFrameByIndexNoisily(uint32_t frame_idx, const bool broadcast = true; bool success = SetSelectedFrameByIndex(frame_idx, broadcast); if (success) { - StackFrameSP frame_sp = GetSelectedFrame(); + StackFrameSP frame_sp = GetSelectedFrame(DoNoSelectMostRelevantFrame); if (frame_sp) { bool already_shown = false; SymbolContext frame_sc( frame_sp->GetSymbolContext(eSymbolContextLineEntry)); - if (GetProcess()->GetTarget().GetDebugger().GetUseExternalEditor() && - frame_sc.line_entry.file && frame_sc.line_entry.line != 0) { - already_shown = Host::OpenFileInExternalEditor( - frame_sc.line_entry.file, frame_sc.line_entry.line); + const Debugger &debugger = GetProcess()->GetTarget().GetDebugger(); + if (debugger.GetUseExternalEditor() && frame_sc.line_entry.file && + frame_sc.line_entry.line != 0) { + if (llvm::Error e = Host::OpenFileInExternalEditor( + debugger.GetExternalEditor(), frame_sc.line_entry.file, + frame_sc.line_entry.line)) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Host), std::move(e), + "OpenFileInExternalEditor failed: {0}"); + } else { + already_shown = true; + } } bool show_frame_info = true; @@ -588,36 +591,9 @@ std::string Thread::GetStopDescriptionRaw() { return raw_stop_description; } -void Thread::SelectMostRelevantFrame() { - Log *log = GetLog(LLDBLog::Thread); - - auto frames_list_sp = GetStackFrameList(); - - // Only the top frame should be recognized. - auto frame_sp = frames_list_sp->GetFrameAtIndex(0); - - auto recognized_frame_sp = frame_sp->GetRecognizedFrame(); - - if (!recognized_frame_sp) { - LLDB_LOG(log, "Frame #0 not recognized"); - return; - } - - if (StackFrameSP most_relevant_frame_sp = - recognized_frame_sp->GetMostRelevantFrame()) { - LLDB_LOG(log, "Found most relevant frame at index {0}", - most_relevant_frame_sp->GetFrameIndex()); - SetSelectedFrame(most_relevant_frame_sp.get()); - } else { - LLDB_LOG(log, "No relevant frame!"); - } -} - void Thread::WillStop() { ThreadPlan *current_plan = GetCurrentPlan(); - SelectMostRelevantFrame(); - // FIXME: I may decide to disallow threads with no plans. In which // case this should go to an assert. @@ -734,7 +710,7 @@ bool Thread::ShouldResume(StateType resume_state) { return need_to_resume; } -void Thread::DidResume() { +void Thread::DidResume() { SetResumeSignal(LLDB_INVALID_SIGNAL_NUMBER); // This will get recomputed each time when we stop. SetShouldRunBeforePublicStop(false); @@ -778,7 +754,7 @@ bool Thread::ShouldStop(Event *event_ptr) { : LLDB_INVALID_ADDRESS); return false; } - + // Clear the "must run me before stop" if it was set: SetShouldRunBeforePublicStop(false); @@ -1008,7 +984,7 @@ Vote Thread::ShouldReportStop(Event *event_ptr) { } if (GetPlans().AnyCompletedPlans()) { - // Pass skip_private = false to GetCompletedPlan, since we want to ask + // Pass skip_private = false to GetCompletedPlan, since we want to ask // the last plan, regardless of whether it is private or not. LLDB_LOGF(log, "Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 @@ -1046,7 +1022,7 @@ Vote Thread::ShouldReportRun(Event *event_ptr) { Log *log = GetLog(LLDBLog::Step); if (GetPlans().AnyCompletedPlans()) { - // Pass skip_private = false to GetCompletedPlan, since we want to ask + // Pass skip_private = false to GetCompletedPlan, since we want to ask // the last plan, regardless of whether it is private or not. LLDB_LOGF(log, "Current Plan for thread %d(%p) (0x%4.4" PRIx64 @@ -1099,7 +1075,7 @@ void Thread::PushPlan(ThreadPlanSP thread_plan_sp) { static_cast<void *>(this), s.GetData(), thread_plan_sp->GetThread().GetID()); } - + GetPlans().PushPlan(std::move(thread_plan_sp)); } @@ -1117,7 +1093,7 @@ void Thread::DiscardPlan() { ThreadPlanSP discarded_plan_sp = GetPlans().DiscardPlan(); LLDB_LOGF(log, "Discarding plan: \"%s\", tid = 0x%4.4" PRIx64 ".", - discarded_plan_sp->GetName(), + discarded_plan_sp->GetName(), discarded_plan_sp->GetThread().GetID()); } @@ -1246,7 +1222,7 @@ Status Thread::UnwindInnermostExpression() { if (!innermost_expr_plan) { error.SetErrorString("No expressions currently active on this thread"); return error; - } + } DiscardThreadPlansUpToPlan(innermost_expr_plan); return error; } @@ -1390,8 +1366,8 @@ ThreadPlanSP Thread::QueueThreadPlanForStepUntil( } lldb::ThreadPlanSP Thread::QueueThreadPlanForStepScripted( - bool abort_other_plans, const char *class_name, - StructuredData::ObjectSP extra_args_sp, bool stop_other_threads, + bool abort_other_plans, const char *class_name, + StructuredData::ObjectSP extra_args_sp, bool stop_other_threads, Status &status) { ThreadPlanSP thread_plan_sp(new ThreadPlanPython( @@ -1752,8 +1728,12 @@ size_t Thread::GetStatus(Stream &strm, uint32_t start_frame, SymbolContext frame_sc( frame_sp->GetSymbolContext(eSymbolContextLineEntry)); if (frame_sc.line_entry.line != 0 && frame_sc.line_entry.file) { - Host::OpenFileInExternalEditor(frame_sc.line_entry.file, - frame_sc.line_entry.line); + if (llvm::Error e = Host::OpenFileInExternalEditor( + target->GetDebugger().GetExternalEditor(), + frame_sc.line_entry.file, frame_sc.line_entry.line)) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Host), std::move(e), + "OpenFileInExternalEditor failed: {0}"); + } } } } @@ -1826,7 +1806,7 @@ bool Thread::GetDescription(Stream &strm, lldb::DescriptionLevel level, id->GetType() == eStructuredDataTypeInteger) { strm.Format(" Activity '{0}', {1:x}\n", name->GetAsString()->GetValue(), - id->GetAsInteger()->GetValue()); + id->GetUnsignedIntegerValue()); } printed_activity = true; } diff --git a/lldb/source/Target/ThreadPlan.cpp b/lldb/source/Target/ThreadPlan.cpp index 9913ecb591fa..7927fc314014 100644 --- a/lldb/source/Target/ThreadPlan.cpp +++ b/lldb/source/Target/ThreadPlan.cpp @@ -171,6 +171,9 @@ bool ThreadPlan::IsUsuallyUnexplainedStopReason(lldb::StopReason reason) { case eStopReasonExec: case eStopReasonThreadExiting: case eStopReasonInstrumentation: + case eStopReasonFork: + case eStopReasonVFork: + case eStopReasonVForkDone: return true; default: return false; diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp index 7e9bb963bb5d..31027cd9e011 100644 --- a/lldb/source/Target/ThreadPlanCallFunction.cpp +++ b/lldb/source/Target/ThreadPlanCallFunction.cpp @@ -163,7 +163,7 @@ void ThreadPlanCallFunction::ReportRegisterState(const char *message) { reg_idx < num_registers; ++reg_idx) { const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_idx); if (reg_ctx->ReadRegister(reg_info, reg_value)) { - DumpRegisterValue(reg_value, &strm, reg_info, true, false, + DumpRegisterValue(reg_value, strm, *reg_info, true, false, eFormatDefault); strm.EOL(); } diff --git a/lldb/source/Target/ThreadPlanPython.cpp b/lldb/source/Target/ThreadPlanPython.cpp index bc2a7a02e99c..d6de6b3c3cf0 100644 --- a/lldb/source/Target/ThreadPlanPython.cpp +++ b/lldb/source/Target/ThreadPlanPython.cpp @@ -136,8 +136,11 @@ bool ThreadPlanPython::MischiefManaged() { // I don't really need mischief_managed, since it's simpler to just call // SetPlanComplete in should_stop. mischief_managed = IsPlanComplete(); - if (mischief_managed) + if (mischief_managed) { + // We need to cache the stop reason here we'll need it in GetDescription. + GetDescription(&m_stop_description, eDescriptionLevelBrief); m_implementation_sp.reset(); + } } return mischief_managed; } @@ -158,15 +161,40 @@ lldb::StateType ThreadPlanPython::GetPlanRunState() { return run_state; } -// The ones below are not currently exported to Python. void ThreadPlanPython::GetDescription(Stream *s, lldb::DescriptionLevel level) { - s->Printf("Python thread plan implemented by class %s.", + Log *log = GetLog(LLDBLog::Thread); + LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, + m_class_name.c_str()); + if (m_implementation_sp) { + ScriptInterpreter *script_interp = GetScriptInterpreter(); + if (script_interp) { + bool script_error; + bool added_desc = script_interp->ScriptedThreadPlanGetStopDescription( + m_implementation_sp, s, script_error); + if (script_error || !added_desc) + s->Printf("Python thread plan implemented by class %s.", m_class_name.c_str()); + } + return; + } + // It's an error not to have a description, so if we get here, we should + // add something. + if (m_stop_description.Empty()) + s->Printf("Python thread plan implemented by class %s.", + m_class_name.c_str()); + s->PutCString(m_stop_description.GetData()); } +// The ones below are not currently exported to Python. bool ThreadPlanPython::WillStop() { Log *log = GetLog(LLDBLog::Thread); LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, m_class_name.c_str()); return true; } + +bool ThreadPlanPython::DoWillResume(lldb::StateType resume_state, + bool current_plan) { + m_stop_description.Clear(); + return true; +} diff --git a/lldb/source/Target/ThreadPlanTracer.cpp b/lldb/source/Target/ThreadPlanTracer.cpp index 82927ef64877..f4d80ba89071 100644 --- a/lldb/source/Target/ThreadPlanTracer.cpp +++ b/lldb/source/Target/ThreadPlanTracer.cpp @@ -56,7 +56,7 @@ Stream *ThreadPlanTracer::GetLogStream() { Thread &ThreadPlanTracer::GetThread() { if (m_thread) return *m_thread; - + ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(m_tid); m_thread = thread_sp.get(); return *m_thread; @@ -107,8 +107,9 @@ TypeFromUser ThreadPlanAssemblyTracer::GetIntPointerType() { auto type_system_or_err = target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC); if (auto err = type_system_or_err.takeError()) { - LLDB_LOG_ERROR(GetLog(LLDBLog::Types), std::move(err), - "Unable to get integer pointer type from TypeSystem"); + LLDB_LOG_ERROR( + GetLog(LLDBLog::Types), std::move(err), + "Unable to get integer pointer type from TypeSystem: {0}"); } else { if (auto ts = *type_system_or_err) m_intptr_type = TypeFromUser(ts->GetBuiltinTypeForEncodingAndBitSize( @@ -223,7 +224,7 @@ void ThreadPlanAssemblyTracer::Log() { reg_value != m_register_values[reg_num]) { if (reg_value.GetType() != RegisterValue::eTypeInvalid) { stream->PutCString("\n\t"); - DumpRegisterValue(reg_value, stream, reg_info, true, false, + DumpRegisterValue(reg_value, *stream, *reg_info, true, false, eFormatDefault); } } diff --git a/lldb/source/Target/UnixSignals.cpp b/lldb/source/Target/UnixSignals.cpp index 858b1691f318..0e738241b1c5 100644 --- a/lldb/source/Target/UnixSignals.cpp +++ b/lldb/source/Target/UnixSignals.cpp @@ -9,11 +9,11 @@ #include "lldb/Target/UnixSignals.h" #include "Plugins/Process/Utility/FreeBSDSignals.h" #include "Plugins/Process/Utility/LinuxSignals.h" -#include "Plugins/Process/Utility/MipsLinuxSignals.h" #include "Plugins/Process/Utility/NetBSDSignals.h" #include "lldb/Host/HostInfo.h" #include "lldb/Utility/ArchSpec.h" #include <optional> +#include <sstream> using namespace lldb_private; using namespace llvm; @@ -33,17 +33,8 @@ UnixSignals::Signal::Signal(const char *name, bool default_suppress, lldb::UnixSignalsSP UnixSignals::Create(const ArchSpec &arch) { const auto &triple = arch.GetTriple(); switch (triple.getOS()) { - case llvm::Triple::Linux: { - switch (triple.getArch()) { - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - return std::make_shared<MipsLinuxSignals>(); - default: - return std::make_shared<LinuxSignals>(); - } - } + case llvm::Triple::Linux: + return std::make_shared<LinuxSignals>(); case llvm::Triple::FreeBSD: case llvm::Triple::OpenBSD: return std::make_shared<FreeBSDSignals>(); @@ -122,6 +113,17 @@ void UnixSignals::AddSignal(int signo, const char *name, bool default_suppress, ++m_version; } +void UnixSignals::AddSignalCode(int signo, int code, + const llvm::StringLiteral description, + SignalCodePrintOption print_option) { + collection::iterator signal = m_signals.find(signo); + assert(signal != m_signals.end() && + "Tried to add code to signal that does not exist."); + signal->second.m_codes.insert( + std::pair{code, SignalCode{description, print_option}}); + ++m_version; +} + void UnixSignals::RemoveSignal(int signo) { collection::iterator pos = m_signals.find(signo); if (pos != m_signals.end()) @@ -137,14 +139,64 @@ const char *UnixSignals::GetSignalAsCString(int signo) const { return pos->second.m_name.GetCString(); } +std::string +UnixSignals::GetSignalDescription(int32_t signo, std::optional<int32_t> code, + std::optional<lldb::addr_t> addr, + std::optional<lldb::addr_t> lower, + std::optional<lldb::addr_t> upper) const { + std::string str; + + collection::const_iterator pos = m_signals.find(signo); + if (pos != m_signals.end()) { + str = pos->second.m_name.GetCString(); + + if (code) { + std::map<int32_t, SignalCode>::const_iterator cpos = + pos->second.m_codes.find(*code); + if (cpos != pos->second.m_codes.end()) { + const SignalCode &sc = cpos->second; + str += ": "; + if (sc.m_print_option != SignalCodePrintOption::Bounds) + str += sc.m_description.str(); + + std::stringstream strm; + switch (sc.m_print_option) { + case SignalCodePrintOption::None: + break; + case SignalCodePrintOption::Address: + if (addr) + strm << " (fault address: 0x" << std::hex << *addr << ")"; + break; + case SignalCodePrintOption::Bounds: + if (lower && upper && addr) { + if ((unsigned long)(*addr) < *lower) + strm << "lower bound violation "; + else + strm << "upper bound violation "; + + strm << "(fault address: 0x" << std::hex << *addr; + strm << ", lower bound: 0x" << std::hex << *lower; + strm << ", upper bound: 0x" << std::hex << *upper; + strm << ")"; + } else + strm << sc.m_description.str(); + + break; + } + str += strm.str(); + } + } + } + + return str; +} + bool UnixSignals::SignalIsValid(int32_t signo) const { return m_signals.find(signo) != m_signals.end(); } -ConstString UnixSignals::GetShortName(ConstString name) const { - if (name) - return ConstString(name.GetStringRef().substr(3)); // Remove "SIG" from name - return name; +llvm::StringRef UnixSignals::GetShortName(llvm::StringRef name) const { + return name.substr(3); // Remove "SIG" from name } int32_t UnixSignals::GetSignalNumberFromName(const char *name) const { |
