diff --git a/lldb/include/lldb/DataFormatters/FormattersHelpers.h b/lldb/include/lldb/DataFormatters/FormattersHelpers.h --- a/lldb/include/lldb/DataFormatters/FormattersHelpers.h +++ b/lldb/include/lldb/DataFormatters/FormattersHelpers.h @@ -56,7 +56,7 @@ size_t ExtractIndexFromString(const char *item_name); -lldb::addr_t GetArrayAddressOrPointerValue(ValueObject &valobj); +Address GetArrayAddressOrPointerValue(ValueObject &valobj); lldb::ValueObjectSP GetValueOfLibCXXCompressedPair(ValueObject &pair); diff --git a/lldb/include/lldb/DataFormatters/StringPrinter.h b/lldb/include/lldb/DataFormatters/StringPrinter.h --- a/lldb/include/lldb/DataFormatters/StringPrinter.h +++ b/lldb/include/lldb/DataFormatters/StringPrinter.h @@ -12,9 +12,9 @@ #include #include -#include "lldb/lldb-forward.h" - +#include "lldb/Core/Address.h" #include "lldb/Utility/DataExtractor.h" +#include "lldb/lldb-forward.h" namespace lldb_private { namespace formatters { @@ -105,21 +105,21 @@ ReadStringAndDumpToStreamOptions(ValueObject &valobj); - void SetLocation(uint64_t l) { m_location = l; } + void SetLocation(Address l) { m_location = std::move(l); } - uint64_t GetLocation() const { return m_location; } + const Address &GetLocation() const { return m_location; } - void SetProcessSP(lldb::ProcessSP p) { m_process_sp = std::move(p); } + void SetTargetSP(lldb::TargetSP t) { m_target_sp = std::move(t); } - lldb::ProcessSP GetProcessSP() const { return m_process_sp; } + lldb::TargetSP GetTargetSP() const { return m_target_sp; } void SetHasSourceSize(bool e) { m_has_source_size = e; } bool HasSourceSize() const { return m_has_source_size; } private: - uint64_t m_location = 0; - lldb::ProcessSP m_process_sp; + Address m_location; + lldb::TargetSP m_target_sp; /// True iff we know the source size of the string. bool m_has_source_size = false; }; diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -1482,36 +1482,6 @@ size_t ReadMemoryFromInferior(lldb::addr_t vm_addr, void *buf, size_t size, Status &error); - /// Read a NULL terminated string from memory - /// - /// This function will read a cache page at a time until a NULL string - /// terminator is found. It will stop reading if an aligned sequence of NULL - /// termination \a type_width bytes is not found before reading \a - /// cstr_max_len bytes. The results are always guaranteed to be NULL - /// terminated, and that no more than (max_bytes - type_width) bytes will be - /// read. - /// - /// \param[in] vm_addr - /// The virtual load address to start the memory read. - /// - /// \param[in] str - /// A character buffer containing at least max_bytes. - /// - /// \param[in] max_bytes - /// The maximum number of bytes to read. - /// - /// \param[in] error - /// The error status of the read operation. - /// - /// \param[in] type_width - /// The size of the null terminator (1 to 4 bytes per - /// character). Defaults to 1. - /// - /// \return - /// The error status or the number of bytes prior to the null terminator. - size_t ReadStringFromMemory(lldb::addr_t vm_addr, char *str, size_t max_bytes, - Status &error, size_t type_width = 1); - /// Read a NULL terminated C string from memory /// /// This function will read a cache page at a time until the NULL diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -1023,6 +1023,37 @@ size_t ReadCStringFromMemory(const Address &addr, char *dst, size_t dst_max_len, Status &result_error); + /// Read a NULL terminated string from memory + /// + /// This function will read a cache page at a time until a NULL string + /// terminator is found. It will stop reading if an aligned sequence of NULL + /// termination \a type_width bytes is not found before reading \a + /// cstr_max_len bytes. The results are always guaranteed to be NULL + /// terminated, and that no more than (max_bytes - type_width) bytes will be + /// read. + /// + /// \param[in] addr + /// The address to start the memory read. + /// + /// \param[in] dst + /// A character buffer containing at least max_bytes. + /// + /// \param[in] max_bytes + /// The maximum number of bytes to read. + /// + /// \param[in] error + /// The error status of the read operation. + /// + /// \param[in] type_width + /// The size of the null terminator (1 to 4 bytes per + /// character). Defaults to 1. + /// + /// \return + /// The error status or the number of bytes prior to the null terminator. + size_t ReadStringFromMemory(const Address &addr, char *dst, size_t max_bytes, + Status &error, size_t type_width, + bool force_live_memory = true); + size_t ReadScalarIntegerFromMemory(const Address &addr, uint32_t byte_size, bool is_signed, Scalar &scalar, Status &error, @@ -1490,6 +1521,10 @@ void FinalizeFileActions(ProcessLaunchInfo &info); + /// Return a recommended size for memory reads at \a addr, optimizing for + /// cache usage. + lldb::addr_t GetReasonableReadSize(const Address &addr); + Target(const Target &) = delete; const Target &operator=(const Target &) = delete; }; diff --git a/lldb/source/DataFormatters/FormattersHelpers.cpp b/lldb/source/DataFormatters/FormattersHelpers.cpp --- a/lldb/source/DataFormatters/FormattersHelpers.cpp +++ b/lldb/source/DataFormatters/FormattersHelpers.cpp @@ -10,7 +10,7 @@ #include "lldb/DataFormatters/FormattersHelpers.h" - +#include "lldb/Core/Module.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" @@ -131,14 +131,17 @@ return idx; } -lldb::addr_t +Address lldb_private::formatters::GetArrayAddressOrPointerValue(ValueObject &valobj) { lldb::addr_t data_addr = LLDB_INVALID_ADDRESS; + AddressType type; if (valobj.IsPointerType()) - data_addr = valobj.GetValueAsUnsigned(0); + data_addr = valobj.GetPointerValue(&type); else if (valobj.IsArrayType()) - data_addr = valobj.GetAddressOf(); + data_addr = valobj.GetAddressOf(/*scalar_is_load_address=*/true, &type); + if (data_addr != LLDB_INVALID_ADDRESS && type == eAddressTypeFile) + return Address(data_addr, valobj.GetModule()->GetSectionList()); return data_addr; } diff --git a/lldb/source/DataFormatters/StringPrinter.cpp b/lldb/source/DataFormatters/StringPrinter.cpp --- a/lldb/source/DataFormatters/StringPrinter.cpp +++ b/lldb/source/DataFormatters/StringPrinter.cpp @@ -408,8 +408,8 @@ options.GetLocation() == LLDB_INVALID_ADDRESS) return false; - lldb::ProcessSP process_sp(options.GetProcessSP()); - if (!process_sp) + lldb::TargetSP target_sp = options.GetTargetSP(); + if (!target_sp) return false; constexpr int type_width = sizeof(SourceDataType); @@ -423,7 +423,7 @@ bool needs_zero_terminator = options.GetNeedsZeroTermination(); bool is_truncated = false; - const auto max_size = process_sp->GetTarget().GetMaximumSizeOfStringSummary(); + const auto max_size = target_sp->GetMaximumSizeOfStringSummary(); uint32_t sourceSize; if (elem_type == StringElementType::ASCII && !options.GetSourceSize()) { @@ -462,22 +462,22 @@ char *buffer = reinterpret_cast(buffer_sp->GetBytes()); if (elem_type == StringElementType::ASCII) - process_sp->ReadCStringFromMemory(options.GetLocation(), buffer, + target_sp->ReadCStringFromMemory(options.GetLocation(), buffer, bufferSPSize, error); else if (needs_zero_terminator) - process_sp->ReadStringFromMemory(options.GetLocation(), buffer, + target_sp->ReadStringFromMemory(options.GetLocation(), buffer, bufferSPSize, error, type_width); else - process_sp->ReadMemoryFromInferior(options.GetLocation(), buffer, - bufferSPSize, error); + target_sp->ReadMemory(options.GetLocation(), buffer, bufferSPSize, error); if (error.Fail()) { options.GetStream()->Printf("unable to read data"); return true; } StringPrinter::ReadBufferAndDumpToStreamOptions dump_options(options); - dump_options.SetData(DataExtractor(buffer_sp, process_sp->GetByteOrder(), - process_sp->GetAddressByteSize())); + dump_options.SetData( + DataExtractor(buffer_sp, target_sp->GetArchitecture().GetByteOrder(), + target_sp->GetArchitecture().GetAddressByteSize())); dump_options.SetSourceSize(sourceSize); dump_options.SetIsTruncated(is_truncated); dump_options.SetNeedsZeroTermination(needs_zero_terminator); diff --git a/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp b/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp --- a/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp @@ -50,17 +50,13 @@ template static bool CharStringSummaryProvider(ValueObject &valobj, Stream &stream) { - ProcessSP process_sp = valobj.GetProcessSP(); - if (!process_sp) - return false; - - lldb::addr_t valobj_addr = GetArrayAddressOrPointerValue(valobj); - if (valobj_addr == 0 || valobj_addr == LLDB_INVALID_ADDRESS) + Address valobj_addr = GetArrayAddressOrPointerValue(valobj); + if (!valobj_addr.IsValid()) return false; StringPrinter::ReadStringAndDumpToStreamOptions options(valobj); options.SetLocation(valobj_addr); - options.SetProcessSP(process_sp); + options.SetTargetSP(valobj.GetTargetSP()); options.SetStream(&stream); options.SetPrefixToken(getElementTraits(ElemType).first); @@ -115,12 +111,8 @@ bool lldb_private::formatters::WCharStringSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) { - ProcessSP process_sp = valobj.GetProcessSP(); - if (!process_sp) - return false; - - lldb::addr_t valobj_addr = GetArrayAddressOrPointerValue(valobj); - if (valobj_addr == 0 || valobj_addr == LLDB_INVALID_ADDRESS) + Address valobj_addr = GetArrayAddressOrPointerValue(valobj); + if (!valobj_addr.IsValid()) return false; // Get a wchar_t basic type from the current type system @@ -138,7 +130,7 @@ StringPrinter::ReadStringAndDumpToStreamOptions options(valobj); options.SetLocation(valobj_addr); - options.SetProcessSP(process_sp); + options.SetTargetSP(valobj.GetTargetSP()); options.SetStream(&stream); options.SetPrefixToken("L"); diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp --- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp @@ -250,7 +250,7 @@ addr_of_data == LLDB_INVALID_ADDRESS) return false; options.SetLocation(addr_of_data); - options.SetProcessSP(process_sp); + options.SetTargetSP(valobj.GetTargetSP()); options.SetStream(&stream); options.SetNeedsZeroTermination(false); options.SetBinaryZeroIsTerminator(true); @@ -311,7 +311,7 @@ addr_of_data == LLDB_INVALID_ADDRESS) return false; options.SetLocation(addr_of_data); - options.SetProcessSP(process_sp); + options.SetTargetSP(valobj.GetTargetSP()); options.SetStream(&stream); options.SetNeedsZeroTermination(false); options.SetBinaryZeroIsTerminator(false); diff --git a/lldb/source/Plugins/Language/ObjC/NSString.cpp b/lldb/source/Plugins/Language/ObjC/NSString.cpp --- a/lldb/source/Plugins/Language/ObjC/NSString.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSString.cpp @@ -166,7 +166,7 @@ return false; if (has_explicit_length && is_unicode) { options.SetLocation(location); - options.SetProcessSP(process_sp); + options.SetTargetSP(valobj.GetTargetSP()); options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); @@ -179,7 +179,7 @@ StringPrinter::StringElementType::UTF16>(options); } else { options.SetLocation(location + 1); - options.SetProcessSP(process_sp); + options.SetTargetSP(valobj.GetTargetSP()); options.SetStream(&stream); options.SetSourceSize(explicit_length); options.SetHasSourceSize(has_explicit_length); @@ -195,7 +195,7 @@ uint64_t location = 3 * ptr_size + valobj_addr; options.SetLocation(location); - options.SetProcessSP(process_sp); + options.SetTargetSP(valobj.GetTargetSP()); options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); @@ -217,7 +217,7 @@ return false; } options.SetLocation(location); - options.SetProcessSP(process_sp); + options.SetTargetSP(valobj.GetTargetSP()); options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); @@ -237,7 +237,7 @@ lldb::addr_t location = valobj.GetValueAsUnsigned(0) + ptr_size + 4; options.SetLocation(location); - options.SetProcessSP(process_sp); + options.SetTargetSP(valobj.GetTargetSP()); options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); @@ -260,7 +260,7 @@ location++; } options.SetLocation(location); - options.SetProcessSP(process_sp); + options.SetTargetSP(valobj.GetTargetSP()); options.SetStream(&stream); options.SetSourceSize(explicit_length); options.SetHasSourceSize(has_explicit_length); @@ -283,7 +283,7 @@ explicit_length++; // account for the fact that there is no NULL and we // need to have one added options.SetLocation(location); - options.SetProcessSP(process_sp); + options.SetTargetSP(valobj.GetTargetSP()); options.SetStream(&stream); options.SetSourceSize(explicit_length); options.SetHasSourceSize(has_explicit_length); diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -1983,57 +1983,6 @@ return out_str.size(); } -size_t Process::ReadStringFromMemory(addr_t addr, char *dst, size_t max_bytes, - Status &error, size_t type_width) { - size_t total_bytes_read = 0; - if (dst && max_bytes && type_width && max_bytes >= type_width) { - // Ensure a null terminator independent of the number of bytes that is - // read. - memset(dst, 0, max_bytes); - size_t bytes_left = max_bytes - type_width; - - const char terminator[4] = {'\0', '\0', '\0', '\0'}; - assert(sizeof(terminator) >= type_width && "Attempting to validate a " - "string with more than 4 bytes " - "per character!"); - - addr_t curr_addr = addr; - const size_t cache_line_size = m_memory_cache.GetMemoryCacheLineSize(); - char *curr_dst = dst; - - error.Clear(); - while (bytes_left > 0 && error.Success()) { - addr_t cache_line_bytes_left = - cache_line_size - (curr_addr % cache_line_size); - addr_t bytes_to_read = - std::min(bytes_left, cache_line_bytes_left); - size_t bytes_read = ReadMemory(curr_addr, curr_dst, bytes_to_read, error); - - if (bytes_read == 0) - break; - - // Search for a null terminator of correct size and alignment in - // bytes_read - size_t aligned_start = total_bytes_read - total_bytes_read % type_width; - for (size_t i = aligned_start; - i + type_width <= total_bytes_read + bytes_read; i += type_width) - if (::memcmp(&dst[i], terminator, type_width) == 0) { - error.Clear(); - return i; - } - - total_bytes_read += bytes_read; - curr_dst += bytes_read; - curr_addr += bytes_read; - bytes_left -= bytes_read; - } - } else { - if (max_bytes) - error.SetErrorString("invalid arguments"); - } - return total_bytes_read; -} - // Deprecated in favor of ReadStringFromMemory which has wchar support and // correct code to find null terminators. size_t Process::ReadCStringFromMemory(addr_t addr, char *dst, diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -1904,6 +1904,68 @@ return total_cstr_len; } +addr_t Target::GetReasonableReadSize(const Address &addr) { + addr_t load_addr = addr.GetLoadAddress(this); + if (load_addr != LLDB_INVALID_ADDRESS && m_process_sp) { + // Avoid crossing cache line boundaries. + addr_t cache_line_size = m_process_sp->GetMemoryCacheLineSize(); + return cache_line_size - (load_addr % cache_line_size); + } + + // The read is going to go to the file cache, so we can just pick a largish + // value. + return 0x1000; +} + +size_t Target::ReadStringFromMemory(const Address &addr, char *dst, + size_t max_bytes, Status &error, + size_t type_width, bool force_live_memory) { + if (!dst || !max_bytes || !type_width || max_bytes < type_width) + return 0; + + size_t total_bytes_read = 0; + + // Ensure a null terminator independent of the number of bytes that is + // read. + memset(dst, 0, max_bytes); + size_t bytes_left = max_bytes - type_width; + + const char terminator[4] = {'\0', '\0', '\0', '\0'}; + assert(sizeof(terminator) >= type_width && "Attempting to validate a " + "string with more than 4 bytes " + "per character!"); + + Address address = addr; + char *curr_dst = dst; + + error.Clear(); + while (bytes_left > 0 && error.Success()) { + addr_t bytes_to_read = + std::min(bytes_left, GetReasonableReadSize(address)); + size_t bytes_read = + ReadMemory(address, curr_dst, bytes_to_read, error, force_live_memory); + + if (bytes_read == 0) + break; + + // Search for a null terminator of correct size and alignment in + // bytes_read + size_t aligned_start = total_bytes_read - total_bytes_read % type_width; + for (size_t i = aligned_start; + i + type_width <= total_bytes_read + bytes_read; i += type_width) + if (::memcmp(&dst[i], terminator, type_width) == 0) { + error.Clear(); + return i; + } + + total_bytes_read += bytes_read; + curr_dst += bytes_read; + address.Slide(bytes_read); + bytes_left -= bytes_read; + } + return total_bytes_read; +} + size_t Target::ReadScalarIntegerFromMemory(const Address &addr, uint32_t byte_size, bool is_signed, Scalar &scalar, Status &error, diff --git a/lldb/test/API/lang/cpp/char8_t/TestCxxChar8_t.py b/lldb/test/API/lang/cpp/char8_t/TestCxxChar8_t.py --- a/lldb/test/API/lang/cpp/char8_t/TestCxxChar8_t.py +++ b/lldb/test/API/lang/cpp/char8_t/TestCxxChar8_t.py @@ -18,8 +18,24 @@ def test(self): """Test that C++ supports char8_t correctly.""" self.build() - lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.cpp")) + lldbutil.run_to_breakpoint_make_target(self) + + # Make sure the variables can be printed without a running process. + self.expect("target variable a", substrs=["char8_t", "0x61 u8'a'"]) + self.expect("target variable ab", + substrs=["const char8_t *", 'u8"你好"']) + self.expect("target variable abc", substrs=["char8_t[9]", 'u8"你好"']) + + self.expect_expr("a", result_type="char8_t", result_summary="0x61 u8'a'") + self.expect_expr("ab", result_type="const char8_t *", result_summary='u8"你好"') + # FIXME: This should work too. + self.expect("expr abc", substrs=['u8"你好"'], matching=False) + + lldbutil.run_break_set_by_source_regexp(self, "// break here", "-f main.cpp") + self.runCmd("run") + + # As well as with it self.expect_expr("a", result_type="char8_t", result_summary="0x61 u8'a'") self.expect_expr("ab", result_type="const char8_t *", result_summary='u8"你好"') self.expect_expr("abc", result_type="char8_t[9]", result_summary='u8"你好"')