Further isolate Linux specific code

This commit is contained in:
Derek Parker
2014-12-08 17:15:52 -06:00
parent 2ecf625c5b
commit d41bbbf5c3
3 changed files with 100 additions and 105 deletions

View File

@ -4,25 +4,13 @@ import (
"debug/gosym"
"fmt"
"os"
"sync"
"syscall"
"github.com/derekparker/delve/dwarf/frame"
"github.com/derekparker/delve/vendor/elf"
)
// Struct representing a debugged process. Holds onto pid, register values,
// process struct and process state.
type DebuggedProcess struct {
Pid int
Process *os.Process
Executable *elf.File
GoSymTable *gosym.Table
FrameEntries *frame.FrameDescriptionEntries
BreakPoints map[uint64]*BreakPoint
Threads map[int]*ThreadContext
CurrentThread *ThreadContext
}
func (dbp *DebuggedProcess) addThread(tid int) (*ThreadContext, error) {
err := syscall.PtraceSetOptions(tid, syscall.PTRACE_O_TRACECLONE)
if err == syscall.ESRCH {
@ -60,20 +48,97 @@ func parseProcessStatus(pid int) (*ProcessStatus, error) {
return &ps, nil
}
func (dbp *DebuggedProcess) findExecutable() error {
// 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 {
return err
return nil, err
}
elffile, err := elf.NewFile(f)
if err != nil {
return err
return nil, err
}
dbp.Executable = elffile
data, err := elffile.DWARF()
if err != nil {
return nil, err
}
dbp.Dwarf = data
return nil
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
}