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