diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index a324af57b61df..75731ebfde672 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -674,11 +674,11 @@ def request_disconnect(self, terminateDebuggee=None): return self.send_recv(command_dict) def request_disassemble( - self, memoryReference, offset=-50, instructionCount=200, resolveSymbols=True + self, memoryReference, instructionOffset=0, instructionCount=10, resolveSymbols=True ): args_dict = { "memoryReference": memoryReference, - "offset": offset, + "instructionOffset": instructionOffset, "instructionCount": instructionCount, "resolveSymbols": resolveSymbols, } diff --git a/lldb/test/API/tools/lldb-dap/disassemble/TestDAP_disassemble.py b/lldb/test/API/tools/lldb-dap/disassemble/TestDAP_disassemble.py index 9e8ef5b289f2e..ab72eb2d13d72 100644 --- a/lldb/test/API/tools/lldb-dap/disassemble/TestDAP_disassemble.py +++ b/lldb/test/API/tools/lldb-dap/disassemble/TestDAP_disassemble.py @@ -29,6 +29,14 @@ def test_disassemble(self): ) self.continue_to_next_stop() + stackFrames = self.get_stackFrames( + threadId=threadId, startFrame=frameIndex, levels=1 + ) + self.assertIsNotNone(stackFrames) + + # XXX finish updating test case + memoryReference = stackFrames[0]["instructionPointerReference"] + pc_assembly = self.disassemble(frameIndex=0) self.assertIn("location", pc_assembly, "Source location missing.") self.assertIn("instruction", pc_assembly, "Assembly instruction missing.") diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp index ea84f31aec3a6..5d9d28b59ea80 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -3910,8 +3910,8 @@ void request_disassemble(const llvm::json::Object &request) { return; } - addr_ptr += GetSigned(arguments, "instructionOffset", 0); - lldb::SBAddress addr(addr_ptr, g_dap.target); + addr_ptr += GetSigned(arguments, "offset", 0); + lldb::SBAddress addr = g_dap.target.ResolveLoadAddress(addr_ptr); if (!addr.IsValid()) { response["success"] = false; response["message"] = "Memory reference not found in the current binary."; @@ -3919,9 +3919,27 @@ void request_disassemble(const llvm::json::Object &request) { return; } - const auto inst_count = GetUnsigned(arguments, "instructionCount", 0); - lldb::SBInstructionList insts = - g_dap.target.ReadInstructions(addr, inst_count); + int64_t inst_offset = GetSigned(arguments, "instructionOffset", 0); + const int64_t inst_count = GetSigned(arguments, "instructionCount", 0); + if (inst_count < 0) { + response["success"] = false; + response["message"] = "Negative instruction count."; + g_dap.SendJSON(llvm::json::Value(std::move(response))); + return; + } + + lldb::SBInstructionList insts; + if (lldb::SBFunction func = addr.GetFunction()) { + // First try to identify the function boundaries through debug information + insts = func.GetInstructions(g_dap.target); + } else if (lldb::SBSymbol sym = addr.GetSymbol()) { + // Try to identify the function boundaries through the symbol table + insts = sym.GetInstructions(g_dap.target); + } else { + // We could not identify the function. Just disassemble starting from the + // provided address. + insts = g_dap.target.ReadInstructions(addr, inst_offset + inst_count); + } if (!insts.IsValid()) { response["success"] = false; @@ -3930,10 +3948,46 @@ void request_disassemble(const llvm::json::Object &request) { return; } + // Find the start offset in the disassembled function + ssize_t offset = 0; + while (insts.GetInstructionAtIndex(offset).GetAddress().GetLoadAddress( + g_dap.target) < addr.GetLoadAddress(g_dap.target)) + ++offset; + offset += inst_offset; + + // Format the disassembled instructions const bool resolveSymbols = GetBoolean(arguments, "resolveSymbols", false); llvm::json::Array instructions; - const auto num_insts = insts.GetSize(); - for (size_t i = 0; i < num_insts; ++i) { + for (ssize_t i = offset; i < inst_count + offset; ++i) { + // Before the range of disassembled instructions? + if (i < 0) { + auto fake_addr = + insts.GetInstructionAtIndex(0).GetAddress().GetLoadAddress( + g_dap.target) - + offset + i; + llvm::json::Object disassembled_inst{ + {"address", "0x" + llvm::utohexstr(fake_addr)}, + {"instruction", "Instruction before disassembled address range"}, + {"presentationHint", "invalid"}, + }; + instructions.emplace_back(std::move(disassembled_inst)); + continue; + } + // Past the range of disassembled instructions? + if (static_cast(i) >= insts.GetSize()) { + auto fake_addr = insts.GetInstructionAtIndex(insts.GetSize() - 1) + .GetAddress() + .GetLoadAddress(g_dap.target) - + offset + i - insts.GetSize(); + llvm::json::Object disassembled_inst{ + {"address", "0x" + llvm::utohexstr(fake_addr)}, + {"instruction", "Instruction after disassembled address range"}, + {"presentationHint", "invalid"}, + }; + instructions.emplace_back(std::move(disassembled_inst)); + continue; + } + lldb::SBInstruction inst = insts.GetInstructionAtIndex(i); auto addr = inst.GetAddress(); const auto inst_addr = addr.GetLoadAddress(g_dap.target);