mirror of
				https://github.com/go-delve/delve.git
				synced 2025-11-04 06:32:16 +08:00 
			
		
		
		
	* proc/core: off-by-one error reading ELF core files core.(*splicedMemory).ReadMemory checked the entry interval erroneously when dealing with contiguous entries. * terminal,service,proc/*: adds dump command (gcore equivalent) Adds the `dump` command that creates a core file from the target process. Backends will need to implement a new, optional, method `MemoryMap` that returns a list of mapped memory regions. Additionally the method `DumpProcessNotes` can be implemented to write out to the core file notes describing the target process and its threads. If DumpProcessNotes is not implemented `proc.Dump` will write a description of the process and its threads in a OS/arch-independent format (that only Delve understands). Currently only linux/amd64 implements `DumpProcessNotes`. Core files are only written in ELF, there is no minidump or macho-o writers. # Conflicts: # pkg/proc/proc_test.go
		
			
				
	
	
		
			153 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			153 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package native
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"debug/elf"
 | 
						|
	"encoding/binary"
 | 
						|
	"fmt"
 | 
						|
	"io/ioutil"
 | 
						|
	"path/filepath"
 | 
						|
 | 
						|
	"github.com/go-delve/delve/pkg/elfwriter"
 | 
						|
	"github.com/go-delve/delve/pkg/proc/linutil"
 | 
						|
	"golang.org/x/sys/unix"
 | 
						|
)
 | 
						|
 | 
						|
const _NT_AUXV elf.NType = 0x6
 | 
						|
 | 
						|
type linuxPrPsInfo struct {
 | 
						|
	State                uint8
 | 
						|
	Sname                int8
 | 
						|
	Zomb                 uint8
 | 
						|
	Nice                 int8
 | 
						|
	_                    [4]uint8
 | 
						|
	Flag                 uint64
 | 
						|
	Uid, Gid             uint32
 | 
						|
	Pid, Ppid, Pgrp, Sid int32
 | 
						|
	Fname                [16]uint8
 | 
						|
	Args                 [80]uint8
 | 
						|
}
 | 
						|
 | 
						|
func (p *nativeProcess) DumpProcessNotes(notes []elfwriter.Note, threadDone func()) (threadsDone bool, out []elfwriter.Note, err error) {
 | 
						|
	tobytes := func(x interface{}) []byte {
 | 
						|
		out := new(bytes.Buffer)
 | 
						|
		_ = binary.Write(out, binary.LittleEndian, x)
 | 
						|
		return out.Bytes()
 | 
						|
	}
 | 
						|
 | 
						|
	prpsinfo := linuxPrPsInfo{
 | 
						|
		Pid: int32(p.pid),
 | 
						|
	}
 | 
						|
 | 
						|
	fname := p.os.comm
 | 
						|
	if len(fname) > len(prpsinfo.Fname)-1 {
 | 
						|
		fname = fname[:len(prpsinfo.Fname)-1]
 | 
						|
	}
 | 
						|
	copy(prpsinfo.Fname[:], fname)
 | 
						|
	prpsinfo.Fname[len(fname)] = 0
 | 
						|
 | 
						|
	if cmdline, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cmdline", p.pid)); err == nil {
 | 
						|
		for len(cmdline) > 0 && cmdline[len(cmdline)-1] == '\n' {
 | 
						|
			cmdline = cmdline[:len(cmdline)-1]
 | 
						|
		}
 | 
						|
		if zero := bytes.Index(cmdline, []byte{0}); zero >= 0 {
 | 
						|
			cmdline = cmdline[zero+1:]
 | 
						|
		}
 | 
						|
		path := p.BinInfo().Images[0].Path
 | 
						|
		if abs, err := filepath.Abs(path); err == nil {
 | 
						|
			path = abs
 | 
						|
		}
 | 
						|
		args := make([]byte, 0, len(path)+len(cmdline)+1)
 | 
						|
		args = append(args, []byte(path)...)
 | 
						|
		args = append(args, 0)
 | 
						|
		args = append(args, cmdline...)
 | 
						|
		if len(args) > len(prpsinfo.Args)-1 {
 | 
						|
			args = args[:len(prpsinfo.Args)-1]
 | 
						|
		}
 | 
						|
		copy(prpsinfo.Args[:], args)
 | 
						|
		prpsinfo.Args[len(args)] = 0
 | 
						|
	}
 | 
						|
	notes = append(notes, elfwriter.Note{
 | 
						|
		Type: elf.NT_PRPSINFO,
 | 
						|
		Data: tobytes(prpsinfo),
 | 
						|
	})
 | 
						|
 | 
						|
	auxvbuf, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/auxv", p.pid))
 | 
						|
	if err == nil {
 | 
						|
		notes = append(notes, elfwriter.Note{
 | 
						|
			Type: _NT_AUXV,
 | 
						|
			Data: auxvbuf,
 | 
						|
		})
 | 
						|
	}
 | 
						|
 | 
						|
	for _, th := range p.threads {
 | 
						|
		regs, err := th.Registers()
 | 
						|
		if err != nil {
 | 
						|
			return false, notes, err
 | 
						|
		}
 | 
						|
 | 
						|
		regs, err = regs.Copy() // triggers floating point register load
 | 
						|
		if err != nil {
 | 
						|
			return false, notes, err
 | 
						|
		}
 | 
						|
 | 
						|
		nregs := regs.(*linutil.AMD64Registers)
 | 
						|
 | 
						|
		var prstatus linuxPrStatusAMD64
 | 
						|
		prstatus.Pid = int32(th.ID)
 | 
						|
		prstatus.Ppid = int32(p.pid)
 | 
						|
		prstatus.Pgrp = int32(p.pid)
 | 
						|
		prstatus.Sid = int32(p.pid)
 | 
						|
		prstatus.Reg = *(nregs.Regs)
 | 
						|
		notes = append(notes, elfwriter.Note{
 | 
						|
			Type: elf.NT_PRSTATUS,
 | 
						|
			Data: tobytes(prstatus),
 | 
						|
		})
 | 
						|
 | 
						|
		var xsave []byte
 | 
						|
 | 
						|
		if nregs.Fpregset != nil && nregs.Fpregset.Xsave != nil {
 | 
						|
			xsave = make([]byte, len(nregs.Fpregset.Xsave))
 | 
						|
			copy(xsave, nregs.Fpregset.Xsave)
 | 
						|
		} else {
 | 
						|
			xsave = make([]byte, 512+64) // XSAVE header start + XSAVE header length
 | 
						|
		}
 | 
						|
 | 
						|
		// Even if we have the XSAVE area on some versions of linux (or some CPU
 | 
						|
		// models?) it won't contain the legacy x87 registers, so copy them over
 | 
						|
		// in case we got them from PTRACE_GETFPREGS.
 | 
						|
		buf := new(bytes.Buffer)
 | 
						|
		binary.Write(buf, binary.LittleEndian, &nregs.Fpregset.AMD64PtraceFpRegs)
 | 
						|
		copy(xsave, buf.Bytes())
 | 
						|
 | 
						|
		notes = append(notes, elfwriter.Note{
 | 
						|
			Type: _NT_X86_XSTATE,
 | 
						|
			Data: xsave,
 | 
						|
		})
 | 
						|
 | 
						|
		threadDone()
 | 
						|
	}
 | 
						|
 | 
						|
	return true, notes, nil
 | 
						|
}
 | 
						|
 | 
						|
type linuxPrStatusAMD64 struct {
 | 
						|
	Siginfo                      linuxSiginfo
 | 
						|
	Cursig                       uint16
 | 
						|
	_                            [2]uint8
 | 
						|
	Sigpend                      uint64
 | 
						|
	Sighold                      uint64
 | 
						|
	Pid, Ppid, Pgrp, Sid         int32
 | 
						|
	Utime, Stime, CUtime, CStime unix.Timeval
 | 
						|
	Reg                          linutil.AMD64PtraceRegs
 | 
						|
	Fpvalid                      int64
 | 
						|
}
 | 
						|
 | 
						|
// LinuxSiginfo is a copy of the
 | 
						|
// siginfo kernel struct.
 | 
						|
type linuxSiginfo struct {
 | 
						|
	Signo int32
 | 
						|
	Code  int32
 | 
						|
	Errno int32
 | 
						|
}
 |