Skip to content

Commit d396656

Browse files
committed
[Backtracing][Linux] Replace regex with ProcMapsScanner.
We were using a regular expression to scan `/proc/<pid>/maps`, but we shouldn't really do that because it breaks non-bootstrapped builds. rdar://110452324
1 parent 97e6b56 commit d396656

File tree

3 files changed

+326
-85
lines changed

3 files changed

+326
-85
lines changed

stdlib/public/Backtracing/Backtrace.swift

+68-84
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
import Swift
1818

19-
@_implementationOnly import _StringProcessing
20-
2119
@_implementationOnly import OS.Libc
2220

2321
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
@@ -476,107 +474,93 @@ public struct Backtrace: CustomStringConvertible, Sendable {
476474
return []
477475
}
478476

479-
let mapRegex = #/
480-
^(?<start>[A-Fa-f0-9]+)-(?<end>[A-Fa-f0-9]+)\s+
481-
(?<perms>[-rwxsp]{4})\s+
482-
(?<offset>[A-Fa-f0-9]+)\s+
483-
(?<major>[A-Fa-f0-9]+):(?<minor>[A-Fa-f0-9]+)\s+
484-
(?<inode>\d+)\s+
485-
(?<pathname>.*)\s*$
486-
/#
487-
let lines = procMaps.split(separator: "\n")
488-
489477
// Find all the mapped files and get high/low ranges
490478
var mappedFiles: [Substring:AddressRange] = [:]
491-
for line in lines {
492-
if let match = try? mapRegex.wholeMatch(in: line) {
493-
let path = stripWhitespace(match.pathname)
494-
if match.inode == "0" || path == "" {
495-
continue
496-
}
497-
guard let start = Address(match.start, radix: 16),
498-
let end = Address(match.end, radix: 16) else {
499-
continue
500-
}
479+
for match in ProcMapsScanner(procMaps) {
480+
let path = stripWhitespace(match.pathname)
481+
if match.inode == "0" || path == "" {
482+
continue
483+
}
484+
guard let start = Address(match.start, radix: 16),
485+
let end = Address(match.end, radix: 16) else {
486+
continue
487+
}
501488

502-
if let range = mappedFiles[path] {
503-
mappedFiles[path] = AddressRange(low: min(start, range.low),
504-
high: max(end, range.high))
505-
} else {
506-
mappedFiles[path] = AddressRange(low: start,
507-
high: end)
508-
}
489+
if let range = mappedFiles[path] {
490+
mappedFiles[path] = AddressRange(low: min(start, range.low),
491+
high: max(end, range.high))
492+
} else {
493+
mappedFiles[path] = AddressRange(low: start,
494+
high: end)
509495
}
510496
}
511497

512498
// Look for ELF headers in the process' memory
513499
typealias Source = MemoryImageSource<M>
514500
let source = Source(with: reader)
515-
for line in lines {
516-
if let match = try? mapRegex.wholeMatch(in: line) {
517-
let path = stripWhitespace(match.pathname)
518-
if match.inode == "0" || path == "" {
519-
continue
520-
}
501+
for match in ProcMapsScanner(procMaps) {
502+
let path = stripWhitespace(match.pathname)
503+
if match.inode == "0" || path == "" {
504+
continue
505+
}
521506

522-
guard let start = Address(match.start, radix: 16),
523-
let end = Address(match.end, radix: 16),
524-
let offset = Address(match.offset, radix: 16) else {
525-
continue
526-
}
507+
guard let start = Address(match.start, radix: 16),
508+
let end = Address(match.end, radix: 16),
509+
let offset = Address(match.offset, radix: 16) else {
510+
continue
511+
}
527512

528-
if offset != 0 || end - start < EI_NIDENT {
529-
continue
530-
}
513+
if offset != 0 || end - start < EI_NIDENT {
514+
continue
515+
}
531516

532-
// Extract the filename from path
533-
let name: Substring
534-
if let slashIndex = path.lastIndex(of: "/") {
535-
name = path.suffix(from: path.index(after: slashIndex))
536-
} else {
537-
name = path
538-
}
517+
// Extract the filename from path
518+
let name: Substring
519+
if let slashIndex = path.lastIndex(of: "/") {
520+
name = path.suffix(from: path.index(after: slashIndex))
521+
} else {
522+
name = path
523+
}
539524

540-
// Inspect the image and extract the UUID and end of text
541-
let range = mappedFiles[path]!
542-
let subSource = SubImageSource(parent: source,
543-
baseAddress: Source.Address(range.low),
544-
length: Source.Size(range.high
545-
- range.low))
546-
var theUUID: [UInt8]? = nil
547-
var endOfText: Address = range.low
548-
549-
if let image = try? Elf32Image(source: subSource) {
550-
theUUID = image.uuid
551-
552-
for hdr in image.programHeaders {
553-
if hdr.p_type == .PT_LOAD && (hdr.p_flags & PF_X) != 0 {
554-
endOfText = max(endOfText, range.low + Address(hdr.p_vaddr
555-
+ hdr.p_memsz))
556-
}
525+
// Inspect the image and extract the UUID and end of text
526+
let range = mappedFiles[path]!
527+
let subSource = SubImageSource(parent: source,
528+
baseAddress: Source.Address(range.low),
529+
length: Source.Size(range.high
530+
- range.low))
531+
var theUUID: [UInt8]? = nil
532+
var endOfText: Address = range.low
533+
534+
if let image = try? Elf32Image(source: subSource) {
535+
theUUID = image.uuid
536+
537+
for hdr in image.programHeaders {
538+
if hdr.p_type == .PT_LOAD && (hdr.p_flags & PF_X) != 0 {
539+
endOfText = max(endOfText, range.low + Address(hdr.p_vaddr
540+
+ hdr.p_memsz))
557541
}
558-
} else if let image = try? Elf64Image(source: subSource) {
559-
theUUID = image.uuid
542+
}
543+
} else if let image = try? Elf64Image(source: subSource) {
544+
theUUID = image.uuid
560545

561-
for hdr in image.programHeaders {
562-
if hdr.p_type == .PT_LOAD && (hdr.p_flags & PF_X) != 0 {
563-
endOfText = max(endOfText, range.low + Address(hdr.p_vaddr
564-
+ hdr.p_memsz))
565-
}
546+
for hdr in image.programHeaders {
547+
if hdr.p_type == .PT_LOAD && (hdr.p_flags & PF_X) != 0 {
548+
endOfText = max(endOfText, range.low + Address(hdr.p_vaddr
549+
+ hdr.p_memsz))
566550
}
567-
} else {
568-
// Not a valid ELF image
569-
continue
570551
}
552+
} else {
553+
// Not a valid ELF image
554+
continue
555+
}
571556

572-
let image = Image(name: String(name),
573-
path: String(path),
574-
buildID: theUUID,
575-
baseAddress: range.low,
576-
endOfText: endOfText)
557+
let image = Image(name: String(name),
558+
path: String(path),
559+
buildID: theUUID,
560+
baseAddress: range.low,
561+
endOfText: endOfText)
577562

578-
images.append(image)
579-
}
563+
images.append(image)
580564
}
581565
#endif
582566

stdlib/public/Backtracing/CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ set(BACKTRACING_SOURCES
3636
ImageSource.swift
3737
MemoryImageSource.swift
3838
MemoryReader.swift
39+
ProcMapsScanner.swift
3940
Registers.swift
4041
SymbolicatedBacktrace.swift
4142
Utils.swift
@@ -75,7 +76,7 @@ set(LLVM_OPTIONAL_SOURCES
7576
add_swift_target_library(swift_Backtracing ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB
7677
${BACKTRACING_SOURCES}
7778

78-
SWIFT_MODULE_DEPENDS ${concurrency} _StringProcessing
79+
SWIFT_MODULE_DEPENDS ${concurrency}
7980

8081
LINK_LIBRARIES ${swift_backtracing_link_libraries}
8182

0 commit comments

Comments
 (0)