bee/vendor/github.com/derekparker/delve/pkg/proc/moduledata.go

204 lines
4.7 KiB
Go
Raw Normal View History

2017-03-19 22:45:54 +00:00
package proc
import (
"go/constant"
"unsafe"
)
// delve counterpart to runtime.moduledata
type moduleData struct {
types, etypes uintptr
typemapVar *Variable
}
2018-10-13 13:45:53 +00:00
func loadModuleData(bi *BinaryInfo, mem MemoryReadWriter) (err error) {
bi.loadModuleDataOnce.Do(func() {
scope := globalScope(bi, mem)
2017-03-19 22:45:54 +00:00
var md *Variable
2018-10-13 13:45:53 +00:00
md, err = scope.findGlobal("runtime.firstmoduledata")
2017-03-19 22:45:54 +00:00
if err != nil {
return
}
for md.Addr != 0 {
var typesVar, etypesVar, nextVar, typemapVar *Variable
var types, etypes uint64
if typesVar, err = md.structMember("types"); err != nil {
return
}
if etypesVar, err = md.structMember("etypes"); err != nil {
return
}
if nextVar, err = md.structMember("next"); err != nil {
return
}
if typemapVar, err = md.structMember("typemap"); err != nil {
return
}
if types, err = typesVar.asUint(); err != nil {
return
}
if etypes, err = etypesVar.asUint(); err != nil {
return
}
2018-10-13 13:45:53 +00:00
bi.moduleData = append(bi.moduleData, moduleData{uintptr(types), uintptr(etypes), typemapVar})
2017-03-19 22:45:54 +00:00
md = nextVar.maybeDereference()
if md.Unreadable != nil {
err = md.Unreadable
return
}
}
})
return
}
2018-10-13 13:45:53 +00:00
func findModuleDataForType(bi *BinaryInfo, typeAddr uintptr, mem MemoryReadWriter) (*moduleData, error) {
if err := loadModuleData(bi, mem); err != nil {
2017-03-19 22:45:54 +00:00
return nil, err
}
var md *moduleData
2018-10-13 13:45:53 +00:00
for i := range bi.moduleData {
if typeAddr >= bi.moduleData[i].types && typeAddr < bi.moduleData[i].etypes {
md = &bi.moduleData[i]
2017-03-19 22:45:54 +00:00
}
}
2018-10-13 13:45:53 +00:00
return md, nil
}
func resolveTypeOff(bi *BinaryInfo, typeAddr uintptr, off uintptr, mem MemoryReadWriter) (*Variable, error) {
// See runtime.(*_type).typeOff in $GOROOT/src/runtime/type.go
md, err := findModuleDataForType(bi, typeAddr, mem)
if err != nil {
return nil, err
}
rtyp, err := bi.findType("runtime._type")
2017-03-19 22:45:54 +00:00
if err != nil {
return nil, err
}
if md == nil {
2018-10-13 13:45:53 +00:00
v, err := reflectOffsMapAccess(bi, off, mem)
2017-03-19 22:45:54 +00:00
if err != nil {
return nil, err
}
v.loadValue(LoadConfig{false, 1, 0, 0, -1})
addr, _ := constant.Int64Val(v.Value)
2018-10-13 13:45:53 +00:00
return v.newVariable(v.Name, uintptr(addr), rtyp, mem), nil
2017-03-19 22:45:54 +00:00
}
2018-10-13 13:45:53 +00:00
if t, _ := md.typemapVar.mapAccess(newConstant(constant.MakeUint64(uint64(off)), mem)); t != nil {
2017-03-19 22:45:54 +00:00
return t, nil
}
res := md.types + uintptr(off)
2018-10-13 13:45:53 +00:00
return newVariable("", res, rtyp, bi, mem), nil
2017-03-19 22:45:54 +00:00
}
2018-10-13 13:45:53 +00:00
func resolveNameOff(bi *BinaryInfo, typeAddr uintptr, off uintptr, mem MemoryReadWriter) (name, tag string, pkgpathoff int32, err error) {
2017-03-19 22:45:54 +00:00
// See runtime.resolveNameOff in $GOROOT/src/runtime/type.go
2018-10-13 13:45:53 +00:00
if err = loadModuleData(bi, mem); err != nil {
2017-03-19 22:45:54 +00:00
return "", "", 0, err
}
2018-10-13 13:45:53 +00:00
for _, md := range bi.moduleData {
2017-03-19 22:45:54 +00:00
if typeAddr >= md.types && typeAddr < md.etypes {
2018-10-13 13:45:53 +00:00
return loadName(bi, md.types+off, mem)
2017-03-19 22:45:54 +00:00
}
}
2018-10-13 13:45:53 +00:00
v, err := reflectOffsMapAccess(bi, off, mem)
2017-03-19 22:45:54 +00:00
if err != nil {
return "", "", 0, err
}
resv := v.maybeDereference()
if resv.Unreadable != nil {
return "", "", 0, resv.Unreadable
}
2018-10-13 13:45:53 +00:00
return loadName(bi, resv.Addr, mem)
2017-03-19 22:45:54 +00:00
}
2018-10-13 13:45:53 +00:00
func reflectOffsMapAccess(bi *BinaryInfo, off uintptr, mem MemoryReadWriter) (*Variable, error) {
scope := globalScope(bi, mem)
reflectOffs, err := scope.findGlobal("runtime.reflectOffs")
2017-03-19 22:45:54 +00:00
if err != nil {
return nil, err
}
reflectOffsm, err := reflectOffs.structMember("m")
if err != nil {
return nil, err
}
2018-10-13 13:45:53 +00:00
return reflectOffsm.mapAccess(newConstant(constant.MakeUint64(uint64(off)), mem))
2017-03-19 22:45:54 +00:00
}
const (
// flags for the name struct (see 'type name struct' in $GOROOT/src/reflect/type.go)
nameflagExported = 1 << 0
nameflagHasTag = 1 << 1
nameflagHasPkg = 1 << 2
)
2018-10-13 13:45:53 +00:00
func loadName(bi *BinaryInfo, addr uintptr, mem MemoryReadWriter) (name, tag string, pkgpathoff int32, err error) {
2017-03-19 22:45:54 +00:00
off := addr
2018-10-13 13:45:53 +00:00
namedata := make([]byte, 3)
_, err = mem.ReadMemory(namedata, off)
2017-03-19 22:45:54 +00:00
off += 3
if err != nil {
return "", "", 0, err
}
2018-10-13 13:45:53 +00:00
namelen := uint16(namedata[1])<<8 | uint16(namedata[2])
2017-03-19 22:45:54 +00:00
2018-10-13 13:45:53 +00:00
rawstr := make([]byte, int(namelen))
_, err = mem.ReadMemory(rawstr, off)
2017-03-19 22:45:54 +00:00
off += uintptr(namelen)
if err != nil {
return "", "", 0, err
}
name = string(rawstr)
if namedata[0]&nameflagHasTag != 0 {
2018-10-13 13:45:53 +00:00
taglendata := make([]byte, 2)
_, err = mem.ReadMemory(taglendata, off)
2017-03-19 22:45:54 +00:00
off += 2
if err != nil {
return "", "", 0, err
}
2018-10-13 13:45:53 +00:00
taglen := uint16(taglendata[0])<<8 | uint16(taglendata[1])
2017-03-19 22:45:54 +00:00
2018-10-13 13:45:53 +00:00
rawstr := make([]byte, int(taglen))
_, err = mem.ReadMemory(rawstr, off)
2017-03-19 22:45:54 +00:00
off += uintptr(taglen)
if err != nil {
return "", "", 0, err
}
tag = string(rawstr)
}
if namedata[0]&nameflagHasPkg != 0 {
2018-10-13 13:45:53 +00:00
pkgdata := make([]byte, 4)
_, err = mem.ReadMemory(pkgdata, off)
2017-03-19 22:45:54 +00:00
if err != nil {
return "", "", 0, err
}
// see func pkgPath in $GOROOT/src/reflect/type.go
copy((*[4]byte)(unsafe.Pointer(&pkgpathoff))[:], pkgdata)
}
return name, tag, pkgpathoff, nil
}