gitlab.com/Raven-IO/raven-delve@v1.22.4/pkg/proc/native/dump_linux_amd64.go (about)

     1  package native
     2  
     3  import (
     4  	"bytes"
     5  	"debug/elf"
     6  	"encoding/binary"
     7  	"fmt"
     8  	"os"
     9  	"path/filepath"
    10  
    11  	"gitlab.com/Raven-IO/raven-delve/pkg/elfwriter"
    12  	"gitlab.com/Raven-IO/raven-delve/pkg/proc/linutil"
    13  	"golang.org/x/sys/unix"
    14  )
    15  
    16  const _NT_AUXV elf.NType = 0x6
    17  
    18  type linuxPrPsInfo struct {
    19  	State                uint8
    20  	Sname                int8
    21  	Zomb                 uint8
    22  	Nice                 int8
    23  	_                    [4]uint8
    24  	Flag                 uint64
    25  	Uid, Gid             uint32
    26  	Pid, Ppid, Pgrp, Sid int32
    27  	Fname                [16]uint8
    28  	Args                 [80]uint8
    29  }
    30  
    31  func (p *nativeProcess) DumpProcessNotes(notes []elfwriter.Note, threadDone func()) (threadsDone bool, out []elfwriter.Note, err error) {
    32  	tobytes := func(x interface{}) []byte {
    33  		out := new(bytes.Buffer)
    34  		_ = binary.Write(out, binary.LittleEndian, x)
    35  		return out.Bytes()
    36  	}
    37  
    38  	prpsinfo := linuxPrPsInfo{
    39  		Pid: int32(p.pid),
    40  	}
    41  
    42  	fname := p.os.comm
    43  	if len(fname) > len(prpsinfo.Fname)-1 {
    44  		fname = fname[:len(prpsinfo.Fname)-1]
    45  	}
    46  	copy(prpsinfo.Fname[:], fname)
    47  	prpsinfo.Fname[len(fname)] = 0
    48  
    49  	if cmdline, err := os.ReadFile(fmt.Sprintf("/proc/%d/cmdline", p.pid)); err == nil {
    50  		for len(cmdline) > 0 && cmdline[len(cmdline)-1] == '\n' {
    51  			cmdline = cmdline[:len(cmdline)-1]
    52  		}
    53  		if zero := bytes.Index(cmdline, []byte{0}); zero >= 0 {
    54  			cmdline = cmdline[zero+1:]
    55  		}
    56  		path := p.BinInfo().Images[0].Path
    57  		if abs, err := filepath.Abs(path); err == nil {
    58  			path = abs
    59  		}
    60  		args := make([]byte, 0, len(path)+len(cmdline)+1)
    61  		args = append(args, []byte(path)...)
    62  		args = append(args, 0)
    63  		args = append(args, cmdline...)
    64  		if len(args) > len(prpsinfo.Args)-1 {
    65  			args = args[:len(prpsinfo.Args)-1]
    66  		}
    67  		copy(prpsinfo.Args[:], args)
    68  		prpsinfo.Args[len(args)] = 0
    69  	}
    70  	notes = append(notes, elfwriter.Note{
    71  		Type: elf.NT_PRPSINFO,
    72  		Data: tobytes(prpsinfo),
    73  	})
    74  
    75  	auxvbuf, err := os.ReadFile(fmt.Sprintf("/proc/%d/auxv", p.pid))
    76  	if err == nil {
    77  		notes = append(notes, elfwriter.Note{
    78  			Type: _NT_AUXV,
    79  			Data: auxvbuf,
    80  		})
    81  	}
    82  
    83  	for _, th := range p.threads {
    84  		regs, err := th.Registers()
    85  		if err != nil {
    86  			return false, notes, err
    87  		}
    88  
    89  		regs, err = regs.Copy() // triggers floating point register load
    90  		if err != nil {
    91  			return false, notes, err
    92  		}
    93  
    94  		nregs := regs.(*linutil.AMD64Registers)
    95  
    96  		var prstatus linuxPrStatusAMD64
    97  		prstatus.Pid = int32(th.ID)
    98  		prstatus.Ppid = int32(p.pid)
    99  		prstatus.Pgrp = int32(p.pid)
   100  		prstatus.Sid = int32(p.pid)
   101  		prstatus.Reg = *(nregs.Regs)
   102  		notes = append(notes, elfwriter.Note{
   103  			Type: elf.NT_PRSTATUS,
   104  			Data: tobytes(prstatus),
   105  		})
   106  
   107  		var xsave []byte
   108  
   109  		if nregs.Fpregset != nil && nregs.Fpregset.Xsave != nil {
   110  			xsave = make([]byte, len(nregs.Fpregset.Xsave))
   111  			copy(xsave, nregs.Fpregset.Xsave)
   112  		} else {
   113  			xsave = make([]byte, 512+64) // XSAVE header start + XSAVE header length
   114  		}
   115  
   116  		// Even if we have the XSAVE area on some versions of linux (or some CPU
   117  		// models?) it won't contain the legacy x87 registers, so copy them over
   118  		// in case we got them from PTRACE_GETFPREGS.
   119  		buf := new(bytes.Buffer)
   120  		binary.Write(buf, binary.LittleEndian, &nregs.Fpregset.AMD64PtraceFpRegs)
   121  		copy(xsave, buf.Bytes())
   122  
   123  		notes = append(notes, elfwriter.Note{
   124  			Type: _NT_X86_XSTATE,
   125  			Data: xsave,
   126  		})
   127  
   128  		threadDone()
   129  	}
   130  
   131  	return true, notes, nil
   132  }
   133  
   134  type linuxPrStatusAMD64 struct {
   135  	Siginfo                      linuxSiginfo
   136  	Cursig                       uint16
   137  	_                            [2]uint8
   138  	Sigpend                      uint64
   139  	Sighold                      uint64
   140  	Pid, Ppid, Pgrp, Sid         int32
   141  	Utime, Stime, CUtime, CStime unix.Timeval
   142  	Reg                          linutil.AMD64PtraceRegs
   143  	Fpvalid                      int64
   144  }
   145  
   146  // LinuxSiginfo is a copy of the
   147  // siginfo kernel struct.
   148  type linuxSiginfo struct {
   149  	Signo int32
   150  	Code  int32
   151  	Errno int32
   152  }