rea-agents 6.0.0 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (611) hide show
  1. package/README.md +26 -18
  2. package/bridge/android/ReaJadxBridge.java +14 -5
  3. package/bridge/ghidra/ReaGhidraBridge.java +205 -51
  4. package/bridge/hopper_bridge.py +314 -127
  5. package/bridge/mitmproxy/capture.py +0 -2
  6. package/bridge/native/rea_lldb_tracer.py +630 -94
  7. package/bridge/process/ProcessRunTokenReader.swift +39 -5
  8. package/bridge/pwntools/recorded_crash_impl.py +4 -0
  9. package/dist/android/JadxConfiguration.js +274 -31
  10. package/dist/android/JadxMcpTransport.js +18 -2
  11. package/dist/android/JadxProtocol.js +6 -0
  12. package/dist/android/JadxProvider.js +76 -37
  13. package/dist/android/JadxSession.js +23 -4
  14. package/dist/application/AnalysisContextQueries.js +8 -35
  15. package/dist/application/AnalysisDocument.js +32 -0
  16. package/dist/application/AppBundleExecutable.js +67 -21
  17. package/dist/application/BinaryTargetResolver.js +5 -3
  18. package/dist/application/BrowserEvidence.js +3 -8
  19. package/dist/application/BrowserScenarioEvidence.js +2 -18
  20. package/dist/application/CallPathTracing.js +19 -3
  21. package/dist/application/CapabilityInventory.js +48 -11
  22. package/dist/application/ClientConfigurationDocument.js +917 -8
  23. package/dist/application/ClientRegistrationIdentity.js +26 -5
  24. package/dist/application/ClientRegistrationStatus.js +29 -14
  25. package/dist/application/DirectAnalysis.js +56 -51
  26. package/dist/application/DirectAnalysisCleanup.js +72 -0
  27. package/dist/application/DirectAnalysisStatus.js +4 -5
  28. package/dist/application/Doctor.js +19 -21
  29. package/dist/application/DoctorDiagnostics.js +1 -2
  30. package/dist/application/DoctorScope.js +25 -13
  31. package/dist/application/EnhancedLiteralTracing.js +22 -25
  32. package/dist/application/EnhancedTools.js +64 -17
  33. package/dist/application/EvidenceBundleFiles.js +30 -13
  34. package/dist/application/FunctionAnalysisEvidence.js +2 -3
  35. package/dist/application/InventoryProjectionEvidence.js +4 -3
  36. package/dist/application/InvestigationProviders.js +11 -2
  37. package/dist/application/JsonFiles.js +83 -28
  38. package/dist/application/LinuxHopper.js +9 -6
  39. package/dist/application/MacHopper.js +15 -18
  40. package/dist/application/ProcedureAddressResolution.js +11 -0
  41. package/dist/application/RealHopperAssertions.js +0 -11
  42. package/dist/application/ReconstructionCoverageService.js +7 -4
  43. package/dist/application/ReconstructionObligationCandidates.js +1 -1
  44. package/dist/application/ReconstructionObligationLedgerService.js +4 -3
  45. package/dist/application/ReferenceSourceImportEntries.js +1 -1
  46. package/dist/application/Setup.js +21 -17
  47. package/dist/application/SetupClientConfiguration.js +10 -15
  48. package/dist/application/SetupHost.js +21 -29
  49. package/dist/application/SetupPlan.js +11 -9
  50. package/dist/application/SupportedClients.js +34 -1
  51. package/dist/application/Uninstall.js +82 -29
  52. package/dist/application/Update.js +18 -3
  53. package/dist/application/UpdateMaintenance.js +7 -5
  54. package/dist/application/UpdateRuntime.js +57 -36
  55. package/dist/application/WebModuleTraceService.js +4 -2
  56. package/dist/application/WebNetworkCaptureService.js +4 -2
  57. package/dist/application/WebRuntimeService.js +5 -3
  58. package/dist/application/WebScriptExportService.js +32 -6
  59. package/dist/application/WebSourceLocationService.js +4 -2
  60. package/dist/application/WorkflowEvidence.js +105 -0
  61. package/dist/application/XrefsAddressResolution.js +45 -0
  62. package/dist/application/analysisView/AnalysisViewService.js +76 -0
  63. package/dist/application/binary/AnalysisClientCleanup.js +30 -5
  64. package/dist/application/binary/AnalysisProviderEvaluation.js +22 -7
  65. package/dist/application/binary/AnalysisProviderRegistry.js +4 -6
  66. package/dist/application/binary/AnalysisSnapshotCache.js +13 -14
  67. package/dist/application/binary/BinarySession.js +161 -93
  68. package/dist/application/binary/BinarySessionComposition.js +1 -3
  69. package/dist/application/binary/BinarySessionExecution.js +3 -5
  70. package/dist/application/binary/BinarySessionOpen.js +4 -4
  71. package/dist/application/binary/BinarySessionRecords.js +26 -4
  72. package/dist/application/binary/BinarySessionStatus.js +18 -7
  73. package/dist/application/binary/CompositeProvider.js +16 -17
  74. package/dist/application/binary/LazyAnalysisProvider.js +8 -5
  75. package/dist/application/binary/SessionProviderRouter.js +27 -135
  76. package/dist/application/binaryDiagnostics/BinaryLayoutService.js +4 -2
  77. package/dist/application/binaryDiagnostics/RecordedCrashService.js +4 -2
  78. package/dist/application/evm/EvmInterfaceService.js +4 -2
  79. package/dist/application/homebrew.js +48 -0
  80. package/dist/application/investigation/EvidenceLedger.js +21 -7
  81. package/dist/application/investigation/InvestigationRecords.js +8 -0
  82. package/dist/application/javascript/ElectronActiveEvidence.js +9 -13
  83. package/dist/application/javascript/JavaScriptAnalysisControl.js +34 -0
  84. package/dist/application/javascript/JavaScriptApplicationEvidence.js +21 -4
  85. package/dist/application/javascript/JavaScriptApplicationEvidenceGraph.js +19 -2
  86. package/dist/application/javascript/JavaScriptApplicationService.js +27 -15
  87. package/dist/application/javascript/JavaScriptApplicationWorkflowService.js +5 -5
  88. package/dist/application/javascript/JavaScriptArtifactAnalysis.js +10 -7
  89. package/dist/application/javascript/JavaScriptArtifactGraphBuilder.js +44 -10
  90. package/dist/application/javascript/JavaScriptArtifactGraphBundlers.js +11 -3
  91. package/dist/application/javascript/JavaScriptArtifactGraphContext.js +9 -0
  92. package/dist/application/javascript/JavaScriptArtifactGraphDocuments.js +8 -5
  93. package/dist/application/javascript/JavaScriptArtifactGraphFindings.js +12 -3
  94. package/dist/application/javascript/JavaScriptArtifactGraphStructure.js +0 -1
  95. package/dist/application/javascript/JavaScriptArtifactPathResolution.js +49 -19
  96. package/dist/application/javascript/JavaScriptArtifactReconstruction.js +56 -8
  97. package/dist/application/javascript/JavaScriptModuleRelationships.js +38 -9
  98. package/dist/application/javascript/JavaScriptRecoveryService.js +4 -2
  99. package/dist/application/javascript/JavaScriptRuntimeObservationService.js +6 -4
  100. package/dist/application/javascript/JavaScriptRuntimeReconciliationService.js +3 -3
  101. package/dist/application/javascript/JavaScriptSemanticGraphAsyncProjection.js +2 -3
  102. package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +63 -61
  103. package/dist/application/javascript/JavaScriptSemanticGraphChildProcessProjection.js +1 -2
  104. package/dist/application/javascript/JavaScriptSemanticGraphDataProjection.js +2 -3
  105. package/dist/application/javascript/JavaScriptSemanticGraphFlowProjection.js +1 -5
  106. package/dist/application/javascript/JavaScriptSemanticGraphObjectProjection.js +75 -46
  107. package/dist/application/javascript/JavaScriptSemanticGraphResourceProjection.js +2 -3
  108. package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +64 -19
  109. package/dist/application/managed/ManagedApplicationGraphService.js +4 -3
  110. package/dist/application/managed/ManagedMemberComparisonService.js +9 -5
  111. package/dist/application/managed/ManagedNativeVerificationService.js +6 -4
  112. package/dist/application/managed/ManagedReconstructionService.js +4 -3
  113. package/dist/application/process/ProcessCli.js +25 -17
  114. package/dist/application/process/ProcessEvidence.js +4 -4
  115. package/dist/application/workflowInputError.js +18 -0
  116. package/dist/artifacts/ArtifactProvider.js +48 -13
  117. package/dist/artifacts/ArtifactReader.js +31 -0
  118. package/dist/artifacts/DirectoryArtifactReader.js +2 -1
  119. package/dist/artifacts/MachOSliceArtifactReader.js +106 -15
  120. package/dist/artifacts/NativeDmgArtifactReader.js +73 -21
  121. package/dist/artifacts/SafeOutputTree.js +16 -2
  122. package/dist/artifacts/ZipArtifactReader.js +11 -4
  123. package/dist/artifacts/apple/AppleAssetCatalogAnalysis.js +26 -5
  124. package/dist/artifacts/apple/DylibResolutionReader.js +17 -7
  125. package/dist/artifacts/apple/InterfaceBuilderAnalysis.js +176 -56
  126. package/dist/artifacts/apple/InterfaceBuilderDecodeBudget.js +195 -0
  127. package/dist/artifacts/apple/KeyedArchiveReader.js +55 -23
  128. package/dist/artifacts/apple/MachoLoadCommandReader.js +92 -31
  129. package/dist/artifacts/apple/NibArchive.js +81 -14
  130. package/dist/artifacts/apple/NibViewHierarchy.js +10 -3
  131. package/dist/artifacts/apple/PlistNumberLiterals.js +164 -0
  132. package/dist/artifacts/extraction/ArtifactExtraction.js +78 -21
  133. package/dist/artifacts/inventory/ArtifactGraphConstruction.js +79 -68
  134. package/dist/artifacts/inventory/ArtifactInventory.js +0 -1
  135. package/dist/artifacts/inventory/reader.js +3 -3
  136. package/dist/artifacts/inventory/scanCanonical.js +59 -38
  137. package/dist/artifacts/inventory/scanReader.js +5 -9
  138. package/dist/artifacts/javascript/JavaScriptArtifactFiles.js +6 -2
  139. package/dist/browser/BrowserScenarioPartialObservation.js +106 -0
  140. package/dist/browser/CdpBrowserProvider.js +2 -3
  141. package/dist/browser/CdpCaptureCompleteness.js +2 -0
  142. package/dist/browser/CdpCaptureEventHandlers.js +78 -15
  143. package/dist/browser/CdpCaptureEventTypes.js +5 -1
  144. package/dist/browser/CdpCaptureEvents.js +25 -1
  145. package/dist/browser/CdpCaptureValues.js +20 -0
  146. package/dist/browser/CdpConnection.js +30 -11
  147. package/dist/browser/CdpElectronProvider.js +0 -2
  148. package/dist/browser/CdpElectronScriptEvents.js +2 -8
  149. package/dist/browser/CdpElectronScripts.js +2 -3
  150. package/dist/browser/CdpOptionalCommand.js +2 -3
  151. package/dist/browser/CdpPageCapture.js +23 -1
  152. package/dist/browser/CdpPageCaptureScripts.js +2 -3
  153. package/dist/browser/CdpSafeMetadata.js +10 -10
  154. package/dist/browser/PlaywrightBrowserScenarioProvider.js +59 -44
  155. package/dist/browser/PlaywrightElectronActiveActions.js +34 -79
  156. package/dist/browser/PlaywrightElectronActiveProjection.js +141 -0
  157. package/dist/browser/PlaywrightElectronActiveProvider.js +133 -130
  158. package/dist/browser/PlaywrightScenarioArtifacts.js +1 -1
  159. package/dist/browser/PlaywrightScenarioBrowser.js +139 -39
  160. package/dist/browser/PlaywrightScenarioEvents.js +1 -1
  161. package/dist/browser/PlaywrightScenarioSession.js +39 -22
  162. package/dist/browser/WebSourceMapFetcher.js +426 -72
  163. package/dist/browser/assets/LocalWebScriptArtifacts.js +2 -2
  164. package/dist/browser/assets/ScriptCaptureAdapters.js +1 -1
  165. package/dist/browser/history/CaptureFailures.js +41 -1
  166. package/dist/browser/history/CaptureRelease.js +5 -0
  167. package/dist/browser/history/HarCaptureAdapter.js +3 -3
  168. package/dist/browser/history/HarJson.js +3 -2
  169. package/dist/browser/history/HistoricalCaptureDecoder.js +4 -2
  170. package/dist/browser/history/MitmproxyCaptureAdapter.js +4 -2
  171. package/dist/catalogIdentity.js +0 -1
  172. package/dist/cli/analysisSelector.js +23 -0
  173. package/dist/cli/analysisViewCommands.js +36 -0
  174. package/dist/cli/applicationCommands.js +2 -3
  175. package/dist/cli/artifactCommands.js +11 -12
  176. package/dist/cli/coreAnalysisCommands.js +3 -3
  177. package/dist/cli/coreBinaryCommands.js +100 -37
  178. package/dist/cli/coreNativeCommands.js +9 -10
  179. package/dist/cli/electronCommands.js +10 -9
  180. package/dist/cli/interactiveSetup.js +6 -6
  181. package/dist/cli/javascriptApplicationAnalysis.js +7 -3
  182. package/dist/cli/jsonOutput.js +4 -99
  183. package/dist/cli/managedCommands.js +7 -8
  184. package/dist/cli/nativeCallCommands.js +3 -5
  185. package/dist/cli/omittableDefaults.js +50 -0
  186. package/dist/cli/processCommands.js +3 -2
  187. package/dist/cli/setupCommands.js +16 -15
  188. package/dist/cli/utilityCommands.js +9 -9
  189. package/dist/cli/webRuntimeCommands.js +8 -8
  190. package/dist/cli.js +18 -9
  191. package/dist/cliBrowserScenarioCommands.js +2 -2
  192. package/dist/cliCommandNames.js +1 -1
  193. package/dist/cliJsonInput.js +24 -5
  194. package/dist/cliOutput.js +0 -38
  195. package/dist/composition/auxiliaryAnalysisProviders.js +27 -23
  196. package/dist/composition/binary.js +9 -9
  197. package/dist/composition/browserScenario.js +2 -1
  198. package/dist/composition/directAnalysis.js +20 -13
  199. package/dist/composition/electronScenario.js +1 -1
  200. package/dist/composition/optionalObservationProviders.js +12 -7
  201. package/dist/config/environment.js +10 -0
  202. package/dist/config/ghidraStartupTimeout.js +12 -0
  203. package/dist/config/homeDirectory.js +12 -0
  204. package/dist/config/mcpResponseBudget.js +30 -0
  205. package/dist/config/parseConfig.js +8 -3
  206. package/dist/config/parsers.js +19 -22
  207. package/dist/contracts/analysisViewToolContracts.js +56 -0
  208. package/dist/contracts/applicationToolContracts.js +5 -4
  209. package/dist/contracts/artifactComparisonExample.js +2 -2
  210. package/dist/contracts/artifactToolContracts.js +1 -1
  211. package/dist/contracts/browserScenarioToolContracts.js +1 -1
  212. package/dist/contracts/browserToolContracts.js +19 -15
  213. package/dist/contracts/enhancedInputs.js +7 -5
  214. package/dist/contracts/enhancedToolContracts.js +7 -6
  215. package/dist/contracts/evm/evmToolContracts.js +1 -1
  216. package/dist/contracts/functionWorkflowToolContracts.js +1 -1
  217. package/dist/contracts/hopperMemoryContracts.js +2 -5
  218. package/dist/contracts/inputSchemaPresentation.js +90 -0
  219. package/dist/contracts/investigationExamples.js +4 -3
  220. package/dist/contracts/javascript/electronToolContracts.js +2 -2
  221. package/dist/contracts/javascript/javascriptApplicationWorkflowExamples.js +0 -20
  222. package/dist/contracts/javascript/javascriptExportShapeComparisonExample.js +245 -0
  223. package/dist/contracts/javascript/javascriptRuntimeObservationToolContracts.js +1 -1
  224. package/dist/contracts/managed/managedToolContracts.js +7 -14
  225. package/dist/contracts/managed/managedWorkflowToolContracts.js +1 -1
  226. package/dist/contracts/mobileApplicationGraphExamples.js +3 -3
  227. package/dist/contracts/native/binaryDiagnosticsToolContracts.js +1 -1
  228. package/dist/contracts/native/nativeToolContracts.js +5 -3
  229. package/dist/contracts/officialToolContracts.js +16 -16
  230. package/dist/contracts/promptContracts.js +5 -5
  231. package/dist/contracts/providerSelection.js +1 -1
  232. package/dist/contracts/sessionLifecycleInputs.js +3 -7
  233. package/dist/contracts/sessionStatusContract.js +2 -4
  234. package/dist/contracts/sessionToolContracts.js +18 -8
  235. package/dist/contracts/sessionToolSchemas.js +3 -19
  236. package/dist/contracts/toolContractExamples.js +0 -1
  237. package/dist/contracts/toolContractHelpers.js +4 -1
  238. package/dist/contracts/toolContracts.js +2 -0
  239. package/dist/contracts/toolEffects.js +1 -1
  240. package/dist/contracts/toolOutputSchemaGroups.js +160 -115
  241. package/dist/contracts/toolOutputSchemaPrimitives.js +28 -20
  242. package/dist/contracts/toolSchemaMetadata.js +41 -33
  243. package/dist/contracts/webNetworkCaptureToolContracts.js +2 -2
  244. package/dist/contracts/webRuntimeToolContracts.js +1 -1
  245. package/dist/contracts/webScriptToolContracts.js +1 -1
  246. package/dist/doctorRuntime.js +7 -5
  247. package/dist/domain/analysisErrorBase.js +8 -3
  248. package/dist/domain/analysisErrorCore.js +6 -1
  249. package/dist/domain/analysisErrorPresentation.js +90 -20
  250. package/dist/domain/analysisErrorProjection.js +130 -32
  251. package/dist/domain/analysisSnapshot.js +29 -31
  252. package/dist/domain/analysisView/analysisView.js +243 -0
  253. package/dist/domain/analysisView/analysisViewCoverage.js +19 -0
  254. package/dist/domain/analysisView/binaryLayoutView.js +159 -0
  255. package/dist/domain/analysisView/javascriptApplicationView.js +238 -0
  256. package/dist/domain/android/androidAnalysis.js +2 -4
  257. package/dist/domain/android/androidApplication.js +18 -10
  258. package/dist/domain/apple/appleApplication.js +42 -15
  259. package/dist/domain/apple/dyldEnvironment.js +73 -0
  260. package/dist/domain/apple/dylibResolution.js +130 -12
  261. package/dist/domain/apple/dylibResolutionFindings.js +9 -7
  262. package/dist/domain/apple/interfaceBuilderGraph.js +25 -14
  263. package/dist/domain/apple/interfaceBuilderKeyedArchive.js +13 -3
  264. package/dist/domain/apple/keyedArchive.js +35 -3
  265. package/dist/domain/apple/machoContainer.js +54 -0
  266. package/dist/domain/apple/plistNumbers.js +76 -0
  267. package/dist/domain/artifactComparison.js +15 -6
  268. package/dist/domain/artifactGraph.js +16 -3
  269. package/dist/domain/artifactIdentity.js +29 -0
  270. package/dist/domain/artifactInventoryEvidence.js +28 -40
  271. package/dist/domain/artifactOperationError.js +3 -3
  272. package/dist/domain/artifactPartialObservation.js +1 -0
  273. package/dist/domain/artifactPathSyntax.js +49 -0
  274. package/dist/domain/binaryTarget.js +39 -13
  275. package/dist/domain/bridgeCandidateProjection.js +71 -0
  276. package/dist/domain/browserCaptureComparison.js +13 -49
  277. package/dist/domain/browserCompleteness.js +1 -0
  278. package/dist/domain/browserNetworkEvidence.js +10 -4
  279. package/dist/domain/browserObservation.js +0 -1
  280. package/dist/domain/browserObservationError.js +24 -5
  281. package/dist/domain/browserObservationSchemas.js +14 -3
  282. package/dist/domain/browserScenario.js +0 -1
  283. package/dist/domain/browserScenarioCapture.js +1 -2
  284. package/dist/domain/browserScenarioDiff.js +0 -2
  285. package/dist/domain/browserScenarioDiffEvidence.js +0 -12
  286. package/dist/domain/browserScenarioDiffValues.js +2 -2
  287. package/dist/domain/browserScenarioValues.js +5 -10
  288. package/dist/domain/bundleComparison.js +3 -2
  289. package/dist/domain/callPath.js +8 -9
  290. package/dist/domain/callPathSchemas.js +2 -2
  291. package/dist/domain/canonicalJsonDigestSteps.js +133 -0
  292. package/dist/domain/canonicalOrdering.js +9 -5
  293. package/dist/domain/changedBehavior.js +9 -9
  294. package/dist/domain/comparisonSourceEvidence.js +40 -0
  295. package/dist/domain/completionLedgerGeneration.js +2 -1
  296. package/dist/domain/configurationErrors.js +13 -1
  297. package/dist/domain/conformancePackage.js +4 -3
  298. package/dist/domain/evidence.js +65 -36
  299. package/dist/domain/evidenceBundle.js +47 -8
  300. package/dist/domain/evidenceCompletionLedger.js +2 -1
  301. package/dist/domain/evidenceErrors.js +12 -1
  302. package/dist/domain/explicitSensitiveFailure.js +17 -1
  303. package/dist/domain/firmware/firmwareAnalysis.js +6 -7
  304. package/dist/domain/functionComparison.js +4 -5
  305. package/dist/domain/functionComparisonDimensions.js +120 -87
  306. package/dist/domain/functionComparisonNormalization.js +23 -34
  307. package/dist/domain/functionComparisonResults.js +1 -4
  308. package/dist/domain/functionComparisonSchemas.js +2 -8
  309. package/dist/domain/functionDossierEvidence.js +2 -37
  310. package/dist/domain/hopperErrors.js +23 -2
  311. package/dist/domain/hopperValues.js +51 -8
  312. package/dist/domain/immutableJson.js +114 -0
  313. package/dist/domain/inputIssueProjection.js +3 -0
  314. package/dist/domain/javascript/electronActiveObservation.js +47 -64
  315. package/dist/domain/javascript/electronObservation.js +14 -3
  316. package/dist/domain/javascript/electronStaticAnalysisBrowser.js +10 -9
  317. package/dist/domain/javascript/electronStaticAnalysisIpc.js +2 -1
  318. package/dist/domain/javascript/electronStaticAnalysisNative.js +2 -1
  319. package/dist/domain/javascript/electronStaticAnalysisValues.js +6 -12
  320. package/dist/domain/javascript/javascriptApplicationAnalysis.js +71 -23
  321. package/dist/domain/javascript/javascriptApplicationEvidenceSchemas.js +2 -0
  322. package/dist/domain/javascript/javascriptApplicationGraph.js +39 -3
  323. package/dist/domain/javascript/javascriptApplicationGraphSchemas.js +9 -2
  324. package/dist/domain/javascript/javascriptApplicationVersionItems.js +5 -2
  325. package/dist/domain/javascript/javascriptApplicationVersionKeys.js +2 -1
  326. package/dist/domain/javascript/javascriptAstValues.js +20 -0
  327. package/dist/{application/javascript/JavaScriptReturnShapeProjection.js → domain/javascript/javascriptExportReturnShapeProjection.js} +4 -4
  328. package/dist/domain/javascript/javascriptExportShapeComparison.js +7 -1
  329. package/dist/domain/javascript/javascriptExportShapeComparisonIdentity.js +6 -1
  330. package/dist/domain/javascript/javascriptExportShapeComparisonSchemas.js +29 -1
  331. package/dist/domain/javascript/javascriptExportShapeSelection.js +5 -5
  332. package/dist/domain/javascript/javascriptExportShapeVariants.js +67 -14
  333. package/dist/domain/javascript/javascriptFeatureSeed.js +20 -0
  334. package/dist/domain/javascript/javascriptFeatureTraversal.js +0 -1
  335. package/dist/domain/javascript/javascriptNativeHandoff.js +1 -1
  336. package/dist/domain/javascript/javascriptRecovery.js +3 -8
  337. package/dist/domain/javascript/javascriptRuntimeLoadState.js +0 -1
  338. package/dist/domain/javascript/javascriptRuntimeObservation.js +10 -2
  339. package/dist/domain/javascript/javascriptRuntimeReconciliationMatching.js +1 -1
  340. package/dist/domain/javascript/javascriptRuntimeReconciliationParsing.js +3 -2
  341. package/dist/domain/javascript/javascriptRuntimeStaticCandidates.js +0 -1
  342. package/dist/domain/javascript/javascriptSemanticAnalysis.js +106 -5
  343. package/dist/domain/javascript/javascriptSemanticAsyncEffects.js +2 -1
  344. package/dist/domain/javascript/javascriptSemanticCalls.js +2 -1
  345. package/dist/domain/javascript/javascriptSemanticChildProcesses.js +2 -1
  346. package/dist/domain/javascript/javascriptSemanticCoverage.js +6 -5
  347. package/dist/domain/javascript/javascriptSemanticDataEffectHelpers.js +9 -17
  348. package/dist/domain/javascript/javascriptSemanticDataEffects.js +23 -6
  349. package/dist/domain/javascript/javascriptSemanticGraph.js +98 -43
  350. package/dist/domain/javascript/javascriptSemanticGraphSchemas.js +1 -0
  351. package/dist/domain/javascript/javascriptSemanticMemberMutations.js +77 -20
  352. package/dist/domain/javascript/javascriptSemanticMutationValues.js +21 -27
  353. package/dist/domain/javascript/javascriptSemanticObjects.js +83 -42
  354. package/dist/domain/javascript/javascriptSemanticPrimitives.js +18 -21
  355. package/dist/domain/javascript/javascriptSemanticProjection.js +2 -3
  356. package/dist/domain/javascript/javascriptSemanticPromises.js +2 -1
  357. package/dist/domain/javascript/javascriptSemanticQuerySchemas.js +8 -4
  358. package/dist/domain/javascript/javascriptSemanticResourceLimits.js +77 -0
  359. package/dist/domain/javascript/javascriptSemanticResources.js +1 -1
  360. package/dist/domain/javascript/javascriptSemanticReturns.js +32 -17
  361. package/dist/domain/javascript/javascriptSemanticSlots.js +72 -0
  362. package/dist/domain/javascript/javascriptSemanticValues.js +126 -61
  363. package/dist/domain/javascript/javascriptSourceMapPaths.js +104 -0
  364. package/dist/domain/javascript/javascriptSourceParser.js +6 -2
  365. package/dist/domain/javascript/javascriptStaticAnalysis.js +22 -17
  366. package/dist/domain/javascript/javascriptStaticAnalysisBundler.js +5 -3
  367. package/dist/domain/javascript/javascriptStaticAnalysisCalls.js +16 -5
  368. package/dist/domain/javascript/javascriptStaticAnalysisFindings.js +66 -7
  369. package/dist/domain/javascript/javascriptStaticAnalysisHelpers.js +28 -17
  370. package/dist/domain/javascript/javascriptStaticAnalysisState.js +3 -2
  371. package/dist/domain/javascript/sourceToBundleComparison.js +12 -3
  372. package/dist/domain/javascript/sourceToBundleSignals.js +47 -19
  373. package/dist/domain/jsonSerialization.js +109 -0
  374. package/dist/domain/jsonValue.js +90 -6
  375. package/dist/domain/localPath.js +6 -0
  376. package/dist/domain/managed/managedApplicationGraph.js +10 -10
  377. package/dist/domain/managed/managedArtifact.js +6 -4
  378. package/dist/domain/managed/managedInspectionEvidence.js +16 -0
  379. package/dist/domain/managed/managedMemberComparison.js +2 -9
  380. package/dist/domain/managed/managedMemberComparisonMatch.js +5 -9
  381. package/dist/domain/managed/managedNativeVerification.js +3 -11
  382. package/dist/domain/managed/managedNativeVerificationMatch.js +9 -3
  383. package/dist/domain/native/binaryLayout.js +2 -3
  384. package/dist/domain/native/fileOffsetPartialObservation.js +1 -0
  385. package/dist/domain/native/nativeApiBoundary.js +1 -1
  386. package/dist/domain/native/nativeCallObservation.js +37 -13
  387. package/dist/domain/native/nativeCallPartialObservation.js +33 -0
  388. package/dist/domain/native/nativeInstruction.js +7 -0
  389. package/dist/domain/native/recordedCrash.js +2 -3
  390. package/dist/domain/offsetDateTime.js +17 -0
  391. package/dist/domain/process/processCapture.js +21 -16
  392. package/dist/domain/process/processCaptureCoverage.js +67 -0
  393. package/dist/domain/process/processCaptureExample.js +2 -1
  394. package/dist/domain/process/processCaptureParsing.js +1 -34
  395. package/dist/domain/process/processCaptureValidation.js +81 -13
  396. package/dist/domain/process/processComparison.js +79 -26
  397. package/dist/domain/process/processObservation.js +10 -2
  398. package/dist/domain/process/processScenario.js +35 -12
  399. package/dist/domain/process/processTraceComparison.js +0 -2
  400. package/dist/domain/process/processTraceDimensionProjection.js +1 -1
  401. package/dist/domain/process/processTraceEvaluation.js +15 -11
  402. package/dist/domain/process/processTraceSpecification.js +3 -4
  403. package/dist/domain/propertyListKeys.js +1 -1
  404. package/dist/domain/propertyListXmlText.js +19 -0
  405. package/dist/domain/providerAdapterError.js +3 -1
  406. package/dist/domain/providerOperationHealth.js +54 -0
  407. package/dist/domain/reconstructionCoverage.js +5 -2
  408. package/dist/domain/reconstructionObligationLedgerSchemas.js +2 -1
  409. package/dist/domain/reconstructionReadinessSchemas.js +2 -1
  410. package/dist/domain/reconstructionVerification.js +9 -46
  411. package/dist/domain/reconstructionVerificationSchemas.js +4 -3
  412. package/dist/domain/referenceSourceGraph.js +20 -21
  413. package/dist/domain/staticRuntimeCorrelation.js +8 -45
  414. package/dist/domain/stringPatterns.js +6 -0
  415. package/dist/domain/swiftSymbolClassification.js +61 -0
  416. package/dist/domain/symbolAnalysis.js +66 -18
  417. package/dist/domain/webBundleAnalysis.js +20 -8
  418. package/dist/domain/webBundleAnalyzerInspection.js +13 -8
  419. package/dist/domain/webBundleAnalyzerResult.js +41 -2
  420. package/dist/domain/webCaptureDiff.js +0 -1
  421. package/dist/domain/webCaptureDiffSchemas.js +6 -3
  422. package/dist/domain/webEventListeners.js +3 -2
  423. package/dist/domain/webExecution.js +3 -2
  424. package/dist/domain/webRuntime.js +19 -7
  425. package/dist/domain/webScriptExport.js +1 -1
  426. package/dist/domain/webSourceLocation.js +1 -0
  427. package/dist/dotnet/ManagedArtifactInspector.js +2 -19
  428. package/dist/dotnet/ManagedMemberInspector.js +12 -18
  429. package/dist/dotnet/ManagedMemberInspectorCore.js +47 -44
  430. package/dist/dotnet/ManagedMemberRows.js +75 -62
  431. package/dist/dotnet/ManagedMetadataInventory.js +16 -22
  432. package/dist/dotnet/ManagedMethodBodyReader.js +4 -0
  433. package/dist/dotnet/ManagedNativeBoundaryHelpers.js +109 -94
  434. package/dist/dotnet/ManagedNativeBoundaryInspector.js +12 -21
  435. package/dist/dotnet/ManagedReaderFailure.js +16 -0
  436. package/dist/dotnet/ManagedStaticProvider.js +3 -5
  437. package/dist/evaluation/AgentEvaluationFixtures.js +250 -0
  438. package/dist/evaluation/AgentEvaluationReport.js +28 -0
  439. package/dist/evaluation/CodexAgentEval.js +12 -8
  440. package/dist/evaluation/KnownAnswerEvaluation.js +281 -0
  441. package/dist/evm/EvmoleInterfaceProvider.js +2 -1
  442. package/dist/firmware/FirmwareCommand.js +9 -5
  443. package/dist/firmware/FirmwareFiles.js +1 -1
  444. package/dist/firmware/FirmwareProvider.js +4 -4
  445. package/dist/generatedPackageMetadata.js +2 -2
  446. package/dist/ghidra/GhidraAnalysisProfile.js +7 -5
  447. package/dist/ghidra/GhidraClient.js +126 -34
  448. package/dist/ghidra/GhidraClientStartup.js +0 -2
  449. package/dist/ghidra/GhidraDiagnostics.js +7 -7
  450. package/dist/ghidra/GhidraDoctor.js +6 -5
  451. package/dist/ghidra/GhidraFunctionValues.js +13 -12
  452. package/dist/ghidra/GhidraInstallation.js +58 -33
  453. package/dist/ghidra/GhidraInventoryValues.js +14 -4
  454. package/dist/ghidra/GhidraJavaLaunch.js +66 -0
  455. package/dist/ghidra/GhidraLauncher.js +47 -22
  456. package/dist/ghidra/GhidraProvider.js +6 -2
  457. package/dist/ghidra/GhidraProviderCapabilities.js +20 -2
  458. package/dist/ghidra/GhidraProviderClient.js +36 -15
  459. package/dist/ghidra/GhidraSessionError.js +13 -7
  460. package/dist/ghidra/GhidraSessionRoot.js +39 -0
  461. package/dist/ghidra/GhidraTargetSnapshot.js +47 -12
  462. package/dist/ghidra/GhidraTransport.js +20 -0
  463. package/dist/ghidra/extensions/GhidraExtensions.js +17 -10
  464. package/dist/ghidra/extensions/nativeaot/NativeAotAdapter.js +8 -2
  465. package/dist/hopper/BridgeLauncher.js +65 -56
  466. package/dist/hopper/HopperAnalysisProfile.js +65 -12
  467. package/dist/hopper/HopperCleanup.js +63 -22
  468. package/dist/hopper/HopperClient.js +288 -59
  469. package/dist/hopper/HopperFileOffset.js +237 -0
  470. package/dist/hopper/HopperMachOImage.js +197 -0
  471. package/dist/hopper/HopperOperationStage.js +6 -0
  472. package/dist/hopper/HopperProvider.js +71 -19
  473. package/dist/hopper/HopperProviderCapabilities.js +19 -1
  474. package/dist/hopper/HopperRegexSearch.js +134 -0
  475. package/dist/hopper/HopperRegexWorker.js +27 -0
  476. package/dist/hopper/HopperRequestQueue.js +68 -19
  477. package/dist/hopper/HopperTargetLease.js +133 -49
  478. package/dist/hopper/LinuxPrivateDisplayProbe.js +6 -0
  479. package/dist/ida/IdaConfiguration.js +8 -3
  480. package/dist/ida/IdaInput.js +1 -7
  481. package/dist/ida/IdaMcpConnection.js +8 -4
  482. package/dist/ida/IdaOperationRunner.js +3 -3
  483. package/dist/ida/IdaProvider.js +8 -12
  484. package/dist/ida/IdaSessionClient.js +20 -18
  485. package/dist/ida/IdaWorkspace.js +12 -13
  486. package/dist/inspector/JavaScriptRuntimeScope.js +9 -1
  487. package/dist/inspector/V8InspectorCaptureProjection.js +9 -4
  488. package/dist/inspector/V8InspectorProvider.js +82 -36
  489. package/dist/javascript/recovery/WakaruCommand.js +7 -2
  490. package/dist/javascript/recovery/WakaruExecution.js +5 -2
  491. package/dist/javascript/sourceMaps/DecodedSourceMap.js +47 -0
  492. package/dist/javascript/sourceMaps/SourceMapCommand.js +16 -0
  493. package/dist/javascript/sourceMaps/SourceMapFormat.js +79 -31
  494. package/dist/javascript/sourceMaps/TraceSourceMap.js +14 -28
  495. package/dist/main/shutdown.js +11 -3
  496. package/dist/main/startup.js +9 -2
  497. package/dist/main/transport.js +22 -2
  498. package/dist/main.js +11 -18
  499. package/dist/mcpDoctor.js +62 -2
  500. package/dist/native/AppleDispatchCoverage.js +47 -6
  501. package/dist/native/AppleDispatchDecodeFacts.js +6 -0
  502. package/dist/native/AppleDispatchMetadata.js +6 -3
  503. package/dist/native/AppleMachoFixups.js +48 -24
  504. package/dist/native/AppleMachoSelection.js +48 -22
  505. package/dist/native/AppleObjcCategories.js +6 -2
  506. package/dist/native/AppleObjcDispatchFacets.js +5 -2
  507. package/dist/native/AppleObjcProperties.js +2 -1
  508. package/dist/native/AppleSwiftDispatchFacets.js +27 -21
  509. package/dist/native/AppleSwiftVtables.js +21 -15
  510. package/dist/native/CommandRunner.js +87 -88
  511. package/dist/native/LldbCallTracer.js +372 -103
  512. package/dist/native/LldbRetainedObservations.js +178 -0
  513. package/dist/native/NativeCallObservation.js +62 -3
  514. package/dist/native/NativeMacOSProvider.js +122 -31
  515. package/dist/native/NativeUiHelperRuntime.js +11 -2
  516. package/dist/native/NativeUiObservation.js +2 -2
  517. package/dist/native/SignatureTargetBinding.js +155 -0
  518. package/dist/native/parsers/lipo.js +71 -1
  519. package/dist/native/pwndbg/PwndbgCoreContext.js +25 -5
  520. package/dist/native/pwntools/PwntoolsDecoder.js +2 -1
  521. package/dist/native/pwntools/RecordedCrashStructureBindings.js +2 -0
  522. package/dist/process/DarwinProcessRunTokenReader.js +23 -10
  523. package/dist/process/ExecFileOutput.js +108 -6
  524. package/dist/process/OwnedCommand.js +7 -2
  525. package/dist/process/PrivateRuntimeRoot.js +10 -5
  526. package/dist/process/ProcessOwnership.js +204 -57
  527. package/dist/process/ProcessOwnershipObservation.js +60 -9
  528. package/dist/process/ProviderProcess.js +39 -10
  529. package/dist/process/capture/FilesystemSnapshot.js +50 -13
  530. package/dist/process/capture/ProcessCaptureError.js +15 -2
  531. package/dist/process/capture/ProcessCaptureLifecycle.js +235 -81
  532. package/dist/process/capture/ProcessFilesystemEffects.js +33 -3
  533. package/dist/process/capture/ProcessHarness.js +21 -25
  534. package/dist/process/capture/ProcessNormalization.js +20 -2
  535. package/dist/process/capture/ProcessSampling.js +25 -2
  536. package/dist/process/capture/TerminalRenderer.js +14 -0
  537. package/dist/process/snapshotEnvironment.js +14 -0
  538. package/dist/server/EvidenceMcpServer.js +157 -0
  539. package/dist/server/createServer.js +61 -41
  540. package/dist/server/mcpClientMetadata.js +12 -5
  541. package/dist/server/promptCompletion.js +3 -8
  542. package/dist/server/registerAnalysisViewTool.js +15 -0
  543. package/dist/server/registerAndroidTools.js +2 -5
  544. package/dist/server/registerApplicationTools/compareExportShapes.js +4 -5
  545. package/dist/server/registerApplicationTools/compareSourceToBundle.js +4 -5
  546. package/dist/server/registerApplicationTools/compareVersions.js +4 -5
  547. package/dist/server/registerApplicationTools/coverage.js +1 -2
  548. package/dist/server/registerApplicationTools/helpers.js +1 -4
  549. package/dist/server/registerApplicationTools/obligationLedger.js +4 -5
  550. package/dist/server/registerApplicationTools/projectMobileApplicationGraph.js +3 -4
  551. package/dist/server/registerApplicationTools/traceFeature.js +4 -5
  552. package/dist/server/registerApplicationTools/traceSemantics.js +4 -5
  553. package/dist/server/registerArtifactComparisonTool.js +13 -10
  554. package/dist/server/registerBinaryDiagnosticsTools.js +2 -5
  555. package/dist/server/registerBrowserScenarioTool.js +3 -6
  556. package/dist/server/registerBrowserTools.js +13 -18
  557. package/dist/server/registerBundleComparisonTool.js +5 -7
  558. package/dist/server/registerCloseLifecycleTool.js +9 -20
  559. package/dist/server/registerElectronTools.js +10 -15
  560. package/dist/server/registerEnhancedTools.js +36 -77
  561. package/dist/server/registerEvidenceTools.js +3 -6
  562. package/dist/server/registerEvmTools.js +2 -5
  563. package/dist/server/registerFirmwareTools.js +2 -5
  564. package/dist/server/registerFunctionComparisonTool.js +15 -12
  565. package/dist/server/registerInvestigationTools.js +16 -17
  566. package/dist/server/registerJavaScriptRecoveryTool.js +2 -5
  567. package/dist/server/registerJavaScriptRuntimeObservationTools.js +6 -8
  568. package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +5 -8
  569. package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +4 -7
  570. package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +6 -9
  571. package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +6 -9
  572. package/dist/server/registerOfficialTools.js +4 -21
  573. package/dist/server/registerProcessComparisonTool.js +74 -48
  574. package/dist/server/registerRecordedCrashTools.js +2 -5
  575. package/dist/server/registerSessionRecordTools.js +19 -24
  576. package/dist/server/registerSessionStatusTool.js +19 -6
  577. package/dist/server/registerSessionTools.js +20 -18
  578. package/dist/server/registerWebModuleTool.js +2 -5
  579. package/dist/server/registerWebNetworkCaptureTool.js +2 -5
  580. package/dist/server/registerWebRuntimeTools.js +4 -9
  581. package/dist/server/registerWebScriptTool.js +2 -5
  582. package/dist/server/registerWebSourceLocationTool.js +2 -5
  583. package/dist/server/runDerivedOperation.js +15 -3
  584. package/dist/server/sessionAvailabilityPolicy.js +0 -1
  585. package/dist/server/toolRegistrationOptions.js +2 -2
  586. package/dist/server/toolResult.js +75 -51
  587. package/dist/server/toolResultEncoding.js +34 -0
  588. package/dist/windows/WindowsNativeLoader.js +1 -0
  589. package/dist/windows/WindowsOwnedProcess.js +60 -15
  590. package/dist/windows/WindowsPrivateRuntime.js +7 -8
  591. package/install.sh +1 -1
  592. package/native/windows/README.md +3 -1
  593. package/native/windows/build/manifest.json +2 -2
  594. package/native/windows/build/rea-windows-x64.node +0 -0
  595. package/package.json +44 -30
  596. package/scripts/electron-active-hook-boundaries.cjs +18 -20
  597. package/scripts/electron-active-hook.cjs +241 -37
  598. package/scripts/rea.mjs +3 -6
  599. package/skills/reverse-engineer-anything/SKILL.md +12 -3
  600. package/skills/reverse-engineer-anything/references/android-applications.md +6 -3
  601. package/skills/reverse-engineer-anything/references/evidence-workflows.md +8 -4
  602. package/skills/reverse-engineer-anything/references/javascript-applications.md +20 -3
  603. package/skills/reverse-engineer-anything/references/native-and-artifacts.md +9 -0
  604. package/dist/config.js +0 -1
  605. package/dist/contracts/browserCaptureToolInputSchema.js +0 -43
  606. package/dist/contracts/process/processCaptureExample.js +0 -2
  607. package/dist/contracts/toolOutputSchemas.js +0 -2
  608. package/dist/ghidra/GhidraDefaults.js +0 -2
  609. package/dist/main/reload.js +0 -12
  610. package/dist/main/state.js +0 -3
  611. package/dist/server/sessionToolPolicies.js +0 -2
@@ -3,12 +3,18 @@
3
3
  REA imports this module into `lldb --batch` and runs `rea_trace <config.json>`.
4
4
  It launches one owned process, stops at the requested functions and
5
5
  Objective-C methods, records each entry from registers and memory reads only,
6
- continues, and kills the process once it exits, the event limit is reached or
7
- the duration elapses. No expression is evaluated and no target code runs on
8
- the tracer's behalf. The result is written as JSON to the configured path.
6
+ continues, and kills the process once it exits, the event or aggregate resource
7
+ limit is reached, or the duration elapses. Target output is drained through
8
+ bounded FIFOs. No expression is evaluated and no target code runs on the
9
+ tracer's behalf. The result is written as JSON to the configured path.
9
10
  """
10
11
 
12
+ import errno
13
+ import hashlib
11
14
  import json
15
+ import os
16
+ import select
17
+ import threading
12
18
  import time
13
19
 
14
20
  import lldb
@@ -22,9 +28,218 @@ ARGUMENT_REGISTERS = {
22
28
  MAX_SELECTOR_BYTES = 1024
23
29
  MAX_REPORTED_LOCATIONS = 64
24
30
  MAX_OTHER_STOPS = 256
31
+ MAX_TRACE_BYTES = 8 * 1024 * 1024
32
+ MAX_TRACE_FRAMES = 65_536
33
+ MAX_OBSERVATION_JOURNAL_BYTES = MAX_TRACE_BYTES
34
+ MAX_BREAKPOINT_LOCATION_BYTES = 8 * 1024 * 1024
35
+ MAX_TARGET_OUTPUT_BYTES = 1024 * 1024
36
+ OUTPUT_DRAIN_BYTES_PER_PASS = 1024 * 1024
37
+ OUTPUT_EOF_WAIT_SECONDS = 1.0
38
+ OUTPUT_READER_JOIN_SECONDS = 0.5
25
39
  LISTENER_NAME = "rea-native-call-observation"
26
40
 
27
41
 
42
+ def _can_retain_trace(current_bytes, current_frames, event_bytes, event_frames):
43
+ """Whether a complete event fits both aggregate trace budgets."""
44
+ return (
45
+ current_bytes + event_bytes <= MAX_TRACE_BYTES
46
+ and current_frames + event_frames <= MAX_TRACE_FRAMES
47
+ )
48
+
49
+
50
+ def _estimated_json_size(value):
51
+ """Estimate JSON size without encoding potentially oversized values."""
52
+ if isinstance(value, str):
53
+ # json.dumps defaults to ensure_ascii=True; supplementary characters
54
+ # can become two six-byte Unicode escapes.
55
+ return len(value) * 12 + 2
56
+ if value is None or isinstance(value, (bool, int, float)):
57
+ return 32
58
+ if isinstance(value, dict):
59
+ return 2 + sum(
60
+ len(key) * 6 + 4 + _estimated_json_size(item)
61
+ for key, item in value.items()
62
+ )
63
+ if isinstance(value, (list, tuple)):
64
+ return 2 + sum(_estimated_json_size(item) + 1 for item in value)
65
+ return 64
66
+
67
+
68
+ def _fits_trace_budget(value, remaining_bytes):
69
+ return _estimated_json_size(value) <= remaining_bytes
70
+
71
+
72
+ class _ObservationJournal:
73
+ """Flush a bounded JSONL prefix so observations survive tracer failure."""
74
+
75
+ def __init__(self, handle, max_bytes=MAX_OBSERVATION_JOURNAL_BYTES):
76
+ self.handle = handle
77
+ self.max_bytes = max_bytes
78
+ self.bytes = 0
79
+
80
+ def append(self, record):
81
+ encoded = (json.dumps(record) + "\n").encode("utf-8")
82
+ if self.bytes + len(encoded) > self.max_bytes:
83
+ return False
84
+ self.handle.write(encoded)
85
+ self.handle.flush()
86
+ self.bytes += len(encoded)
87
+ return True
88
+
89
+
90
+ def _set_launch_flags(launch):
91
+ launch.SetLaunchFlags(
92
+ launch.GetLaunchFlags()
93
+ | lldb.eLaunchFlagDebug
94
+ | lldb.eLaunchFlagStopAtEntry
95
+ )
96
+
97
+
98
+ def _hash_file(path):
99
+ digest = hashlib.sha256()
100
+ with open(path, "rb") as target_file:
101
+ while True:
102
+ chunk = target_file.read(1024 * 1024)
103
+ if not chunk:
104
+ break
105
+ digest.update(chunk)
106
+ return digest.hexdigest()
107
+
108
+
109
+ def _file_identity(path):
110
+ info = os.stat(path)
111
+ return str(info.st_dev), str(info.st_ino)
112
+
113
+
114
+ def _module_identity(target):
115
+ module = target.FindModule(target.GetExecutable())
116
+ if not module.IsValid():
117
+ return None, None, None
118
+ spec = module.GetFileSpec()
119
+ path = str(spec) if spec.IsValid() else None
120
+ identity = None
121
+ if path:
122
+ try:
123
+ identity = _file_identity(path)
124
+ except OSError:
125
+ pass
126
+ return path, identity, module.GetUUIDString() or None
127
+
128
+
129
+ def _wait_for_identity_ack(config):
130
+ """Hold the target at entry while the host adapter captures its start identity."""
131
+ path = config.get("identity_ack_path")
132
+ if not path:
133
+ return
134
+ while True:
135
+ try:
136
+ with open(path, "r") as handle:
137
+ return handle.read(32).strip()
138
+ except FileNotFoundError:
139
+ time.sleep(0.025)
140
+
141
+
142
+ class _OutputPipe:
143
+ """Drain a target FIFO while retaining only its bounded output prefix."""
144
+
145
+ def __init__(self, fifo_path, capture_path, max_bytes):
146
+ os.mkfifo(fifo_path, 0o600)
147
+ self.path = fifo_path
148
+ try:
149
+ self.fd = os.open(fifo_path, os.O_RDONLY | os.O_NONBLOCK)
150
+ except Exception:
151
+ os.unlink(fifo_path)
152
+ raise
153
+ try:
154
+ self.capture = open(capture_path, "wb")
155
+ except Exception:
156
+ os.close(self.fd)
157
+ os.unlink(fifo_path)
158
+ raise
159
+ self.max_bytes = max_bytes
160
+ self.bytes = 0
161
+ self.truncated = False
162
+ self.closed = False
163
+ self.stop_reader = threading.Event()
164
+ self.reader_thread = None
165
+ self.reader_error = None
166
+ self.launched = False
167
+ self.eof = threading.Event()
168
+ self.complete = False
169
+
170
+ def start(self):
171
+ if self.reader_thread is None:
172
+ self.reader_thread = threading.Thread(target=self._reader_loop, daemon=True)
173
+ self.reader_thread.start()
174
+
175
+ def _reader_loop(self):
176
+ try:
177
+ while not self.stop_reader.is_set():
178
+ readable, _, _ = select.select([self.fd], [], [], 0.05)
179
+ if not readable:
180
+ continue
181
+ if self.drain(OUTPUT_DRAIN_BYTES_PER_PASS) == 0:
182
+ # A FIFO read end is readable at EOF before the target opens it.
183
+ time.sleep(0.01)
184
+ except Exception as error:
185
+ self.reader_error = error
186
+ self.stop_reader.set()
187
+
188
+ def mark_launched(self):
189
+ self.launched = True
190
+
191
+ def drain(self, max_bytes=OUTPUT_DRAIN_BYTES_PER_PASS):
192
+ consumed = 0
193
+ while consumed < max_bytes:
194
+ try:
195
+ chunk = os.read(self.fd, min(65_536, max_bytes - consumed))
196
+ except OSError as error:
197
+ if error.errno in (errno.EAGAIN, errno.EWOULDBLOCK):
198
+ return consumed
199
+ raise
200
+ if not chunk:
201
+ if self.launched:
202
+ self.eof.set()
203
+ return consumed
204
+ consumed += len(chunk)
205
+ self.bytes += len(chunk)
206
+ remaining = max(0, self.max_bytes - self.capture.tell())
207
+ if remaining:
208
+ self.capture.write(chunk[:remaining])
209
+ if len(chunk) > remaining:
210
+ self.truncated = True
211
+
212
+ def close(self, expected_exit=False):
213
+ if self.closed:
214
+ return
215
+ if expected_exit and self.launched:
216
+ self.eof.wait(OUTPUT_EOF_WAIT_SECONDS)
217
+ self.stop_reader.set()
218
+ if self.reader_thread is not None:
219
+ self.reader_thread.join(OUTPUT_READER_JOIN_SECONDS)
220
+ stopped = self.reader_thread is None or not self.reader_thread.is_alive()
221
+ if stopped:
222
+ try:
223
+ self.drain(OUTPUT_DRAIN_BYTES_PER_PASS)
224
+ finally:
225
+ try:
226
+ self.capture.close()
227
+ finally:
228
+ os.close(self.fd)
229
+ self.closed = True
230
+ else:
231
+ # A daemon reader may still be unwinding a blocked filesystem write.
232
+ # Leave its handles alone rather than racing that thread at shutdown.
233
+ self.closed = True
234
+ self.complete = bool(
235
+ stopped
236
+ and (not self.launched or (expected_exit and self.eof.is_set()))
237
+ and self.reader_error is None
238
+ )
239
+ if not self.complete:
240
+ self.truncated = True
241
+
242
+
28
243
  def _hex(value):
29
244
  return "0x%x" % value
30
245
 
@@ -34,7 +249,7 @@ def _location(address, target):
34
249
  module = address.GetModule()
35
250
  symbol = address.GetSymbol()
36
251
  file_address = address.GetFileAddress()
37
- return {
252
+ location = {
38
253
  "load_address": _hex(address.GetLoadAddress(target)),
39
254
  "file_address": None
40
255
  if file_address == lldb.LLDB_INVALID_ADDRESS
@@ -43,6 +258,7 @@ def _location(address, target):
43
258
  "module_path": str(module.GetFileSpec()) if module.IsValid() else None,
44
259
  "symbol": symbol.GetName() if symbol.IsValid() else None,
45
260
  }
261
+ return location
46
262
 
47
263
 
48
264
  def _no_files():
@@ -107,33 +323,54 @@ def _wanted(spec, symbol):
107
323
  return symbol.startswith("-[" if method_type == "instance" else "+[")
108
324
 
109
325
 
110
- def _record(context, thread, index, sequence):
326
+ def _read_register(frame, name):
327
+ error = lldb.SBError()
328
+ value = frame.FindRegister(name)
329
+ if not value.IsValid():
330
+ raise RuntimeError("LLDB breakpoint register %s is unavailable" % name)
331
+ number = value.GetValueAsUnsigned(error)
332
+ if error.Fail():
333
+ raise RuntimeError(
334
+ "LLDB breakpoint register %s could not be read: %s" % (name, error)
335
+ )
336
+ return number
337
+
338
+
339
+ def _record(context, thread, frame, index, sequence, location, remaining_bytes):
111
340
  target, process, config = context["target"], context["process"], context["config"]
112
- frame = thread.GetFrameAtIndex(0)
113
- location = _location(frame.GetPCAddress(), target)
114
341
  symbol = location["symbol"] or ""
115
342
  if not _wanted(config["breakpoints"][index], symbol):
116
343
  return None
117
344
  names = ARGUMENT_REGISTERS.get(config["architecture"], [])
345
+ objc_method = symbol.startswith("-[") or symbol.startswith("+[")
346
+ values = {
347
+ name: _read_register(frame, name)
348
+ for name in names[: max(config["argument_registers"], 2 if objc_method else 0)]
349
+ }
118
350
  registers = [
119
- {"name": name, "value": _hex(frame.FindRegister(name).GetValueAsUnsigned())}
351
+ {"name": name, "value": _hex(values[name])}
120
352
  for name in names[: config["argument_registers"]]
121
353
  ]
122
354
  receiver_class = None
123
355
  selector = None
124
- if symbol.startswith("-[") or symbol.startswith("+["):
356
+ if objc_method:
125
357
  error = lldb.SBError()
126
358
  text = process.ReadCStringFromMemory(
127
- frame.FindRegister(names[1]).GetValueAsUnsigned(),
359
+ values[names[1]],
128
360
  MAX_SELECTOR_BYTES,
129
361
  error,
130
362
  )
131
363
  selector = text if error.Success() and text else None
132
364
  if symbol.startswith("-["):
133
- receiver_class = _dynamic_class(
134
- target, frame.FindRegister(names[0]).GetValueAsUnsigned()
135
- )
136
- frames = min(thread.GetNumFrames(), 1 + config["backtrace_frames"])
365
+ receiver_class = _dynamic_class(target, values[names[0]])
366
+ estimated_base = (
367
+ _estimated_json_size(location)
368
+ + _estimated_json_size(receiver_class)
369
+ + _estimated_json_size(selector)
370
+ + 2048
371
+ )
372
+ if estimated_base > remaining_bytes:
373
+ raise ValueError("trace event exceeds aggregate byte budget")
137
374
  record = {
138
375
  "sequence": sequence,
139
376
  "elapsed_ms": round((time.monotonic() - context["started"]) * 1000, 3),
@@ -142,55 +379,154 @@ def _record(context, thread, index, sequence):
142
379
  "receiver_class": receiver_class,
143
380
  "selector": selector,
144
381
  "registers": registers,
145
- "backtrace": [
146
- _location(thread.GetFrameAtIndex(depth).GetPCAddress(), target)
147
- for depth in range(1, frames)
148
- ],
382
+ "backtrace": [],
149
383
  }
150
384
  record.update(location)
151
385
  return record
152
386
 
153
387
 
154
- def _handle_stop(context, events, other_stops):
155
- """Record breakpoint hits of one stop; return an outcome when tracing must end."""
156
- process = context["process"]
157
- for thread in process:
158
- reason = thread.GetStopReason()
159
- if reason == lldb.eStopReasonBreakpoint:
160
- index = context["breakpoint_index"].get(thread.GetStopReasonDataAtIndex(0))
161
- if index is None:
162
- continue
163
- record = _record(context, thread, index, len(events))
164
- if record is not None:
165
- events.append(record)
166
- if len(events) >= context["config"]["max_events"]:
167
- return "event-limit"
168
- elif reason in (lldb.eStopReasonSignal, lldb.eStopReasonException):
169
- other_stops.append(thread.GetStopDescription(256))
388
+ # One trace runs in each owned LLDB subprocess. Its callbacks execute at the
389
+ # breakpoint before LLDB resumes, unlike snapshots of later public stop events.
390
+ _TRACE_CONTEXT = None
391
+
392
+
393
+ def _handle_breakpoint(context, frame, index):
394
+ """Read one hit while LLDB's breakpoint callback owns the stopped frame."""
395
+ if not frame.IsValid() or frame.GetPC() == lldb.LLDB_INVALID_ADDRESS:
396
+ raise RuntimeError("LLDB breakpoint callback did not supply a readable frame")
397
+ thread = frame.GetThread()
398
+ events = context["events"]
399
+ location = _location(frame.GetPCAddress(), context["target"])
400
+ symbol = location["symbol"] or ""
401
+ if not _wanted(context["config"]["breakpoints"][index], symbol):
402
+ return None
403
+ frame_count = max(
404
+ 0,
405
+ min(thread.GetNumFrames() - 1, context["config"]["backtrace_frames"]),
406
+ )
407
+ event_frame_count = 1 + frame_count
408
+ if not _can_retain_trace(
409
+ context["retained_trace_bytes"],
410
+ context["retained_frames"],
411
+ 0,
412
+ event_frame_count,
413
+ ):
414
+ return "resource-limit"
415
+ try:
416
+ remaining_bytes = MAX_TRACE_BYTES - context["retained_trace_bytes"]
417
+ record = _record(
418
+ context, thread, frame, index, len(events), location, remaining_bytes
419
+ )
420
+ except ValueError:
421
+ return "resource-limit"
422
+ if record is not None:
423
+ if not _fits_trace_budget(record, remaining_bytes):
424
+ return "resource-limit"
425
+ record_bytes = len(json.dumps(record).encode("utf-8"))
426
+ if context["retained_trace_bytes"] + record_bytes > MAX_TRACE_BYTES:
427
+ return "resource-limit"
428
+ for depth in range(1, frame_count + 1):
429
+ try:
430
+ location = _location(
431
+ thread.GetFrameAtIndex(depth).GetPCAddress(), context["target"]
432
+ )
433
+ except ValueError:
434
+ return "resource-limit"
435
+ if (
436
+ _estimated_json_size(location) + record_bytes + 1
437
+ > MAX_TRACE_BYTES - context["retained_trace_bytes"]
438
+ ):
439
+ return "resource-limit"
440
+ location_bytes = len(json.dumps(location).encode("utf-8"))
441
+ addition = location_bytes + (1 if record["backtrace"] else 0)
442
+ if (
443
+ context["retained_trace_bytes"]
444
+ + record_bytes
445
+ + addition
446
+ > MAX_TRACE_BYTES
447
+ ):
448
+ return "resource-limit"
449
+ record["backtrace"].append(location)
450
+ record_bytes += addition
451
+ journal = context.get("observation_journal")
452
+ if journal is not None and not journal.append(
453
+ {"kind": "event", "event": record}
454
+ ):
455
+ return "resource-limit"
456
+ events.append(record)
457
+ context["retained_frames"] += event_frame_count
458
+ context["retained_trace_bytes"] += record_bytes
459
+ if len(events) >= context["config"]["max_events"]:
460
+ return "event-limit"
461
+ return None
462
+
463
+
464
+ def breakpoint_hit(frame, location, internal_dict):
465
+ """LLDB callback: capture before resuming, and stop on a limit or failure."""
466
+ context = _TRACE_CONTEXT
467
+ if context is None or context["outcome"] is not None or context["failure"] is not None:
468
+ return True
469
+ try:
470
+ index = context["breakpoint_index"][location.GetBreakpoint().GetID()]
471
+ context["outcome"] = _handle_breakpoint(context, frame, index)
472
+ except Exception as error:
473
+ context["failure"] = "%s: %s" % (type(error).__name__, error)
474
+ return True
475
+ return context["outcome"] is not None
476
+
477
+
478
+ def _handle_stop(context, other_stops):
479
+ """Retain non-breakpoint stop observations; callbacks already capture hits."""
480
+ for thread in context["process"]:
481
+ if thread.GetStopReason() in (lldb.eStopReasonSignal, lldb.eStopReasonException):
482
+ stop_description = thread.GetStopDescription(256)
483
+ journal = context.get("observation_journal")
484
+ if journal is not None and not journal.append(
485
+ {"kind": "other-stop", "reason": stop_description}
486
+ ):
487
+ return "resource-limit"
488
+ other_stops.append(stop_description)
170
489
  if len(other_stops) >= MAX_OTHER_STOPS:
171
490
  return "stop-limit"
172
491
  return None
173
492
 
174
493
 
175
- def _breakpoint_report(target, created):
494
+ def _breakpoint_report(target, created, config):
176
495
  report = []
496
+ retained_location_bytes = 0
497
+ locations_truncated = False
177
498
  for index, breakpoints in enumerate(created):
178
499
  locations = []
179
500
  count = 0
180
501
  for breakpoint in breakpoints:
181
- count += breakpoint.GetNumLocations()
182
502
  for position in range(breakpoint.GetNumLocations()):
503
+ address = breakpoint.GetLocationAtIndex(position).GetAddress()
504
+ location = _location(address, target)
505
+ if not _wanted(config["breakpoints"][index], location["symbol"] or ""):
506
+ continue
507
+ count += 1
183
508
  if len(locations) < MAX_REPORTED_LOCATIONS:
184
- locations.append(
185
- _location(breakpoint.GetLocationAtIndex(position).GetAddress(), target)
509
+ remaining_bytes = (
510
+ MAX_BREAKPOINT_LOCATION_BYTES - retained_location_bytes
186
511
  )
512
+ if not _fits_trace_budget(location, remaining_bytes):
513
+ locations_truncated = True
514
+ continue
515
+ location_bytes = len(json.dumps(location).encode("utf-8"))
516
+ addition = location_bytes + (1 if locations else 0)
517
+ if addition > remaining_bytes:
518
+ locations_truncated = True
519
+ continue
520
+ locations.append(location)
521
+ retained_location_bytes += addition
187
522
  report.append({"index": index, "location_count": count, "locations": locations})
188
- return report
523
+ return report, locations_truncated
189
524
 
190
525
 
191
526
  def _launch_info(target, config, listener):
192
527
  launch = lldb.SBLaunchInfo(config["arguments"])
193
528
  launch.SetListener(listener)
529
+ _set_launch_flags(launch)
194
530
  environment = target.GetEnvironment()
195
531
  for key, value in config["environment"].items():
196
532
  environment.Set(key, value, True)
@@ -210,81 +546,281 @@ def _wait_for_exit(listener, process, seconds):
210
546
  listener.WaitForEvent(1, event)
211
547
 
212
548
 
549
+ def _failed_launch_description(process):
550
+ if process.GetState() != lldb.eStateExited or process.GetExitStatus() != -1:
551
+ return None
552
+ description = process.GetExitDescription()
553
+ if isinstance(description, str) and description.lower().startswith(("attach failed", "launch failed")):
554
+ return description
555
+ return None
556
+
557
+
213
558
  def trace(debugger, config):
559
+ global _TRACE_CONTEXT
214
560
  debugger.SetAsync(True)
215
561
  # Stop at the symbol itself, where argument registers still hold the ABI
216
562
  # arguments, even when line tables would let LLDB skip the prologue.
217
563
  lldb.SBDebugger.SetInternalVariable(
218
564
  "target.skip-prologue", "false", debugger.GetInstanceName()
219
565
  )
566
+ try:
567
+ before_digest = _hash_file(config["executable"])
568
+ before_identity = _file_identity(config["executable"])
569
+ except OSError as error:
570
+ return {"status": "target-integrity-error", "error": str(error)}
571
+ if before_digest != config["expected_sha256"]:
572
+ return {
573
+ "status": "target-integrity-error",
574
+ "error": "selected executable digest changed before LLDB target creation",
575
+ }
220
576
  error = lldb.SBError()
221
577
  target = debugger.CreateTarget(
222
578
  config["executable"], config["architecture"], None, False, error
223
579
  )
224
580
  if not target.IsValid():
225
581
  return {"status": "target-error", "error": error.GetCString()}
582
+ module_path_before, module_file_identity_before, module_uuid_before = (
583
+ _module_identity(target)
584
+ )
585
+ if (
586
+ module_file_identity_before is not None
587
+ and module_file_identity_before != before_identity
588
+ ):
589
+ return {
590
+ "status": "target-integrity-error",
591
+ "error": "LLDB executable module resolved to a different pre-launch file identity",
592
+ }
226
593
  created = [_create_breakpoints(target, spec) for spec in config["breakpoints"]]
227
594
  breakpoint_index = {}
228
595
  for index, breakpoints in enumerate(created):
229
596
  for breakpoint in breakpoints:
230
597
  breakpoint_index[breakpoint.GetID()] = index
231
598
  listener = lldb.SBListener(LISTENER_NAME)
599
+ output_budget = config.get("max_output_bytes", MAX_TARGET_OUTPUT_BYTES)
600
+ stdout = _OutputPipe(
601
+ config["stdout_path"], config["stdout_capture_path"], output_budget
602
+ )
603
+ try:
604
+ stderr = _OutputPipe(
605
+ config["stderr_path"], config["stderr_capture_path"], output_budget
606
+ )
607
+ except Exception:
608
+ stdout.close()
609
+ raise
610
+ stdout.start()
611
+ stderr.start()
612
+ observation_journal = None
232
613
  started = time.monotonic()
233
- process = target.Launch(_launch_info(target, config, listener), error)
234
- if not error.Success() or not process.IsValid():
235
- return {"status": "launch-error", "error": error.GetCString()}
236
- with open(config["pid_path"], "w") as handle:
237
- handle.write(str(process.GetProcessID()))
238
- context = {
239
- "target": target,
240
- "process": process,
241
- "config": config,
242
- "started": started,
243
- "breakpoint_index": breakpoint_index,
244
- }
245
- events = []
246
- other_stops = []
247
- outcome = None
248
- deadline = started + config["duration_ms"] / 1000
249
- event = lldb.SBEvent()
250
- while outcome is None:
251
- if time.monotonic() >= deadline:
252
- outcome = "duration-elapsed"
253
- break
254
- if not listener.WaitForEvent(1, event):
255
- continue
256
- if not lldb.SBProcess.EventIsProcessEvent(event):
257
- continue
258
- state = lldb.SBProcess.GetStateFromEvent(event)
259
- if state == lldb.eStateExited:
260
- outcome = "exited"
261
- elif state == lldb.eStateStopped and not lldb.SBProcess.GetRestartedFromEvent(event):
262
- outcome = _handle_stop(context, events, other_stops)
263
- if outcome is None:
264
- process.Continue()
265
- pid = process.GetProcessID()
266
- exit_status = None
267
- exit_description = None
268
- if outcome == "exited":
269
- exit_status = process.GetExitStatus()
270
- exit_description = process.GetExitDescription()
271
- else:
272
- process.Kill()
273
- _wait_for_exit(listener, process, 5)
274
- return {
275
- "status": "traced",
276
- "version": lldb.SBDebugger.GetVersionString().splitlines()[0],
277
- "pid": pid,
278
- "outcome": outcome,
279
- "exit_status": exit_status,
280
- "exit_description": exit_description,
281
- "killed": outcome != "exited",
282
- "terminated": process.GetState() == lldb.eStateExited,
283
- "elapsed_ms": round((time.monotonic() - started) * 1000, 3),
284
- "breakpoints": _breakpoint_report(target, created),
285
- "events": events,
286
- "other_stops": other_stops,
287
- }
614
+ process = None
615
+ try:
616
+ observation_path = config.get("observation_path")
617
+ if observation_path:
618
+ observation_journal = _ObservationJournal(
619
+ open(observation_path, "wb")
620
+ )
621
+ process = target.Launch(_launch_info(target, config, listener), error)
622
+ if not error.Success() or not process.IsValid():
623
+ stdout.close()
624
+ stderr.close()
625
+ return {"status": "launch-error", "error": error.GetCString()}
626
+ launch_failure = _failed_launch_description(process)
627
+ if launch_failure is not None:
628
+ stdout.close(expected_exit=True)
629
+ stderr.close(expected_exit=True)
630
+ return {"status": "launch-error", "error": launch_failure}
631
+ stdout.mark_launched()
632
+ stderr.mark_launched()
633
+ # Publish the PID before any post-launch file or module inspection. The
634
+ # process is stopped at entry and remains there until identity_ack.
635
+ with open(config["pid_path"], "w") as handle:
636
+ handle.write(str(process.GetProcessID()))
637
+ identity_ack = _wait_for_identity_ack(config)
638
+ if identity_ack != "readable":
639
+ process.Kill()
640
+ _wait_for_exit(listener, process, 5)
641
+ expected_exit = process.GetState() == lldb.eStateExited
642
+ stdout.close(expected_exit=expected_exit)
643
+ stderr.close(expected_exit=expected_exit)
644
+ return {
645
+ "status": "target-identity-unavailable",
646
+ "error": "host could not establish the launched process identity; target was stopped",
647
+ }
648
+ try:
649
+ after_digest = _hash_file(config["executable"])
650
+ after_identity = _file_identity(config["executable"])
651
+ except OSError as identity_error:
652
+ process.Kill()
653
+ stdout.close(expected_exit=process.GetState() == lldb.eStateExited)
654
+ stderr.close(expected_exit=process.GetState() == lldb.eStateExited)
655
+ return {"status": "target-integrity-error", "error": str(identity_error)}
656
+ if after_digest != config["expected_sha256"] or after_identity != before_identity:
657
+ process.Kill()
658
+ _wait_for_exit(listener, process, 5)
659
+ stdout.close(expected_exit=process.GetState() == lldb.eStateExited)
660
+ stderr.close(expected_exit=process.GetState() == lldb.eStateExited)
661
+ return {
662
+ "status": "target-integrity-error",
663
+ "error": "selected executable digest or file identity changed during LLDB launch",
664
+ }
665
+ module_path_after, module_file_identity_after, module_uuid_after = (
666
+ _module_identity(target)
667
+ )
668
+ if (
669
+ module_file_identity_after is not None
670
+ and module_file_identity_after != before_identity
671
+ ):
672
+ process.Kill()
673
+ _wait_for_exit(listener, process, 5)
674
+ stdout.close(expected_exit=process.GetState() == lldb.eStateExited)
675
+ stderr.close(expected_exit=process.GetState() == lldb.eStateExited)
676
+ return {
677
+ "status": "target-integrity-error",
678
+ "error": "LLDB executable module resolved to a different file identity",
679
+ }
680
+ if (
681
+ module_uuid_before is not None
682
+ and module_uuid_after is not None
683
+ and module_uuid_before != module_uuid_after
684
+ ):
685
+ process.Kill()
686
+ _wait_for_exit(listener, process, 5)
687
+ stdout.close(expected_exit=process.GetState() == lldb.eStateExited)
688
+ stderr.close(expected_exit=process.GetState() == lldb.eStateExited)
689
+ return {
690
+ "status": "target-integrity-error",
691
+ "error": "LLDB executable module identity changed during launch",
692
+ }
693
+ context = {
694
+ "target": target,
695
+ "process": process,
696
+ "config": config,
697
+ "started": started,
698
+ "breakpoint_index": breakpoint_index,
699
+ "retained_frames": 0,
700
+ "retained_trace_bytes": 0,
701
+ "observation_journal": observation_journal,
702
+ }
703
+ events = []
704
+ context.update({"events": events, "outcome": None, "failure": None})
705
+ _TRACE_CONTEXT = context
706
+ for breakpoints in created:
707
+ for breakpoint in breakpoints:
708
+ breakpoint.SetScriptCallbackFunction("rea_lldb_tracer.breakpoint_hit")
709
+ other_stops = []
710
+ outcome = None
711
+ deadline = started + config["duration_ms"] / 1000
712
+ event = lldb.SBEvent()
713
+ while outcome is None:
714
+ if stdout.reader_error is not None:
715
+ raise RuntimeError("stdout capture failed: %s" % stdout.reader_error)
716
+ if stderr.reader_error is not None:
717
+ raise RuntimeError("stderr capture failed: %s" % stderr.reader_error)
718
+ if time.monotonic() >= deadline:
719
+ outcome = "duration-elapsed"
720
+ break
721
+ if not listener.WaitForEvent(1, event):
722
+ continue
723
+ if not lldb.SBProcess.EventIsProcessEvent(event):
724
+ continue
725
+ state = lldb.SBProcess.GetStateFromEvent(event)
726
+ if state == lldb.eStateExited:
727
+ outcome = "exited"
728
+ elif state == lldb.eStateStopped and not lldb.SBProcess.GetRestartedFromEvent(event):
729
+ if context["failure"] is not None:
730
+ raise RuntimeError(context["failure"])
731
+ outcome = context["outcome"] or _handle_stop(context, other_stops)
732
+ if outcome is None:
733
+ process.Continue()
734
+ pid = process.GetProcessID()
735
+ exit_status = None
736
+ exit_description = None
737
+ if outcome == "exited":
738
+ exit_status = process.GetExitStatus()
739
+ exit_description = process.GetExitDescription()
740
+ else:
741
+ process.Kill()
742
+ _wait_for_exit(listener, process, 5)
743
+ process_exited = process.GetState() == lldb.eStateExited
744
+ stdout.close(expected_exit=process_exited)
745
+ stderr.close(expected_exit=process_exited)
746
+ # SBTarget.Launch may succeed before debugserver reports an asynchronous
747
+ # attach failure as an exited SBProcess. Its -1 status is not a target
748
+ # exit code; preserve the debugger's concrete launch denial.
749
+ launch_failure = _failed_launch_description(process)
750
+ if launch_failure is not None:
751
+ return {"status": "launch-error", "error": launch_failure}
752
+ launch_identity_stable = (
753
+ module_path_before is not None
754
+ and module_path_after == module_path_before
755
+ and module_file_identity_before == before_identity
756
+ and module_file_identity_after == module_file_identity_before
757
+ and module_uuid_before is not None
758
+ and module_uuid_after == module_uuid_before
759
+ )
760
+ breakpoint_report, breakpoint_locations_truncated = _breakpoint_report(
761
+ target, created, config
762
+ )
763
+ return {
764
+ "status": "traced",
765
+ "version": lldb.SBDebugger.GetVersionString().splitlines()[0],
766
+ "pid": pid,
767
+ "outcome": outcome,
768
+ "exit_status": exit_status,
769
+ "exit_description": exit_description,
770
+ "killed": outcome != "exited",
771
+ "terminated": process.GetState() == lldb.eStateExited,
772
+ "elapsed_ms": round((time.monotonic() - started) * 1000, 3),
773
+ "breakpoints": breakpoint_report,
774
+ "breakpoint_locations_truncated": breakpoint_locations_truncated,
775
+ "events": events,
776
+ "resource_limit_reached": outcome == "resource-limit",
777
+ "target_output": {
778
+ "stdout_bytes": stdout.bytes,
779
+ "stderr_bytes": stderr.bytes,
780
+ "stdout_truncated": stdout.truncated,
781
+ "stderr_truncated": stderr.truncated,
782
+ "stdout_complete": stdout.complete,
783
+ "stderr_complete": stderr.complete,
784
+ },
785
+ "target_identity": {
786
+ "selected_file_sha256": after_digest,
787
+ "loaded_image_sha256": None,
788
+ "file_device": after_identity[0],
789
+ "file_inode": after_identity[1],
790
+ "module_path": module_path_after,
791
+ "module_uuid": module_uuid_after,
792
+ # This records matching path/module identity observations. LLDB
793
+ # does not expose the exact mapped bytes, so it never proves a digest.
794
+ "stable": launch_identity_stable,
795
+ },
796
+ "other_stops": other_stops,
797
+ }
798
+
799
+ finally:
800
+ _TRACE_CONTEXT = None
801
+ if observation_journal is not None:
802
+ try:
803
+ observation_journal.handle.close()
804
+ except Exception:
805
+ pass
806
+ if process is not None:
807
+ try:
808
+ if process.IsValid() and process.GetState() != lldb.eStateExited:
809
+ process.Kill()
810
+ _wait_for_exit(listener, process, 5)
811
+ except Exception:
812
+ pass
813
+ for output_pipe in (stdout, stderr):
814
+ try:
815
+ output_pipe.close(
816
+ expected_exit=(
817
+ process is not None
818
+ and process.IsValid()
819
+ and process.GetState() == lldb.eStateExited
820
+ )
821
+ )
822
+ except Exception:
823
+ pass
288
824
 
289
825
 
290
826
  def run(debugger, command, result, internal_dict):