Skip to content

Commit

Permalink
proc,proc/native,proc/gdbserial: initial plugin support
Browse files Browse the repository at this point in the history
Adds initial support for plugins, this is only the code needed to keep
track of loaded plugins on linux (both native and gdbserial backend).

It does not actually implement support for debugging plugins on linux.

Updates go-delve#865
  • Loading branch information
aarzilli committed Nov 15, 2018
1 parent 33f522e commit 4d7a05b
Show file tree
Hide file tree
Showing 19 changed files with 484 additions and 3 deletions.
5 changes: 5 additions & 0 deletions Documentation/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Command | Description
[goroutine](#goroutine) | Shows or changes current goroutine
[goroutines](#goroutines) | List program goroutines.
[help](#help) | Prints the help message.
[libraries](#libraries) | List loaded dynamic libraries
[list](#list) | Show source code.
[locals](#locals) | Print local variables.
[next](#next) | Step over to next source line.
Expand Down Expand Up @@ -266,6 +267,10 @@ Type "help" followed by the name of a command for more information about it.

Aliases: h

## libraries
List loaded dynamic libraries


## list
Show source code.

Expand Down
9 changes: 9 additions & 0 deletions _fixtures/internal/pluginsupport/pluginsupport.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package pluginsupport

type Something interface {
Callback(int) int
}

type SomethingElse interface {
Callback2(int, int) float64
}
13 changes: 13 additions & 0 deletions _fixtures/plugin1/plugin1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package main

import "fmt"

func Fn1() string {
return "hello"
}

func HelloFn(n int) string {
n++
s := fmt.Sprintf("hello%d", n)
return s
}
33 changes: 33 additions & 0 deletions _fixtures/plugin2/plugin2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package main

import (
"fmt"
"github.com/derekparker/delve/_fixtures/internal/pluginsupport"
)

func Fn2() string {
return "world"
}

type asomethingelse struct {
x, y float64
}

func (a *asomethingelse) Callback2(n, m int) float64 {
r := a.x + 2*a.y
r += float64(n) / float64(m)
return r
}

func TypesTest(s pluginsupport.Something) pluginsupport.SomethingElse {
if A != nil {
aIsNotNil(fmt.Sprintf("%s", A))
}
return &asomethingelse{1.0, float64(s.Callback(2))}
}

var A interface{}

func aIsNotNil(str string) {
// nothing here
}
36 changes: 36 additions & 0 deletions _fixtures/plugintest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package main

import (
"fmt"
"os"
"plugin"
"runtime"
)

func must(err error) {
if err != nil {
panic(err)
}
}

func main() {
plug1, err := plugin.Open(os.Args[1])
must(err)

runtime.Breakpoint()

plug2, err := plugin.Open(os.Args[2])
must(err)

runtime.Breakpoint()

fn1, err := plug1.Lookup("Fn1")
must(err)
fn2, err := plug2.Lookup("Fn2")
must(err)

a := fn1.(func() string)()
b := fn2.(func() string)()

fmt.Println(plug1, plug2, fn1, fn2, a, b)
}
44 changes: 44 additions & 0 deletions _fixtures/plugintest2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package main

import (
"fmt"
"github.com/derekparker/delve/_fixtures/internal/pluginsupport"
"os"
"plugin"
)

type asomething struct {
n int
}

func (a *asomething) Callback(n int) int {
return a.n + n
}

func (a *asomething) String() string {
return "success"
}

var ExeGlobal = &asomething{2}

func must(err error) {
if err != nil {
panic(err)
}
}

func main() {
plug1, err := plugin.Open(os.Args[1])
must(err)
plug2, err := plugin.Open(os.Args[2])
must(err)
fn1iface, err := plug1.Lookup("HelloFn")
must(err)
fn2iface, err := plug2.Lookup("TypesTest")
must(err)
fn1 := fn1iface.(func(int) string)
fn2 := fn2iface.(func(pluginsupport.Something) pluginsupport.SomethingElse)
a := fn1(3)
b := fn2(&asomething{2})
fmt.Println(a, b, ExeGlobal)
}
40 changes: 39 additions & 1 deletion pkg/proc/bininfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ import (
"github.com/derekparker/delve/pkg/goversion"
)

// BinaryInfo holds information on the binary being executed.
// BinaryInfo holds information on the binaries being executed (this
// includes both the executable and also any loaded libraries).
type BinaryInfo struct {
// Path on disk of the binary being executed.
Path string
Expand All @@ -50,6 +51,8 @@ type BinaryInfo struct {

staticBase uint64

ElfDynamicSection ElfDynamicSection

// Maps package names to package paths, needed to lookup types inside DWARF info
packageMap map[string]string

Expand Down Expand Up @@ -79,6 +82,10 @@ type BinaryInfo struct {

loadErrMu sync.Mutex
loadErr error

// Images is a list of loaded shared libraries (also known as
// shared objects on linux or DLLs on windws).
Images []*Image
}

// ErrUnsupportedLinuxArch is returned when attempting to debug a binary compiled for an unsupported architecture.
Expand Down Expand Up @@ -288,6 +295,12 @@ type buildIDHeader struct {
Type uint32
}

// ElfDynamicSection describes the .dynamic section of an ELF executable.
type ElfDynamicSection struct {
Addr uint64 // relocated address of where the .dynamic section is mapped in memory
Size uint64 // size of the .dynamic section of the executable
}

// NewBinaryInfo returns an initialized but unloaded BinaryInfo struct.
func NewBinaryInfo(goos, goarch string) *BinaryInfo {
r := &BinaryInfo{GOOS: goos, nameOfRuntimeType: make(map[uintptr]nameOfRuntimeTypeEntry), typeCache: make(map[dwarf.Offset]godwarf.Type)}
Expand Down Expand Up @@ -409,6 +422,26 @@ func (bi *BinaryInfo) PCToFunc(pc uint64) *Function {
return nil
}

// Image represents a loaded library file (shared object on linux, DLL on windows).
type Image struct {
Path string
addr uint64
}

// AddSharedObject adds the specified shared object to bi.
func (bi *BinaryInfo) AddImage(path string, addr uint64) {
if !strings.HasPrefix(path, "/") {
return
}
for _, image := range bi.Images {
if image.Path == path && image.addr == addr {
return
}
}
//TODO(aarzilli): actually load informations about the image here
bi.Images = append(bi.Images, &Image{Path: path, addr: addr})
}

// Close closes all internal readers.
func (bi *BinaryInfo) Close() error {
if bi.sepDebugCloser != nil {
Expand Down Expand Up @@ -665,6 +698,11 @@ func (bi *BinaryInfo) LoadBinaryInfoElf(path string, entryPoint uint64, debugInf
}
}

if dynsec := elfFile.Section(".dynamic"); dynsec != nil {
bi.ElfDynamicSection.Addr = dynsec.Addr + bi.staticBase
bi.ElfDynamicSection.Size = dynsec.Size
}

dwarfFile := elfFile

bi.dwarf, err = elfFile.DWARF()
Expand Down
6 changes: 6 additions & 0 deletions pkg/proc/gdbserial/gdbserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,12 @@ continueLoop:
return nil, err
}

if p.BinInfo().GOOS == "linux" {
if err := linutil.ElfUpdateSharedObjects(p); err != nil {
return nil, err
}
}

if err := p.setCurrentBreakpoints(); err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit 4d7a05b

Please sign in to comment.