
Cleans up repetitive code in pkg/proc/core and also adds coredumpctl support to our test suite.
162 lines
4.1 KiB
Go
162 lines
4.1 KiB
Go
package core
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/go-delve/delve/pkg/dwarf/op"
|
|
"github.com/go-delve/delve/pkg/elfwriter"
|
|
"github.com/go-delve/delve/pkg/proc"
|
|
)
|
|
|
|
func platformFromNotes(notes []*note) (goos, goarch string, err error) {
|
|
for _, note := range notes {
|
|
if note.Type != elfwriter.DelveHeaderNoteType {
|
|
continue
|
|
}
|
|
lines := strings.Split(string(note.Desc.([]byte)), "\n")
|
|
v := strings.Split(lines[0], "/")
|
|
if len(v) != 2 {
|
|
return "", "", fmt.Errorf("malformed delve header note: %q", string(note.Desc.([]byte)))
|
|
}
|
|
return v[0], v[1], nil
|
|
}
|
|
panic("internal error")
|
|
}
|
|
|
|
func threadsFromDelveNotes(p *process, notes []*note) (proc.Thread, error) {
|
|
var currentThread proc.Thread
|
|
for _, note := range notes {
|
|
if note.Type == elfwriter.DelveHeaderNoteType {
|
|
buf := bytes.NewBuffer(note.Desc.([]byte))
|
|
for {
|
|
line, err := buf.ReadString('\n')
|
|
if err != nil {
|
|
break
|
|
}
|
|
if len(line) > 0 && line[len(line)-1] == '\n' {
|
|
line = line[:len(line)-1]
|
|
}
|
|
switch {
|
|
case strings.HasPrefix(line, elfwriter.DelveHeaderTargetPidPrefix):
|
|
pid, err := strconv.ParseUint(line[len(elfwriter.DelveHeaderTargetPidPrefix):], 10, 64)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("malformed delve header note (bad pid): %v", err)
|
|
}
|
|
p.pid = int(pid)
|
|
case strings.HasPrefix(line, elfwriter.DelveHeaderEntryPointPrefix):
|
|
entry, err := strconv.ParseUint(line[len(elfwriter.DelveHeaderEntryPointPrefix):], 0, 64)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("malformed delve header note (bad entry point): %v", err)
|
|
}
|
|
p.entryPoint = entry
|
|
}
|
|
}
|
|
}
|
|
|
|
if note.Type != elfwriter.DelveThreadNodeType {
|
|
continue
|
|
}
|
|
body := bytes.NewReader(note.Desc.([]byte))
|
|
th := new(delveThread)
|
|
th.regs = new(delveRegisters)
|
|
|
|
var readerr error
|
|
read := func(out interface{}) {
|
|
if readerr != nil {
|
|
return
|
|
}
|
|
readerr = binary.Read(body, binary.LittleEndian, out)
|
|
}
|
|
|
|
read(&th.id)
|
|
|
|
read(&th.regs.pc)
|
|
read(&th.regs.sp)
|
|
read(&th.regs.bp)
|
|
read(&th.regs.tls)
|
|
read(&th.regs.hasGAddr)
|
|
read(&th.regs.gaddr)
|
|
|
|
var n uint32
|
|
read(&n)
|
|
|
|
if readerr != nil {
|
|
return nil, fmt.Errorf("error reading thread note header for thread %d: %v", th.id, readerr)
|
|
}
|
|
|
|
th.regs.slice = make([]proc.Register, n)
|
|
|
|
readBytes := func(maxlen uint16, kind string) []byte {
|
|
if readerr != nil {
|
|
return nil
|
|
}
|
|
var len uint16
|
|
read(&len)
|
|
if maxlen > 0 && len > maxlen {
|
|
readerr = fmt.Errorf("maximum len exceeded (%d) reading %s", len, kind)
|
|
return nil
|
|
}
|
|
if readerr != nil {
|
|
return nil
|
|
}
|
|
buf := make([]byte, len)
|
|
_, readerr = body.Read(buf)
|
|
return buf
|
|
}
|
|
|
|
for i := 0; i < int(n); i++ {
|
|
name := string(readBytes(20, "register name"))
|
|
value := readBytes(2048, "register value")
|
|
th.regs.slice[i] = proc.Register{Name: name, Reg: op.DwarfRegisterFromBytes(value)}
|
|
if readerr != nil {
|
|
return nil, fmt.Errorf("error reading thread note registers for thread %d: %v", th.id, readerr)
|
|
}
|
|
}
|
|
|
|
p.Threads[int(th.id)] = &thread{th, p, proc.CommonThread{}}
|
|
if currentThread == nil {
|
|
currentThread = p.Threads[int(th.id)]
|
|
}
|
|
}
|
|
return currentThread, nil
|
|
}
|
|
|
|
type delveThread struct {
|
|
id uint64
|
|
regs *delveRegisters
|
|
}
|
|
|
|
func (th *delveThread) ThreadID() int {
|
|
return int(th.id)
|
|
}
|
|
|
|
func (th *delveThread) Registers() (proc.Registers, error) {
|
|
return th.regs, nil
|
|
}
|
|
|
|
type delveRegisters struct {
|
|
pc, sp, bp, tls uint64
|
|
hasGAddr bool
|
|
gaddr uint64
|
|
slice []proc.Register
|
|
}
|
|
|
|
func (regs *delveRegisters) PC() uint64 { return regs.pc }
|
|
func (regs *delveRegisters) BP() uint64 { return regs.bp }
|
|
func (regs *delveRegisters) SP() uint64 { return regs.sp }
|
|
func (regs *delveRegisters) TLS() uint64 { return regs.tls }
|
|
func (regs *delveRegisters) GAddr() (uint64, bool) { return regs.gaddr, regs.hasGAddr }
|
|
func (regs *delveRegisters) LR() uint64 { return 0 }
|
|
|
|
func (regs *delveRegisters) Copy() (proc.Registers, error) {
|
|
return regs, nil
|
|
}
|
|
|
|
func (regs *delveRegisters) Slice(bool) ([]proc.Register, error) {
|
|
return regs.slice, nil
|
|
}
|