2014-05-20 18:23:35 +00:00
|
|
|
package proctl
|
|
|
|
|
|
|
|
import (
|
2014-05-23 14:42:06 +00:00
|
|
|
"debug/gosym"
|
2014-05-20 18:23:35 +00:00
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"syscall"
|
2014-06-29 16:52:21 +00:00
|
|
|
|
2014-10-15 14:21:46 +00:00
|
|
|
"github.com/derekparker/delve/dwarf/frame"
|
|
|
|
"github.com/derekparker/delve/vendor/elf"
|
2014-05-20 18:23:35 +00:00
|
|
|
)
|
|
|
|
|
2014-05-21 15:23:14 +00:00
|
|
|
// Struct representing a debugged process. Holds onto pid, register values,
|
|
|
|
// process struct and process state.
|
2014-05-20 18:23:35 +00:00
|
|
|
type DebuggedProcess struct {
|
2014-10-18 01:34:58 +00:00
|
|
|
Pid int
|
|
|
|
Process *os.Process
|
|
|
|
Executable *elf.File
|
|
|
|
Symbols []elf.Symbol
|
|
|
|
GoSymTable *gosym.Table
|
|
|
|
FrameEntries *frame.FrameDescriptionEntries
|
2014-10-25 14:17:05 +00:00
|
|
|
BreakPoints map[uint64]*BreakPoint
|
2014-10-18 01:34:58 +00:00
|
|
|
Threads map[int]*ThreadContext
|
|
|
|
CurrentThread *ThreadContext
|
2014-05-24 16:22:06 +00:00
|
|
|
}
|
|
|
|
|
2014-10-18 01:34:58 +00:00
|
|
|
func (dbp *DebuggedProcess) addThread(tid int) (*ThreadContext, error) {
|
|
|
|
err := syscall.PtraceSetOptions(tid, syscall.PTRACE_O_TRACECLONE)
|
2014-10-27 23:10:45 +00:00
|
|
|
if err == syscall.ESRCH {
|
2014-11-23 00:57:26 +00:00
|
|
|
_, _, err = wait(tid, 0)
|
2014-10-27 23:10:45 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error while waiting after adding thread: %d %s", tid, err)
|
2014-05-27 15:51:38 +00:00
|
|
|
}
|
|
|
|
|
2014-10-27 23:10:45 +00:00
|
|
|
err := syscall.PtraceSetOptions(tid, syscall.PTRACE_O_TRACECLONE)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("could not set options for new traced thread %d %s", tid, err)
|
2014-05-29 15:27:03 +00:00
|
|
|
}
|
2014-10-18 01:34:58 +00:00
|
|
|
}
|
2014-05-29 16:18:28 +00:00
|
|
|
|
2014-10-27 23:10:45 +00:00
|
|
|
dbp.Threads[tid] = &ThreadContext{
|
2014-10-25 14:17:05 +00:00
|
|
|
Id: tid,
|
|
|
|
Process: dbp,
|
|
|
|
Regs: new(syscall.PtraceRegs),
|
2014-05-27 15:43:47 +00:00
|
|
|
}
|
|
|
|
|
2014-10-27 23:10:45 +00:00
|
|
|
return dbp.Threads[tid], nil
|
2014-05-20 18:23:35 +00:00
|
|
|
}
|
2014-05-20 18:23:36 +00:00
|
|
|
|
2014-12-05 22:17:10 +00:00
|
|
|
func parseProcessStatus(pid int) (*ProcessStatus, error) {
|
|
|
|
var ps ProcessStatus
|
2014-07-30 00:00:24 +00:00
|
|
|
|
2014-12-05 22:17:10 +00:00
|
|
|
f, err := os.Open(fmt.Sprintf("/proc/%d/stat", pid))
|
2014-07-30 00:00:24 +00:00
|
|
|
if err != nil {
|
2014-12-05 22:17:10 +00:00
|
|
|
return nil, err
|
2014-08-04 18:25:00 +00:00
|
|
|
}
|
2014-12-05 22:17:10 +00:00
|
|
|
defer f.Close()
|
2014-08-04 20:21:35 +00:00
|
|
|
|
2014-12-05 22:17:10 +00:00
|
|
|
fmt.Fscanf(f, "%d %s %c %d", &ps.pid, &ps.comm, &ps.state, &ps.ppid)
|
2014-07-30 00:00:24 +00:00
|
|
|
|
2014-12-05 22:17:10 +00:00
|
|
|
return &ps, nil
|
2014-05-20 18:23:36 +00:00
|
|
|
}
|
2014-05-23 14:42:06 +00:00
|
|
|
|
|
|
|
func (dbp *DebuggedProcess) findExecutable() error {
|
|
|
|
procpath := fmt.Sprintf("/proc/%d/exe", dbp.Pid)
|
|
|
|
|
2014-09-13 17:28:46 +00:00
|
|
|
f, err := os.OpenFile(procpath, 0, os.ModePerm)
|
2014-05-23 14:42:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
elffile, err := elf.NewFile(f)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
dbp.Executable = elffile
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|