-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[lldb-dap] Handle stack frames without a module #136777
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| C_SOURCES := main.c | ||
| include Makefile.rules |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| """ | ||
| Test lldb-dap stack trace when module is missing | ||
| """ | ||
|
|
||
| from lldbsuite.test.decorators import skipUnlessPlatform | ||
| from lldbsuite.test.lldbtest import line_number | ||
| import lldbdap_testcase | ||
| import re | ||
|
|
||
|
|
||
| class TestDAP_stackTraceMissingModule(lldbdap_testcase.DAPTestCaseBase): | ||
| @skipUnlessPlatform(["linux"]) | ||
| def test_missingModule(self): | ||
| """ | ||
| Test that the stack frame without a module still has assembly source. | ||
| """ | ||
| program = self.getBuildArtifact("a.out") | ||
| self.build_and_launch(program, commandEscapePrefix="") | ||
|
|
||
| source = "main.c" | ||
| self.set_source_breakpoints( | ||
| source, | ||
| [line_number(source, "// Break here")], | ||
| ) | ||
| self.continue_to_next_stop() | ||
|
|
||
| # Evaluate expr -- func | ||
| expr_result = self.dap_server.request_evaluate( | ||
| expression="expr -f pointer -- func", | ||
| context="repl", | ||
| ) | ||
|
|
||
| expr_result_address = re.search( | ||
| r"0x[0-9a-fA-F]+", expr_result["body"]["result"] | ||
| ) | ||
| self.assertIsNotNone( | ||
| expr_result_address, "Failed to get address of dynamic allocated func" | ||
| ) | ||
| func_address = expr_result_address.group(0) | ||
|
|
||
| self.dap_server.request_evaluate( | ||
| expression=f"breakpoint set --address {func_address}", | ||
| context="repl", | ||
| ) | ||
|
|
||
| self.continue_to_next_stop() | ||
|
|
||
| frame_without_module = self.get_stackFrames()[0] | ||
|
|
||
| self.assertIn("line", frame_without_module, "Line number missing.") | ||
| self.assertIn("column", frame_without_module, "Column number missing.") | ||
| self.assertIn("source", frame_without_module, "Source location missing.") | ||
| source = frame_without_module["source"] | ||
| self.assertIn("sourceReference", source, "Source reference missing.") |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| #include <stdint.h> | ||
| #include <stdio.h> | ||
| #include <string.h> | ||
| #include <sys/mman.h> | ||
| #include <unistd.h> | ||
|
|
||
| extern uint8_t __start_target_section[]; | ||
| extern uint8_t __stop_target_section[]; | ||
|
|
||
| __attribute__((used, section("target_section"))) int target_function(void) { | ||
| return 42; | ||
| } | ||
|
|
||
| typedef int (*target_function_t)(void); | ||
|
|
||
| int main(void) { | ||
| size_t target_function_size = __stop_target_section - __start_target_section; | ||
| size_t page_size = sysconf(_SC_PAGESIZE); | ||
| size_t page_aligned_size = | ||
| (target_function_size + page_size - 1) & ~(page_size - 1); | ||
|
|
||
| void *executable_memory = | ||
| mmap(NULL, page_aligned_size, PROT_READ | PROT_WRITE | PROT_EXEC, | ||
| MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | ||
| if (executable_memory == MAP_FAILED) { | ||
| perror("mmap"); | ||
| return 1; | ||
| } | ||
|
|
||
| memcpy(executable_memory, __start_target_section, target_function_size); | ||
|
|
||
| target_function_t func = (target_function_t)executable_memory; | ||
| int result = func(); // Break here | ||
| printf("Result from target function: %d\n", result); | ||
|
|
||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -783,6 +783,16 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame, | |||||||||
| // Line numbers are 1-based. | ||||||||||
| object.try_emplace("line", inst_line + 1); | ||||||||||
| object.try_emplace("column", 1); | ||||||||||
| } else { | ||||||||||
| // No valid line entry or symbol | ||||||||||
|
||||||||||
| // No valid line entry or symbol | |
| // No valid line entry or symbol. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| object.try_emplace("line", 1); | |
| object.try_emplace("column", 1); | |
| object.try_emplace("line", LLDB_INVALID_LINE_NUMBER); | |
| object.try_emplace("column", LLDB_INVALID_LINE_NUMBER); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it still needs to be 1, this way it will be possible to debug the code in the IDE:
Screencast.From.2025-04-24.08-48-53.webm
The only annoying thing is that each step removes the previous assembly lines, but I couldn't think of a straightforward way to tackle it because the frame changes too in every step
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When writing comments, write them as English prose, using proper capitalization, punctuation, etc.