Skip to content

[Backtracing][Linux] Replace regex with ProcMapsScanner. #66449

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 68 additions & 84 deletions stdlib/public/Backtracing/Backtrace.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

import Swift

@_implementationOnly import _StringProcessing

@_implementationOnly import OS.Libc

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

let mapRegex = #/
^(?<start>[A-Fa-f0-9]+)-(?<end>[A-Fa-f0-9]+)\s+
(?<perms>[-rwxsp]{4})\s+
(?<offset>[A-Fa-f0-9]+)\s+
(?<major>[A-Fa-f0-9]+):(?<minor>[A-Fa-f0-9]+)\s+
(?<inode>\d+)\s+
(?<pathname>.*)\s*$
/#
let lines = procMaps.split(separator: "\n")

// Find all the mapped files and get high/low ranges
var mappedFiles: [Substring:AddressRange] = [:]
for line in lines {
if let match = try? mapRegex.wholeMatch(in: line) {
let path = stripWhitespace(match.pathname)
if match.inode == "0" || path == "" {
continue
}
guard let start = Address(match.start, radix: 16),
let end = Address(match.end, radix: 16) else {
continue
}
for match in ProcMapsScanner(procMaps) {
let path = stripWhitespace(match.pathname)
if match.inode == "0" || path == "" {
continue
}
guard let start = Address(match.start, radix: 16),
let end = Address(match.end, radix: 16) else {
continue
}

if let range = mappedFiles[path] {
mappedFiles[path] = AddressRange(low: min(start, range.low),
high: max(end, range.high))
} else {
mappedFiles[path] = AddressRange(low: start,
high: end)
}
if let range = mappedFiles[path] {
mappedFiles[path] = AddressRange(low: min(start, range.low),
high: max(end, range.high))
} else {
mappedFiles[path] = AddressRange(low: start,
high: end)
}
}

// Look for ELF headers in the process' memory
typealias Source = MemoryImageSource<M>
let source = Source(with: reader)
for line in lines {
if let match = try? mapRegex.wholeMatch(in: line) {
let path = stripWhitespace(match.pathname)
if match.inode == "0" || path == "" {
continue
}
for match in ProcMapsScanner(procMaps) {
let path = stripWhitespace(match.pathname)
if match.inode == "0" || path == "" {
continue
}

guard let start = Address(match.start, radix: 16),
let end = Address(match.end, radix: 16),
let offset = Address(match.offset, radix: 16) else {
continue
}
guard let start = Address(match.start, radix: 16),
let end = Address(match.end, radix: 16),
let offset = Address(match.offset, radix: 16) else {
continue
}

if offset != 0 || end - start < EI_NIDENT {
continue
}
if offset != 0 || end - start < EI_NIDENT {
continue
}

// Extract the filename from path
let name: Substring
if let slashIndex = path.lastIndex(of: "/") {
name = path.suffix(from: path.index(after: slashIndex))
} else {
name = path
}
// Extract the filename from path
let name: Substring
if let slashIndex = path.lastIndex(of: "/") {
name = path.suffix(from: path.index(after: slashIndex))
} else {
name = path
}

// Inspect the image and extract the UUID and end of text
let range = mappedFiles[path]!
let subSource = SubImageSource(parent: source,
baseAddress: Source.Address(range.low),
length: Source.Size(range.high
- range.low))
var theUUID: [UInt8]? = nil
var endOfText: Address = range.low

if let image = try? Elf32Image(source: subSource) {
theUUID = image.uuid

for hdr in image.programHeaders {
if hdr.p_type == .PT_LOAD && (hdr.p_flags & PF_X) != 0 {
endOfText = max(endOfText, range.low + Address(hdr.p_vaddr
+ hdr.p_memsz))
}
// Inspect the image and extract the UUID and end of text
let range = mappedFiles[path]!
let subSource = SubImageSource(parent: source,
baseAddress: Source.Address(range.low),
length: Source.Size(range.high
- range.low))
var theUUID: [UInt8]? = nil
var endOfText: Address = range.low

if let image = try? Elf32Image(source: subSource) {
theUUID = image.uuid

for hdr in image.programHeaders {
if hdr.p_type == .PT_LOAD && (hdr.p_flags & PF_X) != 0 {
endOfText = max(endOfText, range.low + Address(hdr.p_vaddr
+ hdr.p_memsz))
}
} else if let image = try? Elf64Image(source: subSource) {
theUUID = image.uuid
}
} else if let image = try? Elf64Image(source: subSource) {
theUUID = image.uuid

for hdr in image.programHeaders {
if hdr.p_type == .PT_LOAD && (hdr.p_flags & PF_X) != 0 {
endOfText = max(endOfText, range.low + Address(hdr.p_vaddr
+ hdr.p_memsz))
}
for hdr in image.programHeaders {
if hdr.p_type == .PT_LOAD && (hdr.p_flags & PF_X) != 0 {
endOfText = max(endOfText, range.low + Address(hdr.p_vaddr
+ hdr.p_memsz))
}
} else {
// Not a valid ELF image
continue
}
} else {
// Not a valid ELF image
continue
}

let image = Image(name: String(name),
path: String(path),
buildID: theUUID,
baseAddress: range.low,
endOfText: endOfText)
let image = Image(name: String(name),
path: String(path),
buildID: theUUID,
baseAddress: range.low,
endOfText: endOfText)

images.append(image)
}
images.append(image)
}
#endif

Expand Down
3 changes: 2 additions & 1 deletion stdlib/public/Backtracing/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ set(BACKTRACING_SOURCES
ImageSource.swift
MemoryImageSource.swift
MemoryReader.swift
ProcMapsScanner.swift
Registers.swift
SymbolicatedBacktrace.swift
Utils.swift
Expand Down Expand Up @@ -75,7 +76,7 @@ set(LLVM_OPTIONAL_SOURCES
add_swift_target_library(swift_Backtracing ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB
${BACKTRACING_SOURCES}

SWIFT_MODULE_DEPENDS ${concurrency} _StringProcessing
SWIFT_MODULE_DEPENDS ${concurrency}

LINK_LIBRARIES ${swift_backtracing_link_libraries}

Expand Down
Loading