*: 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
|
||||
|
||||
func NewFrameIndex() FrameDescriptionEntries {
|
||||
func newFrameIndex() FrameDescriptionEntries {
|
||||
return make(FrameDescriptionEntries, 0, 1000)
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ func ptrSizeByRuntimeArch() int {
|
||||
}
|
||||
|
||||
func TestFDEForPC(t *testing.T) {
|
||||
frames := NewFrameIndex()
|
||||
frames := newFrameIndex()
|
||||
frames = append(frames,
|
||||
&FrameDescriptionEntry{begin: 10, size: 40},
|
||||
&FrameDescriptionEntry{begin: 50, size: 50},
|
||||
|
@ -29,7 +29,7 @@ type parseContext struct {
|
||||
func Parse(data []byte, order binary.ByteOrder, staticBase uint64, ptrSize int) FrameDescriptionEntries {
|
||||
var (
|
||||
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; {
|
||||
|
@ -127,7 +127,7 @@ func executeCIEInstructions(cie *CommonInformationEntry) *FrameContext {
|
||||
buf: bytes.NewBuffer(initialInstructions),
|
||||
}
|
||||
|
||||
frame.ExecuteDwarfProgram()
|
||||
frame.executeDwarfProgram()
|
||||
return frame
|
||||
}
|
||||
|
||||
@ -142,7 +142,7 @@ func executeDwarfProgramUntilPC(fde *FrameDescriptionEntry, pc uint64) *FrameCon
|
||||
return frame
|
||||
}
|
||||
|
||||
func (frame *FrameContext) ExecuteDwarfProgram() {
|
||||
func (frame *FrameContext) executeDwarfProgram() {
|
||||
for frame.buf.Len() > 0 {
|
||||
executeDwarfInstruction(frame)
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
"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
|
||||
// core, the program text was loaded at 0x400000:
|
||||
// Start End Page Offset
|
||||
@ -22,7 +22,7 @@ import (
|
||||
// 0x0000000000002000 0x0000000000002000 RW 1000
|
||||
// This can be represented in a SplicedMemory by adding the original region,
|
||||
// then putting the RW mapping on top of it.
|
||||
type SplicedMemory struct {
|
||||
type splicedMemory struct {
|
||||
readers []readerEntry
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ type readerEntry struct {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return
|
||||
}
|
||||
@ -93,7 +93,7 @@ func (r *SplicedMemory) Add(reader proc.MemoryReader, off, length uintptr) {
|
||||
}
|
||||
|
||||
// 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
|
||||
for _, entry := range r.readers {
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
// space. For example, if program text is mapped in at 0x400000, an
|
||||
// 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.
|
||||
type OffsetReaderAt struct {
|
||||
type offsetReaderAt struct {
|
||||
reader io.ReaderAt
|
||||
offset uintptr
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
|
||||
// Process represents a core file.
|
||||
type Process struct {
|
||||
// process represents a core file.
|
||||
type process struct {
|
||||
mem proc.MemoryReader
|
||||
Threads map[int]*Thread
|
||||
Threads map[int]*thread
|
||||
pid int
|
||||
|
||||
entryPoint uint64
|
||||
|
||||
bi *proc.BinaryInfo
|
||||
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.
|
||||
type Thread struct {
|
||||
// thread represents a thread in the core file being debugged.
|
||||
type thread struct {
|
||||
th osThread
|
||||
p *Process
|
||||
p *process
|
||||
common proc.CommonThread
|
||||
}
|
||||
|
||||
@ -189,7 +189,7 @@ var (
|
||||
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}
|
||||
|
||||
@ -201,7 +201,7 @@ var ErrUnrecognizedFormat = errors.New("unrecognized core format")
|
||||
// If the DWARF information cannot be found in the binary, Delve will look
|
||||
// for external debug files in the directories passed in.
|
||||
func OpenCore(corePath, exePath string, debugInfoDirs []string) (*proc.Target, error) {
|
||||
var p *Process
|
||||
var p *process
|
||||
var err error
|
||||
for _, openFn := range openFns {
|
||||
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.
|
||||
func (p *Process) BinInfo() *proc.BinaryInfo {
|
||||
func (p *process) BinInfo() *proc.BinaryInfo {
|
||||
return p.bi
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// writeBreakpoint is a noop function since you
|
||||
// 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")
|
||||
}
|
||||
|
||||
// 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.
|
||||
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.
|
||||
func (p *Process) ChangeDirection(proc.Direction) error { return ErrContinueCore }
|
||||
func (p *process) ChangeDirection(proc.Direction) error { return ErrContinueCore }
|
||||
|
||||
// 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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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
|
||||
// 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.
|
||||
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)
|
||||
if err == nil && n != len(data) {
|
||||
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
|
||||
// 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
|
||||
}
|
||||
|
||||
// Location returns the location of this thread based on
|
||||
// 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -293,150 +293,150 @@ func (t *Thread) Location() (*proc.Location, error) {
|
||||
// Breakpoint returns the current breakpoint this thread is stopped at.
|
||||
// For core files this always returns an empty BreakpointState struct, as
|
||||
// there are no breakpoints when debugging core files.
|
||||
func (t *Thread) Breakpoint() *proc.BreakpointState {
|
||||
func (t *thread) Breakpoint() *proc.BreakpointState {
|
||||
return &proc.BreakpointState{}
|
||||
}
|
||||
|
||||
// ThreadID returns the ID for this thread.
|
||||
func (t *Thread) ThreadID() int {
|
||||
func (t *thread) ThreadID() int {
|
||||
return int(t.th.pid())
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// RestoreRegisters will only return an error 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
|
||||
}
|
||||
|
||||
// BinInfo returns information about the binary.
|
||||
func (t *Thread) BinInfo() *proc.BinaryInfo {
|
||||
func (t *thread) BinInfo() *proc.BinaryInfo {
|
||||
return t.p.bi
|
||||
}
|
||||
|
||||
// StepInstruction will only return an error for core files,
|
||||
// you cannot execute a core file.
|
||||
func (t *Thread) StepInstruction() error {
|
||||
func (t *thread) StepInstruction() error {
|
||||
return ErrContinueCore
|
||||
}
|
||||
|
||||
// Blocked will return false always for core files as there is
|
||||
// no execution.
|
||||
func (t *Thread) Blocked() bool {
|
||||
func (t *thread) Blocked() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// SetCurrentBreakpoint will always just return nil
|
||||
// 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
|
||||
}
|
||||
|
||||
// Common returns a struct containing common information
|
||||
// across thread implementations.
|
||||
func (t *Thread) Common() *proc.CommonThread {
|
||||
func (t *thread) Common() *proc.CommonThread {
|
||||
return &t.common
|
||||
}
|
||||
|
||||
// SetPC will always return an error, you cannot
|
||||
// change register values when debugging core files.
|
||||
func (t *Thread) SetPC(uint64) error {
|
||||
func (t *thread) SetPC(uint64) error {
|
||||
return ErrChangeRegisterCore
|
||||
}
|
||||
|
||||
// SetSP will always return an error, you cannot
|
||||
// change register values when debugging core files.
|
||||
func (t *Thread) SetSP(uint64) error {
|
||||
func (t *thread) SetSP(uint64) error {
|
||||
return ErrChangeRegisterCore
|
||||
}
|
||||
|
||||
// SetDX will always return an error, you cannot
|
||||
// change register values when debugging core files.
|
||||
func (t *Thread) SetDX(uint64) error {
|
||||
func (t *thread) SetDX(uint64) error {
|
||||
return ErrChangeRegisterCore
|
||||
}
|
||||
|
||||
// Breakpoints will return all breakpoints for the process.
|
||||
func (p *Process) Breakpoints() *proc.BreakpointMap {
|
||||
func (p *process) Breakpoints() *proc.BreakpointMap {
|
||||
return &p.breakpoints
|
||||
}
|
||||
|
||||
// ClearBreakpoint will always return an error as you cannot set or clear
|
||||
// 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}
|
||||
}
|
||||
|
||||
// ClearInternalBreakpoints will always return nil and have no
|
||||
// effect since you cannot set breakpoints on core files.
|
||||
func (p *Process) ClearInternalBreakpoints() error {
|
||||
func (p *process) ClearInternalBreakpoints() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContinueOnce will always return an error because you
|
||||
// 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
|
||||
}
|
||||
|
||||
// StepInstruction will always return an error
|
||||
// as you cannot control execution of a core file.
|
||||
func (p *Process) StepInstruction() error {
|
||||
func (p *process) StepInstruction() error {
|
||||
return ErrContinueCore
|
||||
}
|
||||
|
||||
// RequestManualStop will return nil and have no effect
|
||||
// as you cannot control execution of a core file.
|
||||
func (p *Process) RequestManualStop() error {
|
||||
func (p *process) RequestManualStop() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckAndClearManualStopRequest will always return false and
|
||||
// have no effect since there are no manual stop requests as
|
||||
// there is no controlling execution of a core file.
|
||||
func (p *Process) CheckAndClearManualStopRequest() bool {
|
||||
func (p *process) CheckAndClearManualStopRequest() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// CurrentThread returns the current active thread.
|
||||
func (p *Process) CurrentThread() proc.Thread {
|
||||
func (p *process) CurrentThread() proc.Thread {
|
||||
return p.currentThread
|
||||
}
|
||||
|
||||
// Detach will always return nil and have no
|
||||
// effect as you cannot detach from a core file
|
||||
// and have it continue execution or exit.
|
||||
func (p *Process) Detach(bool) error {
|
||||
func (p *process) Detach(bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Valid returns whether the process is active. Always returns true
|
||||
// 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
|
||||
}
|
||||
|
||||
// Pid returns the process ID of this process.
|
||||
func (p *Process) Pid() int {
|
||||
func (p *process) Pid() int {
|
||||
return p.pid
|
||||
}
|
||||
|
||||
// ResumeNotify is a no-op on core files as we cannot
|
||||
// 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.
|
||||
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
|
||||
}
|
||||
|
||||
// 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))
|
||||
for _, v := range p.Threads {
|
||||
r = append(r, v)
|
||||
@ -445,12 +445,12 @@ func (p *Process) ThreadList() []proc.Thread {
|
||||
}
|
||||
|
||||
// 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]
|
||||
return t, ok
|
||||
}
|
||||
|
||||
// SetCurrentThread is used internally by proc.Target to change the current thread.
|
||||
func (p *Process) SetCurrentThread(th proc.Thread) {
|
||||
p.currentThread = th.(*Thread)
|
||||
func (p *process) SetCurrentThread(th proc.Thread) {
|
||||
p.currentThread = th.(*thread)
|
||||
}
|
||||
|
@ -134,10 +134,10 @@ func TestSplicedReader(t *testing.T) {
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
mem := &SplicedMemory{}
|
||||
mem := &splicedMemory{}
|
||||
for _, region := range test.regions {
|
||||
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)
|
||||
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
|
||||
// systems.
|
||||
type LinuxCoreTimeval struct {
|
||||
type linuxCoreTimeval struct {
|
||||
Sec int64
|
||||
Usec int64
|
||||
}
|
||||
|
||||
// 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.
|
||||
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
|
||||
const NT_AUXV elf.NType = 0x6
|
||||
const _NT_AUXV elf.NType = 0x6
|
||||
|
||||
// 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
|
||||
// Refer http://man7.org/linux/man-pages/man5/elf.5.html
|
||||
const (
|
||||
EM_AARCH64 = 183
|
||||
EM_X86_64 = 62
|
||||
_EM_AARCH64 = 183
|
||||
_EM_X86_64 = 62
|
||||
_ARM_FP_HEADER_START = 512
|
||||
)
|
||||
|
||||
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 lastThreadARM *linuxARM64Thread
|
||||
for _, note := range notes {
|
||||
switch note.Type {
|
||||
case elf.NT_PRSTATUS:
|
||||
if machineType == EM_X86_64 {
|
||||
t := note.Desc.(*LinuxPrStatusAMD64)
|
||||
if machineType == _EM_X86_64 {
|
||||
t := note.Desc.(*linuxPrStatusAMD64)
|
||||
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 {
|
||||
p.currentThread = p.Threads[int(t.Pid)]
|
||||
}
|
||||
} else if machineType == EM_AARCH64 {
|
||||
t := note.Desc.(*LinuxPrStatusARM64)
|
||||
} else if machineType == _EM_AARCH64 {
|
||||
t := note.Desc.(*linuxPrStatusARM64)
|
||||
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 {
|
||||
p.currentThread = p.Threads[int(t.Pid)]
|
||||
}
|
||||
}
|
||||
case NT_FPREGSET:
|
||||
if machineType == EM_AARCH64 {
|
||||
case _NT_FPREGSET:
|
||||
if machineType == _EM_AARCH64 {
|
||||
if lastThreadARM != nil {
|
||||
lastThreadARM.regs.Fpregs = note.Desc.(*linutil.ARM64PtraceFpRegs).Decode()
|
||||
}
|
||||
}
|
||||
case NT_X86_XSTATE:
|
||||
if machineType == EM_X86_64 {
|
||||
case _NT_X86_XSTATE:
|
||||
if machineType == _EM_X86_64 {
|
||||
if lastThreadAMD != nil {
|
||||
lastThreadAMD.regs.Fpregs = note.Desc.(*linutil.AMD64Xstate).Decode()
|
||||
}
|
||||
}
|
||||
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,
|
||||
// elf_core_dump in http://lxr.free-electrons.com/source/fs/binfmt_elf.c,
|
||||
// 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)
|
||||
if err != nil {
|
||||
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
|
||||
var bi *proc.BinaryInfo
|
||||
switch machineType {
|
||||
case EM_X86_64:
|
||||
case _EM_X86_64:
|
||||
bi = proc.NewBinaryInfo("linux", "amd64")
|
||||
case EM_AARCH64:
|
||||
case _EM_AARCH64:
|
||||
bi = proc.NewBinaryInfo("linux", "arm64")
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported machine type")
|
||||
@ -132,9 +132,9 @@ func readLinuxCore(corePath, exePath string) (*Process, error) {
|
||||
|
||||
entryPoint := findEntryPoint(notes, bi.Arch.PtrSize())
|
||||
|
||||
p := &Process{
|
||||
p := &process{
|
||||
mem: memory,
|
||||
Threads: map[int]*Thread{},
|
||||
Threads: map[int]*thread{},
|
||||
entryPoint: entryPoint,
|
||||
bi: bi,
|
||||
breakpoints: proc.NewBreakpointMap(),
|
||||
@ -146,12 +146,12 @@ func readLinuxCore(corePath, exePath string) (*Process, error) {
|
||||
|
||||
type linuxAMD64Thread struct {
|
||||
regs linutil.AMD64Registers
|
||||
t *LinuxPrStatusAMD64
|
||||
t *linuxPrStatusAMD64
|
||||
}
|
||||
|
||||
type linuxARM64Thread struct {
|
||||
regs linutil.ARM64Registers
|
||||
t *LinuxPrStatusARM64
|
||||
t *linuxPrStatusARM64
|
||||
}
|
||||
|
||||
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_FPREGSET (Not implemented): x87 floating point registers.
|
||||
// - NT_X86_XSTATE: Other registers, including AVX and such.
|
||||
type Note struct {
|
||||
type note struct {
|
||||
Type elf.NType
|
||||
Name string
|
||||
Desc interface{} // Decoded Desc from the
|
||||
}
|
||||
|
||||
// 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
|
||||
for _, prog := range core.Progs {
|
||||
if prog.Type == elf.PT_NOTE {
|
||||
@ -204,7 +204,7 @@ func readNotes(core *elf.File, machineType elf.Machine) ([]*Note, error) {
|
||||
}
|
||||
|
||||
r := notesProg.Open()
|
||||
notes := []*Note{}
|
||||
notes := []*note{}
|
||||
for {
|
||||
note, err := readNote(r, machineType)
|
||||
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.
|
||||
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:
|
||||
// http://www.sco.com/developers/gabi/latest/ch5.pheader.html#note_section
|
||||
note := &Note{}
|
||||
hdr := &ELFNotesHdr{}
|
||||
note := ¬e{}
|
||||
hdr := &elfNotesHdr{}
|
||||
|
||||
err := binary.Read(r, binary.LittleEndian, hdr)
|
||||
if err != nil {
|
||||
@ -247,10 +247,10 @@ func readNote(r io.ReadSeeker, machineType elf.Machine) (*Note, error) {
|
||||
descReader := bytes.NewReader(desc)
|
||||
switch note.Type {
|
||||
case elf.NT_PRSTATUS:
|
||||
if machineType == EM_X86_64 {
|
||||
note.Desc = &LinuxPrStatusAMD64{}
|
||||
} else if machineType == EM_AARCH64 {
|
||||
note.Desc = &LinuxPrStatusARM64{}
|
||||
if machineType == _EM_X86_64 {
|
||||
note.Desc = &linuxPrStatusAMD64{}
|
||||
} else if machineType == _EM_AARCH64 {
|
||||
note.Desc = &linuxPrStatusARM64{}
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
case elf.NT_PRPSINFO:
|
||||
note.Desc = &LinuxPrPsInfo{}
|
||||
note.Desc = &linuxPrPsInfo{}
|
||||
if err := binary.Read(descReader, binary.LittleEndian, note.Desc); err != nil {
|
||||
return nil, fmt.Errorf("reading NT_PRPSINFO: %v", err)
|
||||
}
|
||||
case NT_FILE:
|
||||
case _NT_FILE:
|
||||
// No good documentation reference, but the structure is
|
||||
// simply a header, including entry count, followed by that
|
||||
// many entries, and then the file name of each entry,
|
||||
// null-delimited. Not reading the names here.
|
||||
data := &LinuxNTFile{}
|
||||
if err := binary.Read(descReader, binary.LittleEndian, &data.LinuxNTFileHdr); err != nil {
|
||||
data := &linuxNTFile{}
|
||||
if err := binary.Read(descReader, binary.LittleEndian, &data.linuxNTFileHdr); err != nil {
|
||||
return nil, fmt.Errorf("reading NT_FILE header: %v", err)
|
||||
}
|
||||
for i := 0; i < int(data.Count); i++ {
|
||||
entry := &LinuxNTFileEntry{}
|
||||
entry := &linuxNTFileEntry{}
|
||||
if err := binary.Read(descReader, binary.LittleEndian, entry); err != nil {
|
||||
return nil, fmt.Errorf("reading NT_FILE entry %v: %v", i, err)
|
||||
}
|
||||
data.entries = append(data.entries, entry)
|
||||
}
|
||||
note.Desc = data
|
||||
case NT_X86_XSTATE:
|
||||
if machineType == EM_X86_64 {
|
||||
case _NT_X86_XSTATE:
|
||||
if machineType == _EM_X86_64 {
|
||||
var fpregs linutil.AMD64Xstate
|
||||
if err := linutil.AMD64XstateRead(desc, true, &fpregs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
note.Desc = &fpregs
|
||||
}
|
||||
case NT_AUXV:
|
||||
case _NT_AUXV:
|
||||
note.Desc = desc
|
||||
case NT_FPREGSET:
|
||||
if machineType == EM_AARCH64 {
|
||||
case _NT_FPREGSET:
|
||||
if machineType == _EM_AARCH64 {
|
||||
fpregs := &linutil.ARM64PtraceFpRegs{}
|
||||
rdr := bytes.NewReader(desc[:_ARM_FP_HEADER_START])
|
||||
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
|
||||
}
|
||||
|
||||
func buildMemory(core, exeELF *elf.File, exe io.ReaderAt, notes []*Note) proc.MemoryReader {
|
||||
memory := &SplicedMemory{}
|
||||
func buildMemory(core, exeELF *elf.File, exe io.ReaderAt, notes []*note) proc.MemoryReader {
|
||||
memory := &splicedMemory{}
|
||||
|
||||
// For now, assume all file mappings are to the exe.
|
||||
for _, note := range notes {
|
||||
if note.Type == NT_FILE {
|
||||
fileNote := note.Desc.(*LinuxNTFile)
|
||||
if note.Type == _NT_FILE {
|
||||
fileNote := note.Desc.(*linuxNTFile)
|
||||
for _, entry := range fileNote.entries {
|
||||
r := &OffsetReaderAt{
|
||||
r := &offsetReaderAt{
|
||||
reader: exe,
|
||||
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 {
|
||||
continue
|
||||
}
|
||||
r := &OffsetReaderAt{
|
||||
r := &offsetReaderAt{
|
||||
reader: prog.ReaderAt,
|
||||
offset: uintptr(prog.Vaddr),
|
||||
}
|
||||
@ -357,9 +357,9 @@ func buildMemory(core, exeELF *elf.File, exe io.ReaderAt, notes []*Note) proc.Me
|
||||
return memory
|
||||
}
|
||||
|
||||
func findEntryPoint(notes []*Note, ptrSize int) uint64 {
|
||||
func findEntryPoint(notes []*note, ptrSize int) uint64 {
|
||||
for _, note := range notes {
|
||||
if note.Type == NT_AUXV {
|
||||
if note.Type == _NT_AUXV {
|
||||
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
|
||||
// because some of the fields are word sized.
|
||||
// See http://lxr.free-electrons.com/source/include/uapi/linux/elfcore.h
|
||||
type LinuxPrPsInfo struct {
|
||||
type linuxPrPsInfo struct {
|
||||
State uint8
|
||||
Sname int8
|
||||
Zomb uint8
|
||||
@ -384,61 +384,61 @@ type LinuxPrPsInfo struct {
|
||||
}
|
||||
|
||||
// LinuxPrStatusAMD64 is a copy of the prstatus kernel struct.
|
||||
type LinuxPrStatusAMD64 struct {
|
||||
Siginfo LinuxSiginfo
|
||||
type linuxPrStatusAMD64 struct {
|
||||
Siginfo linuxSiginfo
|
||||
Cursig uint16
|
||||
_ [2]uint8
|
||||
Sigpend uint64
|
||||
Sighold uint64
|
||||
Pid, Ppid, Pgrp, Sid int32
|
||||
Utime, Stime, CUtime, CStime LinuxCoreTimeval
|
||||
Utime, Stime, CUtime, CStime linuxCoreTimeval
|
||||
Reg linutil.AMD64PtraceRegs
|
||||
Fpvalid int32
|
||||
}
|
||||
|
||||
// LinuxPrStatusARM64 is a copy of the prstatus kernel struct.
|
||||
type LinuxPrStatusARM64 struct {
|
||||
Siginfo LinuxSiginfo
|
||||
type linuxPrStatusARM64 struct {
|
||||
Siginfo linuxSiginfo
|
||||
Cursig uint16
|
||||
_ [2]uint8
|
||||
Sigpend uint64
|
||||
Sighold uint64
|
||||
Pid, Ppid, Pgrp, Sid int32
|
||||
Utime, Stime, CUtime, CStime LinuxCoreTimeval
|
||||
Utime, Stime, CUtime, CStime linuxCoreTimeval
|
||||
Reg linutil.ARM64PtraceRegs
|
||||
Fpvalid int32
|
||||
}
|
||||
|
||||
// LinuxSiginfo is a copy of the
|
||||
// siginfo kernel struct.
|
||||
type LinuxSiginfo struct {
|
||||
type linuxSiginfo struct {
|
||||
Signo int32
|
||||
Code int32
|
||||
Errno int32
|
||||
}
|
||||
|
||||
// LinuxNTFile contains information on mapped files.
|
||||
type LinuxNTFile struct {
|
||||
LinuxNTFileHdr
|
||||
entries []*LinuxNTFileEntry
|
||||
type linuxNTFile struct {
|
||||
linuxNTFileHdr
|
||||
entries []*linuxNTFileEntry
|
||||
}
|
||||
|
||||
// LinuxNTFileHdr is a header struct for NTFile.
|
||||
type LinuxNTFileHdr struct {
|
||||
type linuxNTFileHdr struct {
|
||||
Count uint64
|
||||
PageSize uint64
|
||||
}
|
||||
|
||||
// LinuxNTFileEntry is an entry of an NT_FILE note.
|
||||
type LinuxNTFileEntry struct {
|
||||
type linuxNTFileEntry struct {
|
||||
Start uint64
|
||||
End uint64
|
||||
FileOfs uint64
|
||||
}
|
||||
|
||||
// ELFNotesHdr is the ELF Notes header.
|
||||
// elfNotesHdr is the ELF Notes header.
|
||||
// Same size on 64 and 32-bit machines.
|
||||
type ELFNotesHdr struct {
|
||||
type elfNotesHdr struct {
|
||||
Namesz uint32
|
||||
Descsz uint32
|
||||
Type uint32
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
"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{})
|
||||
if logflags.Minidump() {
|
||||
logfn = logflags.MinidumpLogger().Infof
|
||||
@ -21,16 +21,16 @@ func readAMD64Minidump(minidumpPath, exePath string) (*Process, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
memory := &SplicedMemory{}
|
||||
memory := &splicedMemory{}
|
||||
|
||||
for i := range mdmp.MemoryRanges {
|
||||
m := &mdmp.MemoryRanges[i]
|
||||
memory.Add(m, uintptr(m.Addr), uintptr(len(m.Data)))
|
||||
}
|
||||
|
||||
p := &Process{
|
||||
p := &process{
|
||||
mem: memory,
|
||||
Threads: map[int]*Thread{},
|
||||
Threads: map[int]*thread{},
|
||||
bi: proc.NewBinaryInfo("windows", "amd64"),
|
||||
breakpoints: proc.NewBreakpointMap(),
|
||||
pid: int(mdmp.Pid),
|
||||
@ -38,7 +38,7 @@ func readAMD64Minidump(minidumpPath, exePath string) (*Process, error) {
|
||||
|
||||
for i := range mdmp.Threads {
|
||||
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 {
|
||||
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
|
||||
// that understands Gdb Remote Serial Protocol.
|
||||
type Process struct {
|
||||
type gdbProcess struct {
|
||||
bi *proc.BinaryInfo
|
||||
conn gdbConn
|
||||
|
||||
threads map[int]*Thread
|
||||
currentThread *Thread
|
||||
threads map[int]*gdbThread
|
||||
currentThread *gdbThread
|
||||
|
||||
exited, detached bool
|
||||
ctrlC bool // ctrl-c was sent to stop inferior
|
||||
@ -126,15 +126,15 @@ type Process struct {
|
||||
onDetach func() // called after a successful detach
|
||||
}
|
||||
|
||||
var _ proc.ProcessInternal = &Process{}
|
||||
var _ proc.ProcessInternal = &gdbProcess{}
|
||||
|
||||
// Thread represents an operating system thread.
|
||||
type Thread struct {
|
||||
type gdbThread struct {
|
||||
ID int
|
||||
strID string
|
||||
regs gdbRegisters
|
||||
CurrentBreakpoint proc.BreakpointState
|
||||
p *Process
|
||||
p *gdbProcess
|
||||
sig uint8 // signal received by thread after last stop
|
||||
setbp bool // thread was stopped because of a breakpoint
|
||||
common proc.CommonThread
|
||||
@ -165,20 +165,20 @@ type gdbRegister struct {
|
||||
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
|
||||
// Detach.
|
||||
// Use Listen, Dial or Connect to complete connection.
|
||||
func New(process *os.Process) *Process {
|
||||
func newProcess(process *os.Process) *gdbProcess {
|
||||
logger := logflags.GdbWireLogger()
|
||||
p := &Process{
|
||||
p := &gdbProcess{
|
||||
conn: gdbConn{
|
||||
maxTransmitAttempts: maxTransmitAttempts,
|
||||
inbuf: make([]byte, 0, initialInputBufferSize),
|
||||
direction: proc.Forward,
|
||||
log: logger,
|
||||
},
|
||||
threads: make(map[int]*Thread),
|
||||
threads: make(map[int]*gdbThread),
|
||||
bi: proc.NewBinaryInfo(runtime.GOOS, runtime.GOARCH),
|
||||
breakpoints: proc.NewBreakpointMap(),
|
||||
gcmdok: true,
|
||||
@ -198,7 +198,7 @@ func New(process *os.Process) *Process {
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
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.
|
||||
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 {
|
||||
conn, err := net.Dial("tcp", addr)
|
||||
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
|
||||
// some stubs do not provide ways to determine path and pid automatically
|
||||
// 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.pid = pid
|
||||
err := p.conn.handshake()
|
||||
@ -400,7 +400,7 @@ func LLDBLaunch(cmd []string, wd string, foreground bool, debugInfoDirs []string
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p := New(process.Process)
|
||||
p := newProcess(process.Process)
|
||||
p.conn.isDebugserver = isDebugserver
|
||||
|
||||
var tgt *proc.Target
|
||||
@ -450,7 +450,7 @@ func LLDBAttach(pid int, path string, debugInfoDirs []string) (*proc.Target, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p := New(process.Process)
|
||||
p := newProcess(process.Process)
|
||||
p.conn.isDebugserver = isDebugserver
|
||||
|
||||
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
|
||||
// debugging PIEs.
|
||||
func (p *Process) EntryPoint() (uint64, error) {
|
||||
func (p *gdbProcess) EntryPoint() (uint64, error) {
|
||||
var entryPoint uint64
|
||||
if auxv, err := p.conn.readAuxv(); err == nil {
|
||||
// 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
|
||||
// executable path. This command is not supported by all stubs and not all
|
||||
// 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
|
||||
if path == "" {
|
||||
// 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
|
||||
}
|
||||
|
||||
func queryProcessInfo(p *Process, pid int) (int, string, error) {
|
||||
func queryProcessInfo(p *gdbProcess, pid int) (int, string, error) {
|
||||
pi, err := p.conn.queryProcessInfo(pid)
|
||||
if err != nil {
|
||||
return 0, "", err
|
||||
@ -555,24 +555,24 @@ func queryProcessInfo(p *Process, pid int) (int, string, error) {
|
||||
}
|
||||
|
||||
// BinInfo returns information on the binary.
|
||||
func (p *Process) BinInfo() *proc.BinaryInfo {
|
||||
func (p *gdbProcess) BinInfo() *proc.BinaryInfo {
|
||||
return p.bi
|
||||
}
|
||||
|
||||
// Recorded returns whether or not we are debugging
|
||||
// a recorded "traced" program.
|
||||
func (p *Process) Recorded() (bool, string) {
|
||||
func (p *gdbProcess) Recorded() (bool, string) {
|
||||
return p.tracedir != "", p.tracedir
|
||||
}
|
||||
|
||||
// Pid returns the process ID.
|
||||
func (p *Process) Pid() int {
|
||||
func (p *gdbProcess) Pid() int {
|
||||
return int(p.conn.pid)
|
||||
}
|
||||
|
||||
// Valid returns true if we are not detached
|
||||
// and the process has not exited.
|
||||
func (p *Process) Valid() (bool, error) {
|
||||
func (p *gdbProcess) Valid() (bool, error) {
|
||||
if p.detached {
|
||||
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
|
||||
// ContinueOnce finishes resuming the target.
|
||||
func (p *Process) ResumeNotify(ch chan<- struct{}) {
|
||||
func (p *gdbProcess) ResumeNotify(ch chan<- struct{}) {
|
||||
p.conn.resumeChan = ch
|
||||
}
|
||||
|
||||
// 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]
|
||||
return thread, ok
|
||||
}
|
||||
|
||||
// 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))
|
||||
for _, thread := range p.threads {
|
||||
r = append(r, thread)
|
||||
@ -605,13 +605,13 @@ func (p *Process) ThreadList() []proc.Thread {
|
||||
|
||||
// CurrentThread returns the current active
|
||||
// selected thread.
|
||||
func (p *Process) CurrentThread() proc.Thread {
|
||||
func (p *gdbProcess) CurrentThread() proc.Thread {
|
||||
return p.currentThread
|
||||
}
|
||||
|
||||
// SetCurrentThread is used internally by proc.Target to change the current thread.
|
||||
func (p *Process) SetCurrentThread(th proc.Thread) {
|
||||
p.currentThread = th.(*Thread)
|
||||
func (p *gdbProcess) SetCurrentThread(th proc.Thread) {
|
||||
p.currentThread = th.(*gdbThread)
|
||||
}
|
||||
|
||||
const (
|
||||
@ -631,7 +631,7 @@ const (
|
||||
|
||||
// ContinueOnce will continue execution of the process until
|
||||
// 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 {
|
||||
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
|
||||
var threadID string
|
||||
var trapthread *Thread
|
||||
var trapthread *gdbThread
|
||||
var tu = threadUpdater{p: p}
|
||||
var atstart bool
|
||||
continueLoop:
|
||||
@ -732,7 +732,7 @@ continueLoop:
|
||||
return trapthread, stopReason, err
|
||||
}
|
||||
|
||||
func (p *Process) findThreadByStrID(threadID string) *Thread {
|
||||
func (p *gdbProcess) findThreadByStrID(threadID string) *gdbThread {
|
||||
for _, thread := range p.threads {
|
||||
if thread.strID == threadID {
|
||||
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
|
||||
// signals and return control to the user.
|
||||
// Adjusts trapthread to a thread that we actually want to stop at.
|
||||
func (p *Process) handleThreadSignals(trapthread *Thread) (trapthreadOut *Thread, atstart bool, shouldStop bool) {
|
||||
var trapthreadCandidate *Thread
|
||||
func (p *gdbProcess) handleThreadSignals(trapthread *gdbThread) (trapthreadOut *gdbThread, atstart bool, shouldStop bool) {
|
||||
var trapthreadCandidate *gdbThread
|
||||
|
||||
for _, th := range p.threads {
|
||||
isStopSignal := false
|
||||
@ -820,7 +820,7 @@ func (p *Process) handleThreadSignals(trapthread *Thread) (trapthreadOut *Thread
|
||||
|
||||
// RequestManualStop will attempt to stop the process
|
||||
// without a breakpoint or signal having been recieved.
|
||||
func (p *Process) RequestManualStop() error {
|
||||
func (p *gdbProcess) RequestManualStop() error {
|
||||
p.conn.manualStopMutex.Lock()
|
||||
p.manualStopRequested = true
|
||||
if !p.conn.running {
|
||||
@ -834,7 +834,7 @@ func (p *Process) RequestManualStop() error {
|
||||
|
||||
// CheckAndClearManualStopRequest will check for a manual
|
||||
// stop and then clear that state.
|
||||
func (p *Process) CheckAndClearManualStopRequest() bool {
|
||||
func (p *gdbProcess) CheckAndClearManualStopRequest() bool {
|
||||
p.conn.manualStopMutex.Lock()
|
||||
msr := p.manualStopRequested
|
||||
p.manualStopRequested = false
|
||||
@ -842,20 +842,20 @@ func (p *Process) CheckAndClearManualStopRequest() bool {
|
||||
return msr
|
||||
}
|
||||
|
||||
func (p *Process) getManualStopRequested() bool {
|
||||
func (p *gdbProcess) getManualStopRequested() bool {
|
||||
p.conn.manualStopMutex.Lock()
|
||||
msr := p.manualStopRequested
|
||||
p.conn.manualStopMutex.Unlock()
|
||||
return msr
|
||||
}
|
||||
|
||||
func (p *Process) setCtrlC(v bool) {
|
||||
func (p *gdbProcess) setCtrlC(v bool) {
|
||||
p.conn.manualStopMutex.Lock()
|
||||
p.ctrlC = v
|
||||
p.conn.manualStopMutex.Unlock()
|
||||
}
|
||||
|
||||
func (p *Process) getCtrlC() bool {
|
||||
func (p *gdbProcess) getCtrlC() bool {
|
||||
p.conn.manualStopMutex.Lock()
|
||||
defer p.conn.manualStopMutex.Unlock()
|
||||
return p.ctrlC
|
||||
@ -863,7 +863,7 @@ func (p *Process) getCtrlC() bool {
|
||||
|
||||
// Detach will detach from the target 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 {
|
||||
err := p.conn.kill()
|
||||
if err != nil {
|
||||
@ -891,7 +891,7 @@ func (p *Process) Detach(kill bool) error {
|
||||
}
|
||||
|
||||
// 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 == "" {
|
||||
return proc.ErrNotRecorded
|
||||
}
|
||||
@ -932,7 +932,7 @@ func (p *Process) Restart(pos string) error {
|
||||
|
||||
// When executes the 'when' command for the Mozilla RR backend.
|
||||
// This command will return rr's internal event number.
|
||||
func (p *Process) When() (string, error) {
|
||||
func (p *gdbProcess) When() (string, error) {
|
||||
if p.tracedir == "" {
|
||||
return "", proc.ErrNotRecorded
|
||||
}
|
||||
@ -948,7 +948,7 @@ const (
|
||||
)
|
||||
|
||||
// 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 == "" {
|
||||
return -1, proc.ErrNotRecorded
|
||||
}
|
||||
@ -976,7 +976,7 @@ func (p *Process) Checkpoint(where string) (int, error) {
|
||||
}
|
||||
|
||||
// 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 == "" {
|
||||
return nil, proc.ErrNotRecorded
|
||||
}
|
||||
@ -1006,7 +1006,7 @@ func (p *Process) Checkpoints() ([]proc.Checkpoint, error) {
|
||||
const deleteCheckpointPrefix = "Deleted checkpoint "
|
||||
|
||||
// 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 == "" {
|
||||
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.
|
||||
func (p *Process) ChangeDirection(dir proc.Direction) error {
|
||||
func (p *gdbProcess) ChangeDirection(dir proc.Direction) error {
|
||||
if p.tracedir == "" {
|
||||
if dir != proc.Forward {
|
||||
return proc.ErrNotRecorded
|
||||
@ -1042,17 +1042,17 @@ func (p *Process) ChangeDirection(dir proc.Direction) error {
|
||||
}
|
||||
|
||||
// GetDirection returns the current direction of execution.
|
||||
func (p *Process) GetDirection() proc.Direction {
|
||||
func (p *gdbProcess) GetDirection() proc.Direction {
|
||||
return p.conn.direction
|
||||
}
|
||||
|
||||
// Breakpoints returns the list of breakpoints currently set.
|
||||
func (p *Process) Breakpoints() *proc.BreakpointMap {
|
||||
func (p *gdbProcess) Breakpoints() *proc.BreakpointMap {
|
||||
return &p.breakpoints
|
||||
}
|
||||
|
||||
// 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.
|
||||
if bp, ok := p.breakpoints.M[pc]; ok {
|
||||
return bp, true
|
||||
@ -1060,7 +1060,7 @@ func (p *Process) FindBreakpoint(pc uint64) (*proc.Breakpoint, bool) {
|
||||
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))
|
||||
|
||||
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.
|
||||
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 {
|
||||
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.
|
||||
func (p *Process) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) {
|
||||
func (p *gdbProcess) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) {
|
||||
if p.exited {
|
||||
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'.
|
||||
func (p *Process) ClearInternalBreakpoints() error {
|
||||
func (p *gdbProcess) ClearInternalBreakpoints() error {
|
||||
return p.breakpoints.ClearInternalBreakpoints(func(bp *proc.Breakpoint) error {
|
||||
if err := p.conn.clearBreakpoint(bp.Addr); err != nil {
|
||||
return err
|
||||
@ -1104,7 +1104,7 @@ func (p *Process) ClearInternalBreakpoints() error {
|
||||
}
|
||||
|
||||
type threadUpdater struct {
|
||||
p *Process
|
||||
p *gdbProcess
|
||||
seen map[int]bool
|
||||
done bool
|
||||
}
|
||||
@ -1133,7 +1133,7 @@ func (tu *threadUpdater) Add(threads []string) error {
|
||||
tid := int(n)
|
||||
tu.seen[tid] = true
|
||||
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
|
||||
@ -1170,7 +1170,7 @@ func (tu *threadUpdater) Finish() {
|
||||
// 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
|
||||
// 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 {
|
||||
first := true
|
||||
for {
|
||||
@ -1211,19 +1211,19 @@ func (p *Process) updateThreadList(tu *threadUpdater) error {
|
||||
}
|
||||
|
||||
// clearThreadRegisters clears the memoized thread register state.
|
||||
func (p *Process) clearThreadRegisters() {
|
||||
func (p *gdbProcess) clearThreadRegisters() {
|
||||
for _, thread := range p.threads {
|
||||
thread.regs.regs = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Process) clearThreadSignals() {
|
||||
func (p *gdbProcess) clearThreadSignals() {
|
||||
for _, th := range p.threads {
|
||||
th.sig = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Process) setCurrentBreakpoints() error {
|
||||
func (p *gdbProcess) setCurrentBreakpoints() error {
|
||||
if p.threadStopInfo {
|
||||
for _, th := range p.threads {
|
||||
if th.setbp {
|
||||
@ -1248,7 +1248,7 @@ func (p *Process) setCurrentBreakpoints() error {
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
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.
|
||||
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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -1278,17 +1278,17 @@ func (t *Thread) Location() (*proc.Location, error) {
|
||||
}
|
||||
|
||||
// Breakpoint returns the current active breakpoint for this thread.
|
||||
func (t *Thread) Breakpoint() *proc.BreakpointState {
|
||||
func (t *gdbThread) Breakpoint() *proc.BreakpointState {
|
||||
return &t.CurrentBreakpoint
|
||||
}
|
||||
|
||||
// ThreadID returns this threads ID.
|
||||
func (t *Thread) ThreadID() int {
|
||||
func (t *gdbThread) ThreadID() int {
|
||||
return t.ID
|
||||
}
|
||||
|
||||
// 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 err := t.reloadRegisters(); err != nil {
|
||||
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.
|
||||
func (t *Thread) RestoreRegisters(savedRegs proc.Registers) error {
|
||||
func (t *gdbThread) RestoreRegisters(savedRegs proc.Registers) error {
|
||||
copy(t.regs.buf, savedRegs.(*gdbRegisters).buf)
|
||||
return t.writeRegisters()
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// Common returns common information across Process implementations.
|
||||
func (t *Thread) Common() *proc.CommonThread {
|
||||
func (t *gdbThread) Common() *proc.CommonThread {
|
||||
return &t.common
|
||||
}
|
||||
|
||||
func (t *Thread) stepInstruction(tu *threadUpdater) error {
|
||||
func (t *gdbThread) stepInstruction(tu *threadUpdater) error {
|
||||
pc := t.regs.PC()
|
||||
if _, atbp := t.p.breakpoints.M[pc]; atbp {
|
||||
err := t.p.conn.clearBreakpoint(pc)
|
||||
@ -1329,12 +1329,12 @@ func (t *Thread) stepInstruction(tu *threadUpdater) error {
|
||||
}
|
||||
|
||||
// StepInstruction will step exactly 1 CPU instruction.
|
||||
func (t *Thread) StepInstruction() error {
|
||||
func (t *gdbThread) StepInstruction() error {
|
||||
return t.stepInstruction(&threadUpdater{p: t.p})
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return false
|
||||
@ -1362,7 +1362,7 @@ func (t *Thread) Blocked() bool {
|
||||
// loadGInstr returns the correct MOV instruction for the current
|
||||
// OS/architecture that can be executed to load the address of G from an
|
||||
// inferior's thread.
|
||||
func (p *Process) loadGInstr() []byte {
|
||||
func (p *gdbProcess) loadGInstr() []byte {
|
||||
var op []byte
|
||||
switch p.bi.GOOS {
|
||||
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.
|
||||
// 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.
|
||||
func (t *Thread) reloadRegisters() error {
|
||||
func (t *gdbThread) reloadRegisters() error {
|
||||
if t.regs.regs == nil {
|
||||
t.regs.init(t.p.conn.regsInfo)
|
||||
}
|
||||
@ -1438,7 +1438,7 @@ func (t *Thread) reloadRegisters() error {
|
||||
return t.reloadGAtPC()
|
||||
}
|
||||
|
||||
func (t *Thread) writeSomeRegisters(regNames ...string) error {
|
||||
func (t *gdbThread) writeSomeRegisters(regNames ...string) error {
|
||||
if t.p.gcmdok {
|
||||
return t.p.conn.writeRegisters(t.strID, t.regs.buf)
|
||||
}
|
||||
@ -1450,7 +1450,7 @@ func (t *Thread) writeSomeRegisters(regNames ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Thread) writeRegisters() error {
|
||||
func (t *gdbThread) writeRegisters() error {
|
||||
if t.p.gcmdok {
|
||||
return t.p.conn.writeRegisters(t.strID, t.regs.buf)
|
||||
}
|
||||
@ -1462,7 +1462,7 @@ func (t *Thread) writeRegisters() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Thread) readSomeRegisters(regNames ...string) error {
|
||||
func (t *gdbThread) readSomeRegisters(regNames ...string) error {
|
||||
if t.p.gcmdok {
|
||||
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
|
||||
// the MOV instruction used to load current G, executes this single
|
||||
// instruction and then puts everything back the way it was.
|
||||
func (t *Thread) reloadGAtPC() error {
|
||||
func (t *gdbThread) reloadGAtPC() error {
|
||||
movinstr := t.p.loadGInstr()
|
||||
|
||||
if t.Blocked() {
|
||||
@ -1558,7 +1558,7 @@ func (t *Thread) reloadGAtPC() error {
|
||||
// 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
|
||||
// register.
|
||||
func (t *Thread) reloadGAlloc() error {
|
||||
func (t *gdbThread) reloadGAlloc() error {
|
||||
if t.Blocked() {
|
||||
t.regs.tls = 0
|
||||
t.regs.gaddr = 0
|
||||
@ -1606,13 +1606,13 @@ func (t *Thread) reloadGAlloc() error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *Thread) clearBreakpointState() {
|
||||
func (t *gdbThread) clearBreakpointState() {
|
||||
t.setbp = false
|
||||
t.CurrentBreakpoint.Clear()
|
||||
}
|
||||
|
||||
// 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
|
||||
// address correctly after hitting a breakpoint.
|
||||
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.
|
||||
func (t *Thread) SetPC(pc uint64) error {
|
||||
func (t *gdbThread) SetPC(pc uint64) error {
|
||||
t.regs.setPC(pc)
|
||||
if t.p.gcmdok {
|
||||
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.
|
||||
func (t *Thread) SetSP(sp uint64) error {
|
||||
func (t *gdbThread) SetSP(sp uint64) error {
|
||||
t.regs.setSP(sp)
|
||||
if t.p.gcmdok {
|
||||
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.
|
||||
func (t *Thread) SetDX(dx uint64) error {
|
||||
func (t *gdbThread) SetDX(dx uint64) error {
|
||||
t.regs.setDX(dx)
|
||||
if t.p.gcmdok {
|
||||
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,
|
||||
// otherwise the 'C' action will be used and the value of sig will be passed
|
||||
// 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 {
|
||||
conn.outbuf.Reset()
|
||||
fmt.Fprintf(&conn.outbuf, "$vCont")
|
||||
|
@ -104,7 +104,7 @@ func Replay(tracedir string, quiet, deleteOnDetach bool, debugInfoDirs []string)
|
||||
return nil, init.err
|
||||
}
|
||||
|
||||
p := New(rrcmd.Process)
|
||||
p := newProcess(rrcmd.Process)
|
||||
p.tracedir = tracedir
|
||||
if deleteOnDetach {
|
||||
p.onDetach = func() {
|
||||
|
@ -21,15 +21,15 @@ func Attach(pid int, _ []string) (*proc.Target, error) {
|
||||
return nil, ErrNativeBackendDisabled
|
||||
}
|
||||
|
||||
// WaitStatus is a synonym for the platform-specific WaitStatus
|
||||
type WaitStatus struct{}
|
||||
// waitStatus is a synonym for the platform-specific WaitStatus
|
||||
type waitStatus struct{}
|
||||
|
||||
// OSSpecificDetails holds information specific to the OSX/Darwin
|
||||
// osSpecificDetails holds information specific to the OSX/Darwin
|
||||
// operating system / kernel.
|
||||
type OSSpecificDetails struct{}
|
||||
type osSpecificDetails struct{}
|
||||
|
||||
// OSProcessDetails holds Darwin specific information.
|
||||
type OSProcessDetails struct{}
|
||||
// osProcessDetails holds Darwin specific information.
|
||||
type osProcessDetails struct{}
|
||||
|
||||
func findExecutable(path string, pid int) string {
|
||||
panic(ErrNativeBackendDisabled)
|
||||
@ -39,94 +39,94 @@ func killProcess(pid int) error {
|
||||
panic(ErrNativeBackendDisabled)
|
||||
}
|
||||
|
||||
func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) {
|
||||
func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error) {
|
||||
panic(ErrNativeBackendDisabled)
|
||||
}
|
||||
|
||||
func (dbp *Process) loadProcessInformation(wg *sync.WaitGroup) {
|
||||
func (dbp *nativeProcess) loadProcessInformation(wg *sync.WaitGroup) {
|
||||
panic(ErrNativeBackendDisabled)
|
||||
}
|
||||
|
||||
func (dbp *Process) requestManualStop() (err error) {
|
||||
func (dbp *nativeProcess) requestManualStop() (err error) {
|
||||
panic(ErrNativeBackendDisabled)
|
||||
}
|
||||
|
||||
func (dbp *Process) resume() error {
|
||||
func (dbp *nativeProcess) resume() error {
|
||||
panic(ErrNativeBackendDisabled)
|
||||
}
|
||||
|
||||
func (dbp *Process) trapWait(pid int) (*Thread, error) {
|
||||
func (dbp *nativeProcess) trapWait(pid int) (*nativeThread, error) {
|
||||
panic(ErrNativeBackendDisabled)
|
||||
}
|
||||
|
||||
func (dbp *Process) stop(trapthread *Thread) (err error) {
|
||||
func (dbp *nativeProcess) stop(trapthread *nativeThread) (err error) {
|
||||
panic(ErrNativeBackendDisabled)
|
||||
}
|
||||
|
||||
func (dbp *Process) updateThreadList() error {
|
||||
func (dbp *nativeProcess) updateThreadList() error {
|
||||
panic(ErrNativeBackendDisabled)
|
||||
}
|
||||
|
||||
func (dbp *Process) kill() (err error) {
|
||||
func (dbp *nativeProcess) kill() (err error) {
|
||||
panic(ErrNativeBackendDisabled)
|
||||
}
|
||||
|
||||
func (dbp *Process) detach(kill bool) error {
|
||||
func (dbp *nativeProcess) detach(kill bool) error {
|
||||
panic(ErrNativeBackendDisabled)
|
||||
}
|
||||
|
||||
// EntryPoint returns the entry point for the process,
|
||||
// useful for PIEs.
|
||||
func (dbp *Process) EntryPoint() (uint64, error) {
|
||||
func (dbp *nativeProcess) EntryPoint() (uint64, error) {
|
||||
panic(ErrNativeBackendDisabled)
|
||||
}
|
||||
|
||||
// Blocked returns true if the thread is blocked
|
||||
func (t *Thread) Blocked() bool {
|
||||
func (t *nativeThread) Blocked() bool {
|
||||
panic(ErrNativeBackendDisabled)
|
||||
}
|
||||
|
||||
// SetPC sets the value of the PC register.
|
||||
func (t *Thread) SetPC(pc uint64) error {
|
||||
func (t *nativeThread) SetPC(pc uint64) error {
|
||||
panic(ErrNativeBackendDisabled)
|
||||
}
|
||||
|
||||
// SetSP sets the value of the SP register.
|
||||
func (t *Thread) SetSP(sp uint64) error {
|
||||
func (t *nativeThread) SetSP(sp uint64) error {
|
||||
panic(ErrNativeBackendDisabled)
|
||||
}
|
||||
|
||||
// SetDX sets the value of the DX register.
|
||||
func (t *Thread) SetDX(dx uint64) error {
|
||||
func (t *nativeThread) SetDX(dx uint64) error {
|
||||
panic(ErrNativeBackendDisabled)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
func (t *Thread) resume() error {
|
||||
func (t *nativeThread) resume() error {
|
||||
panic(ErrNativeBackendDisabled)
|
||||
}
|
||||
|
||||
func (t *Thread) singleStep() error {
|
||||
func (t *nativeThread) singleStep() error {
|
||||
panic(ErrNativeBackendDisabled)
|
||||
}
|
||||
|
||||
func (t *Thread) restoreRegisters(sr proc.Registers) error {
|
||||
func (t *nativeThread) restoreRegisters(sr proc.Registers) error {
|
||||
panic(ErrNativeBackendDisabled)
|
||||
}
|
||||
|
||||
// Stopped returns whether the thread is stopped at
|
||||
// the operating system level.
|
||||
func (t *Thread) Stopped() bool {
|
||||
func (t *nativeThread) Stopped() bool {
|
||||
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
|
||||
// is holding onto regarding the process we are debugging.
|
||||
type Process struct {
|
||||
type nativeProcess struct {
|
||||
bi *proc.BinaryInfo
|
||||
|
||||
pid int // Process Pid
|
||||
@ -20,12 +20,12 @@ type Process struct {
|
||||
breakpoints proc.BreakpointMap
|
||||
|
||||
// List of threads mapped as such: pid -> *Thread
|
||||
threads map[int]*Thread
|
||||
threads map[int]*nativeThread
|
||||
|
||||
// Active thread
|
||||
currentThread *Thread
|
||||
currentThread *nativeThread
|
||||
|
||||
os *OSProcessDetails
|
||||
os *osProcessDetails
|
||||
firstStart bool
|
||||
stopMu sync.Mutex
|
||||
resumeChan chan<- struct{}
|
||||
@ -37,19 +37,19 @@ type Process struct {
|
||||
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)
|
||||
// functions. For more information, see the documentation on
|
||||
// `handlePtraceFuncs`.
|
||||
func New(pid int) *Process {
|
||||
dbp := &Process{
|
||||
func newProcess(pid int) *nativeProcess {
|
||||
dbp := &nativeProcess{
|
||||
pid: pid,
|
||||
threads: make(map[int]*Thread),
|
||||
threads: make(map[int]*nativeThread),
|
||||
breakpoints: proc.NewBreakpointMap(),
|
||||
firstStart: true,
|
||||
os: new(OSProcessDetails),
|
||||
os: new(osProcessDetails),
|
||||
ptraceChan: make(chan func()),
|
||||
ptraceDoneChan: make(chan interface{}),
|
||||
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.
|
||||
func (dbp *Process) BinInfo() *proc.BinaryInfo {
|
||||
func (dbp *nativeProcess) BinInfo() *proc.BinaryInfo {
|
||||
return dbp.bi
|
||||
}
|
||||
|
||||
// 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
|
||||
// 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
|
||||
// recorded traces.
|
||||
func (dbp *Process) ChangeDirection(dir proc.Direction) error {
|
||||
func (dbp *nativeProcess) ChangeDirection(dir proc.Direction) error {
|
||||
if dir != proc.Forward {
|
||||
return proc.ErrNotRecorded
|
||||
}
|
||||
@ -80,25 +80,25 @@ func (dbp *Process) ChangeDirection(dir proc.Direction) error {
|
||||
}
|
||||
|
||||
// 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.
|
||||
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,
|
||||
// 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,
|
||||
// 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,
|
||||
// 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.
|
||||
func (dbp *Process) Detach(kill bool) (err error) {
|
||||
func (dbp *nativeProcess) Detach(kill bool) (err error) {
|
||||
if dbp.exited {
|
||||
return nil
|
||||
}
|
||||
@ -135,7 +135,7 @@ func (dbp *Process) Detach(kill bool) (err error) {
|
||||
|
||||
// Valid returns whether the process is still attached to and
|
||||
// has not exited.
|
||||
func (dbp *Process) Valid() (bool, error) {
|
||||
func (dbp *nativeProcess) Valid() (bool, error) {
|
||||
if dbp.detached {
|
||||
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
|
||||
// ContinueOnce finishes resuming the target.
|
||||
func (dbp *Process) ResumeNotify(ch chan<- struct{}) {
|
||||
func (dbp *nativeProcess) ResumeNotify(ch chan<- struct{}) {
|
||||
dbp.resumeChan = ch
|
||||
}
|
||||
|
||||
// Pid returns the process ID.
|
||||
func (dbp *Process) Pid() int {
|
||||
func (dbp *nativeProcess) Pid() int {
|
||||
return dbp.pid
|
||||
}
|
||||
|
||||
// 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))
|
||||
for _, v := range dbp.threads {
|
||||
r = append(r, v)
|
||||
@ -166,29 +166,29 @@ func (dbp *Process) ThreadList() []proc.Thread {
|
||||
}
|
||||
|
||||
// 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]
|
||||
return th, ok
|
||||
}
|
||||
|
||||
// CurrentThread returns the current selected, active thread.
|
||||
func (dbp *Process) CurrentThread() proc.Thread {
|
||||
func (dbp *nativeProcess) CurrentThread() proc.Thread {
|
||||
return dbp.currentThread
|
||||
}
|
||||
|
||||
// SetCurrentThread is used internally by proc.Target to change the current thread.
|
||||
func (p *Process) SetCurrentThread(th proc.Thread) {
|
||||
p.currentThread = th.(*Thread)
|
||||
func (p *nativeProcess) SetCurrentThread(th proc.Thread) {
|
||||
p.currentThread = th.(*nativeThread)
|
||||
}
|
||||
|
||||
// Breakpoints returns a list of breakpoints currently set.
|
||||
func (dbp *Process) Breakpoints() *proc.BreakpointMap {
|
||||
func (dbp *nativeProcess) Breakpoints() *proc.BreakpointMap {
|
||||
return &dbp.breakpoints
|
||||
}
|
||||
|
||||
// RequestManualStop sets the `halt` flag and
|
||||
// sends SIGSTOP to all threads.
|
||||
func (dbp *Process) RequestManualStop() error {
|
||||
func (dbp *nativeProcess) RequestManualStop() error {
|
||||
if dbp.exited {
|
||||
return &proc.ErrProcessExited{Pid: dbp.Pid()}
|
||||
}
|
||||
@ -200,7 +200,7 @@ func (dbp *Process) RequestManualStop() error {
|
||||
|
||||
// CheckAndClearManualStopRequest checks if a manual stop has
|
||||
// been requested, and then clears that state.
|
||||
func (dbp *Process) CheckAndClearManualStopRequest() bool {
|
||||
func (dbp *nativeProcess) CheckAndClearManualStopRequest() bool {
|
||||
dbp.stopMu.Lock()
|
||||
defer dbp.stopMu.Unlock()
|
||||
|
||||
@ -210,7 +210,7 @@ func (dbp *Process) CheckAndClearManualStopRequest() bool {
|
||||
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))
|
||||
|
||||
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
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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.
|
||||
// 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 {
|
||||
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.
|
||||
func (dbp *Process) FindBreakpoint(pc uint64, adjustPC bool) (*proc.Breakpoint, bool) {
|
||||
func (dbp *nativeProcess) FindBreakpoint(pc uint64, adjustPC bool) (*proc.Breakpoint, bool) {
|
||||
if adjustPC {
|
||||
// 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 {
|
||||
@ -286,7 +286,7 @@ func (dbp *Process) FindBreakpoint(pc uint64, adjustPC bool) (*proc.Breakpoint,
|
||||
|
||||
// initialize will ensure that all relevant information is loaded
|
||||
// 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 {
|
||||
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
|
||||
// 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 {
|
||||
if err := dbp.currentThread.ClearBreakpoint(bp); err != nil {
|
||||
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
|
||||
// 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.
|
||||
@ -333,19 +333,19 @@ func (dbp *Process) handlePtraceFuncs() {
|
||||
}
|
||||
}
|
||||
|
||||
func (dbp *Process) execPtraceFunc(fn func()) {
|
||||
func (dbp *nativeProcess) execPtraceFunc(fn func()) {
|
||||
dbp.ptraceChan <- fn
|
||||
<-dbp.ptraceDoneChan
|
||||
}
|
||||
|
||||
func (dbp *Process) postExit() {
|
||||
func (dbp *nativeProcess) postExit() {
|
||||
dbp.exited = true
|
||||
close(dbp.ptraceChan)
|
||||
close(dbp.ptraceDoneChan)
|
||||
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())
|
||||
return err
|
||||
}
|
||||
|
@ -20,8 +20,8 @@ import (
|
||||
"github.com/go-delve/delve/pkg/proc"
|
||||
)
|
||||
|
||||
// OSProcessDetails holds Darwin specific information.
|
||||
type OSProcessDetails struct {
|
||||
// osProcessDetails holds Darwin specific information.
|
||||
type osProcessDetails struct {
|
||||
task C.task_t // mach task for the debugged process.
|
||||
exceptionPort C.mach_port_t // mach port for receiving mach exceptions.
|
||||
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.
|
||||
argvSlice = append(argvSlice, nil)
|
||||
|
||||
dbp := New(0)
|
||||
dbp := newProcess(0)
|
||||
var pid int
|
||||
dbp.execPtraceFunc(func() {
|
||||
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.
|
||||
func Attach(pid int, _ []string) (*proc.Target, error) {
|
||||
dbp := New(pid)
|
||||
dbp := newProcess(pid)
|
||||
|
||||
kret := C.acquire_mach_task(C.int(pid),
|
||||
&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
|
||||
|
||||
var err error
|
||||
dbp.execPtraceFunc(func() { err = PtraceAttach(dbp.pid) })
|
||||
dbp.execPtraceFunc(func() { err = ptraceAttach(dbp.pid) })
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -160,7 +160,7 @@ func Attach(pid int, _ []string) (*proc.Target, error) {
|
||||
}
|
||||
|
||||
// Kill kills the process.
|
||||
func (dbp *Process) kill() (err error) {
|
||||
func (dbp *nativeProcess) kill() (err error) {
|
||||
if dbp.exited {
|
||||
return nil
|
||||
}
|
||||
@ -184,7 +184,7 @@ func (dbp *Process) kill() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (dbp *Process) requestManualStop() (err error) {
|
||||
func (dbp *nativeProcess) requestManualStop() (err error) {
|
||||
var (
|
||||
task = C.mach_port_t(dbp.os.task)
|
||||
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 couldNotGetThreadList = errors.New("could not get thread list")
|
||||
|
||||
func (dbp *Process) updateThreadList() error {
|
||||
func (dbp *nativeProcess) updateThreadList() error {
|
||||
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 (
|
||||
err error
|
||||
kret C.kern_return_t
|
||||
@ -255,14 +255,14 @@ func (dbp *Process) updateThreadListForTask(task C.task_t) error {
|
||||
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 {
|
||||
return thread, nil
|
||||
}
|
||||
thread := &Thread{
|
||||
thread := &nativeThread{
|
||||
ID: port,
|
||||
dbp: dbp,
|
||||
os: new(OSSpecificDetails),
|
||||
os: new(osSpecificDetails),
|
||||
}
|
||||
dbp.threads[port] = thread
|
||||
thread.os.threadAct = C.thread_act_t(port)
|
||||
@ -279,7 +279,7 @@ func findExecutable(path string, pid int) string {
|
||||
return path
|
||||
}
|
||||
|
||||
func (dbp *Process) trapWait(pid int) (*Thread, error) {
|
||||
func (dbp *nativeProcess) trapWait(pid int) (*nativeThread, error) {
|
||||
for {
|
||||
task := dbp.os.task
|
||||
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))
|
||||
count := 0
|
||||
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
|
||||
wpid, err := sys.Wait4(pid, &status, options, nil)
|
||||
return wpid, &status, err
|
||||
@ -389,7 +389,7 @@ func killProcess(pid int) error {
|
||||
return sys.Kill(pid, sys.SIGINT)
|
||||
}
|
||||
|
||||
func (dbp *Process) exitGuard(err error) error {
|
||||
func (dbp *nativeProcess) exitGuard(err error) error {
|
||||
if err != ErrContinueThread {
|
||||
return err
|
||||
}
|
||||
@ -401,7 +401,7 @@ func (dbp *Process) exitGuard(err error) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (dbp *Process) resume() error {
|
||||
func (dbp *nativeProcess) resume() error {
|
||||
// all threads stopped over a breakpoint are made to step over it
|
||||
for _, thread := range dbp.threads {
|
||||
if thread.CurrentBreakpoint.Breakpoint != nil {
|
||||
@ -421,7 +421,7 @@ func (dbp *Process) resume() error {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return &proc.ErrProcessExited{Pid: dbp.Pid()}
|
||||
}
|
||||
@ -452,13 +452,13 @@ func (dbp *Process) stop(trapthread *Thread) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dbp *Process) detach(kill bool) error {
|
||||
return PtraceDetach(dbp.pid, 0)
|
||||
func (dbp *nativeProcess) detach(kill bool) error {
|
||||
return ptraceDetach(dbp.pid, 0)
|
||||
}
|
||||
|
||||
func (dbp *Process) EntryPoint() (uint64, error) {
|
||||
func (dbp *nativeProcess) EntryPoint() (uint64, error) {
|
||||
//TODO(aarzilli): implement this
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func initialize(dbp *Process) error { return nil }
|
||||
func initialize(dbp *nativeProcess) error { return nil }
|
||||
|
@ -22,18 +22,18 @@ import (
|
||||
|
||||
// Process statuses
|
||||
const (
|
||||
StatusIdle = 1
|
||||
StatusRunning = 2
|
||||
StatusSleeping = 3
|
||||
StatusStopped = 4
|
||||
StatusZombie = 5
|
||||
StatusWaiting = 6
|
||||
StatusLocked = 7
|
||||
statusIdle = 1
|
||||
statusRunning = 2
|
||||
statusSleeping = 3
|
||||
statusStopped = 4
|
||||
statusZombie = 5
|
||||
statusWaiting = 6
|
||||
statusLocked = 7
|
||||
)
|
||||
|
||||
// OSProcessDetails contains FreeBSD specific
|
||||
// osProcessDetails contains FreeBSD specific
|
||||
// process details.
|
||||
type OSProcessDetails struct {
|
||||
type osProcessDetails struct {
|
||||
comm string
|
||||
tid int
|
||||
}
|
||||
@ -59,7 +59,7 @@ func Launch(cmd []string, wd string, foreground bool, debugInfoDirs []string) (*
|
||||
foreground = false
|
||||
}
|
||||
|
||||
dbp := New(0)
|
||||
dbp := newProcess(0)
|
||||
dbp.execPtraceFunc(func() {
|
||||
process = exec.Command(cmd[0])
|
||||
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
|
||||
// for external debug files in the directories passed in.
|
||||
func Attach(pid int, debugInfoDirs []string) (*proc.Target, error) {
|
||||
dbp := New(pid)
|
||||
dbp := newProcess(pid)
|
||||
|
||||
var err error
|
||||
dbp.execPtraceFunc(func() { err = PtraceAttach(dbp.pid) })
|
||||
dbp.execPtraceFunc(func() { err = ptraceAttach(dbp.pid) })
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -115,7 +115,7 @@ func Attach(pid int, debugInfoDirs []string) (*proc.Target, error) {
|
||||
return tgt, nil
|
||||
}
|
||||
|
||||
func initialize(dbp *Process) error {
|
||||
func initialize(dbp *nativeProcess) error {
|
||||
comm, _ := C.find_command_name(C.int(dbp.pid))
|
||||
defer C.free(unsafe.Pointer(comm))
|
||||
comm_str := C.GoString(comm)
|
||||
@ -124,11 +124,11 @@ func initialize(dbp *Process) error {
|
||||
}
|
||||
|
||||
// kill kills the target process.
|
||||
func (dbp *Process) kill() (err error) {
|
||||
func (dbp *nativeProcess) kill() (err error) {
|
||||
if dbp.exited {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
@ -140,13 +140,13 @@ func (dbp *Process) kill() (err error) {
|
||||
}
|
||||
|
||||
// Used by RequestManualStop
|
||||
func (dbp *Process) requestManualStop() (err error) {
|
||||
func (dbp *nativeProcess) requestManualStop() (err error) {
|
||||
return sys.Kill(dbp.pid, sys.SIGTRAP)
|
||||
}
|
||||
|
||||
// Attach to a newly created thread, and store that thread in our list of
|
||||
// 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 {
|
||||
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,
|
||||
dbp: dbp,
|
||||
os: new(OSSpecificDetails),
|
||||
os: new(osSpecificDetails),
|
||||
}
|
||||
|
||||
if dbp.currentThread == nil {
|
||||
@ -173,9 +173,9 @@ func (dbp *Process) addThread(tid int, attach bool) (*Thread, error) {
|
||||
}
|
||||
|
||||
// Used by initialize
|
||||
func (dbp *Process) updateThreadList() error {
|
||||
func (dbp *nativeProcess) updateThreadList() error {
|
||||
var tids []int32
|
||||
dbp.execPtraceFunc(func() { tids = PtraceGetLwpList(dbp.pid) })
|
||||
dbp.execPtraceFunc(func() { tids = ptraceGetLwpList(dbp.pid) })
|
||||
for _, tid := range tids {
|
||||
if _, err := dbp.addThread(int(tid), false); err != nil {
|
||||
return err
|
||||
@ -195,12 +195,12 @@ func findExecutable(path string, pid int) string {
|
||||
return path
|
||||
}
|
||||
|
||||
func (dbp *Process) trapWait(pid int) (*Thread, error) {
|
||||
func (dbp *nativeProcess) trapWait(pid int) (*nativeThread, error) {
|
||||
return dbp.trapWaitInternal(pid, false)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
wpid, status, err := dbp.wait(pid, 0)
|
||||
if err != nil {
|
||||
@ -225,13 +225,13 @@ func (dbp *Process) trapWaitInternal(pid int, halt bool) (*Thread, error) {
|
||||
pl_flags := int(info.Flags)
|
||||
th, ok := dbp.threads[tid]
|
||||
if ok {
|
||||
th.Status = (*WaitStatus)(status)
|
||||
th.Status = (*waitStatus)(status)
|
||||
}
|
||||
|
||||
if status.StopSignal() == sys.SIGTRAP {
|
||||
if pl_flags&sys.PL_FLAG_EXITED != 0 {
|
||||
delete(dbp.threads, tid)
|
||||
dbp.execPtraceFunc(func() { err = PtraceCont(tid, 0) })
|
||||
dbp.execPtraceFunc(func() { err = ptraceCont(tid, 0) })
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -287,25 +287,25 @@ func status(pid int) rune {
|
||||
|
||||
// Used by stop and singleStep
|
||||
// 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
|
||||
wpid, err := sys.Wait4(pid, &s, 0, nil)
|
||||
return wpid, &s, err
|
||||
}
|
||||
|
||||
// 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
|
||||
wpid, err := sys.Wait4(pid, &s, options, nil)
|
||||
return wpid, &s, err
|
||||
}
|
||||
|
||||
// Only used in this file
|
||||
func (dbp *Process) exitGuard(err error) error {
|
||||
func (dbp *nativeProcess) exitGuard(err error) error {
|
||||
if err != sys.ESRCH {
|
||||
return err
|
||||
}
|
||||
if status(dbp.pid) == StatusZombie {
|
||||
if status(dbp.pid) == statusZombie {
|
||||
_, err := dbp.trapWaitInternal(-1, false)
|
||||
return err
|
||||
}
|
||||
@ -314,7 +314,7 @@ func (dbp *Process) exitGuard(err error) error {
|
||||
}
|
||||
|
||||
// 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
|
||||
for _, thread := range dbp.threads {
|
||||
if thread.CurrentBreakpoint.Breakpoint != nil {
|
||||
@ -326,13 +326,13 @@ func (dbp *Process) resume() error {
|
||||
}
|
||||
// all threads are resumed
|
||||
var err error
|
||||
dbp.execPtraceFunc(func() { err = PtraceCont(dbp.pid, 0) })
|
||||
dbp.execPtraceFunc(func() { err = ptraceCont(dbp.pid, 0) })
|
||||
return err
|
||||
}
|
||||
|
||||
// Used by ContinueOnce
|
||||
// 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 {
|
||||
return &proc.ErrProcessExited{Pid: dbp.Pid()}
|
||||
}
|
||||
@ -348,13 +348,13 @@ func (dbp *Process) stop(trapthread *Thread) (err error) {
|
||||
}
|
||||
|
||||
// Used by Detach
|
||||
func (dbp *Process) detach(kill bool) error {
|
||||
return PtraceDetach(dbp.pid)
|
||||
func (dbp *nativeProcess) detach(kill bool) error {
|
||||
return ptraceDetach(dbp.pid)
|
||||
}
|
||||
|
||||
// Used by PostInitializationSetup
|
||||
// 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))
|
||||
return uint64(ep), err
|
||||
}
|
||||
|
@ -26,21 +26,21 @@ import (
|
||||
|
||||
// Process statuses
|
||||
const (
|
||||
StatusSleeping = 'S'
|
||||
StatusRunning = 'R'
|
||||
StatusTraceStop = 't'
|
||||
StatusZombie = 'Z'
|
||||
statusSleeping = 'S'
|
||||
statusRunning = 'R'
|
||||
statusTraceStop = 't'
|
||||
statusZombie = 'Z'
|
||||
|
||||
// Kernel 2.6 has TraceStop as T
|
||||
// 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
|
||||
// may want to differentiate at some point.
|
||||
StatusTraceStopT = 'T'
|
||||
statusTraceStopT = 'T'
|
||||
)
|
||||
|
||||
// OSProcessDetails contains Linux specific
|
||||
// osProcessDetails contains Linux specific
|
||||
// process details.
|
||||
type OSProcessDetails struct {
|
||||
type osProcessDetails struct {
|
||||
comm string
|
||||
}
|
||||
|
||||
@ -65,7 +65,7 @@ func Launch(cmd []string, wd string, foreground bool, debugInfoDirs []string) (*
|
||||
foreground = false
|
||||
}
|
||||
|
||||
dbp := New(0)
|
||||
dbp := newProcess(0)
|
||||
dbp.execPtraceFunc(func() {
|
||||
process = exec.Command(cmd[0])
|
||||
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
|
||||
// for external debug files in the directories passed in.
|
||||
func Attach(pid int, debugInfoDirs []string) (*proc.Target, error) {
|
||||
dbp := New(pid)
|
||||
dbp := newProcess(pid)
|
||||
|
||||
var err error
|
||||
dbp.execPtraceFunc(func() { err = PtraceAttach(dbp.pid) })
|
||||
dbp.execPtraceFunc(func() { err = ptraceAttach(dbp.pid) })
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -128,7 +128,7 @@ func Attach(pid int, debugInfoDirs []string) (*proc.Target, error) {
|
||||
return tgt, nil
|
||||
}
|
||||
|
||||
func initialize(dbp *Process) error {
|
||||
func initialize(dbp *nativeProcess) error {
|
||||
comm, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/comm", dbp.pid))
|
||||
if err == nil {
|
||||
// removes newline character
|
||||
@ -156,7 +156,7 @@ func initialize(dbp *Process) error {
|
||||
}
|
||||
|
||||
// kill kills the target process.
|
||||
func (dbp *Process) kill() (err error) {
|
||||
func (dbp *nativeProcess) kill() (err error) {
|
||||
if dbp.exited {
|
||||
return nil
|
||||
}
|
||||
@ -173,13 +173,13 @@ func (dbp *Process) kill() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (dbp *Process) requestManualStop() (err error) {
|
||||
func (dbp *nativeProcess) requestManualStop() (err error) {
|
||||
return sys.Kill(dbp.pid, sys.SIGTRAP)
|
||||
}
|
||||
|
||||
// Attach to a newly created thread, and store that thread in our list of
|
||||
// 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 {
|
||||
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,
|
||||
dbp: dbp,
|
||||
os: new(OSSpecificDetails),
|
||||
os: new(osSpecificDetails),
|
||||
}
|
||||
if dbp.currentThread == nil {
|
||||
dbp.currentThread = dbp.threads[tid]
|
||||
@ -228,7 +228,7 @@ func (dbp *Process) addThread(tid int, attach bool) (*Thread, error) {
|
||||
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))
|
||||
for _, tidpath := range tids {
|
||||
tidstr := filepath.Base(tidpath)
|
||||
@ -250,7 +250,7 @@ func findExecutable(path string, pid int) string {
|
||||
return path
|
||||
}
|
||||
|
||||
func (dbp *Process) trapWait(pid int) (*Thread, error) {
|
||||
func (dbp *nativeProcess) trapWait(pid int) (*nativeThread, error) {
|
||||
return dbp.trapWaitInternal(pid, 0)
|
||||
}
|
||||
|
||||
@ -261,7 +261,7 @@ const (
|
||||
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
|
||||
for {
|
||||
wopt := 0
|
||||
@ -280,7 +280,7 @@ func (dbp *Process) trapWaitInternal(pid int, options trapWaitOptions) (*Thread,
|
||||
}
|
||||
th, ok := dbp.threads[wpid]
|
||||
if ok {
|
||||
th.Status = (*WaitStatus)(status)
|
||||
th.Status = (*waitStatus)(status)
|
||||
}
|
||||
if status.Exited() {
|
||||
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
|
||||
func (dbp *Process) waitFast(pid int) (int, *sys.WaitStatus, error) {
|
||||
func (dbp *nativeProcess) waitFast(pid int) (int, *sys.WaitStatus, error) {
|
||||
var s sys.WaitStatus
|
||||
wpid, err := sys.Wait4(pid, &s, sys.WALL, nil)
|
||||
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
|
||||
if (pid != dbp.pid) || (options != 0) {
|
||||
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 {
|
||||
return wpid, &s, err
|
||||
}
|
||||
if status(pid, dbp.os.comm) == StatusZombie {
|
||||
if status(pid, dbp.os.comm) == statusZombie {
|
||||
return pid, nil, nil
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func (dbp *Process) exitGuard(err error) error {
|
||||
func (dbp *nativeProcess) exitGuard(err error) error {
|
||||
if err != sys.ESRCH {
|
||||
return err
|
||||
}
|
||||
if status(dbp.pid, dbp.os.comm) == StatusZombie {
|
||||
if status(dbp.pid, dbp.os.comm) == statusZombie {
|
||||
_, err := dbp.trapWaitInternal(-1, 0)
|
||||
return err
|
||||
}
|
||||
@ -437,7 +437,7 @@ func (dbp *Process) exitGuard(err error) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (dbp *Process) resume() error {
|
||||
func (dbp *nativeProcess) resume() error {
|
||||
// all threads stopped over a breakpoint are made to step over it
|
||||
for _, thread := range dbp.threads {
|
||||
if thread.CurrentBreakpoint.Breakpoint != nil {
|
||||
@ -457,7 +457,7 @@ func (dbp *Process) resume() error {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return &proc.ErrProcessExited{Pid: dbp.Pid()}
|
||||
}
|
||||
@ -517,9 +517,9 @@ func (dbp *Process) stop(trapthread *Thread) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dbp *Process) detach(kill bool) error {
|
||||
func (dbp *nativeProcess) detach(kill bool) error {
|
||||
for threadID := range dbp.threads {
|
||||
err := PtraceDetach(threadID, 0)
|
||||
err := ptraceDetach(threadID, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -540,7 +540,7 @@ func (dbp *Process) detach(kill bool) error {
|
||||
|
||||
// EntryPoint will return the process entry point address, useful for
|
||||
// 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))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("could not read auxiliary vector: %v", err)
|
||||
|
@ -15,8 +15,8 @@ import (
|
||||
"github.com/go-delve/delve/pkg/proc"
|
||||
)
|
||||
|
||||
// OSProcessDetails holds Windows specific information.
|
||||
type OSProcessDetails struct {
|
||||
// osProcessDetails holds Windows specific information.
|
||||
type osProcessDetails struct {
|
||||
hProcess syscall.Handle
|
||||
breakThread int
|
||||
entryPoint uint64
|
||||
@ -58,7 +58,7 @@ func Launch(cmd []string, wd string, foreground bool, _ []string) (*proc.Target,
|
||||
env := proc.DisableAsyncPreemptEnv()
|
||||
|
||||
var p *os.Process
|
||||
dbp := New(0)
|
||||
dbp := newProcess(0)
|
||||
dbp.execPtraceFunc(func() {
|
||||
attr := &os.ProcAttr{
|
||||
Dir: wd,
|
||||
@ -86,7 +86,7 @@ func Launch(cmd []string, wd string, foreground bool, _ []string) (*proc.Target,
|
||||
return tgt, nil
|
||||
}
|
||||
|
||||
func initialize(dbp *Process) error {
|
||||
func initialize(dbp *nativeProcess) error {
|
||||
// It should not actually be possible for the
|
||||
// call to waitForDebugEvent to fail, since Windows
|
||||
// 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.
|
||||
func Attach(pid int, _ []string) (*proc.Target, error) {
|
||||
dbp := New(pid)
|
||||
dbp := newProcess(pid)
|
||||
var err error
|
||||
dbp.execPtraceFunc(func() {
|
||||
// TODO: Probably should have SeDebugPrivilege before starting here.
|
||||
@ -177,7 +177,7 @@ func Attach(pid int, _ []string) (*proc.Target, error) {
|
||||
}
|
||||
|
||||
// kill kills the process.
|
||||
func (dbp *Process) kill() error {
|
||||
func (dbp *nativeProcess) kill() error {
|
||||
if dbp.exited {
|
||||
return nil
|
||||
}
|
||||
@ -203,24 +203,24 @@ func (dbp *Process) kill() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dbp *Process) requestManualStop() error {
|
||||
func (dbp *nativeProcess) requestManualStop() error {
|
||||
return _DebugBreakProcess(dbp.os.hProcess)
|
||||
}
|
||||
|
||||
func (dbp *Process) updateThreadList() error {
|
||||
func (dbp *nativeProcess) updateThreadList() error {
|
||||
// We ignore this request since threads are being
|
||||
// tracked as they are created/killed in waitForDebugEvent.
|
||||
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 {
|
||||
return thread, nil
|
||||
}
|
||||
thread := &Thread{
|
||||
thread := &nativeThread{
|
||||
ID: threadID,
|
||||
dbp: dbp,
|
||||
os: new(OSSpecificDetails),
|
||||
os: new(osSpecificDetails),
|
||||
}
|
||||
thread.os.hThread = hThread
|
||||
dbp.threads[threadID] = thread
|
||||
@ -250,7 +250,7 @@ const (
|
||||
|
||||
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
|
||||
shouldExit := false
|
||||
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 tid, exitCode int
|
||||
dbp.execPtraceFunc(func() {
|
||||
@ -395,15 +395,15 @@ func (dbp *Process) trapWait(pid int) (*Thread, error) {
|
||||
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")
|
||||
}
|
||||
|
||||
func (dbp *Process) exitGuard(err error) error {
|
||||
func (dbp *nativeProcess) exitGuard(err error) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (dbp *Process) resume() error {
|
||||
func (dbp *nativeProcess) resume() error {
|
||||
for _, thread := range dbp.threads {
|
||||
if thread.CurrentBreakpoint.Breakpoint != 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
|
||||
func (dbp *Process) stop(trapthread *Thread) (err error) {
|
||||
func (dbp *nativeProcess) stop(trapthread *nativeThread) (err error) {
|
||||
if dbp.exited {
|
||||
return &proc.ErrProcessExited{Pid: dbp.Pid()}
|
||||
}
|
||||
@ -475,7 +475,7 @@ func (dbp *Process) stop(trapthread *Thread) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dbp *Process) detach(kill bool) error {
|
||||
func (dbp *nativeProcess) detach(kill bool) error {
|
||||
if !kill {
|
||||
//TODO(aarzilli): when debug.Target exist Detach should be moved to
|
||||
// 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))
|
||||
}
|
||||
|
||||
func (dbp *Process) EntryPoint() (uint64, error) {
|
||||
func (dbp *nativeProcess) EntryPoint() (uint64, error) {
|
||||
return dbp.os.entryPoint, nil
|
||||
}
|
||||
|
||||
|
@ -4,23 +4,23 @@ package native
|
||||
|
||||
import sys "golang.org/x/sys/unix"
|
||||
|
||||
// PtraceAttach executes the sys.PtraceAttach call.
|
||||
func PtraceAttach(pid int) error {
|
||||
// ptraceAttach executes the sys.PtraceAttach call.
|
||||
func ptraceAttach(pid int) error {
|
||||
return sys.PtraceAttach(pid)
|
||||
}
|
||||
|
||||
// PtraceDetach executes the PT_DETACH ptrace call.
|
||||
func PtraceDetach(tid, sig int) error {
|
||||
// ptraceDetach executes the PT_DETACH ptrace call.
|
||||
func ptraceDetach(tid, sig int) error {
|
||||
return ptrace(sys.PT_DETACH, tid, 1, uintptr(sig))
|
||||
}
|
||||
|
||||
// PtraceCont executes the PTRACE_CONT ptrace call.
|
||||
func PtraceCont(tid, sig int) error {
|
||||
// ptraceCont executes the PTRACE_CONT ptrace call.
|
||||
func ptraceCont(tid, sig int) error {
|
||||
return ptrace(sys.PTRACE_CONT, tid, 1, 0)
|
||||
}
|
||||
|
||||
// PtraceSingleStep returns PT_STEP ptrace call.
|
||||
func PtraceSingleStep(tid int) error {
|
||||
// ptraceSingleStep returns PT_STEP ptrace call.
|
||||
func ptraceSingleStep(tid int) error {
|
||||
return ptrace(sys.PT_STEP, tid, 1, 0)
|
||||
}
|
||||
|
||||
|
@ -17,31 +17,31 @@ import (
|
||||
"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
|
||||
func PtraceAttach(pid int) error {
|
||||
func ptraceAttach(pid int) error {
|
||||
return sys.PtraceAttach(pid)
|
||||
}
|
||||
|
||||
// PtraceDetach calls ptrace(PTRACE_DETACH).
|
||||
func PtraceDetach(pid int) error {
|
||||
// ptraceDetach calls ptrace(PTRACE_DETACH).
|
||||
func ptraceDetach(pid int) error {
|
||||
return sys.PtraceDetach(pid)
|
||||
}
|
||||
|
||||
// PtraceCont executes ptrace PTRACE_CONT
|
||||
// ptraceCont executes ptrace PTRACE_CONT
|
||||
// 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)
|
||||
}
|
||||
|
||||
// PtraceSingleStep executes ptrace PTRACE_SINGLE_STEP.
|
||||
// ptraceSingleStep executes ptrace PTRACE_SINGLE_STEP.
|
||||
// id may be a PID or an LWPID
|
||||
func PtraceSingleStep(id int) error {
|
||||
func ptraceSingleStep(id int) error {
|
||||
return sys.PtraceSingleStep(id)
|
||||
}
|
||||
|
||||
// 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))
|
||||
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))
|
||||
@ -54,7 +54,7 @@ func ptraceGetLwpInfo(wpid int) (info sys.PtraceLwpInfoStruct, err error) {
|
||||
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)
|
||||
if err == syscall.Errno(0) || err == syscall.ENODEV {
|
||||
var xsave_len C.size_t
|
||||
|
@ -2,18 +2,17 @@ package native
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
sys "golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// PtraceAttach executes the sys.PtraceAttach call.
|
||||
func PtraceAttach(pid int) error {
|
||||
// ptraceAttach executes the sys.PtraceAttach call.
|
||||
func ptraceAttach(pid int) error {
|
||||
return sys.PtraceAttach(pid)
|
||||
}
|
||||
|
||||
// PtraceDetach calls ptrace(PTRACE_DETACH).
|
||||
func PtraceDetach(tid, sig int) error {
|
||||
// ptraceDetach calls ptrace(PTRACE_DETACH).
|
||||
func ptraceDetach(tid, sig int) error {
|
||||
_, _, err := sys.Syscall6(sys.SYS_PTRACE, sys.PTRACE_DETACH, uintptr(tid), 1, uintptr(sig), 0, 0)
|
||||
if err != syscall.Errno(0) {
|
||||
return err
|
||||
@ -21,31 +20,7 @@ func PtraceDetach(tid, sig int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PtraceCont executes ptrace PTRACE_CONT
|
||||
func PtraceCont(tid, sig int) error {
|
||||
// ptraceCont executes ptrace PTRACE_CONT
|
||||
func ptraceCont(tid, sig int) error {
|
||||
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"
|
||||
)
|
||||
|
||||
// PtraceGetRegset returns floating point registers of the specified thread
|
||||
// ptraceGetRegset returns floating point registers of the specified thread
|
||||
// using PTRACE.
|
||||
// See i386_linux_fetch_inferior_registers in gdb/i386-linux-nat.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
|
||||
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)
|
||||
if err == syscall.Errno(0) || err == syscall.ENODEV {
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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.
|
||||
// struct user_desc at https://golang.org/src/runtime/sys_linux_386.s
|
||||
// type UserDesc struct {
|
||||
@ -52,7 +52,7 @@ func PtraceGetRegset(tid int) (regset linutil.I386Xstate, err error) {
|
||||
// Limit uint32
|
||||
// Flag uint32
|
||||
// }
|
||||
func PtraceGetTls(gs int32, tid int) (uint32, error) {
|
||||
func ptraceGetTls(gs int32, tid int) (uint32, error) {
|
||||
ud := [4]uint32{}
|
||||
|
||||
// Gs usually is 0x33
|
||||
@ -64,8 +64,8 @@ func PtraceGetTls(gs int32, tid int) (uint32, error) {
|
||||
return uint32(ud[1]), nil
|
||||
}
|
||||
|
||||
// ProcessVmRead calls process_vm_readv
|
||||
func ProcessVmRead(tid int, addr uintptr, data []byte) (int, error) {
|
||||
// processVmRead calls process_vm_readv
|
||||
func processVmRead(tid int, addr uintptr, data []byte) (int, error) {
|
||||
len_iov := uint32(len(data))
|
||||
local_iov := sys.Iovec{Base: &data[0], 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
|
||||
}
|
||||
|
||||
// ProcessVmWrite calls process_vm_writev
|
||||
func ProcessVmWrite(tid int, addr uintptr, data []byte) (int, error) {
|
||||
// processVmWrite calls process_vm_writev
|
||||
func processVmWrite(tid int, addr uintptr, data []byte) (int, error) {
|
||||
len_iov := uint32(len(data))
|
||||
local_iov := sys.Iovec{Base: &data[0], 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"
|
||||
)
|
||||
|
||||
// ProcessVmRead calls process_vm_readv
|
||||
func ProcessVmRead(tid int, addr uintptr, data []byte) (int, error) {
|
||||
// processVmRead calls process_vm_readv
|
||||
func processVmRead(tid int, addr uintptr, data []byte) (int, error) {
|
||||
len_iov := uint64(len(data))
|
||||
local_iov := sys.Iovec{Base: &data[0], 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
|
||||
}
|
||||
|
||||
// ProcessVmWrite calls process_vm_writev
|
||||
func ProcessVmWrite(tid int, addr uintptr, data []byte) (int, error) {
|
||||
// processVmWrite calls process_vm_writev
|
||||
func processVmWrite(tid int, addr uintptr, data []byte) (int, error) {
|
||||
len_iov := uint64(len(data))
|
||||
local_iov := sys.Iovec{Base: &data[0], 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"
|
||||
)
|
||||
|
||||
// PtraceGetRegset returns floating point registers of the specified thread
|
||||
// ptraceGetRegset returns floating point registers of the specified thread
|
||||
// using PTRACE.
|
||||
// See amd64_linux_fetch_inferior_registers in gdb/amd64-linux-nat.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
|
||||
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)
|
||||
if err == syscall.Errno(0) || err == syscall.ENODEV {
|
||||
// ignore ENODEV, it just means this CPU doesn't have X87 registers (??)
|
||||
@ -38,4 +38,4 @@ func PtraceGetRegset(tid int) (regset linutil.AMD64Xstate, err error) {
|
||||
regset.Xsave = xstateargs[:iov.Len]
|
||||
err = linutil.AMD64XstateRead(regset.Xsave, false, ®set)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -22,7 +22,7 @@ func (thread *Thread) SetPC(pc uint64) error {
|
||||
}
|
||||
|
||||
// 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
|
||||
ir, err = registers(thread, false)
|
||||
if err != nil {
|
||||
@ -34,7 +34,7 @@ func (thread *Thread) SetSP(sp uint64) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (thread *Thread) SetDX(dx uint64) (err error) {
|
||||
func (thread *nativeThread) SetDX(dx uint64) (err error) {
|
||||
var ir proc.Registers
|
||||
ir, err = registers(thread, false)
|
||||
if err != nil {
|
||||
@ -46,7 +46,7 @@ func (thread *Thread) SetDX(dx uint64) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) {
|
||||
func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error) {
|
||||
var (
|
||||
regs linutil.I386PtraceRegs
|
||||
err error
|
||||
@ -65,7 +65,7 @@ func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) {
|
||||
}
|
||||
}
|
||||
thread.dbp.execPtraceFunc(func() {
|
||||
tls, _ := PtraceGetTls(regs.Xgs, thread.ThreadID())
|
||||
tls, _ := ptraceGetTls(regs.Xgs, thread.ThreadID())
|
||||
r.Tls = uint64(tls)
|
||||
})
|
||||
return r, nil
|
||||
@ -81,8 +81,8 @@ const (
|
||||
_XSAVE_SSE_REGION_LEN = 416
|
||||
)
|
||||
|
||||
func (thread *Thread) fpRegisters() (regs []proc.Register, fpregs linutil.I386Xstate, err error) {
|
||||
thread.dbp.execPtraceFunc(func() { fpregs, err = PtraceGetRegset(thread.ID) })
|
||||
func (thread *nativeThread) fpRegisters() (regs []proc.Register, fpregs linutil.I386Xstate, err error) {
|
||||
thread.dbp.execPtraceFunc(func() { fpregs, err = ptraceGetRegset(thread.ID) })
|
||||
regs = fpregs.Decode()
|
||||
if err != nil {
|
||||
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`.
|
||||
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))
|
||||
if kret != C.KERN_SUCCESS {
|
||||
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`.
|
||||
func (thread *Thread) SetSP(sp uint64) error {
|
||||
func (thread *nativeThread) SetSP(sp uint64) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (thread *Thread) SetDX(dx uint64) error {
|
||||
func (thread *nativeThread) SetDX(dx uint64) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
@ -285,7 +285,7 @@ func (r *Regs) Get(n int) (uint64, error) {
|
||||
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 identity C.thread_identifier_info_data_t
|
||||
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'.
|
||||
func (thread *Thread) SetPC(pc uint64) error {
|
||||
func (thread *nativeThread) SetPC(pc uint64) error {
|
||||
ir, err := registers(thread, false)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -22,7 +22,7 @@ func (thread *Thread) SetPC(pc uint64) error {
|
||||
}
|
||||
|
||||
// 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
|
||||
ir, err = registers(thread, false)
|
||||
if err != nil {
|
||||
@ -34,7 +34,7 @@ func (thread *Thread) SetSP(sp uint64) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (thread *Thread) SetDX(dx uint64) (err error) {
|
||||
func (thread *nativeThread) SetDX(dx uint64) (err error) {
|
||||
var ir proc.Registers
|
||||
ir, err = registers(thread, false)
|
||||
if err != nil {
|
||||
@ -46,7 +46,7 @@ func (thread *Thread) SetDX(dx uint64) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) {
|
||||
func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error) {
|
||||
var (
|
||||
regs fbsdutil.AMD64PtraceRegs
|
||||
err error
|
||||
@ -82,8 +82,8 @@ const (
|
||||
_XSAVE_SSE_REGION_LEN = 416
|
||||
)
|
||||
|
||||
func (thread *Thread) fpRegisters() (regs []proc.Register, fpregs fbsdutil.AMD64Xstate, err error) {
|
||||
thread.dbp.execPtraceFunc(func() { fpregs, err = PtraceGetRegset(thread.ID) })
|
||||
func (thread *nativeThread) fpRegisters() (regs []proc.Register, fpregs fbsdutil.AMD64Xstate, err error) {
|
||||
thread.dbp.execPtraceFunc(func() { fpregs, err = ptraceGetRegset(thread.ID) })
|
||||
if err != nil {
|
||||
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'.
|
||||
func (thread *Thread) SetPC(pc uint64) error {
|
||||
func (thread *nativeThread) SetPC(pc uint64) error {
|
||||
ir, err := registers(thread, false)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -22,7 +22,7 @@ func (thread *Thread) SetPC(pc uint64) error {
|
||||
}
|
||||
|
||||
// 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
|
||||
ir, err = registers(thread, false)
|
||||
if err != nil {
|
||||
@ -34,7 +34,7 @@ func (thread *Thread) SetSP(sp uint64) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (thread *Thread) SetDX(dx uint64) (err error) {
|
||||
func (thread *nativeThread) SetDX(dx uint64) (err error) {
|
||||
var ir proc.Registers
|
||||
ir, err = registers(thread, false)
|
||||
if err != nil {
|
||||
@ -46,7 +46,7 @@ func (thread *Thread) SetDX(dx uint64) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) {
|
||||
func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error) {
|
||||
var (
|
||||
regs linutil.AMD64PtraceRegs
|
||||
err error
|
||||
@ -77,8 +77,8 @@ const (
|
||||
_XSAVE_SSE_REGION_LEN = 416
|
||||
)
|
||||
|
||||
func (thread *Thread) fpRegisters() (regs []proc.Register, fpregs linutil.AMD64Xstate, err error) {
|
||||
thread.dbp.execPtraceFunc(func() { fpregs, err = PtraceGetRegset(thread.ID) })
|
||||
func (thread *nativeThread) fpRegisters() (regs []proc.Register, fpregs linutil.AMD64Xstate, err error) {
|
||||
thread.dbp.execPtraceFunc(func() { fpregs, err = ptraceGetRegset(thread.ID) })
|
||||
regs = fpregs.Decode()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not get floating point registers: %v", err.Error())
|
||||
|
@ -13,12 +13,12 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
AARCH64_GREGS_SIZE = 34 * 8
|
||||
AARCH64_FPREGS_SIZE = 32*16 + 8
|
||||
_AARCH64_GREGS_SIZE = 34 * 8
|
||||
_AARCH64_FPREGS_SIZE = 32*16 + 8
|
||||
)
|
||||
|
||||
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)
|
||||
if err == syscall.Errno(0) {
|
||||
err = nil
|
||||
@ -27,7 +27,7 @@ func ptraceGetGRegs(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)
|
||||
if err == syscall.Errno(0) {
|
||||
err = nil
|
||||
@ -35,11 +35,11 @@ func ptraceSetGRegs(pid int, regs *linutil.ARM64PtraceRegs) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// PtraceGetFpRegset returns floating point registers of the specified thread
|
||||
// ptraceGetFpRegset returns floating point registers of the specified thread
|
||||
// using PTRACE.
|
||||
func PtraceGetFpRegset(tid int) (fpregset []byte, err error) {
|
||||
var arm64_fpregs [AARCH64_FPREGS_SIZE]byte
|
||||
iov := sys.Iovec{Base: &arm64_fpregs[0], Len: AARCH64_FPREGS_SIZE}
|
||||
func ptraceGetFpRegset(tid int) (fpregset []byte, err error) {
|
||||
var arm64_fpregs [_AARCH64_FPREGS_SIZE]byte
|
||||
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)
|
||||
if err != syscall.Errno(0) {
|
||||
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'.
|
||||
func (thread *Thread) SetPC(pc uint64) error {
|
||||
func (thread *nativeThread) SetPC(pc uint64) error {
|
||||
ir, err := registers(thread, false)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -67,7 +67,7 @@ func (thread *Thread) SetPC(pc uint64) error {
|
||||
}
|
||||
|
||||
// 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
|
||||
ir, err = registers(thread, false)
|
||||
if err != nil {
|
||||
@ -79,11 +79,11 @@ func (thread *Thread) SetSP(sp uint64) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (thread *Thread) SetDX(dx uint64) (err error) {
|
||||
func (thread *nativeThread) SetDX(dx uint64) (err error) {
|
||||
return fmt.Errorf("not supported")
|
||||
}
|
||||
|
||||
func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) {
|
||||
func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error) {
|
||||
var (
|
||||
regs linutil.ARM64PtraceRegs
|
||||
err error
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
// 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.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`.
|
||||
func (thread *Thread) SetSP(sp uint64) error {
|
||||
func (thread *nativeThread) SetSP(sp uint64) error {
|
||||
context := winutil.NewCONTEXT()
|
||||
context.ContextFlags = _CONTEXT_ALL
|
||||
|
||||
@ -38,7 +38,7 @@ func (thread *Thread) SetSP(sp uint64) error {
|
||||
return _SetThreadContext(thread.os.hThread, context)
|
||||
}
|
||||
|
||||
func (thread *Thread) SetDX(dx uint64) error {
|
||||
func (thread *nativeThread) SetDX(dx uint64) error {
|
||||
context := winutil.NewCONTEXT()
|
||||
context.ContextFlags = _CONTEXT_ALL
|
||||
|
||||
@ -52,7 +52,7 @@ func (thread *Thread) SetDX(dx uint64) error {
|
||||
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.ContextFlags = _CONTEXT_ALL
|
||||
|
@ -11,14 +11,14 @@ import (
|
||||
// Process struct that contains info on the process as
|
||||
// a whole, and Status represents the last result of a `wait` call
|
||||
// on this thread.
|
||||
type Thread struct {
|
||||
type nativeThread struct {
|
||||
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
|
||||
|
||||
dbp *Process
|
||||
dbp *nativeProcess
|
||||
singleStepping bool
|
||||
os *OSSpecificDetails
|
||||
os *osSpecificDetails
|
||||
common proc.CommonThread
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@ type Thread struct {
|
||||
// If we are currently at a breakpoint, we'll clear it
|
||||
// first and then resume execution. Thread will continue until
|
||||
// it hits a breakpoint or is signaled.
|
||||
func (t *Thread) Continue() error {
|
||||
func (t *nativeThread) Continue() error {
|
||||
pc, err := t.PC()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -48,7 +48,7 @@ func (t *Thread) Continue() error {
|
||||
// If the thread is at a breakpoint, we first clear it,
|
||||
// execute the instruction, and then replace the breakpoint.
|
||||
// Otherwise we simply execute the next instruction.
|
||||
func (t *Thread) StepInstruction() (err error) {
|
||||
func (t *nativeThread) StepInstruction() (err error) {
|
||||
t.singleStepping = true
|
||||
defer func() {
|
||||
t.singleStepping = false
|
||||
@ -85,7 +85,7 @@ func (t *Thread) StepInstruction() (err error) {
|
||||
// Location returns the threads location, including the file:line
|
||||
// of the corresponding source code, the function we're in
|
||||
// and the current instruction address.
|
||||
func (t *Thread) Location() (*proc.Location, error) {
|
||||
func (t *nativeThread) Location() (*proc.Location, error) {
|
||||
pc, err := t.PC()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -95,19 +95,19 @@ func (t *Thread) Location() (*proc.Location, error) {
|
||||
}
|
||||
|
||||
// BinInfo returns information on the binary.
|
||||
func (t *Thread) BinInfo() *proc.BinaryInfo {
|
||||
func (t *nativeThread) BinInfo() *proc.BinaryInfo {
|
||||
return t.dbp.bi
|
||||
}
|
||||
|
||||
// Common returns information common across Process
|
||||
// implementations.
|
||||
func (t *Thread) Common() *proc.CommonThread {
|
||||
func (t *nativeThread) Common() *proc.CommonThread {
|
||||
return &t.common
|
||||
}
|
||||
|
||||
// SetCurrentBreakpoint sets the current breakpoint that this
|
||||
// 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()
|
||||
pc, err := t.PC()
|
||||
if err != nil {
|
||||
@ -139,17 +139,17 @@ func (t *Thread) SetCurrentBreakpoint(adjustPC bool) error {
|
||||
|
||||
// Breakpoint returns the current breakpoint that is active
|
||||
// on this thread.
|
||||
func (t *Thread) Breakpoint() *proc.BreakpointState {
|
||||
func (t *nativeThread) Breakpoint() *proc.BreakpointState {
|
||||
return &t.CurrentBreakpoint
|
||||
}
|
||||
|
||||
// ThreadID returns the ID of this thread.
|
||||
func (t *Thread) ThreadID() int {
|
||||
func (t *nativeThread) ThreadID() int {
|
||||
return t.ID
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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.
|
||||
func (t *Thread) Registers(floatingPoint bool) (proc.Registers, error) {
|
||||
func (t *nativeThread) Registers(floatingPoint bool) (proc.Registers, error) {
|
||||
return registers(t, floatingPoint)
|
||||
}
|
||||
|
||||
// RestoreRegisters will set the value of the CPU registers to those
|
||||
// passed in via 'savedRegs'.
|
||||
func (t *Thread) RestoreRegisters(savedRegs proc.Registers) error {
|
||||
func (t *nativeThread) RestoreRegisters(savedRegs proc.Registers) error {
|
||||
return t.restoreRegisters(savedRegs)
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -15,12 +15,12 @@ import (
|
||||
"github.com/go-delve/delve/pkg/proc"
|
||||
)
|
||||
|
||||
// WaitStatus is a synonym for the platform-specific WaitStatus
|
||||
type WaitStatus sys.WaitStatus
|
||||
// waitStatus is a synonym for the platform-specific WaitStatus
|
||||
type waitStatus sys.WaitStatus
|
||||
|
||||
// OSSpecificDetails holds information specific to the OSX/Darwin
|
||||
// osSpecificDetails holds information specific to the OSX/Darwin
|
||||
// operating system / kernel.
|
||||
type OSSpecificDetails struct {
|
||||
type osSpecificDetails struct {
|
||||
threadAct C.thread_act_t
|
||||
registers C.x86_thread_state64_t
|
||||
exists bool
|
||||
@ -30,7 +30,7 @@ type OSSpecificDetails struct {
|
||||
// be continued.
|
||||
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)
|
||||
if kret != C.KERN_SUCCESS {
|
||||
errStr := C.GoString(C.mach_error_string(C.mach_error_t(kret)))
|
||||
@ -49,7 +49,7 @@ func (t *Thread) stop() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (t *Thread) singleStep() error {
|
||||
func (t *nativeThread) singleStep() error {
|
||||
kret := C.single_step(t.os.threadAct)
|
||||
if kret != C.KERN_SUCCESS {
|
||||
return fmt.Errorf("could not single step")
|
||||
@ -71,10 +71,10 @@ func (t *Thread) singleStep() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Thread) resume() error {
|
||||
func (t *nativeThread) resume() error {
|
||||
// TODO(dp) set flag for ptrace stops
|
||||
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 {
|
||||
return nil
|
||||
}
|
||||
@ -85,7 +85,7 @@ func (t *Thread) resume() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Thread) Blocked() bool {
|
||||
func (t *nativeThread) Blocked() bool {
|
||||
// TODO(dp) cache the func pc to remove this lookup
|
||||
regs, err := t.Registers(false)
|
||||
if err != nil {
|
||||
@ -106,11 +106,11 @@ func (t *Thread) Blocked() bool {
|
||||
|
||||
// Stopped returns whether the thread is stopped at
|
||||
// the operating system level.
|
||||
func (t *Thread) Stopped() bool {
|
||||
func (t *nativeThread) Stopped() bool {
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
func (t *Thread) ReadMemory(buf []byte, addr uintptr) (int, error) {
|
||||
func (t *nativeThread) ReadMemory(buf []byte, addr uintptr) (int, error) {
|
||||
if t.dbp.exited {
|
||||
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
|
||||
}
|
||||
|
||||
func (t *Thread) restoreRegisters(sr proc.Registers) error {
|
||||
func (t *nativeThread) restoreRegisters(sr proc.Registers) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
@ -13,14 +13,14 @@ import (
|
||||
"github.com/go-delve/delve/pkg/proc"
|
||||
)
|
||||
|
||||
type WaitStatus sys.WaitStatus
|
||||
type waitStatus sys.WaitStatus
|
||||
|
||||
// OSSpecificDetails hold FreeBSD specific process details.
|
||||
type OSSpecificDetails struct {
|
||||
// osSpecificDetails hold FreeBSD specific process details.
|
||||
type osSpecificDetails struct {
|
||||
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))
|
||||
if err != nil {
|
||||
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
|
||||
// signal
|
||||
t.dbp.execPtraceFunc(func() { err = PtraceCont(t.dbp.pid, 0) })
|
||||
t.dbp.execPtraceFunc(func() { err = ptraceCont(t.dbp.pid, 0) })
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -40,22 +40,22 @@ func (t *Thread) stop() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (t *Thread) Stopped() bool {
|
||||
func (t *nativeThread) Stopped() bool {
|
||||
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)
|
||||
}
|
||||
|
||||
func (t *Thread) resumeWithSig(sig int) (err error) {
|
||||
t.dbp.execPtraceFunc(func() { err = PtraceCont(t.ID, sig) })
|
||||
func (t *nativeThread) resumeWithSig(sig int) (err error) {
|
||||
t.dbp.execPtraceFunc(func() { err = ptraceCont(t.ID, sig) })
|
||||
return
|
||||
}
|
||||
|
||||
func (t *Thread) singleStep() (err error) {
|
||||
t.dbp.execPtraceFunc(func() { err = PtraceSingleStep(t.ID) })
|
||||
func (t *nativeThread) singleStep() (err error) {
|
||||
t.dbp.execPtraceFunc(func() { err = ptraceSingleStep(t.ID) })
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -67,7 +67,7 @@ func (t *Thread) singleStep() (err error) {
|
||||
if th.ID == t.ID {
|
||||
break
|
||||
}
|
||||
t.dbp.execPtraceFunc(func() { err = PtraceCont(th.ID, 0) })
|
||||
t.dbp.execPtraceFunc(func() { err = ptraceCont(th.ID, 0) })
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -75,7 +75,7 @@ func (t *Thread) singleStep() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Thread) Blocked() bool {
|
||||
func (t *nativeThread) Blocked() bool {
|
||||
loc, err := t.Location()
|
||||
if err != nil {
|
||||
return false
|
||||
@ -86,7 +86,7 @@ func (t *Thread) Blocked() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *Thread) restoreRegisters(savedRegs proc.Registers) error {
|
||||
func (t *nativeThread) restoreRegisters(savedRegs proc.Registers) error {
|
||||
sr := savedRegs.(*fbsdutil.AMD64Registers)
|
||||
|
||||
var restoreRegistersErr error
|
||||
@ -110,7 +110,7 @@ func (t *Thread) restoreRegisters(savedRegs proc.Registers) error {
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
return 0, proc.ErrProcessExited{Pid: t.dbp.pid}
|
||||
}
|
||||
|
@ -8,18 +8,18 @@ import (
|
||||
"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.
|
||||
type OSSpecificDetails struct {
|
||||
type osSpecificDetails struct {
|
||||
delayedSignal int
|
||||
registers sys.PtraceRegs
|
||||
running 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)
|
||||
if err != nil {
|
||||
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
|
||||
// the operating system level.
|
||||
func (t *Thread) Stopped() bool {
|
||||
func (t *nativeThread) Stopped() bool {
|
||||
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
|
||||
t.os.delayedSignal = 0
|
||||
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.dbp.execPtraceFunc(func() { err = PtraceCont(t.ID, sig) })
|
||||
t.dbp.execPtraceFunc(func() { err = ptraceCont(t.ID, sig) })
|
||||
return
|
||||
}
|
||||
|
||||
func (t *Thread) singleStep() (err error) {
|
||||
func (t *nativeThread) singleStep() (err error) {
|
||||
for {
|
||||
t.dbp.execPtraceFunc(func() { err = sys.PtraceSingleStep(t.ID) })
|
||||
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)
|
||||
if err != nil {
|
||||
return false
|
||||
@ -84,7 +84,7 @@ func (t *Thread) Blocked() bool {
|
||||
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 {
|
||||
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
|
||||
// even bother for small writes -- likely breakpoints and such.
|
||||
if len(data) > sys.SizeofPtr {
|
||||
written, _ = ProcessVmWrite(t.ID, addr, data)
|
||||
written, _ = processVmWrite(t.ID, addr, data)
|
||||
}
|
||||
if written == 0 {
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
return 0, proc.ErrProcessExited{Pid: t.dbp.pid}
|
||||
}
|
||||
if len(data) == 0 {
|
||||
return
|
||||
}
|
||||
n, _ = ProcessVmRead(t.ID, addr, data)
|
||||
n, _ = processVmRead(t.ID, addr, data)
|
||||
if n == 0 {
|
||||
t.dbp.execPtraceFunc(func() { n, err = sys.PtracePeekData(t.ID, addr, data) })
|
||||
}
|
||||
|
@ -5,6 +5,6 @@ import (
|
||||
"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")
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
"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)
|
||||
|
||||
var restoreRegistersErr error
|
||||
|
@ -12,10 +12,10 @@ import (
|
||||
"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 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()
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
func (t *Thread) restoreRegisters(savedRegs proc.Registers) error {
|
||||
func (t *nativeThread) restoreRegisters(savedRegs proc.Registers) error {
|
||||
sr := savedRegs.(*linutil.ARM64Registers)
|
||||
|
||||
var restoreRegistersErr error
|
||||
|
@ -10,16 +10,16 @@ import (
|
||||
"github.com/go-delve/delve/pkg/proc/winutil"
|
||||
)
|
||||
|
||||
// WaitStatus is a synonym for the platform-specific WaitStatus
|
||||
type WaitStatus sys.WaitStatus
|
||||
// waitStatus is a synonym for the platform-specific WaitStatus
|
||||
type waitStatus sys.WaitStatus
|
||||
|
||||
// OSSpecificDetails holds information specific to the Windows
|
||||
// osSpecificDetails holds information specific to the Windows
|
||||
// operating system / kernel.
|
||||
type OSSpecificDetails struct {
|
||||
type osSpecificDetails struct {
|
||||
hThread syscall.Handle
|
||||
}
|
||||
|
||||
func (t *Thread) singleStep() error {
|
||||
func (t *nativeThread) singleStep() error {
|
||||
context := winutil.NewCONTEXT()
|
||||
context.ContextFlags = _CONTEXT_ALL
|
||||
|
||||
@ -101,7 +101,7 @@ func (t *Thread) singleStep() error {
|
||||
return _SetThreadContext(t.os.hThread, context)
|
||||
}
|
||||
|
||||
func (t *Thread) resume() error {
|
||||
func (t *nativeThread) resume() error {
|
||||
var err error
|
||||
t.dbp.execPtraceFunc(func() {
|
||||
//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
|
||||
}
|
||||
|
||||
func (t *Thread) Blocked() bool {
|
||||
func (t *nativeThread) Blocked() bool {
|
||||
// TODO: Probably incorrect - what are the runtime functions that
|
||||
// indicate blocking on Windows?
|
||||
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
|
||||
// level. On windows this always returns true.
|
||||
func (t *Thread) Stopped() bool {
|
||||
func (t *nativeThread) Stopped() bool {
|
||||
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 {
|
||||
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")
|
||||
|
||||
func (t *Thread) ReadMemory(buf []byte, addr uintptr) (int, error) {
|
||||
func (t *nativeThread) ReadMemory(buf []byte, addr uintptr) (int, error) {
|
||||
if t.dbp.exited {
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
@ -239,12 +239,6 @@ func TestHalt(t *testing.T) {
|
||||
withTestProcess("loopprog", t, func(p *proc.Target, fixture protest.Fixture) {
|
||||
setFunctionBreakpoint(p, t, "main.loop")
|
||||
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)
|
||||
go func() {
|
||||
<-resumeChan
|
||||
@ -258,21 +252,6 @@ func TestHalt(t *testing.T) {
|
||||
if err, ok := retVal.(error); ok && err != nil {
|
||||
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.
|
||||
type FixtureKey struct {
|
||||
type fixtureKey struct {
|
||||
Name string
|
||||
Flags BuildFlags
|
||||
}
|
||||
|
||||
// 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
|
||||
var PathsToRemove []string
|
||||
@ -84,8 +84,8 @@ func BuildFixture(name string, flags BuildFlags) Fixture {
|
||||
if !runningWithFixtures {
|
||||
panic("RunTestsWithFixtures not called")
|
||||
}
|
||||
fk := FixtureKey{name, flags}
|
||||
if f, ok := Fixtures[fk]; ok {
|
||||
fk := fixtureKey{name, flags}
|
||||
if f, ok := fixtures[fk]; ok {
|
||||
return f
|
||||
}
|
||||
|
||||
@ -180,8 +180,8 @@ func BuildFixture(name string, flags BuildFlags) Fixture {
|
||||
|
||||
fixture := Fixture{Name: name, Path: tmpfile, Source: source, BuildDir: absdir}
|
||||
|
||||
Fixtures[fk] = fixture
|
||||
return Fixtures[fk]
|
||||
fixtures[fk] = fixture
|
||||
return fixtures[fk]
|
||||
}
|
||||
|
||||
// RunTestsWithFixtures will pre-compile test fixtures before running test
|
||||
@ -194,7 +194,7 @@ func RunTestsWithFixtures(m *testing.M) int {
|
||||
status := m.Run()
|
||||
|
||||
// Remove the fixtures.
|
||||
for _, f := range Fixtures {
|
||||
for _, f := range fixtures {
|
||||
os.Remove(f.Path)
|
||||
}
|
||||
|
||||
|
@ -85,23 +85,23 @@ type Commands struct {
|
||||
}
|
||||
|
||||
var (
|
||||
// LongLoadConfig loads more information:
|
||||
// longLoadConfig loads more information:
|
||||
// * Follows pointers
|
||||
// * Loads more array values
|
||||
// * 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
|
||||
// and limiting struct fields loaded to 3.
|
||||
ShortLoadConfig = api.LoadConfig{MaxStringLen: 64, MaxStructFields: 3}
|
||||
)
|
||||
|
||||
// ByFirstAlias will sort by the first
|
||||
// byFirstAlias will sort by the first
|
||||
// alias of a command.
|
||||
type ByFirstAlias []command
|
||||
type byFirstAlias []command
|
||||
|
||||
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) Less(i, j int) bool { return a[i].aliases[0] < a[j].aliases[0] }
|
||||
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) Less(i, j int) bool { return a[i].aliases[0] < a[j].aliases[0] }
|
||||
|
||||
// DebugCommands returns a Commands struct with default commands defined.
|
||||
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
|
||||
}
|
||||
|
||||
@ -592,7 +592,7 @@ func threads(t *Term, ctx callContext, args string) error {
|
||||
}
|
||||
if th.Function != nil {
|
||||
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())
|
||||
} else {
|
||||
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)
|
||||
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)
|
||||
return nil
|
||||
}
|
||||
@ -863,7 +863,7 @@ func formatThread(th *api.Thread) string {
|
||||
if th == 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
|
||||
@ -876,7 +876,7 @@ const (
|
||||
)
|
||||
|
||||
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 {
|
||||
@ -1325,19 +1325,19 @@ func clearAll(t *Term, ctx callContext, args string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ByID sorts breakpoints by ID.
|
||||
type ByID []*api.Breakpoint
|
||||
// byID sorts breakpoints by ID.
|
||||
type byID []*api.Breakpoint
|
||||
|
||||
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) Less(i, j int) bool { return a[i].ID < a[j].ID }
|
||||
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) Less(i, j int) bool { return a[i].ID < a[j].ID }
|
||||
|
||||
func breakpoints(t *Term, ctx callContext, args string) error {
|
||||
breakPoints, err := t.client.ListBreakpoints()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sort.Sort(ByID(breakPoints))
|
||||
sort.Sort(byID(breakPoints))
|
||||
for _, bp := range breakPoints {
|
||||
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")
|
||||
}
|
||||
if bp.LoadArgs != nil {
|
||||
if *(bp.LoadArgs) == LongLoadConfig {
|
||||
if *(bp.LoadArgs) == longLoadConfig {
|
||||
attrs = append(attrs, "\targs -v")
|
||||
} else {
|
||||
attrs = append(attrs, "\targs")
|
||||
}
|
||||
}
|
||||
if bp.LoadLocals != nil {
|
||||
if *(bp.LoadLocals) == LongLoadConfig {
|
||||
if *(bp.LoadLocals) == longLoadConfig {
|
||||
attrs = append(attrs, "\tlocals -v")
|
||||
} else {
|
||||
attrs = append(attrs, "\tlocals")
|
||||
@ -1955,7 +1955,7 @@ func disassCommand(t *Term, ctx callContext, args string) error {
|
||||
return disasmErr
|
||||
}
|
||||
|
||||
DisasmPrint(disasm, os.Stdout)
|
||||
disasmPrint(disasm, os.Stdout)
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -2004,7 +2004,7 @@ func printStack(stack []api.Stackframe, ind string, offsets bool) {
|
||||
continue
|
||||
}
|
||||
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 {
|
||||
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) {
|
||||
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 {
|
||||
fmt.Println(optimizedFunctionWarning)
|
||||
}
|
||||
@ -2137,7 +2137,7 @@ func printcontextThread(t *Term, th *api.Thread) {
|
||||
bpname,
|
||||
fn.Name(),
|
||||
args,
|
||||
ShortenFilePath(th.File),
|
||||
shortenFilePath(th.File),
|
||||
th.Line,
|
||||
th.GoroutineID,
|
||||
hitCount,
|
||||
@ -2148,7 +2148,7 @@ func printcontextThread(t *Term, th *api.Thread) {
|
||||
bpname,
|
||||
fn.Name(),
|
||||
args,
|
||||
ShortenFilePath(th.File),
|
||||
shortenFilePath(th.File),
|
||||
th.Line,
|
||||
th.Breakpoint.TotalHitCount,
|
||||
th.PC)
|
||||
@ -2172,14 +2172,14 @@ func printcontextThread(t *Term, th *api.Thread) {
|
||||
}
|
||||
|
||||
for _, v := range bpi.Locals {
|
||||
if *bp.LoadLocals == LongLoadConfig {
|
||||
if *bp.LoadLocals == longLoadConfig {
|
||||
fmt.Printf("\t%s: %s\n", v.Name, v.MultilineString("\t"))
|
||||
} else {
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
|
||||
// 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 './'.
|
||||
func ShortenFilePath(fullPath string) string {
|
||||
func shortenFilePath(fullPath string) string {
|
||||
workingDir, _ := os.Getwd()
|
||||
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, " for ")
|
||||
p := ShortenFilePath(bp.File)
|
||||
p := shortenFilePath(bp.File)
|
||||
if bp.FunctionName != "" {
|
||||
fmt.Fprintf(&out, "%s() ", bp.FunctionName)
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
"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)
|
||||
defer bw.Flush()
|
||||
if len(dv) > 0 && dv[0].Loc.Function != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user