Files
luma/Sources/LumaCore/Models/ModuleAnalysis.swift
Ole André Vadla Ravnås dc6af656fd Persist basic blocks per analyzed function
Split ModuleAnalysis persistence into module_analysis,
module_analysis_function and module_analysis_block tables.
Harvest blocks via afbj and use them to answer enclosingFunction
offline. R2Hex accepts both 0x-prefixed strings and raw integers,
since cfg.json.num=hex doesn't cover afbj. When the cache is
present but blocks are missing, replay anyway unless we're online
and can re-analyze.
2026-05-20 19:17:57 +02:00

97 lines
2.7 KiB
Swift

import Foundation
import GRDB
public struct ModuleAnalysis: Codable, Sendable {
public var sessionID: UUID
public var modulePath: String
public var moduleUUID: String?
public var mappedRanges: [ProcessNode.ModuleRange]
public var functions: [Function]
public var analyzedAt: Date
public enum CodingKeys: String, CodingKey {
case sessionID = "session_id"
case modulePath = "module_path"
case moduleUUID = "module_uuid"
case mappedRanges = "mapped_ranges"
case functions
case analyzedAt = "analyzed_at"
}
public init(
sessionID: UUID,
modulePath: String,
moduleUUID: String? = nil,
mappedRanges: [ProcessNode.ModuleRange],
functions: [Function],
analyzedAt: Date = Date()
) {
self.sessionID = sessionID
self.modulePath = modulePath
self.moduleUUID = moduleUUID
self.mappedRanges = mappedRanges
self.functions = functions
self.analyzedAt = analyzedAt
}
public struct Function: Codable, Sendable, Hashable {
public enum Source: String, Codable, Sendable {
case exported
case symbol
case prelude
case unwind
}
public struct Block: Codable, Sendable, Hashable {
public var offset: UInt64
public var size: UInt64
public init(offset: UInt64, size: UInt64) {
self.offset = offset
self.size = size
}
}
public var offset: UInt64
public var name: String?
public var source: Source
public var blocks: [Block]
public init(offset: UInt64, name: String?, source: Source, blocks: [Block] = []) {
self.offset = offset
self.name = name
self.source = source
self.blocks = blocks
}
}
}
extension ModuleAnalysis {
private static let wireEncoder: JSONEncoder = {
let e = JSONEncoder()
e.dateEncodingStrategy = .iso8601
return e
}()
private static let wireDecoder: JSONDecoder = {
let d = JSONDecoder()
d.dateDecodingStrategy = .iso8601
return d
}()
public func toWireJSON() -> [String: Any]? {
guard let data = try? Self.wireEncoder.encode(self),
let obj = try? JSONSerialization.jsonObject(with: data) as? [String: Any]
else { return nil }
return obj
}
public static func fromWireJSON(_ obj: [String: Any]) -> ModuleAnalysis? {
guard let data = try? JSONSerialization.data(withJSONObject: obj),
let analysis = try? wireDecoder.decode(ModuleAnalysis.self, from: data)
else { return nil }
return analysis
}
}