mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
We want to be able to efficiently serialise lists of images, and to do so it makes most sense to create a separate `ImageMap` type. This also provides a useful place to put methods to e.g. find an image by address or by build ID. rdar://124913332
122 lines
3.4 KiB
Swift
122 lines
3.4 KiB
Swift
//===--- ImageMap+Linux.swift --------------------------------*- swift -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2024 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Linux specifics for ImageMap capture.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#if os(Linux)
|
|
|
|
import Swift
|
|
|
|
#if canImport(Glibc)
|
|
internal import Glibc
|
|
#elseif canImport(Musl)
|
|
internal import Musl
|
|
#endif
|
|
|
|
internal import BacktracingImpl.ImageFormats.Elf
|
|
|
|
extension ImageMap {
|
|
|
|
private struct AddressRange {
|
|
var low: Address = 0
|
|
var high: Address = 0
|
|
}
|
|
|
|
@_specialize(exported: true, kind: full, where M == UnsafeLocalMemoryReader)
|
|
@_specialize(exported: true, kind: full, where M == RemoteMemoryReader)
|
|
@_specialize(exported: true, kind: full, where M == LocalMemoryReader)
|
|
@_spi(Internal)
|
|
public static func capture<M: MemoryReader>(
|
|
using reader: M,
|
|
forProcess pid: Int? = nil
|
|
) -> ImageMap {
|
|
var images: [Image] = []
|
|
|
|
let wordSize: WordSize
|
|
|
|
#if arch(x86_64) || arch(arm64) || arch(arm64_32)
|
|
wordSize = .sixtyFourBit
|
|
#elseif arch(i386) || arch(arm)
|
|
wordSize = .thirtyTwoBit
|
|
#endif
|
|
|
|
let path: String
|
|
if let pid = pid {
|
|
path = "/proc/\(pid)/maps"
|
|
} else {
|
|
path = "/proc/self/maps"
|
|
}
|
|
|
|
guard let procMaps = readString(from: path) else {
|
|
return ImageMap(images: [], wordSize: wordSize)
|
|
}
|
|
|
|
// Find all the mapped files and get high/low ranges
|
|
var mappedFiles: [Substring:AddressRange] = [:]
|
|
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: Swift.min(start, range.low),
|
|
high: Swift.max(end, range.high))
|
|
} else {
|
|
mappedFiles[path] = AddressRange(low: start,
|
|
high: end)
|
|
}
|
|
}
|
|
|
|
// Look at each mapped file to see if it's an ELF image
|
|
for (path, range) in mappedFiles {
|
|
// 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
|
|
guard let (endOfText, uuid) = getElfImageInfo(
|
|
at: M.Address(exactly: range.low)!,
|
|
using: reader
|
|
) else {
|
|
// Not an ELF image
|
|
continue
|
|
}
|
|
|
|
let image = Image(name: String(name),
|
|
path: String(path),
|
|
uniqueID: uuid,
|
|
baseAddress: range.low,
|
|
endOfText: Address(endOfText))
|
|
|
|
images.append(image)
|
|
}
|
|
|
|
images.sort(by: { $0.baseAddress < $1.baseAddress })
|
|
|
|
return ImageMap(images: images, wordSize: wordSize)
|
|
}
|
|
|
|
}
|
|
|
|
#endif // os(Linux)
|