blob: 610de0a2f0816f058f59b7ebdcc2411df789ca0e [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 (
"internal/byteorder"
"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,
byteorder.LEUint64(info.Offset[:]),
regionFilename(addr),
"")
added = true
}
addr += memRegionSize
}
}
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