diff --git a/lldb/include/lldb/Host/common/NativeProcessProtocol.h b/lldb/include/lldb/Host/common/NativeProcessProtocol.h index 37dacca6ff8134192c638087912483a62aa352c7..9d83bc5038ffcced5d3f30cef2c983b3d3c5322e 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 505e211e09b630fceca4c099ec99b2b7cb35abbf..d7ea0cb9a35197880a9c0483a10fd006c3b87d68 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 3af8c71dd977057be8f34b3b5d033f16e4d4cfdc..3315025e0279db76026e9801a8e4e56634b29055 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 d869950ab6dd1788a7e24f71f3365401451c9916..a79bead0dc26449128d009ecfda98263ef3fda09 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 5051f9aeec851cd08567a44a23c567c796156280..d94a93ca66a8859edd421e39d541fb3ade8c5c51 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 69b04ee55ba297550c928e7f6546f72e89c42ac6..9b22a16c9793a968253c38984da5c4f49e8ec6d3 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 5804c13fe7b6447c52025bda2decc6b94954c36e..bb3a29412642a3464680b1ad1cc90f217c7b3106 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 1165b60ac762b394e6376d753c8225612b702ccb..047bc6970aa5dbafd594ca89337398dd8a594e79 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 7423f1b93a3b4b13e57e9ef124b25389d5a4921f..4412b8eba631a79e04acf85b3cf81a4679887a04 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 50cef8e499dcc97e9bffd918808b024e0495cb04..b770dcb77e24a3a609759541d8e66a10dd04d390 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 e1a60fba29b5401daad34f5984ea55406c3dcd14..b7e86808f57dd3ce84898b18c0b8e6c2cff0088b 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 3d39fe8152a531db6e419f3d11e90ff071d22926..9d4acaeb9315a365b3588afef95865c3b2a216fe 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 fc740615dd05a28c78f6f90d70ee16b60dac2688..f6c35e3e747c3b176b95c0b7e37d394160e28bbd 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 0000000000000000000000000000000000000000..10495940055b63d2b69fd0ee465e69dad1889d2f --- /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 0000000000000000000000000000000000000000..a8e4f07f81c8904d8f62b26ba2d47501a06a539d --- /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 0000000000000000000000000000000000000000..715c457c30ba45d7b4b6886a34ed934b8f934415 --- /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; +}