Files
luma/Sources/LumaCore/Models/MemoryPage.swift
Ole André Vadla Ravnås 12d5491c22 Sync disasm cache across collab
Identify a process instance by a deterministic identity returned
from the agent (per-OS, with a Process.mainModule + pid fallback)
and stash it on ProcessSession.processInfo. Rekey memory_page
into memory_page_module (module UUID + offset) so cached bytes
survive ASLR, and memory_page_anon (process identity + address)
for JIT / heap regions that only survive within one process
instance. Purge stale anon pages on every fresh attach.

Add updateProcessInfo, updateModuleAnalysis and updateInsight
SessionOps plus a side-channel publish-memory-page op and a
+fetch-memory-page request. The driver write-throughs every
page it fetches; non-drivers pull on miss and persist locally.
Module-analysis rows flow the same way so non-drivers can key
their cache by module UUID. The lab-join snapshot now carries
processInfo and module_analyses too.

Refresh actions on the insight detail view: Reread Bytes drops
the pages overlapping the visible range; Reanalyze Module drops
the module's analysis and pages, re-running r2 on next access.

The macOS detail view now reads the insight live from
insightsBySession via observation; GTK forwards .insightUpdated
into the detail and reschedules a refresh when the resolved
address changes.
2026-05-19 15:16:48 +02:00

99 lines
3.0 KiB
Swift

import Foundation
import GRDB
public enum MemoryPage {
public static let size: UInt64 = 0x1000
public static let mask: UInt64 = size &- 1
public static func base(of address: UInt64) -> UInt64 {
address & ~mask
}
}
public enum MemoryPageRegion: Sendable, Equatable {
case module(uuid: String, offset: UInt64)
case anonymous(identity: String, address: UInt64)
}
public struct MemoryPagePublish: Sendable {
public let region: MemoryPageRegion
public let bytes: Data
public let capturedAt: Date
public init(region: MemoryPageRegion, bytes: Data, capturedAt: Date = Date()) {
self.region = region
self.bytes = bytes
self.capturedAt = capturedAt
}
}
public struct MemoryPageModule: Codable, Sendable, FetchableRecord, PersistableRecord {
public static let databaseTableName = "memory_page_module"
public var sessionID: UUID
public var moduleUUID: String
public var offset: UInt64
public var bytes: Data
public var capturedAt: Date
public init(sessionID: UUID, moduleUUID: String, offset: UInt64, bytes: Data, capturedAt: Date = Date()) {
self.sessionID = sessionID
self.moduleUUID = moduleUUID
self.offset = offset
self.bytes = bytes
self.capturedAt = capturedAt
}
public func encode(to container: inout PersistenceContainer) {
container["session_id"] = sessionID
container["module_uuid"] = moduleUUID
container["offset"] = Int64(bitPattern: offset)
container["bytes"] = bytes
container["captured_at"] = capturedAt
}
public init(row: Row) throws {
sessionID = row["session_id"]
moduleUUID = row["module_uuid"]
let raw: Int64 = row["offset"]
offset = UInt64(bitPattern: raw)
bytes = row["bytes"]
capturedAt = row["captured_at"]
}
}
public struct MemoryPageAnon: Codable, Sendable, FetchableRecord, PersistableRecord {
public static let databaseTableName = "memory_page_anon"
public var sessionID: UUID
public var processIdentity: String
public var address: UInt64
public var bytes: Data
public var capturedAt: Date
public init(sessionID: UUID, processIdentity: String, address: UInt64, bytes: Data, capturedAt: Date = Date()) {
self.sessionID = sessionID
self.processIdentity = processIdentity
self.address = address
self.bytes = bytes
self.capturedAt = capturedAt
}
public func encode(to container: inout PersistenceContainer) {
container["session_id"] = sessionID
container["process_identity"] = processIdentity
container["address"] = Int64(bitPattern: address)
container["bytes"] = bytes
container["captured_at"] = capturedAt
}
public init(row: Row) throws {
sessionID = row["session_id"]
processIdentity = row["process_identity"]
let raw: Int64 = row["address"]
address = UInt64(bitPattern: raw)
bytes = row["bytes"]
capturedAt = row["captured_at"]
}
}