mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 18:57:18 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			153 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			153 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package native
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"debug/elf"
 | |
| 	"encoding/binary"
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"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 := os.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 := os.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
 | |
| }
 | 
