*: un-export unnecessarily public symbols
This commit is contained in:
parent
1ee8d5c218
commit
3c8d4d52b8
@ -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 := ¬e{}
|
||||||
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(®set.AMD64PtraceFpRegs)), 0, 0, 0)
|
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETFPREGS, uintptr(id), uintptr(unsafe.Pointer(®set.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 Developer’s Manual, Volume 1: Basic Architecture
|
// and Section 13.1 (and following) of Intel® 64 and IA-32 Architectures Software Developer’s 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(®set.I386PtraceFpRegs)), 0, 0)
|
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETFPREGS, uintptr(tid), uintptr(0), uintptr(unsafe.Pointer(®set.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 Developer’s Manual, Volume 1: Basic Architecture
|
// and Section 13.1 (and following) of Intel® 64 and IA-32 Architectures Software Developer’s 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(®set.AMD64PtraceFpRegs)), 0, 0)
|
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETFPREGS, uintptr(tid), uintptr(0), uintptr(unsafe.Pointer(®set.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 {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user