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// +build linux
16
17package server
18
19import (
20	"fmt"
21
22	"cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug"
23	"cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf"
24)
25
26// value peeks the program's memory at the given address, parsing it as a value of type t.
27func (s *Server) value(t dwarf.Type, addr uint64) (debug.Value, error) {
28	// readBasic reads the memory for a basic type of size n bytes.
29	readBasic := func(n int64) ([]byte, error) {
30		switch n {
31		case 1, 2, 4, 8, 16:
32		default:
33			return nil, fmt.Errorf("invalid size: %d", n)
34		}
35		buf := make([]byte, n)
36		if err := s.peek(uintptr(addr), buf); err != nil {
37			return nil, err
38		}
39		return buf, nil
40	}
41
42	switch t := t.(type) {
43	case *dwarf.CharType, *dwarf.IntType:
44		bs := t.Common().ByteSize
45		buf, err := readBasic(bs)
46		if err != nil {
47			return nil, fmt.Errorf("reading integer: %s", err)
48		}
49		x := s.arch.IntN(buf)
50		switch bs {
51		case 1:
52			return int8(x), nil
53		case 2:
54			return int16(x), nil
55		case 4:
56			return int32(x), nil
57		case 8:
58			return int64(x), nil
59		default:
60			return nil, fmt.Errorf("invalid integer size: %d", bs)
61		}
62	case *dwarf.UcharType, *dwarf.UintType, *dwarf.AddrType:
63		bs := t.Common().ByteSize
64		buf, err := readBasic(bs)
65		if err != nil {
66			return nil, fmt.Errorf("reading unsigned integer: %s", err)
67		}
68		x := s.arch.UintN(buf)
69		switch bs {
70		case 1:
71			return uint8(x), nil
72		case 2:
73			return uint16(x), nil
74		case 4:
75			return uint32(x), nil
76		case 8:
77			return uint64(x), nil
78		default:
79			return nil, fmt.Errorf("invalid unsigned integer size: %d", bs)
80		}
81	case *dwarf.BoolType:
82		bs := t.Common().ByteSize
83		buf, err := readBasic(bs)
84		if err != nil {
85			return nil, fmt.Errorf("reading boolean: %s", err)
86		}
87		for _, b := range buf {
88			if b != 0 {
89				return true, nil
90			}
91		}
92		return false, nil
93	case *dwarf.FloatType:
94		bs := t.Common().ByteSize
95		buf, err := readBasic(bs)
96		if err != nil {
97			return nil, fmt.Errorf("reading float: %s", err)
98		}
99		switch bs {
100		case 4:
101			return s.arch.Float32(buf), nil
102		case 8:
103			return s.arch.Float64(buf), nil
104		default:
105			return nil, fmt.Errorf("invalid float size: %d", bs)
106		}
107	case *dwarf.ComplexType:
108		bs := t.Common().ByteSize
109		buf, err := readBasic(bs)
110		if err != nil {
111			return nil, fmt.Errorf("reading complex: %s", err)
112		}
113		switch bs {
114		case 8:
115			return s.arch.Complex64(buf), nil
116		case 16:
117			return s.arch.Complex128(buf), nil
118		default:
119			return nil, fmt.Errorf("invalid complex size: %d", bs)
120		}
121	case *dwarf.PtrType:
122		bs := t.Common().ByteSize
123		if bs != int64(s.arch.PointerSize) {
124			return nil, fmt.Errorf("invalid pointer size: %d", bs)
125		}
126		buf, err := readBasic(bs)
127		if err != nil {
128			return nil, fmt.Errorf("reading pointer: %s", err)
129		}
130		return debug.Pointer{
131			TypeID:  uint64(t.Type.Common().Offset),
132			Address: uint64(s.arch.Uintptr(buf)),
133		}, nil
134	case *dwarf.SliceType:
135		if s, err := s.peekSlice(t, addr); err != nil {
136			return nil, err
137		} else {
138			return s, nil
139		}
140	case *dwarf.ArrayType:
141		length := t.Count
142		stride := t.StrideBitSize
143		if stride%8 != 0 {
144			return nil, fmt.Errorf("array is not byte-aligned")
145		}
146		return debug.Array{
147			ElementTypeID: uint64(t.Type.Common().Offset),
148			Address:       uint64(addr),
149			Length:        uint64(length),
150			StrideBits:    uint64(stride),
151		}, nil
152	case *dwarf.StructType:
153		fields := make([]debug.StructField, len(t.Field))
154		for i, field := range t.Field {
155			fields[i] = debug.StructField{
156				Name: field.Name,
157				Var: debug.Var{
158					TypeID:  uint64(field.Type.Common().Offset),
159					Address: uint64(addr) + uint64(field.ByteOffset),
160				},
161			}
162		}
163		return debug.Struct{fields}, nil
164	case *dwarf.TypedefType:
165		return s.value(t.Type, addr)
166	case *dwarf.MapType:
167		length, err := s.peekMapLength(t, addr)
168		if err != nil {
169			return nil, err
170		}
171		return debug.Map{
172			TypeID:  uint64(t.Common().Offset),
173			Address: addr,
174			Length:  length,
175		}, nil
176	case *dwarf.StringType:
177		ptr, err := s.peekPtrStructField(&t.StructType, addr, "str")
178		if err != nil {
179			return nil, fmt.Errorf("reading string location: %s", err)
180		}
181		length, err := s.peekUintOrIntStructField(&t.StructType, addr, "len")
182		if err != nil {
183			return nil, fmt.Errorf("reading string length: %s", err)
184		}
185
186		const maxStringSize = 256
187
188		n := length
189		if n > maxStringSize {
190			n = maxStringSize
191		}
192		tmp := make([]byte, n)
193		if err := s.peekBytes(ptr, tmp); err != nil {
194			return nil, fmt.Errorf("reading string contents: %s", err)
195		}
196		return debug.String{Length: length, String: string(tmp)}, nil
197	case *dwarf.ChanType:
198		pt, ok := t.TypedefType.Type.(*dwarf.PtrType)
199		if !ok {
200			return nil, fmt.Errorf("reading channel: type is not a pointer")
201		}
202		st, ok := pt.Type.(*dwarf.StructType)
203		if !ok {
204			return nil, fmt.Errorf("reading channel: type is not a pointer to struct")
205		}
206
207		a, err := s.peekPtr(addr)
208		if err != nil {
209			return nil, fmt.Errorf("reading channel pointer: %s", err)
210		}
211		if a == 0 {
212			// This channel is nil.
213			return debug.Channel{
214				ElementTypeID: uint64(t.ElemType.Common().Offset),
215				Address:       0,
216				Buffer:        0,
217				Length:        0,
218				Capacity:      0,
219				Stride:        uint64(t.ElemType.Common().ByteSize),
220				BufferStart:   0,
221			}, nil
222		}
223
224		buf, err := s.peekPtrStructField(st, a, "buf")
225		if err != nil {
226			return nil, fmt.Errorf("reading channel buffer location: %s", err)
227		}
228		qcount, err := s.peekUintOrIntStructField(st, a, "qcount")
229		if err != nil {
230			return nil, fmt.Errorf("reading channel length: %s", err)
231		}
232		capacity, err := s.peekUintOrIntStructField(st, a, "dataqsiz")
233		if err != nil {
234			return nil, fmt.Errorf("reading channel capacity: %s", err)
235		}
236		recvx, err := s.peekUintOrIntStructField(st, a, "recvx")
237		if err != nil {
238			return nil, fmt.Errorf("reading channel buffer index: %s", err)
239		}
240		return debug.Channel{
241			ElementTypeID: uint64(t.ElemType.Common().Offset),
242			Address:       a,
243			Buffer:        buf,
244			Length:        qcount,
245			Capacity:      capacity,
246			Stride:        uint64(t.ElemType.Common().ByteSize),
247			BufferStart:   recvx,
248		}, nil
249	case *dwarf.FuncType:
250		a, err := s.peekPtr(addr)
251		if err != nil {
252			return nil, fmt.Errorf("reading func: %s", err)
253		}
254		return debug.Func{Address: a}, nil
255	case *dwarf.InterfaceType:
256		return debug.Interface{}, nil
257		// TODO: more types
258	}
259	return nil, fmt.Errorf("Unsupported type %T", t)
260}
261