created repo
4 files changed, 151 insertions(+), 0 deletions(-)

A => README.md
A => cmd/dump/main.go
A => linux.go
A => memdump.go
A => README.md +3 -0
@@ 0,0 1,3 @@ 
+memdump - a tool for dumping the memory of a process into a file 
+================================================================
+Runs with linux only. Because of the limitations of Go this program will not work on 64-bit machines.

          
A => cmd/dump/main.go +53 -0
@@ 0,0 1,53 @@ 
+package main
+
+import (
+	"bitbucket.org/telesto/memdump"
+	"flag"
+	"fmt"
+	"os"
+)
+
+func usage() {
+	fmt.Fprintln(os.Stderr, "usage: dump -p pid")
+}
+
+func main() {
+	pid := flag.Int("pid", 0, "pid of the process to dump")
+	split := flag.Bool("s", false, "write one file for each memory region")
+	file := flag.String("o", "", "write regions into file")
+
+	flag.Parse()
+	if *pid <= 0 {
+		usage()
+		os.Exit(0)
+	}
+
+	maps, err := memdump.ParseMappings(*pid)
+	if err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+	conn, err := memdump.Open(*pid)
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(1)
+	}
+	for i := range maps {
+		if *split {
+			err = memdump.Dump(conn, maps[i].Start, maps[i].End)
+			if err != nil {
+				fmt.Fprintln(os.Stderr, err)
+				conn.Close()
+				os.Exit(1)
+			}
+		}
+		if len(*file) != 0 {
+			// todo:
+		}
+	}
+	if err := conn.Close(); err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(1)
+	}
+	os.Exit(0)
+}

          
A => linux.go +34 -0
@@ 0,0 1,34 @@ 
+package memdump
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"os"
+)
+
+const proc = "/proc"
+
+func openMemory(pid int) (*os.File, error) {
+	return os.Open(fmt.Sprintf("%s/%d/mem", proc, pid))
+}
+
+func ParseMappings(pid int) ([]MemoryRegion, error) {
+	c, err := ioutil.ReadFile(fmt.Sprintf("%s/%d/maps", proc, pid))
+	if err != nil {
+		return nil, err
+	}
+	maps := []MemoryRegion{}
+	for _, line := range bytes.Split(bytes.TrimSpace(c), []byte{'\n'}) {
+		var r MemoryRegion
+		n, err := fmt.Sscanf(string(line), "%x-%x", &r.Start, &r.End)
+		if err != nil {
+			return nil, err
+		}
+		if n != 2 {
+			return nil, fmt.Errorf("needed %d values for scanning, found %d", 2, n)
+		}
+		maps = append(maps, r)
+	}
+	return maps, nil
+}

          
A => memdump.go +61 -0
@@ 0,0 1,61 @@ 
+package memdump
+
+import (
+	"fmt"
+	"io"
+	"os"
+	"syscall"
+)
+
+type MemoryRegion struct {
+	Start, End int64
+}
+
+type Connection interface {
+	io.ReaderAt
+	io.Closer
+}
+
+type connection struct {
+	pid int
+	*os.File
+}
+
+func (c *connection) Close() error {
+	err := c.File.Close()
+	err1 := syscall.PtraceDetach(c.pid)
+	if err1 != nil {
+		err = err1
+	}
+	return err
+}
+
+func Open(pid int) (Connection, error) {
+	var err error
+	if err = syscall.PtraceAttach(pid); err != nil {
+		return nil, err
+	}
+	if pid, err = syscall.Wait4(pid, nil, 0, nil); err != nil {
+		return nil, err
+	}
+	conn, err := openMemory(pid)
+	if err != nil {
+		syscall.PtraceDetach(pid)
+		return nil, err
+	}
+	return &connection{pid, conn}, nil
+}
+
+func Dump(conn Connection, start, end int64) error {
+	dump, err := os.Create(fmt.Sprintf("%x-%x.bin", start, end))
+	defer dump.Close()
+	if err != nil {
+		return err
+	}
+	written, err := io.Copy(dump, io.NewSectionReader(conn, start, end))
+	if written != end-start {
+		return fmt.Errorf("written %d bytes, expected %d bytes to copy",
+			written, end-start)
+	}
+	return err
+}