func (p *Profile) setMain() {
	for i := 0; i < len(p.Mapping); i++ {
		file := strings.TrimSpace(strings.Replace(p.Mapping[i].File, "(deleted)", "", -1))
		if len(file) == 0 {
			continue
		}
		if len(libRx.FindStringSubmatch(file)) > 0 {
			continue
		}
		if strings.HasPrefix(file, "[") {
			continue
		}
		tmp := p.Mapping[i]
		p.Mapping[i] = p.Mapping[0]
		p.Mapping[0] = tmp
		break
	}
}
setMain scans Mapping entries and guesses which entry is main
because legacy profiles don't obey the convention of putting main
first.
package profile
import (
	"bytes"
	"compress/gzip"
	"fmt"
	"io"
	"io/ioutil"
	"regexp"
	"strings"
	"time"
)
type Profile struct {
	SampleType []*ValueType
	Sample     []*Sample
	Mapping    []*Mapping
	Location   []*Location
	Function   []*Function
	DropFrames string
	KeepFrames string
	TimeNanos     int64
	DurationNanos int64
	PeriodType    *ValueType
	Period        int64
	dropFramesX int64
	keepFramesX int64
	stringTable []string
}
type ValueType struct {
	Type string  
	Unit string  
	typeX int64
	unitX int64
}
type Sample struct {
	Location []*Location
	Value    []int64
	Label    map[string][]string
	NumLabel map[string][]int64
	locationIDX []uint64
	labelX      []Label
}
type Label struct {
	keyX int64
	strX int64
	numX int64  
}
type Mapping struct {
	ID              uint64
	Start           uint64
	Limit           uint64
	Offset          uint64
	File            string
	BuildID         string
	HasFunctions    bool
	HasFilenames    bool
	HasLineNumbers  bool
	HasInlineFrames bool
	fileX    int64
	buildIDX int64
}
type Location struct {
	ID      uint64
	Mapping *Mapping
	Address uint64
	Line    []Line
	mappingIDX uint64
}
type Line struct {
	Function *Function
	Line     int64
	functionIDX uint64
}
type Function struct {
	ID         uint64
	Name       string
	SystemName string
	Filename   string
	StartLine  int64
	nameX       int64
	systemNameX int64
	filenameX   int64
}
func Parse(r io.Reader) (*Profile, error) {
	orig, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}
	var p *Profile
	if len(orig) >= 2 && orig[0] == 0x1f && orig[1] == 0x8b {
		gz, err := gzip.NewReader(bytes.NewBuffer(orig))
		if err != nil {
			return nil, fmt.Errorf("decompressing profile: %v", err)
		}
		data, err := ioutil.ReadAll(gz)
		if err != nil {
			return nil, fmt.Errorf("decompressing profile: %v", err)
		}
		orig = data
	}
	if p, err = parseUncompressed(orig); err != nil {
		if p, err = parseLegacy(orig); err != nil {
			return nil, fmt.Errorf("parsing profile: %v", err)
		}
	}
	if err := p.CheckValid(); err != nil {
		return nil, fmt.Errorf("malformed profile: %v", err)
	}
	return p, nil
}
var errUnrecognized = fmt.Errorf("unrecognized profile format")
var errMalformed = fmt.Errorf("malformed profile format")
func parseLegacy(data []byte) (*Profile, error) {
	parsers := []func([]byte) (*Profile, error){
		parseCPU,
		parseHeap,
		parseGoCount,  
		parseThread,
		parseContention,
	}
	for _, parser := range parsers {
		p, err := parser(data)
		if err == nil {
			p.setMain()
			p.addLegacyFrameInfo()
			return p, nil
		}
		if err != errUnrecognized {
			return nil, err
		}
	}
	return nil, errUnrecognized
}
func parseUncompressed(data []byte) (*Profile, error) {
	p := &Profile{}
	if err := unmarshal(data, p); err != nil {
		return nil, err
	}
	if err := p.postDecode(); err != nil {
		return nil, err
	}
	return p, nil
}
var libRx = regexp.MustCompile(`([.]so$|[.]so[._][0-9]+)`)