code: func (d *addr2Liner) readFrame() (plugin.Frame, bool) {
  	funcname, err := d.readString()
  	if err != nil {
  		return plugin.Frame{}, true
  	}
  	if strings.HasPrefix(funcname, "0x") {
  		// If addr2line returns a hex address we can assume it is the
  		// sentinel. Read and ignore next two lines of output from
  		// addr2line
  		d.readString()
  		d.readString()
  		return plugin.Frame{}, true
  	}
  
  	fileline, err := d.readString()
  	if err != nil {
  		return plugin.Frame{}, true
  	}
  
  	linenumber := 0
  
  	if funcname == "??" {
  		funcname = ""
  	}
  
  	if fileline == "??:0" {
  		fileline = ""
  	} else {
  		if i := strings.LastIndex(fileline, ":"); i >= 0 {
  			// Remove discriminator, if present
  			if disc := strings.Index(fileline, " (discriminator"); disc > 0 {
  				fileline = fileline[:disc]
  			}
  			// If we cannot parse a number after the last ":", keep it as
  			// part of the filename.
  			if line, err := strconv.Atoi(fileline[i+1:]); err == nil {
  				linenumber = line
  				fileline = fileline[:i]
  			}
  		}
  	}
  
  	return plugin.Frame{
  		Func: funcname,
  		File: fileline,
  		Line: linenumber}, false
  }
docs: // readFrame parses the addr2line output for a single address. It
  // returns a populated plugin.Frame and whether it has reached the end of the
  // data.