github.com/lsg2020/gort@v0.0.0-20220515072951-7a7794baa036/gort_plugin.go (about) 1 package gort 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "io" 8 "strings" 9 10 "github.com/go-delve/delve/pkg/proc" 11 ) 12 13 func (d *DwarfRT) SearchPluginByName(name string) (string, uint64, error) { 14 libs, addr, err := d.SearchPlugins() 15 if err != nil { 16 return "", 0, err 17 } 18 for i := 0; i < len(libs); i++ { 19 if strings.LastIndex(libs[i], name) >= 0 { 20 return libs[i], addr[i], nil 21 } 22 } 23 return "", 0, ErrNotFound 24 } 25 26 func (d *DwarfRT) SearchPlugins() ([]string, []uint64, error) { 27 if err := d.check(); err != nil { 28 return nil, nil, err 29 } 30 bi := d.bi 31 32 if bi.ElfDynamicSection.Addr == 0 { 33 // no dynamic section, therefore nothing to do here 34 return nil, nil, nil 35 } 36 debugAddr, err := dynamicSearchDebug(bi) 37 if err != nil { 38 return nil, nil, err 39 } 40 if debugAddr == 0 { 41 // no DT_DEBUG entry 42 return nil, nil, nil 43 } 44 45 // Offsets of the fields of the r_debug and link_map structs, 46 // see /usr/include/elf/link.h for a full description of those structs. 47 debugMapOffset := uint64(bi.Arch.PtrSize()) 48 49 r_map, err := readPtr(bi, debugAddr+debugMapOffset) 50 if err != nil { 51 return nil, nil, err 52 } 53 54 var libs []string 55 var addr []uint64 56 57 for { 58 if r_map == 0 { 59 break 60 } 61 if len(libs) > maxNumLibraries { 62 return nil, nil, ErrTooManyLibraries 63 } 64 lm, err := readLinkMapNode(bi, r_map) 65 if err != nil { 66 return nil, nil, err 67 } 68 69 libs = append(libs, lm.name) 70 addr = append(addr, lm.addr) 71 r_map = lm.next 72 } 73 74 return libs, addr, nil 75 } 76 77 const ( 78 maxNumLibraries = 1000000 // maximum number of loaded libraries, to avoid loading forever on corrupted memory 79 maxLibraryPathLength = 1000000 // maximum length for the path of a library, to avoid loading forever on corrupted memory 80 ) 81 82 const ( 83 _DT_NULL = 0 // DT_NULL as defined by SysV ABI specification 84 _DT_DEBUG = 21 // DT_DEBUG as defined by SysV ABI specification 85 ) 86 87 func readPtr(bi *proc.BinaryInfo, addr uint64) (uint64, error) { 88 ptrbuf := entryAddress(uintptr(addr), bi.Arch.PtrSize()) 89 return readUintRaw(bytes.NewReader(ptrbuf), binary.LittleEndian, bi.Arch.PtrSize()) 90 } 91 92 // readUintRaw reads an integer of ptrSize bytes, with the specified byte order, from reader. 93 func readUintRaw(reader io.Reader, order binary.ByteOrder, ptrSize int) (uint64, error) { 94 switch ptrSize { 95 case 4: 96 var n uint32 97 if err := binary.Read(reader, order, &n); err != nil { 98 return 0, err 99 } 100 return uint64(n), nil 101 case 8: 102 var n uint64 103 if err := binary.Read(reader, order, &n); err != nil { 104 return 0, err 105 } 106 return n, nil 107 } 108 return 0, fmt.Errorf("not supprted ptr size %d", ptrSize) 109 } 110 111 // dynamicSearchDebug searches for the DT_DEBUG entry in the .dynamic section 112 func dynamicSearchDebug(bi *proc.BinaryInfo) (uint64, error) { 113 dynbuf := entryAddress(uintptr(bi.ElfDynamicSection.Addr), int(bi.ElfDynamicSection.Size)) 114 rd := bytes.NewReader(dynbuf) 115 116 for { 117 var tag, val uint64 118 var err error 119 if tag, err = readUintRaw(rd, binary.LittleEndian, bi.Arch.PtrSize()); err != nil { 120 return 0, err 121 } 122 if val, err = readUintRaw(rd, binary.LittleEndian, bi.Arch.PtrSize()); err != nil { 123 return 0, err 124 } 125 switch tag { 126 case _DT_NULL: 127 return 0, nil 128 case _DT_DEBUG: 129 return val, nil 130 } 131 } 132 } 133 134 type linkMap struct { 135 addr uint64 136 name string 137 ld uint64 138 next, prev uint64 139 } 140 141 func readLinkMapNode(bi *proc.BinaryInfo, r_map uint64) (*linkMap, error) { 142 var lm linkMap 143 var ptrs [5]uint64 144 for i := range ptrs { 145 var err error 146 ptrs[i], err = readPtr(bi, r_map+uint64(bi.Arch.PtrSize()*i)) 147 if err != nil { 148 return nil, err 149 } 150 } 151 lm.addr = ptrs[0] 152 var err error 153 lm.name, err = readCString(ptrs[1]) 154 if err != nil { 155 return nil, err 156 } 157 lm.ld = ptrs[2] 158 lm.next = ptrs[3] 159 lm.prev = ptrs[4] 160 return &lm, nil 161 } 162 163 func readCString(addr uint64) (string, error) { 164 if addr == 0 { 165 return "", nil 166 } 167 r := []byte{} 168 for { 169 if len(r) > maxLibraryPathLength { 170 return "", fmt.Errorf("error reading libraries: string too long (%d)", len(r)) 171 } 172 buf := entryAddress(uintptr(addr), 1) 173 if buf[0] == 0 { 174 break 175 } 176 r = append(r, buf[0]) 177 addr++ 178 } 179 return string(r), nil 180 }