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, 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 | ||||||
| } | } | ||||||
|  | |||||||
| @ -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
	 Derek Parker
					Derek Parker