github.com/undoio/delve@v1.9.0/pkg/proc/moduledata.go (about) 1 package proc 2 3 import ( 4 "go/constant" 5 "unsafe" 6 ) 7 8 // delve counterpart to runtime.moduledata 9 type moduleData struct { 10 text, etext uint64 11 types, etypes uint64 12 typemapVar *Variable 13 } 14 15 func loadModuleData(bi *BinaryInfo, mem MemoryReadWriter) ([]moduleData, error) { 16 // +rtype -var firstmoduledata moduledata 17 // +rtype -field moduledata.text uintptr 18 // +rtype -field moduledata.types uintptr 19 20 scope := globalScope(nil, bi, bi.Images[0], mem) 21 var md *Variable 22 md, err := scope.findGlobal("runtime", "firstmoduledata") 23 if err != nil { 24 return nil, err 25 } 26 27 r := []moduleData{} 28 29 for md.Addr != 0 { 30 const ( 31 typesField = "types" 32 etypesField = "etypes" 33 textField = "text" 34 etextField = "etext" 35 nextField = "next" 36 typemapField = "typemap" 37 ) 38 vars := map[string]*Variable{} 39 40 for _, fieldName := range []string{typesField, etypesField, textField, etextField, nextField, typemapField} { 41 var err error 42 vars[fieldName], err = md.structMember(fieldName) 43 if err != nil { 44 return nil, err 45 } 46 47 } 48 49 var err error 50 51 touint := func(name string) (ret uint64) { 52 if err == nil { 53 var n uint64 54 n, err = vars[name].asUint() 55 ret = n 56 } 57 return ret 58 } 59 60 r = append(r, moduleData{ 61 types: touint(typesField), etypes: touint(etypesField), 62 text: touint(textField), etext: touint(etextField), 63 typemapVar: vars[typemapField], 64 }) 65 if err != nil { 66 return nil, err 67 } 68 69 md = vars[nextField].maybeDereference() 70 if md.Unreadable != nil { 71 return nil, md.Unreadable 72 } 73 } 74 75 return r, nil 76 } 77 78 func findModuleDataForType(bi *BinaryInfo, mds []moduleData, typeAddr uint64, mem MemoryReadWriter) *moduleData { 79 for i := range mds { 80 if typeAddr >= mds[i].types && typeAddr < mds[i].etypes { 81 return &mds[i] 82 } 83 } 84 return nil 85 } 86 87 func resolveTypeOff(bi *BinaryInfo, mds []moduleData, typeAddr, off uint64, mem MemoryReadWriter) (*Variable, error) { 88 // See runtime.(*_type).typeOff in $GOROOT/src/runtime/type.go 89 md := findModuleDataForType(bi, mds, typeAddr, mem) 90 91 rtyp, err := bi.findType("runtime._type") 92 if err != nil { 93 return nil, err 94 } 95 96 if md == nil { 97 v, err := reflectOffsMapAccess(bi, off, mem) 98 if err != nil { 99 return nil, err 100 } 101 v.loadValue(LoadConfig{false, 1, 0, 0, -1, 0}) 102 addr, _ := constant.Int64Val(v.Value) 103 return v.newVariable(v.Name, uint64(addr), rtyp, mem), nil 104 } 105 106 if t, _ := md.typemapVar.mapAccess(newConstant(constant.MakeUint64(uint64(off)), mem)); t != nil { 107 return t, nil 108 } 109 110 res := md.types + off 111 112 return newVariable("", uint64(res), rtyp, bi, mem), nil 113 } 114 115 func resolveNameOff(bi *BinaryInfo, mds []moduleData, typeAddr, off uint64, mem MemoryReadWriter) (name, tag string, pkgpathoff int32, err error) { 116 // See runtime.resolveNameOff in $GOROOT/src/runtime/type.go 117 for _, md := range mds { 118 if typeAddr >= md.types && typeAddr < md.etypes { 119 return loadName(bi, md.types+off, mem) 120 } 121 } 122 123 v, err := reflectOffsMapAccess(bi, off, mem) 124 if err != nil { 125 return "", "", 0, err 126 } 127 128 resv := v.maybeDereference() 129 if resv.Unreadable != nil { 130 return "", "", 0, resv.Unreadable 131 } 132 133 return loadName(bi, resv.Addr, mem) 134 } 135 136 func reflectOffsMapAccess(bi *BinaryInfo, off uint64, mem MemoryReadWriter) (*Variable, error) { 137 scope := globalScope(nil, bi, bi.Images[0], mem) 138 reflectOffs, err := scope.findGlobal("runtime", "reflectOffs") 139 if err != nil { 140 return nil, err 141 } 142 143 reflectOffsm, err := reflectOffs.structMember("m") 144 if err != nil { 145 return nil, err 146 } 147 148 return reflectOffsm.mapAccess(newConstant(constant.MakeUint64(uint64(off)), mem)) 149 } 150 151 const ( 152 // flags for the name struct (see 'type name struct' in $GOROOT/src/reflect/type.go) 153 nameflagExported = 1 << 0 154 nameflagHasTag = 1 << 1 155 nameflagHasPkg = 1 << 2 156 ) 157 158 func loadName(bi *BinaryInfo, addr uint64, mem MemoryReadWriter) (name, tag string, pkgpathoff int32, err error) { 159 off := addr 160 namedata := make([]byte, 3) 161 _, err = mem.ReadMemory(namedata, off) 162 off += 3 163 if err != nil { 164 return "", "", 0, err 165 } 166 167 namelen := uint16(namedata[1])<<8 | uint16(namedata[2]) 168 169 rawstr := make([]byte, int(namelen)) 170 _, err = mem.ReadMemory(rawstr, off) 171 off += uint64(namelen) 172 if err != nil { 173 return "", "", 0, err 174 } 175 176 name = string(rawstr) 177 178 if namedata[0]&nameflagHasTag != 0 { 179 taglendata := make([]byte, 2) 180 _, err = mem.ReadMemory(taglendata, off) 181 off += 2 182 if err != nil { 183 return "", "", 0, err 184 } 185 taglen := uint16(taglendata[0])<<8 | uint16(taglendata[1]) 186 187 rawstr := make([]byte, int(taglen)) 188 _, err = mem.ReadMemory(rawstr, off) 189 off += uint64(taglen) 190 if err != nil { 191 return "", "", 0, err 192 } 193 194 tag = string(rawstr) 195 } 196 197 if namedata[0]&nameflagHasPkg != 0 { 198 pkgdata := make([]byte, 4) 199 _, err = mem.ReadMemory(pkgdata, off) 200 if err != nil { 201 return "", "", 0, err 202 } 203 204 // see func pkgPath in $GOROOT/src/reflect/type.go 205 copy((*[4]byte)(unsafe.Pointer(&pkgpathoff))[:], pkgdata) 206 } 207 208 return name, tag, pkgpathoff, nil 209 }