forked from OSchip/llvm-project
Implement xfer:libraries-svr4:read packet
Summary: This is the fourth patch to improve module loading in a series that started here (where I explain the motivation and solution): D62499 Implement the `xfer:libraries-svr4` packet by adding a new function that generates the list and then in Handle_xfer I generate the XML for it. The XML is really simple so I'm just using string concatenation because I believe it's more readable than having to deal with a DOM api. Reviewers: clayborg, xiaobai, labath Reviewed By: labath Subscribers: emaste, mgorny, srhines, krytarowski, lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D62502 llvm-svn: 363707
This commit is contained in:
parent
5cf216c9a7
commit
fda83c9b0b
|
@ -32,6 +32,14 @@ namespace lldb_private {
|
||||||
class MemoryRegionInfo;
|
class MemoryRegionInfo;
|
||||||
class ResumeActionList;
|
class ResumeActionList;
|
||||||
|
|
||||||
|
struct SVR4LibraryInfo {
|
||||||
|
std::string name;
|
||||||
|
lldb::addr_t link_map;
|
||||||
|
lldb::addr_t base_addr;
|
||||||
|
lldb::addr_t ld_addr;
|
||||||
|
lldb::addr_t next;
|
||||||
|
};
|
||||||
|
|
||||||
// NativeProcessProtocol
|
// NativeProcessProtocol
|
||||||
class NativeProcessProtocol {
|
class NativeProcessProtocol {
|
||||||
public:
|
public:
|
||||||
|
@ -86,6 +94,12 @@ public:
|
||||||
|
|
||||||
virtual lldb::addr_t GetSharedLibraryInfoAddress() = 0;
|
virtual lldb::addr_t GetSharedLibraryInfoAddress() = 0;
|
||||||
|
|
||||||
|
virtual llvm::Expected<std::vector<SVR4LibraryInfo>>
|
||||||
|
GetLoadedSVR4Libraries() {
|
||||||
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
||||||
|
"Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool IsAlive() const;
|
virtual bool IsAlive() const;
|
||||||
|
|
||||||
virtual size_t UpdateThreads() = 0;
|
virtual size_t UpdateThreads() = 0;
|
||||||
|
|
|
@ -513,7 +513,8 @@ class GdbRemoteTestCaseBase(TestBase):
|
||||||
self,
|
self,
|
||||||
inferior_args=None,
|
inferior_args=None,
|
||||||
inferior_sleep_seconds=3,
|
inferior_sleep_seconds=3,
|
||||||
inferior_exe_path=None):
|
inferior_exe_path=None,
|
||||||
|
inferior_env=None):
|
||||||
"""Prep the debug monitor, the inferior, and the expected packet stream.
|
"""Prep the debug monitor, the inferior, and the expected packet stream.
|
||||||
|
|
||||||
Handle the separate cases of using the debug monitor in attach-to-inferior mode
|
Handle the separate cases of using the debug monitor in attach-to-inferior mode
|
||||||
|
@ -576,6 +577,9 @@ class GdbRemoteTestCaseBase(TestBase):
|
||||||
|
|
||||||
# Build the expected protocol stream
|
# Build the expected protocol stream
|
||||||
self.add_no_ack_remote_stream()
|
self.add_no_ack_remote_stream()
|
||||||
|
if inferior_env:
|
||||||
|
for name, value in inferior_env.items():
|
||||||
|
self.add_set_environment_packets(name, value)
|
||||||
if self._inferior_startup == self._STARTUP_LAUNCH:
|
if self._inferior_startup == self._STARTUP_LAUNCH:
|
||||||
self.add_verified_launch_packets(launch_args)
|
self.add_verified_launch_packets(launch_args)
|
||||||
|
|
||||||
|
@ -656,6 +660,12 @@ class GdbRemoteTestCaseBase(TestBase):
|
||||||
{"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$", "capture": {1: "process_info_raw"}}],
|
{"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$", "capture": {1: "process_info_raw"}}],
|
||||||
True)
|
True)
|
||||||
|
|
||||||
|
def add_set_environment_packets(self, name, value):
|
||||||
|
self.test_sequence.add_log_lines(
|
||||||
|
["read packet: $QEnvironment:" + name + "=" + value + "#00",
|
||||||
|
"send packet: $OK#00",
|
||||||
|
], True)
|
||||||
|
|
||||||
_KNOWN_PROCESS_INFO_KEYS = [
|
_KNOWN_PROCESS_INFO_KEYS = [
|
||||||
"pid",
|
"pid",
|
||||||
"parent-pid",
|
"parent-pid",
|
||||||
|
@ -816,6 +826,7 @@ class GdbRemoteTestCaseBase(TestBase):
|
||||||
"error"])
|
"error"])
|
||||||
self.assertIsNotNone(val)
|
self.assertIsNotNone(val)
|
||||||
|
|
||||||
|
mem_region_dict["name"] = seven.unhexlify(mem_region_dict.get("name", ""))
|
||||||
# Return the dictionary of key-value pairs for the memory region.
|
# Return the dictionary of key-value pairs for the memory region.
|
||||||
return mem_region_dict
|
return mem_region_dict
|
||||||
|
|
||||||
|
@ -1000,6 +1011,22 @@ class GdbRemoteTestCaseBase(TestBase):
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
def continue_process_and_wait_for_stop(self):
|
||||||
|
self.test_sequence.add_log_lines(
|
||||||
|
[
|
||||||
|
"read packet: $vCont;c#a8",
|
||||||
|
{
|
||||||
|
"direction": "send",
|
||||||
|
"regex": r"^\$T([0-9a-fA-F]{2})(.*)#[0-9a-fA-F]{2}$",
|
||||||
|
"capture": {1: "stop_signo", 2: "stop_key_val_text"},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
context = self.expect_gdbremote_sequence()
|
||||||
|
self.assertIsNotNone(context)
|
||||||
|
return self.parse_interrupt_packets(context)
|
||||||
|
|
||||||
def select_modifiable_register(self, reg_infos):
|
def select_modifiable_register(self, reg_infos):
|
||||||
"""Find a register that can be read/written freely."""
|
"""Find a register that can be read/written freely."""
|
||||||
PREFERRED_REGISTER_NAMES = set(["rax", ])
|
PREFERRED_REGISTER_NAMES = set(["rax", ])
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
LEVEL = ../../../make
|
||||||
|
|
||||||
|
LIB_PREFIX := svr4lib
|
||||||
|
LD_EXTRAS := -L. -l$(LIB_PREFIX)_a -l$(LIB_PREFIX)_b\"
|
||||||
|
CXX_SOURCES := main.cpp
|
||||||
|
USE_LIBDL := 1
|
||||||
|
MAKE_DSYM := NO
|
||||||
|
|
||||||
|
include $(LEVEL)/Makefile.rules
|
||||||
|
|
||||||
|
a.out: $(LIB_PREFIX)_a $(LIB_PREFIX)_b_quote
|
||||||
|
|
||||||
|
svr4lib_%:
|
||||||
|
$(MAKE) VPATH=$(SRCDIR) -I $(SRCDIR) -f "$(SRCDIR)/$(LIB_PREFIX)_$*.mk"
|
||||||
|
|
||||||
|
clean::
|
||||||
|
$(MAKE) -f $(SRCDIR)/$(LIB_PREFIX)_a.mk clean
|
|
@ -0,0 +1,127 @@
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
import gdbremote_testcase
|
||||||
|
from lldbsuite.test.decorators import *
|
||||||
|
from lldbsuite.test.lldbtest import *
|
||||||
|
|
||||||
|
|
||||||
|
class TestGdbRemoteLibrariesSvr4Support(gdbremote_testcase.GdbRemoteTestCaseBase):
|
||||||
|
|
||||||
|
mydir = TestBase.compute_mydir(__file__)
|
||||||
|
|
||||||
|
FEATURE_NAME = "qXfer:libraries-svr4:read"
|
||||||
|
|
||||||
|
def setup_test(self):
|
||||||
|
self.init_llgs_test()
|
||||||
|
self.build()
|
||||||
|
self.set_inferior_startup_launch()
|
||||||
|
env = {}
|
||||||
|
env[self.dylibPath] = self.getBuildDir()
|
||||||
|
self.prep_debug_monitor_and_inferior(inferior_env=env)
|
||||||
|
self.continue_process_and_wait_for_stop()
|
||||||
|
|
||||||
|
def has_libraries_svr4_support(self):
|
||||||
|
self.add_qSupported_packets()
|
||||||
|
context = self.expect_gdbremote_sequence()
|
||||||
|
self.assertIsNotNone(context)
|
||||||
|
features = self.parse_qSupported_response(context)
|
||||||
|
return self.FEATURE_NAME in features and features[self.FEATURE_NAME] == "+"
|
||||||
|
|
||||||
|
def get_libraries_svr4_data(self):
|
||||||
|
# Start up llgs and inferior, and check for libraries-svr4 support.
|
||||||
|
if not self.has_libraries_svr4_support():
|
||||||
|
self.skipTest("libraries-svr4 not supported")
|
||||||
|
|
||||||
|
# Grab the libraries-svr4 data.
|
||||||
|
self.reset_test_sequence()
|
||||||
|
self.test_sequence.add_log_lines(
|
||||||
|
[
|
||||||
|
"read packet: $qXfer:libraries-svr4:read::0,ffff:#00",
|
||||||
|
{
|
||||||
|
"direction": "send",
|
||||||
|
"regex": re.compile(
|
||||||
|
r"^\$([^E])(.*)#[0-9a-fA-F]{2}$", re.MULTILINE | re.DOTALL
|
||||||
|
),
|
||||||
|
"capture": {1: "response_type", 2: "content_raw"},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
|
||||||
|
context = self.expect_gdbremote_sequence()
|
||||||
|
self.assertIsNotNone(context)
|
||||||
|
|
||||||
|
# Ensure we end up with all libraries-svr4 data in one packet.
|
||||||
|
self.assertEqual(context.get("response_type"), "l")
|
||||||
|
|
||||||
|
# Decode binary data.
|
||||||
|
content_raw = context.get("content_raw")
|
||||||
|
self.assertIsNotNone(content_raw)
|
||||||
|
return content_raw
|
||||||
|
|
||||||
|
def get_libraries_svr4_xml(self):
|
||||||
|
libraries_svr4 = self.get_libraries_svr4_data()
|
||||||
|
xml_root = None
|
||||||
|
try:
|
||||||
|
xml_root = ET.fromstring(libraries_svr4)
|
||||||
|
except xml.etree.ElementTree.ParseError:
|
||||||
|
pass
|
||||||
|
self.assertIsNotNone(xml_root, "Malformed libraries-svr4 XML")
|
||||||
|
return xml_root
|
||||||
|
|
||||||
|
def libraries_svr4_well_formed(self):
|
||||||
|
xml_root = self.get_libraries_svr4_xml()
|
||||||
|
self.assertEqual(xml_root.tag, "library-list-svr4")
|
||||||
|
for child in xml_root:
|
||||||
|
self.assertEqual(child.tag, "library")
|
||||||
|
self.assertItemsEqual(child.attrib.keys(), ["name", "lm", "l_addr", "l_ld"])
|
||||||
|
|
||||||
|
def libraries_svr4_has_correct_load_addr(self):
|
||||||
|
xml_root = self.get_libraries_svr4_xml()
|
||||||
|
for child in xml_root:
|
||||||
|
name = child.attrib.get("name")
|
||||||
|
if not name:
|
||||||
|
continue
|
||||||
|
load_addr = int(child.attrib.get("l_addr"), 16)
|
||||||
|
self.reset_test_sequence()
|
||||||
|
self.add_query_memory_region_packets(load_addr)
|
||||||
|
context = self.expect_gdbremote_sequence()
|
||||||
|
mem_region = self.parse_memory_region_packet(context)
|
||||||
|
self.assertEqual(load_addr, int(mem_region.get("start", 0), 16))
|
||||||
|
self.assertEqual(
|
||||||
|
os.path.realpath(name), os.path.realpath(mem_region.get("name", ""))
|
||||||
|
)
|
||||||
|
|
||||||
|
def libraries_svr4_libs_present(self):
|
||||||
|
xml_root = self.get_libraries_svr4_xml()
|
||||||
|
libraries_svr4_names = []
|
||||||
|
for child in xml_root:
|
||||||
|
name = child.attrib.get("name")
|
||||||
|
libraries_svr4_names.append(os.path.realpath(name))
|
||||||
|
expected_libs = ["libsvr4lib_a.so", 'libsvr4lib_b".so']
|
||||||
|
for lib in expected_libs:
|
||||||
|
self.assertIn(self.getBuildDir() + "/" + lib, libraries_svr4_names)
|
||||||
|
|
||||||
|
@llgs_test
|
||||||
|
@skipUnlessPlatform(["linux", "android", "netbsd"])
|
||||||
|
def test_supports_libraries_svr4(self):
|
||||||
|
self.setup_test()
|
||||||
|
self.assertTrue(self.has_libraries_svr4_support())
|
||||||
|
|
||||||
|
@llgs_test
|
||||||
|
@skipUnlessPlatform(["linux", "android", "netbsd"])
|
||||||
|
def test_libraries_svr4_well_formed(self):
|
||||||
|
self.setup_test()
|
||||||
|
self.libraries_svr4_well_formed()
|
||||||
|
|
||||||
|
@llgs_test
|
||||||
|
@skipUnlessPlatform(["linux", "android", "netbsd"])
|
||||||
|
def test_libraries_svr4_load_addr(self):
|
||||||
|
self.setup_test()
|
||||||
|
self.libraries_svr4_has_correct_load_addr()
|
||||||
|
|
||||||
|
@llgs_test
|
||||||
|
@skipUnlessPlatform(["linux", "android", "netbsd"])
|
||||||
|
def test_libraries_svr4_libs_present(self):
|
||||||
|
self.setup_test()
|
||||||
|
self.libraries_svr4_libs_present()
|
|
@ -0,0 +1,15 @@
|
||||||
|
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
// Perform a null pointer access.
|
||||||
|
int *const null_int_ptr = nullptr;
|
||||||
|
*null_int_ptr = 0xDEAD;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
int svr4lib_a() { return 42; }
|
|
@ -0,0 +1,9 @@
|
||||||
|
LEVEL = ../../../make
|
||||||
|
|
||||||
|
LIB_PREFIX := svr4lib
|
||||||
|
|
||||||
|
DYLIB_NAME := $(LIB_PREFIX)_a
|
||||||
|
DYLIB_CXX_SOURCES := $(LIB_PREFIX)_a.cpp
|
||||||
|
DYLIB_ONLY := YES
|
||||||
|
|
||||||
|
include $(LEVEL)/Makefile.rules
|
|
@ -0,0 +1,9 @@
|
||||||
|
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
int svr4lib_b_quote() { return 42; }
|
|
@ -0,0 +1,9 @@
|
||||||
|
LEVEL = ../../../make
|
||||||
|
|
||||||
|
LIB_PREFIX := svr4lib
|
||||||
|
|
||||||
|
DYLIB_NAME := $(LIB_PREFIX)_b\"
|
||||||
|
DYLIB_CXX_SOURCES := $(LIB_PREFIX)_b_quote.cpp
|
||||||
|
DYLIB_ONLY := YES
|
||||||
|
|
||||||
|
include $(LEVEL)/Makefile.rules
|
|
@ -2076,4 +2076,4 @@ Status NativeProcessLinux::StopProcessorTracingOnThread(lldb::user_id_t traceid,
|
||||||
m_processor_trace_monitor.erase(iter);
|
m_processor_trace_monitor.erase(iter);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
|
@ -9,12 +9,12 @@
|
||||||
#ifndef liblldb_NativeProcessNetBSD_H_
|
#ifndef liblldb_NativeProcessNetBSD_H_
|
||||||
#define liblldb_NativeProcessNetBSD_H_
|
#define liblldb_NativeProcessNetBSD_H_
|
||||||
|
|
||||||
|
#include "Plugins/Process/POSIX/NativeProcessELF.h"
|
||||||
#include "lldb/Target/MemoryRegionInfo.h"
|
#include "lldb/Target/MemoryRegionInfo.h"
|
||||||
#include "lldb/Utility/ArchSpec.h"
|
#include "lldb/Utility/ArchSpec.h"
|
||||||
#include "lldb/Utility/FileSpec.h"
|
#include "lldb/Utility/FileSpec.h"
|
||||||
|
|
||||||
#include "NativeThreadNetBSD.h"
|
#include "NativeThreadNetBSD.h"
|
||||||
#include "lldb/Host/common/NativeProcessProtocol.h"
|
|
||||||
|
|
||||||
namespace lldb_private {
|
namespace lldb_private {
|
||||||
namespace process_netbsd {
|
namespace process_netbsd {
|
||||||
|
@ -25,7 +25,7 @@ namespace process_netbsd {
|
||||||
/// for debugging.
|
/// for debugging.
|
||||||
///
|
///
|
||||||
/// Changes in the inferior process state are broadcasted.
|
/// Changes in the inferior process state are broadcasted.
|
||||||
class NativeProcessNetBSD : public NativeProcessProtocol {
|
class NativeProcessNetBSD : public NativeProcessELF {
|
||||||
public:
|
public:
|
||||||
class Factory : public NativeProcessProtocol::Factory {
|
class Factory : public NativeProcessProtocol::Factory {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -107,4 +107,73 @@ lldb::addr_t NativeProcessELF::GetELFImageInfoAddress() {
|
||||||
return LLDB_INVALID_ADDRESS;
|
return LLDB_INVALID_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
llvm::Expected<SVR4LibraryInfo>
|
||||||
|
NativeProcessELF::ReadSVR4LibraryInfo(lldb::addr_t link_map_addr) {
|
||||||
|
ELFLinkMap<T> link_map;
|
||||||
|
size_t bytes_read;
|
||||||
|
auto error =
|
||||||
|
ReadMemory(link_map_addr, &link_map, sizeof(link_map), bytes_read);
|
||||||
|
if (!error.Success())
|
||||||
|
return error.ToError();
|
||||||
|
|
||||||
|
char name_buffer[PATH_MAX];
|
||||||
|
error = ReadMemory(link_map.l_name, &name_buffer, sizeof(name_buffer),
|
||||||
|
bytes_read);
|
||||||
|
if (!error.Success())
|
||||||
|
return error.ToError();
|
||||||
|
name_buffer[PATH_MAX - 1] = '\0';
|
||||||
|
|
||||||
|
SVR4LibraryInfo info;
|
||||||
|
info.name = std::string(name_buffer);
|
||||||
|
info.link_map = link_map_addr;
|
||||||
|
info.base_addr = link_map.l_addr;
|
||||||
|
info.ld_addr = link_map.l_ld;
|
||||||
|
info.next = link_map.l_next;
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Expected<std::vector<SVR4LibraryInfo>>
|
||||||
|
NativeProcessELF::GetLoadedSVR4Libraries() {
|
||||||
|
// Address of DT_DEBUG.d_ptr which points to r_debug
|
||||||
|
lldb::addr_t info_address = GetSharedLibraryInfoAddress();
|
||||||
|
if (info_address == LLDB_INVALID_ADDRESS)
|
||||||
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
||||||
|
"Invalid shared library info address");
|
||||||
|
// Address of r_debug
|
||||||
|
lldb::addr_t address = 0;
|
||||||
|
size_t bytes_read;
|
||||||
|
auto status =
|
||||||
|
ReadMemory(info_address, &address, GetAddressByteSize(), bytes_read);
|
||||||
|
if (!status.Success())
|
||||||
|
return status.ToError();
|
||||||
|
if (address == 0)
|
||||||
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
||||||
|
"Invalid r_debug address");
|
||||||
|
// Read r_debug.r_map
|
||||||
|
lldb::addr_t link_map = 0;
|
||||||
|
status = ReadMemory(address + GetAddressByteSize(), &link_map,
|
||||||
|
GetAddressByteSize(), bytes_read);
|
||||||
|
if (!status.Success())
|
||||||
|
return status.ToError();
|
||||||
|
if (address == 0)
|
||||||
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
||||||
|
"Invalid link_map address");
|
||||||
|
|
||||||
|
std::vector<SVR4LibraryInfo> library_list;
|
||||||
|
while (link_map) {
|
||||||
|
llvm::Expected<SVR4LibraryInfo> info =
|
||||||
|
GetAddressByteSize() == 8 ? ReadSVR4LibraryInfo<uint64_t>(link_map)
|
||||||
|
: ReadSVR4LibraryInfo<uint32_t>(link_map);
|
||||||
|
if (!info)
|
||||||
|
return info.takeError();
|
||||||
|
if (!info->name.empty() && info->base_addr != 0)
|
||||||
|
library_list.push_back(*info);
|
||||||
|
link_map = info->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return library_list;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace lldb_private
|
} // namespace lldb_private
|
|
@ -37,6 +37,13 @@ protected:
|
||||||
template <typename ELF_EHDR, typename ELF_PHDR, typename ELF_DYN>
|
template <typename ELF_EHDR, typename ELF_PHDR, typename ELF_DYN>
|
||||||
lldb::addr_t GetELFImageInfoAddress();
|
lldb::addr_t GetELFImageInfoAddress();
|
||||||
|
|
||||||
|
llvm::Expected<std::vector<SVR4LibraryInfo>>
|
||||||
|
GetLoadedSVR4Libraries() override;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
llvm::Expected<SVR4LibraryInfo>
|
||||||
|
ReadSVR4LibraryInfo(lldb::addr_t link_map_addr);
|
||||||
|
|
||||||
std::unique_ptr<AuxVector> m_aux_vector;
|
std::unique_ptr<AuxVector> m_aux_vector;
|
||||||
llvm::Optional<lldb::addr_t> m_shared_library_info_addr;
|
llvm::Optional<lldb::addr_t> m_shared_library_info_addr;
|
||||||
};
|
};
|
||||||
|
|
|
@ -825,6 +825,7 @@ GDBRemoteCommunicationServerCommon::Handle_qSupported(
|
||||||
#if defined(__linux__) || defined(__NetBSD__)
|
#if defined(__linux__) || defined(__NetBSD__)
|
||||||
response.PutCString(";QPassSignals+");
|
response.PutCString(";QPassSignals+");
|
||||||
response.PutCString(";qXfer:auxv:read+");
|
response.PutCString(";qXfer:auxv:read+");
|
||||||
|
response.PutCString(";qXfer:libraries-svr4:read+");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return SendPacketNoLock(response.GetString());
|
return SendPacketNoLock(response.GetString());
|
||||||
|
|
|
@ -2765,6 +2765,24 @@ GDBRemoteCommunicationServerLLGS::ReadXferObject(llvm::StringRef object,
|
||||||
return std::move(*buffer_or_error);
|
return std::move(*buffer_or_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (object == "libraries-svr4") {
|
||||||
|
auto library_list = m_debugged_process_up->GetLoadedSVR4Libraries();
|
||||||
|
if (!library_list)
|
||||||
|
return library_list.takeError();
|
||||||
|
|
||||||
|
StreamString response;
|
||||||
|
response.Printf("<library-list-svr4 version=\"1.0\">");
|
||||||
|
for (auto const &library : *library_list) {
|
||||||
|
response.Printf("<library name=\"%s\" ",
|
||||||
|
XMLEncodeAttributeValue(library.name.c_str()).c_str());
|
||||||
|
response.Printf("lm=\"0x%" PRIx64 "\" ", library.link_map);
|
||||||
|
response.Printf("l_addr=\"0x%" PRIx64 "\" ", library.base_addr);
|
||||||
|
response.Printf("l_ld=\"0x%" PRIx64 "\" />", library.ld_addr);
|
||||||
|
}
|
||||||
|
response.Printf("</library-list-svr4>");
|
||||||
|
return MemoryBuffer::getMemBufferCopy(response.GetString(), __FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
return llvm::make_error<PacketUnimplementedError>(
|
return llvm::make_error<PacketUnimplementedError>(
|
||||||
"Xfer object not supported");
|
"Xfer object not supported");
|
||||||
}
|
}
|
||||||
|
@ -3283,3 +3301,28 @@ GDBRemoteCommunicationServerLLGS::FindModuleFile(const std::string &module_path,
|
||||||
|
|
||||||
return GDBRemoteCommunicationServerCommon::FindModuleFile(module_path, arch);
|
return GDBRemoteCommunicationServerCommon::FindModuleFile(module_path, arch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GDBRemoteCommunicationServerLLGS::XMLEncodeAttributeValue(
|
||||||
|
llvm::StringRef value) {
|
||||||
|
std::string result;
|
||||||
|
for (const char &c : value) {
|
||||||
|
switch (c) {
|
||||||
|
case '\'':
|
||||||
|
result += "'";
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
result += """;
|
||||||
|
break;
|
||||||
|
case '<':
|
||||||
|
result += "<";
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
result += ">";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result += c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
|
@ -196,6 +196,8 @@ protected:
|
||||||
llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
|
llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
|
||||||
ReadXferObject(llvm::StringRef object, llvm::StringRef annex);
|
ReadXferObject(llvm::StringRef object, llvm::StringRef annex);
|
||||||
|
|
||||||
|
static std::string XMLEncodeAttributeValue(llvm::StringRef value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void HandleInferiorState_Exited(NativeProcessProtocol *process);
|
void HandleInferiorState_Exited(NativeProcessProtocol *process);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue