1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
14 const debugParseRemoteType
= false
16 // A remoteType is the local representation of a type in a remote process.
17 type remoteType
struct {
19 // The size of values of this type in bytes.
21 // The field alignment of this type. Only used for
22 // manually-constructed types.
24 // The maker function to turn a remote address of a value of
25 // this type into an interpreter Value.
29 var manualTypes
= make(map[Arch
]map[eval
.Type
]*remoteType
)
31 // newManualType constructs a remote type from an interpreter Type
32 // using the size and alignment properties of the given architecture.
33 // Most types are parsed directly out of the remote process, but to do
34 // so we need to layout the structures that describe those types ourselves.
35 func newManualType(t eval
.Type
, arch Arch
) *remoteType
{
36 if nt
, ok
:= t
.(*eval
.NamedType
); ok
{
40 // Get the type map for this architecture
41 typeMap
:= manualTypes
[arch
]
43 typeMap
= make(map[eval
.Type
]*remoteType
)
44 manualTypes
[arch
] = typeMap
46 // Construct basic types for this architecture
47 basicType
:= func(t eval
.Type
, mk maker
, size
int, fieldAlign
int) {
48 t
= t
.(*eval
.NamedType
).Def
52 typeMap
[t
] = &remoteType
{t
, size
, fieldAlign
, mk
}
54 basicType(eval
.Uint8Type
, mkUint8
, 1, 0)
55 basicType(eval
.Uint32Type
, mkUint32
, 4, 0)
56 basicType(eval
.UintptrType
, mkUintptr
, arch
.PtrSize(), 0)
57 basicType(eval
.Int16Type
, mkInt16
, 2, 0)
58 basicType(eval
.Int32Type
, mkInt32
, 4, 0)
59 basicType(eval
.IntType
, mkInt
, arch
.IntSize(), 0)
60 basicType(eval
.StringType
, mkString
, arch
.PtrSize()+arch
.IntSize(), arch
.PtrSize())
63 if rt
, ok
:= typeMap
[t
]; ok
{
68 switch t
:= t
.(type) {
71 mk
:= func(r remote
) eval
.Value
{ return remotePtr
{r
, elem
} }
72 rt
= &remoteType
{t
, arch
.PtrSize(), arch
.PtrSize(), mk
}
73 // Construct the element type after registering the
74 // type to break cycles.
75 typeMap
[eval
.Type(t
)] = rt
76 elem
= newManualType(t
.Elem
, arch
)
79 elem
:= newManualType(t
.Elem
, arch
)
80 mk
:= func(r remote
) eval
.Value
{ return remoteArray
{r
, t
.Len
, elem
} }
81 rt
= &remoteType
{t
, elem
.size
* int(t
.Len
), elem
.fieldAlign
, mk
}
84 elem
:= newManualType(t
.Elem
, arch
)
85 mk
:= func(r remote
) eval
.Value
{ return remoteSlice
{r
, elem
} }
86 rt
= &remoteType
{t
, arch
.PtrSize() + 2*arch
.IntSize(), arch
.PtrSize(), mk
}
88 case *eval
.StructType
:
89 layout
:= make([]remoteStructField
, len(t
.Elems
))
92 for i
, f
:= range t
.Elems
{
93 elem
:= newManualType(f
.Type
, arch
)
95 fieldAlign
= elem
.fieldAlign
97 offset
= arch
.Align(offset
, elem
.fieldAlign
)
98 layout
[i
].offset
= offset
99 layout
[i
].fieldType
= elem
102 mk
:= func(r remote
) eval
.Value
{ return remoteStruct
{r
, layout
} }
103 rt
= &remoteType
{t
, offset
, fieldAlign
, mk
}
106 log
.Panicf("cannot manually construct type %T", t
)
115 // parseRemoteType parses a Type structure in a remote process to
116 // construct the corresponding interpreter type and remote type.
117 func parseRemoteType(a aborter
, rs remoteStruct
) *remoteType
{
118 addr
:= rs
.addr().base
121 // We deal with circular types by discovering cycles at
122 // NamedTypes. If a type cycles back to something other than
123 // a named type, we're guaranteed that there will be a named
124 // type somewhere in that cycle. Thus, we continue down,
125 // re-parsing types until we reach the named type in the
126 // cycle. In order to still create one remoteType per remote
127 // type, we insert an empty remoteType in the type map the
128 // first time we encounter the type and re-use that structure
129 // the second time we encounter it.
131 rt
, ok
:= p
.types
[addr
]
132 if ok
&& rt
.Type
!= nil {
139 if debugParseRemoteType
{
140 sym
:= p
.syms
.SymByAddr(uint64(addr
))
145 log
.Printf("%sParsing type at %#x (%s)", prtIndent
, addr
, name
)
147 defer func() { prtIndent
= prtIndent
[0 : len(prtIndent
)-1] }()
151 itype
:= proc
.Word(rs
.field(p
.f
.Type
.Typ
).(remoteUint
).aGet(a
))
152 typ
:= rs
.field(p
.f
.Type
.Ptr
).(remotePtr
).aGet(a
).(remoteStruct
)
154 // Is this a named type?
155 var nt
*eval
.NamedType
156 uncommon
:= typ
.field(p
.f
.CommonType
.UncommonType
).(remotePtr
).aGet(a
)
158 name
:= uncommon
.(remoteStruct
).field(p
.f
.UncommonType
.Name
).(remotePtr
).aGet(a
)
160 // TODO(austin) Declare type in appropriate remote package
161 nt
= eval
.NewNamedType(name
.(remoteString
).aGet(a
))
170 case p
.runtime
.PBoolType
:
173 case p
.runtime
.PUint8Type
:
176 case p
.runtime
.PUint16Type
:
179 case p
.runtime
.PUint32Type
:
182 case p
.runtime
.PUint64Type
:
185 case p
.runtime
.PUintType
:
188 case p
.runtime
.PUintptrType
:
191 case p
.runtime
.PInt8Type
:
194 case p
.runtime
.PInt16Type
:
197 case p
.runtime
.PInt32Type
:
200 case p
.runtime
.PInt64Type
:
203 case p
.runtime
.PIntType
:
206 case p
.runtime
.PFloat32Type
:
209 case p
.runtime
.PFloat64Type
:
212 case p
.runtime
.PFloatType
:
215 case p
.runtime
.PStringType
:
219 case p
.runtime
.PArrayType
:
220 // Cast to an ArrayType
221 typ
:= p
.runtime
.ArrayType
.mk(typ
.addr()).(remoteStruct
)
222 len := int64(typ
.field(p
.f
.ArrayType
.Len
).(remoteUint
).aGet(a
))
223 elem
:= parseRemoteType(a
, typ
.field(p
.f
.ArrayType
.Elem
).(remotePtr
).aGet(a
).(remoteStruct
))
224 t
= eval
.NewArrayType(len, elem
.Type
)
225 mk
= func(r remote
) eval
.Value
{ return remoteArray
{r
, len, elem
} }
227 case p
.runtime
.PStructType
:
228 // Cast to a StructType
229 typ
:= p
.runtime
.StructType
.mk(typ
.addr()).(remoteStruct
)
230 fs
:= typ
.field(p
.f
.StructType
.Fields
).(remoteSlice
).aGet(a
)
232 fields
:= make([]eval
.StructField
, fs
.Len
)
233 layout
:= make([]remoteStructField
, fs
.Len
)
234 for i
:= range fields
{
235 f
:= fs
.Base
.(remoteArray
).elem(int64(i
)).(remoteStruct
)
236 elemrs
:= f
.field(p
.f
.StructField
.Typ
).(remotePtr
).aGet(a
).(remoteStruct
)
237 elem
:= parseRemoteType(a
, elemrs
)
238 fields
[i
].Type
= elem
.Type
239 name
:= f
.field(p
.f
.StructField
.Name
).(remotePtr
).aGet(a
)
241 fields
[i
].Anonymous
= true
243 fields
[i
].Name
= name
.(remoteString
).aGet(a
)
245 layout
[i
].offset
= int(f
.field(p
.f
.StructField
.Offset
).(remoteUint
).aGet(a
))
246 layout
[i
].fieldType
= elem
249 t
= eval
.NewStructType(fields
)
250 mk
= func(r remote
) eval
.Value
{ return remoteStruct
{r
, layout
} }
252 case p
.runtime
.PPtrType
:
254 typ
:= p
.runtime
.PtrType
.mk(typ
.addr()).(remoteStruct
)
255 elem
:= parseRemoteType(a
, typ
.field(p
.f
.PtrType
.Elem
).(remotePtr
).aGet(a
).(remoteStruct
))
256 t
= eval
.NewPtrType(elem
.Type
)
257 mk
= func(r remote
) eval
.Value
{ return remotePtr
{r
, elem
} }
259 case p
.runtime
.PSliceType
:
260 // Cast to a SliceType
261 typ
:= p
.runtime
.SliceType
.mk(typ
.addr()).(remoteStruct
)
262 elem
:= parseRemoteType(a
, typ
.field(p
.f
.SliceType
.Elem
).(remotePtr
).aGet(a
).(remoteStruct
))
263 t
= eval
.NewSliceType(elem
.Type
)
264 mk
= func(r remote
) eval
.Value
{ return remoteSlice
{r
, elem
} }
266 case p
.runtime
.PMapType
, p
.runtime
.PChanType
, p
.runtime
.PFuncType
, p
.runtime
.PInterfaceType
, p
.runtime
.PUnsafePointerType
, p
.runtime
.PDotDotDotType
:
272 sym
:= p
.syms
.SymByAddr(uint64(itype
))
273 name
:= "<unknown symbol>"
277 err
:= fmt
.Sprintf("runtime type at %#x has unexpected type %#x (%s)", addr
, itype
, name
)
278 a
.Abort(FormatError(err
))
281 // Fill in the remote type
287 rt
.size
= int(typ
.field(p
.f
.CommonType
.Size
).(remoteUint
).aGet(a
))