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 }