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