diff options
Diffstat (limited to 'libgo/go/exp/ogle/rtype.go')
-rw-r--r-- | libgo/go/exp/ogle/rtype.go | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/libgo/go/exp/ogle/rtype.go b/libgo/go/exp/ogle/rtype.go new file mode 100644 index 000000000..b3c35575a --- /dev/null +++ b/libgo/go/exp/ogle/rtype.go @@ -0,0 +1,288 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ogle + +import ( + "debug/proc" + "exp/eval" + "fmt" + "log" +) + +const debugParseRemoteType = false + +// A remoteType is the local representation of a type in a remote process. +type remoteType struct { + eval.Type + // The size of values of this type in bytes. + size int + // The field alignment of this type. Only used for + // manually-constructed types. + fieldAlign int + // The maker function to turn a remote address of a value of + // this type into an interpreter Value. + mk maker +} + +var manualTypes = make(map[Arch]map[eval.Type]*remoteType) + +// newManualType constructs a remote type from an interpreter Type +// using the size and alignment properties of the given architecture. +// Most types are parsed directly out of the remote process, but to do +// so we need to layout the structures that describe those types ourselves. +func newManualType(t eval.Type, arch Arch) *remoteType { + if nt, ok := t.(*eval.NamedType); ok { + t = nt.Def + } + + // Get the type map for this architecture + typeMap := manualTypes[arch] + if typeMap == nil { + typeMap = make(map[eval.Type]*remoteType) + manualTypes[arch] = typeMap + + // Construct basic types for this architecture + basicType := func(t eval.Type, mk maker, size int, fieldAlign int) { + t = t.(*eval.NamedType).Def + if fieldAlign == 0 { + fieldAlign = size + } + typeMap[t] = &remoteType{t, size, fieldAlign, mk} + } + basicType(eval.Uint8Type, mkUint8, 1, 0) + basicType(eval.Uint32Type, mkUint32, 4, 0) + basicType(eval.UintptrType, mkUintptr, arch.PtrSize(), 0) + basicType(eval.Int16Type, mkInt16, 2, 0) + basicType(eval.Int32Type, mkInt32, 4, 0) + basicType(eval.IntType, mkInt, arch.IntSize(), 0) + basicType(eval.StringType, mkString, arch.PtrSize()+arch.IntSize(), arch.PtrSize()) + } + + if rt, ok := typeMap[t]; ok { + return rt + } + + var rt *remoteType + switch t := t.(type) { + case *eval.PtrType: + var elem *remoteType + mk := func(r remote) eval.Value { return remotePtr{r, elem} } + rt = &remoteType{t, arch.PtrSize(), arch.PtrSize(), mk} + // Construct the element type after registering the + // type to break cycles. + typeMap[eval.Type(t)] = rt + elem = newManualType(t.Elem, arch) + + case *eval.ArrayType: + elem := newManualType(t.Elem, arch) + mk := func(r remote) eval.Value { return remoteArray{r, t.Len, elem} } + rt = &remoteType{t, elem.size * int(t.Len), elem.fieldAlign, mk} + + case *eval.SliceType: + elem := newManualType(t.Elem, arch) + mk := func(r remote) eval.Value { return remoteSlice{r, elem} } + rt = &remoteType{t, arch.PtrSize() + 2*arch.IntSize(), arch.PtrSize(), mk} + + case *eval.StructType: + layout := make([]remoteStructField, len(t.Elems)) + offset := 0 + fieldAlign := 0 + for i, f := range t.Elems { + elem := newManualType(f.Type, arch) + if fieldAlign == 0 { + fieldAlign = elem.fieldAlign + } + offset = arch.Align(offset, elem.fieldAlign) + layout[i].offset = offset + layout[i].fieldType = elem + offset += elem.size + } + mk := func(r remote) eval.Value { return remoteStruct{r, layout} } + rt = &remoteType{t, offset, fieldAlign, mk} + + default: + log.Panicf("cannot manually construct type %T", t) + } + + typeMap[t] = rt + return rt +} + +var prtIndent = "" + +// parseRemoteType parses a Type structure in a remote process to +// construct the corresponding interpreter type and remote type. +func parseRemoteType(a aborter, rs remoteStruct) *remoteType { + addr := rs.addr().base + p := rs.addr().p + + // We deal with circular types by discovering cycles at + // NamedTypes. If a type cycles back to something other than + // a named type, we're guaranteed that there will be a named + // type somewhere in that cycle. Thus, we continue down, + // re-parsing types until we reach the named type in the + // cycle. In order to still create one remoteType per remote + // type, we insert an empty remoteType in the type map the + // first time we encounter the type and re-use that structure + // the second time we encounter it. + + rt, ok := p.types[addr] + if ok && rt.Type != nil { + return rt + } else if !ok { + rt = &remoteType{} + p.types[addr] = rt + } + + if debugParseRemoteType { + sym := p.syms.SymByAddr(uint64(addr)) + name := "<unknown>" + if sym != nil { + name = sym.Name + } + log.Printf("%sParsing type at %#x (%s)", prtIndent, addr, name) + prtIndent += " " + defer func() { prtIndent = prtIndent[0 : len(prtIndent)-1] }() + } + + // Get Type header + itype := proc.Word(rs.field(p.f.Type.Typ).(remoteUint).aGet(a)) + typ := rs.field(p.f.Type.Ptr).(remotePtr).aGet(a).(remoteStruct) + + // Is this a named type? + var nt *eval.NamedType + uncommon := typ.field(p.f.CommonType.UncommonType).(remotePtr).aGet(a) + if uncommon != nil { + name := uncommon.(remoteStruct).field(p.f.UncommonType.Name).(remotePtr).aGet(a) + if name != nil { + // TODO(austin) Declare type in appropriate remote package + nt = eval.NewNamedType(name.(remoteString).aGet(a)) + rt.Type = nt + } + } + + // Create type + var t eval.Type + var mk maker + switch itype { + case p.runtime.PBoolType: + t = eval.BoolType + mk = mkBool + case p.runtime.PUint8Type: + t = eval.Uint8Type + mk = mkUint8 + case p.runtime.PUint16Type: + t = eval.Uint16Type + mk = mkUint16 + case p.runtime.PUint32Type: + t = eval.Uint32Type + mk = mkUint32 + case p.runtime.PUint64Type: + t = eval.Uint64Type + mk = mkUint64 + case p.runtime.PUintType: + t = eval.UintType + mk = mkUint + case p.runtime.PUintptrType: + t = eval.UintptrType + mk = mkUintptr + case p.runtime.PInt8Type: + t = eval.Int8Type + mk = mkInt8 + case p.runtime.PInt16Type: + t = eval.Int16Type + mk = mkInt16 + case p.runtime.PInt32Type: + t = eval.Int32Type + mk = mkInt32 + case p.runtime.PInt64Type: + t = eval.Int64Type + mk = mkInt64 + case p.runtime.PIntType: + t = eval.IntType + mk = mkInt + case p.runtime.PFloat32Type: + t = eval.Float32Type + mk = mkFloat32 + case p.runtime.PFloat64Type: + t = eval.Float64Type + mk = mkFloat64 + case p.runtime.PStringType: + t = eval.StringType + mk = mkString + + case p.runtime.PArrayType: + // Cast to an ArrayType + typ := p.runtime.ArrayType.mk(typ.addr()).(remoteStruct) + len := int64(typ.field(p.f.ArrayType.Len).(remoteUint).aGet(a)) + elem := parseRemoteType(a, typ.field(p.f.ArrayType.Elem).(remotePtr).aGet(a).(remoteStruct)) + t = eval.NewArrayType(len, elem.Type) + mk = func(r remote) eval.Value { return remoteArray{r, len, elem} } + + case p.runtime.PStructType: + // Cast to a StructType + typ := p.runtime.StructType.mk(typ.addr()).(remoteStruct) + fs := typ.field(p.f.StructType.Fields).(remoteSlice).aGet(a) + + fields := make([]eval.StructField, fs.Len) + layout := make([]remoteStructField, fs.Len) + for i := range fields { + f := fs.Base.(remoteArray).elem(int64(i)).(remoteStruct) + elemrs := f.field(p.f.StructField.Typ).(remotePtr).aGet(a).(remoteStruct) + elem := parseRemoteType(a, elemrs) + fields[i].Type = elem.Type + name := f.field(p.f.StructField.Name).(remotePtr).aGet(a) + if name == nil { + fields[i].Anonymous = true + } else { + fields[i].Name = name.(remoteString).aGet(a) + } + layout[i].offset = int(f.field(p.f.StructField.Offset).(remoteUint).aGet(a)) + layout[i].fieldType = elem + } + + t = eval.NewStructType(fields) + mk = func(r remote) eval.Value { return remoteStruct{r, layout} } + + case p.runtime.PPtrType: + // Cast to a PtrType + typ := p.runtime.PtrType.mk(typ.addr()).(remoteStruct) + elem := parseRemoteType(a, typ.field(p.f.PtrType.Elem).(remotePtr).aGet(a).(remoteStruct)) + t = eval.NewPtrType(elem.Type) + mk = func(r remote) eval.Value { return remotePtr{r, elem} } + + case p.runtime.PSliceType: + // Cast to a SliceType + typ := p.runtime.SliceType.mk(typ.addr()).(remoteStruct) + elem := parseRemoteType(a, typ.field(p.f.SliceType.Elem).(remotePtr).aGet(a).(remoteStruct)) + t = eval.NewSliceType(elem.Type) + mk = func(r remote) eval.Value { return remoteSlice{r, elem} } + + case p.runtime.PMapType, p.runtime.PChanType, p.runtime.PFuncType, p.runtime.PInterfaceType, p.runtime.PUnsafePointerType, p.runtime.PDotDotDotType: + // TODO(austin) + t = eval.UintptrType + mk = mkUintptr + + default: + sym := p.syms.SymByAddr(uint64(itype)) + name := "<unknown symbol>" + if sym != nil { + name = sym.Name + } + err := fmt.Sprintf("runtime type at %#x has unexpected type %#x (%s)", addr, itype, name) + a.Abort(FormatError(err)) + } + + // Fill in the remote type + if nt != nil { + nt.Complete(t) + } else { + rt.Type = t + } + rt.size = int(typ.field(p.f.CommonType.Size).(remoteUint).aGet(a)) + rt.mk = mk + + return rt +} |