From 4e18e664213a569b4f1d7050784fe7e2c8f15346 Mon Sep 17 00:00:00 2001 From: liu-yaxue Date: Thu, 26 Dec 2024 20:53:31 +0800 Subject: [PATCH] Description: Implement both lldb and lldb-server codes and create interface between them to create and implement the command "memory show". issue:lldb real memory show with breakpoint https://gitee.com/openharmony/third_party_llvm-project/issues/IB5YGV Test:Use memory show on a certain address before and after setting a breakpoint, we will see the difference of machine code on the address. Signed-off-by: liu-yaxue --- .../lldb/Host/common/NativeProcessProtocol.h | 5 + lldb/include/lldb/Target/Process.h | 70 +++++++++++ lldb/include/lldb/Target/Target.h | 5 + .../lldb/Utility/StringExtractorGDBRemote.h | 1 + lldb/source/Commands/CommandObjectMemory.cpp | 113 ++++++++++++++++++ .../Host/common/NativeProcessProtocol.cpp | 11 ++ .../GDBRemoteCommunicationServerLLGS.cpp | 76 ++++++++++++ .../GDBRemoteCommunicationServerLLGS.h | 2 + .../Process/gdb-remote/ProcessGDBRemote.cpp | 62 ++++++++++ .../Process/gdb-remote/ProcessGDBRemote.h | 5 + lldb/source/Target/Process.cpp | 23 ++++ lldb/source/Target/Target.cpp | 47 ++++++++ .../Utility/StringExtractorGDBRemote.cpp | 4 + lldb/test/API/commands/memory/show/Makefile | 3 + .../commands/memory/show/TestMemoryShow.py | 77 ++++++++++++ lldb/test/API/commands/memory/show/main.c | 9 ++ 16 files changed, 513 insertions(+) create mode 100644 lldb/test/API/commands/memory/show/Makefile create mode 100644 lldb/test/API/commands/memory/show/TestMemoryShow.py create mode 100644 lldb/test/API/commands/memory/show/main.c diff --git a/lldb/include/lldb/Host/common/NativeProcessProtocol.h b/lldb/include/lldb/Host/common/NativeProcessProtocol.h index 37dacca6ff81..9d83bc5038ff 100644 --- a/lldb/include/lldb/Host/common/NativeProcessProtocol.h +++ b/lldb/include/lldb/Host/common/NativeProcessProtocol.h @@ -98,6 +98,11 @@ public: Status ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t size, size_t &bytes_read); + // OHOS_LOCAL begin + Status ShowMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t size, + size_t &bytes_read); + // OHOS_LOCAL end + virtual Status ReadMemoryTags(int32_t type, lldb::addr_t addr, size_t len, std::vector &tags); diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index 505e211e09b6..d7ea0cb9a351 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -1448,6 +1448,43 @@ public: virtual size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, Status &error); + // OHOS_LOCAL begin + /// show memory without coverage of a process. + /// + /// This function will read and show memory from the current process's address space + /// and the memory will not be covered, showing the true status(with/without breakpoints). + /// + /// This function is not meant to be overridden by Process subclasses, the + /// subclasses should implement Process::DoShowMemory (lldb::addr_t vm_addr, void *buf, + /// size_t size, Status &error). + /// + /// \param[in] vm_addr + /// A virtual load address that indicates where to start reading + /// memory from. + /// + /// \param[out] buf + /// A byte buffer that is at least \a size bytes long that + /// will receive the memory bytes. + /// + /// \param[in] size + /// The number of bytes to read. + /// + /// \param[out] error + /// An error that indicates the success or failure of this + /// operation. If error indicates success (error.Success()), + /// then the value returned can be trusted, otherwise zero + /// will be returned. + /// + /// \return + /// The number of bytes that were actually read into \a buf. If + /// the returned number is greater than zero, yet less than \a + /// size, then this function will get called again with \a + /// vm_addr, \a buf, and \a size updated appropriately. Zero is + /// returned in the case of an error. + virtual size_t ShowMemory(lldb::addr_t vm_addr, void *buf, size_t size, + Status &error); + // OHOS_LOCAL end + /// Read of memory from a process. /// /// This function has the same semantics of ReadMemory except that it @@ -2602,6 +2639,39 @@ protected: virtual size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, Status &error) = 0; + // OHOS_LOCAL begin + /// Actually do the reading of memory without coverage from a process. + /// + /// Subclasses must override this function and can return fewer bytes than + /// requested when memory requests are too large. This class will break up + /// the memory requests and keep advancing the arguments along as needed. + /// + /// \param[in] vm_addr + /// A virtual load address that indicates where to start reading + /// memory from. + /// + /// \param[in] size + /// The number of bytes to read. + /// + /// \param[out] buf + /// A byte buffer that is at least \a size bytes long that + /// will receive the memory bytes. + /// + /// \param[out] error + /// An error that indicates the success or failure of this + /// operation. If error indicates success (error.Success()), + /// then the value returned can be trusted, otherwise zero + /// will be returned. + /// + /// \return + /// The number of bytes that were actually read into \a buf. + /// Zero is returned in the case of an error. + virtual size_t DoShowMemory(lldb::addr_t vm_addr, void *buf, size_t size, + Status &error) { + return 0; + } + // OHOS_LOCAL end + /// DoGetMemoryRegionInfo is called by GetMemoryRegionInfo after it has /// removed non address bits from load_addr. Override this method in /// subclasses of Process. diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 3af8c71dd977..3315025e0279 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -1038,6 +1038,11 @@ public: Status &error, bool force_live_memory = false, lldb::addr_t *load_addr_ptr = nullptr); + // OHOS_LOCAL begin + size_t ShowMemory(const Address &addr, void *dst, size_t dst_len, + Status &error, lldb::addr_t *load_addr_ptr = nullptr); + // OHOS_LOCAL end + size_t ReadCStringFromMemory(const Address &addr, std::string &out_str, Status &error, bool force_live_memory = false); diff --git a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h index d869950ab6dd..a79bead0dc26 100644 --- a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h +++ b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h @@ -180,6 +180,7 @@ public: eServerPacketType_vStopped, eServerPacketType_vCtrlC, eServerPacketType_vStdio, + eServerPacketType_qShowMem, // OHOS_LOCAL }; ServerPacketType GetServerPacketType() const; diff --git a/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp index 5051f9aeec85..d94a93ca66a8 100644 --- a/lldb/source/Commands/CommandObjectMemory.cpp +++ b/lldb/source/Commands/CommandObjectMemory.cpp @@ -280,6 +280,115 @@ public: OptionValueLanguage m_language_for_type; }; +// OHOS_LOCAL begin +class CommandObjectMemoryShow : public CommandObjectParsed { +public: + CommandObjectMemoryShow(CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "memory show", + "Displays the memory of the certain address without covering breakpoints." + "This command is supported in the following scenarios:" + "local debugging on Linux, remote debugging from Linux or Windows to aarch64-linux-ohos," + "and local debugging on aarch64-linux-ohos. However, it is not supported for local debugging on Windows. ", nullptr, + eCommandRequiresTarget | eCommandProcessMustBePaused) { + CommandArgumentEntry arg; + CommandArgumentData addr_arg; + addr_arg.arg_type = eArgTypeAddressOrExpression; + addr_arg.arg_repetition = eArgRepeatPlain; + arg.push_back(addr_arg); + m_arguments.push_back(arg); + } + + ~CommandObjectMemoryShow() override = default; + + Options *GetOptions() override { return nullptr; } + + llvm::Optional GetRepeatCommand(Args ¤t_command_args, + uint32_t index) override { + return m_cmd_name; + } + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + // No need to check "target" for validity as eCommandRequiresTarget ensures + // it is valid + Target *target = m_exe_ctx.GetTargetPtr(); + const size_t argc = command.GetArgumentCount(); + if (argc != 1) { + result.AppendError("Usage: memory show
"); + return false; + } + lldb::addr_t addr; + size_t item_count = 32; + size_t item_byte_size = 1; + const size_t num_per_line = 16; + size_t total_byte_size = item_count * item_byte_size; + Status error; + addr = OptionArgParser::ToAddress(&m_exe_ctx, command[0].ref(), + LLDB_INVALID_ADDRESS, &error); + + if (addr == LLDB_INVALID_ADDRESS) { + result.AppendError("invalid start address expression."); + result.AppendError(error.AsCString()); + return false; + } + + ABISP abi; + if (Process *proc = m_exe_ctx.GetProcessPtr()) + abi = proc->GetABI(); + + if (abi) + addr = abi->FixDataAddress(addr); + + WritableDataBufferSP data_sp; + size_t bytes_read = 0; + data_sp = std::make_shared(total_byte_size, '\0'); + if (data_sp->GetBytes() == nullptr) { + result.AppendErrorWithFormat( + "can't allocate 0x%" PRIx32 + " bytes for the memory show buffer, specify a smaller size to show", + (uint32_t)total_byte_size); + return false; + } + + Address address(addr, nullptr); + bytes_read = target->ShowMemory(address, data_sp->GetBytes(), + data_sp->GetByteSize(), error); + if (bytes_read == 0) { + const char *error_cstr = error.AsCString(); + if (error_cstr && error_cstr[0]) { + result.AppendError(error_cstr); + } else { + result.AppendErrorWithFormat( + "failed to show memory from 0x%" PRIx64 ".\n", addr); + } + return false; + } + + if (bytes_read < total_byte_size) + result.AppendWarningWithFormat( + "Not all bytes (%" PRIu64 "/%" PRIu64 + ") were able to be show from 0x%" PRIx64 ".\n", + (uint64_t)bytes_read, (uint64_t)total_byte_size, addr); + + Stream *output_stream_p = &result.GetOutputStream(); + ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope(); + + result.SetStatus(eReturnStatusSuccessFinishResult); + DataExtractor data(data_sp, target->GetArchitecture().GetByteOrder(), + target->GetArchitecture().GetAddressByteSize(), + target->GetArchitecture().GetDataByteSize()); + assert(output_stream_p); + DumpDataExtractor( + data, output_stream_p, 0, eFormatBytesWithASCII, item_byte_size, item_count, + num_per_line / target->GetArchitecture().GetDataByteSize(), addr, 0, 0, + exe_scope, false); + output_stream_p->EOL(); + return true; + } +}; +// OHOS_LOCAL end + // Read memory from the inferior process class CommandObjectMemoryRead : public CommandObjectParsed { public: @@ -1880,6 +1989,10 @@ CommandObjectMemory::CommandObjectMemory(CommandInterpreter &interpreter) CommandObjectSP(new CommandObjectMemoryRead(interpreter))); LoadSubCommand("write", CommandObjectSP(new CommandObjectMemoryWrite(interpreter))); + // OHOS_LOCAL begin + LoadSubCommand("show", + CommandObjectSP(new CommandObjectMemoryShow(interpreter))); + // OHOS_LOCAL end LoadSubCommand("history", CommandObjectSP(new CommandObjectMemoryHistory(interpreter))); LoadSubCommand("region", diff --git a/lldb/source/Host/common/NativeProcessProtocol.cpp b/lldb/source/Host/common/NativeProcessProtocol.cpp index 69b04ee55ba2..9b22a16c9793 100644 --- a/lldb/source/Host/common/NativeProcessProtocol.cpp +++ b/lldb/source/Host/common/NativeProcessProtocol.cpp @@ -659,6 +659,17 @@ Status NativeProcessProtocol::ReadMemoryWithoutTrap(lldb::addr_t addr, return Status(); } +// OHOS_LOCAL begin +Status NativeProcessProtocol::ShowMemoryWithoutTrap(lldb::addr_t addr, + void *buf, size_t size, + size_t &bytes_read) { + Status error = ReadMemory(addr, buf, size, bytes_read); + if (error.Fail()) + return error; + return Status(); +} +// OHOS_LOCAL end + llvm::Expected NativeProcessProtocol::ReadCStringFromMemory(lldb::addr_t addr, char *buffer, size_t max_size, diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 5804c13fe7b6..bb3a29412642 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -95,6 +95,11 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_m, &GDBRemoteCommunicationServerLLGS::Handle_memory_read); + // OHOS_LOCAL begin + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qShowMem, + &GDBRemoteCommunicationServerLLGS::Handle_memory_show); + // OHOS_LOCAL end RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_M, &GDBRemoteCommunicationServerLLGS::Handle_M); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType__M, @@ -2550,6 +2555,77 @@ GDBRemoteCommunicationServerLLGS::Handle_memory_read( return SendPacketNoLock(response.GetString()); } +// OHOS_LOCAL begin +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_memory_show( + StringExtractorGDBRemote &packet) { + Log *log = GetLog(LLDBLog::Process); + + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { + LLDB_LOGF( + log, + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + //Parse out the memory address. + packet.SetFilePos(strlen("qShowMem")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short qShowMem packet"); + + // Read the address. Punting on validation. + const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0); + + // Validate comma. + if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ',')) + return SendIllFormedResponse(packet, "Comma sep missing in qShowMem packet"); + + // Get # bytes to read. + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Length missing in qShowMem packet"); + + const uint64_t byte_count = packet.GetHexMaxU64(false, 0); + if (byte_count == 0) { + LLDB_LOGF(log, + "GDBRemoteCommunicationServerLLGS::%s nothing to read: " + "zero-length packet", + __FUNCTION__); + return SendOKResponse(); + } + + // Allocate the response buffer. + std::string buf(byte_count, '\0'); + if (buf.empty()) + return SendErrorResponse(0x78); + + // Retrieve the process memory. + size_t bytes_read = 0; + Status error = m_current_process->ShowMemoryWithoutTrap( + read_addr, &buf[0], byte_count, bytes_read); + if (error.Fail()) { + LLDB_LOGF(log, + "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " mem 0x%" PRIx64 ": failed to read. Error: %s", + __FUNCTION__, m_current_process->GetID(), read_addr, + error.AsCString()); + return SendErrorResponse(0x08); + } + if (bytes_read == 0) { + LLDB_LOGF(log, + "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " mem 0x%" PRIx64 ": read 0 of %" PRIu64 " requested bytes", + __FUNCTION__, m_current_process->GetID(), read_addr, byte_count); + return SendErrorResponse(0x08); + } + StreamGDBRemote response; + packet.SetFilePos(0); + response.PutEscapedBytes(buf.data(), byte_count); + return SendPacketNoLock(response.GetString()); +} +// OHOS_LOCAL end + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle__M(StringExtractorGDBRemote &packet) { Log *log = GetLog(LLDBLog::Process); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index 1165b60ac762..047bc6970aa5 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -189,6 +189,8 @@ protected: PacketResult Handle_interrupt(StringExtractorGDBRemote &packet); + PacketResult Handle_memory_show(StringExtractorGDBRemote &packet);// OHOS_LOCAL + // Handles $m and $x packets. PacketResult Handle_memory_read(StringExtractorGDBRemote &packet); diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 7423f1b93a3b..4412b8eba631 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -2581,6 +2581,68 @@ size_t ProcessGDBRemote::DoReadMemory(addr_t addr, void *buf, size_t size, return 0; } +// OHOS_LOCAL begin +size_t ProcessGDBRemote::DoShowMemory(addr_t addr, void *buf, size_t size, + Status &error) { + LLDB_MODULE_TIMER(LLDBPerformanceTagName::TAG_GDBREMOTE); + GetMaxMemorySize(); + //Copy from GDBRemoteCommunicationClient::GetxPacketSupported(), + //here we test if qShowMem packet can be sent. + char packet_test[256]; + StringExtractorGDBRemote response_test; + snprintf(packet_test, sizeof(packet_test), "qShowMem0,0"); + if (m_gdb_comm.SendPacketAndWaitForResponse(packet_test, response_test) == + GDBRemoteCommunication::PacketResult::Success) { + if (!response_test.IsOKResponse()) + error.SetErrorStringWithFormat( + "failed to send packet: '%s', memory show failed", packet_test); + } + size_t max_memory_size =m_max_memory_size; + if (size > max_memory_size) { + // Keep memory read sizes down to a sane limit. This function will be + // called multiple times in order to complete the task by + // lldb_private::Process so it is ok to do this. + size = max_memory_size; + } + char packet[64]; + int packet_len; + packet_len = ::snprintf(packet, sizeof(packet), "%s%" PRIx64 ",%" PRIx64, + "qShowMem", (uint64_t)addr, (uint64_t)size); + assert(packet_len + 1 < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response, + GetInterruptTimeout()) == + GDBRemoteCommunication::PacketResult::Success) { + if (response.IsNormalResponse()) { + error.Clear(); + // The lower level GDBRemoteCommunication packet receive layer has + // already de-quoted any 0x7d character escaping that was present in + // the packet + size_t data_received_size = response.GetBytesLeft(); + if (data_received_size > size) { + // Don't write past the end of BUF if the remote debug server gave us + // too much data for some reason. + data_received_size = size; + } + memcpy(buf, response.GetStringRef().data(), data_received_size); + return data_received_size; + } else if (response.IsErrorResponse()) + error.SetErrorStringWithFormat("memory show failed for 0x%" PRIx64, addr); + else if (response.IsUnsupportedResponse()) + error.SetErrorStringWithFormat( + "GDB server does not support showing memory"); + else + error.SetErrorStringWithFormat( + "unexpected response to GDB server memory show packet '%s': '%s'", + packet, response.GetStringRef().data()); + } else { + error.SetErrorStringWithFormat("failed to send packet: '%s'", packet); + } + return 0; +} +// OHOS_LOCAL end + bool ProcessGDBRemote::SupportsMemoryTagging() { return m_gdb_comm.GetMemoryTaggingSupported(); } diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 50cef8e499dc..b770dcb77e24 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -136,6 +136,11 @@ public: size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, Status &error) override; + // OHOS_LOCAL begin + size_t DoShowMemory(lldb::addr_t addr, void *buf, size_t size, + Status &error) override; + // OHOS_LOCAL end + Status WriteObjectFile(std::vector entries) override; diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index e1a60fba29b5..b7e86808f57d 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -1967,6 +1967,29 @@ size_t Process::ReadMemory(addr_t addr, void *buf, size_t size, Status &error) { } } +// OHOS_LOCAL begin +size_t Process::ShowMemory(addr_t addr, void *buf, size_t size, Status &error) { + if (ABISP abi_sp = GetABI()) + addr = abi_sp->FixAnyAddress(addr); + LLDB_SCOPED_TIMER(); + LLDB_MODULE_TIMER(LLDBPerformanceTagName::TAG_PROCESS); + if (buf == nullptr || size == 0) { + return 0; + } + size_t bytes_read = 0; + uint8_t *bytes = (uint8_t *)buf; + while (bytes_read < size) { + const size_t curr_size = size - bytes_read; + const size_t curr_bytes_read = + DoShowMemory(addr + bytes_read, bytes + bytes_read, curr_size, error); + bytes_read += curr_bytes_read; + if (curr_bytes_read == curr_size || curr_bytes_read == 0) + break; + } + return bytes_read; +} +// OHOS_LOCAL end + size_t Process::ReadCStringFromMemory(addr_t addr, std::string &out_str, Status &error) { char buf[256]; diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 3d39fe8152a5..9d4acaeb9315 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -1867,6 +1867,53 @@ size_t Target::ReadMemory(const Address &addr, void *dst, size_t dst_len, return 0; } +// OHOS_LOCAL begin +size_t Target::ShowMemory(const Address &addr, void *dst, size_t dst_len, + Status &error, lldb::addr_t *load_addr_ptr) { + error.Clear(); + + Address fixed_addr = addr; + if (ProcessIsValid()) + if (const ABISP &abi = m_process_sp->GetABI()) + fixed_addr.SetLoadAddress(abi->FixAnyAddress(addr.GetLoadAddress(this)), + this); + + // if we end up reading this from process memory, we will fill this with the + // actual load address + if (load_addr_ptr) + *load_addr_ptr = LLDB_INVALID_ADDRESS; + + size_t bytes_read = 0; + + addr_t load_addr = fixed_addr.GetLoadAddress(this); + if (ProcessIsValid()) { + if (load_addr == LLDB_INVALID_ADDRESS) { + error.SetErrorStringWithFormat("load_addr is invalid"); + } else { + bytes_read = m_process_sp->ShowMemory(load_addr, dst, dst_len, error); + if (bytes_read != dst_len) { + if (error.Success()) { + if (bytes_read == 0) + error.SetErrorStringWithFormat( + "show memory from 0x%" PRIx64 " failed", load_addr); + else + error.SetErrorStringWithFormat( + "only %" PRIu64 " of %" PRIu64 + " bytes were read from memory at 0x%" PRIx64, + (uint64_t)bytes_read, (uint64_t)dst_len, load_addr); + } + } + if (bytes_read) { + if (load_addr_ptr) + *load_addr_ptr = load_addr; + return bytes_read; + } + } + } + return 0; +} +// OHOS_LOCAL end + size_t Target::ReadCStringFromMemory(const Address &addr, std::string &out_str, Status &error, bool force_live_memory) { char buf[256]; diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp index fc740615dd05..f6c35e3e747c 100644 --- a/lldb/source/Utility/StringExtractorGDBRemote.cpp +++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -279,6 +279,10 @@ StringExtractorGDBRemote::GetServerPacketType() const { return eServerPacketType_qSupported; if (PACKET_MATCHES("qSyncThreadStateSupported")) return eServerPacketType_qSyncThreadStateSupported; + // OHOS_LOCAL begin + if (PACKET_STARTS_WITH("qShowMem")) + return eServerPacketType_qShowMem; + // OHOS_LOCAL end break; case 'T': diff --git a/lldb/test/API/commands/memory/show/Makefile b/lldb/test/API/commands/memory/show/Makefile new file mode 100644 index 000000000000..10495940055b --- /dev/null +++ b/lldb/test/API/commands/memory/show/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/commands/memory/show/TestMemoryShow.py b/lldb/test/API/commands/memory/show/TestMemoryShow.py new file mode 100644 index 000000000000..a8e4f07f81c8 --- /dev/null +++ b/lldb/test/API/commands/memory/show/TestMemoryShow.py @@ -0,0 +1,77 @@ +import lldb +import lldbsuite.test.lldbutil as lldbutil +import re +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * + + +class MemoryShowTestCase(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + def build_run_test_stop(self): + self.build() + lldbutil.run_to_source_breakpoint(self, "// breakpoint", + lldb.SBFileSpec("main.c")) + + def test_memory_show(self): + """Test the 'memory read' and 'memory show' commands with a given address.""" + self.build_run_test_stop() + + # Find the starting address for variable 'argc' to use in the test. + self.runCmd("p &argc") + line = self.res.GetOutput().splitlines()[0] + address = int(line.split('=')[1].strip(), 0) + + # Run 'memory read' command and capture the output. + self.runCmd(f"memory read {address}") + memory_read_output = self.res.GetOutput().strip() + + # Run 'memory show' command and capture the output. + self.runCmd(f"memory show {address}") + memory_show_output = self.res.GetOutput().strip() + + # Compare the outputs of 'memory read' and 'memory show'. + self.assertEqual(memory_read_output, memory_show_output, "The output of 'memory read' and 'memory show' should be the same.") + + @skipUnlessArch("x86_64") + def test_memory_show_breakpoint_x86(self): + self.build_run_test_stop() + self.runCmd("b 5") + self.runCmd("b 7") + self.runCmd("breakpoint list") + line = self.res.GetOutput().splitlines()[5] + pattern = r"0x[0-9a-fA-F]+" + address = re.search(pattern, line).group(0) + self.runCmd("memory show " + address) + res = self.res.GetOutput() + memory_data = res.split(':')[1][1:3] + self.assertEqual( + memory_data, "cc") + self.runCmd("br del 2") + self.runCmd("memory show " + address) + res = self.res.GetOutput() + memory_data = res.split(':')[1][1:3] + self.assertNotEqual( + memory_data, "cc") + + @skipUnlessArch("aarch64") + def test_memory_show_breakpoint_aarch64(self): + self.build_run_test_stop() + self.runCmd("b 5") + self.runCmd("b 7") + self.runCmd("breakpoint list") + pattern_line = r"2.1.*, resolved" + line = re.search(pattern_line, self.res.GetOutput()).group(0) + pattern = r"0x[0-9a-fA-F]+" + address = re.search(pattern, line).group(0) + self.runCmd("memory show " + address) + res = self.res.GetOutput() + memory_data = res.split(':')[1][1:12] + self.assertEqual( + memory_data, "00 00 20 d4") + self.runCmd("br del 2") + self.runCmd("memory show " + address) + res = self.res.GetOutput() + memory_data = res.split(':')[1][1:3] + self.assertNotEqual( + memory_data, "00 00 20 d4") diff --git a/lldb/test/API/commands/memory/show/main.c b/lldb/test/API/commands/memory/show/main.c new file mode 100644 index 000000000000..715c457c30ba --- /dev/null +++ b/lldb/test/API/commands/memory/show/main.c @@ -0,0 +1,9 @@ +#include + +int main(int argc, const char *argv[]) { + char my_string[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 0}; // breakpoint + double my_double = 1234.5678; + int my_ints[] = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22}; + uint64_t my_uint64s[] = {0, 1, 2, 3, 4, 5, 6, 7}; + return 0; +} -- Gitee