https://github.com/Da-Viper updated https://github.com/llvm/llvm-project/pull/106907
>From c5dda32e63371b3f265a209fdcd5105a7c6197dc Mon Sep 17 00:00:00 2001 From: Ezike Ebuka <yerimy...@gmail.com> Date: Wed, 12 Feb 2025 00:16:46 +0000 Subject: [PATCH 1/5] [lldb-dap] Add Tests: Show children for return values --- .../lldb-dap/variables/TestDAP_variables.py | 57 +++++++++++++++---- .../children/TestDAP_variables_children.py | 55 ++++++++++++++++++ .../lldb-dap/variables/children/main.cpp | 12 ++++ .../API/tools/lldb-dap/variables/main.cpp | 9 +++ 4 files changed, 122 insertions(+), 11 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py index fde66a28382c7..dba62d11d021e 100644 --- a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py +++ b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py @@ -341,9 +341,9 @@ def do_test_scopes_variables_setVariable_evaluate( verify_locals["argc"]["equals"]["value"] = "123" verify_locals["pt"]["children"]["x"]["equals"]["value"] = "111" - verify_locals["x @ main.cpp:17"] = {"equals": {"type": "int", "value": "89"}} - verify_locals["x @ main.cpp:19"] = {"equals": {"type": "int", "value": "42"}} - verify_locals["x @ main.cpp:21"] = {"equals": {"type": "int", "value": "72"}} + verify_locals["x @ main.cpp:19"] = {"equals": {"type": "int", "value": "89"}} + verify_locals["x @ main.cpp:21"] = {"equals": {"type": "int", "value": "42"}} + verify_locals["x @ main.cpp:23"] = {"equals": {"type": "int", "value": "72"}} self.verify_variables(verify_locals, self.dap_server.get_local_variables()) @@ -353,32 +353,32 @@ def do_test_scopes_variables_setVariable_evaluate( self.dap_server.request_setVariable(1, "x @ main.cpp:0", 9)["success"] ) - self.assertTrue( - self.dap_server.request_setVariable(1, "x @ main.cpp:17", 17)["success"] - ) self.assertTrue( self.dap_server.request_setVariable(1, "x @ main.cpp:19", 19)["success"] ) self.assertTrue( self.dap_server.request_setVariable(1, "x @ main.cpp:21", 21)["success"] ) + self.assertTrue( + self.dap_server.request_setVariable(1, "x @ main.cpp:23", 23)["success"] + ) # The following should have no effect self.assertFalse( - self.dap_server.request_setVariable(1, "x @ main.cpp:21", "invalid")[ + self.dap_server.request_setVariable(1, "x @ main.cpp:23", "invalid")[ "success" ] ) - verify_locals["x @ main.cpp:17"]["equals"]["value"] = "17" verify_locals["x @ main.cpp:19"]["equals"]["value"] = "19" verify_locals["x @ main.cpp:21"]["equals"]["value"] = "21" + verify_locals["x @ main.cpp:23"]["equals"]["value"] = "23" self.verify_variables(verify_locals, self.dap_server.get_local_variables()) # The plain x variable shold refer to the innermost x self.assertTrue(self.dap_server.request_setVariable(1, "x", 22)["success"]) - verify_locals["x @ main.cpp:21"]["equals"]["value"] = "22" + verify_locals["x @ main.cpp:23"]["equals"]["value"] = "22" self.verify_variables(verify_locals, self.dap_server.get_local_variables()) @@ -394,10 +394,10 @@ def do_test_scopes_variables_setVariable_evaluate( locals = self.dap_server.get_local_variables() names = [var["name"] for var in locals] # The first shadowed x shouldn't have a suffix anymore - verify_locals["x"] = {"equals": {"type": "int", "value": "17"}} - self.assertNotIn("x @ main.cpp:17", names) + verify_locals["x"] = {"equals": {"type": "int", "value": "19"}} self.assertNotIn("x @ main.cpp:19", names) self.assertNotIn("x @ main.cpp:21", names) + self.assertNotIn("x @ main.cpp:23", names) self.verify_variables(verify_locals, locals) @@ -663,6 +663,41 @@ def do_test_indexedVariables(self, enableSyntheticChildDebugging: bool): ]["variables"] self.verify_variables(verify_children, children) + def test_return_variables(self): + """ + Test the stepping out of a function with return value show the variable correctly. + """ + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + + verify_locals = { + "(Return Value)": {"equals": {"type": "int", "value": "300"}}, + "argc": {}, + "argv": {}, + "pt": {}, + "x": {}, + "return_result": {"equals": {"type": "int"}}, + } + + function_name = "test_return_variable" + breakpoint_ids = self.set_function_breakpoints([function_name]) + + self.assertEqual(len(breakpoint_ids), 1) + self.continue_to_breakpoints(breakpoint_ids) + + threads = self.dap_server.get_threads() + for thread in threads: + if thread.get("reason") == "breakpoint": + # We have a thread that + thread_id = thread["id"] + + self.stepOut(threadId=thread_id) + + local_variables = self.dap_server.get_local_variables() + varref_dict = {} + self.verify_variables(verify_locals, local_variables, varref_dict) + break + @skipIfWindows def test_indexedVariables(self): self.do_test_indexedVariables(enableSyntheticChildDebugging=False) diff --git a/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py b/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py index 805e88ddf8f70..f671a02c75a78 100644 --- a/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py +++ b/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py @@ -40,3 +40,58 @@ def test_get_num_children(self): "`script formatter.num_children_calls", context="repl" )["body"]["result"], ) + + def test_return_variable_with_children(self): + """ + Test the stepping out of a function with return value show the children correctly + """ + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + + function_name = "test_return_variable_with_children" + breakpoint_ids = self.set_function_breakpoints([function_name]) + + self.assertEqual(len(breakpoint_ids), 1) + self.continue_to_breakpoints(breakpoint_ids) + + threads = self.dap_server.get_threads() + for thread in threads: + if thread.get("reason") == "breakpoint": + thread_id = thread.get("id") + self.assertIsNot(thread_id, None) + + self.stepOut(threadId=thread_id) + + local_variables = self.dap_server.get_local_variables() + + # verify has return variable as local + result_variable = list( + filter( + lambda val: val.get("name") == "(Return Value)", local_variables + ) + ) + self.assertEqual(len(result_variable), 1) + result_variable = result_variable[0] + + result_var_ref = result_variable.get("variablesReference") + self.assertIsNot(result_var_ref, None, "There is no result value") + + result_value = self.dap_server.request_variables(result_var_ref) + result_children = result_value["body"]["variables"] + self.assertNotEqual( + result_children, None, "The result does not have children" + ) + + verify_children = {"buffer": '"hello world!"', "x": "10", "y": "20"} + for child in result_children: + actual_name = child["name"] + actual_value = child["value"] + verify_value = verify_children.get(actual_name) + self.assertNotEqual(verify_value, None) + self.assertEqual( + actual_value, + verify_value, + "Expected child value does not match", + ) + + break diff --git a/lldb/test/API/tools/lldb-dap/variables/children/main.cpp b/lldb/test/API/tools/lldb-dap/variables/children/main.cpp index 5d625fe1903a3..59a86f758ab28 100644 --- a/lldb/test/API/tools/lldb-dap/variables/children/main.cpp +++ b/lldb/test/API/tools/lldb-dap/variables/children/main.cpp @@ -1,8 +1,20 @@ struct Indexed {}; struct NotIndexed {}; +#define BUFFER_SIZE 16 +struct NonPrimitive { + char buffer[BUFFER_SIZE]; + int x; + long y; +}; + +NonPrimitive test_return_variable_with_children() { + return NonPrimitive{"hello world!", 10, 20}; +} + int main() { Indexed indexed; NotIndexed not_indexed; + NonPrimitive non_primitive_result = test_return_variable_with_children(); return 0; // break here } diff --git a/lldb/test/API/tools/lldb-dap/variables/main.cpp b/lldb/test/API/tools/lldb-dap/variables/main.cpp index 3557067ed9ce1..0e363001f2f42 100644 --- a/lldb/test/API/tools/lldb-dap/variables/main.cpp +++ b/lldb/test/API/tools/lldb-dap/variables/main.cpp @@ -9,6 +9,8 @@ struct PointType { int g_global = 123; static int s_global = 234; int test_indexedVariables(); +int test_return_variable(); + int main(int argc, char const *argv[]) { static float s_local = 2.25; PointType pt = {11, 22, {0}}; @@ -22,6 +24,9 @@ int main(int argc, char const *argv[]) { s_global = x; // breakpoint 2 } } + { + int return_result = test_return_variable(); + } return test_indexedVariables(); // breakpoint 3 } @@ -34,3 +39,7 @@ int test_indexedVariables() { large_vector.assign(200, 0); return 0; // breakpoint 4 } + +int test_return_variable() { + return 300; // breakpoint 5 +} \ No newline at end of file >From 774e23fc434340fb860473fb2b39abccf5f02dff Mon Sep 17 00:00:00 2001 From: Ezike Ebuka <yerimy...@gmail.com> Date: Thu, 13 Feb 2025 13:12:23 +0000 Subject: [PATCH 2/5] [lldb-dap] Fix: only show return values in the local scope. --- lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py index dba62d11d021e..5592b2e4d7581 100644 --- a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py +++ b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py @@ -688,7 +688,6 @@ def test_return_variables(self): threads = self.dap_server.get_threads() for thread in threads: if thread.get("reason") == "breakpoint": - # We have a thread that thread_id = thread["id"] self.stepOut(threadId=thread_id) >From 9ffff641f1ec39a6cffe8c29378610a9cfb5765b Mon Sep 17 00:00:00 2001 From: Ezike Ebuka <yerimy...@gmail.com> Date: Thu, 13 Feb 2025 23:59:38 +0000 Subject: [PATCH 3/5] [lldb-dap] skip memory return test on arm64 --- .../lldb-dap/variables/children/TestDAP_variables_children.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py b/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py index f671a02c75a78..f0e1e51365d9b 100644 --- a/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py +++ b/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py @@ -41,6 +41,7 @@ def test_get_num_children(self): )["body"]["result"], ) + @skipIf(archs=["arm64"]) def test_return_variable_with_children(self): """ Test the stepping out of a function with return value show the children correctly >From 528bb545d7059d0dc99a9e625d28d0070facac70 Mon Sep 17 00:00:00 2001 From: Ezike Ebuka <yerimy...@gmail.com> Date: Fri, 14 Feb 2025 10:02:25 +0000 Subject: [PATCH 4/5] [lldb-dap] Add feature to ReleaseNotes.md --- llvm/docs/ReleaseNotes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md index 12dd09ad41135..f1f64f77ee71a 100644 --- a/llvm/docs/ReleaseNotes.md +++ b/llvm/docs/ReleaseNotes.md @@ -168,6 +168,7 @@ Changes to LLDB ### Changes to lldb-dap * Breakpoints can now be set for specific columns within a line. +* Function return value is now displayed on step-out. Changes to BOLT --------------------------------- >From 4453e42213c54f1636a1d55bbd2d1be2ab0e3180 Mon Sep 17 00:00:00 2001 From: Ezike Ebuka <yerimy...@gmail.com> Date: Sat, 1 Mar 2025 22:12:30 +0000 Subject: [PATCH 5/5] [lldb-dap] Add: Show return values Explicitly check for the return value variable --- .../lldb-dap/variables/TestDAP_variables.py | 16 ++++++++++++- .../Handler/VariablesRequestHandler.cpp | 23 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py index 5592b2e4d7581..ee5b49de14d98 100644 --- a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py +++ b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py @@ -670,8 +670,9 @@ def test_return_variables(self): program = self.getBuildArtifact("a.out") self.build_and_launch(program) + return_name = "(Return Value)" verify_locals = { - "(Return Value)": {"equals": {"type": "int", "value": "300"}}, + return_name: {"equals": {"type": "int", "value": "300"}}, "argc": {}, "argv": {}, "pt": {}, @@ -694,6 +695,19 @@ def test_return_variables(self): local_variables = self.dap_server.get_local_variables() varref_dict = {} + + # `verify_variable` function only checks if the local variables + # are in the `verify_dict` passed this will cause this test to pass + # even if there is no return value. + local_variable_names = [ + variable["name"] for variable in local_variables + ] + self.assertIn( + return_name, + local_variable_names, + "return variable is not in local variables", + ) + self.verify_variables(verify_locals, local_variables, varref_dict) break diff --git a/lldb/tools/lldb-dap/Handler/VariablesRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/VariablesRequestHandler.cpp index 3a62682566236..d096c4220914a 100644 --- a/lldb/tools/lldb-dap/Handler/VariablesRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/VariablesRequestHandler.cpp @@ -164,6 +164,29 @@ void VariablesRequestHandler::operator()( variable_name_counts[GetNonNullVariableName(variable)]++; } + // Show return value if there is any ( in the local top frame ) + if (variablesReference == VARREF_LOCALS) { + auto process = dap.target.GetProcess(); + auto selected_thread = process.GetSelectedThread(); + lldb::SBValue stop_return_value = selected_thread.GetStopReturnValue(); + + if (stop_return_value.IsValid() && + (selected_thread.GetSelectedFrame().GetFrameID() == 0)) { + auto renamed_return_value = stop_return_value.Clone("(Return Value)"); + int64_t return_var_ref = 0; + + if (stop_return_value.MightHaveChildren() || + stop_return_value.IsSynthetic()) { + return_var_ref = dap.variables.InsertVariable(stop_return_value, + /*is_permanent=*/false); + } + variables.emplace_back( + CreateVariable(renamed_return_value, return_var_ref, hex, + dap.enable_auto_variable_summaries, + dap.enable_synthetic_child_debugging, false)); + } + } + // Now we construct the result with unique display variable names for (auto i = start_idx; i < end_idx; ++i) { lldb::SBValue variable = top_scope->GetValueAtIndex(i); _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits