ashgti updated this revision to Diff 544957.
ashgti added a comment.
Herald added a subscriber: JDevlieghere.

Minor fix.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156493/new/

https://reviews.llvm.org/D156493

Files:
  lldb/tools/lldb-vscode/JSONUtils.cpp
  lldb/tools/lldb-vscode/lldb-vscode.cpp

Index: lldb/tools/lldb-vscode/lldb-vscode.cpp
===================================================================
--- lldb/tools/lldb-vscode/lldb-vscode.cpp
+++ lldb/tools/lldb-vscode/lldb-vscode.cpp
@@ -50,6 +50,7 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/ScopeExit.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/Option/Arg.h"
 #include "llvm/Option/ArgList.h"
 #include "llvm/Option/Option.h"
@@ -1563,6 +1564,8 @@
   body.try_emplace("supportsStepInTargetsRequest", false);
   // The debug adapter supports the completions request.
   body.try_emplace("supportsCompletionsRequest", true);
+  // The debug adapter supports the disassembly request.
+  body.try_emplace("supportsDisassembleRequest", true);
 
   llvm::json::Array completion_characters;
   completion_characters.emplace_back(".");
@@ -3290,6 +3293,211 @@
   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
 }
 
+// "DisassembleRequest": {
+//   "allOf": [ { "$ref": "#/definitions/Request" }, {
+//     "type": "object",
+//     "description": "Disassembles code stored at the provided
+//     location.\nClients should only call this request if the corresponding
+//     capability `supportsDisassembleRequest` is true.", "properties": {
+//       "command": {
+//         "type": "string",
+//         "enum": [ "disassemble" ]
+//       },
+//       "arguments": {
+//         "$ref": "#/definitions/DisassembleArguments"
+//       }
+//     },
+//     "required": [ "command", "arguments" ]
+//   }]
+// },
+// "DisassembleArguments": {
+//   "type": "object",
+//   "description": "Arguments for `disassemble` request.",
+//   "properties": {
+//     "memoryReference": {
+//       "type": "string",
+//       "description": "Memory reference to the base location containing the
+//       instructions to disassemble."
+//     },
+//     "offset": {
+//       "type": "integer",
+//       "description": "Offset (in bytes) to be applied to the reference
+//       location before disassembling. Can be negative."
+//     },
+//     "instructionOffset": {
+//       "type": "integer",
+//       "description": "Offset (in instructions) to be applied after the byte
+//       offset (if any) before disassembling. Can be negative."
+//     },
+//     "instructionCount": {
+//       "type": "integer",
+//       "description": "Number of instructions to disassemble starting at the
+//       specified location and offset.\nAn adapter must return exactly this
+//       number of instructions - any unavailable instructions should be
+//       replaced with an implementation-defined 'invalid instruction' value."
+//     },
+//     "resolveSymbols": {
+//       "type": "boolean",
+//       "description": "If true, the adapter should attempt to resolve memory
+//       addresses and other values to symbolic names."
+//     }
+//   },
+//   "required": [ "memoryReference", "instructionCount" ]
+// },
+// "DisassembleResponse": {
+//   "allOf": [ { "$ref": "#/definitions/Response" }, {
+//     "type": "object",
+//     "description": "Response to `disassemble` request.",
+//     "properties": {
+//       "body": {
+//         "type": "object",
+//         "properties": {
+//           "instructions": {
+//             "type": "array",
+//             "items": {
+//               "$ref": "#/definitions/DisassembledInstruction"
+//             },
+//             "description": "The list of disassembled instructions."
+//           }
+//         },
+//         "required": [ "instructions" ]
+//       }
+//     }
+//   }]
+// }
+void request_disassemble(const llvm::json::Object &request) {
+  llvm::json::Object response;
+  FillResponse(request, response);
+  auto arguments = request.getObject("arguments");
+
+  auto memoryReference = GetString(arguments, "memoryReference");
+  lldb::addr_t addr_ptr;
+  if (memoryReference.consumeInteger(0, addr_ptr)) {
+    response["success"] = false;
+    response["message"] =
+        "Malformed memory reference: " + memoryReference.str();
+    g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+    return;
+  }
+
+  addr_ptr += GetSigned(arguments, "instructionOffset", 0);
+  lldb::SBAddress addr(addr_ptr, g_vsc.target);
+  if (!addr.IsValid()) {
+    response["success"] = false;
+    response["message"] = "Memory reference not found in the current binary.";
+    g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+    return;
+  }
+
+  const auto inst_count = GetUnsigned(arguments, "instructionCount", 0);
+  lldb::SBInstructionList insts =
+      g_vsc.target.ReadInstructions(addr, inst_count);
+
+  if (!insts.IsValid()) {
+    response["success"] = false;
+    response["message"] = "Failed to find instructions for memory address.";
+    g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+    return;
+  }
+
+  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) {
+    lldb::SBInstruction inst = insts.GetInstructionAtIndex(i);
+    auto addr = inst.GetAddress();
+    const auto inst_addr = addr.GetLoadAddress(g_vsc.target);
+    const char *m = inst.GetMnemonic(g_vsc.target);
+    const char *o = inst.GetOperands(g_vsc.target);
+    const char *c = inst.GetComment(g_vsc.target);
+    auto d = inst.GetData(g_vsc.target);
+
+    std::string bytes;
+    llvm::raw_string_ostream sb(bytes);
+    for (unsigned i = 0; i < inst.GetByteSize(); i++) {
+      lldb::SBError error;
+      uint8_t b = d.GetUnsignedInt8(error, i);
+      if (error.Success()) {
+        sb << llvm::format("%2.2x ", b);
+      }
+    }
+    sb.flush();
+
+    llvm::json::Object disassembled_inst{
+        {"address", "0x" + llvm::utohexstr(inst_addr)},
+        {"instructionBytes",
+         bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : ""},
+    };
+
+    std::string instruction;
+    llvm::raw_string_ostream si(instruction);
+
+    lldb::SBSymbol symbol = addr.GetSymbol();
+    // Only add the symbol on the first line of the function.
+    if (symbol.IsValid() && symbol.GetStartAddress() == addr) {
+      // If we have a valid symbol, append it as a label prefix for the first
+      // instruction. This is so you can see the start of a function/callsite
+      // in the assembly, at the moment VS Code (1.80) does not visualize the
+      // symbol associated with the assembly instruction.
+      si << (symbol.GetMangledName() != nullptr ? symbol.GetMangledName()
+                                                : symbol.GetName())
+         << ": ";
+
+      if (resolveSymbols) {
+        disassembled_inst.try_emplace("symbol", symbol.GetDisplayName());
+      }
+    }
+
+    si << llvm::formatv("{0,7} {1,12}", m, o);
+    if (c && c[0]) {
+      si << " ; " << c;
+    }
+    si.flush();
+
+    disassembled_inst.try_emplace("instruction", instruction);
+
+    auto line_entry = addr.GetLineEntry();
+    // If the line number is 0 then the entry represents a compiler generated
+    // location.
+    if (line_entry.GetStartAddress() == addr && line_entry.IsValid() &&
+        line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) {
+      auto source = CreateSource(line_entry);
+      disassembled_inst.try_emplace("location", source);
+
+      const auto line = line_entry.GetLine();
+      if (line && line != LLDB_INVALID_LINE_NUMBER) {
+        disassembled_inst.try_emplace("line", line);
+      }
+      const auto column = line_entry.GetColumn();
+      if (column && column != LLDB_INVALID_COLUMN_NUMBER) {
+        disassembled_inst.try_emplace("column", column);
+      }
+
+      auto end_line_entry = line_entry.GetEndAddress().GetLineEntry();
+      if (end_line_entry.IsValid() &&
+          end_line_entry.GetFileSpec() == line_entry.GetFileSpec()) {
+        const auto end_line = end_line_entry.GetLine();
+        if (end_line && end_line != LLDB_INVALID_LINE_NUMBER &&
+            end_line != line) {
+          disassembled_inst.try_emplace("endLine", end_line);
+
+          const auto end_column = end_line_entry.GetColumn();
+          if (end_column && end_column != LLDB_INVALID_COLUMN_NUMBER &&
+              end_column != column) {
+            disassembled_inst.try_emplace("endColumn", end_column - 1);
+          }
+        }
+      }
+    }
+
+    instructions.emplace_back(std::move(disassembled_inst));
+  }
+
+  llvm::json::Object body;
+  body.try_emplace("instructions", std::move(instructions));
+  response.try_emplace("body", std::move(body));
+  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+}
 // A request used in testing to get the details on all breakpoints that are
 // currently set in the target. This helps us to test "setBreakpoints" and
 // "setFunctionBreakpoints" requests to verify we have the correct set of
@@ -3334,6 +3542,7 @@
   g_vsc.RegisterRequestCallback("stepOut", request_stepOut);
   g_vsc.RegisterRequestCallback("threads", request_threads);
   g_vsc.RegisterRequestCallback("variables", request_variables);
+  g_vsc.RegisterRequestCallback("disassemble", request_disassemble);
   // Custom requests
   g_vsc.RegisterRequestCallback("compileUnits", request_compileUnits);
   g_vsc.RegisterRequestCallback("modules", request_modules);
Index: lldb/tools/lldb-vscode/JSONUtils.cpp
===================================================================
--- lldb/tools/lldb-vscode/JSONUtils.cpp
+++ lldb/tools/lldb-vscode/JSONUtils.cpp
@@ -342,6 +342,9 @@
     object.try_emplace("source", CreateSource(*request_path));
 
   if (bp_addr.IsValid()) {
+    std::string formatted_addr =
+        "0x" + llvm::utohexstr(bp_addr.GetLoadAddress(g_vsc.target));
+    object.try_emplace("instructionReference", formatted_addr);
     auto line_entry = bp_addr.GetLineEntry();
     const auto line = line_entry.GetLine();
     if (line != UINT32_MAX)
@@ -600,8 +603,8 @@
     if (name)
       EmplaceSafeString(object, "name", name);
     char path[PATH_MAX] = "";
-    file.GetPath(path, sizeof(path));
-    if (path[0]) {
+    if (file.GetPath(path, sizeof(path)) &&
+        lldb::SBFileSpec::ResolvePath(path, path, PATH_MAX)) {
       EmplaceSafeString(object, "path", std::string(path));
     }
   }
@@ -616,97 +619,14 @@
   return llvm::json::Value(std::move(source));
 }
 
-llvm::json::Value CreateSource(lldb::SBFrame &frame, int64_t &disasm_line) {
-  disasm_line = 0;
+std::optional<llvm::json::Value> CreateSource(lldb::SBFrame &frame) {
   auto line_entry = frame.GetLineEntry();
   // A line entry of 0 indicates the line is compiler generated i.e. no source
-  // file so don't return early with the line entry.
+  // file is associated with the frame.
   if (line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0)
     return CreateSource(line_entry);
 
-  llvm::json::Object object;
-  const auto pc = frame.GetPC();
-
-  lldb::SBInstructionList insts;
-  lldb::SBFunction function = frame.GetFunction();
-  lldb::addr_t low_pc = LLDB_INVALID_ADDRESS;
-  if (function.IsValid()) {
-    low_pc = function.GetStartAddress().GetLoadAddress(g_vsc.target);
-    auto addr_srcref = g_vsc.addr_to_source_ref.find(low_pc);
-    if (addr_srcref != g_vsc.addr_to_source_ref.end()) {
-      // We have this disassembly cached already, return the existing
-      // sourceReference
-      object.try_emplace("sourceReference", addr_srcref->second);
-      disasm_line = g_vsc.GetLineForPC(addr_srcref->second, pc);
-    } else {
-      insts = function.GetInstructions(g_vsc.target);
-    }
-  } else {
-    lldb::SBSymbol symbol = frame.GetSymbol();
-    if (symbol.IsValid()) {
-      low_pc = symbol.GetStartAddress().GetLoadAddress(g_vsc.target);
-      auto addr_srcref = g_vsc.addr_to_source_ref.find(low_pc);
-      if (addr_srcref != g_vsc.addr_to_source_ref.end()) {
-        // We have this disassembly cached already, return the existing
-        // sourceReference
-        object.try_emplace("sourceReference", addr_srcref->second);
-        disasm_line = g_vsc.GetLineForPC(addr_srcref->second, pc);
-      } else {
-        insts = symbol.GetInstructions(g_vsc.target);
-      }
-    }
-  }
-  const auto num_insts = insts.GetSize();
-  if (low_pc != LLDB_INVALID_ADDRESS && num_insts > 0) {
-    if (line_entry.GetLine() == 0) {
-      EmplaceSafeString(object, "name", "<compiler-generated>");
-    } else {
-      EmplaceSafeString(object, "name", frame.GetDisplayFunctionName());
-    }
-    SourceReference source;
-    llvm::raw_string_ostream src_strm(source.content);
-    std::string line;
-    for (size_t i = 0; i < num_insts; ++i) {
-      lldb::SBInstruction inst = insts.GetInstructionAtIndex(i);
-      const auto inst_addr = inst.GetAddress().GetLoadAddress(g_vsc.target);
-      const char *m = inst.GetMnemonic(g_vsc.target);
-      const char *o = inst.GetOperands(g_vsc.target);
-      const char *c = inst.GetComment(g_vsc.target);
-      if (pc == inst_addr)
-        disasm_line = i + 1;
-      const auto inst_offset = inst_addr - low_pc;
-      int spaces = 0;
-      if (inst_offset < 10)
-        spaces = 3;
-      else if (inst_offset < 100)
-        spaces = 2;
-      else if (inst_offset < 1000)
-        spaces = 1;
-      line.clear();
-      llvm::raw_string_ostream line_strm(line);
-      line_strm << llvm::formatv("{0:X+}: <{1}> {2} {3,12} {4}", inst_addr,
-                                 inst_offset, llvm::fmt_repeat(' ', spaces), m,
-                                 o);
-
-      // If there is a comment append it starting at column 60 or after one
-      // space past the last char
-      const uint32_t comment_row = std::max(line_strm.str().size(), (size_t)60);
-      if (c && c[0]) {
-        if (line.size() < comment_row)
-          line_strm.indent(comment_row - line_strm.str().size());
-        line_strm << " # " << c;
-      }
-      src_strm << line_strm.str() << "\n";
-      source.addr_to_line[inst_addr] = i + 1;
-    }
-    // Flush the source stream
-    src_strm.str();
-    auto sourceReference = VSCode::GetNextSourceReference();
-    g_vsc.source_map[sourceReference] = std::move(source);
-    g_vsc.addr_to_source_ref[low_pc] = sourceReference;
-    object.try_emplace("sourceReference", sourceReference);
-  }
-  return llvm::json::Value(std::move(object));
+  return {};
 }
 
 // "StackFrame": {
@@ -748,6 +668,12 @@
 //       "description": "An optional end column of the range covered by the
 //                       stack frame."
 //     },
+//     "instructionPointerReference": {
+// 	     "type": "string",
+// 	     "description": "A memory reference for the current instruction
+// pointer
+//                       in this frame."
+//     },
 //     "moduleId": {
 //       "type": ["integer", "string"],
 //       "description": "The module associated with this frame, if any."
@@ -770,30 +696,47 @@
   int64_t frame_id = MakeVSCodeFrameID(frame);
   object.try_emplace("id", frame_id);
 
-  std::string frame_name;
-  const char *func_name = frame.GetFunctionName();
-  if (func_name)
-    frame_name = func_name;
-  else
+  std::string frame_name = llvm::json::fixUTF8(frame.GetDisplayFunctionName());
+  if (frame_name.empty())
     frame_name = "<unknown>";
   bool is_optimized = frame.GetFunction().GetIsOptimized();
   if (is_optimized)
     frame_name += " [opt]";
   EmplaceSafeString(object, "name", frame_name);
 
-  int64_t disasm_line = 0;
-  object.try_emplace("source", CreateSource(frame, disasm_line));
+  auto source = CreateSource(frame);
 
-  auto line_entry = frame.GetLineEntry();
-  if (disasm_line > 0) {
-    object.try_emplace("line", disasm_line);
-  } else {
+  if (source) {
+    object.try_emplace("source", *source);
+    auto line_entry = frame.GetLineEntry();
     auto line = line_entry.GetLine();
-    if (line == UINT32_MAX)
-      line = 0;
-    object.try_emplace("line", line);
+    if (line && line != LLDB_INVALID_LINE_NUMBER)
+      object.try_emplace("line", line);
+    auto column = line_entry.GetColumn();
+    if (column && column != LLDB_INVALID_COLUMN_NUMBER)
+      object.try_emplace("column", column);
+  } else {
+    object.try_emplace("line", 0);
+    object.try_emplace("column", 0);
+    object.try_emplace("presentationHint", "subtle");
+  }
+
+  lldb::addr_t inst_ptr = LLDB_INVALID_ADDRESS;
+  lldb::SBFunction func = frame.GetFunction();
+  if (func.IsValid()) {
+    inst_ptr = func.GetStartAddress().GetLoadAddress(g_vsc.target);
+  } else {
+    lldb::SBSymbol symbol = frame.GetSymbol();
+    if (symbol.IsValid()) {
+      inst_ptr = symbol.GetStartAddress().GetLoadAddress(g_vsc.target);
+    }
   }
-  object.try_emplace("column", line_entry.GetColumn());
+
+  if (inst_ptr != LLDB_INVALID_ADDRESS) {
+    std::string formatted_addr = "0x" + llvm::utohexstr(inst_ptr);
+    object.try_emplace("instructionPointerReference", formatted_addr);
+  }
+
   return llvm::json::Value(std::move(object));
 }
 
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to