Skip to content

[LLDB] Run API tests with native PDB too #149305

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 1 commit into
base: main
Choose a base branch
from

Conversation

Nerixyz
Copy link
Contributor

@Nerixyz Nerixyz commented Jul 17, 2025

From #148554 (comment) - this adds an option for API tests to be run with the native PDB reader on Windows. As there are a lot of failures with PDB, this is an opt-in per test. Once #51933 makes progress, this could be expanded.

To get PDB, -g has to be used on Clang. As far as I know, there's no way to specify something like -gpdb. -gcodeview is the closest, but I don't think it sets the correct linker flags (or something similar) - at least LLDB doesn't have any debug info in that case.

#149498 tracks the (currently) failing tests.

Copy link

github-actions bot commented Jul 17, 2025

✅ With the latest revision this PR passed the Python code formatter.

@Nerixyz
Copy link
Contributor Author

Nerixyz commented Jul 17, 2025

@DavidSpickett added the PDB tests here - Is the general approach fine?

@DavidSpickett
Copy link
Collaborator

Yes this is what I was thinking of. Don't go diving into the failures yet, I'll try this on the bot machine first and see if we need other adjustments.

@DavidSpickett
Copy link
Collaborator

I ran this on Linaro's bot machine and got these results:

********************
Unresolved Tests (5):
  lldb-api :: functionalities/data-formatter/data-formatter-stl/generic/string/TestDataFormatterStdString.py
  lldb-api :: lang/c/vla/TestVLA.py
  lldb-api :: python_api/frame/get-variables/TestGetVariables.py
  lldb-api :: python_api/process/TestProcessAPI.py
  lldb-api :: tools/lldb-dap/commands/TestDAP_commands.py

********************
Failed Tests (119):
  lldb-api :: commands/dwim-print/TestDWIMPrint.py
  lldb-api :: commands/expression/anonymous-struct/TestCallUserAnonTypedef.py
  lldb-api :: commands/expression/argument_passing_restrictions/TestArgumentPassingRestrictions.py
  lldb-api :: commands/expression/call-function/TestCallStdStringFunction.py
  lldb-api :: commands/expression/call-function/TestCallStopAndContinue.py
  lldb-api :: commands/expression/call-function/TestCallUserDefinedFunction.py
  lldb-api :: commands/expression/char/TestExprsChar.py
  lldb-api :: commands/expression/class_template_specialization_empty_pack/TestClassTemplateSpecializationParametersHandling.py
  lldb-api :: commands/expression/codegen-crash-typedefdecl-not-in_declcontext/TestCodegenCrashTypedefDeclNotInDeclContext.py
  lldb-api :: commands/expression/context-object/TestContextObject.py
  lldb-api :: commands/expression/deleting-implicit-copy-constructor/TestDeletingImplicitCopyConstructor.py
  lldb-api :: commands/expression/diagnostics/TestExprDiagnostics.py
  lldb-api :: commands/expression/expr_inside_lambda/TestExprInsideLambdas.py
  lldb-api :: commands/expression/formatters/TestFormatters.py
  lldb-api :: commands/expression/import_base_class_when_class_has_derived_member/TestImportBaseClassWhenClassHasDerivedMember.py
  lldb-api :: commands/expression/inline-namespace/TestInlineNamespace.py
  lldb-api :: commands/expression/namespace-alias/TestInlineNamespaceAlias.py
  lldb-api :: commands/expression/nested/TestNestedExpressions.py
  lldb-api :: commands/expression/no-deadlock/TestExprDoesntBlock.py
  lldb-api :: commands/expression/options/TestExprOptions.py
  lldb-api :: commands/expression/pr35310/TestExprsBug35310.py
  lldb-api :: commands/expression/rdar42038760/TestScalarURem.py
  lldb-api :: commands/expression/rdar44436068/Test128BitsInteger.py
  lldb-api :: commands/expression/static-initializers/TestStaticInitializers.py
  lldb-api :: commands/expression/test/TestExprs.py
  lldb-api :: commands/expression/unwind_expression/TestUnwindExpression.py
  lldb-api :: commands/expression/xvalue/TestXValuePrinting.py
  lldb-api :: commands/frame/recognizer/TestFrameRecognizer.py
  lldb-api :: commands/frame/var-dil/basics/NoDebugInfo/TestFrameVarDILNoDebugInfo.py
  lldb-api :: commands/platform/launchgdbserver/TestPlatformLaunchGDBServer.py
  lldb-api :: functionalities/breakpoint/breakpoint_by_line_and_column/TestBreakpointByLineAndColumn.py
  lldb-api :: functionalities/breakpoint/breakpoint_ids/TestBreakpointIDs.py
  lldb-api :: functionalities/breakpoint/breakpoint_language/TestBreakpointLanguage.py
  lldb-api :: functionalities/breakpoint/breakpoint_on_overload/TestBreakOnOverload.py
  lldb-api :: functionalities/breakpoint/breakpoint_options/TestBreakpointOptions.py
  lldb-api :: functionalities/data-formatter/data-formatter-cpp/TestDataFormatterCpp.py
  lldb-api :: functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py
  lldb-api :: functionalities/data-formatter/data-formatter-skip-summary/TestDataFormatterSkipSummary.py
  lldb-api :: functionalities/data-formatter/data-formatter-stl/generic/forward_list/TestDataFormatterGenericForwardList.py
  lldb-api :: functionalities/data-formatter/data-formatter-stl/generic/list/TestDataFormatterGenericList.py
  lldb-api :: functionalities/data-formatter/data-formatter-stl/generic/shared_ptr/TestDataFormatterStdSharedPtr.py
  lldb-api :: functionalities/data-formatter/data-formatter-stl/generic/tuple/TestDataFormatterStdTuple.py
  lldb-api :: functionalities/data-formatter/data-formatter-stl/generic/u8string/TestDataFormatterStdU8String.py
  lldb-api :: functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/TestDataFormatterStdUniquePtr.py
  lldb-api :: functionalities/data-formatter/ptr_ref_typedef/TestPtrRef2Typedef.py
  lldb-api :: functionalities/data-formatter/special-chars/TestSummaryStringSpecialChars.py
  lldb-api :: functionalities/data-formatter/stringprinter/TestStringPrinter.py
  lldb-api :: functionalities/data-formatter/typedef_array/TestTypedefArray.py
  lldb-api :: functionalities/data-formatter/var-in-aggregate-misuse/TestVarInAggregateMisuse.py
  lldb-api :: functionalities/data-formatter/varscript_formatting/TestDataFormatterVarScriptFormatting.py
  lldb-api :: functionalities/data-formatter/vector-types/TestVectorTypesFormatting.py
  lldb-api :: functionalities/inline-stepping/TestInlineStepping.py
  lldb-api :: functionalities/location-list-lookup/TestLocationListLookup.py
  lldb-api :: functionalities/memory/find/TestMemoryFind.py
  lldb-api :: functionalities/multiple-slides/TestMultipleSlides.py
  lldb-api :: functionalities/optimized_code/TestNoASanExceptionAfterEvalOP_piece.py
  lldb-api :: functionalities/return-value/TestReturnValue.py
  lldb-api :: functionalities/target_var/TestTargetVar.py
  lldb-api :: functionalities/type_find_first/TestFindFirstType.py
  lldb-api :: functionalities/type_get_module/TestTypeGetModule.py
  lldb-api :: functionalities/type_types/TestFindTypes.py
  lldb-api :: functionalities/unused-inlined-parameters/TestUnusedInlinedParameters.py
  lldb-api :: lang/c/enum_types/TestEnumTypes.py
  lldb-api :: lang/c/fpeval/TestFPEval.py
  lldb-api :: lang/c/inlines/TestRedefinitionsInInlines.py
  lldb-api :: lang/c/local_variables/TestLocalVariables.py
  lldb-api :: lang/c/set_values/TestSetValues.py
  lldb-api :: lang/c/shared_lib/TestSharedLib.py
  lldb-api :: lang/c/struct_types/TestStructTypes.py
  lldb-api :: lang/c/unicode/TestUnicodeSymbols.py
  lldb-api :: lang/cpp/break-on-initializers/TestBreakOnCPP11Initializers.py
  lldb-api :: lang/cpp/breakpoint-commands/TestCPPBreakpointCommands.py
  lldb-api :: lang/cpp/call-function/TestCallCPPFunction.py
  lldb-api :: lang/cpp/chained-calls/TestCppChainedCalls.py
  lldb-api :: lang/cpp/class-template-parameter-pack/TestClassTemplateParameterPack.py
  lldb-api :: lang/cpp/class-template-parameter-pack/TestTemplatePackArgs.py
  lldb-api :: lang/cpp/class_static/TestStaticVariables.py
  lldb-api :: lang/cpp/const_static_integral_member/TestConstStaticIntegralMember.py
  lldb-api :: lang/cpp/const_static_integral_member_int128/TestConstStaticIntegralMemberInt128.py
  lldb-api :: lang/cpp/constructors/TestCppConstructors.py
  lldb-api :: lang/cpp/dereferencing_references/TestCPPDereferencingReferences.py
  lldb-api :: lang/cpp/enum_promotion/TestCPPEnumPromotion.py
  lldb-api :: lang/cpp/extern_c/TestExternCSymbols.py
  lldb-api :: lang/cpp/forward/TestCPPForwardDeclaration.py
  lldb-api :: lang/cpp/function-qualifiers/TestCppFunctionQualifiers.py
  lldb-api :: lang/cpp/function-ref-qualifiers/TestCppFunctionRefQualifiers.py
  lldb-api :: lang/cpp/global_operators/TestCppGlobalOperators.py
  lldb-api :: lang/cpp/global_variables/TestCPPGlobalVariables.py
  lldb-api :: lang/cpp/incompatible-class-templates/TestCppIncompatibleClassTemplates.py
  lldb-api :: lang/cpp/llvm-style/TestLLVMStyle.py
  lldb-api :: lang/cpp/multiple-inheritance/TestCppMultipleInheritance.py
  lldb-api :: lang/cpp/namespace/TestNamespace.py
  lldb-api :: lang/cpp/namespace/TestNamespaceLookup.py
  lldb-api :: lang/cpp/namespace_conflicts/TestNamespaceConflicts.py
  lldb-api :: lang/cpp/nested-template/TestNestedTemplate.py
  lldb-api :: lang/cpp/nsimport/TestCppNsImport.py
  lldb-api :: lang/cpp/operators/TestCppOperators.py
  lldb-api :: lang/cpp/overloaded-functions/TestOverloadedFunctions.py
  lldb-api :: lang/cpp/preferred_name/TestPreferredName.py
  lldb-api :: lang/cpp/rvalue-references/TestRvalueReferences.py
  lldb-api :: lang/cpp/static_methods/TestCPPStaticMethods.py
  lldb-api :: lang/cpp/step-through-trampoline/TestStepThroughTrampoline.py
  lldb-api :: lang/cpp/stl/TestSTL.py
  lldb-api :: lang/cpp/structured-binding/TestStructuredBinding.py
  lldb-api :: lang/cpp/template-specialization-type/TestTemplateSpecializationType.py
  lldb-api :: lang/cpp/template/TestTemplateArgs.py
  lldb-api :: lang/cpp/type_lookup/TestCppTypeLookup.py
  lldb-api :: lang/cpp/type_lookup_duplicate/TestCppTypeLookupDuplicate.py
  lldb-api :: lang/cpp/typedef-to-outer-fwd/TestTypedefToOuterFwd.py
  lldb-api :: lang/cpp/typedef/TestCppTypedef.py
  lldb-api :: lang/cpp/unique-types2/TestUniqueTypes2.py
  lldb-api :: lang/cpp/unsigned_types/TestUnsignedTypes.py
  lldb-api :: lang/mixed/TestMixedLanguages.py
  lldb-api :: macosx/duplicate-archive-members/TestDuplicateMembers.py
  lldb-api :: python_api/frame/inlines/TestInlinedFrame.py
  lldb-api :: python_api/sbmodule/FindTypes/TestSBModuleFindTypes.py
  lldb-api :: python_api/target/TestTargetAPI.py
  lldb-api :: python_api/thread/TestThreadAPI.py
  lldb-api :: python_api/type/TestTypeList.py

********************
Unexpectedly Passed Tests (2):
  lldb-api :: lang/cpp/function_refs/TestFunctionRefs.py
  lldb-api :: lang/cpp/reference-to-outer-type/TestCppReferenceToOuterClass.py


Testing Time: 801.33s

Total Discovered Tests: 1288
  Unsupported        : 670 (52.02%)
  Passed             : 482 (37.42%)
  Expectedly Failed  :  10 (0.78%)
  Unresolved         :   5 (0.39%)
  Failed             : 119 (9.24%)
  Unexpectedly Passed:   2 (0.16%)

Draft, because there are about 120 failed tests I need to check.

So if you are on Windows X64, then it's a good sign we got similar results on Windows on Arm. A couple of those are random timeouts unrelated to PDB, so it's not exactly the same.

Unfortunately I don't have time to go digging into them myself, so I am thinking about a sustainable way forward for what you want to do.

One idea is to opt-in tests to being run with PDB. This means you can do that for your formatter changes, which keeps reviewers happy. The other stuff we open an issue for the problem that forcing PDB breaks a bunch of existing tests.

I like what you're doing with the formatters and don't want to derail you from that.

@DavidSpickett
Copy link
Collaborator

Opened #149498 so you can refer to it.

I think it's a reasonable pitch to say:

  • Formatters that work with PDB are a good idea.
  • If we opt-in those formatters for testing using PDB, they will be run on at least Linaro's Windows on Arm bot, maybe the x86 one too.
  • One day we might clean up the rest, and by we I mean future people who may or may not be us :)

@Nerixyz
Copy link
Contributor Author

Nerixyz commented Jul 18, 2025

I made it opt-in now. A test can set TEST_WITH_PDB_DEBUG_INFO = True. Unfortunately, all STL tests currently fail. Most of this is because the demangled name in the native PDB parser has spaces at different positions than the DIA parser which I used before.

I'm not sure if it's possible to test both the native parser and the DIA one, since they're selected by an environment variable.

@Nerixyz Nerixyz marked this pull request as ready for review July 18, 2025 13:58
@Nerixyz Nerixyz requested a review from JDevlieghere as a code owner July 18, 2025 13:58
@llvmbot llvmbot added the lldb label Jul 18, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 18, 2025

@llvm/pr-subscribers-lldb

Author: nerix (Nerixyz)

Changes

From #148554 (comment) - this adds an option for API tests to be run with the native PDB reader on Windows. As there are a lot of failures with PDB, this is an opt-in per test. Once #51933 makes progress, this could be expanded.

To get PDB, -g has to be used on Clang. As far as I know, there's no way to specify something like -gpdb. -gcodeview is the closest, but I don't think it sets the correct linker flags (or something similar) - at least LLDB doesn't have any debug info in that case.

#149498 tracks the (currently) failing tests.


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

4 Files Affected:

  • (modified) lldb/packages/Python/lldbsuite/test/builders/builder.py (+1)
  • (modified) lldb/packages/Python/lldbsuite/test/lldbtest.py (+13)
  • (modified) lldb/packages/Python/lldbsuite/test/test_categories.py (+16-1)
  • (modified) lldb/test/API/lit.cfg.py (+2)
diff --git a/lldb/packages/Python/lldbsuite/test/builders/builder.py b/lldb/packages/Python/lldbsuite/test/builders/builder.py
index ada6f9ff4a54f..2021d348138e6 100644
--- a/lldb/packages/Python/lldbsuite/test/builders/builder.py
+++ b/lldb/packages/Python/lldbsuite/test/builders/builder.py
@@ -255,6 +255,7 @@ def _getDebugInfoArgs(self, debug_info):
             "gmodules": {"MAKE_DSYM": "NO", "MAKE_GMODULES": "YES"},
             "debug_names": {"MAKE_DEBUG_NAMES": "YES"},
             "dwp": {"MAKE_DSYM": "NO", "MAKE_DWP": "YES"},
+            "pdb": {"DEBUG_INFO_FLAG": "-g"},
         }
 
         # Collect all flags, with later options overriding earlier ones
diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py
index 63fadb59a82a1..f1b5e38a1c9ec 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbtest.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py
@@ -1790,6 +1790,11 @@ def no_reason(_):
                         if can_replicate
                     ]
 
+                    # PDB is off by default, because it has a lot of failures right now.
+                    # See llvm.org/pr149498
+                    if original_testcase.TEST_WITH_PDB_DEBUG_INFO:
+                        categories.append("pdb")
+
                 xfail_for_debug_info_cat_fn = getattr(
                     attrvalue, "__xfail_for_debug_info_cat_fn__", no_reason
                 )
@@ -1877,6 +1882,14 @@ class TestBase(Base, metaclass=LLDBTestCaseFactory):
     # test multiple times with various debug info types.
     NO_DEBUG_INFO_TESTCASE = False
 
+    TEST_WITH_PDB_DEBUG_INFO = False
+    """
+    Subclasses can set this to True to test with PDB (native) in addition to
+    the other debug info types. This id off by default because many tests will
+    fail due to missing functionality in PDB.
+    See llvm.org/pr149498.
+    """
+
     def generateSource(self, source):
         template = source + ".template"
         temp = os.path.join(self.getSourceDir(), template)
diff --git a/lldb/packages/Python/lldbsuite/test/test_categories.py b/lldb/packages/Python/lldbsuite/test/test_categories.py
index 1f6e8a78e0c0d..fe475a9f8aef3 100644
--- a/lldb/packages/Python/lldbsuite/test/test_categories.py
+++ b/lldb/packages/Python/lldbsuite/test/test_categories.py
@@ -4,6 +4,7 @@
 
 # System modules
 import sys
+import os
 
 # Third-party modules
 
@@ -12,7 +13,13 @@
 
 # Key: Category name
 # Value: should be used in lldbtest's debug-info replication
-debug_info_categories = {"dwarf": True, "dwo": True, "dsym": True, "gmodules": False}
+debug_info_categories = {
+    "dwarf": True,
+    "dwo": True,
+    "dsym": True,
+    "pdb": False,
+    "gmodules": False,
+}
 
 all_categories = {
     "basic_process": "Basic process execution sniff tests.",
@@ -34,6 +41,7 @@
     "lldb-dap": "Tests for the Debug Adapter Protocol with lldb-dap",
     "llgs": "Tests for the gdb-server functionality of lldb-server",
     "msvcstl": "Test for MSVC STL data formatters",
+    "pdb": "Tests that can be run with PDB debug information",
     "pexpect": "Tests requiring the pexpect library to be available",
     "objc": "Tests related to the Objective-C programming language support",
     "pyapi": "Tests related to the Python API",
@@ -65,6 +73,13 @@ def is_supported_on_platform(category, platform, compiler_path):
         if platform not in ["darwin", "macosx", "ios", "watchos", "tvos", "bridgeos"]:
             return False
         return gmodules.is_compiler_clang_with_gmodules(compiler_path)
+    elif category == "pdb":
+        if platform == "windows":
+            assert (
+                os.environ.get("LLDB_USE_NATIVE_PDB_READER") == "1"
+            ), "Only the native PDB reader is supported"
+            return True
+        return False
     return True
 
 
diff --git a/lldb/test/API/lit.cfg.py b/lldb/test/API/lit.cfg.py
index 83713213ce1fe..5bd15a4b8c60b 100644
--- a/lldb/test/API/lit.cfg.py
+++ b/lldb/test/API/lit.cfg.py
@@ -349,6 +349,8 @@ def delete_module_cache(path):
     for v in ["SystemDrive"]:
         if v in os.environ:
             config.environment[v] = os.environ[v]
+    # Always use the native PDB reader
+    config.environment["LLDB_USE_NATIVE_PDB_READER"] = "1"
 
 # Some steps required to initialize the tests dynamically link with python.dll
 # and need to know the location of the Python libraries. This ensures that we

@Michael137
Copy link
Member

Michael137 commented Jul 18, 2025

I think as a pre-requisite to this we should remove the non-native PDB parser (and anything associated with it). That way we wouldn't need any special environment variable setting etc.

We agreed that the native parser would be the way forward in the last EuroLLVM round-table IIRC (CC @JDevlieghere @labath). I think Jonas had a PR open for it but there were some small test blockers. What was the outcome of that work @JDevlieghere ?

@DavidSpickett
Copy link
Collaborator

#114906 as well.

@JDevlieghere
Copy link
Member

We agreed that the native parser would be the way forward in the last EuroLLVM round-table IIRC (CC @JDevlieghere @labath).

That's right. The problem is that neither implementation is complete, and things only work because there's an automatic fallback. No matter which one you pick, it's going to introduce some regressions. Conceptually, everyone is in agreement that the native parser is the way forward:

  • It means we're not limited to testing PDF support on Windows hosts.
  • It means we have the ability to improve support (we don't have control over DIA).

I think Jonas had a PR open for it but there were some small test blockers. What was the outcome of that work @JDevlieghere ?

Here's the link to that PR: #113647. At the time, removing the DIA implementation caused 72 test failures. Shortly after, @ZequanWu put up some PRs that improved the situation, but I haven't rebased my PR since. Depending on the number of failures, we can reopen the discussion. I totally understand that folks relying on the DIA implementation are hesitant to regress, but I believe it's in the best interest of LLDB.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants