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 }