|
- // Copyright 2018 Google Inc. All Rights Reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
-
- // +build linux
-
- package server
-
- import (
- "fmt"
-
- "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug"
- "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf"
- )
-
- // value peeks the program's memory at the given address, parsing it as a value of type t.
- func (s *Server) value(t dwarf.Type, addr uint64) (debug.Value, error) {
- // readBasic reads the memory for a basic type of size n bytes.
- readBasic := func(n int64) ([]byte, error) {
- switch n {
- case 1, 2, 4, 8, 16:
- default:
- return nil, fmt.Errorf("invalid size: %d", n)
- }
- buf := make([]byte, n)
- if err := s.peek(uintptr(addr), buf); err != nil {
- return nil, err
- }
- return buf, nil
- }
-
- switch t := t.(type) {
- case *dwarf.CharType, *dwarf.IntType:
- bs := t.Common().ByteSize
- buf, err := readBasic(bs)
- if err != nil {
- return nil, fmt.Errorf("reading integer: %s", err)
- }
- x := s.arch.IntN(buf)
- switch bs {
- case 1:
- return int8(x), nil
- case 2:
- return int16(x), nil
- case 4:
- return int32(x), nil
- case 8:
- return int64(x), nil
- default:
- return nil, fmt.Errorf("invalid integer size: %d", bs)
- }
- case *dwarf.UcharType, *dwarf.UintType, *dwarf.AddrType:
- bs := t.Common().ByteSize
- buf, err := readBasic(bs)
- if err != nil {
- return nil, fmt.Errorf("reading unsigned integer: %s", err)
- }
- x := s.arch.UintN(buf)
- switch bs {
- case 1:
- return uint8(x), nil
- case 2:
- return uint16(x), nil
- case 4:
- return uint32(x), nil
- case 8:
- return uint64(x), nil
- default:
- return nil, fmt.Errorf("invalid unsigned integer size: %d", bs)
- }
- case *dwarf.BoolType:
- bs := t.Common().ByteSize
- buf, err := readBasic(bs)
- if err != nil {
- return nil, fmt.Errorf("reading boolean: %s", err)
- }
- for _, b := range buf {
- if b != 0 {
- return true, nil
- }
- }
- return false, nil
- case *dwarf.FloatType:
- bs := t.Common().ByteSize
- buf, err := readBasic(bs)
- if err != nil {
- return nil, fmt.Errorf("reading float: %s", err)
- }
- switch bs {
- case 4:
- return s.arch.Float32(buf), nil
- case 8:
- return s.arch.Float64(buf), nil
- default:
- return nil, fmt.Errorf("invalid float size: %d", bs)
- }
- case *dwarf.ComplexType:
- bs := t.Common().ByteSize
- buf, err := readBasic(bs)
- if err != nil {
- return nil, fmt.Errorf("reading complex: %s", err)
- }
- switch bs {
- case 8:
- return s.arch.Complex64(buf), nil
- case 16:
- return s.arch.Complex128(buf), nil
- default:
- return nil, fmt.Errorf("invalid complex size: %d", bs)
- }
- case *dwarf.PtrType:
- bs := t.Common().ByteSize
- if bs != int64(s.arch.PointerSize) {
- return nil, fmt.Errorf("invalid pointer size: %d", bs)
- }
- buf, err := readBasic(bs)
- if err != nil {
- return nil, fmt.Errorf("reading pointer: %s", err)
- }
- return debug.Pointer{
- TypeID: uint64(t.Type.Common().Offset),
- Address: uint64(s.arch.Uintptr(buf)),
- }, nil
- case *dwarf.SliceType:
- if s, err := s.peekSlice(t, addr); err != nil {
- return nil, err
- } else {
- return s, nil
- }
- case *dwarf.ArrayType:
- length := t.Count
- stride := t.StrideBitSize
- if stride%8 != 0 {
- return nil, fmt.Errorf("array is not byte-aligned")
- }
- return debug.Array{
- ElementTypeID: uint64(t.Type.Common().Offset),
- Address: uint64(addr),
- Length: uint64(length),
- StrideBits: uint64(stride),
- }, nil
- case *dwarf.StructType:
- fields := make([]debug.StructField, len(t.Field))
- for i, field := range t.Field {
- fields[i] = debug.StructField{
- Name: field.Name,
- Var: debug.Var{
- TypeID: uint64(field.Type.Common().Offset),
- Address: uint64(addr) + uint64(field.ByteOffset),
- },
- }
- }
- return debug.Struct{fields}, nil
- case *dwarf.TypedefType:
- return s.value(t.Type, addr)
- case *dwarf.MapType:
- length, err := s.peekMapLength(t, addr)
- if err != nil {
- return nil, err
- }
- return debug.Map{
- TypeID: uint64(t.Common().Offset),
- Address: addr,
- Length: length,
- }, nil
- case *dwarf.StringType:
- ptr, err := s.peekPtrStructField(&t.StructType, addr, "str")
- if err != nil {
- return nil, fmt.Errorf("reading string location: %s", err)
- }
- length, err := s.peekUintOrIntStructField(&t.StructType, addr, "len")
- if err != nil {
- return nil, fmt.Errorf("reading string length: %s", err)
- }
-
- const maxStringSize = 256
-
- n := length
- if n > maxStringSize {
- n = maxStringSize
- }
- tmp := make([]byte, n)
- if err := s.peekBytes(ptr, tmp); err != nil {
- return nil, fmt.Errorf("reading string contents: %s", err)
- }
- return debug.String{Length: length, String: string(tmp)}, nil
- case *dwarf.ChanType:
- pt, ok := t.TypedefType.Type.(*dwarf.PtrType)
- if !ok {
- return nil, fmt.Errorf("reading channel: type is not a pointer")
- }
- st, ok := pt.Type.(*dwarf.StructType)
- if !ok {
- return nil, fmt.Errorf("reading channel: type is not a pointer to struct")
- }
-
- a, err := s.peekPtr(addr)
- if err != nil {
- return nil, fmt.Errorf("reading channel pointer: %s", err)
- }
- if a == 0 {
- // This channel is nil.
- return debug.Channel{
- ElementTypeID: uint64(t.ElemType.Common().Offset),
- Address: 0,
- Buffer: 0,
- Length: 0,
- Capacity: 0,
- Stride: uint64(t.ElemType.Common().ByteSize),
- BufferStart: 0,
- }, nil
- }
-
- buf, err := s.peekPtrStructField(st, a, "buf")
- if err != nil {
- return nil, fmt.Errorf("reading channel buffer location: %s", err)
- }
- qcount, err := s.peekUintOrIntStructField(st, a, "qcount")
- if err != nil {
- return nil, fmt.Errorf("reading channel length: %s", err)
- }
- capacity, err := s.peekUintOrIntStructField(st, a, "dataqsiz")
- if err != nil {
- return nil, fmt.Errorf("reading channel capacity: %s", err)
- }
- recvx, err := s.peekUintOrIntStructField(st, a, "recvx")
- if err != nil {
- return nil, fmt.Errorf("reading channel buffer index: %s", err)
- }
- return debug.Channel{
- ElementTypeID: uint64(t.ElemType.Common().Offset),
- Address: a,
- Buffer: buf,
- Length: qcount,
- Capacity: capacity,
- Stride: uint64(t.ElemType.Common().ByteSize),
- BufferStart: recvx,
- }, nil
- case *dwarf.FuncType:
- a, err := s.peekPtr(addr)
- if err != nil {
- return nil, fmt.Errorf("reading func: %s", err)
- }
- return debug.Func{Address: a}, nil
- case *dwarf.InterfaceType:
- return debug.Interface{}, nil
- // TODO: more types
- }
- return nil, fmt.Errorf("Unsupported type %T", t)
- }
|