2016-05-29 19:20:09 +00:00
|
|
|
package proc
|
|
|
|
|
|
|
|
import (
|
|
|
|
"go/constant"
|
2016-09-08 16:11:20 +00:00
|
|
|
"unsafe"
|
2016-05-29 19:20:09 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// delve counterpart to runtime.moduledata
|
|
|
|
type moduleData struct {
|
2020-09-09 17:36:15 +00:00
|
|
|
text, etext uint64
|
|
|
|
types, etypes uint64
|
2016-09-08 16:11:20 +00:00
|
|
|
typemapVar *Variable
|
2016-05-29 19:20:09 +00:00
|
|
|
}
|
|
|
|
|
2019-05-08 21:06:38 +00:00
|
|
|
func loadModuleData(bi *BinaryInfo, mem MemoryReadWriter) ([]moduleData, error) {
|
|
|
|
scope := globalScope(bi, bi.Images[0], mem)
|
|
|
|
var md *Variable
|
2019-11-25 17:10:18 +00:00
|
|
|
md, err := scope.findGlobal("runtime", "firstmoduledata")
|
2019-05-08 21:06:38 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2016-05-29 19:20:09 +00:00
|
|
|
|
2019-05-08 21:06:38 +00:00
|
|
|
r := []moduleData{}
|
|
|
|
|
|
|
|
for md.Addr != 0 {
|
|
|
|
const (
|
|
|
|
typesField = "types"
|
|
|
|
etypesField = "etypes"
|
|
|
|
textField = "text"
|
|
|
|
etextField = "etext"
|
|
|
|
nextField = "next"
|
|
|
|
typemapField = "typemap"
|
|
|
|
)
|
|
|
|
vars := map[string]*Variable{}
|
|
|
|
|
|
|
|
for _, fieldName := range []string{typesField, etypesField, textField, etextField, nextField, typemapField} {
|
|
|
|
var err error
|
|
|
|
vars[fieldName], err = md.structMember(fieldName)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2016-05-29 19:20:09 +00:00
|
|
|
}
|
|
|
|
|
2019-05-08 21:06:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var err error
|
2016-05-29 19:20:09 +00:00
|
|
|
|
2020-09-09 17:36:15 +00:00
|
|
|
touint := func(name string) (ret uint64) {
|
2019-05-08 21:06:38 +00:00
|
|
|
if err == nil {
|
|
|
|
var n uint64
|
|
|
|
n, err = vars[name].asUint()
|
2020-09-09 17:36:15 +00:00
|
|
|
ret = n
|
2016-05-29 19:20:09 +00:00
|
|
|
}
|
2019-05-08 21:06:38 +00:00
|
|
|
return ret
|
2016-05-29 19:20:09 +00:00
|
|
|
}
|
|
|
|
|
2019-05-08 21:06:38 +00:00
|
|
|
r = append(r, moduleData{
|
|
|
|
types: touint(typesField), etypes: touint(etypesField),
|
|
|
|
text: touint(textField), etext: touint(etextField),
|
|
|
|
typemapVar: vars[typemapField],
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2016-05-29 19:20:09 +00:00
|
|
|
|
2019-05-08 21:06:38 +00:00
|
|
|
md = vars[nextField].maybeDereference()
|
|
|
|
if md.Unreadable != nil {
|
|
|
|
return nil, md.Unreadable
|
|
|
|
}
|
2016-09-08 16:11:20 +00:00
|
|
|
}
|
|
|
|
|
2019-05-08 21:06:38 +00:00
|
|
|
return r, nil
|
|
|
|
}
|
|
|
|
|
2020-09-09 17:36:15 +00:00
|
|
|
func findModuleDataForType(bi *BinaryInfo, mds []moduleData, typeAddr uint64, mem MemoryReadWriter) *moduleData {
|
2019-05-08 21:06:38 +00:00
|
|
|
for i := range mds {
|
|
|
|
if typeAddr >= mds[i].types && typeAddr < mds[i].etypes {
|
|
|
|
return &mds[i]
|
2016-09-08 16:11:20 +00:00
|
|
|
}
|
|
|
|
}
|
2019-05-08 21:06:38 +00:00
|
|
|
return nil
|
2018-04-18 18:09:33 +00:00
|
|
|
}
|
|
|
|
|
2020-09-09 17:36:15 +00:00
|
|
|
func resolveTypeOff(bi *BinaryInfo, mds []moduleData, typeAddr, off uint64, mem MemoryReadWriter) (*Variable, error) {
|
2018-04-18 18:09:33 +00:00
|
|
|
// See runtime.(*_type).typeOff in $GOROOT/src/runtime/type.go
|
2019-05-08 21:06:38 +00:00
|
|
|
md := findModuleDataForType(bi, mds, typeAddr, mem)
|
2018-04-18 18:09:33 +00:00
|
|
|
|
2017-04-06 18:14:01 +00:00
|
|
|
rtyp, err := bi.findType("runtime._type")
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2016-05-29 19:20:09 +00:00
|
|
|
}
|
2016-09-08 16:11:20 +00:00
|
|
|
|
|
|
|
if md == nil {
|
2017-04-13 23:19:57 +00:00
|
|
|
v, err := reflectOffsMapAccess(bi, off, mem)
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-10-29 11:22:03 +00:00
|
|
|
v.loadValue(LoadConfig{false, 1, 0, 0, -1, 0})
|
2016-09-08 16:11:20 +00:00
|
|
|
addr, _ := constant.Int64Val(v.Value)
|
2020-09-09 17:36:15 +00:00
|
|
|
return v.newVariable(v.Name, uint64(addr), rtyp, mem), nil
|
2016-09-08 16:11:20 +00:00
|
|
|
}
|
|
|
|
|
2017-04-06 18:14:01 +00:00
|
|
|
if t, _ := md.typemapVar.mapAccess(newConstant(constant.MakeUint64(uint64(off)), mem)); t != nil {
|
2016-09-08 16:11:20 +00:00
|
|
|
return t, nil
|
|
|
|
}
|
|
|
|
|
2020-09-09 17:36:15 +00:00
|
|
|
res := md.types + off
|
2016-09-08 16:11:20 +00:00
|
|
|
|
2020-09-09 17:36:15 +00:00
|
|
|
return newVariable("", uint64(res), rtyp, bi, mem), nil
|
2016-09-08 16:11:20 +00:00
|
|
|
}
|
|
|
|
|
2020-09-09 17:36:15 +00:00
|
|
|
func resolveNameOff(bi *BinaryInfo, mds []moduleData, typeAddr, off uint64, mem MemoryReadWriter) (name, tag string, pkgpathoff int32, err error) {
|
2016-09-08 16:11:20 +00:00
|
|
|
// See runtime.resolveNameOff in $GOROOT/src/runtime/type.go
|
2019-05-08 21:06:38 +00:00
|
|
|
for _, md := range mds {
|
2016-05-29 19:20:09 +00:00
|
|
|
if typeAddr >= md.types && typeAddr < md.etypes {
|
2017-04-13 23:19:57 +00:00
|
|
|
return loadName(bi, md.types+off, mem)
|
2016-05-29 19:20:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-13 23:19:57 +00:00
|
|
|
v, err := reflectOffsMapAccess(bi, off, mem)
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", "", 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
resv := v.maybeDereference()
|
|
|
|
if resv.Unreadable != nil {
|
|
|
|
return "", "", 0, resv.Unreadable
|
|
|
|
}
|
|
|
|
|
2017-04-13 23:19:57 +00:00
|
|
|
return loadName(bi, resv.Addr, mem)
|
2016-09-08 16:11:20 +00:00
|
|
|
}
|
|
|
|
|
2020-09-09 17:36:15 +00:00
|
|
|
func reflectOffsMapAccess(bi *BinaryInfo, off uint64, mem MemoryReadWriter) (*Variable, error) {
|
2019-05-08 21:06:38 +00:00
|
|
|
scope := globalScope(bi, bi.Images[0], mem)
|
2019-11-25 17:10:18 +00:00
|
|
|
reflectOffs, err := scope.findGlobal("runtime", "reflectOffs")
|
2016-05-29 19:20:09 +00:00
|
|
|
if err != nil {
|
2016-09-08 16:11:20 +00:00
|
|
|
return nil, err
|
2016-05-29 19:20:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
reflectOffsm, err := reflectOffs.structMember("m")
|
|
|
|
if err != nil {
|
2016-09-08 16:11:20 +00:00
|
|
|
return nil, err
|
2016-05-29 19:20:09 +00:00
|
|
|
}
|
|
|
|
|
2017-04-13 23:19:57 +00:00
|
|
|
return reflectOffsm.mapAccess(newConstant(constant.MakeUint64(uint64(off)), mem))
|
2016-09-08 16:11:20 +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
|
|
|
|
)
|
|
|
|
|
2020-09-09 17:36:15 +00:00
|
|
|
func loadName(bi *BinaryInfo, addr uint64, mem MemoryReadWriter) (name, tag string, pkgpathoff int32, err error) {
|
2016-09-08 16:11:20 +00:00
|
|
|
off := addr
|
2017-04-18 14:24:45 +00:00
|
|
|
namedata := make([]byte, 3)
|
|
|
|
_, err = mem.ReadMemory(namedata, off)
|
2016-09-08 16:11:20 +00:00
|
|
|
off += 3
|
2016-05-29 19:20:09 +00:00
|
|
|
if err != nil {
|
2016-09-08 16:11:20 +00:00
|
|
|
return "", "", 0, err
|
2016-05-29 19:20:09 +00:00
|
|
|
}
|
|
|
|
|
2018-04-19 05:27:34 +00:00
|
|
|
namelen := uint16(namedata[1])<<8 | uint16(namedata[2])
|
2016-09-08 16:11:20 +00:00
|
|
|
|
2017-04-18 14:24:45 +00:00
|
|
|
rawstr := make([]byte, int(namelen))
|
|
|
|
_, err = mem.ReadMemory(rawstr, off)
|
2020-09-09 17:36:15 +00:00
|
|
|
off += uint64(namelen)
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", "", 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
name = string(rawstr)
|
|
|
|
|
|
|
|
if namedata[0]&nameflagHasTag != 0 {
|
2017-04-18 14:24:45 +00:00
|
|
|
taglendata := make([]byte, 2)
|
|
|
|
_, err = mem.ReadMemory(taglendata, off)
|
2016-09-08 16:11:20 +00:00
|
|
|
off += 2
|
|
|
|
if err != nil {
|
|
|
|
return "", "", 0, err
|
|
|
|
}
|
2018-04-19 05:27:34 +00:00
|
|
|
taglen := uint16(taglendata[0])<<8 | uint16(taglendata[1])
|
2016-09-08 16:11:20 +00:00
|
|
|
|
2017-04-18 14:24:45 +00:00
|
|
|
rawstr := make([]byte, int(taglen))
|
|
|
|
_, err = mem.ReadMemory(rawstr, off)
|
2020-09-09 17:36:15 +00:00
|
|
|
off += uint64(taglen)
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", "", 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
tag = string(rawstr)
|
|
|
|
}
|
|
|
|
|
|
|
|
if namedata[0]&nameflagHasPkg != 0 {
|
2017-04-18 14:24:45 +00:00
|
|
|
pkgdata := make([]byte, 4)
|
|
|
|
_, err = mem.ReadMemory(pkgdata, off)
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", "", 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// see func pkgPath in $GOROOT/src/reflect/type.go
|
|
|
|
copy((*[4]byte)(unsafe.Pointer(&pkgpathoff))[:], pkgdata)
|
2016-05-29 19:20:09 +00:00
|
|
|
}
|
|
|
|
|
2016-09-08 16:11:20 +00:00
|
|
|
return name, tag, pkgpathoff, nil
|
2016-05-29 19:20:09 +00:00
|
|
|
}
|