Skip to content
Merged
15 changes: 9 additions & 6 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// swift-tools-version: 5.10
// swift-tools-version: 6.1
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription
@preconcurrency import PackageDescription
import CompilerPluginSupport

let useSPMPrebuildVersion = false
Expand Down Expand Up @@ -72,7 +72,7 @@ extension Target.Dependency {

let package = Package(
name: "MachOSwiftSection",
platforms: [.macOS(.v10_15)],
platforms: [.macOS(.v10_15), .iOS(.v13), .tvOS(.v13), .watchOS(.v6), .visionOS(.v1)],
products: [
.library(
name: "MachOSwiftSection",
Expand All @@ -89,7 +89,7 @@ let package = Package(
],
dependencies: [
.MachOKit,
.package(url: "https://github.com/swiftlang/swift-syntax.git", "509.1.0"..<"602.0.0"),
.package(url: "https://github.com/swiftlang/swift-syntax.git", "509.1.0" ..< "602.0.0"),
.package(url: "https://github.com/p-x9/AssociatedObject", from: "0.13.0"),
.package(url: "https://github.com/p-x9/swift-fileio.git", from: "0.9.0"),
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.5.1"),
Expand All @@ -111,6 +111,7 @@ let package = Package(
name: "MachOExtensions",
dependencies: [
.MachOKit,
"MachOMacro",
]
),

Expand Down Expand Up @@ -146,10 +147,10 @@ let package = Package(
.target(
name: "MachOSwiftSection",
dependencies: [
.MachOKit,
"Demangle",
"MachOFoundation",
"MachOMacro",
.MachOKit,
]
),

Expand All @@ -158,6 +159,7 @@ let package = Package(
dependencies: [
.MachOKit,
"MachOExtensions",
"SwiftDump",
]
),

Expand Down Expand Up @@ -219,5 +221,6 @@ let package = Package(
"MachOTestingSupport",
]
),
]
],
swiftLanguageModes: [.v5]
)
5 changes: 2 additions & 3 deletions Sources/Demangle/Main/DemangleOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ public struct DemangleOptions: OptionSet, Codable, Sendable {
public static let printForTypeName = DemangleOptions(rawValue: 1 << 19)
public static let showClosureSignature = DemangleOptions(rawValue: 1 << 20)
public static let showModuleInDependentMemberType = DemangleOptions(rawValue: 1 << 21)
public static let showPrefixAndSuffix = DemangleOptions(rawValue: 1 << 22)

package static let removeWeakPrefix = DemangleOptions(rawValue: 1 << 100)

public init(rawValue: Int) {
self.rawValue = rawValue
Expand All @@ -47,8 +47,7 @@ public struct DemangleOptions: OptionSet, Codable, Sendable {
.displayStdlibModule,
.displayObjCModule,
.showClosureSignature,
.showModuleInDependentMemberType,
.showPrefixAndSuffix
.showModuleInDependentMemberType
]

public static let simplified: DemangleOptions = [
Expand Down
53 changes: 36 additions & 17 deletions Sources/Demangle/Main/NodePrinter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ struct NodePrinter: Sendable {
var specializationPrefixPrinted: Bool
var options: DemangleOptions
var hidingCurrentModule: String = ""

init(options: DemangleOptions = .default) {
self.target = .init()
self.specializationPrefixPrinted = false
Expand All @@ -16,7 +16,7 @@ struct NodePrinter: Sendable {
guard options.contains(.qualifyEntities) else {
return false
}
if !options.contains(.showModuleInDependentMemberType), let dependentMemberType = context.parent?.parent?.parent?.parent, dependentMemberType.kind == .dependentMemberType {
if !options.contains(.showModuleInDependentMemberType), let dependentMemberType = context.parent?.parent?.parent?.parent, dependentMemberType.kind == .dependentMemberType {
return false
}
if context.kind == .module, let text = context.text, !text.isEmpty {
Expand All @@ -35,13 +35,9 @@ struct NodePrinter: Sendable {

mutating func printOptional(_ optional: Node?, prefix: String? = nil, suffix: String? = nil, asPrefixContext: Bool = false) -> Node? {
guard let o = optional else { return nil }
if options.contains(.showPrefixAndSuffix) {
prefix.map { target.write($0) }
}
prefix.map { target.write($0) }
let r = printName(o)
if options.contains(.showPrefixAndSuffix) {
suffix.map { target.write($0) }
}
suffix.map { target.write($0) }
return r
}

Expand Down Expand Up @@ -105,7 +101,7 @@ struct NodePrinter: Sendable {

mutating func printModule(_ name: Node) {
if options.contains(.displayModuleNames) {
target.write(name.text ?? "")
target.write(name.text ?? "", type: .other)
}
}

Expand Down Expand Up @@ -848,7 +844,7 @@ struct NodePrinter: Sendable {

mutating func printImplDifferentiabilityKind(_ name: Node) {
target.write("@differentiable")
if case let .index(value) = name.contents, let differentiability = Differentiability(value) {
if case .index(let value) = name.contents, let differentiability = Differentiability(value) {
switch differentiability {
case .normal: break
case .linear: target.write("(_linear)")
Expand All @@ -859,7 +855,7 @@ struct NodePrinter: Sendable {
}

mutating func printImplCoroutineKind(_ name: Node) {
guard case let .name(value) = name.contents, !value.isEmpty else { return }
guard case .name(let value) = name.contents, !value.isEmpty else { return }
target.write("@\(value)")
}

Expand All @@ -876,7 +872,7 @@ struct NodePrinter: Sendable {
}

mutating func printImplParameterName(_ name: Node) {
guard case let .name(value) = name.contents, !value.isEmpty else { return }
guard case .name(let value) = name.contents, !value.isEmpty else { return }
target.write("\(value) ")
}

Expand Down Expand Up @@ -1183,7 +1179,7 @@ struct NodePrinter: Sendable {
case .globalVariableOnceFunction,
.globalVariableOnceToken: printGlobalVariableOnceFunction(name)
case .hasSymbolQuery: target.write("#_hasSymbol query for ")
case .identifier: target.write(name.text ?? "", type: (name.parent?.kind == .function || name.parent?.kind == .variable) ? .functionDeclaration : .typeName)
case .identifier: printIdentifier(name, asPrefixContext: asPrefixContext)
case .implConvention: target.write(name.text ?? "")
case .implCoroutineKind: printImplCoroutineKind(name)
case .implDifferentiabilityKind: printImplDifferentiabilityKind(name)
Expand Down Expand Up @@ -1396,13 +1392,36 @@ struct NodePrinter: Sendable {
case .variadicMarker: target.write(" variadic-marker ")
case .vTableAttribute: target.write("override ")
case .vTableThunk: printVTableThunk(name)
case .weak: printFirstChild(name, prefix: "weak ")
case .weak: printFirstChild(name, prefix: options.contains(.removeWeakPrefix) ? "" : "weak ")
case .willSet: return printAbstractStorage(name.children.first, asPrefixContext: asPrefixContext, extraName: "willset")
}

return nil
}

mutating func printIdentifier(_ name: Node, asPrefixContext: Bool = false) {
let semanticType: SemanticType

switch name.parent?.kind {
case .function:
semanticType = .function(.declaration)
case .variable:
semanticType = .variable
case .enum:
semanticType = .type(.enum, .name)
case .structure:
semanticType = .type(.struct, .name)
case .class:
semanticType = .type(.class, .name)
case .protocol:
semanticType = .type(.protocol, .name)
default:
semanticType = .standard
}

target.write(name.text ?? "", type: semanticType)
}

mutating func printAbstractStorage(_ name: Node?, asPrefixContext: Bool, extraName: String) -> Node? {
guard let n = name else { return nil }
switch n.kind {
Expand Down Expand Up @@ -1609,17 +1628,17 @@ struct NodePrinter: Sendable {
target.write("(")
for tuple in parameters.children.enumerated() {
if let label = labelList?.children.at(tuple.offset) {
target.write(label.kind == .identifier ? (label.text ?? "") : "_", type: .functionDeclaration)
target.write(label.kind == .identifier ? (label.text ?? "") : "_", type: .function(.declaration))
target.write(":")
if showTypes {
target.write(" ")
}
} else if !showTypes {
if let label = tuple.element.children.first(where: { $0.kind == .tupleElementName }) {
target.write(label.text ?? "", type: .functionDeclaration)
target.write(label.text ?? "", type: .function(.declaration))
target.write(":")
} else {
target.write("_", type: .functionDeclaration)
target.write("_", type: .function(.declaration))
target.write(":")
}
}
Expand Down
17 changes: 17 additions & 0 deletions Sources/MachOExtensions/MachORepresentable+.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Foundation
import MachOKit
import MachOMacro

@MachOImageAllMembersGenerator
extension MachORepresentable {
package func _section(
for name: String,
in machOFile: MachOFile
) -> (any SectionProtocol)? {
sections.first(
where: {
$0.sectionName == name
}
)
}
}
22 changes: 19 additions & 3 deletions Sources/MachOExtensions/MachORepresentableWithCache.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import MachOKit

package protocol MachORepresentableWithCache: MachORepresentable {
var cache: DyldCache? { get }
associatedtype Cache: DyldCacheRepresentable

var cache: Cache? { get }
var startOffset: Int { get }
}

Expand All @@ -16,8 +18,22 @@ extension MachOFile: MachORepresentableWithCache {
}

extension MachOImage: MachORepresentableWithCache {
package var cache: DyldCache? { nil }
package var startOffset: Int { 0 }
package var cache: DyldCacheLoaded? {
guard let currentCache = DyldCacheLoaded.current else { return nil }

if ptr.int - currentCache.mainCacheHeader.sharedRegionStart.cast() >= 0 {
return currentCache
}
return nil
}

package var startOffset: Int {
if let cache {
return cache.mainCacheHeader.sharedRegionStart.cast()
} else {
return 0
}
}
}

package func address<MachO: MachORepresentableWithCache>(of fileOffset: Int, in machO: MachO) -> UInt64 {
Expand Down
3 changes: 3 additions & 0 deletions Sources/MachOExtensions/SegmentCommandProtocol+.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ extension SegmentCommandProtocol {
)
}
}



16 changes: 11 additions & 5 deletions Sources/MachOPointer/Symbol/MachOSymbolCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,16 @@ class MachOSymbolCache {
var cacheEntry: CacheEntry = [:]
for symbol in symbols64 where !symbol.name.isEmpty {
var offset = symbol.offset
cacheEntry[offset] = .init(offset: offset, stringValue: symbol.name)
if let cache = machO.cache {
offset -= cache.mainCacheHeader.sharedRegionStart.cast()
cacheEntry[offset] = .init(offset: offset, stringValue: symbol.name)
}
cacheEntry[offset] = .init(offset: offset, stringValue: symbol.name)
}

for exportedSymbol in machO.exportedSymbols {
if var offset = exportedSymbol.offset {
cacheEntry[offset] = .init(offset: offset, stringValue: exportedSymbol.name)
offset += machO.startOffset
cacheEntry[offset] = .init(offset: offset, stringValue: exportedSymbol.name)
}
Expand Down Expand Up @@ -78,15 +80,19 @@ class MachOSymbolCache {

func symbol(for offset: Int, in machOImage: MachOImage) -> MachOSymbol? {
let identifier = CacheIdentifier.image(machOImage.ptr)
return symbol(for: offset, with: identifier)
return symbol(for: offset, with: identifier, in: machOImage)
}

func symbol(for offset: Int, in machOFile: MachOFile) -> MachOSymbol? {
let identifier = CacheIdentifier.file(machOFile.imagePath)
return symbol(for: offset, with: identifier)
return symbol(for: offset, with: identifier, in: machOFile)
}

private func symbol(for offset: Int, with identifier: CacheIdentifier) -> MachOSymbol? {
return entryByIdentifier[identifier]?[offset]
private func symbol<MachO: MachORepresentableWithCache>(for offset: Int, with identifier: CacheIdentifier, in machO: MachO) -> MachOSymbol? {
if let symbol = entryByIdentifier[identifier, default: [:]][offset] {
return symbol
} else {
return nil
}
}
}
13 changes: 13 additions & 0 deletions Sources/MachOSwiftSection/Extensions/Array+.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Foundation

func + <Element>(lhs: [Element]?, rhs: [Element]?) -> [Element] {
(lhs ?? []) + (rhs ?? [])
}

func + <Element>(lhs: [Element], rhs: [Element]?) -> [Element] {
lhs + (rhs ?? [])
}

func + <Element>(lhs: [Element]?, rhs: [Element]) -> [Element] {
(lhs ?? []) + rhs
}
3 changes: 0 additions & 3 deletions Sources/MachOSwiftSection/Extensions/Data+.swift

This file was deleted.

47 changes: 47 additions & 0 deletions Sources/MachOSwiftSection/Extensions/MachORepresentable+.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import Foundation
import MachOKit
import MachOMacro

extension MachOFile {
func section(for swiftMachOSection: MachOSwiftSectionName) throws -> (any SectionProtocol) {
let loadCommands = loadCommands
let swiftSection: any SectionProtocol
if let text = loadCommands.text64,
let section = text._section(for: swiftMachOSection.rawValue, in: self) {
swiftSection = section
} else if let text = loadCommands.text,
let section = text._section(for: swiftMachOSection.rawValue, in: self) {
swiftSection = section
} else if let section = sections.first(where: { $0.sectionName == swiftMachOSection.rawValue }) {
swiftSection = section
} else {
throw MachOSwiftSectionError.sectionNotFound(section: swiftMachOSection, allSectionNames: sections.map(\.sectionName))
}
guard swiftSection.align * 2 == 4 else {
throw MachOSwiftSectionError.invalidSectionAlignment(section: swiftMachOSection, align: swiftSection.align)
}
return swiftSection
}
}

extension MachOImage {
func section(for swiftMachOSection: MachOSwiftSectionName) throws -> (any SectionProtocol) {
let loadCommands = loadCommands
let swiftSection: any SectionProtocol
if let text = loadCommands.text64,
let section = text._section(for: swiftMachOSection.rawValue, in: self) {
swiftSection = section
} else if let text = loadCommands.text,
let section = text._section(for: swiftMachOSection.rawValue, in: self) {
swiftSection = section
} else if let section = sections.first(where: { $0.sectionName == swiftMachOSection.rawValue }) {
swiftSection = section
} else {
throw MachOSwiftSectionError.sectionNotFound(section: swiftMachOSection, allSectionNames: sections.map(\.sectionName))
}
guard swiftSection.align * 2 == 4 else {
throw MachOSwiftSectionError.invalidSectionAlignment(section: swiftMachOSection, align: swiftSection.align)
}
return swiftSection
}
}
Loading