code: func (p *Profile) ParseMemoryMap(rd io.Reader) error {
  	b := bufio.NewReader(rd)
  
  	var attrs []string
  	var r *strings.Replacer
  	const delimiter = "="
  	for {
  		l, err := b.ReadString('\n')
  		if err != nil {
  			if err != io.EOF {
  				return err
  			}
  			if l == "" {
  				break
  			}
  		}
  		if l = strings.TrimSpace(l); l == "" {
  			continue
  		}
  
  		if r != nil {
  			l = r.Replace(l)
  		}
  		m, err := parseMappingEntry(l)
  		if err != nil {
  			if err == errUnrecognized {
  				// Recognize assignments of the form: attr=value, and replace
  				// $attr with value on subsequent mappings.
  				if attr := strings.SplitN(l, delimiter, 2); len(attr) == 2 {
  					attrs = append(attrs, "$"+strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1]))
  					r = strings.NewReplacer(attrs...)
  				}
  				// Ignore any unrecognized entries
  				continue
  			}
  			return err
  		}
  		if m == nil || (m.File == "" && len(p.Mapping) != 0) {
  			// In some cases the first entry may include the address range
  			// but not the name of the file. It should be followed by
  			// another entry with the name.
  			continue
  		}
  		if len(p.Mapping) == 1 && p.Mapping[0].File == "" {
  			// Update the name if this is the entry following that empty one.
  			p.Mapping[0].File = m.File
  			continue
  		}
  		p.Mapping = append(p.Mapping, m)
  	}
  	p.remapLocationIDs()
  	p.remapFunctionIDs()
  	p.remapMappingIDs()
  	return nil
  }
docs: // ParseMemoryMap parses a memory map in the format of
  // /proc/self/maps, and overrides the mappings in the current profile.
  // It renumbers the samples and locations in the profile correspondingly.