Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions lldb/test/API/tools/lldb-dap/disassemble/TestDAP_disassemble.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,25 @@ def test_disassemble_backwards(self):
# clear breakpoints
self.set_source_breakpoints(source, [])
self.continue_to_exit()

def test_disassemble_empty_memory_reference(self):
"""
Tests the 'disassemble' request with empty memory reference.
"""
program = self.getBuildArtifact("a.out")
self.build_and_launch(program)
source = "main.c"
bp_line_no = line_number(source, "// breakpoint 1")
self.set_source_breakpoints(source, [bp_line_no])
self.continue_to_next_stop()

instructions = self.dap_server.request_disassemble(
memoryReference="", instructionOffset=0, instructionCount=50
)
self.assertEqual(len(instructions), 50)
for instruction in instructions:
self.assertEqual(instruction["presentationHint"], "invalid")

# clear breakpoints
self.set_source_breakpoints(source, [])
self.continue_to_exit()
5 changes: 5 additions & 0 deletions lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,11 @@ static DisassembledInstruction ConvertSBInstructionToDisassembledInstruction(
/// `supportsDisassembleRequest` is true.
llvm::Expected<DisassembleResponseBody>
DisassembleRequestHandler::Run(const DisassembleArguments &args) const {
if (args.memoryReference == LLDB_INVALID_ADDRESS) {
std::vector<DisassembledInstruction> invalid_instructions(
args.instructionCount, GetInvalidInstruction());
return DisassembleResponseBody{std::move(invalid_instructions)};
}
const lldb::addr_t addr_ptr = args.memoryReference + args.offset;
lldb::SBAddress addr(addr_ptr, dap.target);
if (!addr.IsValid())
Expand Down
7 changes: 6 additions & 1 deletion lldb/tools/lldb-dap/JSONUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ DecodeMemoryReference(llvm::StringRef memoryReference) {

bool DecodeMemoryReference(const llvm::json::Value &v, llvm::StringLiteral key,
lldb::addr_t &out, llvm::json::Path path,
bool required) {
bool required, bool allow_empty) {
const llvm::json::Object *v_obj = v.getAsObject();
if (!v_obj) {
path.report("expected object");
Expand All @@ -145,6 +145,11 @@ bool DecodeMemoryReference(const llvm::json::Value &v, llvm::StringLiteral key,
return false;
}

if (allow_empty && mem_ref_str->empty()) {
out = LLDB_INVALID_ADDRESS;
return true;
}

const std::optional<lldb::addr_t> addr_opt =
DecodeMemoryReference(*mem_ref_str);
if (!addr_opt) {
Expand Down
6 changes: 5 additions & 1 deletion lldb/tools/lldb-dap/JSONUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,15 @@ DecodeMemoryReference(llvm::StringRef memoryReference);
/// Indicates if the key is required to be present, otherwise report an error
/// if the key is missing.
///
/// \param[in] allow_empty
/// Interpret empty string as a valid value, don't report an error (see
/// VSCode issue https://github.com/microsoft/vscode/issues/270593).
///
/// \return
/// Returns \b true if the address was decoded successfully.
bool DecodeMemoryReference(const llvm::json::Value &v, llvm::StringLiteral key,
lldb::addr_t &out, llvm::json::Path path,
bool required);
bool required, bool allow_empty = false);

/// Extract an array of strings for the specified key from an object.
///
Expand Down
2 changes: 1 addition & 1 deletion lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ bool fromJSON(const llvm::json::Value &Params, DisassembleArguments &DA,
json::ObjectMapper O(Params, P);
return O &&
DecodeMemoryReference(Params, "memoryReference", DA.memoryReference, P,
/*required=*/true) &&
/*required=*/true, /*allow_empty*/ true) &&
O.mapOptional("offset", DA.offset) &&
O.mapOptional("instructionOffset", DA.instructionOffset) &&
O.map("instructionCount", DA.instructionCount) &&
Expand Down
Loading