blob: 35b9e6d4879c565d1783b64e1b5215be8ce10db8 [file] [log] [blame]
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package pprof
import (
"os"
"unsafe"
)
func isExecutable(protection int32) bool {
return (protection&_VM_PROT_EXECUTE) != 0 && (protection&_VM_PROT_READ) != 0
}
// machVMInfo uses the mach_vm_region region system call to add mapping entries
// for the text region of the running process.
func machVMInfo(addMapping func(lo, hi, offset uint64, file, buildID string)) bool {
added := false
var addr uint64 = 0x1
for {
var memRegionSize uint64
var info machVMRegionBasicInfoData
// Get the first address and page size.
kr := mach_vm_region(
&addr,
&memRegionSize,
unsafe.Pointer(&info))
if kr != 0 {
if kr == _MACH_SEND_INVALID_DEST {
// No more memory regions.
return true
}
return added // return true if at least one mapping was added
}
if isExecutable(info.Protection) {
// NOTE: the meaning/value of Offset is unclear. However,
// this likely doesn't matter as the text segment's file
// offset is usually 0.
addMapping(addr,
addr+memRegionSize,
read64(&info.Offset),
regionFilename(addr),
"")
added = true
}
addr += memRegionSize
}
}
func read64(p *[8]byte) uint64 {
// all supported darwin platforms are little endian
return uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 | uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56
}
func regionFilename(address uint64) string {
buf := make([]byte, _MAXPATHLEN)
r := proc_regionfilename(
os.Getpid(),
address,
unsafe.SliceData(buf),
int64(cap(buf)))
if r == 0 {
return ""
}
return string(buf[:r])
}
// mach_vm_region and proc_regionfilename are implemented by
// the runtime package (runtime/sys_darwin.go).
//
//go:noescape
func mach_vm_region(address, region_size *uint64, info unsafe.Pointer) int32
//go:noescape
func proc_regionfilename(pid int, address uint64, buf *byte, buflen int64) int32