Skip to content

Make LLDB IR data formatters more robust #7927

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

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open

Conversation

samestep
Copy link
Contributor

@samestep samestep commented Jul 25, 2025

This is a followup on #7828 to fix bugs that were causing CodeLLDB to give wrong values and hang (see vadimcn/codelldb#1302) because I didn't realize that these data formatters can be passed either a value of a given type or a pointer to a value of that type, and need to handle both cases. I also introduced loop bounds to prevent hangs in the case where these synthetic values are constructed for things like uninitialized variables.

From looking at the preexisting data formatters from #4272 in source/core/core_lldb.py, it seems like they technically have similar bugs to this, but since those types are simpler, it's unclear to me whether that can actually manifest in meaningful ways like these bugs in source/slang/slang_lldb.py were doing.

Anyways, to test this, put a breakpoint here:

auto handler = StringEscapeUtil::getHandler(StringEscapeUtil::Style::Cpp);

And use this .vscode/launch.json for CodeLLDB:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "LLDB",
      "preLaunchTask": "Debug build",
      "type": "lldb",
      "request": "launch",
      "initCommands": ["command source .lldbinit"],
      "program": "build/Debug/bin/slangc",
      "args": [
        "tests/cpu-program/cpu-hello-world-test.slang",
        "-target",
        "executable",
        "-o",
        "hello"
      ]
    }
  ]
}

Before this PR, the inst variable will display in the debug pane as {kIROp_StringLit 0x00007fffffff5f68}, which is the wrong pointer value. You can also check this by running p inst in the Debug Console, which will print this:

(Slang::IRInst *) 0x000055555fdac3b8 {kIROp_StringLit 0x00007fffffff5f68}

In contrast, running p *inst prints the correct pointer value:

(Slang::IRInst) {kIROp_StringLit 0x000055555fdac3b8} {
  [op] = kIROp_StringLit
  [UID] = 76
  [type] = 0x000055555fdac348 {kIROp_StringType None}
  [decorations/children] = {}
  [parent] = 0x000055555fdac2d0 {kIROp_ModuleInst None}
  [uses] = 0x000055555fdadf18 {kIROp_StringLit 0x000055555fdac3b8}
}

But as you can see, in that case the synthetic [value] child is completely missing.

Then if you try to expand inst in the debug pane, CodeLLDB will hang (or at least it does when I try this).

After this PR, the hex integer for the pointer is always consistent, and CodeLLDB does not hang in the debug pane when you expand inst, and shows the correct [value] child just like when running v *inst.

As an aside: after this PR, the [value] child is still missing when specifically running p *inst in the Debug Console. It is possible to fix this:

diff --git a/source/slang/slang_lldb.py b/source/slang/slang_lldb.py
index 23905d8c5..d2b3a4da9 100644
--- a/source/slang/slang_lldb.py
+++ b/source/slang/slang_lldb.py
@@ -93,13 +93,11 @@ class IRInst_synthetic(lldb.SBSyntheticValueProvider):
         value: list[tuple[str, lldb.SBValue]] = []
         match op.value:
             case "kIROp_StringLit":
-                string_lit_t = target.FindFirstType("Slang::IRStringLit")
-                string_lit = self.valobj.Cast(string_lit_t)
+                string_lit = self.valobj.EvaluateExpression("(Slang::IRStringLit*)this")
                 val = string_lit.GetChildMemberWithName("value")
                 value = [("[value]", val.GetChildMemberWithName("stringVal"))]
             case "kIROp_IntLit":
-                int_lit_t = target.FindFirstType("Slang::IRIntLit")
-                int_lit = self.valobj.Cast(int_lit_t)
+                int_lit = self.valobj.EvaluateExpression("(Slang::IRIntLit*)this")
                 val = int_lit.GetChildMemberWithName("value")
                 value = [("[value]", val.GetChildMemberWithName("intVal"))]
 
diff --git a/typings/lldb.pyi b/typings/lldb.pyi
index 2672ba244..3a08e9141 100644
--- a/typings/lldb.pyi
+++ b/typings/lldb.pyi
@@ -496,7 +496,7 @@ class SBValue:
     def Persist(self): ...
     def GetDescription(self, description): ...
     def GetExpressionPath(self, *args): ...
-    def EvaluateExpression(self, *args): ...
+    def EvaluateExpression(self, expr: str) -> SBValue: ...
     def Watch(self, *args): ...
     def WatchPointee(self, resolve_location, read, write, error): ...
     def GetVTable(self): ...

However, that makes the debugger run significantly slower, so I'm choosing not do do it here.

@samestep samestep requested a review from a team as a code owner July 25, 2025 20:49
@samestep samestep added the pr: non-breaking PRs without breaking changes label Jul 25, 2025
@samestep samestep marked this pull request as draft July 30, 2025 12:44
@samestep samestep marked this pull request as ready for review July 30, 2025 17:01
@samestep samestep changed the title Handle both pointers and pointees in LLDB Make LLDB IR data formatters more robust Jul 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr: non-breaking PRs without breaking changes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant