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.
- package/README.md +26 -18
- package/bridge/android/ReaJadxBridge.java +14 -5
- package/bridge/ghidra/ReaGhidraBridge.java +205 -51
- package/bridge/hopper_bridge.py +314 -127
- package/bridge/mitmproxy/capture.py +0 -2
- package/bridge/native/rea_lldb_tracer.py +630 -94
- package/bridge/process/ProcessRunTokenReader.swift +39 -5
- package/bridge/pwntools/recorded_crash_impl.py +4 -0
- package/dist/android/JadxConfiguration.js +274 -31
- package/dist/android/JadxMcpTransport.js +18 -2
- package/dist/android/JadxProtocol.js +6 -0
- package/dist/android/JadxProvider.js +76 -37
- package/dist/android/JadxSession.js +23 -4
- package/dist/application/AnalysisContextQueries.js +8 -35
- package/dist/application/AnalysisDocument.js +32 -0
- package/dist/application/AppBundleExecutable.js +67 -21
- package/dist/application/BinaryTargetResolver.js +5 -3
- package/dist/application/BrowserEvidence.js +3 -8
- package/dist/application/BrowserScenarioEvidence.js +2 -18
- package/dist/application/CallPathTracing.js +19 -3
- package/dist/application/CapabilityInventory.js +48 -11
- package/dist/application/ClientConfigurationDocument.js +917 -8
- package/dist/application/ClientRegistrationIdentity.js +26 -5
- package/dist/application/ClientRegistrationStatus.js +29 -14
- package/dist/application/DirectAnalysis.js +56 -51
- package/dist/application/DirectAnalysisCleanup.js +72 -0
- package/dist/application/DirectAnalysisStatus.js +4 -5
- package/dist/application/Doctor.js +19 -21
- package/dist/application/DoctorDiagnostics.js +1 -2
- package/dist/application/DoctorScope.js +25 -13
- package/dist/application/EnhancedLiteralTracing.js +22 -25
- package/dist/application/EnhancedTools.js +64 -17
- package/dist/application/EvidenceBundleFiles.js +30 -13
- package/dist/application/FunctionAnalysisEvidence.js +2 -3
- package/dist/application/InventoryProjectionEvidence.js +4 -3
- package/dist/application/InvestigationProviders.js +11 -2
- package/dist/application/JsonFiles.js +83 -28
- package/dist/application/LinuxHopper.js +9 -6
- package/dist/application/MacHopper.js +15 -18
- package/dist/application/ProcedureAddressResolution.js +11 -0
- package/dist/application/RealHopperAssertions.js +0 -11
- package/dist/application/ReconstructionCoverageService.js +7 -4
- package/dist/application/ReconstructionObligationCandidates.js +1 -1
- package/dist/application/ReconstructionObligationLedgerService.js +4 -3
- package/dist/application/ReferenceSourceImportEntries.js +1 -1
- package/dist/application/Setup.js +21 -17
- package/dist/application/SetupClientConfiguration.js +10 -15
- package/dist/application/SetupHost.js +21 -29
- package/dist/application/SetupPlan.js +11 -9
- package/dist/application/SupportedClients.js +34 -1
- package/dist/application/Uninstall.js +82 -29
- package/dist/application/Update.js +18 -3
- package/dist/application/UpdateMaintenance.js +7 -5
- package/dist/application/UpdateRuntime.js +57 -36
- package/dist/application/WebModuleTraceService.js +4 -2
- package/dist/application/WebNetworkCaptureService.js +4 -2
- package/dist/application/WebRuntimeService.js +5 -3
- package/dist/application/WebScriptExportService.js +32 -6
- package/dist/application/WebSourceLocationService.js +4 -2
- package/dist/application/WorkflowEvidence.js +105 -0
- package/dist/application/XrefsAddressResolution.js +45 -0
- package/dist/application/analysisView/AnalysisViewService.js +76 -0
- package/dist/application/binary/AnalysisClientCleanup.js +30 -5
- package/dist/application/binary/AnalysisProviderEvaluation.js +22 -7
- package/dist/application/binary/AnalysisProviderRegistry.js +4 -6
- package/dist/application/binary/AnalysisSnapshotCache.js +13 -14
- package/dist/application/binary/BinarySession.js +161 -93
- package/dist/application/binary/BinarySessionComposition.js +1 -3
- package/dist/application/binary/BinarySessionExecution.js +3 -5
- package/dist/application/binary/BinarySessionOpen.js +4 -4
- package/dist/application/binary/BinarySessionRecords.js +26 -4
- package/dist/application/binary/BinarySessionStatus.js +18 -7
- package/dist/application/binary/CompositeProvider.js +16 -17
- package/dist/application/binary/LazyAnalysisProvider.js +8 -5
- package/dist/application/binary/SessionProviderRouter.js +27 -135
- package/dist/application/binaryDiagnostics/BinaryLayoutService.js +4 -2
- package/dist/application/binaryDiagnostics/RecordedCrashService.js +4 -2
- package/dist/application/evm/EvmInterfaceService.js +4 -2
- package/dist/application/homebrew.js +48 -0
- package/dist/application/investigation/EvidenceLedger.js +21 -7
- package/dist/application/investigation/InvestigationRecords.js +8 -0
- package/dist/application/javascript/ElectronActiveEvidence.js +9 -13
- package/dist/application/javascript/JavaScriptAnalysisControl.js +34 -0
- package/dist/application/javascript/JavaScriptApplicationEvidence.js +21 -4
- package/dist/application/javascript/JavaScriptApplicationEvidenceGraph.js +19 -2
- package/dist/application/javascript/JavaScriptApplicationService.js +27 -15
- package/dist/application/javascript/JavaScriptApplicationWorkflowService.js +5 -5
- package/dist/application/javascript/JavaScriptArtifactAnalysis.js +10 -7
- package/dist/application/javascript/JavaScriptArtifactGraphBuilder.js +44 -10
- package/dist/application/javascript/JavaScriptArtifactGraphBundlers.js +11 -3
- package/dist/application/javascript/JavaScriptArtifactGraphContext.js +9 -0
- package/dist/application/javascript/JavaScriptArtifactGraphDocuments.js +8 -5
- package/dist/application/javascript/JavaScriptArtifactGraphFindings.js +12 -3
- package/dist/application/javascript/JavaScriptArtifactGraphStructure.js +0 -1
- package/dist/application/javascript/JavaScriptArtifactPathResolution.js +49 -19
- package/dist/application/javascript/JavaScriptArtifactReconstruction.js +56 -8
- package/dist/application/javascript/JavaScriptModuleRelationships.js +38 -9
- package/dist/application/javascript/JavaScriptRecoveryService.js +4 -2
- package/dist/application/javascript/JavaScriptRuntimeObservationService.js +6 -4
- package/dist/application/javascript/JavaScriptRuntimeReconciliationService.js +3 -3
- package/dist/application/javascript/JavaScriptSemanticGraphAsyncProjection.js +2 -3
- package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +63 -61
- package/dist/application/javascript/JavaScriptSemanticGraphChildProcessProjection.js +1 -2
- package/dist/application/javascript/JavaScriptSemanticGraphDataProjection.js +2 -3
- package/dist/application/javascript/JavaScriptSemanticGraphFlowProjection.js +1 -5
- package/dist/application/javascript/JavaScriptSemanticGraphObjectProjection.js +75 -46
- package/dist/application/javascript/JavaScriptSemanticGraphResourceProjection.js +2 -3
- package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +64 -19
- package/dist/application/managed/ManagedApplicationGraphService.js +4 -3
- package/dist/application/managed/ManagedMemberComparisonService.js +9 -5
- package/dist/application/managed/ManagedNativeVerificationService.js +6 -4
- package/dist/application/managed/ManagedReconstructionService.js +4 -3
- package/dist/application/process/ProcessCli.js +25 -17
- package/dist/application/process/ProcessEvidence.js +4 -4
- package/dist/application/workflowInputError.js +18 -0
- package/dist/artifacts/ArtifactProvider.js +48 -13
- package/dist/artifacts/ArtifactReader.js +31 -0
- package/dist/artifacts/DirectoryArtifactReader.js +2 -1
- package/dist/artifacts/MachOSliceArtifactReader.js +106 -15
- package/dist/artifacts/NativeDmgArtifactReader.js +73 -21
- package/dist/artifacts/SafeOutputTree.js +16 -2
- package/dist/artifacts/ZipArtifactReader.js +11 -4
- package/dist/artifacts/apple/AppleAssetCatalogAnalysis.js +26 -5
- package/dist/artifacts/apple/DylibResolutionReader.js +17 -7
- package/dist/artifacts/apple/InterfaceBuilderAnalysis.js +176 -56
- package/dist/artifacts/apple/InterfaceBuilderDecodeBudget.js +195 -0
- package/dist/artifacts/apple/KeyedArchiveReader.js +55 -23
- package/dist/artifacts/apple/MachoLoadCommandReader.js +92 -31
- package/dist/artifacts/apple/NibArchive.js +81 -14
- package/dist/artifacts/apple/NibViewHierarchy.js +10 -3
- package/dist/artifacts/apple/PlistNumberLiterals.js +164 -0
- package/dist/artifacts/extraction/ArtifactExtraction.js +78 -21
- package/dist/artifacts/inventory/ArtifactGraphConstruction.js +79 -68
- package/dist/artifacts/inventory/ArtifactInventory.js +0 -1
- package/dist/artifacts/inventory/reader.js +3 -3
- package/dist/artifacts/inventory/scanCanonical.js +59 -38
- package/dist/artifacts/inventory/scanReader.js +5 -9
- package/dist/artifacts/javascript/JavaScriptArtifactFiles.js +6 -2
- package/dist/browser/BrowserScenarioPartialObservation.js +106 -0
- package/dist/browser/CdpBrowserProvider.js +2 -3
- package/dist/browser/CdpCaptureCompleteness.js +2 -0
- package/dist/browser/CdpCaptureEventHandlers.js +78 -15
- package/dist/browser/CdpCaptureEventTypes.js +5 -1
- package/dist/browser/CdpCaptureEvents.js +25 -1
- package/dist/browser/CdpCaptureValues.js +20 -0
- package/dist/browser/CdpConnection.js +30 -11
- package/dist/browser/CdpElectronProvider.js +0 -2
- package/dist/browser/CdpElectronScriptEvents.js +2 -8
- package/dist/browser/CdpElectronScripts.js +2 -3
- package/dist/browser/CdpOptionalCommand.js +2 -3
- package/dist/browser/CdpPageCapture.js +23 -1
- package/dist/browser/CdpPageCaptureScripts.js +2 -3
- package/dist/browser/CdpSafeMetadata.js +10 -10
- package/dist/browser/PlaywrightBrowserScenarioProvider.js +59 -44
- package/dist/browser/PlaywrightElectronActiveActions.js +34 -79
- package/dist/browser/PlaywrightElectronActiveProjection.js +141 -0
- package/dist/browser/PlaywrightElectronActiveProvider.js +133 -130
- package/dist/browser/PlaywrightScenarioArtifacts.js +1 -1
- package/dist/browser/PlaywrightScenarioBrowser.js +139 -39
- package/dist/browser/PlaywrightScenarioEvents.js +1 -1
- package/dist/browser/PlaywrightScenarioSession.js +39 -22
- package/dist/browser/WebSourceMapFetcher.js +426 -72
- package/dist/browser/assets/LocalWebScriptArtifacts.js +2 -2
- package/dist/browser/assets/ScriptCaptureAdapters.js +1 -1
- package/dist/browser/history/CaptureFailures.js +41 -1
- package/dist/browser/history/CaptureRelease.js +5 -0
- package/dist/browser/history/HarCaptureAdapter.js +3 -3
- package/dist/browser/history/HarJson.js +3 -2
- package/dist/browser/history/HistoricalCaptureDecoder.js +4 -2
- package/dist/browser/history/MitmproxyCaptureAdapter.js +4 -2
- package/dist/catalogIdentity.js +0 -1
- package/dist/cli/analysisSelector.js +23 -0
- package/dist/cli/analysisViewCommands.js +36 -0
- package/dist/cli/applicationCommands.js +2 -3
- package/dist/cli/artifactCommands.js +11 -12
- package/dist/cli/coreAnalysisCommands.js +3 -3
- package/dist/cli/coreBinaryCommands.js +100 -37
- package/dist/cli/coreNativeCommands.js +9 -10
- package/dist/cli/electronCommands.js +10 -9
- package/dist/cli/interactiveSetup.js +6 -6
- package/dist/cli/javascriptApplicationAnalysis.js +7 -3
- package/dist/cli/jsonOutput.js +4 -99
- package/dist/cli/managedCommands.js +7 -8
- package/dist/cli/nativeCallCommands.js +3 -5
- package/dist/cli/omittableDefaults.js +50 -0
- package/dist/cli/processCommands.js +3 -2
- package/dist/cli/setupCommands.js +16 -15
- package/dist/cli/utilityCommands.js +9 -9
- package/dist/cli/webRuntimeCommands.js +8 -8
- package/dist/cli.js +18 -9
- package/dist/cliBrowserScenarioCommands.js +2 -2
- package/dist/cliCommandNames.js +1 -1
- package/dist/cliJsonInput.js +24 -5
- package/dist/cliOutput.js +0 -38
- package/dist/composition/auxiliaryAnalysisProviders.js +27 -23
- package/dist/composition/binary.js +9 -9
- package/dist/composition/browserScenario.js +2 -1
- package/dist/composition/directAnalysis.js +20 -13
- package/dist/composition/electronScenario.js +1 -1
- package/dist/composition/optionalObservationProviders.js +12 -7
- package/dist/config/environment.js +10 -0
- package/dist/config/ghidraStartupTimeout.js +12 -0
- package/dist/config/homeDirectory.js +12 -0
- package/dist/config/mcpResponseBudget.js +30 -0
- package/dist/config/parseConfig.js +8 -3
- package/dist/config/parsers.js +19 -22
- package/dist/contracts/analysisViewToolContracts.js +56 -0
- package/dist/contracts/applicationToolContracts.js +5 -4
- package/dist/contracts/artifactComparisonExample.js +2 -2
- package/dist/contracts/artifactToolContracts.js +1 -1
- package/dist/contracts/browserScenarioToolContracts.js +1 -1
- package/dist/contracts/browserToolContracts.js +19 -15
- package/dist/contracts/enhancedInputs.js +7 -5
- package/dist/contracts/enhancedToolContracts.js +7 -6
- package/dist/contracts/evm/evmToolContracts.js +1 -1
- package/dist/contracts/functionWorkflowToolContracts.js +1 -1
- package/dist/contracts/hopperMemoryContracts.js +2 -5
- package/dist/contracts/inputSchemaPresentation.js +90 -0
- package/dist/contracts/investigationExamples.js +4 -3
- package/dist/contracts/javascript/electronToolContracts.js +2 -2
- package/dist/contracts/javascript/javascriptApplicationWorkflowExamples.js +0 -20
- package/dist/contracts/javascript/javascriptExportShapeComparisonExample.js +245 -0
- package/dist/contracts/javascript/javascriptRuntimeObservationToolContracts.js +1 -1
- package/dist/contracts/managed/managedToolContracts.js +7 -14
- package/dist/contracts/managed/managedWorkflowToolContracts.js +1 -1
- package/dist/contracts/mobileApplicationGraphExamples.js +3 -3
- package/dist/contracts/native/binaryDiagnosticsToolContracts.js +1 -1
- package/dist/contracts/native/nativeToolContracts.js +5 -3
- package/dist/contracts/officialToolContracts.js +16 -16
- package/dist/contracts/promptContracts.js +5 -5
- package/dist/contracts/providerSelection.js +1 -1
- package/dist/contracts/sessionLifecycleInputs.js +3 -7
- package/dist/contracts/sessionStatusContract.js +2 -4
- package/dist/contracts/sessionToolContracts.js +18 -8
- package/dist/contracts/sessionToolSchemas.js +3 -19
- package/dist/contracts/toolContractExamples.js +0 -1
- package/dist/contracts/toolContractHelpers.js +4 -1
- package/dist/contracts/toolContracts.js +2 -0
- package/dist/contracts/toolEffects.js +1 -1
- package/dist/contracts/toolOutputSchemaGroups.js +160 -115
- package/dist/contracts/toolOutputSchemaPrimitives.js +28 -20
- package/dist/contracts/toolSchemaMetadata.js +41 -33
- package/dist/contracts/webNetworkCaptureToolContracts.js +2 -2
- package/dist/contracts/webRuntimeToolContracts.js +1 -1
- package/dist/contracts/webScriptToolContracts.js +1 -1
- package/dist/doctorRuntime.js +7 -5
- package/dist/domain/analysisErrorBase.js +8 -3
- package/dist/domain/analysisErrorCore.js +6 -1
- package/dist/domain/analysisErrorPresentation.js +90 -20
- package/dist/domain/analysisErrorProjection.js +130 -32
- package/dist/domain/analysisSnapshot.js +29 -31
- package/dist/domain/analysisView/analysisView.js +243 -0
- package/dist/domain/analysisView/analysisViewCoverage.js +19 -0
- package/dist/domain/analysisView/binaryLayoutView.js +159 -0
- package/dist/domain/analysisView/javascriptApplicationView.js +238 -0
- package/dist/domain/android/androidAnalysis.js +2 -4
- package/dist/domain/android/androidApplication.js +18 -10
- package/dist/domain/apple/appleApplication.js +42 -15
- package/dist/domain/apple/dyldEnvironment.js +73 -0
- package/dist/domain/apple/dylibResolution.js +130 -12
- package/dist/domain/apple/dylibResolutionFindings.js +9 -7
- package/dist/domain/apple/interfaceBuilderGraph.js +25 -14
- package/dist/domain/apple/interfaceBuilderKeyedArchive.js +13 -3
- package/dist/domain/apple/keyedArchive.js +35 -3
- package/dist/domain/apple/machoContainer.js +54 -0
- package/dist/domain/apple/plistNumbers.js +76 -0
- package/dist/domain/artifactComparison.js +15 -6
- package/dist/domain/artifactGraph.js +16 -3
- package/dist/domain/artifactIdentity.js +29 -0
- package/dist/domain/artifactInventoryEvidence.js +28 -40
- package/dist/domain/artifactOperationError.js +3 -3
- package/dist/domain/artifactPartialObservation.js +1 -0
- package/dist/domain/artifactPathSyntax.js +49 -0
- package/dist/domain/binaryTarget.js +39 -13
- package/dist/domain/bridgeCandidateProjection.js +71 -0
- package/dist/domain/browserCaptureComparison.js +13 -49
- package/dist/domain/browserCompleteness.js +1 -0
- package/dist/domain/browserNetworkEvidence.js +10 -4
- package/dist/domain/browserObservation.js +0 -1
- package/dist/domain/browserObservationError.js +24 -5
- package/dist/domain/browserObservationSchemas.js +14 -3
- package/dist/domain/browserScenario.js +0 -1
- package/dist/domain/browserScenarioCapture.js +1 -2
- package/dist/domain/browserScenarioDiff.js +0 -2
- package/dist/domain/browserScenarioDiffEvidence.js +0 -12
- package/dist/domain/browserScenarioDiffValues.js +2 -2
- package/dist/domain/browserScenarioValues.js +5 -10
- package/dist/domain/bundleComparison.js +3 -2
- package/dist/domain/callPath.js +8 -9
- package/dist/domain/callPathSchemas.js +2 -2
- package/dist/domain/canonicalJsonDigestSteps.js +133 -0
- package/dist/domain/canonicalOrdering.js +9 -5
- package/dist/domain/changedBehavior.js +9 -9
- package/dist/domain/comparisonSourceEvidence.js +40 -0
- package/dist/domain/completionLedgerGeneration.js +2 -1
- package/dist/domain/configurationErrors.js +13 -1
- package/dist/domain/conformancePackage.js +4 -3
- package/dist/domain/evidence.js +65 -36
- package/dist/domain/evidenceBundle.js +47 -8
- package/dist/domain/evidenceCompletionLedger.js +2 -1
- package/dist/domain/evidenceErrors.js +12 -1
- package/dist/domain/explicitSensitiveFailure.js +17 -1
- package/dist/domain/firmware/firmwareAnalysis.js +6 -7
- package/dist/domain/functionComparison.js +4 -5
- package/dist/domain/functionComparisonDimensions.js +120 -87
- package/dist/domain/functionComparisonNormalization.js +23 -34
- package/dist/domain/functionComparisonResults.js +1 -4
- package/dist/domain/functionComparisonSchemas.js +2 -8
- package/dist/domain/functionDossierEvidence.js +2 -37
- package/dist/domain/hopperErrors.js +23 -2
- package/dist/domain/hopperValues.js +51 -8
- package/dist/domain/immutableJson.js +114 -0
- package/dist/domain/inputIssueProjection.js +3 -0
- package/dist/domain/javascript/electronActiveObservation.js +47 -64
- package/dist/domain/javascript/electronObservation.js +14 -3
- package/dist/domain/javascript/electronStaticAnalysisBrowser.js +10 -9
- package/dist/domain/javascript/electronStaticAnalysisIpc.js +2 -1
- package/dist/domain/javascript/electronStaticAnalysisNative.js +2 -1
- package/dist/domain/javascript/electronStaticAnalysisValues.js +6 -12
- package/dist/domain/javascript/javascriptApplicationAnalysis.js +71 -23
- package/dist/domain/javascript/javascriptApplicationEvidenceSchemas.js +2 -0
- package/dist/domain/javascript/javascriptApplicationGraph.js +39 -3
- package/dist/domain/javascript/javascriptApplicationGraphSchemas.js +9 -2
- package/dist/domain/javascript/javascriptApplicationVersionItems.js +5 -2
- package/dist/domain/javascript/javascriptApplicationVersionKeys.js +2 -1
- package/dist/domain/javascript/javascriptAstValues.js +20 -0
- package/dist/{application/javascript/JavaScriptReturnShapeProjection.js → domain/javascript/javascriptExportReturnShapeProjection.js} +4 -4
- package/dist/domain/javascript/javascriptExportShapeComparison.js +7 -1
- package/dist/domain/javascript/javascriptExportShapeComparisonIdentity.js +6 -1
- package/dist/domain/javascript/javascriptExportShapeComparisonSchemas.js +29 -1
- package/dist/domain/javascript/javascriptExportShapeSelection.js +5 -5
- package/dist/domain/javascript/javascriptExportShapeVariants.js +67 -14
- package/dist/domain/javascript/javascriptFeatureSeed.js +20 -0
- package/dist/domain/javascript/javascriptFeatureTraversal.js +0 -1
- package/dist/domain/javascript/javascriptNativeHandoff.js +1 -1
- package/dist/domain/javascript/javascriptRecovery.js +3 -8
- package/dist/domain/javascript/javascriptRuntimeLoadState.js +0 -1
- package/dist/domain/javascript/javascriptRuntimeObservation.js +10 -2
- package/dist/domain/javascript/javascriptRuntimeReconciliationMatching.js +1 -1
- package/dist/domain/javascript/javascriptRuntimeReconciliationParsing.js +3 -2
- package/dist/domain/javascript/javascriptRuntimeStaticCandidates.js +0 -1
- package/dist/domain/javascript/javascriptSemanticAnalysis.js +106 -5
- package/dist/domain/javascript/javascriptSemanticAsyncEffects.js +2 -1
- package/dist/domain/javascript/javascriptSemanticCalls.js +2 -1
- package/dist/domain/javascript/javascriptSemanticChildProcesses.js +2 -1
- package/dist/domain/javascript/javascriptSemanticCoverage.js +6 -5
- package/dist/domain/javascript/javascriptSemanticDataEffectHelpers.js +9 -17
- package/dist/domain/javascript/javascriptSemanticDataEffects.js +23 -6
- package/dist/domain/javascript/javascriptSemanticGraph.js +98 -43
- package/dist/domain/javascript/javascriptSemanticGraphSchemas.js +1 -0
- package/dist/domain/javascript/javascriptSemanticMemberMutations.js +77 -20
- package/dist/domain/javascript/javascriptSemanticMutationValues.js +21 -27
- package/dist/domain/javascript/javascriptSemanticObjects.js +83 -42
- package/dist/domain/javascript/javascriptSemanticPrimitives.js +18 -21
- package/dist/domain/javascript/javascriptSemanticProjection.js +2 -3
- package/dist/domain/javascript/javascriptSemanticPromises.js +2 -1
- package/dist/domain/javascript/javascriptSemanticQuerySchemas.js +8 -4
- package/dist/domain/javascript/javascriptSemanticResourceLimits.js +77 -0
- package/dist/domain/javascript/javascriptSemanticResources.js +1 -1
- package/dist/domain/javascript/javascriptSemanticReturns.js +32 -17
- package/dist/domain/javascript/javascriptSemanticSlots.js +72 -0
- package/dist/domain/javascript/javascriptSemanticValues.js +126 -61
- package/dist/domain/javascript/javascriptSourceMapPaths.js +104 -0
- package/dist/domain/javascript/javascriptSourceParser.js +6 -2
- package/dist/domain/javascript/javascriptStaticAnalysis.js +22 -17
- package/dist/domain/javascript/javascriptStaticAnalysisBundler.js +5 -3
- package/dist/domain/javascript/javascriptStaticAnalysisCalls.js +16 -5
- package/dist/domain/javascript/javascriptStaticAnalysisFindings.js +66 -7
- package/dist/domain/javascript/javascriptStaticAnalysisHelpers.js +28 -17
- package/dist/domain/javascript/javascriptStaticAnalysisState.js +3 -2
- package/dist/domain/javascript/sourceToBundleComparison.js +12 -3
- package/dist/domain/javascript/sourceToBundleSignals.js +47 -19
- package/dist/domain/jsonSerialization.js +109 -0
- package/dist/domain/jsonValue.js +90 -6
- package/dist/domain/localPath.js +6 -0
- package/dist/domain/managed/managedApplicationGraph.js +10 -10
- package/dist/domain/managed/managedArtifact.js +6 -4
- package/dist/domain/managed/managedInspectionEvidence.js +16 -0
- package/dist/domain/managed/managedMemberComparison.js +2 -9
- package/dist/domain/managed/managedMemberComparisonMatch.js +5 -9
- package/dist/domain/managed/managedNativeVerification.js +3 -11
- package/dist/domain/managed/managedNativeVerificationMatch.js +9 -3
- package/dist/domain/native/binaryLayout.js +2 -3
- package/dist/domain/native/fileOffsetPartialObservation.js +1 -0
- package/dist/domain/native/nativeApiBoundary.js +1 -1
- package/dist/domain/native/nativeCallObservation.js +37 -13
- package/dist/domain/native/nativeCallPartialObservation.js +33 -0
- package/dist/domain/native/nativeInstruction.js +7 -0
- package/dist/domain/native/recordedCrash.js +2 -3
- package/dist/domain/offsetDateTime.js +17 -0
- package/dist/domain/process/processCapture.js +21 -16
- package/dist/domain/process/processCaptureCoverage.js +67 -0
- package/dist/domain/process/processCaptureExample.js +2 -1
- package/dist/domain/process/processCaptureParsing.js +1 -34
- package/dist/domain/process/processCaptureValidation.js +81 -13
- package/dist/domain/process/processComparison.js +79 -26
- package/dist/domain/process/processObservation.js +10 -2
- package/dist/domain/process/processScenario.js +35 -12
- package/dist/domain/process/processTraceComparison.js +0 -2
- package/dist/domain/process/processTraceDimensionProjection.js +1 -1
- package/dist/domain/process/processTraceEvaluation.js +15 -11
- package/dist/domain/process/processTraceSpecification.js +3 -4
- package/dist/domain/propertyListKeys.js +1 -1
- package/dist/domain/propertyListXmlText.js +19 -0
- package/dist/domain/providerAdapterError.js +3 -1
- package/dist/domain/providerOperationHealth.js +54 -0
- package/dist/domain/reconstructionCoverage.js +5 -2
- package/dist/domain/reconstructionObligationLedgerSchemas.js +2 -1
- package/dist/domain/reconstructionReadinessSchemas.js +2 -1
- package/dist/domain/reconstructionVerification.js +9 -46
- package/dist/domain/reconstructionVerificationSchemas.js +4 -3
- package/dist/domain/referenceSourceGraph.js +20 -21
- package/dist/domain/staticRuntimeCorrelation.js +8 -45
- package/dist/domain/stringPatterns.js +6 -0
- package/dist/domain/swiftSymbolClassification.js +61 -0
- package/dist/domain/symbolAnalysis.js +66 -18
- package/dist/domain/webBundleAnalysis.js +20 -8
- package/dist/domain/webBundleAnalyzerInspection.js +13 -8
- package/dist/domain/webBundleAnalyzerResult.js +41 -2
- package/dist/domain/webCaptureDiff.js +0 -1
- package/dist/domain/webCaptureDiffSchemas.js +6 -3
- package/dist/domain/webEventListeners.js +3 -2
- package/dist/domain/webExecution.js +3 -2
- package/dist/domain/webRuntime.js +19 -7
- package/dist/domain/webScriptExport.js +1 -1
- package/dist/domain/webSourceLocation.js +1 -0
- package/dist/dotnet/ManagedArtifactInspector.js +2 -19
- package/dist/dotnet/ManagedMemberInspector.js +12 -18
- package/dist/dotnet/ManagedMemberInspectorCore.js +47 -44
- package/dist/dotnet/ManagedMemberRows.js +75 -62
- package/dist/dotnet/ManagedMetadataInventory.js +16 -22
- package/dist/dotnet/ManagedMethodBodyReader.js +4 -0
- package/dist/dotnet/ManagedNativeBoundaryHelpers.js +109 -94
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +12 -21
- package/dist/dotnet/ManagedReaderFailure.js +16 -0
- package/dist/dotnet/ManagedStaticProvider.js +3 -5
- package/dist/evaluation/AgentEvaluationFixtures.js +250 -0
- package/dist/evaluation/AgentEvaluationReport.js +28 -0
- package/dist/evaluation/CodexAgentEval.js +12 -8
- package/dist/evaluation/KnownAnswerEvaluation.js +281 -0
- package/dist/evm/EvmoleInterfaceProvider.js +2 -1
- package/dist/firmware/FirmwareCommand.js +9 -5
- package/dist/firmware/FirmwareFiles.js +1 -1
- package/dist/firmware/FirmwareProvider.js +4 -4
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraAnalysisProfile.js +7 -5
- package/dist/ghidra/GhidraClient.js +126 -34
- package/dist/ghidra/GhidraClientStartup.js +0 -2
- package/dist/ghidra/GhidraDiagnostics.js +7 -7
- package/dist/ghidra/GhidraDoctor.js +6 -5
- package/dist/ghidra/GhidraFunctionValues.js +13 -12
- package/dist/ghidra/GhidraInstallation.js +58 -33
- package/dist/ghidra/GhidraInventoryValues.js +14 -4
- package/dist/ghidra/GhidraJavaLaunch.js +66 -0
- package/dist/ghidra/GhidraLauncher.js +47 -22
- package/dist/ghidra/GhidraProvider.js +6 -2
- package/dist/ghidra/GhidraProviderCapabilities.js +20 -2
- package/dist/ghidra/GhidraProviderClient.js +36 -15
- package/dist/ghidra/GhidraSessionError.js +13 -7
- package/dist/ghidra/GhidraSessionRoot.js +39 -0
- package/dist/ghidra/GhidraTargetSnapshot.js +47 -12
- package/dist/ghidra/GhidraTransport.js +20 -0
- package/dist/ghidra/extensions/GhidraExtensions.js +17 -10
- package/dist/ghidra/extensions/nativeaot/NativeAotAdapter.js +8 -2
- package/dist/hopper/BridgeLauncher.js +65 -56
- package/dist/hopper/HopperAnalysisProfile.js +65 -12
- package/dist/hopper/HopperCleanup.js +63 -22
- package/dist/hopper/HopperClient.js +288 -59
- package/dist/hopper/HopperFileOffset.js +237 -0
- package/dist/hopper/HopperMachOImage.js +197 -0
- package/dist/hopper/HopperOperationStage.js +6 -0
- package/dist/hopper/HopperProvider.js +71 -19
- package/dist/hopper/HopperProviderCapabilities.js +19 -1
- package/dist/hopper/HopperRegexSearch.js +134 -0
- package/dist/hopper/HopperRegexWorker.js +27 -0
- package/dist/hopper/HopperRequestQueue.js +68 -19
- package/dist/hopper/HopperTargetLease.js +133 -49
- package/dist/hopper/LinuxPrivateDisplayProbe.js +6 -0
- package/dist/ida/IdaConfiguration.js +8 -3
- package/dist/ida/IdaInput.js +1 -7
- package/dist/ida/IdaMcpConnection.js +8 -4
- package/dist/ida/IdaOperationRunner.js +3 -3
- package/dist/ida/IdaProvider.js +8 -12
- package/dist/ida/IdaSessionClient.js +20 -18
- package/dist/ida/IdaWorkspace.js +12 -13
- package/dist/inspector/JavaScriptRuntimeScope.js +9 -1
- package/dist/inspector/V8InspectorCaptureProjection.js +9 -4
- package/dist/inspector/V8InspectorProvider.js +82 -36
- package/dist/javascript/recovery/WakaruCommand.js +7 -2
- package/dist/javascript/recovery/WakaruExecution.js +5 -2
- package/dist/javascript/sourceMaps/DecodedSourceMap.js +47 -0
- package/dist/javascript/sourceMaps/SourceMapCommand.js +16 -0
- package/dist/javascript/sourceMaps/SourceMapFormat.js +79 -31
- package/dist/javascript/sourceMaps/TraceSourceMap.js +14 -28
- package/dist/main/shutdown.js +11 -3
- package/dist/main/startup.js +9 -2
- package/dist/main/transport.js +22 -2
- package/dist/main.js +11 -18
- package/dist/mcpDoctor.js +62 -2
- package/dist/native/AppleDispatchCoverage.js +47 -6
- package/dist/native/AppleDispatchDecodeFacts.js +6 -0
- package/dist/native/AppleDispatchMetadata.js +6 -3
- package/dist/native/AppleMachoFixups.js +48 -24
- package/dist/native/AppleMachoSelection.js +48 -22
- package/dist/native/AppleObjcCategories.js +6 -2
- package/dist/native/AppleObjcDispatchFacets.js +5 -2
- package/dist/native/AppleObjcProperties.js +2 -1
- package/dist/native/AppleSwiftDispatchFacets.js +27 -21
- package/dist/native/AppleSwiftVtables.js +21 -15
- package/dist/native/CommandRunner.js +87 -88
- package/dist/native/LldbCallTracer.js +372 -103
- package/dist/native/LldbRetainedObservations.js +178 -0
- package/dist/native/NativeCallObservation.js +62 -3
- package/dist/native/NativeMacOSProvider.js +122 -31
- package/dist/native/NativeUiHelperRuntime.js +11 -2
- package/dist/native/NativeUiObservation.js +2 -2
- package/dist/native/SignatureTargetBinding.js +155 -0
- package/dist/native/parsers/lipo.js +71 -1
- package/dist/native/pwndbg/PwndbgCoreContext.js +25 -5
- package/dist/native/pwntools/PwntoolsDecoder.js +2 -1
- package/dist/native/pwntools/RecordedCrashStructureBindings.js +2 -0
- package/dist/process/DarwinProcessRunTokenReader.js +23 -10
- package/dist/process/ExecFileOutput.js +108 -6
- package/dist/process/OwnedCommand.js +7 -2
- package/dist/process/PrivateRuntimeRoot.js +10 -5
- package/dist/process/ProcessOwnership.js +204 -57
- package/dist/process/ProcessOwnershipObservation.js +60 -9
- package/dist/process/ProviderProcess.js +39 -10
- package/dist/process/capture/FilesystemSnapshot.js +50 -13
- package/dist/process/capture/ProcessCaptureError.js +15 -2
- package/dist/process/capture/ProcessCaptureLifecycle.js +235 -81
- package/dist/process/capture/ProcessFilesystemEffects.js +33 -3
- package/dist/process/capture/ProcessHarness.js +21 -25
- package/dist/process/capture/ProcessNormalization.js +20 -2
- package/dist/process/capture/ProcessSampling.js +25 -2
- package/dist/process/capture/TerminalRenderer.js +14 -0
- package/dist/process/snapshotEnvironment.js +14 -0
- package/dist/server/EvidenceMcpServer.js +157 -0
- package/dist/server/createServer.js +61 -41
- package/dist/server/mcpClientMetadata.js +12 -5
- package/dist/server/promptCompletion.js +3 -8
- package/dist/server/registerAnalysisViewTool.js +15 -0
- package/dist/server/registerAndroidTools.js +2 -5
- package/dist/server/registerApplicationTools/compareExportShapes.js +4 -5
- package/dist/server/registerApplicationTools/compareSourceToBundle.js +4 -5
- package/dist/server/registerApplicationTools/compareVersions.js +4 -5
- package/dist/server/registerApplicationTools/coverage.js +1 -2
- package/dist/server/registerApplicationTools/helpers.js +1 -4
- package/dist/server/registerApplicationTools/obligationLedger.js +4 -5
- package/dist/server/registerApplicationTools/projectMobileApplicationGraph.js +3 -4
- package/dist/server/registerApplicationTools/traceFeature.js +4 -5
- package/dist/server/registerApplicationTools/traceSemantics.js +4 -5
- package/dist/server/registerArtifactComparisonTool.js +13 -10
- package/dist/server/registerBinaryDiagnosticsTools.js +2 -5
- package/dist/server/registerBrowserScenarioTool.js +3 -6
- package/dist/server/registerBrowserTools.js +13 -18
- package/dist/server/registerBundleComparisonTool.js +5 -7
- package/dist/server/registerCloseLifecycleTool.js +9 -20
- package/dist/server/registerElectronTools.js +10 -15
- package/dist/server/registerEnhancedTools.js +36 -77
- package/dist/server/registerEvidenceTools.js +3 -6
- package/dist/server/registerEvmTools.js +2 -5
- package/dist/server/registerFirmwareTools.js +2 -5
- package/dist/server/registerFunctionComparisonTool.js +15 -12
- package/dist/server/registerInvestigationTools.js +16 -17
- package/dist/server/registerJavaScriptRecoveryTool.js +2 -5
- package/dist/server/registerJavaScriptRuntimeObservationTools.js +6 -8
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +5 -8
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +4 -7
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +6 -9
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +6 -9
- package/dist/server/registerOfficialTools.js +4 -21
- package/dist/server/registerProcessComparisonTool.js +74 -48
- package/dist/server/registerRecordedCrashTools.js +2 -5
- package/dist/server/registerSessionRecordTools.js +19 -24
- package/dist/server/registerSessionStatusTool.js +19 -6
- package/dist/server/registerSessionTools.js +20 -18
- package/dist/server/registerWebModuleTool.js +2 -5
- package/dist/server/registerWebNetworkCaptureTool.js +2 -5
- package/dist/server/registerWebRuntimeTools.js +4 -9
- package/dist/server/registerWebScriptTool.js +2 -5
- package/dist/server/registerWebSourceLocationTool.js +2 -5
- package/dist/server/runDerivedOperation.js +15 -3
- package/dist/server/sessionAvailabilityPolicy.js +0 -1
- package/dist/server/toolRegistrationOptions.js +2 -2
- package/dist/server/toolResult.js +75 -51
- package/dist/server/toolResultEncoding.js +34 -0
- package/dist/windows/WindowsNativeLoader.js +1 -0
- package/dist/windows/WindowsOwnedProcess.js +60 -15
- package/dist/windows/WindowsPrivateRuntime.js +7 -8
- package/install.sh +1 -1
- package/native/windows/README.md +3 -1
- package/native/windows/build/manifest.json +2 -2
- package/native/windows/build/rea-windows-x64.node +0 -0
- package/package.json +44 -30
- package/scripts/electron-active-hook-boundaries.cjs +18 -20
- package/scripts/electron-active-hook.cjs +241 -37
- package/scripts/rea.mjs +3 -6
- package/skills/reverse-engineer-anything/SKILL.md +12 -3
- package/skills/reverse-engineer-anything/references/android-applications.md +6 -3
- package/skills/reverse-engineer-anything/references/evidence-workflows.md +8 -4
- package/skills/reverse-engineer-anything/references/javascript-applications.md +20 -3
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +9 -0
- package/dist/config.js +0 -1
- package/dist/contracts/browserCaptureToolInputSchema.js +0 -43
- package/dist/contracts/process/processCaptureExample.js +0 -2
- package/dist/contracts/toolOutputSchemas.js +0 -2
- package/dist/ghidra/GhidraDefaults.js +0 -2
- package/dist/main/reload.js +0 -12
- package/dist/main/state.js +0 -3
- 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
|
|
7
|
-
the duration elapses.
|
|
8
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
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
|
|
356
|
+
if objc_method:
|
|
125
357
|
error = lldb.SBError()
|
|
126
358
|
text = process.ReadCStringFromMemory(
|
|
127
|
-
|
|
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
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
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
|
-
|
|
185
|
-
|
|
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 =
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
"
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
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):
|