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