github.com/eh-steve/goloader@v0.0.0-20240111193454-90ff3cfdae39/mmap/vmmap/vmmap_fallback_darwin.go (about) 1 //go:build darwin && !cgo 2 // +build darwin,!cgo 3 4 package vmmap 5 6 import ( 7 "bytes" 8 "fmt" 9 "github.com/eh-steve/goloader/mmap/mapping" 10 "os" 11 "os/exec" 12 "strconv" 13 ) 14 15 func Vmmap() ([]mapping.Mapping, error) { 16 // This is horrible 17 pid := os.Getpid() 18 cmd := exec.Command("vmmap", "-pages", "-interleaved", fmt.Sprintf("%d", pid)) 19 output, err := cmd.CombinedOutput() 20 21 if err != nil { 22 return nil, fmt.Errorf("could not run 'vmmap -v %d': %w", pid, err) 23 } 24 25 sections := bytes.Split(output, []byte("REGION DETAIL\n")) 26 lines := bytes.Split(sections[0], []byte("\n")) 27 28 columnHeaders := append(lines[len(lines)-1], []byte("REGION DETAIL")...) 29 if len(sections) != 2 { 30 return nil, fmt.Errorf("failed to parse vmmap output: expected REGION_DETAIL to be column header, got %d", len(sections)) 31 } 32 sections = bytes.Split(sections[1], []byte("==== Legend\n")) 33 if len(sections) != 2 { 34 return nil, fmt.Errorf("failed to parse vmmap output: expected REGION_DETAIL to be column header, got") 35 } 36 37 // The vmmap address start/end output is centered around a common hyphen placement - we need to find the index of that hyphen, then split around it 38 hyphenIndex := bytes.Index(columnHeaders, []byte("START - END")) + len("START ") 39 entries := bytes.Split(sections[0], []byte("\n")) 40 var mappings = make([]mapping.Mapping, 0, len(entries)) 41 for rowNumber, entry := range entries { 42 if len(entry) <= hyphenIndex { 43 continue 44 } 45 var i int 46 for i = hyphenIndex; i > 0; i-- { 47 if entry[i] == ' ' { 48 i++ 49 break 50 } 51 } 52 startStr := string(entry[i:hyphenIndex]) 53 for i = hyphenIndex + 1; i < hyphenIndex+18; i++ { 54 if entry[i] == ' ' { 55 break 56 } 57 } 58 endStr := string(entry[hyphenIndex+1 : i]) 59 start, err := strconv.ParseUint(startStr, 16, 64) 60 if err != nil { 61 return nil, fmt.Errorf("failed to parse start hex uint64 from '%s' on row %d of vmmap output. Full output:\n%s", startStr, rowNumber, output) 62 } 63 end, err := strconv.ParseUint(endStr, 16, 64) 64 if err != nil { 65 return nil, fmt.Errorf("failed to parse end hex uint64 from '%s' on row %d of vmmap output. Full output:\n%s", endStr, rowNumber, output) 66 } 67 m := mapping.Mapping{ 68 StartAddr: uintptr(start), 69 EndAddr: uintptr(end), 70 } 71 mappings = append(mappings, m) 72 } 73 74 return mappings, nil 75 }