Skip to content

Commit 6ce89c3

Browse files
authored
Merge pull request #229 from p-x9/feature/local-symbol-for-image-in-cache
Enhance `DyldCacheLocalSymbolsInfo`
2 parents 1173a24 + efa5ebf commit 6ce89c3

File tree

5 files changed

+143
-1
lines changed

5 files changed

+143
-1
lines changed

Sources/MachOKit/DyldCache.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,10 @@ extension DyldCache {
196196
}
197197
let suffix = ".symbols"
198198
let path = url.path + suffix
199-
return try .init(url: .init(fileURLWithPath: path))
199+
return try .init(
200+
subcacheUrl: .init(fileURLWithPath: path),
201+
mainCacheHeader: mainCacheHeader
202+
)
200203
}
201204
}
202205

Sources/MachOKit/Model/DyldCache/DyldCacheLocalSymbolsInfo.swift

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,3 +338,92 @@ extension DyldCacheLocalSymbolsInfo {
338338
}
339339
}
340340
}
341+
342+
extension DyldCacheLocalSymbolsInfo {
343+
public func entry64(
344+
for machO: MachOFile,
345+
in cache: DyldCache
346+
) -> DyldCacheLocalSymbolsEntry64? {
347+
guard let offset = machO.textOffset(in: cache) else { return nil }
348+
return entries64(in: cache)?.first(
349+
where: {
350+
$0.dylibOffset == offset
351+
}
352+
)
353+
}
354+
355+
public func entry32(
356+
for machO: MachOFile,
357+
in cache: DyldCache
358+
) -> DyldCacheLocalSymbolsEntry? {
359+
guard let offset = machO.textOffset(in: cache) else { return nil }
360+
return entries32(in: cache)?.first(
361+
where: {
362+
$0.dylibOffset == offset
363+
}
364+
)
365+
}
366+
367+
public func entry(
368+
for machO: MachOFile,
369+
in cache: DyldCache
370+
) -> (any DyldCacheLocalSymbolsEntryProtocol)? {
371+
guard let offset = machO.textOffset(in: cache) else { return nil }
372+
return entries(in: cache).first(
373+
where: {
374+
$0.dylibOffset == offset
375+
}
376+
)
377+
}
378+
}
379+
380+
extension DyldCacheLocalSymbolsInfo {
381+
public func entry64(
382+
for machO: MachOFile,
383+
in cache: FullDyldCache
384+
) -> DyldCacheLocalSymbolsEntry64? {
385+
guard let offset = machO.textOffset(in: cache) else { return nil }
386+
return entries64(in: cache)?.first(
387+
where: {
388+
$0.dylibOffset == offset
389+
}
390+
)
391+
}
392+
393+
public func entry32(
394+
for machO: MachOFile,
395+
in cache: FullDyldCache
396+
) -> DyldCacheLocalSymbolsEntry? {
397+
guard let offset = machO.textOffset(in: cache) else { return nil }
398+
return entries32(in: cache)?.first(
399+
where: {
400+
$0.dylibOffset == offset
401+
}
402+
)
403+
}
404+
405+
public func entry(
406+
for machO: MachOFile,
407+
in cache: FullDyldCache
408+
) -> (any DyldCacheLocalSymbolsEntryProtocol)? {
409+
guard let offset = machO.textOffset(in: cache) else { return nil }
410+
return entries(in: cache).first(
411+
where: {
412+
$0.dylibOffset == offset
413+
}
414+
)
415+
}
416+
}
417+
418+
fileprivate extension MachOFile {
419+
func textOffset(in cache: DyldCache) -> UInt64? {
420+
let loadCommands = loadCommands
421+
let text: (any SegmentCommandProtocol)? = loadCommands.text64 ?? loadCommands.text
422+
guard let text else { return nil }
423+
return numericCast(text.virtualMemoryAddress) - cache.mainCacheHeader.sharedRegionStart
424+
}
425+
426+
func textOffset(in cache: FullDyldCache) -> UInt64? {
427+
textOffset(in: cache.mainCache)
428+
}
429+
}

Sources/MachOKit/Protocol/DyldCacheLocalSymbolsEntryProtocol.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,9 @@ public protocol DyldCacheLocalSymbolsEntryProtocol {
1818
/// Number of local symbols for this dylib
1919
var nlistCount: Int { get }
2020
}
21+
22+
extension DyldCacheLocalSymbolsEntryProtocol {
23+
public var nlistRange: Range<Int> {
24+
nlistStartIndex ..< nlistStartIndex + nlistCount
25+
}
26+
}

Tests/MachOKitTests/DyldCachePrintTests.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,28 @@ final class DyldCachePrintTests: XCTestCase {
152152
}
153153
}
154154

155+
func testLocalSymbolsInSymbolCache() throws {
156+
guard let symbolCache = try cache.symbolCache else {
157+
return
158+
}
159+
guard let info = symbolCache.localSymbolsInfo else {
160+
return
161+
}
162+
let machO = cache.machOFiles().first(
163+
where: {
164+
$0.imagePath.contains("/SwiftUICore")
165+
}
166+
)!
167+
guard let entry = info.entry(for: machO, in: symbolCache) else {
168+
XCTFail("No entry found")
169+
return
170+
}
171+
let symbols = Array(info.symbols(in: symbolCache))[entry.nlistRange]
172+
for symbol in symbols.prefix(100) {
173+
print(symbol.name)
174+
}
175+
}
176+
155177
func testMachOFiles() throws {
156178
let machOs = cache.machOFiles()
157179
for machO in machOs {

Tests/MachOKitTests/FullDyldCachePrintTests.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,28 @@ final class FullDyldCachePrintTests: XCTestCase {
148148
}
149149
}
150150

151+
func testLocalSymbolsInSymbolCache() throws {
152+
guard let symbolCache = try cache.symbolCache else {
153+
return
154+
}
155+
guard let info = symbolCache.localSymbolsInfo else {
156+
return
157+
}
158+
let machO = cache.machOFiles().first(
159+
where: {
160+
$0.imagePath.contains("/SwiftUICore")
161+
}
162+
)!
163+
guard let entry = info.entry(for: machO, in: symbolCache) else {
164+
XCTFail("No entry found")
165+
return
166+
}
167+
let symbols = Array(info.symbols(in: symbolCache))[entry.nlistRange]
168+
for symbol in symbols.prefix(100) {
169+
print(symbol.name)
170+
}
171+
}
172+
151173
func testMachOFiles() throws {
152174
let machOs = cache.machOFiles()
153175
for machO in machOs {

0 commit comments

Comments
 (0)