Skip to content

Commit

Permalink
proc,proc/native,proc/gdbserial: initial plugin support (go-delve#1413)
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 authored and derekparker committed Mar 20, 2019
1 parent 903ec65 commit 837fb94
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/go-delve/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/go-delve/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/go-delve/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 @@ -43,6 +44,12 @@ type BinaryInfo struct {
// LookupFunc maps function names to a description of the function.
LookupFunc map[string]*Function

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

ElfDynamicSection ElfDynamicSection

lastModified time.Time // Time the executable of this process was last modified

closer io.Closer
Expand Down Expand Up @@ -289,6 +296,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 @@ -412,6 +425,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
}

// AddImage adds the specified image 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 @@ -671,6 +704,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 @@ -702,6 +702,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 837fb94

Please sign in to comment.