github.com/undoio/delve@v1.9.0/pkg/proc/native/dump_linux.go (about)

     1  package native
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"strconv"
     7  	"strings"
     8  
     9  	"github.com/undoio/delve/pkg/proc"
    10  )
    11  
    12  func (p *nativeProcess) MemoryMap() ([]proc.MemoryMapEntry, error) {
    13  	const VmFlagsPrefix = "VmFlags:"
    14  
    15  	smapsbuf, err := ioutil.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 = ioutil.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://github.com/go-delve/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  }