1// Copyright 2018 Google Inc. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Functions for reading values of various types from a program's memory.
16
17// +build linux
18
19package server
20
21import (
22	"errors"
23	"fmt"
24
25	"cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug"
26	"cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf"
27)
28
29// peekBytes reads len(buf) bytes at addr.
30func (s *Server) peekBytes(addr uint64, buf []byte) error {
31	return s.ptracePeek(s.stoppedPid, uintptr(addr), buf)
32}
33
34// peekPtr reads a pointer at addr.
35func (s *Server) peekPtr(addr uint64) (uint64, error) {
36	buf := make([]byte, s.arch.PointerSize)
37	if err := s.peekBytes(addr, buf); err != nil {
38		return 0, err
39	}
40	return s.arch.Uintptr(buf), nil
41}
42
43// peekUint8 reads a single byte at addr.
44func (s *Server) peekUint8(addr uint64) (byte, error) {
45	buf := make([]byte, 1)
46	if err := s.peekBytes(addr, buf); err != nil {
47		return 0, err
48	}
49	return uint8(s.arch.UintN(buf)), nil
50}
51
52// peekInt reads an int of size n bytes at addr.
53func (s *Server) peekInt(addr uint64, n int64) (int64, error) {
54	buf := make([]byte, n)
55	if err := s.peekBytes(addr, buf); err != nil {
56		return 0, err
57	}
58	return s.arch.IntN(buf), nil
59}
60
61// peekUint reads a uint of size n bytes at addr.
62func (s *Server) peekUint(addr uint64, n int64) (uint64, error) {
63	buf := make([]byte, n)
64	if err := s.peekBytes(addr, buf); err != nil {
65		return 0, err
66	}
67	return s.arch.UintN(buf), nil
68}
69
70// peekSlice reads the header of a slice with the given type and address.
71func (s *Server) peekSlice(t *dwarf.SliceType, addr uint64) (debug.Slice, error) {
72	ptr, err := s.peekPtrStructField(&t.StructType, addr, "array")
73	if err != nil {
74		return debug.Slice{}, fmt.Errorf("reading slice location: %s", err)
75	}
76	length, err := s.peekUintOrIntStructField(&t.StructType, addr, "len")
77	if err != nil {
78		return debug.Slice{}, fmt.Errorf("reading slice length: %s", err)
79	}
80	capacity, err := s.peekUintOrIntStructField(&t.StructType, addr, "cap")
81	if err != nil {
82		return debug.Slice{}, fmt.Errorf("reading slice capacity: %s", err)
83	}
84	if capacity < length {
85		return debug.Slice{}, fmt.Errorf("slice's capacity %d is less than its length %d", capacity, length)
86	}
87
88	return debug.Slice{
89		debug.Array{
90			ElementTypeID: uint64(t.ElemType.Common().Offset),
91			Address:       uint64(ptr),
92			Length:        length,
93			StrideBits:    uint64(t.ElemType.Common().ByteSize) * 8,
94		},
95		capacity,
96	}, nil
97}
98
99// peekString reads a string of the given type at the given address.
100// At most byteLimit bytes will be read.  If the string is longer, "..." is appended.
101func (s *Server) peekString(typ *dwarf.StringType, a uint64, byteLimit uint64) (string, error) {
102	ptr, err := s.peekPtrStructField(&typ.StructType, a, "str")
103	if err != nil {
104		return "", err
105	}
106	length, err := s.peekUintOrIntStructField(&typ.StructType, a, "len")
107	if err != nil {
108		return "", err
109	}
110	if length > byteLimit {
111		buf := make([]byte, byteLimit, byteLimit+3)
112		if err := s.peekBytes(ptr, buf); err != nil {
113			return "", err
114		} else {
115			buf = append(buf, '.', '.', '.')
116			return string(buf), nil
117		}
118	} else {
119		buf := make([]byte, length)
120		if err := s.peekBytes(ptr, buf); err != nil {
121			return "", err
122		} else {
123			return string(buf), nil
124		}
125	}
126}
127
128// peekCString reads a NUL-terminated string at the given address.
129// At most byteLimit bytes will be read.  If the string is longer, "..." is appended.
130// peekCString never returns errors; if an error occurs, the string will be truncated in some way.
131func (s *Server) peekCString(a uint64, byteLimit uint64) string {
132	buf := make([]byte, byteLimit, byteLimit+3)
133	s.peekBytes(a, buf)
134	for i, c := range buf {
135		if c == 0 {
136			return string(buf[0:i])
137		}
138	}
139	buf = append(buf, '.', '.', '.')
140	return string(buf)
141}
142
143// peekPtrStructField reads a pointer in the field fieldName of the struct
144// of type t at addr.
145func (s *Server) peekPtrStructField(t *dwarf.StructType, addr uint64, fieldName string) (uint64, error) {
146	f, err := getField(t, fieldName)
147	if err != nil {
148		return 0, fmt.Errorf("reading field %s: %s", fieldName, err)
149	}
150	if _, ok := f.Type.(*dwarf.PtrType); !ok {
151		return 0, fmt.Errorf("field %s is not a pointer", fieldName)
152	}
153	return s.peekPtr(addr + uint64(f.ByteOffset))
154}
155
156// peekUintOrIntStructField reads a signed or unsigned integer in the field fieldName
157// of the struct of type t at addr. If the value is negative, it returns an error.
158// This function is used when the value should be non-negative, but the DWARF
159// type of the field may be signed or unsigned.
160func (s *Server) peekUintOrIntStructField(t *dwarf.StructType, addr uint64, fieldName string) (uint64, error) {
161	f, err := getField(t, fieldName)
162	if err != nil {
163		return 0, fmt.Errorf("reading field %s: %s", fieldName, err)
164	}
165	ut, ok := f.Type.(*dwarf.UintType)
166	if ok {
167		return s.peekUint(addr+uint64(f.ByteOffset), ut.ByteSize)
168	}
169	it, ok := f.Type.(*dwarf.IntType)
170	if !ok {
171		return 0, fmt.Errorf("field %s is not an integer", fieldName)
172	}
173	i, err := s.peekInt(addr+uint64(f.ByteOffset), it.ByteSize)
174	if err != nil {
175		return 0, err
176	}
177	if i < 0 {
178		return 0, fmt.Errorf("field %s is negative", fieldName)
179	}
180	return uint64(i), nil
181}
182
183// peekUintStructField reads a uint in the field fieldName of the struct
184// of type t at addr.  The size of the uint is determined by the field.
185func (s *Server) peekUintStructField(t *dwarf.StructType, addr uint64, fieldName string) (uint64, error) {
186	f, err := getField(t, fieldName)
187	if err != nil {
188		return 0, fmt.Errorf("reading field %s: %s", fieldName, err)
189	}
190	ut, ok := f.Type.(*dwarf.UintType)
191	if !ok {
192		return 0, fmt.Errorf("field %s is not an unsigned integer", fieldName)
193	}
194	return s.peekUint(addr+uint64(f.ByteOffset), ut.ByteSize)
195}
196
197// peekIntStructField reads an int in the field fieldName of the struct
198// of type t at addr.  The size of the int is determined by the field.
199func (s *Server) peekIntStructField(t *dwarf.StructType, addr uint64, fieldName string) (int64, error) {
200	f, err := getField(t, fieldName)
201	if err != nil {
202		return 0, fmt.Errorf("reading field %s: %s", fieldName, err)
203	}
204	it, ok := f.Type.(*dwarf.IntType)
205	if !ok {
206		return 0, fmt.Errorf("field %s is not a signed integer", fieldName)
207	}
208	return s.peekInt(addr+uint64(f.ByteOffset), it.ByteSize)
209}
210
211// peekStringStructField reads a string field from the struct of the given type
212// at the given address.
213// At most byteLimit bytes will be read.  If the string is longer, "..." is appended.
214func (s *Server) peekStringStructField(t *dwarf.StructType, addr uint64, fieldName string, byteLimit uint64) (string, error) {
215	f, err := getField(t, fieldName)
216	if err != nil {
217		return "", fmt.Errorf("reading field %s: %s", fieldName, err)
218	}
219	st, ok := followTypedefs(f.Type).(*dwarf.StringType)
220	if !ok {
221		return "", fmt.Errorf("field %s is not a string", fieldName)
222	}
223	return s.peekString(st, addr+uint64(f.ByteOffset), byteLimit)
224}
225
226// peekMapLocationAndType returns the address and DWARF type of the underlying
227// struct of a map variable.
228func (s *Server) peekMapLocationAndType(t *dwarf.MapType, a uint64) (uint64, *dwarf.StructType, error) {
229	// Maps are pointers to structs.
230	pt, ok := t.Type.(*dwarf.PtrType)
231	if !ok {
232		return 0, nil, errors.New("bad map type: not a pointer")
233	}
234	st, ok := pt.Type.(*dwarf.StructType)
235	if !ok {
236		return 0, nil, errors.New("bad map type: not a pointer to a struct")
237	}
238	// a is the address of a pointer to a struct.  Get the pointer's value.
239	a, err := s.peekPtr(a)
240	if err != nil {
241		return 0, nil, fmt.Errorf("reading map pointer: %s", err)
242	}
243	return a, st, nil
244}
245
246// peekMapValues reads a map at the given address and calls fn with the addresses for each (key, value) pair.
247// If fn returns false, peekMapValues stops.
248func (s *Server) peekMapValues(t *dwarf.MapType, a uint64, fn func(keyAddr, valAddr uint64, keyType, valType dwarf.Type) bool) error {
249	a, st, err := s.peekMapLocationAndType(t, a)
250	if err != nil {
251		return err
252	}
253	if a == 0 {
254		// The pointer was nil, so the map is empty.
255		return nil
256	}
257	// Gather information about the struct type and the map bucket type.
258	b, err := s.peekUintStructField(st, a, "B")
259	if err != nil {
260		return fmt.Errorf("reading map: %s", err)
261	}
262	buckets, err := s.peekPtrStructField(st, a, "buckets")
263	if err != nil {
264		return fmt.Errorf("reading map: %s", err)
265	}
266	oldbuckets, err := s.peekPtrStructField(st, a, "oldbuckets")
267	if err != nil {
268		return fmt.Errorf("reading map: %s", err)
269	}
270	bf, err := getField(st, "buckets")
271	if err != nil {
272		return fmt.Errorf("reading map: %s", err)
273	}
274	bucketPtrType, ok := bf.Type.(*dwarf.PtrType)
275	if !ok {
276		return errors.New("bad map bucket type: not a pointer")
277	}
278	bt, ok := bucketPtrType.Type.(*dwarf.StructType)
279	if !ok {
280		return errors.New("bad map bucket type: not a pointer to a struct")
281	}
282	bucketSize := uint64(bucketPtrType.Type.Size())
283	tophashField, err := getField(bt, "tophash")
284	if err != nil {
285		return fmt.Errorf("reading map: %s", err)
286	}
287	bucketCnt := uint64(tophashField.Type.Size())
288	tophashFieldOffset := uint64(tophashField.ByteOffset)
289	keysField, err := getField(bt, "keys")
290	if err != nil {
291		return fmt.Errorf("reading map: %s", err)
292	}
293	keysType, ok := keysField.Type.(*dwarf.ArrayType)
294	if !ok {
295		return errors.New(`bad map bucket type: "keys" is not an array`)
296	}
297	keyType := keysType.Type
298	keysStride := uint64(keysType.StrideBitSize / 8)
299	keysFieldOffset := uint64(keysField.ByteOffset)
300	valuesField, err := getField(bt, "values")
301	if err != nil {
302		return fmt.Errorf("reading map: %s", err)
303	}
304	valuesType, ok := valuesField.Type.(*dwarf.ArrayType)
305	if !ok {
306		return errors.New(`bad map bucket type: "values" is not an array`)
307	}
308	valueType := valuesType.Type
309	valuesStride := uint64(valuesType.StrideBitSize / 8)
310	valuesFieldOffset := uint64(valuesField.ByteOffset)
311	overflowField, err := getField(bt, "overflow")
312	if err != nil {
313		return fmt.Errorf("reading map: %s", err)
314	}
315	overflowFieldOffset := uint64(overflowField.ByteOffset)
316
317	// Iterate through the two arrays of buckets.
318	bucketArrays := [2]struct {
319		addr uint64
320		size uint64
321	}{
322		{buckets, 1 << b},
323		{oldbuckets, 1 << (b - 1)},
324	}
325	for _, bucketArray := range bucketArrays {
326		if bucketArray.addr == 0 {
327			continue
328		}
329		for i := uint64(0); i < bucketArray.size; i++ {
330			bucketAddr := bucketArray.addr + i*bucketSize
331			// Iterate through the linked list of buckets.
332			// TODO: check for repeated bucket pointers.
333			for bucketAddr != 0 {
334				// Iterate through each entry in the bucket.
335				for j := uint64(0); j < bucketCnt; j++ {
336					tophash, err := s.peekUint8(bucketAddr + tophashFieldOffset + j)
337					if err != nil {
338						return errors.New("reading map: " + err.Error())
339					}
340					// From runtime/hashmap.go
341					const minTopHash = 4
342					if tophash < minTopHash {
343						continue
344					}
345					keyAddr := bucketAddr + keysFieldOffset + j*keysStride
346					valAddr := bucketAddr + valuesFieldOffset + j*valuesStride
347					if !fn(keyAddr, valAddr, keyType, valueType) {
348						return nil
349					}
350				}
351				var err error
352				bucketAddr, err = s.peekPtr(bucketAddr + overflowFieldOffset)
353				if err != nil {
354					return errors.New("reading map: " + err.Error())
355				}
356			}
357		}
358	}
359
360	return nil
361}
362
363// peekMapLength returns the number of elements in a map at the given address.
364func (s *Server) peekMapLength(t *dwarf.MapType, a uint64) (uint64, error) {
365	a, st, err := s.peekMapLocationAndType(t, a)
366	if err != nil {
367		return 0, err
368	}
369	if a == 0 {
370		// The pointer was nil, so the map is empty.
371		return 0, nil
372	}
373	length, err := s.peekUintOrIntStructField(st, a, "count")
374	if err != nil {
375		return 0, fmt.Errorf("reading map: %s", err)
376	}
377	return uint64(length), nil
378}
379