func Core()

in internal/core/process.go [138:241]


func Core(coreFile, base, exePath string) (*Process, error) {
	core, err := os.Open(coreFile)
	if err != nil {
		return nil, fmt.Errorf("failed to open core file: %v", err)
	}

	p := &Process{base: base, files: make(map[string]*file)}
	if exePath != "" {
		bin, err := os.Open(exePath)
		if err != nil {
			return nil, fmt.Errorf("failed to open executable file: %v", err)
		}
		p.exe = bin
	}

	if err := p.readExec(p.exe); err != nil {
		return nil, err
	}

	if err := p.readCore(core); err != nil {
		return nil, err
	}

	if err := p.readDebugInfo(); err != nil {
		return nil, err
	}

	// Sort then merge mappings, just to clean up a bit.
	mappings := p.memory.mappings
	sort.Slice(mappings, func(i, j int) bool {
		return mappings[i].min < mappings[j].min
	})
	ms := mappings[1:]
	mappings = mappings[:1]
	for _, m := range ms {
		k := mappings[len(mappings)-1]
		if m.min == k.max &&
			m.perm == k.perm &&
			m.f == k.f &&
			m.off == k.off+k.Size() {
			k.max = m.max
			// TODO: also check origF?
		} else {
			mappings = append(mappings, m)
		}
	}
	p.memory.mappings = mappings

	// Memory map all the mappings.
	hostPageSize := int64(syscall.Getpagesize())
	for _, m := range p.memory.mappings {
		size := m.max.Sub(m.min)
		if m.f == nil {
			// We don't have any source for this data.
			// Could be a mapped file that we couldn't find.
			// Could be a mapping madvised as MADV_DONTDUMP.
			// Pretend this is read-as-zero.
			// The other option is to just throw away
			// the mapping (and thus make Read*s of this
			// mapping fail).
			p.warnings = append(p.warnings,
				fmt.Sprintf("Missing data at addresses [%x %x]. Assuming all zero.", m.min, m.max))
			// TODO: this allocation could be large.
			// Use mmap to avoid real backing store for all those zeros, or
			// perhaps split the mapping up into chunks and share the zero contents among them.
			m.contents = make([]byte, size)
			continue
		}
		if m.perm&Write != 0 && m.f != core {
			p.warnings = append(p.warnings,
				fmt.Sprintf("Writeable data at [%x %x] missing from core. Using possibly stale backup source %s.", m.min, m.max, m.f.Name()))
		}
		// Data in core file might not be aligned enough for the host.
		// Expand memory range so we can map full pages.
		minOff := m.off
		maxOff := m.off + size
		minOff -= minOff % hostPageSize
		if maxOff%hostPageSize != 0 {
			maxOff += hostPageSize - maxOff%hostPageSize
		}

		// Read data from file.
		data, err := mapFile(int(m.f.Fd()), minOff, int(maxOff-minOff))
		if err != nil {
			return nil, fmt.Errorf("can't memory map %s at %x: %s\n", m.f.Name(), minOff, err)
		}

		// Trim any data we mapped but don't need.
		data = data[m.off-minOff:]
		data = data[:size]

		m.contents = data
	}

	// Build page table for mapping lookup.
	for _, m := range p.memory.mappings {
		err := p.addMapping(m)
		if err != nil {
			return nil, err
		}
	}

	return p, nil
}