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,54 @@ +#include + +int main() { +#if defined(__x86_64__) + struct alignas(16) xmm_t { + uint64_t a, b; + }; + uint64_t r8 = 0x0102030405060708; + uint64_t r9 = 0x1112131415161718; + uint64_t r10 = 0x2122232425262728; + uint64_t r11 = 0x3132333435363738; + uint64_t r12 = 0x4142434445464748; + uint64_t r13 = 0x5152535455565758; + uint64_t r14 = 0x6162636465666768; + uint64_t r15 = 0x7172737475767778; + + xmm_t xmm8 = {0x020406080A0C0E01, 0x030507090B0D0F00}; + xmm_t xmm9 = {0x121416181A1C1E11, 0x131517191B1D1F10}; + xmm_t xmm10 = {0x222426282A2C2E21, 0x232527292B2D2F20}; + xmm_t xmm11 = {0x323436383A3C3E31, 0x333537393B3D3F30}; + xmm_t xmm12 = {0x424446484A4C4E41, 0x434547494B4D4F40}; + xmm_t xmm13 = {0x525456585A5C5E51, 0x535557595B5D5F50}; + xmm_t xmm14 = {0x626466686A6C6E61, 0x636567696B6D6F60}; + xmm_t xmm15 = {0x727476787A7C7E71, 0x737577797B7D7F70}; + + asm volatile("movq %0, %%r8\n\t" + "movq %1, %%r9\n\t" + "movq %2, %%r10\n\t" + "movq %3, %%r11\n\t" + "movq %4, %%r12\n\t" + "movq %5, %%r13\n\t" + "movq %6, %%r14\n\t" + "movq %7, %%r15\n\t" + "\n\t" + "movaps %8, %%xmm8\n\t" + "movaps %9, %%xmm9\n\t" + "movaps %10, %%xmm10\n\t" + "movaps %11, %%xmm11\n\t" + "movaps %12, %%xmm12\n\t" + "movaps %13, %%xmm13\n\t" + "movaps %14, %%xmm14\n\t" + "movaps %15, %%xmm15\n\t" + "\n\t" + "int3" + : + : "g"(r8), "g"(r9), "g"(r10), "g"(r11), "g"(r12), "g"(r13), + "g"(r14), "g"(r15), "m"(xmm8), "m"(xmm9), "m"(xmm10), + "m"(xmm11), "m"(xmm12), "m"(xmm13), "m"(xmm14), "m"(xmm15) + : "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", + "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm12", "%xmm13", + "%xmm14", "%xmm15"); +#endif + return 0; +} 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 @@ -846,6 +846,7 @@ #if defined(__linux__) || defined(__NetBSD__) response.PutCString(";QPassSignals+"); response.PutCString(";qXfer:auxv:read+"); + response.PutCString(";qXfer:features:read+"); response.PutCString(";qXfer:libraries-svr4:read+"); #endif 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,87 @@ } } +static std::string GetEncodingNameOrEmpty(const RegisterInfo *reg_info) { + switch (reg_info->encoding) { + case eEncodingUint: + return "uint"; + case eEncodingSint: + return "sint"; + case eEncodingIEEE754: + return "ieee754"; + case eEncodingVector: + return "vector"; + default: + return ""; + } +} + +static std::string GetFormatNameOrEmpty(const RegisterInfo *reg_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 std::string GetKindGenericOrEmpty(const RegisterInfo *reg_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 WriteRegisterValueInHexFixedWidth( StreamString &response, NativeRegisterContext ®_ctx, const RegisterInfo ®_info, const RegisterValue *reg_value_p, @@ -1699,66 +1780,19 @@ 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; + std::string encoding = GetEncodingNameOrEmpty(reg_info); + if (!encoding.empty()) { + response.PutCString("encoding:"); + response.PutCString(encoding.c_str()); + response.PutChar(';'); } - 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; - }; + std::string format = GetFormatNameOrEmpty(reg_info); + if (!format.empty()) { + response.PutCString("format:"); + response.PutCString(format.c_str()); + response.PutChar(';'); + } const char *const register_set_name = reg_context.GetRegisterSetNameForRegisterAtIndex(reg_index); @@ -1777,48 +1811,11 @@ 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; + std::string kind_generic = GetKindGenericOrEmpty(reg_info); + if (!kind_generic.empty()) { + response.PutCString("generic:"); + response.PutCString(kind_generic.c_str()); + response.PutChar(';'); } if (reg_info->value_regs && reg_info->value_regs[0] != LLDB_INVALID_REGNUM) { @@ -2786,6 +2783,132 @@ return MemoryBuffer::getMemBufferCopy(response.GetString(), __FUNCTION__); } + if (object == "features" && annex == "target.xml") { + // 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"); + } + + // 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); + } + + std::string encoding = GetEncodingNameOrEmpty(reg_info); + if (!encoding.empty()) { + response.Printf("encoding=\"%s\" ", encoding.c_str()); + } + + std::string format = GetFormatNameOrEmpty(reg_info); + if (!format.empty()) { + response.Printf("format=\"%s\" ", format.c_str()); + } + + const char *const register_set_name = + reg_context.GetRegisterSetNameForRegisterAtIndex(reg_index); + if (register_set_name) { + response.Printf("group=\"%s\" ", 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]); + + std::string kind_generic = GetKindGenericOrEmpty(reg_info); + if (!kind_generic.empty()) { + response.Printf("generic=\"%s\" ", kind_generic.c_str()); + } + + if (reg_info->value_regs && + reg_info->value_regs[0] != LLDB_INVALID_REGNUM) { + response.PutCString("value_regnums=\""); + 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); + } + response.Printf("\" "); + } + + if (reg_info->invalidate_regs && reg_info->invalidate_regs[0]) { + response.PutCString("invalidate_regnums=\""); + 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); + } + 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"); + } + return llvm::make_error( "Xfer object not supported"); }