*: un-export unnecessarily public symbols

This commit is contained in:
aarzilli 2020-03-26 13:05:09 +01:00 committed by Derek Parker
parent 1ee8d5c218
commit 3c8d4d52b8
41 changed files with 593 additions and 639 deletions

@ -53,7 +53,7 @@ func (fde *FrameDescriptionEntry) EstablishFrame(pc uint64) *FrameContext {
type FrameDescriptionEntries []*FrameDescriptionEntry type FrameDescriptionEntries []*FrameDescriptionEntry
func NewFrameIndex() FrameDescriptionEntries { func newFrameIndex() FrameDescriptionEntries {
return make(FrameDescriptionEntries, 0, 1000) return make(FrameDescriptionEntries, 0, 1000)
} }

@ -13,7 +13,7 @@ func ptrSizeByRuntimeArch() int {
} }
func TestFDEForPC(t *testing.T) { func TestFDEForPC(t *testing.T) {
frames := NewFrameIndex() frames := newFrameIndex()
frames = append(frames, frames = append(frames,
&FrameDescriptionEntry{begin: 10, size: 40}, &FrameDescriptionEntry{begin: 10, size: 40},
&FrameDescriptionEntry{begin: 50, size: 50}, &FrameDescriptionEntry{begin: 50, size: 50},

@ -29,7 +29,7 @@ type parseContext struct {
func Parse(data []byte, order binary.ByteOrder, staticBase uint64, ptrSize int) FrameDescriptionEntries { func Parse(data []byte, order binary.ByteOrder, staticBase uint64, ptrSize int) FrameDescriptionEntries {
var ( var (
buf = bytes.NewBuffer(data) buf = bytes.NewBuffer(data)
pctx = &parseContext{buf: buf, entries: NewFrameIndex(), staticBase: staticBase, ptrSize: ptrSize} pctx = &parseContext{buf: buf, entries: newFrameIndex(), staticBase: staticBase, ptrSize: ptrSize}
) )
for fn := parselength; buf.Len() != 0; { for fn := parselength; buf.Len() != 0; {

@ -127,7 +127,7 @@ func executeCIEInstructions(cie *CommonInformationEntry) *FrameContext {
buf: bytes.NewBuffer(initialInstructions), buf: bytes.NewBuffer(initialInstructions),
} }
frame.ExecuteDwarfProgram() frame.executeDwarfProgram()
return frame return frame
} }
@ -142,7 +142,7 @@ func executeDwarfProgramUntilPC(fde *FrameDescriptionEntry, pc uint64) *FrameCon
return frame return frame
} }
func (frame *FrameContext) ExecuteDwarfProgram() { func (frame *FrameContext) executeDwarfProgram() {
for frame.buf.Len() > 0 { for frame.buf.Len() > 0 {
executeDwarfInstruction(frame) executeDwarfInstruction(frame)
} }

@ -9,7 +9,7 @@ import (
"github.com/go-delve/delve/pkg/proc" "github.com/go-delve/delve/pkg/proc"
) )
// A SplicedMemory represents a memory space formed from multiple regions, // A splicedMemory represents a memory space formed from multiple regions,
// each of which may override previously regions. For example, in the following // each of which may override previously regions. For example, in the following
// core, the program text was loaded at 0x400000: // core, the program text was loaded at 0x400000:
// Start End Page Offset // Start End Page Offset
@ -22,7 +22,7 @@ import (
// 0x0000000000002000 0x0000000000002000 RW 1000 // 0x0000000000002000 0x0000000000002000 RW 1000
// This can be represented in a SplicedMemory by adding the original region, // This can be represented in a SplicedMemory by adding the original region,
// then putting the RW mapping on top of it. // then putting the RW mapping on top of it.
type SplicedMemory struct { type splicedMemory struct {
readers []readerEntry readers []readerEntry
} }
@ -33,7 +33,7 @@ type readerEntry struct {
} }
// Add adds a new region to the SplicedMemory, which may override existing regions. // Add adds a new region to the SplicedMemory, which may override existing regions.
func (r *SplicedMemory) Add(reader proc.MemoryReader, off, length uintptr) { func (r *splicedMemory) Add(reader proc.MemoryReader, off, length uintptr) {
if length == 0 { if length == 0 {
return return
} }
@ -93,7 +93,7 @@ func (r *SplicedMemory) Add(reader proc.MemoryReader, off, length uintptr) {
} }
// ReadMemory implements MemoryReader.ReadMemory. // ReadMemory implements MemoryReader.ReadMemory.
func (r *SplicedMemory) ReadMemory(buf []byte, addr uintptr) (n int, err error) { func (r *splicedMemory) ReadMemory(buf []byte, addr uintptr) (n int, err error) {
started := false started := false
for _, entry := range r.readers { for _, entry := range r.readers {
if entry.offset+entry.length < addr { if entry.offset+entry.length < addr {
@ -132,40 +132,40 @@ func (r *SplicedMemory) ReadMemory(buf []byte, addr uintptr) (n int, err error)
return n, nil return n, nil
} }
// OffsetReaderAt wraps a ReaderAt into a MemoryReader, subtracting a fixed // offsetReaderAt wraps a ReaderAt into a MemoryReader, subtracting a fixed
// offset from the address. This is useful to represent a mapping in an address // offset from the address. This is useful to represent a mapping in an address
// space. For example, if program text is mapped in at 0x400000, an // space. For example, if program text is mapped in at 0x400000, an
// OffsetReaderAt with offset 0x400000 can be wrapped around file.Open(program) // OffsetReaderAt with offset 0x400000 can be wrapped around file.Open(program)
// to return the results of a read in that part of the address space. // to return the results of a read in that part of the address space.
type OffsetReaderAt struct { type offsetReaderAt struct {
reader io.ReaderAt reader io.ReaderAt
offset uintptr offset uintptr
} }
// ReadMemory will read the memory at addr-offset. // ReadMemory will read the memory at addr-offset.
func (r *OffsetReaderAt) ReadMemory(buf []byte, addr uintptr) (n int, err error) { func (r *offsetReaderAt) ReadMemory(buf []byte, addr uintptr) (n int, err error) {
return r.reader.ReadAt(buf, int64(addr-r.offset)) return r.reader.ReadAt(buf, int64(addr-r.offset))
} }
// Process represents a core file. // process represents a core file.
type Process struct { type process struct {
mem proc.MemoryReader mem proc.MemoryReader
Threads map[int]*Thread Threads map[int]*thread
pid int pid int
entryPoint uint64 entryPoint uint64
bi *proc.BinaryInfo bi *proc.BinaryInfo
breakpoints proc.BreakpointMap breakpoints proc.BreakpointMap
currentThread *Thread currentThread *thread
} }
var _ proc.ProcessInternal = &Process{} var _ proc.ProcessInternal = &process{}
// Thread represents a thread in the core file being debugged. // thread represents a thread in the core file being debugged.
type Thread struct { type thread struct {
th osThread th osThread
p *Process p *process
common proc.CommonThread common proc.CommonThread
} }
@ -189,7 +189,7 @@ var (
ErrChangeRegisterCore = errors.New("can not change register values of core process") ErrChangeRegisterCore = errors.New("can not change register values of core process")
) )
type openFn func(string, string) (*Process, error) type openFn func(string, string) (*process, error)
var openFns = []openFn{readLinuxCore, readAMD64Minidump} var openFns = []openFn{readLinuxCore, readAMD64Minidump}
@ -201,7 +201,7 @@ var ErrUnrecognizedFormat = errors.New("unrecognized core format")
// If the DWARF information cannot be found in the binary, Delve will look // If the DWARF information cannot be found in the binary, Delve will look
// for external debug files in the directories passed in. // for external debug files in the directories passed in.
func OpenCore(corePath, exePath string, debugInfoDirs []string) (*proc.Target, error) { func OpenCore(corePath, exePath string, debugInfoDirs []string) (*proc.Target, error) {
var p *Process var p *process
var err error var err error
for _, openFn := range openFns { for _, openFn := range openFns {
p, err = openFn(corePath, exePath) p, err = openFn(corePath, exePath)
@ -222,49 +222,49 @@ func OpenCore(corePath, exePath string, debugInfoDirs []string) (*proc.Target, e
} }
// BinInfo will return the binary info. // BinInfo will return the binary info.
func (p *Process) BinInfo() *proc.BinaryInfo { func (p *process) BinInfo() *proc.BinaryInfo {
return p.bi return p.bi
} }
// EntryPoint will return the entry point address for this core file. // EntryPoint will return the entry point address for this core file.
func (p *Process) EntryPoint() (uint64, error) { func (p *process) EntryPoint() (uint64, error) {
return p.entryPoint, nil return p.entryPoint, nil
} }
// writeBreakpoint is a noop function since you // writeBreakpoint is a noop function since you
// cannot write breakpoints into core files. // cannot write breakpoints into core files.
func (p *Process) writeBreakpoint(addr uint64) (file string, line int, fn *proc.Function, originalData []byte, err error) { func (p *process) writeBreakpoint(addr uint64) (file string, line int, fn *proc.Function, originalData []byte, err error) {
return "", 0, nil, nil, errors.New("cannot write a breakpoint to a core file") return "", 0, nil, nil, errors.New("cannot write a breakpoint to a core file")
} }
// Recorded returns whether this is a live or recorded process. Always returns true for core files. // Recorded returns whether this is a live or recorded process. Always returns true for core files.
func (p *Process) Recorded() (bool, string) { return true, "" } func (p *process) Recorded() (bool, string) { return true, "" }
// Restart will only return an error for core files, as they are not executing. // Restart will only return an error for core files, as they are not executing.
func (p *Process) Restart(string) error { return ErrContinueCore } func (p *process) Restart(string) error { return ErrContinueCore }
// ChangeDirection will only return an error as you cannot continue a core process. // ChangeDirection will only return an error as you cannot continue a core process.
func (p *Process) ChangeDirection(proc.Direction) error { return ErrContinueCore } func (p *process) ChangeDirection(proc.Direction) error { return ErrContinueCore }
// GetDirection will always return forward. // GetDirection will always return forward.
func (p *Process) GetDirection() proc.Direction { return proc.Forward } func (p *process) GetDirection() proc.Direction { return proc.Forward }
// When does not apply to core files, it is to support the Mozilla 'rr' backend. // When does not apply to core files, it is to support the Mozilla 'rr' backend.
func (p *Process) When() (string, error) { return "", nil } func (p *process) When() (string, error) { return "", nil }
// Checkpoint for core files returns an error, there is no execution of a core file. // Checkpoint for core files returns an error, there is no execution of a core file.
func (p *Process) Checkpoint(string) (int, error) { return -1, ErrContinueCore } func (p *process) Checkpoint(string) (int, error) { return -1, ErrContinueCore }
// Checkpoints returns nil on core files, you cannot set checkpoints when debugging core files. // Checkpoints returns nil on core files, you cannot set checkpoints when debugging core files.
func (p *Process) Checkpoints() ([]proc.Checkpoint, error) { return nil, nil } func (p *process) Checkpoints() ([]proc.Checkpoint, error) { return nil, nil }
// ClearCheckpoint clears a checkpoint, but will only return an error for core files. // ClearCheckpoint clears a checkpoint, but will only return an error for core files.
func (p *Process) ClearCheckpoint(int) error { return errors.New("checkpoint not found") } func (p *process) ClearCheckpoint(int) error { return errors.New("checkpoint not found") }
// ReadMemory will return memory from the core file at the specified location and put the // ReadMemory will return memory from the core file at the specified location and put the
// read memory into `data`, returning the length read, and returning an error if // read memory into `data`, returning the length read, and returning an error if
// the length read is shorter than the length of the `data` buffer. // the length read is shorter than the length of the `data` buffer.
func (t *Thread) ReadMemory(data []byte, addr uintptr) (n int, err error) { func (t *thread) ReadMemory(data []byte, addr uintptr) (n int, err error) {
n, err = t.p.mem.ReadMemory(data, addr) n, err = t.p.mem.ReadMemory(data, addr)
if err == nil && n != len(data) { if err == nil && n != len(data) {
err = ErrShortRead err = ErrShortRead
@ -274,13 +274,13 @@ func (t *Thread) ReadMemory(data []byte, addr uintptr) (n int, err error) {
// WriteMemory will only return an error for core files, you cannot write // WriteMemory will only return an error for core files, you cannot write
// to the memory of a core process. // to the memory of a core process.
func (t *Thread) WriteMemory(addr uintptr, data []byte) (int, error) { func (t *thread) WriteMemory(addr uintptr, data []byte) (int, error) {
return 0, ErrWriteCore return 0, ErrWriteCore
} }
// Location returns the location of this thread based on // Location returns the location of this thread based on
// the value of the instruction pointer register. // the value of the instruction pointer register.
func (t *Thread) Location() (*proc.Location, error) { func (t *thread) Location() (*proc.Location, error) {
regs, err := t.th.registers(false) regs, err := t.th.registers(false)
if err != nil { if err != nil {
return nil, err return nil, err
@ -293,150 +293,150 @@ func (t *Thread) Location() (*proc.Location, error) {
// Breakpoint returns the current breakpoint this thread is stopped at. // Breakpoint returns the current breakpoint this thread is stopped at.
// For core files this always returns an empty BreakpointState struct, as // For core files this always returns an empty BreakpointState struct, as
// there are no breakpoints when debugging core files. // there are no breakpoints when debugging core files.
func (t *Thread) Breakpoint() *proc.BreakpointState { func (t *thread) Breakpoint() *proc.BreakpointState {
return &proc.BreakpointState{} return &proc.BreakpointState{}
} }
// ThreadID returns the ID for this thread. // ThreadID returns the ID for this thread.
func (t *Thread) ThreadID() int { func (t *thread) ThreadID() int {
return int(t.th.pid()) return int(t.th.pid())
} }
// Registers returns the current value of the registers for this thread. // Registers returns the current value of the registers for this thread.
func (t *Thread) Registers(floatingPoint bool) (proc.Registers, error) { func (t *thread) Registers(floatingPoint bool) (proc.Registers, error) {
return t.th.registers(floatingPoint) return t.th.registers(floatingPoint)
} }
// RestoreRegisters will only return an error for core files, // RestoreRegisters will only return an error for core files,
// you cannot change register values for core files. // you cannot change register values for core files.
func (t *Thread) RestoreRegisters(proc.Registers) error { func (t *thread) RestoreRegisters(proc.Registers) error {
return ErrChangeRegisterCore return ErrChangeRegisterCore
} }
// BinInfo returns information about the binary. // BinInfo returns information about the binary.
func (t *Thread) BinInfo() *proc.BinaryInfo { func (t *thread) BinInfo() *proc.BinaryInfo {
return t.p.bi return t.p.bi
} }
// StepInstruction will only return an error for core files, // StepInstruction will only return an error for core files,
// you cannot execute a core file. // you cannot execute a core file.
func (t *Thread) StepInstruction() error { func (t *thread) StepInstruction() error {
return ErrContinueCore return ErrContinueCore
} }
// Blocked will return false always for core files as there is // Blocked will return false always for core files as there is
// no execution. // no execution.
func (t *Thread) Blocked() bool { func (t *thread) Blocked() bool {
return false return false
} }
// SetCurrentBreakpoint will always just return nil // SetCurrentBreakpoint will always just return nil
// for core files, as there are no breakpoints in core files. // for core files, as there are no breakpoints in core files.
func (t *Thread) SetCurrentBreakpoint(adjustPC bool) error { func (t *thread) SetCurrentBreakpoint(adjustPC bool) error {
return nil return nil
} }
// Common returns a struct containing common information // Common returns a struct containing common information
// across thread implementations. // across thread implementations.
func (t *Thread) Common() *proc.CommonThread { func (t *thread) Common() *proc.CommonThread {
return &t.common return &t.common
} }
// SetPC will always return an error, you cannot // SetPC will always return an error, you cannot
// change register values when debugging core files. // change register values when debugging core files.
func (t *Thread) SetPC(uint64) error { func (t *thread) SetPC(uint64) error {
return ErrChangeRegisterCore return ErrChangeRegisterCore
} }
// SetSP will always return an error, you cannot // SetSP will always return an error, you cannot
// change register values when debugging core files. // change register values when debugging core files.
func (t *Thread) SetSP(uint64) error { func (t *thread) SetSP(uint64) error {
return ErrChangeRegisterCore return ErrChangeRegisterCore
} }
// SetDX will always return an error, you cannot // SetDX will always return an error, you cannot
// change register values when debugging core files. // change register values when debugging core files.
func (t *Thread) SetDX(uint64) error { func (t *thread) SetDX(uint64) error {
return ErrChangeRegisterCore return ErrChangeRegisterCore
} }
// Breakpoints will return all breakpoints for the process. // Breakpoints will return all breakpoints for the process.
func (p *Process) Breakpoints() *proc.BreakpointMap { func (p *process) Breakpoints() *proc.BreakpointMap {
return &p.breakpoints return &p.breakpoints
} }
// ClearBreakpoint will always return an error as you cannot set or clear // ClearBreakpoint will always return an error as you cannot set or clear
// breakpoints on core files. // breakpoints on core files.
func (p *Process) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) { func (p *process) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) {
return nil, proc.NoBreakpointError{Addr: addr} return nil, proc.NoBreakpointError{Addr: addr}
} }
// ClearInternalBreakpoints will always return nil and have no // ClearInternalBreakpoints will always return nil and have no
// effect since you cannot set breakpoints on core files. // effect since you cannot set breakpoints on core files.
func (p *Process) ClearInternalBreakpoints() error { func (p *process) ClearInternalBreakpoints() error {
return nil return nil
} }
// ContinueOnce will always return an error because you // ContinueOnce will always return an error because you
// cannot control execution of a core file. // cannot control execution of a core file.
func (p *Process) ContinueOnce() (proc.Thread, proc.StopReason, error) { func (p *process) ContinueOnce() (proc.Thread, proc.StopReason, error) {
return nil, proc.StopUnknown, ErrContinueCore return nil, proc.StopUnknown, ErrContinueCore
} }
// StepInstruction will always return an error // StepInstruction will always return an error
// as you cannot control execution of a core file. // as you cannot control execution of a core file.
func (p *Process) StepInstruction() error { func (p *process) StepInstruction() error {
return ErrContinueCore return ErrContinueCore
} }
// RequestManualStop will return nil and have no effect // RequestManualStop will return nil and have no effect
// as you cannot control execution of a core file. // as you cannot control execution of a core file.
func (p *Process) RequestManualStop() error { func (p *process) RequestManualStop() error {
return nil return nil
} }
// CheckAndClearManualStopRequest will always return false and // CheckAndClearManualStopRequest will always return false and
// have no effect since there are no manual stop requests as // have no effect since there are no manual stop requests as
// there is no controlling execution of a core file. // there is no controlling execution of a core file.
func (p *Process) CheckAndClearManualStopRequest() bool { func (p *process) CheckAndClearManualStopRequest() bool {
return false return false
} }
// CurrentThread returns the current active thread. // CurrentThread returns the current active thread.
func (p *Process) CurrentThread() proc.Thread { func (p *process) CurrentThread() proc.Thread {
return p.currentThread return p.currentThread
} }
// Detach will always return nil and have no // Detach will always return nil and have no
// effect as you cannot detach from a core file // effect as you cannot detach from a core file
// and have it continue execution or exit. // and have it continue execution or exit.
func (p *Process) Detach(bool) error { func (p *process) Detach(bool) error {
return nil return nil
} }
// Valid returns whether the process is active. Always returns true // Valid returns whether the process is active. Always returns true
// for core files as it cannot exit or be otherwise detached from. // for core files as it cannot exit or be otherwise detached from.
func (p *Process) Valid() (bool, error) { func (p *process) Valid() (bool, error) {
return true, nil return true, nil
} }
// Pid returns the process ID of this process. // Pid returns the process ID of this process.
func (p *Process) Pid() int { func (p *process) Pid() int {
return p.pid return p.pid
} }
// ResumeNotify is a no-op on core files as we cannot // ResumeNotify is a no-op on core files as we cannot
// control execution. // control execution.
func (p *Process) ResumeNotify(chan<- struct{}) { func (p *process) ResumeNotify(chan<- struct{}) {
} }
// SetBreakpoint will always return an error for core files as you cannot write memory or control execution. // SetBreakpoint will always return an error for core files as you cannot write memory or control execution.
func (p *Process) SetBreakpoint(addr uint64, kind proc.BreakpointKind, cond ast.Expr) (*proc.Breakpoint, error) { func (p *process) SetBreakpoint(addr uint64, kind proc.BreakpointKind, cond ast.Expr) (*proc.Breakpoint, error) {
return nil, ErrWriteCore return nil, ErrWriteCore
} }
// ThreadList will return a list of all threads currently in the process. // ThreadList will return a list of all threads currently in the process.
func (p *Process) ThreadList() []proc.Thread { func (p *process) ThreadList() []proc.Thread {
r := make([]proc.Thread, 0, len(p.Threads)) r := make([]proc.Thread, 0, len(p.Threads))
for _, v := range p.Threads { for _, v := range p.Threads {
r = append(r, v) r = append(r, v)
@ -445,12 +445,12 @@ func (p *Process) ThreadList() []proc.Thread {
} }
// FindThread will return the thread with the corresponding thread ID. // FindThread will return the thread with the corresponding thread ID.
func (p *Process) FindThread(threadID int) (proc.Thread, bool) { func (p *process) FindThread(threadID int) (proc.Thread, bool) {
t, ok := p.Threads[threadID] t, ok := p.Threads[threadID]
return t, ok return t, ok
} }
// SetCurrentThread is used internally by proc.Target to change the current thread. // SetCurrentThread is used internally by proc.Target to change the current thread.
func (p *Process) SetCurrentThread(th proc.Thread) { func (p *process) SetCurrentThread(th proc.Thread) {
p.currentThread = th.(*Thread) p.currentThread = th.(*thread)
} }

@ -134,10 +134,10 @@ func TestSplicedReader(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
mem := &SplicedMemory{} mem := &splicedMemory{}
for _, region := range test.regions { for _, region := range test.regions {
r := bytes.NewReader(region.data) r := bytes.NewReader(region.data)
mem.Add(&OffsetReaderAt{r, 0}, region.off, region.length) mem.Add(&offsetReaderAt{r, 0}, region.off, region.length)
} }
got := make([]byte, test.readLen) got := make([]byte, test.readLen)
n, err := mem.ReadMemory(got, test.readAddr) n, err := mem.ReadMemory(got, test.readAddr)

@ -15,68 +15,68 @@ import (
// Copied from golang.org/x/sys/unix.Timeval since it's not available on all // Copied from golang.org/x/sys/unix.Timeval since it's not available on all
// systems. // systems.
type LinuxCoreTimeval struct { type linuxCoreTimeval struct {
Sec int64 Sec int64
Usec int64 Usec int64
} }
// NT_FILE is file mapping information, e.g. program text mappings. Desc is a LinuxNTFile. // NT_FILE is file mapping information, e.g. program text mappings. Desc is a LinuxNTFile.
const NT_FILE elf.NType = 0x46494c45 // "FILE". const _NT_FILE elf.NType = 0x46494c45 // "FILE".
// NT_X86_XSTATE is other registers, including AVX and such. // NT_X86_XSTATE is other registers, including AVX and such.
const NT_X86_XSTATE elf.NType = 0x202 // Note type for notes containing X86 XSAVE area. const _NT_X86_XSTATE elf.NType = 0x202 // Note type for notes containing X86 XSAVE area.
// NT_AUXV is the note type for notes containing a copy of the Auxv array // NT_AUXV is the note type for notes containing a copy of the Auxv array
const NT_AUXV elf.NType = 0x6 const _NT_AUXV elf.NType = 0x6
// NT_FPREGSET is the note type for floating point registers. // NT_FPREGSET is the note type for floating point registers.
const NT_FPREGSET elf.NType = 0x2 const _NT_FPREGSET elf.NType = 0x2
// Fetch architecture using exeELF.Machine from core file // Fetch architecture using exeELF.Machine from core file
// Refer http://man7.org/linux/man-pages/man5/elf.5.html // Refer http://man7.org/linux/man-pages/man5/elf.5.html
const ( const (
EM_AARCH64 = 183 _EM_AARCH64 = 183
EM_X86_64 = 62 _EM_X86_64 = 62
_ARM_FP_HEADER_START = 512 _ARM_FP_HEADER_START = 512
) )
const elfErrorBadMagicNumber = "bad magic number" const elfErrorBadMagicNumber = "bad magic number"
func linuxThreadsFromNotes(p *Process, notes []*Note, machineType elf.Machine) { func linuxThreadsFromNotes(p *process, notes []*note, machineType elf.Machine) {
var lastThreadAMD *linuxAMD64Thread var lastThreadAMD *linuxAMD64Thread
var lastThreadARM *linuxARM64Thread var lastThreadARM *linuxARM64Thread
for _, note := range notes { for _, note := range notes {
switch note.Type { switch note.Type {
case elf.NT_PRSTATUS: case elf.NT_PRSTATUS:
if machineType == EM_X86_64 { if machineType == _EM_X86_64 {
t := note.Desc.(*LinuxPrStatusAMD64) t := note.Desc.(*linuxPrStatusAMD64)
lastThreadAMD = &linuxAMD64Thread{linutil.AMD64Registers{Regs: &t.Reg}, t} lastThreadAMD = &linuxAMD64Thread{linutil.AMD64Registers{Regs: &t.Reg}, t}
p.Threads[int(t.Pid)] = &Thread{lastThreadAMD, p, proc.CommonThread{}} p.Threads[int(t.Pid)] = &thread{lastThreadAMD, p, proc.CommonThread{}}
if p.currentThread == nil { if p.currentThread == nil {
p.currentThread = p.Threads[int(t.Pid)] p.currentThread = p.Threads[int(t.Pid)]
} }
} else if machineType == EM_AARCH64 { } else if machineType == _EM_AARCH64 {
t := note.Desc.(*LinuxPrStatusARM64) t := note.Desc.(*linuxPrStatusARM64)
lastThreadARM = &linuxARM64Thread{linutil.ARM64Registers{Regs: &t.Reg}, t} lastThreadARM = &linuxARM64Thread{linutil.ARM64Registers{Regs: &t.Reg}, t}
p.Threads[int(t.Pid)] = &Thread{lastThreadARM, p, proc.CommonThread{}} p.Threads[int(t.Pid)] = &thread{lastThreadARM, p, proc.CommonThread{}}
if p.currentThread == nil { if p.currentThread == nil {
p.currentThread = p.Threads[int(t.Pid)] p.currentThread = p.Threads[int(t.Pid)]
} }
} }
case NT_FPREGSET: case _NT_FPREGSET:
if machineType == EM_AARCH64 { if machineType == _EM_AARCH64 {
if lastThreadARM != nil { if lastThreadARM != nil {
lastThreadARM.regs.Fpregs = note.Desc.(*linutil.ARM64PtraceFpRegs).Decode() lastThreadARM.regs.Fpregs = note.Desc.(*linutil.ARM64PtraceFpRegs).Decode()
} }
} }
case NT_X86_XSTATE: case _NT_X86_XSTATE:
if machineType == EM_X86_64 { if machineType == _EM_X86_64 {
if lastThreadAMD != nil { if lastThreadAMD != nil {
lastThreadAMD.regs.Fpregs = note.Desc.(*linutil.AMD64Xstate).Decode() lastThreadAMD.regs.Fpregs = note.Desc.(*linutil.AMD64Xstate).Decode()
} }
} }
case elf.NT_PRPSINFO: case elf.NT_PRPSINFO:
p.pid = int(note.Desc.(*LinuxPrPsInfo).Pid) p.pid = int(note.Desc.(*linuxPrPsInfo).Pid)
} }
} }
} }
@ -87,7 +87,7 @@ func linuxThreadsFromNotes(p *Process, notes []*Note, machineType elf.Machine) {
// http://uhlo.blogspot.fr/2012/05/brief-look-into-core-dumps.html, // http://uhlo.blogspot.fr/2012/05/brief-look-into-core-dumps.html,
// elf_core_dump in http://lxr.free-electrons.com/source/fs/binfmt_elf.c, // elf_core_dump in http://lxr.free-electrons.com/source/fs/binfmt_elf.c,
// and, if absolutely desperate, readelf.c from the binutils source. // and, if absolutely desperate, readelf.c from the binutils source.
func readLinuxCore(corePath, exePath string) (*Process, error) { func readLinuxCore(corePath, exePath string) (*process, error) {
coreFile, err := elf.Open(corePath) coreFile, err := elf.Open(corePath)
if err != nil { if err != nil {
if _, isfmterr := err.(*elf.FormatError); isfmterr && (strings.Contains(err.Error(), elfErrorBadMagicNumber) || strings.Contains(err.Error(), " at offset 0x0: too short")) { if _, isfmterr := err.(*elf.FormatError); isfmterr && (strings.Contains(err.Error(), elfErrorBadMagicNumber) || strings.Contains(err.Error(), " at offset 0x0: too short")) {
@ -122,9 +122,9 @@ func readLinuxCore(corePath, exePath string) (*Process, error) {
// TODO support 386 // TODO support 386
var bi *proc.BinaryInfo var bi *proc.BinaryInfo
switch machineType { switch machineType {
case EM_X86_64: case _EM_X86_64:
bi = proc.NewBinaryInfo("linux", "amd64") bi = proc.NewBinaryInfo("linux", "amd64")
case EM_AARCH64: case _EM_AARCH64:
bi = proc.NewBinaryInfo("linux", "arm64") bi = proc.NewBinaryInfo("linux", "arm64")
default: default:
return nil, fmt.Errorf("unsupported machine type") return nil, fmt.Errorf("unsupported machine type")
@ -132,9 +132,9 @@ func readLinuxCore(corePath, exePath string) (*Process, error) {
entryPoint := findEntryPoint(notes, bi.Arch.PtrSize()) entryPoint := findEntryPoint(notes, bi.Arch.PtrSize())
p := &Process{ p := &process{
mem: memory, mem: memory,
Threads: map[int]*Thread{}, Threads: map[int]*thread{},
entryPoint: entryPoint, entryPoint: entryPoint,
bi: bi, bi: bi,
breakpoints: proc.NewBreakpointMap(), breakpoints: proc.NewBreakpointMap(),
@ -146,12 +146,12 @@ func readLinuxCore(corePath, exePath string) (*Process, error) {
type linuxAMD64Thread struct { type linuxAMD64Thread struct {
regs linutil.AMD64Registers regs linutil.AMD64Registers
t *LinuxPrStatusAMD64 t *linuxPrStatusAMD64
} }
type linuxARM64Thread struct { type linuxARM64Thread struct {
regs linutil.ARM64Registers regs linutil.ARM64Registers
t *LinuxPrStatusARM64 t *linuxPrStatusARM64
} }
func (t *linuxAMD64Thread) registers(floatingPoint bool) (proc.Registers, error) { func (t *linuxAMD64Thread) registers(floatingPoint bool) (proc.Registers, error) {
@ -187,14 +187,14 @@ func (t *linuxARM64Thread) pid() int {
// - NT_PRSTATUS: Information about a thread, including base registers, state, etc. Desc is a LinuxPrStatus. // - NT_PRSTATUS: Information about a thread, including base registers, state, etc. Desc is a LinuxPrStatus.
// - NT_FPREGSET (Not implemented): x87 floating point registers. // - NT_FPREGSET (Not implemented): x87 floating point registers.
// - NT_X86_XSTATE: Other registers, including AVX and such. // - NT_X86_XSTATE: Other registers, including AVX and such.
type Note struct { type note struct {
Type elf.NType Type elf.NType
Name string Name string
Desc interface{} // Decoded Desc from the Desc interface{} // Decoded Desc from the
} }
// readNotes reads all the notes from the notes prog in core. // readNotes reads all the notes from the notes prog in core.
func readNotes(core *elf.File, machineType elf.Machine) ([]*Note, error) { func readNotes(core *elf.File, machineType elf.Machine) ([]*note, error) {
var notesProg *elf.Prog var notesProg *elf.Prog
for _, prog := range core.Progs { for _, prog := range core.Progs {
if prog.Type == elf.PT_NOTE { if prog.Type == elf.PT_NOTE {
@ -204,7 +204,7 @@ func readNotes(core *elf.File, machineType elf.Machine) ([]*Note, error) {
} }
r := notesProg.Open() r := notesProg.Open()
notes := []*Note{} notes := []*note{}
for { for {
note, err := readNote(r, machineType) note, err := readNote(r, machineType)
if err == io.EOF { if err == io.EOF {
@ -220,11 +220,11 @@ func readNotes(core *elf.File, machineType elf.Machine) ([]*Note, error) {
} }
// readNote reads a single note from r, decoding the descriptor if possible. // readNote reads a single note from r, decoding the descriptor if possible.
func readNote(r io.ReadSeeker, machineType elf.Machine) (*Note, error) { func readNote(r io.ReadSeeker, machineType elf.Machine) (*note, error) {
// Notes are laid out as described in the SysV ABI: // Notes are laid out as described in the SysV ABI:
// http://www.sco.com/developers/gabi/latest/ch5.pheader.html#note_section // http://www.sco.com/developers/gabi/latest/ch5.pheader.html#note_section
note := &Note{} note := &note{}
hdr := &ELFNotesHdr{} hdr := &elfNotesHdr{}
err := binary.Read(r, binary.LittleEndian, hdr) err := binary.Read(r, binary.LittleEndian, hdr)
if err != nil { if err != nil {
@ -247,10 +247,10 @@ func readNote(r io.ReadSeeker, machineType elf.Machine) (*Note, error) {
descReader := bytes.NewReader(desc) descReader := bytes.NewReader(desc)
switch note.Type { switch note.Type {
case elf.NT_PRSTATUS: case elf.NT_PRSTATUS:
if machineType == EM_X86_64 { if machineType == _EM_X86_64 {
note.Desc = &LinuxPrStatusAMD64{} note.Desc = &linuxPrStatusAMD64{}
} else if machineType == EM_AARCH64 { } else if machineType == _EM_AARCH64 {
note.Desc = &LinuxPrStatusARM64{} note.Desc = &linuxPrStatusARM64{}
} else { } else {
return nil, fmt.Errorf("unsupported machine type") return nil, fmt.Errorf("unsupported machine type")
} }
@ -258,39 +258,39 @@ func readNote(r io.ReadSeeker, machineType elf.Machine) (*Note, error) {
return nil, fmt.Errorf("reading NT_PRSTATUS: %v", err) return nil, fmt.Errorf("reading NT_PRSTATUS: %v", err)
} }
case elf.NT_PRPSINFO: case elf.NT_PRPSINFO:
note.Desc = &LinuxPrPsInfo{} note.Desc = &linuxPrPsInfo{}
if err := binary.Read(descReader, binary.LittleEndian, note.Desc); err != nil { if err := binary.Read(descReader, binary.LittleEndian, note.Desc); err != nil {
return nil, fmt.Errorf("reading NT_PRPSINFO: %v", err) return nil, fmt.Errorf("reading NT_PRPSINFO: %v", err)
} }
case NT_FILE: case _NT_FILE:
// No good documentation reference, but the structure is // No good documentation reference, but the structure is
// simply a header, including entry count, followed by that // simply a header, including entry count, followed by that
// many entries, and then the file name of each entry, // many entries, and then the file name of each entry,
// null-delimited. Not reading the names here. // null-delimited. Not reading the names here.
data := &LinuxNTFile{} data := &linuxNTFile{}
if err := binary.Read(descReader, binary.LittleEndian, &data.LinuxNTFileHdr); err != nil { if err := binary.Read(descReader, binary.LittleEndian, &data.linuxNTFileHdr); err != nil {
return nil, fmt.Errorf("reading NT_FILE header: %v", err) return nil, fmt.Errorf("reading NT_FILE header: %v", err)
} }
for i := 0; i < int(data.Count); i++ { for i := 0; i < int(data.Count); i++ {
entry := &LinuxNTFileEntry{} entry := &linuxNTFileEntry{}
if err := binary.Read(descReader, binary.LittleEndian, entry); err != nil { if err := binary.Read(descReader, binary.LittleEndian, entry); err != nil {
return nil, fmt.Errorf("reading NT_FILE entry %v: %v", i, err) return nil, fmt.Errorf("reading NT_FILE entry %v: %v", i, err)
} }
data.entries = append(data.entries, entry) data.entries = append(data.entries, entry)
} }
note.Desc = data note.Desc = data
case NT_X86_XSTATE: case _NT_X86_XSTATE:
if machineType == EM_X86_64 { if machineType == _EM_X86_64 {
var fpregs linutil.AMD64Xstate var fpregs linutil.AMD64Xstate
if err := linutil.AMD64XstateRead(desc, true, &fpregs); err != nil { if err := linutil.AMD64XstateRead(desc, true, &fpregs); err != nil {
return nil, err return nil, err
} }
note.Desc = &fpregs note.Desc = &fpregs
} }
case NT_AUXV: case _NT_AUXV:
note.Desc = desc note.Desc = desc
case NT_FPREGSET: case _NT_FPREGSET:
if machineType == EM_AARCH64 { if machineType == _EM_AARCH64 {
fpregs := &linutil.ARM64PtraceFpRegs{} fpregs := &linutil.ARM64PtraceFpRegs{}
rdr := bytes.NewReader(desc[:_ARM_FP_HEADER_START]) rdr := bytes.NewReader(desc[:_ARM_FP_HEADER_START])
if err := binary.Read(rdr, binary.LittleEndian, fpregs.Byte()); err != nil { if err := binary.Read(rdr, binary.LittleEndian, fpregs.Byte()); err != nil {
@ -320,15 +320,15 @@ func skipPadding(r io.ReadSeeker, pad int64) error {
return nil return nil
} }
func buildMemory(core, exeELF *elf.File, exe io.ReaderAt, notes []*Note) proc.MemoryReader { func buildMemory(core, exeELF *elf.File, exe io.ReaderAt, notes []*note) proc.MemoryReader {
memory := &SplicedMemory{} memory := &splicedMemory{}
// For now, assume all file mappings are to the exe. // For now, assume all file mappings are to the exe.
for _, note := range notes { for _, note := range notes {
if note.Type == NT_FILE { if note.Type == _NT_FILE {
fileNote := note.Desc.(*LinuxNTFile) fileNote := note.Desc.(*linuxNTFile)
for _, entry := range fileNote.entries { for _, entry := range fileNote.entries {
r := &OffsetReaderAt{ r := &offsetReaderAt{
reader: exe, reader: exe,
offset: uintptr(entry.Start - (entry.FileOfs * fileNote.PageSize)), offset: uintptr(entry.Start - (entry.FileOfs * fileNote.PageSize)),
} }
@ -346,7 +346,7 @@ func buildMemory(core, exeELF *elf.File, exe io.ReaderAt, notes []*Note) proc.Me
if prog.Filesz == 0 { if prog.Filesz == 0 {
continue continue
} }
r := &OffsetReaderAt{ r := &offsetReaderAt{
reader: prog.ReaderAt, reader: prog.ReaderAt,
offset: uintptr(prog.Vaddr), offset: uintptr(prog.Vaddr),
} }
@ -357,9 +357,9 @@ func buildMemory(core, exeELF *elf.File, exe io.ReaderAt, notes []*Note) proc.Me
return memory return memory
} }
func findEntryPoint(notes []*Note, ptrSize int) uint64 { func findEntryPoint(notes []*note, ptrSize int) uint64 {
for _, note := range notes { for _, note := range notes {
if note.Type == NT_AUXV { if note.Type == _NT_AUXV {
return linutil.EntryPointFromAuxv(note.Desc.([]byte), ptrSize) return linutil.EntryPointFromAuxv(note.Desc.([]byte), ptrSize)
} }
} }
@ -370,7 +370,7 @@ func findEntryPoint(notes []*Note, ptrSize int) uint64 {
// AMD64 specific primarily because of unix.PtraceRegs, but also // AMD64 specific primarily because of unix.PtraceRegs, but also
// because some of the fields are word sized. // because some of the fields are word sized.
// See http://lxr.free-electrons.com/source/include/uapi/linux/elfcore.h // See http://lxr.free-electrons.com/source/include/uapi/linux/elfcore.h
type LinuxPrPsInfo struct { type linuxPrPsInfo struct {
State uint8 State uint8
Sname int8 Sname int8
Zomb uint8 Zomb uint8
@ -384,61 +384,61 @@ type LinuxPrPsInfo struct {
} }
// LinuxPrStatusAMD64 is a copy of the prstatus kernel struct. // LinuxPrStatusAMD64 is a copy of the prstatus kernel struct.
type LinuxPrStatusAMD64 struct { type linuxPrStatusAMD64 struct {
Siginfo LinuxSiginfo Siginfo linuxSiginfo
Cursig uint16 Cursig uint16
_ [2]uint8 _ [2]uint8
Sigpend uint64 Sigpend uint64
Sighold uint64 Sighold uint64
Pid, Ppid, Pgrp, Sid int32 Pid, Ppid, Pgrp, Sid int32
Utime, Stime, CUtime, CStime LinuxCoreTimeval Utime, Stime, CUtime, CStime linuxCoreTimeval
Reg linutil.AMD64PtraceRegs Reg linutil.AMD64PtraceRegs
Fpvalid int32 Fpvalid int32
} }
// LinuxPrStatusARM64 is a copy of the prstatus kernel struct. // LinuxPrStatusARM64 is a copy of the prstatus kernel struct.
type LinuxPrStatusARM64 struct { type linuxPrStatusARM64 struct {
Siginfo LinuxSiginfo Siginfo linuxSiginfo
Cursig uint16 Cursig uint16
_ [2]uint8 _ [2]uint8
Sigpend uint64 Sigpend uint64
Sighold uint64 Sighold uint64
Pid, Ppid, Pgrp, Sid int32 Pid, Ppid, Pgrp, Sid int32
Utime, Stime, CUtime, CStime LinuxCoreTimeval Utime, Stime, CUtime, CStime linuxCoreTimeval
Reg linutil.ARM64PtraceRegs Reg linutil.ARM64PtraceRegs
Fpvalid int32 Fpvalid int32
} }
// LinuxSiginfo is a copy of the // LinuxSiginfo is a copy of the
// siginfo kernel struct. // siginfo kernel struct.
type LinuxSiginfo struct { type linuxSiginfo struct {
Signo int32 Signo int32
Code int32 Code int32
Errno int32 Errno int32
} }
// LinuxNTFile contains information on mapped files. // LinuxNTFile contains information on mapped files.
type LinuxNTFile struct { type linuxNTFile struct {
LinuxNTFileHdr linuxNTFileHdr
entries []*LinuxNTFileEntry entries []*linuxNTFileEntry
} }
// LinuxNTFileHdr is a header struct for NTFile. // LinuxNTFileHdr is a header struct for NTFile.
type LinuxNTFileHdr struct { type linuxNTFileHdr struct {
Count uint64 Count uint64
PageSize uint64 PageSize uint64
} }
// LinuxNTFileEntry is an entry of an NT_FILE note. // LinuxNTFileEntry is an entry of an NT_FILE note.
type LinuxNTFileEntry struct { type linuxNTFileEntry struct {
Start uint64 Start uint64
End uint64 End uint64
FileOfs uint64 FileOfs uint64
} }
// ELFNotesHdr is the ELF Notes header. // elfNotesHdr is the ELF Notes header.
// Same size on 64 and 32-bit machines. // Same size on 64 and 32-bit machines.
type ELFNotesHdr struct { type elfNotesHdr struct {
Namesz uint32 Namesz uint32
Descsz uint32 Descsz uint32
Type uint32 Type uint32

@ -7,7 +7,7 @@ import (
"github.com/go-delve/delve/pkg/proc/winutil" "github.com/go-delve/delve/pkg/proc/winutil"
) )
func readAMD64Minidump(minidumpPath, exePath string) (*Process, error) { func readAMD64Minidump(minidumpPath, exePath string) (*process, error) {
var logfn func(string, ...interface{}) var logfn func(string, ...interface{})
if logflags.Minidump() { if logflags.Minidump() {
logfn = logflags.MinidumpLogger().Infof logfn = logflags.MinidumpLogger().Infof
@ -21,16 +21,16 @@ func readAMD64Minidump(minidumpPath, exePath string) (*Process, error) {
return nil, err return nil, err
} }
memory := &SplicedMemory{} memory := &splicedMemory{}
for i := range mdmp.MemoryRanges { for i := range mdmp.MemoryRanges {
m := &mdmp.MemoryRanges[i] m := &mdmp.MemoryRanges[i]
memory.Add(m, uintptr(m.Addr), uintptr(len(m.Data))) memory.Add(m, uintptr(m.Addr), uintptr(len(m.Data)))
} }
p := &Process{ p := &process{
mem: memory, mem: memory,
Threads: map[int]*Thread{}, Threads: map[int]*thread{},
bi: proc.NewBinaryInfo("windows", "amd64"), bi: proc.NewBinaryInfo("windows", "amd64"),
breakpoints: proc.NewBreakpointMap(), breakpoints: proc.NewBreakpointMap(),
pid: int(mdmp.Pid), pid: int(mdmp.Pid),
@ -38,7 +38,7 @@ func readAMD64Minidump(minidumpPath, exePath string) (*Process, error) {
for i := range mdmp.Threads { for i := range mdmp.Threads {
th := &mdmp.Threads[i] th := &mdmp.Threads[i]
p.Threads[int(th.ID)] = &Thread{&windowsAMD64Thread{th}, p, proc.CommonThread{}} p.Threads[int(th.ID)] = &thread{&windowsAMD64Thread{th}, p, proc.CommonThread{}}
if p.currentThread == nil { if p.currentThread == nil {
p.currentThread = p.Threads[int(th.ID)] p.currentThread = p.Threads[int(th.ID)]
} }

@ -100,12 +100,12 @@ var ErrDirChange = errors.New("direction change with internal breakpoints")
// Process implements proc.Process using a connection to a debugger stub // Process implements proc.Process using a connection to a debugger stub
// that understands Gdb Remote Serial Protocol. // that understands Gdb Remote Serial Protocol.
type Process struct { type gdbProcess struct {
bi *proc.BinaryInfo bi *proc.BinaryInfo
conn gdbConn conn gdbConn
threads map[int]*Thread threads map[int]*gdbThread
currentThread *Thread currentThread *gdbThread
exited, detached bool exited, detached bool
ctrlC bool // ctrl-c was sent to stop inferior ctrlC bool // ctrl-c was sent to stop inferior
@ -126,15 +126,15 @@ type Process struct {
onDetach func() // called after a successful detach onDetach func() // called after a successful detach
} }
var _ proc.ProcessInternal = &Process{} var _ proc.ProcessInternal = &gdbProcess{}
// Thread represents an operating system thread. // Thread represents an operating system thread.
type Thread struct { type gdbThread struct {
ID int ID int
strID string strID string
regs gdbRegisters regs gdbRegisters
CurrentBreakpoint proc.BreakpointState CurrentBreakpoint proc.BreakpointState
p *Process p *gdbProcess
sig uint8 // signal received by thread after last stop sig uint8 // signal received by thread after last stop
setbp bool // thread was stopped because of a breakpoint setbp bool // thread was stopped because of a breakpoint
common proc.CommonThread common proc.CommonThread
@ -165,20 +165,20 @@ type gdbRegister struct {
regnum int regnum int
} }
// New creates a new Process instance. // newProcess creates a new Process instance.
// If process is not nil it is the stub's process and will be killed after // If process is not nil it is the stub's process and will be killed after
// Detach. // Detach.
// Use Listen, Dial or Connect to complete connection. // Use Listen, Dial or Connect to complete connection.
func New(process *os.Process) *Process { func newProcess(process *os.Process) *gdbProcess {
logger := logflags.GdbWireLogger() logger := logflags.GdbWireLogger()
p := &Process{ p := &gdbProcess{
conn: gdbConn{ conn: gdbConn{
maxTransmitAttempts: maxTransmitAttempts, maxTransmitAttempts: maxTransmitAttempts,
inbuf: make([]byte, 0, initialInputBufferSize), inbuf: make([]byte, 0, initialInputBufferSize),
direction: proc.Forward, direction: proc.Forward,
log: logger, log: logger,
}, },
threads: make(map[int]*Thread), threads: make(map[int]*gdbThread),
bi: proc.NewBinaryInfo(runtime.GOOS, runtime.GOARCH), bi: proc.NewBinaryInfo(runtime.GOOS, runtime.GOARCH),
breakpoints: proc.NewBreakpointMap(), breakpoints: proc.NewBreakpointMap(),
gcmdok: true, gcmdok: true,
@ -198,7 +198,7 @@ func New(process *os.Process) *Process {
} }
// Listen waits for a connection from the stub. // Listen waits for a connection from the stub.
func (p *Process) Listen(listener net.Listener, path string, pid int, debugInfoDirs []string, stopReason proc.StopReason) (*proc.Target, error) { func (p *gdbProcess) Listen(listener net.Listener, path string, pid int, debugInfoDirs []string, stopReason proc.StopReason) (*proc.Target, error) {
acceptChan := make(chan net.Conn) acceptChan := make(chan net.Conn)
go func() { go func() {
@ -220,7 +220,7 @@ func (p *Process) Listen(listener net.Listener, path string, pid int, debugInfoD
} }
// Dial attempts to connect to the stub. // Dial attempts to connect to the stub.
func (p *Process) Dial(addr string, path string, pid int, debugInfoDirs []string, stopReason proc.StopReason) (*proc.Target, error) { func (p *gdbProcess) Dial(addr string, path string, pid int, debugInfoDirs []string, stopReason proc.StopReason) (*proc.Target, error) {
for { for {
conn, err := net.Dial("tcp", addr) conn, err := net.Dial("tcp", addr)
if err == nil { if err == nil {
@ -241,7 +241,7 @@ func (p *Process) Dial(addr string, path string, pid int, debugInfoDirs []string
// program and the PID of the target process, both are optional, however // program and the PID of the target process, both are optional, however
// some stubs do not provide ways to determine path and pid automatically // some stubs do not provide ways to determine path and pid automatically
// and Connect will be unable to function without knowing them. // and Connect will be unable to function without knowing them.
func (p *Process) Connect(conn net.Conn, path string, pid int, debugInfoDirs []string, stopReason proc.StopReason) (*proc.Target, error) { func (p *gdbProcess) Connect(conn net.Conn, path string, pid int, debugInfoDirs []string, stopReason proc.StopReason) (*proc.Target, error) {
p.conn.conn = conn p.conn.conn = conn
p.conn.pid = pid p.conn.pid = pid
err := p.conn.handshake() err := p.conn.handshake()
@ -400,7 +400,7 @@ func LLDBLaunch(cmd []string, wd string, foreground bool, debugInfoDirs []string
return nil, err return nil, err
} }
p := New(process.Process) p := newProcess(process.Process)
p.conn.isDebugserver = isDebugserver p.conn.isDebugserver = isDebugserver
var tgt *proc.Target var tgt *proc.Target
@ -450,7 +450,7 @@ func LLDBAttach(pid int, path string, debugInfoDirs []string) (*proc.Target, err
return nil, err return nil, err
} }
p := New(process.Process) p := newProcess(process.Process)
p.conn.isDebugserver = isDebugserver p.conn.isDebugserver = isDebugserver
var tgt *proc.Target var tgt *proc.Target
@ -464,7 +464,7 @@ func LLDBAttach(pid int, path string, debugInfoDirs []string) (*proc.Target, err
// EntryPoint will return the process entry point address, useful for // EntryPoint will return the process entry point address, useful for
// debugging PIEs. // debugging PIEs.
func (p *Process) EntryPoint() (uint64, error) { func (p *gdbProcess) EntryPoint() (uint64, error) {
var entryPoint uint64 var entryPoint uint64
if auxv, err := p.conn.readAuxv(); err == nil { if auxv, err := p.conn.readAuxv(); err == nil {
// If we can't read the auxiliary vector it just means it's not supported // If we can't read the auxiliary vector it just means it's not supported
@ -478,7 +478,7 @@ func (p *Process) EntryPoint() (uint64, error) {
// initialize uses qProcessInfo to load the inferior's PID and // initialize uses qProcessInfo to load the inferior's PID and
// executable path. This command is not supported by all stubs and not all // executable path. This command is not supported by all stubs and not all
// stubs will report both the PID and executable path. // stubs will report both the PID and executable path.
func (p *Process) initialize(path string, debugInfoDirs []string, stopReason proc.StopReason) (*proc.Target, error) { func (p *gdbProcess) initialize(path string, debugInfoDirs []string, stopReason proc.StopReason) (*proc.Target, error) {
var err error var err error
if path == "" { if path == "" {
// If we are attaching to a running process and the user didn't specify // If we are attaching to a running process and the user didn't specify
@ -542,7 +542,7 @@ func (p *Process) initialize(path string, debugInfoDirs []string, stopReason pro
return tgt, nil return tgt, nil
} }
func queryProcessInfo(p *Process, pid int) (int, string, error) { func queryProcessInfo(p *gdbProcess, pid int) (int, string, error) {
pi, err := p.conn.queryProcessInfo(pid) pi, err := p.conn.queryProcessInfo(pid)
if err != nil { if err != nil {
return 0, "", err return 0, "", err
@ -555,24 +555,24 @@ func queryProcessInfo(p *Process, pid int) (int, string, error) {
} }
// BinInfo returns information on the binary. // BinInfo returns information on the binary.
func (p *Process) BinInfo() *proc.BinaryInfo { func (p *gdbProcess) BinInfo() *proc.BinaryInfo {
return p.bi return p.bi
} }
// Recorded returns whether or not we are debugging // Recorded returns whether or not we are debugging
// a recorded "traced" program. // a recorded "traced" program.
func (p *Process) Recorded() (bool, string) { func (p *gdbProcess) Recorded() (bool, string) {
return p.tracedir != "", p.tracedir return p.tracedir != "", p.tracedir
} }
// Pid returns the process ID. // Pid returns the process ID.
func (p *Process) Pid() int { func (p *gdbProcess) Pid() int {
return int(p.conn.pid) return int(p.conn.pid)
} }
// Valid returns true if we are not detached // Valid returns true if we are not detached
// and the process has not exited. // and the process has not exited.
func (p *Process) Valid() (bool, error) { func (p *gdbProcess) Valid() (bool, error) {
if p.detached { if p.detached {
return false, proc.ErrProcessDetached return false, proc.ErrProcessDetached
} }
@ -584,18 +584,18 @@ func (p *Process) Valid() (bool, error) {
// ResumeNotify specifies a channel that will be closed the next time // ResumeNotify specifies a channel that will be closed the next time
// ContinueOnce finishes resuming the target. // ContinueOnce finishes resuming the target.
func (p *Process) ResumeNotify(ch chan<- struct{}) { func (p *gdbProcess) ResumeNotify(ch chan<- struct{}) {
p.conn.resumeChan = ch p.conn.resumeChan = ch
} }
// FindThread returns the thread with the given ID. // FindThread returns the thread with the given ID.
func (p *Process) FindThread(threadID int) (proc.Thread, bool) { func (p *gdbProcess) FindThread(threadID int) (proc.Thread, bool) {
thread, ok := p.threads[threadID] thread, ok := p.threads[threadID]
return thread, ok return thread, ok
} }
// ThreadList returns all threads in the process. // ThreadList returns all threads in the process.
func (p *Process) ThreadList() []proc.Thread { func (p *gdbProcess) ThreadList() []proc.Thread {
r := make([]proc.Thread, 0, len(p.threads)) r := make([]proc.Thread, 0, len(p.threads))
for _, thread := range p.threads { for _, thread := range p.threads {
r = append(r, thread) r = append(r, thread)
@ -605,13 +605,13 @@ func (p *Process) ThreadList() []proc.Thread {
// CurrentThread returns the current active // CurrentThread returns the current active
// selected thread. // selected thread.
func (p *Process) CurrentThread() proc.Thread { func (p *gdbProcess) CurrentThread() proc.Thread {
return p.currentThread return p.currentThread
} }
// SetCurrentThread is used internally by proc.Target to change the current thread. // SetCurrentThread is used internally by proc.Target to change the current thread.
func (p *Process) SetCurrentThread(th proc.Thread) { func (p *gdbProcess) SetCurrentThread(th proc.Thread) {
p.currentThread = th.(*Thread) p.currentThread = th.(*gdbThread)
} }
const ( const (
@ -631,7 +631,7 @@ const (
// ContinueOnce will continue execution of the process until // ContinueOnce will continue execution of the process until
// a breakpoint is hit or signal is received. // a breakpoint is hit or signal is received.
func (p *Process) ContinueOnce() (proc.Thread, proc.StopReason, error) { func (p *gdbProcess) ContinueOnce() (proc.Thread, proc.StopReason, error) {
if p.exited { if p.exited {
return nil, proc.StopExited, &proc.ErrProcessExited{Pid: p.conn.pid} return nil, proc.StopExited, &proc.ErrProcessExited{Pid: p.conn.pid}
} }
@ -655,7 +655,7 @@ func (p *Process) ContinueOnce() (proc.Thread, proc.StopReason, error) {
// resume all threads // resume all threads
var threadID string var threadID string
var trapthread *Thread var trapthread *gdbThread
var tu = threadUpdater{p: p} var tu = threadUpdater{p: p}
var atstart bool var atstart bool
continueLoop: continueLoop:
@ -732,7 +732,7 @@ continueLoop:
return trapthread, stopReason, err return trapthread, stopReason, err
} }
func (p *Process) findThreadByStrID(threadID string) *Thread { func (p *gdbProcess) findThreadByStrID(threadID string) *gdbThread {
for _, thread := range p.threads { for _, thread := range p.threads {
if thread.strID == threadID { if thread.strID == threadID {
return thread return thread
@ -746,8 +746,8 @@ func (p *Process) findThreadByStrID(threadID string) *Thread {
// and returns true if we should stop execution in response to one of the // and returns true if we should stop execution in response to one of the
// signals and return control to the user. // signals and return control to the user.
// Adjusts trapthread to a thread that we actually want to stop at. // Adjusts trapthread to a thread that we actually want to stop at.
func (p *Process) handleThreadSignals(trapthread *Thread) (trapthreadOut *Thread, atstart bool, shouldStop bool) { func (p *gdbProcess) handleThreadSignals(trapthread *gdbThread) (trapthreadOut *gdbThread, atstart bool, shouldStop bool) {
var trapthreadCandidate *Thread var trapthreadCandidate *gdbThread
for _, th := range p.threads { for _, th := range p.threads {
isStopSignal := false isStopSignal := false
@ -820,7 +820,7 @@ func (p *Process) handleThreadSignals(trapthread *Thread) (trapthreadOut *Thread
// RequestManualStop will attempt to stop the process // RequestManualStop will attempt to stop the process
// without a breakpoint or signal having been recieved. // without a breakpoint or signal having been recieved.
func (p *Process) RequestManualStop() error { func (p *gdbProcess) RequestManualStop() error {
p.conn.manualStopMutex.Lock() p.conn.manualStopMutex.Lock()
p.manualStopRequested = true p.manualStopRequested = true
if !p.conn.running { if !p.conn.running {
@ -834,7 +834,7 @@ func (p *Process) RequestManualStop() error {
// CheckAndClearManualStopRequest will check for a manual // CheckAndClearManualStopRequest will check for a manual
// stop and then clear that state. // stop and then clear that state.
func (p *Process) CheckAndClearManualStopRequest() bool { func (p *gdbProcess) CheckAndClearManualStopRequest() bool {
p.conn.manualStopMutex.Lock() p.conn.manualStopMutex.Lock()
msr := p.manualStopRequested msr := p.manualStopRequested
p.manualStopRequested = false p.manualStopRequested = false
@ -842,20 +842,20 @@ func (p *Process) CheckAndClearManualStopRequest() bool {
return msr return msr
} }
func (p *Process) getManualStopRequested() bool { func (p *gdbProcess) getManualStopRequested() bool {
p.conn.manualStopMutex.Lock() p.conn.manualStopMutex.Lock()
msr := p.manualStopRequested msr := p.manualStopRequested
p.conn.manualStopMutex.Unlock() p.conn.manualStopMutex.Unlock()
return msr return msr
} }
func (p *Process) setCtrlC(v bool) { func (p *gdbProcess) setCtrlC(v bool) {
p.conn.manualStopMutex.Lock() p.conn.manualStopMutex.Lock()
p.ctrlC = v p.ctrlC = v
p.conn.manualStopMutex.Unlock() p.conn.manualStopMutex.Unlock()
} }
func (p *Process) getCtrlC() bool { func (p *gdbProcess) getCtrlC() bool {
p.conn.manualStopMutex.Lock() p.conn.manualStopMutex.Lock()
defer p.conn.manualStopMutex.Unlock() defer p.conn.manualStopMutex.Unlock()
return p.ctrlC return p.ctrlC
@ -863,7 +863,7 @@ func (p *Process) getCtrlC() bool {
// Detach will detach from the target process, // Detach will detach from the target process,
// if 'kill' is true it will also kill the process. // if 'kill' is true it will also kill the process.
func (p *Process) Detach(kill bool) error { func (p *gdbProcess) Detach(kill bool) error {
if kill && !p.exited { if kill && !p.exited {
err := p.conn.kill() err := p.conn.kill()
if err != nil { if err != nil {
@ -891,7 +891,7 @@ func (p *Process) Detach(kill bool) error {
} }
// Restart will restart the process from the given position. // Restart will restart the process from the given position.
func (p *Process) Restart(pos string) error { func (p *gdbProcess) Restart(pos string) error {
if p.tracedir == "" { if p.tracedir == "" {
return proc.ErrNotRecorded return proc.ErrNotRecorded
} }
@ -932,7 +932,7 @@ func (p *Process) Restart(pos string) error {
// When executes the 'when' command for the Mozilla RR backend. // When executes the 'when' command for the Mozilla RR backend.
// This command will return rr's internal event number. // This command will return rr's internal event number.
func (p *Process) When() (string, error) { func (p *gdbProcess) When() (string, error) {
if p.tracedir == "" { if p.tracedir == "" {
return "", proc.ErrNotRecorded return "", proc.ErrNotRecorded
} }
@ -948,7 +948,7 @@ const (
) )
// Checkpoint creates a checkpoint from which you can restart the program. // Checkpoint creates a checkpoint from which you can restart the program.
func (p *Process) Checkpoint(where string) (int, error) { func (p *gdbProcess) Checkpoint(where string) (int, error) {
if p.tracedir == "" { if p.tracedir == "" {
return -1, proc.ErrNotRecorded return -1, proc.ErrNotRecorded
} }
@ -976,7 +976,7 @@ func (p *Process) Checkpoint(where string) (int, error) {
} }
// Checkpoints returns a list of all checkpoints set. // Checkpoints returns a list of all checkpoints set.
func (p *Process) Checkpoints() ([]proc.Checkpoint, error) { func (p *gdbProcess) Checkpoints() ([]proc.Checkpoint, error) {
if p.tracedir == "" { if p.tracedir == "" {
return nil, proc.ErrNotRecorded return nil, proc.ErrNotRecorded
} }
@ -1006,7 +1006,7 @@ func (p *Process) Checkpoints() ([]proc.Checkpoint, error) {
const deleteCheckpointPrefix = "Deleted checkpoint " const deleteCheckpointPrefix = "Deleted checkpoint "
// ClearCheckpoint clears the checkpoint for the given ID. // ClearCheckpoint clears the checkpoint for the given ID.
func (p *Process) ClearCheckpoint(id int) error { func (p *gdbProcess) ClearCheckpoint(id int) error {
if p.tracedir == "" { if p.tracedir == "" {
return proc.ErrNotRecorded return proc.ErrNotRecorded
} }
@ -1021,7 +1021,7 @@ func (p *Process) ClearCheckpoint(id int) error {
} }
// ChangeDirection sets whether to run the program forwards or in reverse execution. // ChangeDirection sets whether to run the program forwards or in reverse execution.
func (p *Process) ChangeDirection(dir proc.Direction) error { func (p *gdbProcess) ChangeDirection(dir proc.Direction) error {
if p.tracedir == "" { if p.tracedir == "" {
if dir != proc.Forward { if dir != proc.Forward {
return proc.ErrNotRecorded return proc.ErrNotRecorded
@ -1042,17 +1042,17 @@ func (p *Process) ChangeDirection(dir proc.Direction) error {
} }
// GetDirection returns the current direction of execution. // GetDirection returns the current direction of execution.
func (p *Process) GetDirection() proc.Direction { func (p *gdbProcess) GetDirection() proc.Direction {
return p.conn.direction return p.conn.direction
} }
// Breakpoints returns the list of breakpoints currently set. // Breakpoints returns the list of breakpoints currently set.
func (p *Process) Breakpoints() *proc.BreakpointMap { func (p *gdbProcess) Breakpoints() *proc.BreakpointMap {
return &p.breakpoints return &p.breakpoints
} }
// FindBreakpoint returns the breakpoint at the given address. // FindBreakpoint returns the breakpoint at the given address.
func (p *Process) FindBreakpoint(pc uint64) (*proc.Breakpoint, bool) { func (p *gdbProcess) FindBreakpoint(pc uint64) (*proc.Breakpoint, bool) {
// Directly use addr to lookup breakpoint. // Directly use addr to lookup breakpoint.
if bp, ok := p.breakpoints.M[pc]; ok { if bp, ok := p.breakpoints.M[pc]; ok {
return bp, true return bp, true
@ -1060,7 +1060,7 @@ func (p *Process) FindBreakpoint(pc uint64) (*proc.Breakpoint, bool) {
return nil, false return nil, false
} }
func (p *Process) writeBreakpoint(addr uint64) (string, int, *proc.Function, []byte, error) { func (p *gdbProcess) writeBreakpoint(addr uint64) (string, int, *proc.Function, []byte, error) {
f, l, fn := p.bi.PCToLine(uint64(addr)) f, l, fn := p.bi.PCToLine(uint64(addr))
if err := p.conn.setBreakpoint(addr); err != nil { if err := p.conn.setBreakpoint(addr); err != nil {
@ -1071,7 +1071,7 @@ func (p *Process) writeBreakpoint(addr uint64) (string, int, *proc.Function, []b
} }
// SetBreakpoint creates a new breakpoint. // SetBreakpoint creates a new breakpoint.
func (p *Process) SetBreakpoint(addr uint64, kind proc.BreakpointKind, cond ast.Expr) (*proc.Breakpoint, error) { func (p *gdbProcess) SetBreakpoint(addr uint64, kind proc.BreakpointKind, cond ast.Expr) (*proc.Breakpoint, error) {
if p.exited { if p.exited {
return nil, &proc.ErrProcessExited{Pid: p.conn.pid} return nil, &proc.ErrProcessExited{Pid: p.conn.pid}
} }
@ -1079,7 +1079,7 @@ func (p *Process) SetBreakpoint(addr uint64, kind proc.BreakpointKind, cond ast.
} }
// ClearBreakpoint clears a breakpoint at the given address. // ClearBreakpoint clears a breakpoint at the given address.
func (p *Process) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) { func (p *gdbProcess) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) {
if p.exited { if p.exited {
return nil, &proc.ErrProcessExited{Pid: p.conn.pid} return nil, &proc.ErrProcessExited{Pid: p.conn.pid}
} }
@ -1089,7 +1089,7 @@ func (p *Process) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) {
} }
// ClearInternalBreakpoints clear all internal use breakpoints like those set by 'next'. // ClearInternalBreakpoints clear all internal use breakpoints like those set by 'next'.
func (p *Process) ClearInternalBreakpoints() error { func (p *gdbProcess) ClearInternalBreakpoints() error {
return p.breakpoints.ClearInternalBreakpoints(func(bp *proc.Breakpoint) error { return p.breakpoints.ClearInternalBreakpoints(func(bp *proc.Breakpoint) error {
if err := p.conn.clearBreakpoint(bp.Addr); err != nil { if err := p.conn.clearBreakpoint(bp.Addr); err != nil {
return err return err
@ -1104,7 +1104,7 @@ func (p *Process) ClearInternalBreakpoints() error {
} }
type threadUpdater struct { type threadUpdater struct {
p *Process p *gdbProcess
seen map[int]bool seen map[int]bool
done bool done bool
} }
@ -1133,7 +1133,7 @@ func (tu *threadUpdater) Add(threads []string) error {
tid := int(n) tid := int(n)
tu.seen[tid] = true tu.seen[tid] = true
if _, found := tu.p.threads[tid]; !found { if _, found := tu.p.threads[tid]; !found {
tu.p.threads[tid] = &Thread{ID: tid, strID: threadID, p: tu.p} tu.p.threads[tid] = &gdbThread{ID: tid, strID: threadID, p: tu.p}
} }
} }
return nil return nil
@ -1170,7 +1170,7 @@ func (tu *threadUpdater) Finish() {
// Some stubs will return the list of running threads in the stop packet, if // Some stubs will return the list of running threads in the stop packet, if
// this happens the threadUpdater will know that we have already updated the // this happens the threadUpdater will know that we have already updated the
// thread list and the first step of updateThreadList will be skipped. // thread list and the first step of updateThreadList will be skipped.
func (p *Process) updateThreadList(tu *threadUpdater) error { func (p *gdbProcess) updateThreadList(tu *threadUpdater) error {
if !tu.done { if !tu.done {
first := true first := true
for { for {
@ -1211,19 +1211,19 @@ func (p *Process) updateThreadList(tu *threadUpdater) error {
} }
// clearThreadRegisters clears the memoized thread register state. // clearThreadRegisters clears the memoized thread register state.
func (p *Process) clearThreadRegisters() { func (p *gdbProcess) clearThreadRegisters() {
for _, thread := range p.threads { for _, thread := range p.threads {
thread.regs.regs = nil thread.regs.regs = nil
} }
} }
func (p *Process) clearThreadSignals() { func (p *gdbProcess) clearThreadSignals() {
for _, th := range p.threads { for _, th := range p.threads {
th.sig = 0 th.sig = 0
} }
} }
func (p *Process) setCurrentBreakpoints() error { func (p *gdbProcess) setCurrentBreakpoints() error {
if p.threadStopInfo { if p.threadStopInfo {
for _, th := range p.threads { for _, th := range p.threads {
if th.setbp { if th.setbp {
@ -1248,7 +1248,7 @@ func (p *Process) setCurrentBreakpoints() error {
} }
// ReadMemory will read into 'data' memory at the address provided. // ReadMemory will read into 'data' memory at the address provided.
func (t *Thread) ReadMemory(data []byte, addr uintptr) (n int, err error) { func (t *gdbThread) ReadMemory(data []byte, addr uintptr) (n int, err error) {
err = t.p.conn.readMemory(data, addr) err = t.p.conn.readMemory(data, addr)
if err != nil { if err != nil {
return 0, err return 0, err
@ -1257,12 +1257,12 @@ func (t *Thread) ReadMemory(data []byte, addr uintptr) (n int, err error) {
} }
// WriteMemory will write into the memory at 'addr' the data provided. // WriteMemory will write into the memory at 'addr' the data provided.
func (t *Thread) WriteMemory(addr uintptr, data []byte) (written int, err error) { func (t *gdbThread) WriteMemory(addr uintptr, data []byte) (written int, err error) {
return t.p.conn.writeMemory(addr, data) return t.p.conn.writeMemory(addr, data)
} }
// Location returns the current location of this thread. // Location returns the current location of this thread.
func (t *Thread) Location() (*proc.Location, error) { func (t *gdbThread) Location() (*proc.Location, error) {
regs, err := t.Registers(false) regs, err := t.Registers(false)
if err != nil { if err != nil {
return nil, err return nil, err
@ -1278,17 +1278,17 @@ func (t *Thread) Location() (*proc.Location, error) {
} }
// Breakpoint returns the current active breakpoint for this thread. // Breakpoint returns the current active breakpoint for this thread.
func (t *Thread) Breakpoint() *proc.BreakpointState { func (t *gdbThread) Breakpoint() *proc.BreakpointState {
return &t.CurrentBreakpoint return &t.CurrentBreakpoint
} }
// ThreadID returns this threads ID. // ThreadID returns this threads ID.
func (t *Thread) ThreadID() int { func (t *gdbThread) ThreadID() int {
return t.ID return t.ID
} }
// Registers returns the CPU registers for this thread. // Registers returns the CPU registers for this thread.
func (t *Thread) Registers(floatingPoint bool) (proc.Registers, error) { func (t *gdbThread) Registers(floatingPoint bool) (proc.Registers, error) {
if t.regs.regs == nil { if t.regs.regs == nil {
if err := t.reloadRegisters(); err != nil { if err := t.reloadRegisters(); err != nil {
return nil, err return nil, err
@ -1298,22 +1298,22 @@ func (t *Thread) Registers(floatingPoint bool) (proc.Registers, error) {
} }
// RestoreRegisters will set the CPU registers the value of those provided. // RestoreRegisters will set the CPU registers the value of those provided.
func (t *Thread) RestoreRegisters(savedRegs proc.Registers) error { func (t *gdbThread) RestoreRegisters(savedRegs proc.Registers) error {
copy(t.regs.buf, savedRegs.(*gdbRegisters).buf) copy(t.regs.buf, savedRegs.(*gdbRegisters).buf)
return t.writeRegisters() return t.writeRegisters()
} }
// BinInfo will return information on the binary being debugged. // BinInfo will return information on the binary being debugged.
func (t *Thread) BinInfo() *proc.BinaryInfo { func (t *gdbThread) BinInfo() *proc.BinaryInfo {
return t.p.bi return t.p.bi
} }
// Common returns common information across Process implementations. // Common returns common information across Process implementations.
func (t *Thread) Common() *proc.CommonThread { func (t *gdbThread) Common() *proc.CommonThread {
return &t.common return &t.common
} }
func (t *Thread) stepInstruction(tu *threadUpdater) error { func (t *gdbThread) stepInstruction(tu *threadUpdater) error {
pc := t.regs.PC() pc := t.regs.PC()
if _, atbp := t.p.breakpoints.M[pc]; atbp { if _, atbp := t.p.breakpoints.M[pc]; atbp {
err := t.p.conn.clearBreakpoint(pc) err := t.p.conn.clearBreakpoint(pc)
@ -1329,12 +1329,12 @@ func (t *Thread) stepInstruction(tu *threadUpdater) error {
} }
// StepInstruction will step exactly 1 CPU instruction. // StepInstruction will step exactly 1 CPU instruction.
func (t *Thread) StepInstruction() error { func (t *gdbThread) StepInstruction() error {
return t.stepInstruction(&threadUpdater{p: t.p}) return t.stepInstruction(&threadUpdater{p: t.p})
} }
// Blocked returns true if the thread is blocked in runtime or kernel code. // Blocked returns true if the thread is blocked in runtime or kernel code.
func (t *Thread) Blocked() bool { func (t *gdbThread) Blocked() bool {
regs, err := t.Registers(false) regs, err := t.Registers(false)
if err != nil { if err != nil {
return false return false
@ -1362,7 +1362,7 @@ func (t *Thread) Blocked() bool {
// loadGInstr returns the correct MOV instruction for the current // loadGInstr returns the correct MOV instruction for the current
// OS/architecture that can be executed to load the address of G from an // OS/architecture that can be executed to load the address of G from an
// inferior's thread. // inferior's thread.
func (p *Process) loadGInstr() []byte { func (p *gdbProcess) loadGInstr() []byte {
var op []byte var op []byte
switch p.bi.GOOS { switch p.bi.GOOS {
case "windows", "darwin", "freebsd": case "windows", "darwin", "freebsd":
@ -1400,7 +1400,7 @@ func (regs *gdbRegisters) init(regsInfo []gdbRegisterInfo) {
// It will also load the address of the thread's G. // It will also load the address of the thread's G.
// Loading the address of G can be done in one of two ways reloadGAlloc, if // Loading the address of G can be done in one of two ways reloadGAlloc, if
// the stub can allocate memory, or reloadGAtPC, if the stub can't. // the stub can allocate memory, or reloadGAtPC, if the stub can't.
func (t *Thread) reloadRegisters() error { func (t *gdbThread) reloadRegisters() error {
if t.regs.regs == nil { if t.regs.regs == nil {
t.regs.init(t.p.conn.regsInfo) t.regs.init(t.p.conn.regsInfo)
} }
@ -1438,7 +1438,7 @@ func (t *Thread) reloadRegisters() error {
return t.reloadGAtPC() return t.reloadGAtPC()
} }
func (t *Thread) writeSomeRegisters(regNames ...string) error { func (t *gdbThread) writeSomeRegisters(regNames ...string) error {
if t.p.gcmdok { if t.p.gcmdok {
return t.p.conn.writeRegisters(t.strID, t.regs.buf) return t.p.conn.writeRegisters(t.strID, t.regs.buf)
} }
@ -1450,7 +1450,7 @@ func (t *Thread) writeSomeRegisters(regNames ...string) error {
return nil return nil
} }
func (t *Thread) writeRegisters() error { func (t *gdbThread) writeRegisters() error {
if t.p.gcmdok { if t.p.gcmdok {
return t.p.conn.writeRegisters(t.strID, t.regs.buf) return t.p.conn.writeRegisters(t.strID, t.regs.buf)
} }
@ -1462,7 +1462,7 @@ func (t *Thread) writeRegisters() error {
return nil return nil
} }
func (t *Thread) readSomeRegisters(regNames ...string) error { func (t *gdbThread) readSomeRegisters(regNames ...string) error {
if t.p.gcmdok { if t.p.gcmdok {
return t.p.conn.readRegisters(t.strID, t.regs.buf) return t.p.conn.readRegisters(t.strID, t.regs.buf)
} }
@ -1478,7 +1478,7 @@ func (t *Thread) readSomeRegisters(regNames ...string) error {
// reloadGAtPC overwrites the instruction that the thread is stopped at with // reloadGAtPC overwrites the instruction that the thread is stopped at with
// the MOV instruction used to load current G, executes this single // the MOV instruction used to load current G, executes this single
// instruction and then puts everything back the way it was. // instruction and then puts everything back the way it was.
func (t *Thread) reloadGAtPC() error { func (t *gdbThread) reloadGAtPC() error {
movinstr := t.p.loadGInstr() movinstr := t.p.loadGInstr()
if t.Blocked() { if t.Blocked() {
@ -1558,7 +1558,7 @@ func (t *Thread) reloadGAtPC() error {
// t.p.loadGInstrAddr must point to valid memory on the inferior, containing // t.p.loadGInstrAddr must point to valid memory on the inferior, containing
// a MOV instruction that loads the address of the current G in the RCX // a MOV instruction that loads the address of the current G in the RCX
// register. // register.
func (t *Thread) reloadGAlloc() error { func (t *gdbThread) reloadGAlloc() error {
if t.Blocked() { if t.Blocked() {
t.regs.tls = 0 t.regs.tls = 0
t.regs.gaddr = 0 t.regs.gaddr = 0
@ -1606,13 +1606,13 @@ func (t *Thread) reloadGAlloc() error {
return err return err
} }
func (t *Thread) clearBreakpointState() { func (t *gdbThread) clearBreakpointState() {
t.setbp = false t.setbp = false
t.CurrentBreakpoint.Clear() t.CurrentBreakpoint.Clear()
} }
// SetCurrentBreakpoint will find and set the threads current breakpoint. // SetCurrentBreakpoint will find and set the threads current breakpoint.
func (t *Thread) SetCurrentBreakpoint(adjustPC bool) error { func (t *gdbThread) SetCurrentBreakpoint(adjustPC bool) error {
// adjustPC is ignored, it is the stub's responsibiility to set the PC // adjustPC is ignored, it is the stub's responsibiility to set the PC
// address correctly after hitting a breakpoint. // address correctly after hitting a breakpoint.
t.clearBreakpointState() t.clearBreakpointState()
@ -1843,7 +1843,7 @@ func (regs *gdbRegisters) Get(n int) (uint64, error) {
} }
// SetPC will set the value of the PC register to the given value. // SetPC will set the value of the PC register to the given value.
func (t *Thread) SetPC(pc uint64) error { func (t *gdbThread) SetPC(pc uint64) error {
t.regs.setPC(pc) t.regs.setPC(pc)
if t.p.gcmdok { if t.p.gcmdok {
return t.p.conn.writeRegisters(t.strID, t.regs.buf) return t.p.conn.writeRegisters(t.strID, t.regs.buf)
@ -1853,7 +1853,7 @@ func (t *Thread) SetPC(pc uint64) error {
} }
// SetSP will set the value of the SP register to the given value. // SetSP will set the value of the SP register to the given value.
func (t *Thread) SetSP(sp uint64) error { func (t *gdbThread) SetSP(sp uint64) error {
t.regs.setSP(sp) t.regs.setSP(sp)
if t.p.gcmdok { if t.p.gcmdok {
return t.p.conn.writeRegisters(t.strID, t.regs.buf) return t.p.conn.writeRegisters(t.strID, t.regs.buf)
@ -1863,7 +1863,7 @@ func (t *Thread) SetSP(sp uint64) error {
} }
// SetDX will set the value of the DX register to the given value. // SetDX will set the value of the DX register to the given value.
func (t *Thread) SetDX(dx uint64) error { func (t *gdbThread) SetDX(dx uint64) error {
t.regs.setDX(dx) t.regs.setDX(dx)
if t.p.gcmdok { if t.p.gcmdok {
return t.p.conn.writeRegisters(t.strID, t.regs.buf) return t.p.conn.writeRegisters(t.strID, t.regs.buf)

@ -545,7 +545,7 @@ func (conn *gdbConn) writeRegister(threadID string, regnum int, data []byte) err
// resume each thread. If a thread has sig == 0 the 'c' action will be used, // resume each thread. If a thread has sig == 0 the 'c' action will be used,
// otherwise the 'C' action will be used and the value of sig will be passed // otherwise the 'C' action will be used and the value of sig will be passed
// to it. // to it.
func (conn *gdbConn) resume(threads map[int]*Thread, tu *threadUpdater) (string, uint8, error) { func (conn *gdbConn) resume(threads map[int]*gdbThread, tu *threadUpdater) (string, uint8, error) {
if conn.direction == proc.Forward { if conn.direction == proc.Forward {
conn.outbuf.Reset() conn.outbuf.Reset()
fmt.Fprintf(&conn.outbuf, "$vCont") fmt.Fprintf(&conn.outbuf, "$vCont")

@ -104,7 +104,7 @@ func Replay(tracedir string, quiet, deleteOnDetach bool, debugInfoDirs []string)
return nil, init.err return nil, init.err
} }
p := New(rrcmd.Process) p := newProcess(rrcmd.Process)
p.tracedir = tracedir p.tracedir = tracedir
if deleteOnDetach { if deleteOnDetach {
p.onDetach = func() { p.onDetach = func() {

@ -21,15 +21,15 @@ func Attach(pid int, _ []string) (*proc.Target, error) {
return nil, ErrNativeBackendDisabled return nil, ErrNativeBackendDisabled
} }
// WaitStatus is a synonym for the platform-specific WaitStatus // waitStatus is a synonym for the platform-specific WaitStatus
type WaitStatus struct{} type waitStatus struct{}
// OSSpecificDetails holds information specific to the OSX/Darwin // osSpecificDetails holds information specific to the OSX/Darwin
// operating system / kernel. // operating system / kernel.
type OSSpecificDetails struct{} type osSpecificDetails struct{}
// OSProcessDetails holds Darwin specific information. // osProcessDetails holds Darwin specific information.
type OSProcessDetails struct{} type osProcessDetails struct{}
func findExecutable(path string, pid int) string { func findExecutable(path string, pid int) string {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
@ -39,94 +39,94 @@ func killProcess(pid int) error {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) { func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error) {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
func (dbp *Process) loadProcessInformation(wg *sync.WaitGroup) { func (dbp *nativeProcess) loadProcessInformation(wg *sync.WaitGroup) {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
func (dbp *Process) requestManualStop() (err error) { func (dbp *nativeProcess) requestManualStop() (err error) {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
func (dbp *Process) resume() error { func (dbp *nativeProcess) resume() error {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
func (dbp *Process) trapWait(pid int) (*Thread, error) { func (dbp *nativeProcess) trapWait(pid int) (*nativeThread, error) {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
func (dbp *Process) stop(trapthread *Thread) (err error) { func (dbp *nativeProcess) stop(trapthread *nativeThread) (err error) {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
func (dbp *Process) updateThreadList() error { func (dbp *nativeProcess) updateThreadList() error {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
func (dbp *Process) kill() (err error) { func (dbp *nativeProcess) kill() (err error) {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
func (dbp *Process) detach(kill bool) error { func (dbp *nativeProcess) detach(kill bool) error {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
// EntryPoint returns the entry point for the process, // EntryPoint returns the entry point for the process,
// useful for PIEs. // useful for PIEs.
func (dbp *Process) EntryPoint() (uint64, error) { func (dbp *nativeProcess) EntryPoint() (uint64, error) {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
// Blocked returns true if the thread is blocked // Blocked returns true if the thread is blocked
func (t *Thread) Blocked() bool { func (t *nativeThread) Blocked() bool {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
// SetPC sets the value of the PC register. // SetPC sets the value of the PC register.
func (t *Thread) SetPC(pc uint64) error { func (t *nativeThread) SetPC(pc uint64) error {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
// SetSP sets the value of the SP register. // SetSP sets the value of the SP register.
func (t *Thread) SetSP(sp uint64) error { func (t *nativeThread) SetSP(sp uint64) error {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
// SetDX sets the value of the DX register. // SetDX sets the value of the DX register.
func (t *Thread) SetDX(dx uint64) error { func (t *nativeThread) SetDX(dx uint64) error {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
// ReadMemory reads len(buf) bytes at addr into buf. // ReadMemory reads len(buf) bytes at addr into buf.
func (t *Thread) ReadMemory(buf []byte, addr uintptr) (int, error) { func (t *nativeThread) ReadMemory(buf []byte, addr uintptr) (int, error) {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
// WriteMemory writes the contents of data at addr. // WriteMemory writes the contents of data at addr.
func (t *Thread) WriteMemory(addr uintptr, data []byte) (int, error) { func (t *nativeThread) WriteMemory(addr uintptr, data []byte) (int, error) {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
func (t *Thread) resume() error { func (t *nativeThread) resume() error {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
func (t *Thread) singleStep() error { func (t *nativeThread) singleStep() error {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
func (t *Thread) restoreRegisters(sr proc.Registers) error { func (t *nativeThread) restoreRegisters(sr proc.Registers) error {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
// Stopped returns whether the thread is stopped at // Stopped returns whether the thread is stopped at
// the operating system level. // the operating system level.
func (t *Thread) Stopped() bool { func (t *nativeThread) Stopped() bool {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
func initialize(dbp *Process) error { return nil } func initialize(dbp *nativeProcess) error { return nil }

@ -10,7 +10,7 @@ import (
// Process represents all of the information the debugger // Process represents all of the information the debugger
// is holding onto regarding the process we are debugging. // is holding onto regarding the process we are debugging.
type Process struct { type nativeProcess struct {
bi *proc.BinaryInfo bi *proc.BinaryInfo
pid int // Process Pid pid int // Process Pid
@ -20,12 +20,12 @@ type Process struct {
breakpoints proc.BreakpointMap breakpoints proc.BreakpointMap
// List of threads mapped as such: pid -> *Thread // List of threads mapped as such: pid -> *Thread
threads map[int]*Thread threads map[int]*nativeThread
// Active thread // Active thread
currentThread *Thread currentThread *nativeThread
os *OSProcessDetails os *osProcessDetails
firstStart bool firstStart bool
stopMu sync.Mutex stopMu sync.Mutex
resumeChan chan<- struct{} resumeChan chan<- struct{}
@ -37,19 +37,19 @@ type Process struct {
exited, detached bool exited, detached bool
} }
var _ proc.ProcessInternal = &Process{} var _ proc.ProcessInternal = &nativeProcess{}
// New returns an initialized Process struct. Before returning, // newProcess returns an initialized Process struct. Before returning,
// it will also launch a goroutine in order to handle ptrace(2) // it will also launch a goroutine in order to handle ptrace(2)
// functions. For more information, see the documentation on // functions. For more information, see the documentation on
// `handlePtraceFuncs`. // `handlePtraceFuncs`.
func New(pid int) *Process { func newProcess(pid int) *nativeProcess {
dbp := &Process{ dbp := &nativeProcess{
pid: pid, pid: pid,
threads: make(map[int]*Thread), threads: make(map[int]*nativeThread),
breakpoints: proc.NewBreakpointMap(), breakpoints: proc.NewBreakpointMap(),
firstStart: true, firstStart: true,
os: new(OSProcessDetails), os: new(osProcessDetails),
ptraceChan: make(chan func()), ptraceChan: make(chan func()),
ptraceDoneChan: make(chan interface{}), ptraceDoneChan: make(chan interface{}),
bi: proc.NewBinaryInfo(runtime.GOOS, runtime.GOARCH), bi: proc.NewBinaryInfo(runtime.GOOS, runtime.GOARCH),
@ -59,20 +59,20 @@ func New(pid int) *Process {
} }
// BinInfo will return the binary info struct associated with this process. // BinInfo will return the binary info struct associated with this process.
func (dbp *Process) BinInfo() *proc.BinaryInfo { func (dbp *nativeProcess) BinInfo() *proc.BinaryInfo {
return dbp.bi return dbp.bi
} }
// Recorded always returns false for the native proc backend. // Recorded always returns false for the native proc backend.
func (dbp *Process) Recorded() (bool, string) { return false, "" } func (dbp *nativeProcess) Recorded() (bool, string) { return false, "" }
// Restart will always return an error in the native proc backend, only for // Restart will always return an error in the native proc backend, only for
// recorded traces. // recorded traces.
func (dbp *Process) Restart(string) error { return proc.ErrNotRecorded } func (dbp *nativeProcess) Restart(string) error { return proc.ErrNotRecorded }
// ChangeDirection will always return an error in the native proc backend, only for // ChangeDirection will always return an error in the native proc backend, only for
// recorded traces. // recorded traces.
func (dbp *Process) ChangeDirection(dir proc.Direction) error { func (dbp *nativeProcess) ChangeDirection(dir proc.Direction) error {
if dir != proc.Forward { if dir != proc.Forward {
return proc.ErrNotRecorded return proc.ErrNotRecorded
} }
@ -80,25 +80,25 @@ func (dbp *Process) ChangeDirection(dir proc.Direction) error {
} }
// GetDirection will always return Forward. // GetDirection will always return Forward.
func (p *Process) GetDirection() proc.Direction { return proc.Forward } func (p *nativeProcess) GetDirection() proc.Direction { return proc.Forward }
// When will always return an empty string and nil, not supported on native proc backend. // When will always return an empty string and nil, not supported on native proc backend.
func (dbp *Process) When() (string, error) { return "", nil } func (dbp *nativeProcess) When() (string, error) { return "", nil }
// Checkpoint will always return an error on the native proc backend, // Checkpoint will always return an error on the native proc backend,
// only supported for recorded traces. // only supported for recorded traces.
func (dbp *Process) Checkpoint(string) (int, error) { return -1, proc.ErrNotRecorded } func (dbp *nativeProcess) Checkpoint(string) (int, error) { return -1, proc.ErrNotRecorded }
// Checkpoints will always return an error on the native proc backend, // Checkpoints will always return an error on the native proc backend,
// only supported for recorded traces. // only supported for recorded traces.
func (dbp *Process) Checkpoints() ([]proc.Checkpoint, error) { return nil, proc.ErrNotRecorded } func (dbp *nativeProcess) Checkpoints() ([]proc.Checkpoint, error) { return nil, proc.ErrNotRecorded }
// ClearCheckpoint will always return an error on the native proc backend, // ClearCheckpoint will always return an error on the native proc backend,
// only supported in recorded traces. // only supported in recorded traces.
func (dbp *Process) ClearCheckpoint(int) error { return proc.ErrNotRecorded } func (dbp *nativeProcess) ClearCheckpoint(int) error { return proc.ErrNotRecorded }
// Detach from the process being debugged, optionally killing it. // Detach from the process being debugged, optionally killing it.
func (dbp *Process) Detach(kill bool) (err error) { func (dbp *nativeProcess) Detach(kill bool) (err error) {
if dbp.exited { if dbp.exited {
return nil return nil
} }
@ -135,7 +135,7 @@ func (dbp *Process) Detach(kill bool) (err error) {
// Valid returns whether the process is still attached to and // Valid returns whether the process is still attached to and
// has not exited. // has not exited.
func (dbp *Process) Valid() (bool, error) { func (dbp *nativeProcess) Valid() (bool, error) {
if dbp.detached { if dbp.detached {
return false, proc.ErrProcessDetached return false, proc.ErrProcessDetached
} }
@ -147,17 +147,17 @@ func (dbp *Process) Valid() (bool, error) {
// ResumeNotify specifies a channel that will be closed the next time // ResumeNotify specifies a channel that will be closed the next time
// ContinueOnce finishes resuming the target. // ContinueOnce finishes resuming the target.
func (dbp *Process) ResumeNotify(ch chan<- struct{}) { func (dbp *nativeProcess) ResumeNotify(ch chan<- struct{}) {
dbp.resumeChan = ch dbp.resumeChan = ch
} }
// Pid returns the process ID. // Pid returns the process ID.
func (dbp *Process) Pid() int { func (dbp *nativeProcess) Pid() int {
return dbp.pid return dbp.pid
} }
// ThreadList returns a list of threads in the process. // ThreadList returns a list of threads in the process.
func (dbp *Process) ThreadList() []proc.Thread { func (dbp *nativeProcess) ThreadList() []proc.Thread {
r := make([]proc.Thread, 0, len(dbp.threads)) r := make([]proc.Thread, 0, len(dbp.threads))
for _, v := range dbp.threads { for _, v := range dbp.threads {
r = append(r, v) r = append(r, v)
@ -166,29 +166,29 @@ func (dbp *Process) ThreadList() []proc.Thread {
} }
// FindThread attempts to find the thread with the specified ID. // FindThread attempts to find the thread with the specified ID.
func (dbp *Process) FindThread(threadID int) (proc.Thread, bool) { func (dbp *nativeProcess) FindThread(threadID int) (proc.Thread, bool) {
th, ok := dbp.threads[threadID] th, ok := dbp.threads[threadID]
return th, ok return th, ok
} }
// CurrentThread returns the current selected, active thread. // CurrentThread returns the current selected, active thread.
func (dbp *Process) CurrentThread() proc.Thread { func (dbp *nativeProcess) CurrentThread() proc.Thread {
return dbp.currentThread return dbp.currentThread
} }
// SetCurrentThread is used internally by proc.Target to change the current thread. // SetCurrentThread is used internally by proc.Target to change the current thread.
func (p *Process) SetCurrentThread(th proc.Thread) { func (p *nativeProcess) SetCurrentThread(th proc.Thread) {
p.currentThread = th.(*Thread) p.currentThread = th.(*nativeThread)
} }
// Breakpoints returns a list of breakpoints currently set. // Breakpoints returns a list of breakpoints currently set.
func (dbp *Process) Breakpoints() *proc.BreakpointMap { func (dbp *nativeProcess) Breakpoints() *proc.BreakpointMap {
return &dbp.breakpoints return &dbp.breakpoints
} }
// RequestManualStop sets the `halt` flag and // RequestManualStop sets the `halt` flag and
// sends SIGSTOP to all threads. // sends SIGSTOP to all threads.
func (dbp *Process) RequestManualStop() error { func (dbp *nativeProcess) RequestManualStop() error {
if dbp.exited { if dbp.exited {
return &proc.ErrProcessExited{Pid: dbp.Pid()} return &proc.ErrProcessExited{Pid: dbp.Pid()}
} }
@ -200,7 +200,7 @@ func (dbp *Process) RequestManualStop() error {
// CheckAndClearManualStopRequest checks if a manual stop has // CheckAndClearManualStopRequest checks if a manual stop has
// been requested, and then clears that state. // been requested, and then clears that state.
func (dbp *Process) CheckAndClearManualStopRequest() bool { func (dbp *nativeProcess) CheckAndClearManualStopRequest() bool {
dbp.stopMu.Lock() dbp.stopMu.Lock()
defer dbp.stopMu.Unlock() defer dbp.stopMu.Unlock()
@ -210,7 +210,7 @@ func (dbp *Process) CheckAndClearManualStopRequest() bool {
return msr return msr
} }
func (dbp *Process) writeBreakpoint(addr uint64) (string, int, *proc.Function, []byte, error) { func (dbp *nativeProcess) writeBreakpoint(addr uint64) (string, int, *proc.Function, []byte, error) {
f, l, fn := dbp.bi.PCToLine(uint64(addr)) f, l, fn := dbp.bi.PCToLine(uint64(addr))
originalData := make([]byte, dbp.bi.Arch.BreakpointSize()) originalData := make([]byte, dbp.bi.Arch.BreakpointSize())
@ -227,12 +227,12 @@ func (dbp *Process) writeBreakpoint(addr uint64) (string, int, *proc.Function, [
// SetBreakpoint sets a breakpoint at addr, and stores it in the process wide // SetBreakpoint sets a breakpoint at addr, and stores it in the process wide
// break point table. // break point table.
func (dbp *Process) SetBreakpoint(addr uint64, kind proc.BreakpointKind, cond ast.Expr) (*proc.Breakpoint, error) { func (dbp *nativeProcess) SetBreakpoint(addr uint64, kind proc.BreakpointKind, cond ast.Expr) (*proc.Breakpoint, error) {
return dbp.breakpoints.Set(addr, kind, cond, dbp.writeBreakpoint) return dbp.breakpoints.Set(addr, kind, cond, dbp.writeBreakpoint)
} }
// ClearBreakpoint clears the breakpoint at addr. // ClearBreakpoint clears the breakpoint at addr.
func (dbp *Process) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) { func (dbp *nativeProcess) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) {
if dbp.exited { if dbp.exited {
return nil, &proc.ErrProcessExited{Pid: dbp.Pid()} return nil, &proc.ErrProcessExited{Pid: dbp.Pid()}
} }
@ -241,7 +241,7 @@ func (dbp *Process) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) {
// ContinueOnce will continue the target until it stops. // ContinueOnce will continue the target until it stops.
// This could be the result of a breakpoint or signal. // This could be the result of a breakpoint or signal.
func (dbp *Process) ContinueOnce() (proc.Thread, proc.StopReason, error) { func (dbp *nativeProcess) ContinueOnce() (proc.Thread, proc.StopReason, error) {
if dbp.exited { if dbp.exited {
return nil, proc.StopExited, &proc.ErrProcessExited{Pid: dbp.Pid()} return nil, proc.StopExited, &proc.ErrProcessExited{Pid: dbp.Pid()}
} }
@ -270,7 +270,7 @@ func (dbp *Process) ContinueOnce() (proc.Thread, proc.StopReason, error) {
} }
// FindBreakpoint finds the breakpoint for the given pc. // FindBreakpoint finds the breakpoint for the given pc.
func (dbp *Process) FindBreakpoint(pc uint64, adjustPC bool) (*proc.Breakpoint, bool) { func (dbp *nativeProcess) FindBreakpoint(pc uint64, adjustPC bool) (*proc.Breakpoint, bool) {
if adjustPC { if adjustPC {
// Check to see if address is past the breakpoint, (i.e. breakpoint was hit). // Check to see if address is past the breakpoint, (i.e. breakpoint was hit).
if bp, ok := dbp.breakpoints.M[pc-uint64(dbp.bi.Arch.BreakpointSize())]; ok { if bp, ok := dbp.breakpoints.M[pc-uint64(dbp.bi.Arch.BreakpointSize())]; ok {
@ -286,7 +286,7 @@ func (dbp *Process) FindBreakpoint(pc uint64, adjustPC bool) (*proc.Breakpoint,
// initialize will ensure that all relevant information is loaded // initialize will ensure that all relevant information is loaded
// so the process is ready to be debugged. // so the process is ready to be debugged.
func (dbp *Process) initialize(path string, debugInfoDirs []string) (*proc.Target, error) { func (dbp *nativeProcess) initialize(path string, debugInfoDirs []string) (*proc.Target, error) {
if err := initialize(dbp); err != nil { if err := initialize(dbp); err != nil {
return nil, err return nil, err
} }
@ -307,7 +307,7 @@ func (dbp *Process) initialize(path string, debugInfoDirs []string) (*proc.Targe
// ClearInternalBreakpoints will clear all non-user set breakpoints. These // ClearInternalBreakpoints will clear all non-user set breakpoints. These
// breakpoints are set for internal operations such as 'next'. // breakpoints are set for internal operations such as 'next'.
func (dbp *Process) ClearInternalBreakpoints() error { func (dbp *nativeProcess) ClearInternalBreakpoints() error {
return dbp.breakpoints.ClearInternalBreakpoints(func(bp *proc.Breakpoint) error { return dbp.breakpoints.ClearInternalBreakpoints(func(bp *proc.Breakpoint) error {
if err := dbp.currentThread.ClearBreakpoint(bp); err != nil { if err := dbp.currentThread.ClearBreakpoint(bp); err != nil {
return err return err
@ -321,7 +321,7 @@ func (dbp *Process) ClearInternalBreakpoints() error {
}) })
} }
func (dbp *Process) handlePtraceFuncs() { func (dbp *nativeProcess) handlePtraceFuncs() {
// We must ensure here that we are running on the same thread during // We must ensure here that we are running on the same thread during
// while invoking the ptrace(2) syscall. This is due to the fact that ptrace(2) expects // while invoking the ptrace(2) syscall. This is due to the fact that ptrace(2) expects
// all commands after PTRACE_ATTACH to come from the same thread. // all commands after PTRACE_ATTACH to come from the same thread.
@ -333,19 +333,19 @@ func (dbp *Process) handlePtraceFuncs() {
} }
} }
func (dbp *Process) execPtraceFunc(fn func()) { func (dbp *nativeProcess) execPtraceFunc(fn func()) {
dbp.ptraceChan <- fn dbp.ptraceChan <- fn
<-dbp.ptraceDoneChan <-dbp.ptraceDoneChan
} }
func (dbp *Process) postExit() { func (dbp *nativeProcess) postExit() {
dbp.exited = true dbp.exited = true
close(dbp.ptraceChan) close(dbp.ptraceChan)
close(dbp.ptraceDoneChan) close(dbp.ptraceDoneChan)
dbp.bi.Close() dbp.bi.Close()
} }
func (dbp *Process) writeSoftwareBreakpoint(thread *Thread, addr uint64) error { func (dbp *nativeProcess) writeSoftwareBreakpoint(thread *nativeThread, addr uint64) error {
_, err := thread.WriteMemory(uintptr(addr), dbp.bi.Arch.BreakpointInstruction()) _, err := thread.WriteMemory(uintptr(addr), dbp.bi.Arch.BreakpointInstruction())
return err return err
} }

@ -20,8 +20,8 @@ import (
"github.com/go-delve/delve/pkg/proc" "github.com/go-delve/delve/pkg/proc"
) )
// OSProcessDetails holds Darwin specific information. // osProcessDetails holds Darwin specific information.
type OSProcessDetails struct { type osProcessDetails struct {
task C.task_t // mach task for the debugged process. task C.task_t // mach task for the debugged process.
exceptionPort C.mach_port_t // mach port for receiving mach exceptions. exceptionPort C.mach_port_t // mach port for receiving mach exceptions.
notificationPort C.mach_port_t // mach port for dead name notification (process exit). notificationPort C.mach_port_t // mach port for dead name notification (process exit).
@ -64,7 +64,7 @@ func Launch(cmd []string, wd string, foreground bool, _ []string) (*proc.Target,
// argv array must be null terminated. // argv array must be null terminated.
argvSlice = append(argvSlice, nil) argvSlice = append(argvSlice, nil)
dbp := New(0) dbp := newProcess(0)
var pid int var pid int
dbp.execPtraceFunc(func() { dbp.execPtraceFunc(func() {
ret := C.fork_exec(argv0, &argvSlice[0], C.int(len(argvSlice)), ret := C.fork_exec(argv0, &argvSlice[0], C.int(len(argvSlice)),
@ -129,7 +129,7 @@ func Launch(cmd []string, wd string, foreground bool, _ []string) (*proc.Target,
// Attach to an existing process with the given PID. // Attach to an existing process with the given PID.
func Attach(pid int, _ []string) (*proc.Target, error) { func Attach(pid int, _ []string) (*proc.Target, error) {
dbp := New(pid) dbp := newProcess(pid)
kret := C.acquire_mach_task(C.int(pid), kret := C.acquire_mach_task(C.int(pid),
&dbp.os.task, &dbp.os.portSet, &dbp.os.exceptionPort, &dbp.os.task, &dbp.os.portSet, &dbp.os.exceptionPort,
@ -142,7 +142,7 @@ func Attach(pid int, _ []string) (*proc.Target, error) {
dbp.os.initialized = true dbp.os.initialized = true
var err error var err error
dbp.execPtraceFunc(func() { err = PtraceAttach(dbp.pid) }) dbp.execPtraceFunc(func() { err = ptraceAttach(dbp.pid) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -160,7 +160,7 @@ func Attach(pid int, _ []string) (*proc.Target, error) {
} }
// Kill kills the process. // Kill kills the process.
func (dbp *Process) kill() (err error) { func (dbp *nativeProcess) kill() (err error) {
if dbp.exited { if dbp.exited {
return nil return nil
} }
@ -184,7 +184,7 @@ func (dbp *Process) kill() (err error) {
return return
} }
func (dbp *Process) requestManualStop() (err error) { func (dbp *nativeProcess) requestManualStop() (err error) {
var ( var (
task = C.mach_port_t(dbp.os.task) task = C.mach_port_t(dbp.os.task)
thread = C.mach_port_t(dbp.currentThread.os.threadAct) thread = C.mach_port_t(dbp.currentThread.os.threadAct)
@ -201,11 +201,11 @@ func (dbp *Process) requestManualStop() (err error) {
var couldNotGetThreadCount = errors.New("could not get thread count") var couldNotGetThreadCount = errors.New("could not get thread count")
var couldNotGetThreadList = errors.New("could not get thread list") var couldNotGetThreadList = errors.New("could not get thread list")
func (dbp *Process) updateThreadList() error { func (dbp *nativeProcess) updateThreadList() error {
return dbp.updateThreadListForTask(dbp.os.task) return dbp.updateThreadListForTask(dbp.os.task)
} }
func (dbp *Process) updateThreadListForTask(task C.task_t) error { func (dbp *nativeProcess) updateThreadListForTask(task C.task_t) error {
var ( var (
err error err error
kret C.kern_return_t kret C.kern_return_t
@ -255,14 +255,14 @@ func (dbp *Process) updateThreadListForTask(task C.task_t) error {
return nil return nil
} }
func (dbp *Process) addThread(port int, attach bool) (*Thread, error) { func (dbp *nativeProcess) addThread(port int, attach bool) (*nativeThread, error) {
if thread, ok := dbp.threads[port]; ok { if thread, ok := dbp.threads[port]; ok {
return thread, nil return thread, nil
} }
thread := &Thread{ thread := &nativeThread{
ID: port, ID: port,
dbp: dbp, dbp: dbp,
os: new(OSSpecificDetails), os: new(osSpecificDetails),
} }
dbp.threads[port] = thread dbp.threads[port] = thread
thread.os.threadAct = C.thread_act_t(port) thread.os.threadAct = C.thread_act_t(port)
@ -279,7 +279,7 @@ func findExecutable(path string, pid int) string {
return path return path
} }
func (dbp *Process) trapWait(pid int) (*Thread, error) { func (dbp *nativeProcess) trapWait(pid int) (*nativeThread, error) {
for { for {
task := dbp.os.task task := dbp.os.task
port := C.mach_port_wait(dbp.os.portSet, &task, C.int(0)) port := C.mach_port_wait(dbp.os.portSet, &task, C.int(0))
@ -357,7 +357,7 @@ func (dbp *Process) trapWait(pid int) (*Thread, error) {
} }
} }
func (dbp *Process) waitForStop() ([]int, error) { func (dbp *nativeProcess) waitForStop() ([]int, error) {
ports := make([]int, 0, len(dbp.threads)) ports := make([]int, 0, len(dbp.threads))
count := 0 count := 0
for { for {
@ -379,7 +379,7 @@ func (dbp *Process) waitForStop() ([]int, error) {
} }
} }
func (dbp *Process) wait(pid, options int) (int, *sys.WaitStatus, error) { func (dbp *nativeProcess) wait(pid, options int) (int, *sys.WaitStatus, error) {
var status sys.WaitStatus var status sys.WaitStatus
wpid, err := sys.Wait4(pid, &status, options, nil) wpid, err := sys.Wait4(pid, &status, options, nil)
return wpid, &status, err return wpid, &status, err
@ -389,7 +389,7 @@ func killProcess(pid int) error {
return sys.Kill(pid, sys.SIGINT) return sys.Kill(pid, sys.SIGINT)
} }
func (dbp *Process) exitGuard(err error) error { func (dbp *nativeProcess) exitGuard(err error) error {
if err != ErrContinueThread { if err != ErrContinueThread {
return err return err
} }
@ -401,7 +401,7 @@ func (dbp *Process) exitGuard(err error) error {
return err return err
} }
func (dbp *Process) resume() error { func (dbp *nativeProcess) resume() error {
// all threads stopped over a breakpoint are made to step over it // all threads stopped over a breakpoint are made to step over it
for _, thread := range dbp.threads { for _, thread := range dbp.threads {
if thread.CurrentBreakpoint.Breakpoint != nil { if thread.CurrentBreakpoint.Breakpoint != nil {
@ -421,7 +421,7 @@ func (dbp *Process) resume() error {
} }
// stop stops all running threads and sets breakpoints // stop stops all running threads and sets breakpoints
func (dbp *Process) stop(trapthread *Thread) (err error) { func (dbp *nativeProcess) stop(trapthread *nativeThread) (err error) {
if dbp.exited { if dbp.exited {
return &proc.ErrProcessExited{Pid: dbp.Pid()} return &proc.ErrProcessExited{Pid: dbp.Pid()}
} }
@ -452,13 +452,13 @@ func (dbp *Process) stop(trapthread *Thread) (err error) {
return nil return nil
} }
func (dbp *Process) detach(kill bool) error { func (dbp *nativeProcess) detach(kill bool) error {
return PtraceDetach(dbp.pid, 0) return ptraceDetach(dbp.pid, 0)
} }
func (dbp *Process) EntryPoint() (uint64, error) { func (dbp *nativeProcess) EntryPoint() (uint64, error) {
//TODO(aarzilli): implement this //TODO(aarzilli): implement this
return 0, nil return 0, nil
} }
func initialize(dbp *Process) error { return nil } func initialize(dbp *nativeProcess) error { return nil }

@ -22,18 +22,18 @@ import (
// Process statuses // Process statuses
const ( const (
StatusIdle = 1 statusIdle = 1
StatusRunning = 2 statusRunning = 2
StatusSleeping = 3 statusSleeping = 3
StatusStopped = 4 statusStopped = 4
StatusZombie = 5 statusZombie = 5
StatusWaiting = 6 statusWaiting = 6
StatusLocked = 7 statusLocked = 7
) )
// OSProcessDetails contains FreeBSD specific // osProcessDetails contains FreeBSD specific
// process details. // process details.
type OSProcessDetails struct { type osProcessDetails struct {
comm string comm string
tid int tid int
} }
@ -59,7 +59,7 @@ func Launch(cmd []string, wd string, foreground bool, debugInfoDirs []string) (*
foreground = false foreground = false
} }
dbp := New(0) dbp := newProcess(0)
dbp.execPtraceFunc(func() { dbp.execPtraceFunc(func() {
process = exec.Command(cmd[0]) process = exec.Command(cmd[0])
process.Args = cmd process.Args = cmd
@ -95,10 +95,10 @@ func Launch(cmd []string, wd string, foreground bool, debugInfoDirs []string) (*
// the DWARF information cannot be found in the binary, Delve will look // the DWARF information cannot be found in the binary, Delve will look
// for external debug files in the directories passed in. // for external debug files in the directories passed in.
func Attach(pid int, debugInfoDirs []string) (*proc.Target, error) { func Attach(pid int, debugInfoDirs []string) (*proc.Target, error) {
dbp := New(pid) dbp := newProcess(pid)
var err error var err error
dbp.execPtraceFunc(func() { err = PtraceAttach(dbp.pid) }) dbp.execPtraceFunc(func() { err = ptraceAttach(dbp.pid) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -115,7 +115,7 @@ func Attach(pid int, debugInfoDirs []string) (*proc.Target, error) {
return tgt, nil return tgt, nil
} }
func initialize(dbp *Process) error { func initialize(dbp *nativeProcess) error {
comm, _ := C.find_command_name(C.int(dbp.pid)) comm, _ := C.find_command_name(C.int(dbp.pid))
defer C.free(unsafe.Pointer(comm)) defer C.free(unsafe.Pointer(comm))
comm_str := C.GoString(comm) comm_str := C.GoString(comm)
@ -124,11 +124,11 @@ func initialize(dbp *Process) error {
} }
// kill kills the target process. // kill kills the target process.
func (dbp *Process) kill() (err error) { func (dbp *nativeProcess) kill() (err error) {
if dbp.exited { if dbp.exited {
return nil return nil
} }
dbp.execPtraceFunc(func() { err = PtraceCont(dbp.pid, int(sys.SIGKILL)) }) dbp.execPtraceFunc(func() { err = ptraceCont(dbp.pid, int(sys.SIGKILL)) })
if err != nil { if err != nil {
return err return err
} }
@ -140,13 +140,13 @@ func (dbp *Process) kill() (err error) {
} }
// Used by RequestManualStop // Used by RequestManualStop
func (dbp *Process) requestManualStop() (err error) { func (dbp *nativeProcess) requestManualStop() (err error) {
return sys.Kill(dbp.pid, sys.SIGTRAP) return sys.Kill(dbp.pid, sys.SIGTRAP)
} }
// Attach to a newly created thread, and store that thread in our list of // Attach to a newly created thread, and store that thread in our list of
// known threads. // known threads.
func (dbp *Process) addThread(tid int, attach bool) (*Thread, error) { func (dbp *nativeProcess) addThread(tid int, attach bool) (*nativeThread, error) {
if thread, ok := dbp.threads[tid]; ok { if thread, ok := dbp.threads[tid]; ok {
return thread, nil return thread, nil
} }
@ -159,10 +159,10 @@ func (dbp *Process) addThread(tid int, attach bool) (*Thread, error) {
} }
} }
dbp.threads[tid] = &Thread{ dbp.threads[tid] = &nativeThread{
ID: tid, ID: tid,
dbp: dbp, dbp: dbp,
os: new(OSSpecificDetails), os: new(osSpecificDetails),
} }
if dbp.currentThread == nil { if dbp.currentThread == nil {
@ -173,9 +173,9 @@ func (dbp *Process) addThread(tid int, attach bool) (*Thread, error) {
} }
// Used by initialize // Used by initialize
func (dbp *Process) updateThreadList() error { func (dbp *nativeProcess) updateThreadList() error {
var tids []int32 var tids []int32
dbp.execPtraceFunc(func() { tids = PtraceGetLwpList(dbp.pid) }) dbp.execPtraceFunc(func() { tids = ptraceGetLwpList(dbp.pid) })
for _, tid := range tids { for _, tid := range tids {
if _, err := dbp.addThread(int(tid), false); err != nil { if _, err := dbp.addThread(int(tid), false); err != nil {
return err return err
@ -195,12 +195,12 @@ func findExecutable(path string, pid int) string {
return path return path
} }
func (dbp *Process) trapWait(pid int) (*Thread, error) { func (dbp *nativeProcess) trapWait(pid int) (*nativeThread, error) {
return dbp.trapWaitInternal(pid, false) return dbp.trapWaitInternal(pid, false)
} }
// Used by stop and trapWait // Used by stop and trapWait
func (dbp *Process) trapWaitInternal(pid int, halt bool) (*Thread, error) { func (dbp *nativeProcess) trapWaitInternal(pid int, halt bool) (*nativeThread, error) {
for { for {
wpid, status, err := dbp.wait(pid, 0) wpid, status, err := dbp.wait(pid, 0)
if err != nil { if err != nil {
@ -225,13 +225,13 @@ func (dbp *Process) trapWaitInternal(pid int, halt bool) (*Thread, error) {
pl_flags := int(info.Flags) pl_flags := int(info.Flags)
th, ok := dbp.threads[tid] th, ok := dbp.threads[tid]
if ok { if ok {
th.Status = (*WaitStatus)(status) th.Status = (*waitStatus)(status)
} }
if status.StopSignal() == sys.SIGTRAP { if status.StopSignal() == sys.SIGTRAP {
if pl_flags&sys.PL_FLAG_EXITED != 0 { if pl_flags&sys.PL_FLAG_EXITED != 0 {
delete(dbp.threads, tid) delete(dbp.threads, tid)
dbp.execPtraceFunc(func() { err = PtraceCont(tid, 0) }) dbp.execPtraceFunc(func() { err = ptraceCont(tid, 0) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -287,25 +287,25 @@ func status(pid int) rune {
// Used by stop and singleStep // Used by stop and singleStep
// waitFast is like wait but does not handle process-exit correctly // waitFast is like wait but does not handle process-exit correctly
func (dbp *Process) waitFast(pid int) (int, *sys.WaitStatus, error) { func (dbp *nativeProcess) waitFast(pid int) (int, *sys.WaitStatus, error) {
var s sys.WaitStatus var s sys.WaitStatus
wpid, err := sys.Wait4(pid, &s, 0, nil) wpid, err := sys.Wait4(pid, &s, 0, nil)
return wpid, &s, err return wpid, &s, err
} }
// Only used in this file // Only used in this file
func (dbp *Process) wait(pid, options int) (int, *sys.WaitStatus, error) { func (dbp *nativeProcess) wait(pid, options int) (int, *sys.WaitStatus, error) {
var s sys.WaitStatus var s sys.WaitStatus
wpid, err := sys.Wait4(pid, &s, options, nil) wpid, err := sys.Wait4(pid, &s, options, nil)
return wpid, &s, err return wpid, &s, err
} }
// Only used in this file // Only used in this file
func (dbp *Process) exitGuard(err error) error { func (dbp *nativeProcess) exitGuard(err error) error {
if err != sys.ESRCH { if err != sys.ESRCH {
return err return err
} }
if status(dbp.pid) == StatusZombie { if status(dbp.pid) == statusZombie {
_, err := dbp.trapWaitInternal(-1, false) _, err := dbp.trapWaitInternal(-1, false)
return err return err
} }
@ -314,7 +314,7 @@ func (dbp *Process) exitGuard(err error) error {
} }
// Used by ContinueOnce // Used by ContinueOnce
func (dbp *Process) resume() error { func (dbp *nativeProcess) resume() error {
// all threads stopped over a breakpoint are made to step over it // all threads stopped over a breakpoint are made to step over it
for _, thread := range dbp.threads { for _, thread := range dbp.threads {
if thread.CurrentBreakpoint.Breakpoint != nil { if thread.CurrentBreakpoint.Breakpoint != nil {
@ -326,13 +326,13 @@ func (dbp *Process) resume() error {
} }
// all threads are resumed // all threads are resumed
var err error var err error
dbp.execPtraceFunc(func() { err = PtraceCont(dbp.pid, 0) }) dbp.execPtraceFunc(func() { err = ptraceCont(dbp.pid, 0) })
return err return err
} }
// Used by ContinueOnce // Used by ContinueOnce
// stop stops all running threads and sets breakpoints // stop stops all running threads and sets breakpoints
func (dbp *Process) stop(trapthread *Thread) (err error) { func (dbp *nativeProcess) stop(trapthread *nativeThread) (err error) {
if dbp.exited { if dbp.exited {
return &proc.ErrProcessExited{Pid: dbp.Pid()} return &proc.ErrProcessExited{Pid: dbp.Pid()}
} }
@ -348,13 +348,13 @@ func (dbp *Process) stop(trapthread *Thread) (err error) {
} }
// Used by Detach // Used by Detach
func (dbp *Process) detach(kill bool) error { func (dbp *nativeProcess) detach(kill bool) error {
return PtraceDetach(dbp.pid) return ptraceDetach(dbp.pid)
} }
// Used by PostInitializationSetup // Used by PostInitializationSetup
// EntryPoint will return the process entry point address, useful for debugging PIEs. // EntryPoint will return the process entry point address, useful for debugging PIEs.
func (dbp *Process) EntryPoint() (uint64, error) { func (dbp *nativeProcess) EntryPoint() (uint64, error) {
ep, err := C.get_entry_point(C.int(dbp.pid)) ep, err := C.get_entry_point(C.int(dbp.pid))
return uint64(ep), err return uint64(ep), err
} }

@ -26,21 +26,21 @@ import (
// Process statuses // Process statuses
const ( const (
StatusSleeping = 'S' statusSleeping = 'S'
StatusRunning = 'R' statusRunning = 'R'
StatusTraceStop = 't' statusTraceStop = 't'
StatusZombie = 'Z' statusZombie = 'Z'
// Kernel 2.6 has TraceStop as T // Kernel 2.6 has TraceStop as T
// TODO(derekparker) Since this means something different based on the // TODO(derekparker) Since this means something different based on the
// version of the kernel ('T' is job control stop on modern 3.x+ kernels) we // version of the kernel ('T' is job control stop on modern 3.x+ kernels) we
// may want to differentiate at some point. // may want to differentiate at some point.
StatusTraceStopT = 'T' statusTraceStopT = 'T'
) )
// OSProcessDetails contains Linux specific // osProcessDetails contains Linux specific
// process details. // process details.
type OSProcessDetails struct { type osProcessDetails struct {
comm string comm string
} }
@ -65,7 +65,7 @@ func Launch(cmd []string, wd string, foreground bool, debugInfoDirs []string) (*
foreground = false foreground = false
} }
dbp := New(0) dbp := newProcess(0)
dbp.execPtraceFunc(func() { dbp.execPtraceFunc(func() {
process = exec.Command(cmd[0]) process = exec.Command(cmd[0])
process.Args = cmd process.Args = cmd
@ -101,10 +101,10 @@ func Launch(cmd []string, wd string, foreground bool, debugInfoDirs []string) (*
// the DWARF information cannot be found in the binary, Delve will look // the DWARF information cannot be found in the binary, Delve will look
// for external debug files in the directories passed in. // for external debug files in the directories passed in.
func Attach(pid int, debugInfoDirs []string) (*proc.Target, error) { func Attach(pid int, debugInfoDirs []string) (*proc.Target, error) {
dbp := New(pid) dbp := newProcess(pid)
var err error var err error
dbp.execPtraceFunc(func() { err = PtraceAttach(dbp.pid) }) dbp.execPtraceFunc(func() { err = ptraceAttach(dbp.pid) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -128,7 +128,7 @@ func Attach(pid int, debugInfoDirs []string) (*proc.Target, error) {
return tgt, nil return tgt, nil
} }
func initialize(dbp *Process) error { func initialize(dbp *nativeProcess) error {
comm, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/comm", dbp.pid)) comm, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/comm", dbp.pid))
if err == nil { if err == nil {
// removes newline character // removes newline character
@ -156,7 +156,7 @@ func initialize(dbp *Process) error {
} }
// kill kills the target process. // kill kills the target process.
func (dbp *Process) kill() (err error) { func (dbp *nativeProcess) kill() (err error) {
if dbp.exited { if dbp.exited {
return nil return nil
} }
@ -173,13 +173,13 @@ func (dbp *Process) kill() (err error) {
return return
} }
func (dbp *Process) requestManualStop() (err error) { func (dbp *nativeProcess) requestManualStop() (err error) {
return sys.Kill(dbp.pid, sys.SIGTRAP) return sys.Kill(dbp.pid, sys.SIGTRAP)
} }
// Attach to a newly created thread, and store that thread in our list of // Attach to a newly created thread, and store that thread in our list of
// known threads. // known threads.
func (dbp *Process) addThread(tid int, attach bool) (*Thread, error) { func (dbp *nativeProcess) addThread(tid int, attach bool) (*nativeThread, error) {
if thread, ok := dbp.threads[tid]; ok { if thread, ok := dbp.threads[tid]; ok {
return thread, nil return thread, nil
} }
@ -217,10 +217,10 @@ func (dbp *Process) addThread(tid int, attach bool) (*Thread, error) {
} }
} }
dbp.threads[tid] = &Thread{ dbp.threads[tid] = &nativeThread{
ID: tid, ID: tid,
dbp: dbp, dbp: dbp,
os: new(OSSpecificDetails), os: new(osSpecificDetails),
} }
if dbp.currentThread == nil { if dbp.currentThread == nil {
dbp.currentThread = dbp.threads[tid] dbp.currentThread = dbp.threads[tid]
@ -228,7 +228,7 @@ func (dbp *Process) addThread(tid int, attach bool) (*Thread, error) {
return dbp.threads[tid], nil return dbp.threads[tid], nil
} }
func (dbp *Process) updateThreadList() error { func (dbp *nativeProcess) updateThreadList() error {
tids, _ := filepath.Glob(fmt.Sprintf("/proc/%d/task/*", dbp.pid)) tids, _ := filepath.Glob(fmt.Sprintf("/proc/%d/task/*", dbp.pid))
for _, tidpath := range tids { for _, tidpath := range tids {
tidstr := filepath.Base(tidpath) tidstr := filepath.Base(tidpath)
@ -250,7 +250,7 @@ func findExecutable(path string, pid int) string {
return path return path
} }
func (dbp *Process) trapWait(pid int) (*Thread, error) { func (dbp *nativeProcess) trapWait(pid int) (*nativeThread, error) {
return dbp.trapWaitInternal(pid, 0) return dbp.trapWaitInternal(pid, 0)
} }
@ -261,7 +261,7 @@ const (
trapWaitNohang trapWaitNohang
) )
func (dbp *Process) trapWaitInternal(pid int, options trapWaitOptions) (*Thread, error) { func (dbp *nativeProcess) trapWaitInternal(pid int, options trapWaitOptions) (*nativeThread, error) {
halt := options&trapWaitHalt != 0 halt := options&trapWaitHalt != 0
for { for {
wopt := 0 wopt := 0
@ -280,7 +280,7 @@ func (dbp *Process) trapWaitInternal(pid int, options trapWaitOptions) (*Thread,
} }
th, ok := dbp.threads[wpid] th, ok := dbp.threads[wpid]
if ok { if ok {
th.Status = (*WaitStatus)(status) th.Status = (*waitStatus)(status)
} }
if status.Exited() { if status.Exited() {
if wpid == dbp.pid { if wpid == dbp.pid {
@ -387,13 +387,13 @@ func status(pid int, comm string) rune {
} }
// waitFast is like wait but does not handle process-exit correctly // waitFast is like wait but does not handle process-exit correctly
func (dbp *Process) waitFast(pid int) (int, *sys.WaitStatus, error) { func (dbp *nativeProcess) waitFast(pid int) (int, *sys.WaitStatus, error) {
var s sys.WaitStatus var s sys.WaitStatus
wpid, err := sys.Wait4(pid, &s, sys.WALL, nil) wpid, err := sys.Wait4(pid, &s, sys.WALL, nil)
return wpid, &s, err return wpid, &s, err
} }
func (dbp *Process) wait(pid, options int) (int, *sys.WaitStatus, error) { func (dbp *nativeProcess) wait(pid, options int) (int, *sys.WaitStatus, error) {
var s sys.WaitStatus var s sys.WaitStatus
if (pid != dbp.pid) || (options != 0) { if (pid != dbp.pid) || (options != 0) {
wpid, err := sys.Wait4(pid, &s, sys.WALL|options, nil) wpid, err := sys.Wait4(pid, &s, sys.WALL|options, nil)
@ -418,18 +418,18 @@ func (dbp *Process) wait(pid, options int) (int, *sys.WaitStatus, error) {
if wpid != 0 { if wpid != 0 {
return wpid, &s, err return wpid, &s, err
} }
if status(pid, dbp.os.comm) == StatusZombie { if status(pid, dbp.os.comm) == statusZombie {
return pid, nil, nil return pid, nil, nil
} }
time.Sleep(200 * time.Millisecond) time.Sleep(200 * time.Millisecond)
} }
} }
func (dbp *Process) exitGuard(err error) error { func (dbp *nativeProcess) exitGuard(err error) error {
if err != sys.ESRCH { if err != sys.ESRCH {
return err return err
} }
if status(dbp.pid, dbp.os.comm) == StatusZombie { if status(dbp.pid, dbp.os.comm) == statusZombie {
_, err := dbp.trapWaitInternal(-1, 0) _, err := dbp.trapWaitInternal(-1, 0)
return err return err
} }
@ -437,7 +437,7 @@ func (dbp *Process) exitGuard(err error) error {
return err return err
} }
func (dbp *Process) resume() error { func (dbp *nativeProcess) resume() error {
// all threads stopped over a breakpoint are made to step over it // all threads stopped over a breakpoint are made to step over it
for _, thread := range dbp.threads { for _, thread := range dbp.threads {
if thread.CurrentBreakpoint.Breakpoint != nil { if thread.CurrentBreakpoint.Breakpoint != nil {
@ -457,7 +457,7 @@ func (dbp *Process) resume() error {
} }
// stop stops all running threads and sets breakpoints // stop stops all running threads and sets breakpoints
func (dbp *Process) stop(trapthread *Thread) (err error) { func (dbp *nativeProcess) stop(trapthread *nativeThread) (err error) {
if dbp.exited { if dbp.exited {
return &proc.ErrProcessExited{Pid: dbp.Pid()} return &proc.ErrProcessExited{Pid: dbp.Pid()}
} }
@ -517,9 +517,9 @@ func (dbp *Process) stop(trapthread *Thread) (err error) {
return nil return nil
} }
func (dbp *Process) detach(kill bool) error { func (dbp *nativeProcess) detach(kill bool) error {
for threadID := range dbp.threads { for threadID := range dbp.threads {
err := PtraceDetach(threadID, 0) err := ptraceDetach(threadID, 0)
if err != nil { if err != nil {
return err return err
} }
@ -540,7 +540,7 @@ func (dbp *Process) detach(kill bool) error {
// EntryPoint will return the process entry point address, useful for // EntryPoint will return the process entry point address, useful for
// debugging PIEs. // debugging PIEs.
func (dbp *Process) EntryPoint() (uint64, error) { func (dbp *nativeProcess) EntryPoint() (uint64, error) {
auxvbuf, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/auxv", dbp.pid)) auxvbuf, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/auxv", dbp.pid))
if err != nil { if err != nil {
return 0, fmt.Errorf("could not read auxiliary vector: %v", err) return 0, fmt.Errorf("could not read auxiliary vector: %v", err)

@ -15,8 +15,8 @@ import (
"github.com/go-delve/delve/pkg/proc" "github.com/go-delve/delve/pkg/proc"
) )
// OSProcessDetails holds Windows specific information. // osProcessDetails holds Windows specific information.
type OSProcessDetails struct { type osProcessDetails struct {
hProcess syscall.Handle hProcess syscall.Handle
breakThread int breakThread int
entryPoint uint64 entryPoint uint64
@ -58,7 +58,7 @@ func Launch(cmd []string, wd string, foreground bool, _ []string) (*proc.Target,
env := proc.DisableAsyncPreemptEnv() env := proc.DisableAsyncPreemptEnv()
var p *os.Process var p *os.Process
dbp := New(0) dbp := newProcess(0)
dbp.execPtraceFunc(func() { dbp.execPtraceFunc(func() {
attr := &os.ProcAttr{ attr := &os.ProcAttr{
Dir: wd, Dir: wd,
@ -86,7 +86,7 @@ func Launch(cmd []string, wd string, foreground bool, _ []string) (*proc.Target,
return tgt, nil return tgt, nil
} }
func initialize(dbp *Process) error { func initialize(dbp *nativeProcess) error {
// It should not actually be possible for the // It should not actually be possible for the
// call to waitForDebugEvent to fail, since Windows // call to waitForDebugEvent to fail, since Windows
// will always fire a CREATE_PROCESS_DEBUG_EVENT event // will always fire a CREATE_PROCESS_DEBUG_EVENT event
@ -155,7 +155,7 @@ func findExePath(pid int) (string, error) {
// Attach to an existing process with the given PID. // Attach to an existing process with the given PID.
func Attach(pid int, _ []string) (*proc.Target, error) { func Attach(pid int, _ []string) (*proc.Target, error) {
dbp := New(pid) dbp := newProcess(pid)
var err error var err error
dbp.execPtraceFunc(func() { dbp.execPtraceFunc(func() {
// TODO: Probably should have SeDebugPrivilege before starting here. // TODO: Probably should have SeDebugPrivilege before starting here.
@ -177,7 +177,7 @@ func Attach(pid int, _ []string) (*proc.Target, error) {
} }
// kill kills the process. // kill kills the process.
func (dbp *Process) kill() error { func (dbp *nativeProcess) kill() error {
if dbp.exited { if dbp.exited {
return nil return nil
} }
@ -203,24 +203,24 @@ func (dbp *Process) kill() error {
return nil return nil
} }
func (dbp *Process) requestManualStop() error { func (dbp *nativeProcess) requestManualStop() error {
return _DebugBreakProcess(dbp.os.hProcess) return _DebugBreakProcess(dbp.os.hProcess)
} }
func (dbp *Process) updateThreadList() error { func (dbp *nativeProcess) updateThreadList() error {
// We ignore this request since threads are being // We ignore this request since threads are being
// tracked as they are created/killed in waitForDebugEvent. // tracked as they are created/killed in waitForDebugEvent.
return nil return nil
} }
func (dbp *Process) addThread(hThread syscall.Handle, threadID int, attach, suspendNewThreads bool) (*Thread, error) { func (dbp *nativeProcess) addThread(hThread syscall.Handle, threadID int, attach, suspendNewThreads bool) (*nativeThread, error) {
if thread, ok := dbp.threads[threadID]; ok { if thread, ok := dbp.threads[threadID]; ok {
return thread, nil return thread, nil
} }
thread := &Thread{ thread := &nativeThread{
ID: threadID, ID: threadID,
dbp: dbp, dbp: dbp,
os: new(OSSpecificDetails), os: new(osSpecificDetails),
} }
thread.os.hThread = hThread thread.os.hThread = hThread
dbp.threads[threadID] = thread dbp.threads[threadID] = thread
@ -250,7 +250,7 @@ const (
const _MS_VC_EXCEPTION = 0x406D1388 // part of VisualC protocol to set thread names const _MS_VC_EXCEPTION = 0x406D1388 // part of VisualC protocol to set thread names
func (dbp *Process) waitForDebugEvent(flags waitForDebugEventFlags) (threadID, exitCode int, err error) { func (dbp *nativeProcess) waitForDebugEvent(flags waitForDebugEventFlags) (threadID, exitCode int, err error) {
var debugEvent _DEBUG_EVENT var debugEvent _DEBUG_EVENT
shouldExit := false shouldExit := false
for { for {
@ -378,7 +378,7 @@ func (dbp *Process) waitForDebugEvent(flags waitForDebugEventFlags) (threadID, e
} }
} }
func (dbp *Process) trapWait(pid int) (*Thread, error) { func (dbp *nativeProcess) trapWait(pid int) (*nativeThread, error) {
var err error var err error
var tid, exitCode int var tid, exitCode int
dbp.execPtraceFunc(func() { dbp.execPtraceFunc(func() {
@ -395,15 +395,15 @@ func (dbp *Process) trapWait(pid int) (*Thread, error) {
return th, nil return th, nil
} }
func (dbp *Process) wait(pid, options int) (int, *sys.WaitStatus, error) { func (dbp *nativeProcess) wait(pid, options int) (int, *sys.WaitStatus, error) {
return 0, nil, fmt.Errorf("not implemented: wait") return 0, nil, fmt.Errorf("not implemented: wait")
} }
func (dbp *Process) exitGuard(err error) error { func (dbp *nativeProcess) exitGuard(err error) error {
return err return err
} }
func (dbp *Process) resume() error { func (dbp *nativeProcess) resume() error {
for _, thread := range dbp.threads { for _, thread := range dbp.threads {
if thread.CurrentBreakpoint.Breakpoint != nil { if thread.CurrentBreakpoint.Breakpoint != nil {
if err := thread.StepInstruction(); err != nil { if err := thread.StepInstruction(); err != nil {
@ -424,7 +424,7 @@ func (dbp *Process) resume() error {
} }
// stop stops all running threads threads and sets breakpoints // stop stops all running threads threads and sets breakpoints
func (dbp *Process) stop(trapthread *Thread) (err error) { func (dbp *nativeProcess) stop(trapthread *nativeThread) (err error) {
if dbp.exited { if dbp.exited {
return &proc.ErrProcessExited{Pid: dbp.Pid()} return &proc.ErrProcessExited{Pid: dbp.Pid()}
} }
@ -475,7 +475,7 @@ func (dbp *Process) stop(trapthread *Thread) (err error) {
return nil return nil
} }
func (dbp *Process) detach(kill bool) error { func (dbp *nativeProcess) detach(kill bool) error {
if !kill { if !kill {
//TODO(aarzilli): when debug.Target exist Detach should be moved to //TODO(aarzilli): when debug.Target exist Detach should be moved to
// debug.Target and the call to RestoreAsyncPreempt should be moved there. // debug.Target and the call to RestoreAsyncPreempt should be moved there.
@ -489,7 +489,7 @@ func (dbp *Process) detach(kill bool) error {
return _DebugActiveProcessStop(uint32(dbp.pid)) return _DebugActiveProcessStop(uint32(dbp.pid))
} }
func (dbp *Process) EntryPoint() (uint64, error) { func (dbp *nativeProcess) EntryPoint() (uint64, error) {
return dbp.os.entryPoint, nil return dbp.os.entryPoint, nil
} }

@ -4,23 +4,23 @@ package native
import sys "golang.org/x/sys/unix" import sys "golang.org/x/sys/unix"
// PtraceAttach executes the sys.PtraceAttach call. // ptraceAttach executes the sys.PtraceAttach call.
func PtraceAttach(pid int) error { func ptraceAttach(pid int) error {
return sys.PtraceAttach(pid) return sys.PtraceAttach(pid)
} }
// PtraceDetach executes the PT_DETACH ptrace call. // ptraceDetach executes the PT_DETACH ptrace call.
func PtraceDetach(tid, sig int) error { func ptraceDetach(tid, sig int) error {
return ptrace(sys.PT_DETACH, tid, 1, uintptr(sig)) return ptrace(sys.PT_DETACH, tid, 1, uintptr(sig))
} }
// PtraceCont executes the PTRACE_CONT ptrace call. // ptraceCont executes the PTRACE_CONT ptrace call.
func PtraceCont(tid, sig int) error { func ptraceCont(tid, sig int) error {
return ptrace(sys.PTRACE_CONT, tid, 1, 0) return ptrace(sys.PTRACE_CONT, tid, 1, 0)
} }
// PtraceSingleStep returns PT_STEP ptrace call. // ptraceSingleStep returns PT_STEP ptrace call.
func PtraceSingleStep(tid int) error { func ptraceSingleStep(tid int) error {
return ptrace(sys.PT_STEP, tid, 1, 0) return ptrace(sys.PT_STEP, tid, 1, 0)
} }

@ -17,31 +17,31 @@ import (
"github.com/go-delve/delve/pkg/proc/fbsdutil" "github.com/go-delve/delve/pkg/proc/fbsdutil"
) )
// PtraceAttach executes the sys.PtraceAttach call. // ptraceAttach executes the sys.PtraceAttach call.
// pid must be a PID, not a LWPID // pid must be a PID, not a LWPID
func PtraceAttach(pid int) error { func ptraceAttach(pid int) error {
return sys.PtraceAttach(pid) return sys.PtraceAttach(pid)
} }
// PtraceDetach calls ptrace(PTRACE_DETACH). // ptraceDetach calls ptrace(PTRACE_DETACH).
func PtraceDetach(pid int) error { func ptraceDetach(pid int) error {
return sys.PtraceDetach(pid) return sys.PtraceDetach(pid)
} }
// PtraceCont executes ptrace PTRACE_CONT // ptraceCont executes ptrace PTRACE_CONT
// id may be a PID or an LWPID // id may be a PID or an LWPID
func PtraceCont(id, sig int) error { func ptraceCont(id, sig int) error {
return sys.PtraceCont(id, sig) return sys.PtraceCont(id, sig)
} }
// PtraceSingleStep executes ptrace PTRACE_SINGLE_STEP. // ptraceSingleStep executes ptrace PTRACE_SINGLE_STEP.
// id may be a PID or an LWPID // id may be a PID or an LWPID
func PtraceSingleStep(id int) error { func ptraceSingleStep(id int) error {
return sys.PtraceSingleStep(id) return sys.PtraceSingleStep(id)
} }
// Get a list of the thread ids of a process // Get a list of the thread ids of a process
func PtraceGetLwpList(pid int) (tids []int32) { func ptraceGetLwpList(pid int) (tids []int32) {
num_lwps, _ := C.ptrace_get_num_lwps(C.int(pid)) num_lwps, _ := C.ptrace_get_num_lwps(C.int(pid))
tids = make([]int32, num_lwps) tids = make([]int32, num_lwps)
n, _ := C.ptrace_get_lwp_list(C.int(pid), (*C.int)(unsafe.Pointer(&tids[0])), C.size_t(num_lwps)) n, _ := C.ptrace_get_lwp_list(C.int(pid), (*C.int)(unsafe.Pointer(&tids[0])), C.size_t(num_lwps))
@ -54,7 +54,7 @@ func ptraceGetLwpInfo(wpid int) (info sys.PtraceLwpInfoStruct, err error) {
return info, err return info, err
} }
func PtraceGetRegset(id int) (regset fbsdutil.AMD64Xstate, err error) { func ptraceGetRegset(id int) (regset fbsdutil.AMD64Xstate, err error) {
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETFPREGS, uintptr(id), uintptr(unsafe.Pointer(&regset.AMD64PtraceFpRegs)), 0, 0, 0) _, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETFPREGS, uintptr(id), uintptr(unsafe.Pointer(&regset.AMD64PtraceFpRegs)), 0, 0, 0)
if err == syscall.Errno(0) || err == syscall.ENODEV { if err == syscall.Errno(0) || err == syscall.ENODEV {
var xsave_len C.size_t var xsave_len C.size_t

@ -2,18 +2,17 @@ package native
import ( import (
"syscall" "syscall"
"unsafe"
sys "golang.org/x/sys/unix" sys "golang.org/x/sys/unix"
) )
// PtraceAttach executes the sys.PtraceAttach call. // ptraceAttach executes the sys.PtraceAttach call.
func PtraceAttach(pid int) error { func ptraceAttach(pid int) error {
return sys.PtraceAttach(pid) return sys.PtraceAttach(pid)
} }
// PtraceDetach calls ptrace(PTRACE_DETACH). // ptraceDetach calls ptrace(PTRACE_DETACH).
func PtraceDetach(tid, sig int) error { func ptraceDetach(tid, sig int) error {
_, _, err := sys.Syscall6(sys.SYS_PTRACE, sys.PTRACE_DETACH, uintptr(tid), 1, uintptr(sig), 0, 0) _, _, err := sys.Syscall6(sys.SYS_PTRACE, sys.PTRACE_DETACH, uintptr(tid), 1, uintptr(sig), 0, 0)
if err != syscall.Errno(0) { if err != syscall.Errno(0) {
return err return err
@ -21,31 +20,7 @@ func PtraceDetach(tid, sig int) error {
return nil return nil
} }
// PtraceCont executes ptrace PTRACE_CONT // ptraceCont executes ptrace PTRACE_CONT
func PtraceCont(tid, sig int) error { func ptraceCont(tid, sig int) error {
return sys.PtraceCont(tid, sig) return sys.PtraceCont(tid, sig)
} }
// PtraceSingleStep executes ptrace PTRACE_SINGLE_STEP.
func PtraceSingleStep(tid int) error {
return sys.PtraceSingleStep(tid)
}
// PtracePokeUser execute ptrace PTRACE_POKE_USER.
func PtracePokeUser(tid int, off, addr uintptr) error {
_, _, err := sys.Syscall6(sys.SYS_PTRACE, sys.PTRACE_POKEUSR, uintptr(tid), uintptr(off), uintptr(addr), 0, 0)
if err != syscall.Errno(0) {
return err
}
return nil
}
// PtracePeekUser execute ptrace PTRACE_PEEK_USER.
func PtracePeekUser(tid int, off uintptr) (uintptr, error) {
var val uintptr
_, _, err := syscall.Syscall6(syscall.SYS_PTRACE, syscall.PTRACE_PEEKUSR, uintptr(tid), uintptr(off), uintptr(unsafe.Pointer(&val)), 0, 0)
if err != syscall.Errno(0) {
return 0, err
}
return val, nil
}

@ -12,12 +12,12 @@ import (
"github.com/go-delve/delve/pkg/proc/linutil" "github.com/go-delve/delve/pkg/proc/linutil"
) )
// PtraceGetRegset returns floating point registers of the specified thread // ptraceGetRegset returns floating point registers of the specified thread
// using PTRACE. // using PTRACE.
// See i386_linux_fetch_inferior_registers in gdb/i386-linux-nat.c.html // See i386_linux_fetch_inferior_registers in gdb/i386-linux-nat.c.html
// and i386_supply_xsave in gdb/i386-tdep.c.html // and i386_supply_xsave in gdb/i386-tdep.c.html
// and Section 13.1 (and following) of Intel® 64 and IA-32 Architectures Software Developers Manual, Volume 1: Basic Architecture // and Section 13.1 (and following) of Intel® 64 and IA-32 Architectures Software Developers Manual, Volume 1: Basic Architecture
func PtraceGetRegset(tid int) (regset linutil.I386Xstate, err error) { func ptraceGetRegset(tid int) (regset linutil.I386Xstate, err error) {
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETFPREGS, uintptr(tid), uintptr(0), uintptr(unsafe.Pointer(&regset.I386PtraceFpRegs)), 0, 0) _, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETFPREGS, uintptr(tid), uintptr(0), uintptr(unsafe.Pointer(&regset.I386PtraceFpRegs)), 0, 0)
if err == syscall.Errno(0) || err == syscall.ENODEV { if err == syscall.Errno(0) || err == syscall.ENODEV {
// ignore ENODEV, it just means this CPU doesn't have X87 registers (??) // ignore ENODEV, it just means this CPU doesn't have X87 registers (??)
@ -43,7 +43,7 @@ func PtraceGetRegset(tid int) (regset linutil.I386Xstate, err error) {
return return
} }
// PtraceGetTls return the addr of tls by PTRACE_GET_THREAD_AREA for specify thread. // ptraceGetTls return the addr of tls by PTRACE_GET_THREAD_AREA for specify thread.
// See http://man7.org/linux/man-pages/man2/ptrace.2.html for detail about PTRACE_GET_THREAD_AREA. // See http://man7.org/linux/man-pages/man2/ptrace.2.html for detail about PTRACE_GET_THREAD_AREA.
// struct user_desc at https://golang.org/src/runtime/sys_linux_386.s // struct user_desc at https://golang.org/src/runtime/sys_linux_386.s
// type UserDesc struct { // type UserDesc struct {
@ -52,7 +52,7 @@ func PtraceGetRegset(tid int) (regset linutil.I386Xstate, err error) {
// Limit uint32 // Limit uint32
// Flag uint32 // Flag uint32
// } // }
func PtraceGetTls(gs int32, tid int) (uint32, error) { func ptraceGetTls(gs int32, tid int) (uint32, error) {
ud := [4]uint32{} ud := [4]uint32{}
// Gs usually is 0x33 // Gs usually is 0x33
@ -64,8 +64,8 @@ func PtraceGetTls(gs int32, tid int) (uint32, error) {
return uint32(ud[1]), nil return uint32(ud[1]), nil
} }
// ProcessVmRead calls process_vm_readv // processVmRead calls process_vm_readv
func ProcessVmRead(tid int, addr uintptr, data []byte) (int, error) { func processVmRead(tid int, addr uintptr, data []byte) (int, error) {
len_iov := uint32(len(data)) len_iov := uint32(len(data))
local_iov := sys.Iovec{Base: &data[0], Len: len_iov} local_iov := sys.Iovec{Base: &data[0], Len: len_iov}
remote_iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(addr)), Len: len_iov} remote_iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(addr)), Len: len_iov}
@ -78,8 +78,8 @@ func ProcessVmRead(tid int, addr uintptr, data []byte) (int, error) {
return int(n), nil return int(n), nil
} }
// ProcessVmWrite calls process_vm_writev // processVmWrite calls process_vm_writev
func ProcessVmWrite(tid int, addr uintptr, data []byte) (int, error) { func processVmWrite(tid int, addr uintptr, data []byte) (int, error) {
len_iov := uint32(len(data)) len_iov := uint32(len(data))
local_iov := sys.Iovec{Base: &data[0], Len: len_iov} local_iov := sys.Iovec{Base: &data[0], Len: len_iov}
remote_iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(addr)), Len: len_iov} remote_iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(addr)), Len: len_iov}

@ -9,8 +9,8 @@ import (
sys "golang.org/x/sys/unix" sys "golang.org/x/sys/unix"
) )
// ProcessVmRead calls process_vm_readv // processVmRead calls process_vm_readv
func ProcessVmRead(tid int, addr uintptr, data []byte) (int, error) { func processVmRead(tid int, addr uintptr, data []byte) (int, error) {
len_iov := uint64(len(data)) len_iov := uint64(len(data))
local_iov := sys.Iovec{Base: &data[0], Len: len_iov} local_iov := sys.Iovec{Base: &data[0], Len: len_iov}
remote_iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(addr)), Len: len_iov} remote_iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(addr)), Len: len_iov}
@ -23,8 +23,8 @@ func ProcessVmRead(tid int, addr uintptr, data []byte) (int, error) {
return int(n), nil return int(n), nil
} }
// ProcessVmWrite calls process_vm_writev // processVmWrite calls process_vm_writev
func ProcessVmWrite(tid int, addr uintptr, data []byte) (int, error) { func processVmWrite(tid int, addr uintptr, data []byte) (int, error) {
len_iov := uint64(len(data)) len_iov := uint64(len(data))
local_iov := sys.Iovec{Base: &data[0], Len: len_iov} local_iov := sys.Iovec{Base: &data[0], Len: len_iov}
remote_iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(addr)), Len: len_iov} remote_iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(addr)), Len: len_iov}

@ -9,12 +9,12 @@ import (
"github.com/go-delve/delve/pkg/proc/linutil" "github.com/go-delve/delve/pkg/proc/linutil"
) )
// PtraceGetRegset returns floating point registers of the specified thread // ptraceGetRegset returns floating point registers of the specified thread
// using PTRACE. // using PTRACE.
// See amd64_linux_fetch_inferior_registers in gdb/amd64-linux-nat.c.html // See amd64_linux_fetch_inferior_registers in gdb/amd64-linux-nat.c.html
// and amd64_supply_xsave in gdb/amd64-tdep.c.html // and amd64_supply_xsave in gdb/amd64-tdep.c.html
// and Section 13.1 (and following) of Intel® 64 and IA-32 Architectures Software Developers Manual, Volume 1: Basic Architecture // and Section 13.1 (and following) of Intel® 64 and IA-32 Architectures Software Developers Manual, Volume 1: Basic Architecture
func PtraceGetRegset(tid int) (regset linutil.AMD64Xstate, err error) { func ptraceGetRegset(tid int) (regset linutil.AMD64Xstate, err error) {
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETFPREGS, uintptr(tid), uintptr(0), uintptr(unsafe.Pointer(&regset.AMD64PtraceFpRegs)), 0, 0) _, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETFPREGS, uintptr(tid), uintptr(0), uintptr(unsafe.Pointer(&regset.AMD64PtraceFpRegs)), 0, 0)
if err == syscall.Errno(0) || err == syscall.ENODEV { if err == syscall.Errno(0) || err == syscall.ENODEV {
// ignore ENODEV, it just means this CPU doesn't have X87 registers (??) // ignore ENODEV, it just means this CPU doesn't have X87 registers (??)

@ -10,7 +10,7 @@ import (
) )
// SetPC sets EIP to the value specified by 'pc'. // SetPC sets EIP to the value specified by 'pc'.
func (thread *Thread) SetPC(pc uint64) error { func (thread *nativeThread) SetPC(pc uint64) error {
ir, err := registers(thread, false) ir, err := registers(thread, false)
if err != nil { if err != nil {
return err return err
@ -22,7 +22,7 @@ func (thread *Thread) SetPC(pc uint64) error {
} }
// SetSP sets ESP to the value specified by 'sp' // SetSP sets ESP to the value specified by 'sp'
func (thread *Thread) SetSP(sp uint64) (err error) { func (thread *nativeThread) SetSP(sp uint64) (err error) {
var ir proc.Registers var ir proc.Registers
ir, err = registers(thread, false) ir, err = registers(thread, false)
if err != nil { if err != nil {
@ -34,7 +34,7 @@ func (thread *Thread) SetSP(sp uint64) (err error) {
return return
} }
func (thread *Thread) SetDX(dx uint64) (err error) { func (thread *nativeThread) SetDX(dx uint64) (err error) {
var ir proc.Registers var ir proc.Registers
ir, err = registers(thread, false) ir, err = registers(thread, false)
if err != nil { if err != nil {
@ -46,7 +46,7 @@ func (thread *Thread) SetDX(dx uint64) (err error) {
return return
} }
func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) { func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error) {
var ( var (
regs linutil.I386PtraceRegs regs linutil.I386PtraceRegs
err error err error
@ -65,7 +65,7 @@ func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) {
} }
} }
thread.dbp.execPtraceFunc(func() { thread.dbp.execPtraceFunc(func() {
tls, _ := PtraceGetTls(regs.Xgs, thread.ThreadID()) tls, _ := ptraceGetTls(regs.Xgs, thread.ThreadID())
r.Tls = uint64(tls) r.Tls = uint64(tls)
}) })
return r, nil return r, nil
@ -81,8 +81,8 @@ const (
_XSAVE_SSE_REGION_LEN = 416 _XSAVE_SSE_REGION_LEN = 416
) )
func (thread *Thread) fpRegisters() (regs []proc.Register, fpregs linutil.I386Xstate, err error) { func (thread *nativeThread) fpRegisters() (regs []proc.Register, fpregs linutil.I386Xstate, err error) {
thread.dbp.execPtraceFunc(func() { fpregs, err = PtraceGetRegset(thread.ID) }) thread.dbp.execPtraceFunc(func() { fpregs, err = ptraceGetRegset(thread.ID) })
regs = fpregs.Decode() regs = fpregs.Decode()
if err != nil { if err != nil {
err = fmt.Errorf("could not get floating point registers: %v", err.Error()) err = fmt.Errorf("could not get floating point registers: %v", err.Error())

@ -111,7 +111,7 @@ func (r *Regs) GAddr() (uint64, bool) {
} }
// SetPC sets the RIP register to the value specified by `pc`. // SetPC sets the RIP register to the value specified by `pc`.
func (thread *Thread) SetPC(pc uint64) error { func (thread *nativeThread) SetPC(pc uint64) error {
kret := C.set_pc(thread.os.threadAct, C.uint64_t(pc)) kret := C.set_pc(thread.os.threadAct, C.uint64_t(pc))
if kret != C.KERN_SUCCESS { if kret != C.KERN_SUCCESS {
return fmt.Errorf("could not set pc") return fmt.Errorf("could not set pc")
@ -120,11 +120,11 @@ func (thread *Thread) SetPC(pc uint64) error {
} }
// SetSP sets the RSP register to the value specified by `pc`. // SetSP sets the RSP register to the value specified by `pc`.
func (thread *Thread) SetSP(sp uint64) error { func (thread *nativeThread) SetSP(sp uint64) error {
return errors.New("not implemented") return errors.New("not implemented")
} }
func (thread *Thread) SetDX(dx uint64) error { func (thread *nativeThread) SetDX(dx uint64) error {
return errors.New("not implemented") return errors.New("not implemented")
} }
@ -285,7 +285,7 @@ func (r *Regs) Get(n int) (uint64, error) {
return 0, proc.ErrUnknownRegister return 0, proc.ErrUnknownRegister
} }
func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) { func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error) {
var state C.x86_thread_state64_t var state C.x86_thread_state64_t
var identity C.thread_identifier_info_data_t var identity C.thread_identifier_info_data_t
kret := C.get_registers(C.mach_port_name_t(thread.os.threadAct), &state) kret := C.get_registers(C.mach_port_name_t(thread.os.threadAct), &state)

@ -10,7 +10,7 @@ import (
) )
// SetPC sets RIP to the value specified by 'pc'. // SetPC sets RIP to the value specified by 'pc'.
func (thread *Thread) SetPC(pc uint64) error { func (thread *nativeThread) SetPC(pc uint64) error {
ir, err := registers(thread, false) ir, err := registers(thread, false)
if err != nil { if err != nil {
return err return err
@ -22,7 +22,7 @@ func (thread *Thread) SetPC(pc uint64) error {
} }
// SetSP sets RSP to the value specified by 'sp' // SetSP sets RSP to the value specified by 'sp'
func (thread *Thread) SetSP(sp uint64) (err error) { func (thread *nativeThread) SetSP(sp uint64) (err error) {
var ir proc.Registers var ir proc.Registers
ir, err = registers(thread, false) ir, err = registers(thread, false)
if err != nil { if err != nil {
@ -34,7 +34,7 @@ func (thread *Thread) SetSP(sp uint64) (err error) {
return return
} }
func (thread *Thread) SetDX(dx uint64) (err error) { func (thread *nativeThread) SetDX(dx uint64) (err error) {
var ir proc.Registers var ir proc.Registers
ir, err = registers(thread, false) ir, err = registers(thread, false)
if err != nil { if err != nil {
@ -46,7 +46,7 @@ func (thread *Thread) SetDX(dx uint64) (err error) {
return return
} }
func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) { func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error) {
var ( var (
regs fbsdutil.AMD64PtraceRegs regs fbsdutil.AMD64PtraceRegs
err error err error
@ -82,8 +82,8 @@ const (
_XSAVE_SSE_REGION_LEN = 416 _XSAVE_SSE_REGION_LEN = 416
) )
func (thread *Thread) fpRegisters() (regs []proc.Register, fpregs fbsdutil.AMD64Xstate, err error) { func (thread *nativeThread) fpRegisters() (regs []proc.Register, fpregs fbsdutil.AMD64Xstate, err error) {
thread.dbp.execPtraceFunc(func() { fpregs, err = PtraceGetRegset(thread.ID) }) thread.dbp.execPtraceFunc(func() { fpregs, err = ptraceGetRegset(thread.ID) })
if err != nil { if err != nil {
err = fmt.Errorf("could not get floating point registers: %v", err.Error()) err = fmt.Errorf("could not get floating point registers: %v", err.Error())
} }

@ -10,7 +10,7 @@ import (
) )
// SetPC sets RIP to the value specified by 'pc'. // SetPC sets RIP to the value specified by 'pc'.
func (thread *Thread) SetPC(pc uint64) error { func (thread *nativeThread) SetPC(pc uint64) error {
ir, err := registers(thread, false) ir, err := registers(thread, false)
if err != nil { if err != nil {
return err return err
@ -22,7 +22,7 @@ func (thread *Thread) SetPC(pc uint64) error {
} }
// SetSP sets RSP to the value specified by 'sp' // SetSP sets RSP to the value specified by 'sp'
func (thread *Thread) SetSP(sp uint64) (err error) { func (thread *nativeThread) SetSP(sp uint64) (err error) {
var ir proc.Registers var ir proc.Registers
ir, err = registers(thread, false) ir, err = registers(thread, false)
if err != nil { if err != nil {
@ -34,7 +34,7 @@ func (thread *Thread) SetSP(sp uint64) (err error) {
return return
} }
func (thread *Thread) SetDX(dx uint64) (err error) { func (thread *nativeThread) SetDX(dx uint64) (err error) {
var ir proc.Registers var ir proc.Registers
ir, err = registers(thread, false) ir, err = registers(thread, false)
if err != nil { if err != nil {
@ -46,7 +46,7 @@ func (thread *Thread) SetDX(dx uint64) (err error) {
return return
} }
func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) { func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error) {
var ( var (
regs linutil.AMD64PtraceRegs regs linutil.AMD64PtraceRegs
err error err error
@ -77,8 +77,8 @@ const (
_XSAVE_SSE_REGION_LEN = 416 _XSAVE_SSE_REGION_LEN = 416
) )
func (thread *Thread) fpRegisters() (regs []proc.Register, fpregs linutil.AMD64Xstate, err error) { func (thread *nativeThread) fpRegisters() (regs []proc.Register, fpregs linutil.AMD64Xstate, err error) {
thread.dbp.execPtraceFunc(func() { fpregs, err = PtraceGetRegset(thread.ID) }) thread.dbp.execPtraceFunc(func() { fpregs, err = ptraceGetRegset(thread.ID) })
regs = fpregs.Decode() regs = fpregs.Decode()
if err != nil { if err != nil {
err = fmt.Errorf("could not get floating point registers: %v", err.Error()) err = fmt.Errorf("could not get floating point registers: %v", err.Error())

@ -13,12 +13,12 @@ import (
) )
const ( const (
AARCH64_GREGS_SIZE = 34 * 8 _AARCH64_GREGS_SIZE = 34 * 8
AARCH64_FPREGS_SIZE = 32*16 + 8 _AARCH64_FPREGS_SIZE = 32*16 + 8
) )
func ptraceGetGRegs(pid int, regs *linutil.ARM64PtraceRegs) (err error) { func ptraceGetGRegs(pid int, regs *linutil.ARM64PtraceRegs) (err error) {
iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(regs)), Len: AARCH64_GREGS_SIZE} iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(regs)), Len: _AARCH64_GREGS_SIZE}
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETREGSET, uintptr(pid), uintptr(elf.NT_PRSTATUS), uintptr(unsafe.Pointer(&iov)), 0, 0) _, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETREGSET, uintptr(pid), uintptr(elf.NT_PRSTATUS), uintptr(unsafe.Pointer(&iov)), 0, 0)
if err == syscall.Errno(0) { if err == syscall.Errno(0) {
err = nil err = nil
@ -27,7 +27,7 @@ func ptraceGetGRegs(pid int, regs *linutil.ARM64PtraceRegs) (err error) {
} }
func ptraceSetGRegs(pid int, regs *linutil.ARM64PtraceRegs) (err error) { func ptraceSetGRegs(pid int, regs *linutil.ARM64PtraceRegs) (err error) {
iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(regs)), Len: AARCH64_GREGS_SIZE} iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(regs)), Len: _AARCH64_GREGS_SIZE}
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_SETREGSET, uintptr(pid), uintptr(elf.NT_PRSTATUS), uintptr(unsafe.Pointer(&iov)), 0, 0) _, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_SETREGSET, uintptr(pid), uintptr(elf.NT_PRSTATUS), uintptr(unsafe.Pointer(&iov)), 0, 0)
if err == syscall.Errno(0) { if err == syscall.Errno(0) {
err = nil err = nil
@ -35,11 +35,11 @@ func ptraceSetGRegs(pid int, regs *linutil.ARM64PtraceRegs) (err error) {
return return
} }
// PtraceGetFpRegset returns floating point registers of the specified thread // ptraceGetFpRegset returns floating point registers of the specified thread
// using PTRACE. // using PTRACE.
func PtraceGetFpRegset(tid int) (fpregset []byte, err error) { func ptraceGetFpRegset(tid int) (fpregset []byte, err error) {
var arm64_fpregs [AARCH64_FPREGS_SIZE]byte var arm64_fpregs [_AARCH64_FPREGS_SIZE]byte
iov := sys.Iovec{Base: &arm64_fpregs[0], Len: AARCH64_FPREGS_SIZE} iov := sys.Iovec{Base: &arm64_fpregs[0], Len: _AARCH64_FPREGS_SIZE}
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETREGSET, uintptr(tid), uintptr(elf.NT_FPREGSET), uintptr(unsafe.Pointer(&iov)), 0, 0) _, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETREGSET, uintptr(tid), uintptr(elf.NT_FPREGSET), uintptr(unsafe.Pointer(&iov)), 0, 0)
if err != syscall.Errno(0) { if err != syscall.Errno(0) {
if err == syscall.ENODEV { if err == syscall.ENODEV {
@ -55,7 +55,7 @@ func PtraceGetFpRegset(tid int) (fpregset []byte, err error) {
} }
// SetPC sets PC to the value specified by 'pc'. // SetPC sets PC to the value specified by 'pc'.
func (thread *Thread) SetPC(pc uint64) error { func (thread *nativeThread) SetPC(pc uint64) error {
ir, err := registers(thread, false) ir, err := registers(thread, false)
if err != nil { if err != nil {
return err return err
@ -67,7 +67,7 @@ func (thread *Thread) SetPC(pc uint64) error {
} }
// SetSP sets RSP to the value specified by 'sp' // SetSP sets RSP to the value specified by 'sp'
func (thread *Thread) SetSP(sp uint64) (err error) { func (thread *nativeThread) SetSP(sp uint64) (err error) {
var ir proc.Registers var ir proc.Registers
ir, err = registers(thread, false) ir, err = registers(thread, false)
if err != nil { if err != nil {
@ -79,11 +79,11 @@ func (thread *Thread) SetSP(sp uint64) (err error) {
return return
} }
func (thread *Thread) SetDX(dx uint64) (err error) { func (thread *nativeThread) SetDX(dx uint64) (err error) {
return fmt.Errorf("not supported") return fmt.Errorf("not supported")
} }
func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) { func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error) {
var ( var (
regs linutil.ARM64PtraceRegs regs linutil.ARM64PtraceRegs
err error err error

@ -9,7 +9,7 @@ import (
) )
// SetPC sets the RIP register to the value specified by `pc`. // SetPC sets the RIP register to the value specified by `pc`.
func (thread *Thread) SetPC(pc uint64) error { func (thread *nativeThread) SetPC(pc uint64) error {
context := winutil.NewCONTEXT() context := winutil.NewCONTEXT()
context.ContextFlags = _CONTEXT_ALL context.ContextFlags = _CONTEXT_ALL
@ -24,7 +24,7 @@ func (thread *Thread) SetPC(pc uint64) error {
} }
// SetSP sets the RSP register to the value specified by `sp`. // SetSP sets the RSP register to the value specified by `sp`.
func (thread *Thread) SetSP(sp uint64) error { func (thread *nativeThread) SetSP(sp uint64) error {
context := winutil.NewCONTEXT() context := winutil.NewCONTEXT()
context.ContextFlags = _CONTEXT_ALL context.ContextFlags = _CONTEXT_ALL
@ -38,7 +38,7 @@ func (thread *Thread) SetSP(sp uint64) error {
return _SetThreadContext(thread.os.hThread, context) return _SetThreadContext(thread.os.hThread, context)
} }
func (thread *Thread) SetDX(dx uint64) error { func (thread *nativeThread) SetDX(dx uint64) error {
context := winutil.NewCONTEXT() context := winutil.NewCONTEXT()
context.ContextFlags = _CONTEXT_ALL context.ContextFlags = _CONTEXT_ALL
@ -52,7 +52,7 @@ func (thread *Thread) SetDX(dx uint64) error {
return _SetThreadContext(thread.os.hThread, context) return _SetThreadContext(thread.os.hThread, context)
} }
func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) { func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error) {
context := winutil.NewCONTEXT() context := winutil.NewCONTEXT()
context.ContextFlags = _CONTEXT_ALL context.ContextFlags = _CONTEXT_ALL

@ -11,14 +11,14 @@ import (
// Process struct that contains info on the process as // Process struct that contains info on the process as
// a whole, and Status represents the last result of a `wait` call // a whole, and Status represents the last result of a `wait` call
// on this thread. // on this thread.
type Thread struct { type nativeThread struct {
ID int // Thread ID or mach port ID int // Thread ID or mach port
Status *WaitStatus // Status returned from last wait call Status *waitStatus // Status returned from last wait call
CurrentBreakpoint proc.BreakpointState // Breakpoint thread is currently stopped at CurrentBreakpoint proc.BreakpointState // Breakpoint thread is currently stopped at
dbp *Process dbp *nativeProcess
singleStepping bool singleStepping bool
os *OSSpecificDetails os *osSpecificDetails
common proc.CommonThread common proc.CommonThread
} }
@ -27,7 +27,7 @@ type Thread struct {
// If we are currently at a breakpoint, we'll clear it // If we are currently at a breakpoint, we'll clear it
// first and then resume execution. Thread will continue until // first and then resume execution. Thread will continue until
// it hits a breakpoint or is signaled. // it hits a breakpoint or is signaled.
func (t *Thread) Continue() error { func (t *nativeThread) Continue() error {
pc, err := t.PC() pc, err := t.PC()
if err != nil { if err != nil {
return err return err
@ -48,7 +48,7 @@ func (t *Thread) Continue() error {
// If the thread is at a breakpoint, we first clear it, // If the thread is at a breakpoint, we first clear it,
// execute the instruction, and then replace the breakpoint. // execute the instruction, and then replace the breakpoint.
// Otherwise we simply execute the next instruction. // Otherwise we simply execute the next instruction.
func (t *Thread) StepInstruction() (err error) { func (t *nativeThread) StepInstruction() (err error) {
t.singleStepping = true t.singleStepping = true
defer func() { defer func() {
t.singleStepping = false t.singleStepping = false
@ -85,7 +85,7 @@ func (t *Thread) StepInstruction() (err error) {
// Location returns the threads location, including the file:line // Location returns the threads location, including the file:line
// of the corresponding source code, the function we're in // of the corresponding source code, the function we're in
// and the current instruction address. // and the current instruction address.
func (t *Thread) Location() (*proc.Location, error) { func (t *nativeThread) Location() (*proc.Location, error) {
pc, err := t.PC() pc, err := t.PC()
if err != nil { if err != nil {
return nil, err return nil, err
@ -95,19 +95,19 @@ func (t *Thread) Location() (*proc.Location, error) {
} }
// BinInfo returns information on the binary. // BinInfo returns information on the binary.
func (t *Thread) BinInfo() *proc.BinaryInfo { func (t *nativeThread) BinInfo() *proc.BinaryInfo {
return t.dbp.bi return t.dbp.bi
} }
// Common returns information common across Process // Common returns information common across Process
// implementations. // implementations.
func (t *Thread) Common() *proc.CommonThread { func (t *nativeThread) Common() *proc.CommonThread {
return &t.common return &t.common
} }
// SetCurrentBreakpoint sets the current breakpoint that this // SetCurrentBreakpoint sets the current breakpoint that this
// thread is stopped at as CurrentBreakpoint on the thread struct. // thread is stopped at as CurrentBreakpoint on the thread struct.
func (t *Thread) SetCurrentBreakpoint(adjustPC bool) error { func (t *nativeThread) SetCurrentBreakpoint(adjustPC bool) error {
t.CurrentBreakpoint.Clear() t.CurrentBreakpoint.Clear()
pc, err := t.PC() pc, err := t.PC()
if err != nil { if err != nil {
@ -139,17 +139,17 @@ func (t *Thread) SetCurrentBreakpoint(adjustPC bool) error {
// Breakpoint returns the current breakpoint that is active // Breakpoint returns the current breakpoint that is active
// on this thread. // on this thread.
func (t *Thread) Breakpoint() *proc.BreakpointState { func (t *nativeThread) Breakpoint() *proc.BreakpointState {
return &t.CurrentBreakpoint return &t.CurrentBreakpoint
} }
// ThreadID returns the ID of this thread. // ThreadID returns the ID of this thread.
func (t *Thread) ThreadID() int { func (t *nativeThread) ThreadID() int {
return t.ID return t.ID
} }
// ClearBreakpoint clears the specified breakpoint. // ClearBreakpoint clears the specified breakpoint.
func (t *Thread) ClearBreakpoint(bp *proc.Breakpoint) error { func (t *nativeThread) ClearBreakpoint(bp *proc.Breakpoint) error {
if _, err := t.WriteMemory(uintptr(bp.Addr), bp.OriginalData); err != nil { if _, err := t.WriteMemory(uintptr(bp.Addr), bp.OriginalData); err != nil {
return fmt.Errorf("could not clear breakpoint %s", err) return fmt.Errorf("could not clear breakpoint %s", err)
} }
@ -157,18 +157,18 @@ func (t *Thread) ClearBreakpoint(bp *proc.Breakpoint) error {
} }
// Registers obtains register values from the debugged process. // Registers obtains register values from the debugged process.
func (t *Thread) Registers(floatingPoint bool) (proc.Registers, error) { func (t *nativeThread) Registers(floatingPoint bool) (proc.Registers, error) {
return registers(t, floatingPoint) return registers(t, floatingPoint)
} }
// RestoreRegisters will set the value of the CPU registers to those // RestoreRegisters will set the value of the CPU registers to those
// passed in via 'savedRegs'. // passed in via 'savedRegs'.
func (t *Thread) RestoreRegisters(savedRegs proc.Registers) error { func (t *nativeThread) RestoreRegisters(savedRegs proc.Registers) error {
return t.restoreRegisters(savedRegs) return t.restoreRegisters(savedRegs)
} }
// PC returns the current program counter value for this thread. // PC returns the current program counter value for this thread.
func (t *Thread) PC() (uint64, error) { func (t *nativeThread) PC() (uint64, error) {
regs, err := t.Registers(false) regs, err := t.Registers(false)
if err != nil { if err != nil {
return 0, err return 0, err

@ -15,12 +15,12 @@ import (
"github.com/go-delve/delve/pkg/proc" "github.com/go-delve/delve/pkg/proc"
) )
// WaitStatus is a synonym for the platform-specific WaitStatus // waitStatus is a synonym for the platform-specific WaitStatus
type WaitStatus sys.WaitStatus type waitStatus sys.WaitStatus
// OSSpecificDetails holds information specific to the OSX/Darwin // osSpecificDetails holds information specific to the OSX/Darwin
// operating system / kernel. // operating system / kernel.
type OSSpecificDetails struct { type osSpecificDetails struct {
threadAct C.thread_act_t threadAct C.thread_act_t
registers C.x86_thread_state64_t registers C.x86_thread_state64_t
exists bool exists bool
@ -30,7 +30,7 @@ type OSSpecificDetails struct {
// be continued. // be continued.
var ErrContinueThread = fmt.Errorf("could not continue thread") var ErrContinueThread = fmt.Errorf("could not continue thread")
func (t *Thread) stop() (err error) { func (t *nativeThread) stop() (err error) {
kret := C.thread_suspend(t.os.threadAct) kret := C.thread_suspend(t.os.threadAct)
if kret != C.KERN_SUCCESS { if kret != C.KERN_SUCCESS {
errStr := C.GoString(C.mach_error_string(C.mach_error_t(kret))) errStr := C.GoString(C.mach_error_string(C.mach_error_t(kret)))
@ -49,7 +49,7 @@ func (t *Thread) stop() (err error) {
return return
} }
func (t *Thread) singleStep() error { func (t *nativeThread) singleStep() error {
kret := C.single_step(t.os.threadAct) kret := C.single_step(t.os.threadAct)
if kret != C.KERN_SUCCESS { if kret != C.KERN_SUCCESS {
return fmt.Errorf("could not single step") return fmt.Errorf("could not single step")
@ -71,10 +71,10 @@ func (t *Thread) singleStep() error {
return nil return nil
} }
func (t *Thread) resume() error { func (t *nativeThread) resume() error {
// TODO(dp) set flag for ptrace stops // TODO(dp) set flag for ptrace stops
var err error var err error
t.dbp.execPtraceFunc(func() { err = PtraceCont(t.dbp.pid, 0) }) t.dbp.execPtraceFunc(func() { err = ptraceCont(t.dbp.pid, 0) })
if err == nil { if err == nil {
return nil return nil
} }
@ -85,7 +85,7 @@ func (t *Thread) resume() error {
return nil return nil
} }
func (t *Thread) Blocked() bool { func (t *nativeThread) Blocked() bool {
// TODO(dp) cache the func pc to remove this lookup // TODO(dp) cache the func pc to remove this lookup
regs, err := t.Registers(false) regs, err := t.Registers(false)
if err != nil { if err != nil {
@ -106,11 +106,11 @@ func (t *Thread) Blocked() bool {
// Stopped returns whether the thread is stopped at // Stopped returns whether the thread is stopped at
// the operating system level. // the operating system level.
func (t *Thread) Stopped() bool { func (t *nativeThread) Stopped() bool {
return C.thread_blocked(t.os.threadAct) > C.int(0) return C.thread_blocked(t.os.threadAct) > C.int(0)
} }
func (t *Thread) WriteMemory(addr uintptr, data []byte) (int, error) { func (t *nativeThread) WriteMemory(addr uintptr, data []byte) (int, error) {
if t.dbp.exited { if t.dbp.exited {
return 0, proc.ErrProcessExited{Pid: t.dbp.pid} return 0, proc.ErrProcessExited{Pid: t.dbp.pid}
} }
@ -128,7 +128,7 @@ func (t *Thread) WriteMemory(addr uintptr, data []byte) (int, error) {
return len(data), nil return len(data), nil
} }
func (t *Thread) ReadMemory(buf []byte, addr uintptr) (int, error) { func (t *nativeThread) ReadMemory(buf []byte, addr uintptr) (int, error) {
if t.dbp.exited { if t.dbp.exited {
return 0, proc.ErrProcessExited{Pid: t.dbp.pid} return 0, proc.ErrProcessExited{Pid: t.dbp.pid}
} }
@ -148,6 +148,6 @@ func (t *Thread) ReadMemory(buf []byte, addr uintptr) (int, error) {
return len(buf), nil return len(buf), nil
} }
func (t *Thread) restoreRegisters(sr proc.Registers) error { func (t *nativeThread) restoreRegisters(sr proc.Registers) error {
return errors.New("not implemented") return errors.New("not implemented")
} }

@ -13,14 +13,14 @@ import (
"github.com/go-delve/delve/pkg/proc" "github.com/go-delve/delve/pkg/proc"
) )
type WaitStatus sys.WaitStatus type waitStatus sys.WaitStatus
// OSSpecificDetails hold FreeBSD specific process details. // osSpecificDetails hold FreeBSD specific process details.
type OSSpecificDetails struct { type osSpecificDetails struct {
registers sys.Reg registers sys.Reg
} }
func (t *Thread) stop() (err error) { func (t *nativeThread) stop() (err error) {
_, err = C.thr_kill2(C.pid_t(t.dbp.pid), C.long(t.ID), C.int(sys.SIGSTOP)) _, err = C.thr_kill2(C.pid_t(t.dbp.pid), C.long(t.ID), C.int(sys.SIGSTOP))
if err != nil { if err != nil {
err = fmt.Errorf("stop err %s on thread %d", err, t.ID) err = fmt.Errorf("stop err %s on thread %d", err, t.ID)
@ -28,7 +28,7 @@ func (t *Thread) stop() (err error) {
} }
// If the process is stopped, we must continue it so it can receive the // If the process is stopped, we must continue it so it can receive the
// signal // signal
t.dbp.execPtraceFunc(func() { err = PtraceCont(t.dbp.pid, 0) }) t.dbp.execPtraceFunc(func() { err = ptraceCont(t.dbp.pid, 0) })
if err != nil { if err != nil {
return err return err
} }
@ -40,22 +40,22 @@ func (t *Thread) stop() (err error) {
return return
} }
func (t *Thread) Stopped() bool { func (t *nativeThread) Stopped() bool {
state := status(t.dbp.pid) state := status(t.dbp.pid)
return state == StatusStopped return state == statusStopped
} }
func (t *Thread) resume() error { func (t *nativeThread) resume() error {
return t.resumeWithSig(0) return t.resumeWithSig(0)
} }
func (t *Thread) resumeWithSig(sig int) (err error) { func (t *nativeThread) resumeWithSig(sig int) (err error) {
t.dbp.execPtraceFunc(func() { err = PtraceCont(t.ID, sig) }) t.dbp.execPtraceFunc(func() { err = ptraceCont(t.ID, sig) })
return return
} }
func (t *Thread) singleStep() (err error) { func (t *nativeThread) singleStep() (err error) {
t.dbp.execPtraceFunc(func() { err = PtraceSingleStep(t.ID) }) t.dbp.execPtraceFunc(func() { err = ptraceSingleStep(t.ID) })
if err != nil { if err != nil {
return err return err
} }
@ -67,7 +67,7 @@ func (t *Thread) singleStep() (err error) {
if th.ID == t.ID { if th.ID == t.ID {
break break
} }
t.dbp.execPtraceFunc(func() { err = PtraceCont(th.ID, 0) }) t.dbp.execPtraceFunc(func() { err = ptraceCont(th.ID, 0) })
if err != nil { if err != nil {
return err return err
} }
@ -75,7 +75,7 @@ func (t *Thread) singleStep() (err error) {
return nil return nil
} }
func (t *Thread) Blocked() bool { func (t *nativeThread) Blocked() bool {
loc, err := t.Location() loc, err := t.Location()
if err != nil { if err != nil {
return false return false
@ -86,7 +86,7 @@ func (t *Thread) Blocked() bool {
return false return false
} }
func (t *Thread) restoreRegisters(savedRegs proc.Registers) error { func (t *nativeThread) restoreRegisters(savedRegs proc.Registers) error {
sr := savedRegs.(*fbsdutil.AMD64Registers) sr := savedRegs.(*fbsdutil.AMD64Registers)
var restoreRegistersErr error var restoreRegistersErr error
@ -110,7 +110,7 @@ func (t *Thread) restoreRegisters(savedRegs proc.Registers) error {
return restoreRegistersErr return restoreRegistersErr
} }
func (t *Thread) WriteMemory(addr uintptr, data []byte) (written int, err error) { func (t *nativeThread) WriteMemory(addr uintptr, data []byte) (written int, err error) {
if t.dbp.exited { if t.dbp.exited {
return 0, proc.ErrProcessExited{Pid: t.dbp.pid} return 0, proc.ErrProcessExited{Pid: t.dbp.pid}
} }
@ -121,7 +121,7 @@ func (t *Thread) WriteMemory(addr uintptr, data []byte) (written int, err error)
return written, err return written, err
} }
func (t *Thread) ReadMemory(data []byte, addr uintptr) (n int, err error) { func (t *nativeThread) ReadMemory(data []byte, addr uintptr) (n int, err error) {
if t.dbp.exited { if t.dbp.exited {
return 0, proc.ErrProcessExited{Pid: t.dbp.pid} return 0, proc.ErrProcessExited{Pid: t.dbp.pid}
} }

@ -8,18 +8,18 @@ import (
"github.com/go-delve/delve/pkg/proc" "github.com/go-delve/delve/pkg/proc"
) )
type WaitStatus sys.WaitStatus type waitStatus sys.WaitStatus
// OSSpecificDetails hold Linux specific // osSpecificDetails hold Linux specific
// process details. // process details.
type OSSpecificDetails struct { type osSpecificDetails struct {
delayedSignal int delayedSignal int
registers sys.PtraceRegs registers sys.PtraceRegs
running bool running bool
setbp bool setbp bool
} }
func (t *Thread) stop() (err error) { func (t *nativeThread) stop() (err error) {
err = sys.Tgkill(t.dbp.pid, t.ID, sys.SIGSTOP) err = sys.Tgkill(t.dbp.pid, t.ID, sys.SIGSTOP)
if err != nil { if err != nil {
err = fmt.Errorf("stop err %s on thread %d", err, t.ID) err = fmt.Errorf("stop err %s on thread %d", err, t.ID)
@ -30,24 +30,24 @@ func (t *Thread) stop() (err error) {
// Stopped returns whether the thread is stopped at // Stopped returns whether the thread is stopped at
// the operating system level. // the operating system level.
func (t *Thread) Stopped() bool { func (t *nativeThread) Stopped() bool {
state := status(t.ID, t.dbp.os.comm) state := status(t.ID, t.dbp.os.comm)
return state == StatusTraceStop || state == StatusTraceStopT return state == statusTraceStop || state == statusTraceStopT
} }
func (t *Thread) resume() error { func (t *nativeThread) resume() error {
sig := t.os.delayedSignal sig := t.os.delayedSignal
t.os.delayedSignal = 0 t.os.delayedSignal = 0
return t.resumeWithSig(sig) return t.resumeWithSig(sig)
} }
func (t *Thread) resumeWithSig(sig int) (err error) { func (t *nativeThread) resumeWithSig(sig int) (err error) {
t.os.running = true t.os.running = true
t.dbp.execPtraceFunc(func() { err = PtraceCont(t.ID, sig) }) t.dbp.execPtraceFunc(func() { err = ptraceCont(t.ID, sig) })
return return
} }
func (t *Thread) singleStep() (err error) { func (t *nativeThread) singleStep() (err error) {
for { for {
t.dbp.execPtraceFunc(func() { err = sys.PtraceSingleStep(t.ID) }) t.dbp.execPtraceFunc(func() { err = sys.PtraceSingleStep(t.ID) })
if err != nil { if err != nil {
@ -71,7 +71,7 @@ func (t *Thread) singleStep() (err error) {
} }
} }
func (t *Thread) Blocked() bool { func (t *nativeThread) Blocked() bool {
regs, err := t.Registers(false) regs, err := t.Registers(false)
if err != nil { if err != nil {
return false return false
@ -84,7 +84,7 @@ func (t *Thread) Blocked() bool {
return false return false
} }
func (t *Thread) WriteMemory(addr uintptr, data []byte) (written int, err error) { func (t *nativeThread) WriteMemory(addr uintptr, data []byte) (written int, err error) {
if t.dbp.exited { if t.dbp.exited {
return 0, proc.ErrProcessExited{Pid: t.dbp.pid} return 0, proc.ErrProcessExited{Pid: t.dbp.pid}
} }
@ -94,7 +94,7 @@ func (t *Thread) WriteMemory(addr uintptr, data []byte) (written int, err error)
// ProcessVmWrite can't poke read-only memory like ptrace, so don't // ProcessVmWrite can't poke read-only memory like ptrace, so don't
// even bother for small writes -- likely breakpoints and such. // even bother for small writes -- likely breakpoints and such.
if len(data) > sys.SizeofPtr { if len(data) > sys.SizeofPtr {
written, _ = ProcessVmWrite(t.ID, addr, data) written, _ = processVmWrite(t.ID, addr, data)
} }
if written == 0 { if written == 0 {
t.dbp.execPtraceFunc(func() { written, err = sys.PtracePokeData(t.ID, addr, data) }) t.dbp.execPtraceFunc(func() { written, err = sys.PtracePokeData(t.ID, addr, data) })
@ -102,14 +102,14 @@ func (t *Thread) WriteMemory(addr uintptr, data []byte) (written int, err error)
return return
} }
func (t *Thread) ReadMemory(data []byte, addr uintptr) (n int, err error) { func (t *nativeThread) ReadMemory(data []byte, addr uintptr) (n int, err error) {
if t.dbp.exited { if t.dbp.exited {
return 0, proc.ErrProcessExited{Pid: t.dbp.pid} return 0, proc.ErrProcessExited{Pid: t.dbp.pid}
} }
if len(data) == 0 { if len(data) == 0 {
return return
} }
n, _ = ProcessVmRead(t.ID, addr, data) n, _ = processVmRead(t.ID, addr, data)
if n == 0 { if n == 0 {
t.dbp.execPtraceFunc(func() { n, err = sys.PtracePeekData(t.ID, addr, data) }) t.dbp.execPtraceFunc(func() { n, err = sys.PtracePeekData(t.ID, addr, data) })
} }

@ -5,6 +5,6 @@ import (
"github.com/go-delve/delve/pkg/proc" "github.com/go-delve/delve/pkg/proc"
) )
func (t *Thread) restoreRegisters(savedRegs proc.Registers) error { func (t *nativeThread) restoreRegisters(savedRegs proc.Registers) error {
return fmt.Errorf("restore regs not supported on i386") return fmt.Errorf("restore regs not supported on i386")
} }

@ -10,7 +10,7 @@ import (
"github.com/go-delve/delve/pkg/proc/linutil" "github.com/go-delve/delve/pkg/proc/linutil"
) )
func (t *Thread) restoreRegisters(savedRegs proc.Registers) error { func (t *nativeThread) restoreRegisters(savedRegs proc.Registers) error {
sr := savedRegs.(*linutil.AMD64Registers) sr := savedRegs.(*linutil.AMD64Registers)
var restoreRegistersErr error var restoreRegistersErr error

@ -12,10 +12,10 @@ import (
"github.com/go-delve/delve/pkg/proc/linutil" "github.com/go-delve/delve/pkg/proc/linutil"
) )
func (thread *Thread) fpRegisters() ([]proc.Register, []byte, error) { func (thread *nativeThread) fpRegisters() ([]proc.Register, []byte, error) {
var err error var err error
var arm_fpregs linutil.ARM64PtraceFpRegs var arm_fpregs linutil.ARM64PtraceFpRegs
thread.dbp.execPtraceFunc(func() { arm_fpregs.Vregs, err = PtraceGetFpRegset(thread.ID) }) thread.dbp.execPtraceFunc(func() { arm_fpregs.Vregs, err = ptraceGetFpRegset(thread.ID) })
fpregs := arm_fpregs.Decode() fpregs := arm_fpregs.Decode()
if err != nil { if err != nil {
err = fmt.Errorf("could not get floating point registers: %v", err.Error()) err = fmt.Errorf("could not get floating point registers: %v", err.Error())
@ -23,7 +23,7 @@ func (thread *Thread) fpRegisters() ([]proc.Register, []byte, error) {
return fpregs, arm_fpregs.Vregs, err return fpregs, arm_fpregs.Vregs, err
} }
func (t *Thread) restoreRegisters(savedRegs proc.Registers) error { func (t *nativeThread) restoreRegisters(savedRegs proc.Registers) error {
sr := savedRegs.(*linutil.ARM64Registers) sr := savedRegs.(*linutil.ARM64Registers)
var restoreRegistersErr error var restoreRegistersErr error

@ -10,16 +10,16 @@ import (
"github.com/go-delve/delve/pkg/proc/winutil" "github.com/go-delve/delve/pkg/proc/winutil"
) )
// WaitStatus is a synonym for the platform-specific WaitStatus // waitStatus is a synonym for the platform-specific WaitStatus
type WaitStatus sys.WaitStatus type waitStatus sys.WaitStatus
// OSSpecificDetails holds information specific to the Windows // osSpecificDetails holds information specific to the Windows
// operating system / kernel. // operating system / kernel.
type OSSpecificDetails struct { type osSpecificDetails struct {
hThread syscall.Handle hThread syscall.Handle
} }
func (t *Thread) singleStep() error { func (t *nativeThread) singleStep() error {
context := winutil.NewCONTEXT() context := winutil.NewCONTEXT()
context.ContextFlags = _CONTEXT_ALL context.ContextFlags = _CONTEXT_ALL
@ -101,7 +101,7 @@ func (t *Thread) singleStep() error {
return _SetThreadContext(t.os.hThread, context) return _SetThreadContext(t.os.hThread, context)
} }
func (t *Thread) resume() error { func (t *nativeThread) resume() error {
var err error var err error
t.dbp.execPtraceFunc(func() { t.dbp.execPtraceFunc(func() {
//TODO: Note that we are ignoring the thread we were asked to continue and are continuing the //TODO: Note that we are ignoring the thread we were asked to continue and are continuing the
@ -111,7 +111,7 @@ func (t *Thread) resume() error {
return err return err
} }
func (t *Thread) Blocked() bool { func (t *nativeThread) Blocked() bool {
// TODO: Probably incorrect - what are the runtime functions that // TODO: Probably incorrect - what are the runtime functions that
// indicate blocking on Windows? // indicate blocking on Windows?
regs, err := t.Registers(false) regs, err := t.Registers(false)
@ -133,11 +133,11 @@ func (t *Thread) Blocked() bool {
// Stopped returns whether the thread is stopped at the operating system // Stopped returns whether the thread is stopped at the operating system
// level. On windows this always returns true. // level. On windows this always returns true.
func (t *Thread) Stopped() bool { func (t *nativeThread) Stopped() bool {
return true return true
} }
func (t *Thread) WriteMemory(addr uintptr, data []byte) (int, error) { func (t *nativeThread) WriteMemory(addr uintptr, data []byte) (int, error) {
if t.dbp.exited { if t.dbp.exited {
return 0, proc.ErrProcessExited{Pid: t.dbp.pid} return 0, proc.ErrProcessExited{Pid: t.dbp.pid}
} }
@ -154,7 +154,7 @@ func (t *Thread) WriteMemory(addr uintptr, data []byte) (int, error) {
var ErrShortRead = errors.New("short read") var ErrShortRead = errors.New("short read")
func (t *Thread) ReadMemory(buf []byte, addr uintptr) (int, error) { func (t *nativeThread) ReadMemory(buf []byte, addr uintptr) (int, error) {
if t.dbp.exited { if t.dbp.exited {
return 0, proc.ErrProcessExited{Pid: t.dbp.pid} return 0, proc.ErrProcessExited{Pid: t.dbp.pid}
} }
@ -169,6 +169,6 @@ func (t *Thread) ReadMemory(buf []byte, addr uintptr) (int, error) {
return int(count), err return int(count), err
} }
func (t *Thread) restoreRegisters(savedRegs proc.Registers) error { func (t *nativeThread) restoreRegisters(savedRegs proc.Registers) error {
return _SetThreadContext(t.os.hThread, savedRegs.(*winutil.AMD64Registers).Context) return _SetThreadContext(t.os.hThread, savedRegs.(*winutil.AMD64Registers).Context)
} }

@ -239,12 +239,6 @@ func TestHalt(t *testing.T) {
withTestProcess("loopprog", t, func(p *proc.Target, fixture protest.Fixture) { withTestProcess("loopprog", t, func(p *proc.Target, fixture protest.Fixture) {
setFunctionBreakpoint(p, t, "main.loop") setFunctionBreakpoint(p, t, "main.loop")
assertNoError(p.Continue(), t, "Continue") assertNoError(p.Continue(), t, "Continue")
if p, ok := p.Process.(*native.Process); ok {
for _, th := range p.ThreadList() {
_, err := th.Registers(false)
assertNoError(err, t, "Registers")
}
}
resumeChan := make(chan struct{}, 1) resumeChan := make(chan struct{}, 1)
go func() { go func() {
<-resumeChan <-resumeChan
@ -258,21 +252,6 @@ func TestHalt(t *testing.T) {
if err, ok := retVal.(error); ok && err != nil { if err, ok := retVal.(error); ok && err != nil {
t.Fatal() t.Fatal()
} }
// Loop through threads and make sure they are all
// actually stopped, err will not be nil if the process
// is still running.
if p, ok := p.Process.(*native.Process); ok {
for _, th := range p.ThreadList() {
if th, ok := th.(*native.Thread); ok {
if !th.Stopped() {
t.Fatal("expected thread to be stopped, but was not")
}
}
_, err := th.Registers(false)
assertNoError(err, t, "Registers")
}
}
}) })
} }

@ -35,13 +35,13 @@ type Fixture struct {
} }
// FixtureKey holds the name and builds flags used for a test fixture. // FixtureKey holds the name and builds flags used for a test fixture.
type FixtureKey struct { type fixtureKey struct {
Name string Name string
Flags BuildFlags Flags BuildFlags
} }
// Fixtures is a map of fixtureKey{ Fixture.Name, buildFlags } to Fixture. // Fixtures is a map of fixtureKey{ Fixture.Name, buildFlags } to Fixture.
var Fixtures = make(map[FixtureKey]Fixture) var fixtures = make(map[fixtureKey]Fixture)
// PathsToRemove is a list of files and directories to remove after running all the tests // PathsToRemove is a list of files and directories to remove after running all the tests
var PathsToRemove []string var PathsToRemove []string
@ -84,8 +84,8 @@ func BuildFixture(name string, flags BuildFlags) Fixture {
if !runningWithFixtures { if !runningWithFixtures {
panic("RunTestsWithFixtures not called") panic("RunTestsWithFixtures not called")
} }
fk := FixtureKey{name, flags} fk := fixtureKey{name, flags}
if f, ok := Fixtures[fk]; ok { if f, ok := fixtures[fk]; ok {
return f return f
} }
@ -180,8 +180,8 @@ func BuildFixture(name string, flags BuildFlags) Fixture {
fixture := Fixture{Name: name, Path: tmpfile, Source: source, BuildDir: absdir} fixture := Fixture{Name: name, Path: tmpfile, Source: source, BuildDir: absdir}
Fixtures[fk] = fixture fixtures[fk] = fixture
return Fixtures[fk] return fixtures[fk]
} }
// RunTestsWithFixtures will pre-compile test fixtures before running test // RunTestsWithFixtures will pre-compile test fixtures before running test
@ -194,7 +194,7 @@ func RunTestsWithFixtures(m *testing.M) int {
status := m.Run() status := m.Run()
// Remove the fixtures. // Remove the fixtures.
for _, f := range Fixtures { for _, f := range fixtures {
os.Remove(f.Path) os.Remove(f.Path)
} }

@ -85,23 +85,23 @@ type Commands struct {
} }
var ( var (
// LongLoadConfig loads more information: // longLoadConfig loads more information:
// * Follows pointers // * Follows pointers
// * Loads more array values // * Loads more array values
// * Does not limit struct fields // * Does not limit struct fields
LongLoadConfig = api.LoadConfig{FollowPointers: true, MaxVariableRecurse: 1, MaxStringLen: 64, MaxArrayValues: 64, MaxStructFields: -1} longLoadConfig = api.LoadConfig{FollowPointers: true, MaxVariableRecurse: 1, MaxStringLen: 64, MaxArrayValues: 64, MaxStructFields: -1}
// ShortLoadConfig loads less information, not following pointers // ShortLoadConfig loads less information, not following pointers
// and limiting struct fields loaded to 3. // and limiting struct fields loaded to 3.
ShortLoadConfig = api.LoadConfig{MaxStringLen: 64, MaxStructFields: 3} ShortLoadConfig = api.LoadConfig{MaxStringLen: 64, MaxStructFields: 3}
) )
// ByFirstAlias will sort by the first // byFirstAlias will sort by the first
// alias of a command. // alias of a command.
type ByFirstAlias []command type byFirstAlias []command
func (a ByFirstAlias) Len() int { return len(a) } func (a byFirstAlias) Len() int { return len(a) }
func (a ByFirstAlias) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a byFirstAlias) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByFirstAlias) Less(i, j int) bool { return a[i].aliases[0] < a[j].aliases[0] } func (a byFirstAlias) Less(i, j int) bool { return a[i].aliases[0] < a[j].aliases[0] }
// DebugCommands returns a Commands struct with default commands defined. // DebugCommands returns a Commands struct with default commands defined.
func DebugCommands(client service.Client) *Commands { func DebugCommands(client service.Client) *Commands {
@ -443,7 +443,7 @@ Currently, only the rev step-instruction command is supported.`,
}) })
} }
sort.Sort(ByFirstAlias(c.cmds)) sort.Sort(byFirstAlias(c.cmds))
return c return c
} }
@ -592,7 +592,7 @@ func threads(t *Term, ctx callContext, args string) error {
} }
if th.Function != nil { if th.Function != nil {
fmt.Printf("%sThread %d at %#v %s:%d %s\n", fmt.Printf("%sThread %d at %#v %s:%d %s\n",
prefix, th.ID, th.PC, ShortenFilePath(th.File), prefix, th.ID, th.PC, shortenFilePath(th.File),
th.Line, th.Function.Name()) th.Line, th.Function.Name())
} else { } else {
fmt.Printf("%sThread %s\n", prefix, formatThread(th)) fmt.Printf("%sThread %s\n", prefix, formatThread(th))
@ -825,7 +825,7 @@ func (c *Commands) frameCommand(t *Term, ctx callContext, argstr string, directi
} }
printcontext(t, state) printcontext(t, state)
th := stack[frame] th := stack[frame]
fmt.Printf("Frame %d: %s:%d (PC: %x)\n", frame, ShortenFilePath(th.File), th.Line, th.PC) fmt.Printf("Frame %d: %s:%d (PC: %x)\n", frame, shortenFilePath(th.File), th.Line, th.PC)
printfile(t, th.File, th.Line, true) printfile(t, th.File, th.Line, true)
return nil return nil
} }
@ -863,7 +863,7 @@ func formatThread(th *api.Thread) string {
if th == nil { if th == nil {
return "<nil>" return "<nil>"
} }
return fmt.Sprintf("%d at %s:%d", th.ID, ShortenFilePath(th.File), th.Line) return fmt.Sprintf("%d at %s:%d", th.ID, shortenFilePath(th.File), th.Line)
} }
type formatGoroutineLoc int type formatGoroutineLoc int
@ -876,7 +876,7 @@ const (
) )
func formatLocation(loc api.Location) string { func formatLocation(loc api.Location) string {
return fmt.Sprintf("%s:%d %s (%#v)", ShortenFilePath(loc.File), loc.Line, loc.Function.Name(), loc.PC) return fmt.Sprintf("%s:%d %s (%#v)", shortenFilePath(loc.File), loc.Line, loc.Function.Name(), loc.PC)
} }
func formatGoroutine(g *api.Goroutine, fgl formatGoroutineLoc) string { func formatGoroutine(g *api.Goroutine, fgl formatGoroutineLoc) string {
@ -1325,19 +1325,19 @@ func clearAll(t *Term, ctx callContext, args string) error {
return nil return nil
} }
// ByID sorts breakpoints by ID. // byID sorts breakpoints by ID.
type ByID []*api.Breakpoint type byID []*api.Breakpoint
func (a ByID) Len() int { return len(a) } func (a byID) Len() int { return len(a) }
func (a ByID) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a byID) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByID) Less(i, j int) bool { return a[i].ID < a[j].ID } func (a byID) Less(i, j int) bool { return a[i].ID < a[j].ID }
func breakpoints(t *Term, ctx callContext, args string) error { func breakpoints(t *Term, ctx callContext, args string) error {
breakPoints, err := t.client.ListBreakpoints() breakPoints, err := t.client.ListBreakpoints()
if err != nil { if err != nil {
return err return err
} }
sort.Sort(ByID(breakPoints)) sort.Sort(byID(breakPoints))
for _, bp := range breakPoints { for _, bp := range breakPoints {
fmt.Printf("%s at %v (%d)\n", formatBreakpointName(bp, true), formatBreakpointLocation(bp), bp.TotalHitCount) fmt.Printf("%s at %v (%d)\n", formatBreakpointName(bp, true), formatBreakpointLocation(bp), bp.TotalHitCount)
@ -1352,14 +1352,14 @@ func breakpoints(t *Term, ctx callContext, args string) error {
attrs = append(attrs, "\tgoroutine") attrs = append(attrs, "\tgoroutine")
} }
if bp.LoadArgs != nil { if bp.LoadArgs != nil {
if *(bp.LoadArgs) == LongLoadConfig { if *(bp.LoadArgs) == longLoadConfig {
attrs = append(attrs, "\targs -v") attrs = append(attrs, "\targs -v")
} else { } else {
attrs = append(attrs, "\targs") attrs = append(attrs, "\targs")
} }
} }
if bp.LoadLocals != nil { if bp.LoadLocals != nil {
if *(bp.LoadLocals) == LongLoadConfig { if *(bp.LoadLocals) == longLoadConfig {
attrs = append(attrs, "\tlocals -v") attrs = append(attrs, "\tlocals -v")
} else { } else {
attrs = append(attrs, "\tlocals") attrs = append(attrs, "\tlocals")
@ -1955,7 +1955,7 @@ func disassCommand(t *Term, ctx callContext, args string) error {
return disasmErr return disasmErr
} }
DisasmPrint(disasm, os.Stdout) disasmPrint(disasm, os.Stdout)
return nil return nil
} }
@ -2004,7 +2004,7 @@ func printStack(stack []api.Stackframe, ind string, offsets bool) {
continue continue
} }
fmt.Printf(fmtstr, ind, i, stack[i].PC, stack[i].Function.Name()) fmt.Printf(fmtstr, ind, i, stack[i].PC, stack[i].Function.Name())
fmt.Printf("%sat %s:%d\n", s, ShortenFilePath(stack[i].File), stack[i].Line) fmt.Printf("%sat %s:%d\n", s, shortenFilePath(stack[i].File), stack[i].Line)
if offsets { if offsets {
fmt.Printf("%sframe: %+#x frame pointer %+#x\n", s, stack[i].FrameOffset, stack[i].FramePointerOffset) fmt.Printf("%sframe: %+#x frame pointer %+#x\n", s, stack[i].FrameOffset, stack[i].FramePointerOffset)
@ -2084,7 +2084,7 @@ func printcontext(t *Term, state *api.DebuggerState) {
} }
func printcontextLocation(loc api.Location) { func printcontextLocation(loc api.Location) {
fmt.Printf("> %s() %s:%d (PC: %#v)\n", loc.Function.Name(), ShortenFilePath(loc.File), loc.Line, loc.PC) fmt.Printf("> %s() %s:%d (PC: %#v)\n", loc.Function.Name(), shortenFilePath(loc.File), loc.Line, loc.PC)
if loc.Function != nil && loc.Function.Optimized { if loc.Function != nil && loc.Function.Optimized {
fmt.Println(optimizedFunctionWarning) fmt.Println(optimizedFunctionWarning)
} }
@ -2137,7 +2137,7 @@ func printcontextThread(t *Term, th *api.Thread) {
bpname, bpname,
fn.Name(), fn.Name(),
args, args,
ShortenFilePath(th.File), shortenFilePath(th.File),
th.Line, th.Line,
th.GoroutineID, th.GoroutineID,
hitCount, hitCount,
@ -2148,7 +2148,7 @@ func printcontextThread(t *Term, th *api.Thread) {
bpname, bpname,
fn.Name(), fn.Name(),
args, args,
ShortenFilePath(th.File), shortenFilePath(th.File),
th.Line, th.Line,
th.Breakpoint.TotalHitCount, th.Breakpoint.TotalHitCount,
th.PC) th.PC)
@ -2172,14 +2172,14 @@ func printcontextThread(t *Term, th *api.Thread) {
} }
for _, v := range bpi.Locals { for _, v := range bpi.Locals {
if *bp.LoadLocals == LongLoadConfig { if *bp.LoadLocals == longLoadConfig {
fmt.Printf("\t%s: %s\n", v.Name, v.MultilineString("\t")) fmt.Printf("\t%s: %s\n", v.Name, v.MultilineString("\t"))
} else { } else {
fmt.Printf("\t%s: %s\n", v.Name, v.SinglelineString()) fmt.Printf("\t%s: %s\n", v.Name, v.SinglelineString())
} }
} }
if bp.LoadArgs != nil && *bp.LoadArgs == LongLoadConfig { if bp.LoadArgs != nil && *bp.LoadArgs == longLoadConfig {
for _, v := range bpi.Arguments { for _, v := range bpi.Arguments {
fmt.Printf("\t%s: %s\n", v.Name, v.MultilineString("\t")) fmt.Printf("\t%s: %s\n", v.Name, v.MultilineString("\t"))
} }
@ -2302,9 +2302,9 @@ func conditionCmd(t *Term, ctx callContext, argstr string) error {
return t.client.AmendBreakpoint(bp) return t.client.AmendBreakpoint(bp)
} }
// ShortenFilePath take a full file path and attempts to shorten // shortenFilePath take a full file path and attempts to shorten
// it by replacing the current directory to './'. // it by replacing the current directory to './'.
func ShortenFilePath(fullPath string) string { func shortenFilePath(fullPath string) string {
workingDir, _ := os.Getwd() workingDir, _ := os.Getwd()
return strings.Replace(fullPath, workingDir, ".", 1) return strings.Replace(fullPath, workingDir, ".", 1)
} }
@ -2463,7 +2463,7 @@ func formatBreakpointLocation(bp *api.Breakpoint) string {
fmt.Fprintf(&out, "%#x", bp.Addr) fmt.Fprintf(&out, "%#x", bp.Addr)
} }
fmt.Fprintf(&out, " for ") fmt.Fprintf(&out, " for ")
p := ShortenFilePath(bp.File) p := shortenFilePath(bp.File)
if bp.FunctionName != "" { if bp.FunctionName != "" {
fmt.Fprintf(&out, "%s() ", bp.FunctionName) fmt.Fprintf(&out, "%s() ", bp.FunctionName)
} }

@ -10,7 +10,7 @@ import (
"github.com/go-delve/delve/service/api" "github.com/go-delve/delve/service/api"
) )
func DisasmPrint(dv api.AsmInstructions, out io.Writer) { func disasmPrint(dv api.AsmInstructions, out io.Writer) {
bw := bufio.NewWriter(out) bw := bufio.NewWriter(out)
defer bw.Flush() defer bw.Flush()
if len(dv) > 0 && dv[0].Loc.Function != nil { if len(dv) > 0 && dv[0].Loc.Function != nil {