delve/proctl/proctl_linux_amd64.go

144 lines
2.8 KiB
Go
Raw Normal View History

2014-05-20 18:23:35 +00:00
package proctl
import (
2014-11-24 23:27:56 +00:00
"debug/elf"
"debug/gosym"
2014-05-20 18:23:35 +00:00
"fmt"
"os"
2014-12-08 23:15:52 +00:00
"sync"
2014-05-20 18:23:35 +00:00
"syscall"
2014-10-15 14:21:46 +00:00
"github.com/derekparker/delve/dwarf/frame"
2014-05-20 18:23:35 +00:00
)
func (dbp *DebuggedProcess) addThread(tid int) (*ThreadContext, error) {
err := syscall.PtraceSetOptions(tid, syscall.PTRACE_O_TRACECLONE)
if err == syscall.ESRCH {
_, _, err = wait(tid, 0)
if err != nil {
return nil, fmt.Errorf("error while waiting after adding thread: %d %s", tid, err)
}
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-05-29 16:18:28 +00:00
dbp.Threads[tid] = &ThreadContext{
2014-10-25 14:17:05 +00:00
Id: tid,
Process: dbp,
}
return dbp.Threads[tid], nil
2014-05-20 18:23:35 +00:00
}
2014-05-20 18:23:36 +00:00
func parseProcessStatus(pid int) (*ProcessStatus, error) {
var ps ProcessStatus
2014-07-30 00:00:24 +00:00
f, err := os.Open(fmt.Sprintf("/proc/%d/stat", pid))
2014-07-30 00:00:24 +00:00
if err != nil {
return nil, err
}
defer f.Close()
2014-08-04 20:21:35 +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
return &ps, nil
2014-05-20 18:23:36 +00:00
}
2014-12-08 23:15:52 +00:00
// Finds the executable from /proc/<pid>/exe and then
// uses that to parse the following information:
// * Dwarf .debug_frame section
// * Dwarf .debug_line section
// * Go symbol table.
func (dbp *DebuggedProcess) LoadInformation() error {
var (
wg sync.WaitGroup
exe *elf.File
err error
)
exe, err = dbp.findExecutable()
if err != nil {
return err
}
wg.Add(2)
go dbp.parseDebugFrame(exe, &wg)
go dbp.obtainGoSymbols(exe, &wg)
wg.Wait()
return nil
}
func (dbp *DebuggedProcess) findExecutable() (*elf.File, error) {
procpath := fmt.Sprintf("/proc/%d/exe", dbp.Pid)
f, err := os.OpenFile(procpath, 0, os.ModePerm)
if err != nil {
2014-12-08 23:15:52 +00:00
return nil, err
}
elffile, err := elf.NewFile(f)
if err != nil {
2014-12-08 23:15:52 +00:00
return nil, err
}
2014-12-08 23:15:52 +00:00
data, err := elffile.DWARF()
if err != nil {
return nil, err
}
dbp.Dwarf = data
2014-12-08 23:15:52 +00:00
return elffile, nil
}
func (dbp *DebuggedProcess) parseDebugFrame(exe *elf.File, wg *sync.WaitGroup) {
defer wg.Done()
debugFrame, err := exe.Section(".debug_frame").Data()
if err != nil {
fmt.Println("could not get .debug_frame section", err)
os.Exit(1)
}
dbp.FrameEntries = frame.Parse(debugFrame)
}
func (dbp *DebuggedProcess) obtainGoSymbols(exe *elf.File, wg *sync.WaitGroup) {
defer wg.Done()
var (
symdat []byte
pclndat []byte
err error
)
if sec := exe.Section(".gosymtab"); sec != nil {
symdat, err = sec.Data()
if err != nil {
fmt.Println("could not get .gosymtab section", err)
os.Exit(1)
}
}
if sec := exe.Section(".gopclntab"); sec != nil {
pclndat, err = sec.Data()
if err != nil {
fmt.Println("could not get .gopclntab section", err)
os.Exit(1)
}
}
pcln := gosym.NewLineTable(pclndat, exe.Section(".text").Addr)
tab, err := gosym.NewTable(symdat, pcln)
if err != nil {
fmt.Println("could not get initialize line table", err)
os.Exit(1)
}
dbp.GoSymTable = tab
}