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
}