[K/N][tests] Properly look for the lldb executable

Using `lldb` as the executable name relies on `PATH` to find the
debugger. This can make the tests run differently locally and on CI.

Use `Configurables` to find the proper tools location with lldb and
use it instead.

^KT-75874
diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/ComplexCInteropTest.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/ComplexCInteropTest.kt
index e7b856e..c7e4ed3 100644
--- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/ComplexCInteropTest.kt
+++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/ComplexCInteropTest.kt
@@ -430,6 +430,7 @@
         val testKind = when (extras) {
             is TestCase.NoTestRunnerExtras -> TestKind.STANDALONE_NO_TR
             is TestCase.WithTestRunnerExtras -> TestKind.STANDALONE
+            is TestCase.WithLLDBExtras -> error("lldb tests are not supported here")
         }
         val testCase = TestCase(
             id = TestCaseId.Named(testName),
diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/ObjCToKotlinSteppingInLLDBTest.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/ObjCToKotlinSteppingInLLDBTest.kt
index 8d0d28f..f103fed 100644
--- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/ObjCToKotlinSteppingInLLDBTest.kt
+++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/ObjCToKotlinSteppingInLLDBTest.kt
@@ -303,6 +303,7 @@
         )
         val spec = LLDBSessionSpec.parse(lldbSpec)
         val moduleForTestCase = TestModule.Exclusive(testName, emptySet(), emptySet(), emptySet())
+        val lldb = testRunSettings.get<LLDB>()
         val testCase = TestCase(
             id = TestCaseId.Named(testName),
             kind = TestKind.STANDALONE_LLDB,
@@ -312,9 +313,9 @@
             checks = TestRunChecks.Default(testRunSettings.get<Timeouts>().executionTimeout).copy(
                 outputMatcher = spec.let { TestRunCheck.OutputMatcher { output -> spec.checkLLDBOutput(output, testRunSettings.get()) } }
             ),
-            extras = TestCase.NoTestRunnerExtras(
-                "main",
-                arguments = spec.generateCLIArguments(testRunSettings.get<LLDB>().prettyPrinters)
+            extras = TestCase.WithLLDBExtras(
+                lldb = lldb.executable,
+                arguments = spec.generateCLIArguments(lldb.prettyPrinters)
             )
         ).apply { initialize(null, null) }
 
diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/NativeTestSupport.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/NativeTestSupport.kt
index a60dabc..31399d6 100644
--- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/NativeTestSupport.kt
+++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/NativeTestSupport.kt
@@ -101,7 +101,6 @@
                 nativeHome,
                 RegularKotlinNativeClassLoader.kotlinNativeClassLoader,
                 computeBaseDirs(),
-                LLDB(nativeHome),
                 computeReleasedCompiler()
             )
         } as TestProcessSettings
@@ -242,6 +241,7 @@
         output += computeCInterfaceMode(enforcedProperties)
         output += computeXCTestRunner(enforcedProperties, nativeTargets)
         output += computeKlibIrInlinerMode(tags)
+        output += LLDB(nativeHome, nativeTargets)
 
         // Compute tests timeouts with regard to already calculated properties that may affect execution time
         output += computeTimeouts(enforcedProperties, output)
diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/TestCase.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/TestCase.kt
index e818718..c079fb2 100644
--- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/TestCase.kt
+++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/TestCase.kt
@@ -236,11 +236,13 @@
     sealed interface Extras
     class NoTestRunnerExtras(val entryPoint: String? = null, val inputDataFile: File? = null, val arguments: List<String> = emptyList()) : Extras
     class WithTestRunnerExtras(val runnerType: TestRunnerType, val ignoredTests: Set<String> = emptySet()) : Extras
+    class WithLLDBExtras(val lldb: String, val entryPoint: String? = null, val arguments: List<String> = emptyList()) : Extras
 
     init {
         when (kind) {
-            TestKind.STANDALONE_NO_TR, TestKind.STANDALONE_LLDB -> assertTrue(extras is NoTestRunnerExtras)
+            TestKind.STANDALONE_NO_TR -> assertTrue(extras is NoTestRunnerExtras)
             TestKind.REGULAR, TestKind.STANDALONE -> assertTrue(extras is WithTestRunnerExtras)
+            TestKind.STANDALONE_LLDB -> assertTrue(extras is WithLLDBExtras)
         }
     }
 
diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/compilation/TestCompilation.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/compilation/TestCompilation.kt
index 8e46ba1..fb81fde 100644
--- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/compilation/TestCompilation.kt
+++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/compilation/TestCompilation.kt
@@ -655,6 +655,9 @@
             is NoTestRunnerExtras -> extras.entryPoint?.let {
                 add("-entry", it)
             }
+            is WithLLDBExtras -> extras.entryPoint?.let {
+                add("-entry", it)
+            }
             is WithTestRunnerExtras -> {
                 val testDumpFile: File? = if (sourceModules.isEmpty()
                     && dependencies.includedLibraries.isNotEmpty()
@@ -833,7 +836,7 @@
             "-Xbinary=bundleId=com.jetbrains.kotlin.${expectedArtifact.bundleDir.nameWithoutExtension}"
         )
         when (extras) {
-            is NoTestRunnerExtras -> error("XCTest supports only TestRunner extras")
+            is NoTestRunnerExtras, is WithLLDBExtras -> error("XCTest supports only TestRunner extras")
             is WithTestRunnerExtras -> {
                 val testDumpFile: File? = if (sourceModules.isEmpty()
                     && dependencies.includedLibraries.isNotEmpty()
diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/compilation/TestCompilationFactory.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/compilation/TestCompilationFactory.kt
index 32dbace..0de04fe 100644
--- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/compilation/TestCompilationFactory.kt
+++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/compilation/TestCompilationFactory.kt
@@ -80,7 +80,7 @@
                     No
                 else
                     when (extras) {
-                        is NoTestRunnerExtras -> Yes.Regular
+                        is NoTestRunnerExtras, is WithLLDBExtras -> Yes.Regular
                         is WithTestRunnerExtras -> Yes.ForIncludedKlibWithTests(
                             StaticCacheCompilation.Options.ForIncludedLibraryWithTests(expectedExecutableArtifact, extras)
                         )
diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/group/StandardTestCaseGroupProvider.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/group/StandardTestCaseGroupProvider.kt
index b6d94f5..7487975 100644
--- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/group/StandardTestCaseGroupProvider.kt
+++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/group/StandardTestCaseGroupProvider.kt
@@ -254,7 +254,9 @@
                     WithTestRunnerExtras(runnerType = parseTestRunner(registeredDirectives, location))
                 }
                 TestKind.STANDALONE_LLDB -> {
-                    NoTestRunnerExtras(
+                    val lldb = settings.get<LLDB>()
+                    TestCase.WithLLDBExtras(
+                        lldb = lldb.executable,
                         entryPoint = parseEntryPoint(registeredDirectives, location),
                         arguments = lldbSpec!!.generateCLIArguments(settings.get<LLDB>().prettyPrinters)
                     )
diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/runner/BaseTestRunProvider.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/runner/BaseTestRunProvider.kt
index d0dcfb5..465d6f7 100644
--- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/runner/BaseTestRunProvider.kt
+++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/runner/BaseTestRunProvider.kt
@@ -7,6 +7,7 @@
 
 import org.jetbrains.kotlin.konan.test.blackbox.support.TestCase
 import org.jetbrains.kotlin.konan.test.blackbox.support.TestCase.NoTestRunnerExtras
+import org.jetbrains.kotlin.konan.test.blackbox.support.TestCase.WithLLDBExtras
 import org.jetbrains.kotlin.konan.test.blackbox.support.TestKind
 import org.jetbrains.kotlin.konan.test.blackbox.support.TestName
 import org.jetbrains.kotlin.konan.test.blackbox.support.util.TCTestOutputFilter
@@ -33,9 +34,10 @@
         when (testCase.kind) {
             TestKind.STANDALONE_LLDB -> {
                 assertTrue(testName == null)
+                val extras = testCase.extras<WithLLDBExtras>()
                 // Note: TestRunParameter.WithLLDB adds program arguments and would therefore conflict
                 // with other TestRunParameters that do the same (such as WithTCTestLogger).
-                add(TestRunParameter.WithLLDB(testCase.extras<NoTestRunnerExtras>().arguments))
+                add(TestRunParameter.WithLLDB(extras.lldb, extras.arguments))
             }
             TestKind.STANDALONE_NO_TR -> {
                 assertTrue(testName == null)
diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/runner/TestRun.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/runner/TestRun.kt
index ea38158..f1c4825 100644
--- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/runner/TestRun.kt
+++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/runner/TestRun.kt
@@ -120,9 +120,9 @@
         override fun applyTo(programArgs: MutableList<String>) = Unit
     }
 
-    class WithLLDB(val commands: List<String>) : TestRunParameter {
+    class WithLLDB(val lldb: String, val commands: List<String>) : TestRunParameter {
         override fun applyTo(programArgs: MutableList<String>) {
-            programArgs.add(0, "lldb")
+            programArgs.add(0, lldb)
             programArgs.addAll(commands)
         }
     }
diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/runner/TestRunProvider.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/runner/TestRunProvider.kt
index 56af894..849c4e7 100644
--- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/runner/TestRunProvider.kt
+++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/runner/TestRunProvider.kt
@@ -112,11 +112,16 @@
         fun createTestRun(testRunName: String, testName: TestName?) = createTestRun(testCase, executable, testRunName, testName)
 
         when (testCase.kind) {
-            TestKind.STANDALONE_NO_TR, TestKind.STANDALONE_LLDB -> {
+            TestKind.STANDALONE_NO_TR -> {
                 val testRunName = (testCase.extras<NoTestRunnerExtras>().entryPoint ?: "main").substringAfterLast('.')
                 val testRun = createTestRun(testRunName, testName = null)
                 TreeNode.oneLevel(testRun)
             }
+            TestKind.STANDALONE_LLDB -> {
+                val testRunName = (testCase.extras<TestCase.WithLLDBExtras>().entryPoint ?: "main").substringAfterLast('.')
+                val testRun = createTestRun(testRunName, testName = null)
+                TreeNode.oneLevel(testRun)
+            }
             TestKind.REGULAR, TestKind.STANDALONE -> {
                 val testNames = executable.testNames.filterIrrelevant(testCase)
                 testNames.buildTree(TestName::packageName) { testName ->
diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/settings/SettingsContainers.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/settings/SettingsContainers.kt
index b94e64a..523cb2f 100644
--- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/settings/SettingsContainers.kt
+++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/settings/SettingsContainers.kt
@@ -9,6 +9,7 @@
 import org.jetbrains.kotlin.konan.target.Distribution
 import org.jetbrains.kotlin.konan.target.HostManager
 import org.jetbrains.kotlin.konan.target.PlatformManager
+import org.jetbrains.kotlin.konan.test.blackbox.support.util.buildConfigurables
 import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertTrue
 import org.jetbrains.kotlin.test.services.JUnit5Assertions.fail
 import java.net.URLClassLoader
@@ -66,21 +67,14 @@
 class SimpleTestRunSettings(parent: SimpleTestClassSettings, settings: Iterable<Any>) : Settings(parent, settings)
 
 val Settings.configurables: Configurables
-    get() {
-        val distribution = Distribution(
-            get<KotlinNativeHome>().dir.path,
-            // Development variant of LLVM is used to have utilities like FileCheck
-            propertyOverrides = mapOf("llvmHome.${HostManager.hostName}" to "\$llvm.${HostManager.hostName}.dev")
-        )
-        return PlatformManager(distribution).platform(get<KotlinNativeTargets>().testTarget).configurables
-    }
+    get() = buildConfigurables(get<KotlinNativeHome>(), get<KotlinNativeTargets>())
 
 internal fun Settings.withCustomCompiler(compiler: ReleasedCompiler): Settings {
     return object : Settings(
         parent = this,
         settings = listOf(
             compiler.nativeHome,
-            LLDB(compiler.nativeHome),
+            LLDB(compiler.nativeHome, get<KotlinNativeTargets>()),
             KotlinNativeClassLoader(lazyClassLoader = compiler.lazyClassloader),
             PipelineType.DEFAULT,
             GCType.UNSPECIFIED,
diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/settings/TestProcessSettings.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/settings/TestProcessSettings.kt
index 43dda0c..dab0a75 100644
--- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/settings/TestProcessSettings.kt
+++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/settings/TestProcessSettings.kt
@@ -7,6 +7,7 @@
 
 import org.jetbrains.kotlin.config.LanguageVersion
 import org.jetbrains.kotlin.konan.properties.resolvablePropertyList
+import org.jetbrains.kotlin.konan.target.AppleConfigurables
 import org.jetbrains.kotlin.konan.target.Distribution
 import org.jetbrains.kotlin.konan.target.KonanTarget
 import org.jetbrains.kotlin.konan.test.blackbox.support.ClassLevelProperty
@@ -14,6 +15,7 @@
 import org.jetbrains.kotlin.konan.test.blackbox.support.runner.RunnerWithExecutor
 import org.jetbrains.kotlin.konan.test.blackbox.support.runner.NoopTestRunner
 import org.jetbrains.kotlin.konan.test.blackbox.support.runner.Runner
+import org.jetbrains.kotlin.konan.test.blackbox.support.util.buildConfigurables
 import org.jetbrains.kotlin.native.executors.runProcess
 import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertFalse
 import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertTrue
@@ -42,12 +44,21 @@
     }
 }
 
-internal class LLDB(nativeHome: KotlinNativeHome) {
+internal class LLDB(nativeHome: KotlinNativeHome, nativeTargets: KotlinNativeTargets) {
+    val executable: String = buildConfigurables(nativeHome, nativeTargets).let { configurables ->
+        val root = if (configurables is AppleConfigurables) {
+            configurables.absoluteAdditionalToolsDir
+        } else {
+            configurables.absoluteLlvmHome
+        }
+        "$root/bin/lldb"
+    }
+
     val prettyPrinters: File = nativeHome.dir.resolve("tools/konan_lldb.py")
 
     val isAvailable: Boolean by lazy {
         try {
-            val exitCode = ProcessBuilder("lldb", "-version").start().waitFor()
+            val exitCode = ProcessBuilder(executable, "-version").start().waitFor()
             exitCode == 0
         } catch (e: IOException) {
             false
diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/util/Configurables.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/util/Configurables.kt
new file mode 100644
index 0000000..8e318a3
--- /dev/null
+++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/util/Configurables.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.konan.test.blackbox.support.util
+
+import org.jetbrains.kotlin.konan.target.Configurables
+import org.jetbrains.kotlin.konan.target.Distribution
+import org.jetbrains.kotlin.konan.target.HostManager
+import org.jetbrains.kotlin.konan.target.PlatformManager
+import org.jetbrains.kotlin.konan.test.blackbox.support.settings.KotlinNativeHome
+import org.jetbrains.kotlin.konan.test.blackbox.support.settings.KotlinNativeTargets
+
+fun buildConfigurables(home: KotlinNativeHome, targets: KotlinNativeTargets): Configurables {
+    val distribution = Distribution(
+        home.dir.path,
+        // Development variant of LLVM is used to have utilities like FileCheck
+        propertyOverrides = mapOf("llvmHome.${HostManager.hostName}" to "\$llvm.${HostManager.hostName}.dev")
+    )
+    return PlatformManager(distribution).platform(targets.testTarget).configurables
+}
\ No newline at end of file