gitlab.com/Raven-IO/raven-delve@v1.22.4/pkg/proc/native/dump_linux.go (about) 1 package native 2 3 import ( 4 "fmt" 5 "os" 6 "strconv" 7 "strings" 8 9 "gitlab.com/Raven-IO/raven-delve/pkg/proc" 10 ) 11 12 func (p *nativeProcess) MemoryMap() ([]proc.MemoryMapEntry, error) { 13 const VmFlagsPrefix = "VmFlags:" 14 15 smapsbuf, err := os.ReadFile(fmt.Sprintf("/proc/%d/smaps", p.pid)) 16 if err != nil { 17 // Older versions of Linux don't have smaps but have maps which is in a similar format. 18 smapsbuf, err = os.ReadFile(fmt.Sprintf("/proc/%d/maps", p.pid)) 19 if err != nil { 20 return nil, err 21 } 22 } 23 smapsLines := strings.Split(string(smapsbuf), "\n") 24 r := make([]proc.MemoryMapEntry, 0) 25 26 smapsLinesLoop: 27 for i := 0; i < len(smapsLines); { 28 line := smapsLines[i] 29 if line == "" { 30 i++ 31 continue 32 } 33 start, end, perm, offset, dev, filename, err := parseSmapsHeaderLine(i+1, line) 34 if err != nil { 35 return nil, err 36 } 37 var vmflags []string 38 for i++; i < len(smapsLines); i++ { 39 line := smapsLines[i] 40 if line == "" || line[0] < 'A' || line[0] > 'Z' { 41 break 42 } 43 if strings.HasPrefix(line, VmFlagsPrefix) { 44 vmflags = strings.Split(strings.TrimSpace(line[len(VmFlagsPrefix):]), " ") 45 } 46 } 47 48 for i := range vmflags { 49 switch vmflags[i] { 50 case "pf": 51 // pure PFN range, see https://gitlab.com/Raven-IO/raven-delve/issues/2630 52 continue smapsLinesLoop 53 case "dd": 54 // "don't dump" 55 continue smapsLinesLoop 56 case "io": 57 continue smapsLinesLoop 58 } 59 } 60 if strings.HasPrefix(dev, "00:") { 61 filename = "" 62 offset = 0 63 } 64 65 r = append(r, proc.MemoryMapEntry{ 66 Addr: start, 67 Size: end - start, 68 69 Read: perm[0] == 'r', 70 Write: perm[1] == 'w', 71 Exec: perm[2] == 'x', 72 73 Filename: filename, 74 Offset: offset, 75 }) 76 77 } 78 return r, nil 79 } 80 81 func parseSmapsHeaderLine(lineno int, in string) (start, end uint64, perm string, offset uint64, dev, filename string, err error) { 82 fields := strings.SplitN(in, " ", 6) 83 if len(fields) != 6 { 84 err = fmt.Errorf("malformed /proc/pid/maps on line %d: %q (wrong number of fields)", lineno, in) 85 return 86 } 87 88 v := strings.Split(fields[0], "-") 89 if len(v) != 2 { 90 err = fmt.Errorf("malformed /proc/pid/maps on line %d: %q (bad first field)", lineno, in) 91 return 92 } 93 start, err = strconv.ParseUint(v[0], 16, 64) 94 if err != nil { 95 err = fmt.Errorf("malformed /proc/pid/maps on line %d: %q (%v)", lineno, in, err) 96 return 97 } 98 end, err = strconv.ParseUint(v[1], 16, 64) 99 if err != nil { 100 err = fmt.Errorf("malformed /proc/pid/maps on line %d: %q (%v)", lineno, in, err) 101 return 102 } 103 104 perm = fields[1] 105 if len(perm) < 4 { 106 err = fmt.Errorf("malformed /proc/pid/maps on line %d: %q (permissions column too short)", lineno, in) 107 return 108 } 109 110 offset, err = strconv.ParseUint(fields[2], 16, 64) 111 if err != nil { 112 err = fmt.Errorf("malformed /proc/pid/maps on line %d: %q (%v)", lineno, in, err) 113 return 114 } 115 116 dev = fields[3] 117 118 // fields[4] -> inode 119 120 filename = strings.TrimLeft(fields[5], " ") 121 return 122 123 }