Index: lldb/packages/Python/lldbsuite/test/tools/lldb-server/registers-target-xml-reading/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/tools/lldb-server/registers-target-xml-reading/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules Index: lldb/packages/Python/lldbsuite/test/tools/lldb-server/registers-target-xml-reading/TestGdbRemoteTargetXmlPacket.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/tools/lldb-server/registers-target-xml-reading/TestGdbRemoteTargetXmlPacket.py @@ -0,0 +1,69 @@ + + +import gdbremote_testcase +import textwrap +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +import re +import xml.etree.ElementTree as ET + +class TestGdbRemoteTargetXmlPacket(gdbremote_testcase.GdbRemoteTestCaseBase): + + mydir = TestBase.compute_mydir(__file__) + + @expectedFailureNetBSD + @llgs_test + def test_g_target_xml_returns_correct_data(self): + self.init_llgs_test() + self.build() + self.set_inferior_startup_launch() + + procs = self.prep_debug_monitor_and_inferior() + + OFFSET = 0 + LENGTH = 0x1ffff0 + self.test_sequence.add_log_lines([ + "read packet: $qXfer:features:read:target.xml:{:x},{:x}#00".format( + OFFSET, + LENGTH), + { + "direction": "send", + "regex": re.compile("^\$l(.+)#[0-9a-fA-F]{2}$"), + "capture": {1: "target_xml"} + }], + True) + context = self.expect_gdbremote_sequence() + + target_xml = context.get("target_xml") + + root = ET.fromstring(target_xml) + self.assertIsNotNone(root) + self.assertEqual(root.tag, "target") + + architecture = root.find("architecture") + self.assertIsNotNone(architecture) + self.assertEqual(architecture.text, self.getArchitecture()) + + feature = root.find("feature") + self.assertIsNotNone(feature) + + target_xml_registers = feature.findall("reg") + self.assertTrue(len(target_xml_registers) > 0) + + # registers info collected by qRegisterInfo + self.add_register_info_collection_packets() + context = self.expect_gdbremote_sequence() + self.assertIsNotNone(context) + q_info_registers = self.parse_register_info_packets(context) + + self.assertTrue(len(target_xml_registers) == len(q_info_registers)) + for register in zip(target_xml_registers, q_info_registers): + xml_info_reg = register[0] + q_info_reg = register[1] + self.assertEqual(q_info_reg["name"], xml_info_reg.get("name")) + self.assertEqual(q_info_reg["set"], xml_info_reg.get("group")) + self.assertEqual(q_info_reg["format"], xml_info_reg.get("format")) + self.assertEqual(q_info_reg["bitsize"], xml_info_reg.get("bitsize")) + self.assertEqual(q_info_reg["offset"], xml_info_reg.get("offset")) + self.assertEqual(q_info_reg["encoding"], xml_info_reg.get("encoding")) \ No newline at end of file Index: lldb/packages/Python/lldbsuite/test/tools/lldb-server/registers-target-xml-reading/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/tools/lldb-server/registers-target-xml-reading/main.cpp @@ -0,0 +1 @@ +int main() {} Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -843,6 +843,7 @@ response.PutCString(";QThreadSuffixSupported+"); response.PutCString(";QListThreadsInStopReply+"); response.PutCString(";qEcho+"); + response.PutCString(";qXfer:features:read+"); #if defined(__linux__) || defined(__NetBSD__) response.PutCString(";QPassSignals+"); response.PutCString(";qXfer:auxv:read+"); Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -199,6 +199,8 @@ static std::string XMLEncodeAttributeValue(llvm::StringRef value); private: + llvm::Expected> BuildTargetXml(); + void HandleInferiorState_Exited(NativeProcessProtocol *process); void HandleInferiorState_Stopped(NativeProcessProtocol *process); Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -377,6 +377,99 @@ } } +static llvm::StringRef GetEncodingNameOrEmpty(const RegisterInfo ®_info) { + switch (reg_info.encoding) { + case eEncodingUint: + return "uint"; + case eEncodingSint: + return "sint"; + case eEncodingIEEE754: + return "ieee754"; + case eEncodingVector: + return "vector"; + default: + return ""; + } +} + +static llvm::StringRef GetFormatNameOrEmpty(const RegisterInfo ®_info) { + switch (reg_info.format) { + case eFormatBinary: + return "binary"; + case eFormatDecimal: + return "decimal"; + case eFormatHex: + return "hex"; + case eFormatFloat: + return "float"; + case eFormatVectorOfSInt8: + return "vector-sint8"; + case eFormatVectorOfUInt8: + return "vector-uint8"; + case eFormatVectorOfSInt16: + return "vector-sint16"; + case eFormatVectorOfUInt16: + return "vector-uint16"; + case eFormatVectorOfSInt32: + return "vector-sint32"; + case eFormatVectorOfUInt32: + return "vector-uint32"; + case eFormatVectorOfFloat32: + return "vector-float32"; + case eFormatVectorOfUInt64: + return "vector-uint64"; + case eFormatVectorOfUInt128: + return "vector-uint128"; + default: + return ""; + }; +} + +static llvm::StringRef GetKindGenericOrEmpty(const RegisterInfo ®_info) { + switch (reg_info.kinds[RegisterKind::eRegisterKindGeneric]) { + case LLDB_REGNUM_GENERIC_PC: + return "pc"; + case LLDB_REGNUM_GENERIC_SP: + return "sp"; + case LLDB_REGNUM_GENERIC_FP: + return "fp"; + case LLDB_REGNUM_GENERIC_RA: + return "ra"; + case LLDB_REGNUM_GENERIC_FLAGS: + return "flags"; + case LLDB_REGNUM_GENERIC_ARG1: + return "arg1"; + case LLDB_REGNUM_GENERIC_ARG2: + return "arg2"; + case LLDB_REGNUM_GENERIC_ARG3: + return "arg3"; + case LLDB_REGNUM_GENERIC_ARG4: + return "arg4"; + case LLDB_REGNUM_GENERIC_ARG5: + return "arg5"; + case LLDB_REGNUM_GENERIC_ARG6: + return "arg6"; + case LLDB_REGNUM_GENERIC_ARG7: + return "arg7"; + case LLDB_REGNUM_GENERIC_ARG8: + return "arg8"; + default: + return ""; + } +} + +static void CollectRegNums(const uint32_t *reg_num, StreamString &response, + bool usehex) { + for (int i = 0; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) { + if (i > 0) + response.PutChar(','); + if (usehex) + response.Printf("%" PRIx32, *reg_num); + else + response.Printf("%" PRIu32, *reg_num); + } +} + static void WriteRegisterValueInHexFixedWidth( StreamString &response, NativeRegisterContext ®_ctx, const RegisterInfo ®_info, const RegisterValue *reg_value_p, @@ -1699,74 +1792,18 @@ response.Printf("bitsize:%" PRIu32 ";offset:%" PRIu32 ";", reg_info->byte_size * 8, reg_info->byte_offset); - switch (reg_info->encoding) { - case eEncodingUint: - response.PutCString("encoding:uint;"); - break; - case eEncodingSint: - response.PutCString("encoding:sint;"); - break; - case eEncodingIEEE754: - response.PutCString("encoding:ieee754;"); - break; - case eEncodingVector: - response.PutCString("encoding:vector;"); - break; - default: - break; - } + llvm::StringRef encoding = GetEncodingNameOrEmpty(*reg_info); + if (!encoding.empty()) + response << "encoding:" << encoding << ';'; - switch (reg_info->format) { - case eFormatBinary: - response.PutCString("format:binary;"); - break; - case eFormatDecimal: - response.PutCString("format:decimal;"); - break; - case eFormatHex: - response.PutCString("format:hex;"); - break; - case eFormatFloat: - response.PutCString("format:float;"); - break; - case eFormatVectorOfSInt8: - response.PutCString("format:vector-sint8;"); - break; - case eFormatVectorOfUInt8: - response.PutCString("format:vector-uint8;"); - break; - case eFormatVectorOfSInt16: - response.PutCString("format:vector-sint16;"); - break; - case eFormatVectorOfUInt16: - response.PutCString("format:vector-uint16;"); - break; - case eFormatVectorOfSInt32: - response.PutCString("format:vector-sint32;"); - break; - case eFormatVectorOfUInt32: - response.PutCString("format:vector-uint32;"); - break; - case eFormatVectorOfFloat32: - response.PutCString("format:vector-float32;"); - break; - case eFormatVectorOfUInt64: - response.PutCString("format:vector-uint64;"); - break; - case eFormatVectorOfUInt128: - response.PutCString("format:vector-uint128;"); - break; - default: - break; - }; + llvm::StringRef format = GetFormatNameOrEmpty(*reg_info); + if (!format.empty()) + response << "format:" << format << ';'; const char *const register_set_name = reg_context.GetRegisterSetNameForRegisterAtIndex(reg_index); - if (register_set_name) { - response.PutCString("set:"); - response.PutCString(register_set_name); - response.PutChar(';'); - } + if (register_set_name) + response << "set:" << register_set_name << ';'; if (reg_info->kinds[RegisterKind::eRegisterKindEHFrame] != LLDB_INVALID_REGNUM) @@ -1777,71 +1814,19 @@ response.Printf("dwarf:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindDWARF]); - switch (reg_info->kinds[RegisterKind::eRegisterKindGeneric]) { - case LLDB_REGNUM_GENERIC_PC: - response.PutCString("generic:pc;"); - break; - case LLDB_REGNUM_GENERIC_SP: - response.PutCString("generic:sp;"); - break; - case LLDB_REGNUM_GENERIC_FP: - response.PutCString("generic:fp;"); - break; - case LLDB_REGNUM_GENERIC_RA: - response.PutCString("generic:ra;"); - break; - case LLDB_REGNUM_GENERIC_FLAGS: - response.PutCString("generic:flags;"); - break; - case LLDB_REGNUM_GENERIC_ARG1: - response.PutCString("generic:arg1;"); - break; - case LLDB_REGNUM_GENERIC_ARG2: - response.PutCString("generic:arg2;"); - break; - case LLDB_REGNUM_GENERIC_ARG3: - response.PutCString("generic:arg3;"); - break; - case LLDB_REGNUM_GENERIC_ARG4: - response.PutCString("generic:arg4;"); - break; - case LLDB_REGNUM_GENERIC_ARG5: - response.PutCString("generic:arg5;"); - break; - case LLDB_REGNUM_GENERIC_ARG6: - response.PutCString("generic:arg6;"); - break; - case LLDB_REGNUM_GENERIC_ARG7: - response.PutCString("generic:arg7;"); - break; - case LLDB_REGNUM_GENERIC_ARG8: - response.PutCString("generic:arg8;"); - break; - default: - break; - } + llvm::StringRef kind_generic = GetKindGenericOrEmpty(*reg_info); + if (!kind_generic.empty()) + response << "generic:" << kind_generic << ';'; if (reg_info->value_regs && reg_info->value_regs[0] != LLDB_INVALID_REGNUM) { response.PutCString("container-regs:"); - int i = 0; - for (const uint32_t *reg_num = reg_info->value_regs; - *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) { - if (i > 0) - response.PutChar(','); - response.Printf("%" PRIx32, *reg_num); - } + CollectRegNums(reg_info->value_regs, response, true); response.PutChar(';'); } if (reg_info->invalidate_regs && reg_info->invalidate_regs[0]) { response.PutCString("invalidate-regs:"); - int i = 0; - for (const uint32_t *reg_num = reg_info->invalidate_regs; - *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) { - if (i > 0) - response.PutChar(','); - response.Printf("%" PRIx32, *reg_num); - } + CollectRegNums(reg_info->invalidate_regs, response, true); response.PutChar(';'); } @@ -2750,17 +2735,119 @@ return PacketResult::Success; } +llvm::Expected> +GDBRemoteCommunicationServerLLGS::BuildTargetXml() { + // Ensure we have a thread. + NativeThreadProtocol *thread = m_debugged_process_up->GetThreadAtIndex(0); + if (!thread) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "No thread available"); + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + // Get the register context for the first thread. + NativeRegisterContext ®_context = thread->GetRegisterContext(); + + StreamString response; + + response.Printf(""); + response.Printf(""); + + response.Printf("%s", + m_debugged_process_up->GetArchitecture() + .GetTriple() + .getArchName() + .str() + .c_str()); + + response.Printf(""); + + const int registers_count = reg_context.GetUserRegisterCount(); + for (int reg_index = 0; reg_index < registers_count; reg_index++) { + const RegisterInfo *reg_info = + reg_context.GetRegisterInfoAtIndex(reg_index); + + if (!reg_info) { + LLDB_LOGF(log, + "%s failed to get register info for register index %" PRIu32, + "target.xml", reg_index); + continue; + } + + response.Printf("name, reg_info->byte_size * 8, + reg_info->byte_offset, reg_index); + + if (reg_info->alt_name && reg_info->alt_name[0]) + response.Printf("altname=\"%s\" ", reg_info->alt_name); + + llvm::StringRef encoding = GetEncodingNameOrEmpty(*reg_info); + if (!encoding.empty()) + response << "encoding=\"" << encoding << "\" "; + + llvm::StringRef format = GetFormatNameOrEmpty(*reg_info); + if (!format.empty()) + response << "format=\"" << format << "\" "; + + const char *const register_set_name = + reg_context.GetRegisterSetNameForRegisterAtIndex(reg_index); + if (register_set_name) + response << "group=\"" << register_set_name << "\" "; + + if (reg_info->kinds[RegisterKind::eRegisterKindEHFrame] != + LLDB_INVALID_REGNUM) + response.Printf("ehframe_regnum=\"%" PRIu32 "\" ", + reg_info->kinds[RegisterKind::eRegisterKindEHFrame]); + + if (reg_info->kinds[RegisterKind::eRegisterKindDWARF] != + LLDB_INVALID_REGNUM) + response.Printf("dwarf_regnum=\"%" PRIu32 "\" ", + reg_info->kinds[RegisterKind::eRegisterKindDWARF]); + + llvm::StringRef kind_generic = GetKindGenericOrEmpty(*reg_info); + if (!kind_generic.empty()) + response << "generic=\"" << kind_generic << "\" "; + + if (reg_info->value_regs && + reg_info->value_regs[0] != LLDB_INVALID_REGNUM) { + response.PutCString("value_regnums=\""); + CollectRegNums(reg_info->value_regs, response, false); + response.Printf("\" "); + } + + if (reg_info->invalidate_regs && reg_info->invalidate_regs[0]) { + response.PutCString("invalidate_regnums=\""); + CollectRegNums(reg_info->invalidate_regs, response, false); + response.Printf("\" "); + } + + if (reg_info->dynamic_size_dwarf_expr_bytes) { + const size_t dwarf_opcode_len = reg_info->dynamic_size_dwarf_len; + response.PutCString("dynamic_size_dwarf_expr_bytes=\""); + for (uint32_t i = 0; i < dwarf_opcode_len; ++i) + response.PutHex8(reg_info->dynamic_size_dwarf_expr_bytes[i]); + response.Printf("\" "); + } + + response.Printf("/>"); + } + + response.Printf(""); + response.Printf(""); + return MemoryBuffer::getMemBufferCopy(response.GetString(), "target.xml"); +} + llvm::Expected> GDBRemoteCommunicationServerLLGS::ReadXferObject(llvm::StringRef object, llvm::StringRef annex) { - if (object == "auxv") { - // Make sure we have a valid process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "No process available"); - } + // Make sure we have a valid process. + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "No process available"); + } + if (object == "auxv") { // Grab the auxv data. auto buffer_or_error = m_debugged_process_up->GetAuxvData(); if (!buffer_or_error) @@ -2786,6 +2873,9 @@ return MemoryBuffer::getMemBufferCopy(response.GetString(), __FUNCTION__); } + if (object == "features" && annex == "target.xml") + return BuildTargetXml(); + return llvm::make_error( "Xfer object not supported"); }