1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
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
}
|