> On Thu, 29 Mar 2018 10:33:09 -0700 Tim Wright <
teno...@gmail.com> wrote:
> >
> > But resorting to the sysctl interface does have the advantage
> > of working everywhere including jails if/where procfs isn't mounted.
This turned out to be pretty simple. I extended syscall.Sysctl
to accept a string like "kern.proc.vmmap.1234", that adds a
process id. This allows you to extract per process vmmap. A
quick hack to demonstrate this below.
This is sufficient to implement method readMapping() in
runtime/pprof/proto.go for FreeBSD. kern.proc.vmmap.<pid>
works for OpenBSD & vm.proc.map.<pid>) for NetBSD.
$ git diff
diff --git a/src/syscall/syscall_bsd.go b/src/syscall/syscall_bsd.go
index d141a7de9d..8fb011b050 100644
--- a/src/syscall/syscall_bsd.go
+++ b/src/syscall/syscall_bsd.go
@@ -14,6 +14,8 @@ package syscall
import (
"runtime"
+ "strconv"
+ "strings"
"unsafe"
)
@@ -450,11 +452,21 @@ func Kevent(kq int, changes, events []Kevent_t, timeout *Timespec) (n int, err e
//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
func Sysctl(name string) (value string, err error) {
+ num := -1
// Translate name to mib number.
+ i := strings.LastIndex(name, ".")
+ if i < len(name) && '0' <= name[i+1] && name[i+1] <= '9' {
+ num, err = strconv.Atoi(name[i+1:])
+ if err != nil { return "", err }
+ name = name[:i]
+ }
mib, err := nametomib(name)
if err != nil {
return "", err
}
+ if num >= 0 {
+ mib = append(mib, _C_int(num))
+ }
// Find size.
n := uintptr(0)
$ cat> foo.go<<'EOF'
package main
import (
"fmt"
"os"
"syscall"
)
/*
#include <sys/types.h>
#include <sys/user.h>
#include <sys/sysctl.h>
#include <string.h>
struct kinfo_vmentry* getNextVMEntry(char* b, int off) {
return (struct kinfo_vmentry*)(b+off);
}
*/
import "C"
func main() {
pid := os.Getpid()
r, err := syscall.Sysctl("kern.proc.vmmap."+fmt.Sprint(pid))
if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err); os.Exit(1) }
p := C.CString(r)
for off := 0; off < len(r); {
v := C.getNextVMEntry(p, C.int(off))
off += int(v.kve_structsize)
fmt.Printf("%012x-%012x %o %012x %d %s\n",
v.kve_start, v.kve_end, v.kve_protection,
v.kve_offset, v.kve_structsize,
C.GoString(&v.kve_path[0]))
}
}
EOF
$ go build -o /tmp/foo foo.go && /tmp/foo
000000400000-000000517000 5 000000000000 152 /tmp/foo
000000717000-00000072a000 3 000000000000 152 /tmp/foo
00000072a000-000000800000 3 000000000000 144
000800717000-000800730000 5 000000000000 176 /usr/jails/basejail/libexec/ld-elf.so.1
000800730000-000800754000 3 000000000000 144
...