about summary refs log tree commit diff
path: root/vendor/github.com/radareorg/r2pipe-go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/radareorg/r2pipe-go')
-rw-r--r--vendor/github.com/radareorg/r2pipe-go/LICENSE23
-rw-r--r--vendor/github.com/radareorg/r2pipe-go/Makefile12
-rw-r--r--vendor/github.com/radareorg/r2pipe-go/README.md17
-rw-r--r--vendor/github.com/radareorg/r2pipe-go/api.go47
-rw-r--r--vendor/github.com/radareorg/r2pipe-go/native.go161
-rw-r--r--vendor/github.com/radareorg/r2pipe-go/r2pipe.go243
6 files changed, 503 insertions, 0 deletions
diff --git a/vendor/github.com/radareorg/r2pipe-go/LICENSE b/vendor/github.com/radareorg/r2pipe-go/LICENSE
new file mode 100644
index 0000000..fd92b03
--- /dev/null
+++ b/vendor/github.com/radareorg/r2pipe-go/LICENSE
@@ -0,0 +1,23 @@
+The MIT License (MIT)
+
+Copyright (c) 2021 radare
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
diff --git a/vendor/github.com/radareorg/r2pipe-go/Makefile b/vendor/github.com/radareorg/r2pipe-go/Makefile
new file mode 100644
index 0000000..5dd762a
--- /dev/null
+++ b/vendor/github.com/radareorg/r2pipe-go/Makefile
@@ -0,0 +1,12 @@
+all:
+	go test
+
+ex:
+	cd example ; go run example.go
+
+sync:
+	git clone --depth=1 https://github.com/radareorg/radare2-r2pipe
+	cp -rf radare2-r2pipe/go/*.go .
+	rm -rf radare2-r2pipe
+
+.PHONY: all sync
diff --git a/vendor/github.com/radareorg/r2pipe-go/README.md b/vendor/github.com/radareorg/r2pipe-go/README.md
new file mode 100644
index 0000000..238a1bc
--- /dev/null
+++ b/vendor/github.com/radareorg/r2pipe-go/README.md
@@ -0,0 +1,17 @@
+r2pipe.go
+=========
+
+Go module to interact with radare2
+
+Source
+------
+
+This repository is in sync with [radareorg/r2pipe](https://godoc.org/github.com/radareorg/radare2-r2pipe).
+
+Run `make sync` to update it after changing things in the source repository.
+
+Documentation
+-------------
+
+[![GoDoc](https://godoc.org/github.com/radare/r2pipe-go?status.svg)](https://godoc.org/github.com/radare/r2pipe-go)
+
diff --git a/vendor/github.com/radareorg/r2pipe-go/api.go b/vendor/github.com/radareorg/r2pipe-go/api.go
new file mode 100644
index 0000000..9ccf5ca
--- /dev/null
+++ b/vendor/github.com/radareorg/r2pipe-go/api.go
@@ -0,0 +1,47 @@
+// radare - LGPL - Copyright 2021 - pancake
+
+package r2pipe
+
+// #cgo CFLAGS: -I/usr/local/include/libr
+// #cgo CFLAGS: -I/usr/local/include/libr/sdb
+// #cgo LDFLAGS: -L/usr/local/lib -lr_core
+// #include <stdio.h>
+// #include <stdlib.h>
+// extern void r_core_free(void *);
+// extern void *r_core_new(void);
+// extern char *r_core_cmd_str(void*, const char *);
+//
+import "C"
+
+import (
+	"unsafe"
+)
+
+func (r2p *Pipe) ApiCmd(cmd string) (string, error) {
+	res := C.r_core_cmd_str(r2p.Core, C.CString(cmd))
+	return C.GoString(res), nil
+}
+
+func (r2p *Pipe) ApiClose() error {
+	C.r_core_free(unsafe.Pointer(r2p.Core))
+	r2p.Core = nil
+	return nil
+}
+
+func NewApiPipe(file string) (*Pipe, error) {
+	r2 := C.r_core_new()
+	r2p := &Pipe{
+		File: file,
+		Core: r2,
+		cmd: func(r2p *Pipe, cmd string) (string, error) {
+			return r2p.ApiCmd(cmd)
+		},
+		close: func(r2p *Pipe) error {
+			return r2p.ApiClose()
+		},
+	}
+	if file != "" {
+		r2p.ApiCmd("o " + file)
+	}
+	return r2p, nil
+}
diff --git a/vendor/github.com/radareorg/r2pipe-go/native.go b/vendor/github.com/radareorg/r2pipe-go/native.go
new file mode 100644
index 0000000..2283717
--- /dev/null
+++ b/vendor/github.com/radareorg/r2pipe-go/native.go
@@ -0,0 +1,161 @@
+// radare - LGPL - Copyright 2017 - pancake
+
+package r2pipe
+
+//#cgo linux LDFLAGS: -ldl
+//#include <stdio.h>
+//#include <dlfcn.h>
+// #include <stdlib.h>
+// void *gor_core_new(void *f) {
+// 	void *(*rcn)();
+// 	rcn = (void *(*)())f;
+// 	return rcn();
+// }
+//
+// void gor_core_free(void *f, void *arg) {
+// 	void (*fr)(void *);
+// 	fr = (void (*)(void *))f;
+// 	fr(arg);
+// }
+//
+// char *gor_core_cmd_str(void *f, void *arg, char *arg2) {
+// 	char *(*cmdstr)(void *, char *);
+// 	cmdstr = (char *(*)(void *, char *))f;
+// 	return cmdstr(arg, arg2);
+// }
+import "C"
+
+import (
+	"errors"
+	"fmt"
+	"os"
+	"runtime"
+	"unsafe"
+)
+
+type Ptr = unsafe.Pointer
+
+// *struct{}
+
+var (
+	lib            Ptr = nil
+	r_core_new     func() Ptr
+	r_core_free    func(Ptr)
+	r_core_cmd_str func(Ptr, string) string
+)
+
+type DL struct {
+	handle unsafe.Pointer
+	name   string
+}
+
+func libpath(libname string) string {
+	paths := []string{"/usr/local/lib", "/usr/lib", "/lib"}
+	for _, path := range paths {
+		if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
+			// path/to/whatever does not exist
+		} else {
+			// file exists
+			return path + "/" + libname
+		}
+	}
+	return libname
+}
+
+func dlOpen(path string) (*DL, error) {
+	var ret DL
+	switch runtime.GOOS {
+	case "darwin":
+		path = path + ".dylib"
+	case "windows":
+		path = path + ".dll"
+	default:
+		path = path + ".so" //linux/bsds
+	}
+	path = libpath(path)
+	cpath := C.CString(path)
+	if cpath == nil {
+		return nil, errors.New("Failed to get cpath")
+	}
+	//r2pioe only uses flag 0
+	ret.handle = C.dlopen(cpath, 0)
+	ret.name = path
+	C.free(unsafe.Pointer(cpath))
+	if ret.handle == nil {
+		return nil, errors.New(fmt.Sprintf("Failed to open %s", path))
+	}
+	return &ret, nil
+}
+
+func dlSym(dl *DL, name string) (unsafe.Pointer, error) {
+	cname := C.CString(name)
+	if cname == nil {
+		return nil, errors.New("Fail")
+	}
+	handle := C.dlsym(dl.handle, cname)
+	C.free(unsafe.Pointer(cname))
+	if handle == nil {
+		return nil, errors.New("Fail")
+	}
+	return handle, nil
+}
+
+func NativeLoad() error {
+	if lib != nil {
+		return nil
+	}
+	lib, err := dlOpen("libr_core")
+	_ = lib
+	if err != nil {
+		return err
+	}
+	handle1, _ := dlSym(lib, "r_core_new")
+	r_core_new = func() Ptr {
+		a := (Ptr)(C.gor_core_new(handle1))
+		return a
+	}
+	handle2, _ := dlSym(lib, "r_core_free")
+	r_core_free = func(p Ptr) {
+		C.gor_core_free(handle2, unsafe.Pointer(p))
+	}
+	handle3, _ := dlSym(lib, "r_core_cmd_str")
+	r_core_cmd_str = func(p Ptr, s string) string {
+		a := C.CString(s)
+		b := C.gor_core_cmd_str(handle3, unsafe.Pointer(p), a)
+		C.free(unsafe.Pointer(a))
+		return C.GoString(b)
+	}
+	return nil
+}
+
+func (r2p *Pipe) NativeCmd(cmd string) (string, error) {
+	res := r_core_cmd_str(r2p.Core, cmd)
+	return res, nil
+}
+
+func (r2p *Pipe) NativeClose() error {
+	r_core_free(r2p.Core)
+	r2p.Core = nil
+	return nil
+}
+
+func NewNativePipe(file string) (*Pipe, error) {
+	if err := NativeLoad(); err != nil {
+		return nil, err
+	}
+	r2 := r_core_new()
+	r2p := &Pipe{
+		File: file,
+		Core: r2,
+		cmd: func(r2p *Pipe, cmd string) (string, error) {
+			return r2p.NativeCmd(cmd)
+		},
+		close: func(r2p *Pipe) error {
+			return r2p.NativeClose()
+		},
+	}
+	if file != "" {
+		r2p.NativeCmd("o " + file)
+	}
+	return r2p, nil
+}
diff --git a/vendor/github.com/radareorg/r2pipe-go/r2pipe.go b/vendor/github.com/radareorg/r2pipe-go/r2pipe.go
new file mode 100644
index 0000000..d87e2fe
--- /dev/null
+++ b/vendor/github.com/radareorg/r2pipe-go/r2pipe.go
@@ -0,0 +1,243 @@
+// radare - LGPL - Copyright 2015 - nibble
+
+/*
+Package r2pipe allows to call r2 commands from Go. A simple hello world would
+look like the following snippet:
+
+	package main
+
+	import (
+		"fmt"
+
+		"github.com/radare/r2pipe-go"
+	)
+
+	func main() {
+		r2p, err := r2pipe.NewPipe("malloc://256")
+		if err != nil {
+			panic(err)
+		}
+		defer r2p.Close()
+
+		_, err = r2p.Cmd("w Hello World")
+		if err != nil {
+			panic(err)
+		}
+		buf, err := r2p.Cmd("ps")
+		if err != nil {
+			panic(err)
+		}
+		fmt.Println(buf)
+	}
+*/
+package r2pipe
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"os"
+	"os/exec"
+	"strconv"
+	"strings"
+	"unsafe"
+)
+
+// A Pipe represents a communication interface with r2 that will be used to
+// execute commands and obtain their results.
+type Pipe struct {
+	File   string
+	r2cmd  *exec.Cmd
+	stdin  io.WriteCloser
+	stdout io.ReadCloser
+	stderr io.ReadCloser
+	Core   unsafe.Pointer
+	cmd    CmdDelegate
+	close  CloseDelegate
+}
+
+type (
+	CmdDelegate   func(*Pipe, string) (string, error)
+	CloseDelegate func(*Pipe) error
+	EventDelegate func(*Pipe, string, interface{}, string) bool
+)
+
+// NewPipe returns a new r2 pipe and initializes an r2 core that will try to
+// load the provided file or URI. If file is an empty string, the env vars
+// R2PIPE_{IN,OUT} will be used as file descriptors for input and output, this
+// is the case when r2pipe is called within r2.
+func NewPipe(file string) (*Pipe, error) {
+	if file == "" {
+		return newPipeFd()
+	}
+
+	return newPipeCmd(file)
+}
+
+func newPipeFd() (*Pipe, error) {
+	r2pipeIn := os.Getenv("R2PIPE_IN")
+	r2pipeOut := os.Getenv("R2PIPE_OUT")
+
+	if r2pipeIn == "" || r2pipeOut == "" {
+		return nil, fmt.Errorf("missing R2PIPE_{IN,OUT} vars")
+	}
+
+	r2pipeInFd, err := strconv.Atoi(r2pipeIn)
+	if err != nil {
+		return nil, fmt.Errorf("failed to convert IN into file descriptor")
+	}
+
+	r2pipeOutFd, err := strconv.Atoi(r2pipeOut)
+	if err != nil {
+		return nil, fmt.Errorf("failed to convert OUT into file descriptor")
+	}
+
+	stdout := os.NewFile(uintptr(r2pipeInFd), "R2PIPE_IN")
+	stdin := os.NewFile(uintptr(r2pipeOutFd), "R2PIPE_OUT")
+
+	r2p := &Pipe{
+		File:   "",
+		r2cmd:  nil,
+		stdin:  stdin,
+		stdout: stdout,
+		Core:   nil,
+	}
+
+	return r2p, nil
+}
+
+func newPipeCmd(file string) (*Pipe, error) {
+
+	r2p := &Pipe{File: file, r2cmd: exec.Command("radare2", "-q0", file)}
+	var err error
+	r2p.stdin, err = r2p.r2cmd.StdinPipe()
+	if err == nil {
+		r2p.stdout, err = r2p.r2cmd.StdoutPipe()
+		if err == nil {
+			r2p.stderr, err = r2p.r2cmd.StdoutPipe()
+		}
+		if err = r2p.r2cmd.Start(); err == nil {
+			//Read the initial data
+			_, err = bufio.NewReader(r2p.stdout).ReadString('\x00')
+		}
+	}
+	return r2p, err
+}
+
+// Write implements the standard Write interface: it writes data to the r2
+// pipe, blocking until r2 have consumed all the data.
+func (r2p *Pipe) Write(p []byte) (n int, err error) {
+	return r2p.stdin.Write(p)
+}
+
+// Read implements the standard Read interface: it reads data from the r2
+// pipe's stdin, blocking until the previously issued commands have finished.
+func (r2p *Pipe) Read(p []byte) (n int, err error) {
+	return r2p.stdout.Read(p)
+}
+
+func (r2p *Pipe) ReadErr(p []byte) (n int, err error) {
+	return r2p.stderr.Read(p)
+}
+
+func (r2p *Pipe) On(evname string, p interface{}, cb EventDelegate) error {
+	path, err := r2p.Cmd("===stderr")
+	if err != nil {
+		return err
+	}
+	f, err := os.OpenFile(path, os.O_RDONLY, 0600)
+
+	if err != nil {
+		return err
+	}
+	go func() {
+		var buf bytes.Buffer
+		for {
+			io.Copy(&buf, f)
+			if buf.Len() > 0 {
+				if !cb(r2p, evname, p, buf.String()) {
+					break
+				}
+			}
+		}
+		f.Close()
+	}()
+	return nil
+}
+
+// Cmd is a helper that allows to run r2 commands and receive their output.
+func (r2p *Pipe) Cmd(cmd string) (string, error) {
+	if r2p.Core != nil {
+		if r2p.cmd != nil {
+			return r2p.cmd(r2p, cmd)
+		}
+
+		return "", nil
+	}
+
+	if _, err := fmt.Fprintln(r2p, cmd); err != nil {
+		return "", err
+	}
+
+	buf, err := bufio.NewReader(r2p).ReadString('\x00')
+	if err != nil {
+		return "", err
+	}
+	return strings.TrimRight(buf, "\n\x00"), err
+}
+
+//like cmd but formats the command
+func (r2p *Pipe) Cmdf(f string, args ...interface{}) (string, error) {
+	return r2p.Cmd(fmt.Sprintf(f, args...))
+}
+
+// Cmdj acts like Cmd but interprets the output of the command as json. It
+// returns the parsed json keys and values.
+func (r2p *Pipe) Cmdj(cmd string) (out interface{}, err error) {
+	rstr, err := r2p.Cmd(cmd)
+	if err == nil {
+		err = json.Unmarshal([]byte(rstr), out)
+	}
+	return out, err
+}
+
+//like cmdj but formats the command
+func (r2p *Pipe) Cmdjf(f string, args ...interface{}) (interface{}, error) {
+	return r2p.Cmdj(fmt.Sprintf(f, args...))
+}
+
+// Close shuts down r2, closing the created pipe.
+func (r2p *Pipe) Close() error {
+	if r2p.close != nil {
+		return r2p.close(r2p)
+	}
+
+	if r2p.File == "" {
+		return nil
+	}
+
+	if _, err := r2p.Cmd("q"); err != nil {
+		return err
+	}
+
+	return r2p.r2cmd.Wait()
+}
+
+// Forcing shutdown of r2, closing the created pipe.
+func (r2p *Pipe) ForceClose() error {
+	if r2p.close != nil {
+		return r2p.close(r2p)
+	}
+
+	if r2p.File == "" {
+		return nil
+	}
+
+	if _, err := r2p.Cmd("q!"); err != nil {
+		return err
+	}
+
+	return r2p.r2cmd.Wait()
+}