[Lldb-commits] [lldb] 4f48a81 - [lldb-dap] Support column breakpoints (#113787)

2024-11-16 Thread via lldb-commits

Author: Adrian Vogelsgesang
Date: 2024-11-16T19:01:12+01:00
New Revision: 4f48a81a620bc9280be4780f3554cdc9bda55bd3

URL: 
https://github.com/llvm/llvm-project/commit/4f48a81a620bc9280be4780f3554cdc9bda55bd3
DIFF: 
https://github.com/llvm/llvm-project/commit/4f48a81a620bc9280be4780f3554cdc9bda55bd3.diff

LOG: [lldb-dap] Support column breakpoints (#113787)

This commit adds support for column breakpoints to lldb-dap.

To do so, support for the `breakpointLocations` request was
added. To find all available breakpoint positions, we iterate over
the line table.

The `setBreakpoints` request already forwarded the column correctly to
`SBTarget::BreakpointCreateByLocation`. However, `SourceBreakpointMap`
did not keep track of multiple breakpoints in the same line. To do so,
the `SourceBreakpointMap` is now indexed by line+column instead of by
line only.

See http://jonasdevlieghere.com/post/lldb-column-breakpoints/ for a
high-level introduction to column breakpoints.

Added: 
lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_breakpointLocations.py

Modified: 
lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
lldb/test/API/tools/lldb-dap/breakpoint/Makefile
lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py
lldb/tools/lldb-dap/DAP.h
lldb/tools/lldb-dap/lldb-dap.cpp

Removed: 




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 c29992ce9c7848..043d82e2e2c7d1 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
@@ -612,6 +612,28 @@ def request_attach(
 command_dict = {"command": "attach", "type": "request", "arguments": 
args_dict}
 return self.send_recv(command_dict)
 
+def request_breakpointLocations(
+self, file_path, line, end_line=None, column=None, end_column=None
+):
+(dir, base) = os.path.split(file_path)
+source_dict = {"name": base, "path": file_path}
+args_dict = {}
+args_dict["source"] = source_dict
+if line is not None:
+args_dict["line"] = line
+if end_line is not None:
+args_dict["endLine"] = end_line
+if column is not None:
+args_dict["column"] = column
+if end_column is not None:
+args_dict["endColumn"] = end_column
+command_dict = {
+"command": "breakpointLocations",
+"type": "request",
+"arguments": args_dict,
+}
+return self.send_recv(command_dict)
+
 def request_configurationDone(self):
 command_dict = {
 "command": "configurationDone",
@@ -851,6 +873,8 @@ def request_next(self, threadId, granularity="statement"):
 def request_stepIn(self, threadId, targetId, granularity="statement"):
 if self.exit_status is not None:
 raise ValueError("request_stepIn called after process exited")
+if threadId is None:
+threadId = self.get_thread_id()
 args_dict = {
 "threadId": threadId,
 "targetId": targetId,
@@ -911,18 +935,14 @@ def request_setBreakpoints(self, file_path, line_array, 
data=None):
 breakpoint_data = data[i]
 bp = {"line": line}
 if breakpoint_data is not None:
-if "condition" in breakpoint_data and 
breakpoint_data["condition"]:
+if breakpoint_data.get("condition"):
 bp["condition"] = breakpoint_data["condition"]
-if (
-"hitCondition" in breakpoint_data
-and breakpoint_data["hitCondition"]
-):
+if breakpoint_data.get("hitCondition"):
 bp["hitCondition"] = breakpoint_data["hitCondition"]
-if (
-"logMessage" in breakpoint_data
-and breakpoint_data["logMessage"]
-):
+if breakpoint_data.get("logMessage"):
 bp["logMessage"] = breakpoint_data["logMessage"]
+if breakpoint_data.get("column"):
+bp["column"] = breakpoint_data["column"]
 breakpoints.append(bp)
 args_dict["breakpoints"] = breakpoints
 

diff  --git 
a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py 
b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
index a25466f07fa557..34e9b96dbcc3f5 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
@@ 

[Lldb-commits] [lldb] [lldb-dap] Refactoring lldb-dap port listening mode to allow multiple connections. (PR #116392)

2024-11-16 Thread Adrian Vogelsgesang via lldb-commits


@@ -5028,36 +5218,52 @@ int main(int argc, char *argv[]) {
 #endif
 
   // Initialize LLDB first before we do anything.
-  lldb::SBDebugger::Initialize();
+  lldb::SBError error = lldb::SBDebugger::InitializeWithErrorHandling();
+  if (error.Fail()) {
+llvm::errs() << "Failed to initialize LLDB: " << error.GetCString() << 
"\n";
+return EXIT_FAILURE;
+  }
 
   // Terminate the debugger before the C++ destructor chain kicks in.
   auto terminate_debugger =
   llvm::make_scope_exit([] { lldb::SBDebugger::Terminate(); });
 
-  DAP dap = DAP(program_path.str(), default_repl_mode);
+  if (portno != -1) {
+llvm::errs() << llvm::format("Listening on port %i...\n", portno);
+return AcceptConnection(program_path.str(), pre_init_commands, log,
+default_repl_mode, portno);
+  }
+
+  if (!unix_socket_path.empty()) {

vogelsgesang wrote:

we might want to handle the case that the user specified both a `portno` and a 
`socket_path`?

Does it make sense to listen on both? Does it maybe also make sense to listen 
on multiple ports and multiple socket paths? Or should we report an error if 
both a port and a socket are specified?

https://github.com/llvm/llvm-project/pull/116392
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [llvm] [lldb-dap] Support column breakpoints (PR #113787)

2024-11-16 Thread Adrian Vogelsgesang via lldb-commits

https://github.com/vogelsgesang closed 
https://github.com/llvm/llvm-project/pull/113787
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [llvm] [lldb-dap] Support column breakpoints (PR #113787)

2024-11-16 Thread LLVM Continuous Integration via lldb-commits

llvm-ci wrote:

LLVM Buildbot has detected a new failure on builder `lldb-aarch64-ubuntu` 
running on `linaro-lldb-aarch64-ubuntu` while building `lldb` at step 6 "test".

Full details are available at: 
https://lab.llvm.org/buildbot/#/builders/59/builds/8268


Here is the relevant piece of the build log for the reference

```
Step 6 (test) failure: build (failure)
...
PASS: lldb-api :: python_api/target/TestTargetAPI.py (1104 of 2050)
PASS: lldb-api :: 
symbol_ondemand/breakpoint_source_regex/TestSourceTextRegexBreakpoint.py (1105 
of 2050)
PASS: lldb-api :: 
symbol_ondemand/breakpoint_language/TestBreakpointLanguageOnDemand.py (1106 of 
2050)
PASS: lldb-api :: test_utils/TestDecorators.py (1107 of 2050)
PASS: lldb-api :: terminal/TestSTTYBeforeAndAfter.py (1108 of 2050)
PASS: lldb-api :: test_utils/TestInlineTest.py (1109 of 2050)
PASS: lldb-api :: test_utils/TestPExpectTest.py (1110 of 2050)
PASS: lldb-api :: test_utils/base/TestBaseTest.py ( of 2050)
PASS: lldb-api :: symbol_ondemand/shared_library/TestSharedLibOnDemand.py (1112 
of 2050)
UNSUPPORTED: lldb-api :: 
tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py (1113 of 2050)
FAIL: lldb-api :: tools/lldb-dap/breakpoint/TestDAP_breakpointLocations.py 
(1114 of 2050)
 TEST 'lldb-api :: 
tools/lldb-dap/breakpoint/TestDAP_breakpointLocations.py' FAILED 

Script:
--
/usr/bin/python3.10 
/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/dotest.py
 -u CXXFLAGS -u CFLAGS --env 
LLVM_LIBS_DIR=/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./lib --env 
LLVM_INCLUDE_DIR=/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/include 
--env LLVM_TOOLS_DIR=/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin 
--arch aarch64 --build-dir 
/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex 
--lldb-module-cache-dir 
/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/module-cache-lldb/lldb-api
 --clang-module-cache-dir 
/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/module-cache-clang/lldb-api
 --executable /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin/lldb 
--compiler /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin/clang 
--dsymutil /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin/dsymutil 
--make /usr/bin/make --llvm-tools-dir 
/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin --lldb-obj-root 
/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/tools/lldb --lldb-libs-dir 
/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./lib 
/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/tools/lldb-dap/breakpoint
 -p TestDAP_breakpointLocations.py
--
Exit Code: 1

Command Output (stdout):
--
lldb version 20.0.0git (https://github.com/llvm/llvm-project.git revision 
4f48a81a620bc9280be4780f3554cdc9bda55bd3)
  clang revision 4f48a81a620bc9280be4780f3554cdc9bda55bd3
  llvm revision 4f48a81a620bc9280be4780f3554cdc9bda55bd3
Skipping the following test categories: ['libc++', 'dsym', 'gmodules', 
'debugserver', 'objc']
= DEBUG ADAPTER PROTOCOL LOGS =
1731780632.250944853 --> 
Content-Length: 344

{
  "arguments": {
"adapterID": "lldb-native",
"clientID": "vscode",
"columnsStartAt1": true,
"linesStartAt1": true,
"locale": "en-us",
"pathFormat": "path",
"sourceInitFile": false,
"supportsRunInTerminalRequest": true,
"supportsStartDebuggingRequest": true,
"supportsVariablePaging": true,
"supportsVariableType": true
  },
  "command": "initialize",
  "seq": 1,
  "type": "request"
}
1731780632.252939463 <-- 
Content-Length: 1631


```



https://github.com/llvm/llvm-project/pull/113787
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [llvm] [lldb-dap] Support column breakpoints (PR #113787)

2024-11-16 Thread Adrian Vogelsgesang via lldb-commits


@@ -910,6 +911,183 @@ void request_attach(const llvm::json::Object &request) {
   }
 }
 
+// "BreakpointLocationsRequest": {
+//   "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "The `breakpointLocations` request returns all possible
+// locations for source breakpoints in a given range.\nClients should only
+// call this request if the corresponding capability
+// `supportsBreakpointLocationsRequest` is true.",
+// "properties": {
+//   "command": {
+// "type": "string",
+// "enum": [ "breakpointLocations" ]
+//   },
+//   "arguments": {
+// "$ref": "#/definitions/BreakpointLocationsArguments"
+//   }
+// },
+// "required": [ "command" ]
+//   }]
+// },
+// "BreakpointLocationsArguments": {
+//   "type": "object",
+//   "description": "Arguments for `breakpointLocations` request.",
+//   "properties": {
+// "source": {
+//   "$ref": "#/definitions/Source",
+//   "description": "The source location of the breakpoints; either
+//   `source.path` or `source.sourceReference` must be specified."
+// },
+// "line": {
+//   "type": "integer",
+//   "description": "Start line of range to search possible breakpoint
+//   locations in. If only the line is specified, the request returns all
+//   possible locations in that line."
+// },
+// "column": {
+//   "type": "integer",
+//   "description": "Start position within `line` to search possible
+//   breakpoint locations in. It is measured in UTF-16 code units and the
+//   client capability `columnsStartAt1` determines whether it is 0- or
+//   1-based. If no column is given, the first position in the start line 
is
+//   assumed."
+// },
+// "endLine": {
+//   "type": "integer",
+//   "description": "End line of range to search possible breakpoint
+//   locations in. If no end line is given, then the end line is assumed to
+//   be the start line."
+// },
+// "endColumn": {
+//   "type": "integer",
+//   "description": "End position within `endLine` to search possible
+//   breakpoint locations in. It is measured in UTF-16 code units and the
+//   client capability `columnsStartAt1` determines whether it is 0- or
+//   1-based. If no end column is given, the last position in the end line
+//   is assumed."
+// }
+//   },
+//   "required": [ "source", "line" ]
+// },
+// "BreakpointLocationsResponse": {
+//   "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to `breakpointLocations` request.\nContains
+// possible locations for source breakpoints.",
+// "properties": {
+//   "body": {
+// "type": "object",
+// "properties": {
+//   "breakpoints": {
+// "type": "array",
+// "items": {
+//   "$ref": "#/definitions/BreakpointLocation"
+// },
+// "description": "Sorted set of possible breakpoint locations."
+//   }
+// },
+// "required": [ "breakpoints" ]
+//   }
+// },
+// "required": [ "body" ]
+//   }]
+// },
+// "BreakpointLocation": {
+//   "type": "object",
+//   "description": "Properties of a breakpoint location returned from the
+//   `breakpointLocations` request.",
+//   "properties": {
+// "line": {
+//   "type": "integer",
+//   "description": "Start line of breakpoint location."
+// },
+// "column": {
+//   "type": "integer",
+//   "description": "The start position of a breakpoint location. Position
+//   is measured in UTF-16 code units and the client capability
+//   `columnsStartAt1` determines whether it is 0- or 1-based."
+// },
+// "endLine": {
+//   "type": "integer",
+//   "description": "The end line of breakpoint location if the location
+//   covers a range."
+// },
+// "endColumn": {
+//   "type": "integer",
+//   "description": "The end position of a breakpoint location (if the
+//   location covers a range). Position is measured in UTF-16 code units 
and
+//   the client capability `columnsStartAt1` determines whether it is 0- or
+//   1-based."
+// }
+//   },
+//   "required": [ "line" ]
+// },
+void request_breakpointLocations(const llvm::json::Object &request) {
+  llvm::json::Object response;
+  FillResponse(request, response);
+  auto *arguments = request.getObject("arguments");
+  auto *source = arguments->getObject("source");
+  std::string path = GetString(source, "path").str();
+  uint64_t start_line = GetUnsigned(arguments, "line", 0);
+  uint64_t start_column = GetUnsigned(arguments, "column", 0);
+  uint64_t end_line = GetUnsigned(arguments, "endLine", start_line);
+  uint64_t end_column =
+  GetUnsigned(arguments, "endColumn", 
std::numeric_limits::max());
+
+  lldb::SBFileSpec file_spec

[Lldb-commits] [lldb] [llvm] [lldb-dap] Support column breakpoints (PR #113787)

2024-11-16 Thread Adrian Vogelsgesang via lldb-commits

https://github.com/vogelsgesang edited 
https://github.com/llvm/llvm-project/pull/113787
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [llvm] [lldb-dap] Support column breakpoints (PR #113787)

2024-11-16 Thread Adrian Vogelsgesang via lldb-commits

https://github.com/vogelsgesang updated 
https://github.com/llvm/llvm-project/pull/113787

>From af45bc2e24623d7225d24a4680a28630d67d636e Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang 
Date: Sat, 26 Oct 2024 14:34:31 +
Subject: [PATCH 01/10] [lldb-dap] Support column breakpoints

This commit adds support for column breakpoints to lldb-dap.

To do so, support for `breakpointLocations` was added. To find all
available breakpoint positions, we iterate over the line table.

The `setBreakpoints` request already forwarded the column correctly to
`SBTarget::BreakpointCreateByLocation`. However, `SourceBreakpointMap`
did not keep track of multiple breakpoints in the same line. To do so,
the `SourceBreakpointMap` is now indexed by line+column instead of by
line only.

See http://jonasdevlieghere.com/post/lldb-column-breakpoints/ for a
high-level introduction to column breakpoints.
---
 .../test/tools/lldb-dap/dap_server.py |  30 ++-
 .../API/tools/lldb-dap/breakpoint/Makefile|   2 +-
 .../breakpoint/TestDAP_breakpointLocations.py |  74 +++
 .../breakpoint/TestDAP_setBreakpoints.py  | 172 +--
 lldb/tools/lldb-dap/DAP.h |   2 +-
 lldb/tools/lldb-dap/lldb-dap.cpp  | 197 +-
 .../llvm/DebugInfo/DWARF/DWARFDebugLine.h |   2 +-
 7 files changed, 393 insertions(+), 86 deletions(-)
 create mode 100644 
lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_breakpointLocations.py

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 63748a71f1122d..659408c709a249 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
@@ -612,6 +612,22 @@ def request_attach(
 command_dict = {"command": "attach", "type": "request", "arguments": 
args_dict}
 return self.send_recv(command_dict)
 
+def request_breakpointLocations(self, file_path, line, end_line=None, 
column=None, end_column=None):
+(dir, base) = os.path.split(file_path)
+source_dict = {"name": base, "path": file_path}
+args_dict = {}
+args_dict["source"] = source_dict
+if line is not None:
+   args_dict["line"] = line
+if end_line is not None:
+args_dict["endLine"] = end_line
+if column is not None:
+args_dict["column"] = column
+if end_column is not None:
+args_dict["endColumn"] = end_column
+command_dict = {"command": "breakpointLocations", "type": "request", 
"arguments": args_dict}
+return self.send_recv(command_dict)
+
 def request_configurationDone(self):
 command_dict = {
 "command": "configurationDone",
@@ -912,18 +928,14 @@ def request_setBreakpoints(self, file_path, line_array, 
data=None):
 breakpoint_data = data[i]
 bp = {"line": line}
 if breakpoint_data is not None:
-if "condition" in breakpoint_data and 
breakpoint_data["condition"]:
+if breakpoint_data.get("condition"):
 bp["condition"] = breakpoint_data["condition"]
-if (
-"hitCondition" in breakpoint_data
-and breakpoint_data["hitCondition"]
-):
+if breakpoint_data.get("hitCondition"):
 bp["hitCondition"] = breakpoint_data["hitCondition"]
-if (
-"logMessage" in breakpoint_data
-and breakpoint_data["logMessage"]
-):
+if breakpoint_data.get("logMessage"):
 bp["logMessage"] = breakpoint_data["logMessage"]
+if breakpoint_data.get("column"):
+bp["column"] = breakpoint_data["column"]
 breakpoints.append(bp)
 args_dict["breakpoints"] = breakpoints
 
diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/Makefile 
b/lldb/test/API/tools/lldb-dap/breakpoint/Makefile
index 7634f513e85233..06438b3e6e3139 100644
--- a/lldb/test/API/tools/lldb-dap/breakpoint/Makefile
+++ b/lldb/test/API/tools/lldb-dap/breakpoint/Makefile
@@ -16,4 +16,4 @@ main-copy.cpp: main.cpp
 # The following shared library will be used to test breakpoints under dynamic 
loading
 libother:  other-copy.c
"$(MAKE)" -f $(MAKEFILE_RULES) \
-   DYLIB_ONLY=YES DYLIB_C_SOURCES=other-copy.c DYLIB_NAME=other 
+   DYLIB_ONLY=YES DYLIB_C_SOURCES=other-copy.c DYLIB_NAME=other
diff --git 
a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_breakpointLocations.py 
b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_breakpointLocations.py
new file mode 100644
index 00..d84ce843e3fba8
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP

[Lldb-commits] [lldb] [llvm] [lldb-dap] Support column breakpoints (PR #113787)

2024-11-16 Thread Adrian Vogelsgesang via lldb-commits


@@ -1062,6 +1063,16 @@ void request_breakpointLocations(const 
llvm::json::Object &request) {
 continue;
   if (line == end_line && column > end_column)
 continue;
+
+  // Make sure we are in the right file.
+  // We might have a match on line & column range and still
+  // be in the wrong file, e.g. for included files.
+  if (std::string_view(line_entry.GetFileSpec().GetFilename()) !=

vogelsgesang wrote:

Thanks for that background. Fixed.

https://github.com/llvm/llvm-project/pull/113787
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb-dap] Refactoring lldb-dap port listening mode to allow multiple connections. (PR #116392)

2024-11-16 Thread Adrian Vogelsgesang via lldb-commits


@@ -5028,36 +5218,52 @@ int main(int argc, char *argv[]) {
 #endif
 
   // Initialize LLDB first before we do anything.
-  lldb::SBDebugger::Initialize();
+  lldb::SBError error = lldb::SBDebugger::InitializeWithErrorHandling();
+  if (error.Fail()) {
+llvm::errs() << "Failed to initialize LLDB: " << error.GetCString() << 
"\n";
+return EXIT_FAILURE;
+  }
 
   // Terminate the debugger before the C++ destructor chain kicks in.
   auto terminate_debugger =
   llvm::make_scope_exit([] { lldb::SBDebugger::Terminate(); });
 
-  DAP dap = DAP(program_path.str(), default_repl_mode);
+  if (portno != -1) {
+llvm::errs() << llvm::format("Listening on port %i...\n", portno);
+return AcceptConnection(program_path.str(), pre_init_commands, log,
+default_repl_mode, portno);
+  }
+
+  if (!unix_socket_path.empty()) {
+return AcceptConnection(program_path.str(), pre_init_commands, log,
+default_repl_mode, unix_socket_path);
+  }
+
+  DAP dap = DAP(program_path.str(), log, default_repl_mode, pre_init_commands);

vogelsgesang wrote:

maybe we should factor out the rest of `main` into a 
`HandelStdinStdoutConnection`? Could we reuse `HandleClient` also for 
`stdin`/`stdout` communications?

https://github.com/llvm/llvm-project/pull/116392
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb-dap] Refactoring lldb-dap port listening mode to allow multiple connections. (PR #116392)

2024-11-16 Thread Adrian Vogelsgesang via lldb-commits


@@ -137,42 +141,232 @@ lldb::SBValueList *GetTopLevelScope(DAP &dap, int64_t 
variablesReference) {
   }
 }
 
-SOCKET AcceptConnection(DAP &dap, int portno) {
-  // Accept a socket connection from any host on "portno".
-  SOCKET newsockfd = -1;
-  struct sockaddr_in serv_addr, cli_addr;
+/// Redirect stdout and stderr fo the IDE's console output.
+///
+/// Errors in this operation will be printed to the log file and the IDE's
+/// console output as well.
+///
+/// \return
+/// A fd pointing to the original stdout.
+void SetupRedirection(DAP &dap, int stdoutfd = -1, int stderrfd = -1) {
+  auto output_callback_stderr = [&dap](llvm::StringRef data) {
+dap.SendOutput(OutputType::Stderr, data);
+  };
+  auto output_callback_stdout = [&dap](llvm::StringRef data) {
+dap.SendOutput(OutputType::Stdout, data);
+  };
+
+  llvm::Expected new_stdout_fd =
+  RedirectFd(stdoutfd, output_callback_stdout);
+  if (auto err = new_stdout_fd.takeError()) {
+std::string error_message = llvm::toString(std::move(err));
+if (dap.log)
+  *dap.log << error_message << std::endl;
+output_callback_stderr(error_message);
+  }
+  dap.out = lldb::SBFile(new_stdout_fd.get(), "w", false);
+
+  llvm::Expected new_stderr_fd =
+  RedirectFd(stderrfd, output_callback_stderr);
+  if (auto err = new_stderr_fd.takeError()) {
+std::string error_message = llvm::toString(std::move(err));
+if (dap.log)
+  *dap.log << error_message << std::endl;
+output_callback_stderr(error_message);
+  }
+  dap.err = lldb::SBFile(new_stderr_fd.get(), "w", false);
+}
+
+void HandleClient(int clientfd, llvm::StringRef program_path,
+  const std::vector &pre_init_commands,
+  std::shared_ptr log,
+  ReplMode default_repl_mode) {
+  if (log)
+*log << "client[" << clientfd << "] connected\n";
+  DAP dap = DAP(program_path, log, default_repl_mode, pre_init_commands);
+  dap.debug_adaptor_path = program_path;
+
+  SetupRedirection(dap);
+  RegisterRequestCallbacks(dap);
+
+  dap.input.descriptor = StreamDescriptor::from_socket(clientfd, false);
+  dap.output.descriptor = StreamDescriptor::from_socket(clientfd, false);
+
+  for (const std::string &arg : pre_init_commands) {
+dap.pre_init_commands.push_back(arg);
+  }
+
+  if (auto Err = dap.Loop()) {
+if (log)
+  *log << "Transport Error: " << llvm::toString(std::move(Err)) << "\n";
+  }
+
+  if (log)
+*log << "client[" << clientfd << "] connection closed\n";
+#if defined(_WIN32)
+  closesocket(clientfd);
+#else
+  close(clientfd);
+#endif
+}
+
+std::error_code getLastSocketErrorCode() {
+#ifdef _WIN32
+  return std::error_code(::WSAGetLastError(), std::system_category());
+#else
+  return llvm::errnoAsErrorCode();
+#endif
+}
+
+llvm::Expected getSocketFD(llvm::StringRef path) {
+  if (llvm::sys::fs::exists(path) && (::remove(path.str().c_str()) == -1)) {
+return llvm::make_error(getLastSocketErrorCode(),
+   "Remove existing socket 
failed");
+  }
+
+  SOCKET sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
+  if (sockfd == -1) {
+return llvm::make_error(getLastSocketErrorCode(),
+   "Create socket failed");
+  }
+
+  struct sockaddr_un addr;
+  bzero(&addr, sizeof(addr));
+  addr.sun_family = AF_UNIX;
+  strncpy(addr.sun_path, path.str().c_str(), sizeof(addr.sun_path) - 1);
+
+  if (::bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+#if defined(_WIN32)
+closesocket(sockfd);
+#else
+close(sockfd);
+#endif
+return llvm::make_error(getLastSocketErrorCode(),
+   "Socket bind() failed");
+  }
+
+  if (listen(sockfd, llvm::hardware_concurrency().compute_thread_count()) < 0) 
{
+#if defined(_WIN32)
+closesocket(sockfd);
+#else
+close(sockfd);
+#endif
+return llvm::make_error(getLastSocketErrorCode(),
+   "Socket listen() failed");
+  }
+
+  return sockfd;
+}
+
+llvm::Expected getSocketFD(int portno) {
   SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
   if (sockfd < 0) {
-if (dap.log)
-  *dap.log << "error: opening socket (" << strerror(errno) << ")"
-   << std::endl;
-  } else {
-memset((char *)&serv_addr, 0, sizeof(serv_addr));
-serv_addr.sin_family = AF_INET;
-// serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
-serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-serv_addr.sin_port = htons(portno);
-if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
-  if (dap.log)
-*dap.log << "error: binding socket (" << strerror(errno) << ")"
- << std::endl;
-} else {
-  listen(sockfd, 5);
-  socklen_t clilen = sizeof(cli_addr);
-  newsockfd =
-  llvm::sys::RetryAfterSignal(static_cast(-1), accept, sockfd,
-  (struct sockaddr *)&cli_addr, &

[Lldb-commits] [lldb] [lldb/API] Hoist some of SBFrame logic to lldb_private::StackFrame (NFC) (PR #116298)

2024-11-16 Thread via lldb-commits

llvmbot wrote:




@llvm/pr-subscribers-lldb

Author: Med Ismail Bennani (medismailben)


Changes

This patch moves some of the logic implemented in the SBFrame APIs to the 
lldb_private::StackFrame class so it can be re-used elsewhere.

---
Full diff: https://github.com/llvm/llvm-project/pull/116298.diff


3 Files Affected:

- (modified) lldb/include/lldb/Target/StackFrame.h (+12) 
- (modified) lldb/source/API/SBFrame.cpp (+6-52) 
- (modified) lldb/source/Target/StackFrame.cpp (+51) 


``diff
diff --git a/lldb/include/lldb/Target/StackFrame.h 
b/lldb/include/lldb/Target/StackFrame.h
index fce3a943413ca4..e85430791b7d93 100644
--- a/lldb/include/lldb/Target/StackFrame.h
+++ b/lldb/include/lldb/Target/StackFrame.h
@@ -408,6 +408,18 @@ class StackFrame : public ExecutionContextScope,
   /// system implementation details this way.
   bool IsHidden();
 
+  /// Get the frame's demangled name.
+  ///
+  ///  /// \return
+  ///   A C-String containing the function demangled name. Can be null.
+  const char *GetFunctionName();
+
+  /// Get the frame's demangled display name.
+  ///
+  ///  /// \return
+  ///   A C-String containing the function demangled display name. Can be null.
+  const char *GetDisplayFunctionName();
+
   /// Query this frame to find what frame it is in this Thread's
   /// StackFrameList.
   ///
diff --git a/lldb/source/API/SBFrame.cpp b/lldb/source/API/SBFrame.cpp
index dc41e80b457d7d..e2c691fa9bfd45 100644
--- a/lldb/source/API/SBFrame.cpp
+++ b/lldb/source/API/SBFrame.cpp
@@ -1173,12 +1173,8 @@ bool SBFrame::IsInlined() const {
 Process::StopLocker stop_locker;
 if (stop_locker.TryLock(&process->GetRunLock())) {
   frame = exe_ctx.GetFramePtr();
-  if (frame) {
-
-Block *block = frame->GetSymbolContext(eSymbolContextBlock).block;
-if (block)
-  return block->GetContainingInlinedBlock() != nullptr;
-  }
+  if (frame)
+return frame->IsInlined();
 }
   }
   return false;
@@ -1255,29 +1251,8 @@ const char *SBFrame::GetFunctionName() const {
 Process::StopLocker stop_locker;
 if (stop_locker.TryLock(&process->GetRunLock())) {
   frame = exe_ctx.GetFramePtr();
-  if (frame) {
-SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction |
- eSymbolContextBlock |
- eSymbolContextSymbol));
-if (sc.block) {
-  Block *inlined_block = sc.block->GetContainingInlinedBlock();
-  if (inlined_block) {
-const InlineFunctionInfo *inlined_info =
-inlined_block->GetInlinedFunctionInfo();
-name = inlined_info->GetName().AsCString();
-  }
-}
-
-if (name == nullptr) {
-  if (sc.function)
-name = sc.function->GetName().GetCString();
-}
-
-if (name == nullptr) {
-  if (sc.symbol)
-name = sc.symbol->GetName().GetCString();
-}
-  }
+  if (frame)
+return frame->GetFunctionName();
 }
   }
   return name;
@@ -1298,29 +1273,8 @@ const char *SBFrame::GetDisplayFunctionName() {
 Process::StopLocker stop_locker;
 if (stop_locker.TryLock(&process->GetRunLock())) {
   frame = exe_ctx.GetFramePtr();
-  if (frame) {
-SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction |
- eSymbolContextBlock |
- eSymbolContextSymbol));
-if (sc.block) {
-  Block *inlined_block = sc.block->GetContainingInlinedBlock();
-  if (inlined_block) {
-const InlineFunctionInfo *inlined_info =
-inlined_block->GetInlinedFunctionInfo();
-name = inlined_info->GetDisplayName().AsCString();
-  }
-}
-
-if (name == nullptr) {
-  if (sc.function)
-name = sc.function->GetDisplayName().GetCString();
-}
-
-if (name == nullptr) {
-  if (sc.symbol)
-name = sc.symbol->GetDisplayName().GetCString();
-}
-  }
+  if (frame)
+return frame->GetDisplayFunctionName();
 }
   }
   return name;
diff --git a/lldb/source/Target/StackFrame.cpp 
b/lldb/source/Target/StackFrame.cpp
index 20d8425c578a33..77179fec3ed438 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -1230,6 +1230,57 @@ bool StackFrame::IsHidden() {
   return false;
 }
 
+const char *StackFrame::GetFunctionName() {
+  const char *name = nullptr;
+  SymbolContext sc = GetSymbolContext(
+  eSymbolContextFunction | eSymbolContextBlock | eSymbolContextSymbol);
+  if (sc.block) {
+Block *inlined_block = sc.block->GetContainingInlinedBlock();
+if (inlined_block) {
+  const InlineFunctionInfo *inlined_info =
+  inlined_block->GetInlinedFunctionInfo();
+  name = inlined_info->GetName().AsCString();
+}

[Lldb-commits] [lldb] [lldb/Target] Add null-check before dereferencing inlined_info (NFC) (PR #116300)

2024-11-16 Thread via lldb-commits

llvmbot wrote:




@llvm/pr-subscribers-lldb

Author: Med Ismail Bennani (medismailben)


Changes

This patch is a follow-up to 9c7701fa78037af03be10ed168fd3c75a2ed1aef and adds 
extra-null checks before dereferencing the inlined_info pointer.

---
Full diff: https://github.com/llvm/llvm-project/pull/116300.diff


1 Files Affected:

- (modified) lldb/source/Target/StackFrame.cpp (+4-2) 


``diff
diff --git a/lldb/source/Target/StackFrame.cpp 
b/lldb/source/Target/StackFrame.cpp
index 77179fec3ed438..1bca9786fb7c70 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -1239,7 +1239,8 @@ const char *StackFrame::GetFunctionName() {
 if (inlined_block) {
   const InlineFunctionInfo *inlined_info =
   inlined_block->GetInlinedFunctionInfo();
-  name = inlined_info->GetName().AsCString();
+  if (inlined_info)
+name = inlined_info->GetName().AsCString();
 }
   }
 
@@ -1265,7 +1266,8 @@ const char *StackFrame::GetDisplayFunctionName() {
 if (inlined_block) {
   const InlineFunctionInfo *inlined_info =
   inlined_block->GetInlinedFunctionInfo();
-  name = inlined_info->GetDisplayName().AsCString();
+  if (inlined_info)
+name = inlined_info->GetDisplayName().AsCString();
 }
   }
 

``




https://github.com/llvm/llvm-project/pull/116300
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb-dap] Refactoring lldb-dap port listening mode to allow multiple connections. (PR #116392)

2024-11-16 Thread Adrian Vogelsgesang via lldb-commits


@@ -137,42 +141,232 @@ lldb::SBValueList *GetTopLevelScope(DAP &dap, int64_t 
variablesReference) {
   }
 }
 
-SOCKET AcceptConnection(DAP &dap, int portno) {
-  // Accept a socket connection from any host on "portno".
-  SOCKET newsockfd = -1;
-  struct sockaddr_in serv_addr, cli_addr;
+/// Redirect stdout and stderr fo the IDE's console output.
+///
+/// Errors in this operation will be printed to the log file and the IDE's
+/// console output as well.
+///
+/// \return
+/// A fd pointing to the original stdout.
+void SetupRedirection(DAP &dap, int stdoutfd = -1, int stderrfd = -1) {
+  auto output_callback_stderr = [&dap](llvm::StringRef data) {
+dap.SendOutput(OutputType::Stderr, data);
+  };
+  auto output_callback_stdout = [&dap](llvm::StringRef data) {
+dap.SendOutput(OutputType::Stdout, data);
+  };
+
+  llvm::Expected new_stdout_fd =
+  RedirectFd(stdoutfd, output_callback_stdout);
+  if (auto err = new_stdout_fd.takeError()) {
+std::string error_message = llvm::toString(std::move(err));
+if (dap.log)
+  *dap.log << error_message << std::endl;
+output_callback_stderr(error_message);
+  }
+  dap.out = lldb::SBFile(new_stdout_fd.get(), "w", false);
+
+  llvm::Expected new_stderr_fd =
+  RedirectFd(stderrfd, output_callback_stderr);
+  if (auto err = new_stderr_fd.takeError()) {
+std::string error_message = llvm::toString(std::move(err));
+if (dap.log)
+  *dap.log << error_message << std::endl;
+output_callback_stderr(error_message);
+  }
+  dap.err = lldb::SBFile(new_stderr_fd.get(), "w", false);
+}
+
+void HandleClient(int clientfd, llvm::StringRef program_path,
+  const std::vector &pre_init_commands,
+  std::shared_ptr log,
+  ReplMode default_repl_mode) {
+  if (log)
+*log << "client[" << clientfd << "] connected\n";
+  DAP dap = DAP(program_path, log, default_repl_mode, pre_init_commands);
+  dap.debug_adaptor_path = program_path;
+
+  SetupRedirection(dap);
+  RegisterRequestCallbacks(dap);
+
+  dap.input.descriptor = StreamDescriptor::from_socket(clientfd, false);
+  dap.output.descriptor = StreamDescriptor::from_socket(clientfd, false);
+
+  for (const std::string &arg : pre_init_commands) {
+dap.pre_init_commands.push_back(arg);
+  }
+
+  if (auto Err = dap.Loop()) {
+if (log)
+  *log << "Transport Error: " << llvm::toString(std::move(Err)) << "\n";
+  }
+
+  if (log)
+*log << "client[" << clientfd << "] connection closed\n";
+#if defined(_WIN32)
+  closesocket(clientfd);
+#else
+  close(clientfd);
+#endif
+}
+
+std::error_code getLastSocketErrorCode() {
+#ifdef _WIN32
+  return std::error_code(::WSAGetLastError(), std::system_category());
+#else
+  return llvm::errnoAsErrorCode();
+#endif
+}
+
+llvm::Expected getSocketFD(llvm::StringRef path) {
+  if (llvm::sys::fs::exists(path) && (::remove(path.str().c_str()) == -1)) {
+return llvm::make_error(getLastSocketErrorCode(),
+   "Remove existing socket 
failed");
+  }
+
+  SOCKET sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
+  if (sockfd == -1) {
+return llvm::make_error(getLastSocketErrorCode(),
+   "Create socket failed");
+  }
+
+  struct sockaddr_un addr;
+  bzero(&addr, sizeof(addr));
+  addr.sun_family = AF_UNIX;
+  strncpy(addr.sun_path, path.str().c_str(), sizeof(addr.sun_path) - 1);
+
+  if (::bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+#if defined(_WIN32)
+closesocket(sockfd);
+#else
+close(sockfd);
+#endif
+return llvm::make_error(getLastSocketErrorCode(),
+   "Socket bind() failed");
+  }
+
+  if (listen(sockfd, llvm::hardware_concurrency().compute_thread_count()) < 0) 
{
+#if defined(_WIN32)
+closesocket(sockfd);
+#else
+close(sockfd);
+#endif
+return llvm::make_error(getLastSocketErrorCode(),
+   "Socket listen() failed");
+  }
+
+  return sockfd;
+}
+
+llvm::Expected getSocketFD(int portno) {
   SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
   if (sockfd < 0) {
-if (dap.log)
-  *dap.log << "error: opening socket (" << strerror(errno) << ")"
-   << std::endl;
-  } else {
-memset((char *)&serv_addr, 0, sizeof(serv_addr));
-serv_addr.sin_family = AF_INET;
-// serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
-serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-serv_addr.sin_port = htons(portno);
-if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
-  if (dap.log)
-*dap.log << "error: binding socket (" << strerror(errno) << ")"
- << std::endl;
-} else {
-  listen(sockfd, 5);
-  socklen_t clilen = sizeof(cli_addr);
-  newsockfd =
-  llvm::sys::RetryAfterSignal(static_cast(-1), accept, sockfd,
-  (struct sockaddr *)&cli_addr, &

[Lldb-commits] [lldb] [lldb] Unify/improve MainLoop signal handling (PR #115197)

2024-11-16 Thread Michał Górny via lldb-commits


@@ -295,26 +243,17 @@ MainLoopPosix::RegisterSignal(int signo, const Callback 
&callback,
   sigaddset(&new_action.sa_mask, signo);
   sigset_t old_set;
 
-  g_signal_flags[signo] = 0;
+  // Set signal info before installing the signal handler!
+  g_signal_info[signo].pipe_fd = m_trigger_pipe.GetWriteFileDescriptor();

mgorny wrote:

Do we actually expect having different `pipe_fd` for different signals?

https://github.com/llvm/llvm-project/pull/115197
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits