// 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