github.com/alexflint/go-memdump@v1.1.0/relocate.go (about)

     1  package memdump
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"io"
     7  	"reflect"
     8  	"unsafe"
     9  )
    10  
    11  // locations contains the locations of pointers in a data segments
    12  type locations struct {
    13  	Main     int64   // Main contains the offset of the primary object
    14  	Pointers []int64 // Pointers contains the offset of each pointer
    15  }
    16  
    17  func encodeLocations(w io.Writer, f *locations) error {
    18  	err := binary.Write(w, binary.LittleEndian, int64(len(f.Pointers)))
    19  	if err != nil {
    20  		return err
    21  	}
    22  
    23  	err = binary.Write(w, binary.LittleEndian, f.Main)
    24  	if err != nil {
    25  		return err
    26  	}
    27  
    28  	err = binary.Write(w, binary.LittleEndian, f.Pointers)
    29  	if err != nil {
    30  		return err
    31  	}
    32  
    33  	return nil
    34  }
    35  
    36  func decodeLocations(r io.Reader, f *locations) error {
    37  	// read the number of pointers
    38  	var n int64
    39  	err := binary.Read(r, binary.LittleEndian, &n)
    40  	if err != nil {
    41  		return err
    42  	}
    43  
    44  	// read the main offset
    45  	err = binary.Read(r, binary.LittleEndian, &f.Main)
    46  	if err != nil {
    47  		return err
    48  	}
    49  
    50  	// read the list of pointers
    51  	f.Pointers = make([]int64, n)
    52  	err = binary.Read(r, binary.LittleEndian, f.Pointers)
    53  	if err != nil {
    54  		return err
    55  	}
    56  
    57  	return nil
    58  }
    59  
    60  // relocate adds the base address to each pointer in the buffer, then reinterprets
    61  // the buffer as an object of type t.
    62  func relocate(buf []byte, ptrs []int64, main int64, t reflect.Type) (interface{}, error) {
    63  	if len(buf) == 0 {
    64  		return nil, fmt.Errorf("cannot relocate an empty buffer")
    65  	}
    66  
    67  	// If the buffer is not aligned then we have to move the
    68  	// whole thing. We can assume that a freshly allocated
    69  	// buffer from make() is 8-byte aligned.
    70  	if uintptr(unsafe.Pointer(&buf[0]))%uintptr(t.Align()) != 0 {
    71  		buf2 := make([]byte, len(buf))
    72  		copy(buf2, buf)
    73  		buf = buf2
    74  	}
    75  
    76  	base := uintptr(unsafe.Pointer(&buf[0]))
    77  	for i, loc := range ptrs {
    78  		if loc < 0 || loc >= int64(len(buf)) {
    79  			return nil, fmt.Errorf("pointer %d was out of range: %d (buffer len=%d)", i, loc, len(buf))
    80  		}
    81  		v := (*uintptr)(unsafe.Pointer(&buf[loc]))
    82  		*v += base
    83  	}
    84  	if main < 0 || main >= int64(len(buf)) {
    85  		return nil, fmt.Errorf("main offset was out of range: %d (buffer len=%d)", main, len(buf))
    86  	}
    87  	return reflect.NewAt(t, unsafe.Pointer(&buf[main])).Interface(), nil
    88  }