Skip to content

Commit

Permalink
add CrashLogMessageExtractor swapCxaThrow: Bool arg. Add more memory …
Browse files Browse the repository at this point in the history
…access checks.
  • Loading branch information
mallexxx committed Jul 24, 2024
1 parent 4245888 commit 260b441
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 32 deletions.
6 changes: 4 additions & 2 deletions Sources/Crashes/CrashLogMessageExtractor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public struct CrashLogMessageExtractor {
fileprivate static var nextCppTerminateHandler: (() -> Void)!
fileprivate static var diagnosticsDirectory: URL!

public static func setUp() {
public static func setUp(swapCxaThrow: Bool = true) {
prepareDiagnosticsDirectory()

// Set unhandled NSException handler
Expand All @@ -116,7 +116,9 @@ public struct CrashLogMessageExtractor {
// Set unhandled C++ exception handler
nextCppTerminateHandler = SetCxxExceptionTerminateHandler(handleTerminateOnCxxException)
// Swap C++ `throw` to collect stack trace when throw happens
CxaThrowSwapper.swapCxaThrow(with: captureStackTrace)
if swapCxaThrow {
CxaThrowSwapper.swapCxaThrow(with: captureStackTrace)
}
}

/// create App Support/Diagnostics folder
Expand Down
35 changes: 22 additions & 13 deletions Sources/Crashes/CxaThrowSwapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ private func processMachHeader(_ header: UnsafePointer<mach_header>?, slide: Int
}

private var cxxOriginalThrowFunctions = [UnsafeRawPointer: UnsafeRawPointer]()
private let indicesToSkip = [UInt32(bitPattern: INDIRECT_SYMBOL_ABS), INDIRECT_SYMBOL_LOCAL, UInt32(Int64(INDIRECT_SYMBOL_LOCAL) | Int64(INDIRECT_SYMBOL_ABS))]
private let indicesToSkip = [UInt32(INDIRECT_SYMBOL_ABS), INDIRECT_SYMBOL_LOCAL, INDIRECT_SYMBOL_LOCAL | UInt32(INDIRECT_SYMBOL_ABS)]

private func _processMachHeader(_ header: UnsafePointer<mach_header_64>?, slide: Int) throws {
guard let header, slide != 0 else { throw ProcessingError.zeroSlide }
Expand All @@ -121,23 +121,32 @@ private func _processMachHeader(_ header: UnsafePointer<mach_header_64>?, slide:

guard let imageMap = ImageMap(header: header, slide: slide) else { throw ProcessingError.imageMap }

for case .some(let segment) in [imageMap.dataSegment, imageMap.dataConstSegment] {
for (sectionIdx, section) in segment.sections.enumerated() where [S_LAZY_SYMBOL_POINTERS, S_NON_LAZY_SYMBOL_POINTERS].contains(section.type) {
let symtabIndices = section.indirectSymbolIndices(indirectSymtab: imageMap.indirectSymtab)
for i in 0..<section.count {
let symtabIndex = symtabIndices[i]
guard !indicesToSkip.contains(symtabIndex) else { continue }
let symbolName = imageMap.symbolName(at: Int(symtabIndex))
guard symbolName == "___cxa_throw" else { continue }
try processSegment(imageMap.dataSegment)
try processSegment(imageMap.dataConstSegment)

let sectionInfo = try Dl_info(segment.sections.baseAddress!.advanced(by: sectionIdx))
try section.indirectSymbolBindings(slide: slide).withTemporaryUnprotectedMemory { indirectSymbolBindings in
os_log(.debug, log: CxaThrowSwapper.log, "found %s: %s", symbolName, indirectSymbolBindings[i].debugDescription)
func processSegment(_ segment: UnsafePointer<segment_command_64>?) throws {
guard let segment else { return }
let sections = segment.sections
for section in sections.baseAddress!..<sections.baseAddress!.advanced(by: sections.count)
where [S_LAZY_SYMBOL_POINTERS, S_NON_LAZY_SYMBOL_POINTERS].contains(section.pointee.type) {

try section.pointee.indirectSymbolBindings(slide: slide)?.withTemporaryUnprotectedMemory { indirectSymbolBindings in
guard let indirectSymbolIndices = section.pointee.indirectSymbolIndices(indirectSymtab: imageMap.indirectSymtab) else { return }
for i in 0..<section.pointee.count where indirectSymbolIndices.indices.contains(i) && indirectSymbolBindings.indices.contains(i) {
let symtabIndex = indirectSymbolIndices[i]
guard !indicesToSkip.contains(symtabIndex),
let symbolName = imageMap.symbolName(at: Int(symtabIndex)),
symbolName[0] != 0, symbolName[1] != 0,
strcmp(symbolName.advanced(by: 1), "__cxa_throw") == 0 else { continue }

let sectionInfo = try Dl_info(section)
os_log(.debug, log: CxaThrowSwapper.log, "found %s: %s", String(cString: symbolName), indirectSymbolBindings[i].debugDescription)

cxxOriginalThrowFunctions[UnsafeRawPointer(sectionInfo.dli_fbase)] = indirectSymbolBindings[i]
indirectSymbolBindings[i] = unsafeBitCast(cxaThrowHandler as CxaThrowType, to: UnsafeRawPointer.self)

break
}
break
}
}
}
Expand Down
28 changes: 16 additions & 12 deletions Sources/Crashes/Mach-O/ImageMap.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ struct ImageMap {
let dataSegment: UnsafePointer<segment_command_64>?
let dataConstSegment: UnsafePointer<segment_command_64>?

let symtab: UnsafePointer<nlist_64>
let strtab: UnsafePointer<Int8>
let symtab: UnsafeBufferPointer<nlist_64>
let strtab: UnsafeBufferPointer<Int8>
// indirect symbol table (array of uint32_t indices into symbol table)
let indirectSymtab: UnsafePointer<UInt32>
let indirectSymtab: UnsafeBufferPointer<UInt32>

init?(header: UnsafePointer<mach_header_64>, slide: Int) {
guard case let (symtabCmd?, dysymtabCmd?, linkeditSegment?, dataSegment, dataConstSegment) = Self.findCommandsAndSegments(in: header) else { return nil }
Expand All @@ -40,9 +40,12 @@ struct ImageMap {
self.dataConstSegment = dataConstSegment

let linkeditBase = UnsafeRawPointer(bitPattern: UInt(linkeditSegment.vmaddr))!.advanced(by: slide - Int(linkeditSegment.fileoff))
self.symtab = linkeditBase.advanced(by: Int(symtabCmd.symoff)).assumingMemoryBound(to: nlist_64.self)
self.strtab = linkeditBase.advanced(by: Int(symtabCmd.stroff)).assumingMemoryBound(to: Int8.self)
self.indirectSymtab = linkeditBase.advanced(by: Int(dysymtabCmd.indirectsymoff)).assumingMemoryBound(to: UInt32.self)
self.symtab = UnsafeBufferPointer(start: linkeditBase.advanced(by: Int(symtabCmd.symoff)).assumingMemoryBound(to: nlist_64.self),
count: Int(symtabCmd.nsyms))
self.strtab = UnsafeBufferPointer(start: linkeditBase.advanced(by: Int(symtabCmd.stroff)).assumingMemoryBound(to: Int8.self),
count: Int(symtabCmd.strsize))
self.indirectSymtab = UnsafeBufferPointer(start: linkeditBase.advanced(by: Int(dysymtabCmd.indirectsymoff)).assumingMemoryBound(to: UInt32.self),
count: Int(dysymtabCmd.nindirectsyms))
}

private typealias CommandsAndSegments = (symtabCmd: symtab_command?, dysymtabCmd: dysymtab_command?, linkeditSegment: segment_command_64?, dataSegment: UnsafePointer<segment_command_64>?, dataConstSegment: UnsafePointer<segment_command_64>?) // swiftlint:disable:this large_tuple
Expand Down Expand Up @@ -77,12 +80,13 @@ struct ImageMap {
return result
}

func symbolName(at symtabIndex: Int) -> String {
let strtabOffset = symtab[symtabIndex].n_un.n_strx
let symbolName = strtab.advanced(by: Int(strtabOffset))
let symbolNameStr = String(cString: symbolName)

return symbolNameStr
func symbolName(at symtabIndex: Int) -> UnsafePointer<CChar>? {
guard symtab.indices.contains(symtabIndex) else { return nil }
let strtabOffset = Int(symtab[symtabIndex].n_un.n_strx)
guard strtab.indices.contains(strtabOffset),
strtab.indices.contains(strtabOffset + 1) else { return nil }
let symbolName = strtab.baseAddress!.advanced(by: Int(strtabOffset))
return symbolName
}

}
12 changes: 7 additions & 5 deletions Sources/Crashes/Mach-O/section+helpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ extension section_64 {
Int(self.size / UInt64(MemoryLayout<UnsafeMutableRawPointer?>.size))
}

func indirectSymbolIndices(indirectSymtab: UnsafePointer<UInt32>) -> UnsafeBufferPointer<UInt32> {
UnsafeBufferPointer(start: indirectSymtab.advanced(by: Int(self.reserved1)), count: self.count)
func indirectSymbolIndices(indirectSymtab: UnsafeBufferPointer<UInt32>) -> UnsafeBufferPointer<UInt32>? {
let count = min(self.count, indirectSymtab.count - Int(self.reserved1))
guard count > 0 else { return nil }
return UnsafeBufferPointer(start: indirectSymtab.baseAddress!.advanced(by: Int(self.reserved1)), count: count)
}

func indirectSymbolBindings(slide: Int) -> UnsafeBufferPointer<UnsafeRawPointer> {
UnsafeRawBufferPointer(start: UnsafeRawPointer(bitPattern: UInt(self.addr))!.advanced(by: slide),
count: Int(self.size)).assumingMemoryBound(to: UnsafeRawPointer.self)
func indirectSymbolBindings(slide: Int) -> UnsafeBufferPointer<UnsafeRawPointer>? {
guard let ptr = UnsafeRawPointer(bitPattern: UInt(self.addr) + UInt(slide)) else { return nil }
return UnsafeRawBufferPointer(start: ptr, count: Int(self.size)).assumingMemoryBound(to: UnsafeRawPointer.self)
}

}

0 comments on commit 260b441

Please sign in to comment.