mirror of
https://github.com/go-delve/delve.git
synced 2025-11-01 03:42:59 +08:00
Further isolate Linux specific code
This commit is contained in:
@ -7,12 +7,25 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"sync"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/derekparker/delve/dwarf/frame"
|
"github.com/derekparker/delve/dwarf/frame"
|
||||||
|
"github.com/derekparker/delve/vendor/dwarf"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Struct representing a debugged process. Holds onto pid, register values,
|
||||||
|
// process struct and process state.
|
||||||
|
type DebuggedProcess struct {
|
||||||
|
Pid int
|
||||||
|
Process *os.Process
|
||||||
|
Dwarf *dwarf.Data
|
||||||
|
GoSymTable *gosym.Table
|
||||||
|
FrameEntries *frame.FrameDescriptionEntries
|
||||||
|
BreakPoints map[uint64]*BreakPoint
|
||||||
|
Threads map[int]*ThreadContext
|
||||||
|
CurrentThread *ThreadContext
|
||||||
|
}
|
||||||
|
|
||||||
// Represents a single breakpoint. Stores information on the break
|
// Represents a single breakpoint. Stores information on the break
|
||||||
// point including the byte of data that originally was stored at that
|
// point including the byte of data that originally was stored at that
|
||||||
// address.
|
// address.
|
||||||
@ -179,31 +192,6 @@ func (dbp *DebuggedProcess) PrintThreadInfo() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
err = dbp.findExecutable()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
wg.Add(2)
|
|
||||||
go dbp.parseDebugFrame(&wg)
|
|
||||||
go dbp.obtainGoSymbols(&wg)
|
|
||||||
|
|
||||||
wg.Wait()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Steps through process.
|
// Steps through process.
|
||||||
func (dbp *DebuggedProcess) Step() (err error) {
|
func (dbp *DebuggedProcess) Step() (err error) {
|
||||||
var (
|
var (
|
||||||
@ -310,53 +298,6 @@ func (dbp *DebuggedProcess) EvalSymbol(name string) (*Variable, error) {
|
|||||||
return dbp.CurrentThread.EvalSymbol(name)
|
return dbp.CurrentThread.EvalSymbol(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbp *DebuggedProcess) parseDebugFrame(wg *sync.WaitGroup) {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
debugFrame, err := dbp.Executable.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(wg *sync.WaitGroup) {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
var (
|
|
||||||
symdat []byte
|
|
||||||
pclndat []byte
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
if sec := dbp.Executable.Section(".gosymtab"); sec != nil {
|
|
||||||
symdat, err = sec.Data()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("could not get .gosymtab section", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if sec := dbp.Executable.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, dbp.Executable.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
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProcessExitedError struct {
|
type ProcessExitedError struct {
|
||||||
pid int
|
pid int
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,25 +4,13 @@ import (
|
|||||||
"debug/gosym"
|
"debug/gosym"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/derekparker/delve/dwarf/frame"
|
"github.com/derekparker/delve/dwarf/frame"
|
||||||
"github.com/derekparker/delve/vendor/elf"
|
"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) {
|
func (dbp *DebuggedProcess) addThread(tid int) (*ThreadContext, error) {
|
||||||
err := syscall.PtraceSetOptions(tid, syscall.PTRACE_O_TRACECLONE)
|
err := syscall.PtraceSetOptions(tid, syscall.PTRACE_O_TRACECLONE)
|
||||||
if err == syscall.ESRCH {
|
if err == syscall.ESRCH {
|
||||||
@ -60,20 +48,97 @@ func parseProcessStatus(pid int) (*ProcessStatus, error) {
|
|||||||
return &ps, nil
|
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)
|
procpath := fmt.Sprintf("/proc/%d/exe", dbp.Pid)
|
||||||
|
|
||||||
f, err := os.OpenFile(procpath, 0, os.ModePerm)
|
f, err := os.OpenFile(procpath, 0, os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
elffile, err := elf.NewFile(f)
|
elffile, err := elf.NewFile(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
dbp.Executable = elffile
|
data, err := elffile.DWARF()
|
||||||
|
if err != nil {
|
||||||
return nil
|
return nil, err
|
||||||
|
}
|
||||||
|
dbp.Dwarf = data
|
||||||
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,11 +29,7 @@ type M struct {
|
|||||||
// Parses and returns select info on the internal M
|
// Parses and returns select info on the internal M
|
||||||
// data structures used by the Go scheduler.
|
// data structures used by the Go scheduler.
|
||||||
func (thread *ThreadContext) AllM() ([]*M, error) {
|
func (thread *ThreadContext) AllM() ([]*M, error) {
|
||||||
data, err := thread.Process.Executable.DWARF()
|
reader := thread.Process.Dwarf.Reader()
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
reader := data.Reader()
|
|
||||||
|
|
||||||
allmaddr, err := parseAllMPtr(thread.Process, reader)
|
allmaddr, err := parseAllMPtr(thread.Process, reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -186,11 +182,7 @@ func parseAllMPtr(dbp *DebuggedProcess, reader *dwarf.Reader) (uint64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (dbp *DebuggedProcess) PrintGoroutinesInfo() error {
|
func (dbp *DebuggedProcess) PrintGoroutinesInfo() error {
|
||||||
data, err := dbp.Executable.DWARF()
|
reader := dbp.Dwarf.Reader()
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
reader := data.Reader()
|
|
||||||
|
|
||||||
allglen, err := allglenval(dbp, reader)
|
allglen, err := allglenval(dbp, reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -309,10 +301,7 @@ func offsetFor(dbp *DebuggedProcess, name string, reader *dwarf.Reader, parentin
|
|||||||
|
|
||||||
// Returns the value of the named symbol.
|
// Returns the value of the named symbol.
|
||||||
func (thread *ThreadContext) EvalSymbol(name string) (*Variable, error) {
|
func (thread *ThreadContext) EvalSymbol(name string) (*Variable, error) {
|
||||||
data, err := thread.Process.Executable.DWARF()
|
data := thread.Process.Dwarf
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pc, err := thread.CurrentPC()
|
pc, err := thread.CurrentPC()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user