// FillValue copies a value into a cd.Variable. Any variables referred to by // that value, e.g. struct members and pointer targets, are added to the // collector's queue, to be fetched later by ReadValues. func (c *Collector) FillValue(v debug.Value, dcv *cd.Variable) { if c, ok := v.(debug.Channel); ok { // Convert to channel, which implements indexable. v = channel{c} } // Fill in dcv in a manner depending on the type of the value we got. switch val := v.(type) { case int8, int16, int32, int64, bool, uint8, uint16, uint32, uint64, float32, float64, complex64, complex128: // For simple types, we just print the value to dcv.Value. dcv.Value = fmt.Sprint(val) case string: // Put double quotes around strings. dcv.Value = strconv.Quote(val) case debug.String: if uint64(len(val.String)) < val.Length { // This string value was truncated. dcv.Value = strconv.Quote(val.String + "...") } else { dcv.Value = strconv.Quote(val.String) } case debug.Struct: // For structs, we add an entry to dcv.Members for each field in the // struct. // Each member will contain the name of the field, and the index in the // output table which will contain the value of that field. for _, f := range val.Fields { member := addMember(dcv, f.Name) if index, ok := c.add(f.Var); !ok { // The table is full. member.Status = statusMessage(messageNotCaptured, true, refersToVariableName) } else { member.VarTableIndex = int64(index) } } case debug.Map: dcv.Value = fmt.Sprintf("len = %d", val.Length) for i := uint64(0); i < val.Length; i++ { field := addMember(dcv, `⚫`) if i == maxMapLength { field.Name = "..." field.Status = statusMessage(messageTruncated, true, refersToVariableName) break } if index, ok := c.add(mapElement{val, i}); !ok { // The value table is full; add a member to contain the error message. field.Name = "..." field.Status = statusMessage(messageNotCaptured, true, refersToVariableName) break } else { field.VarTableIndex = int64(index) } } case debug.Pointer: if val.Address == 0 { dcv.Value = "<nil>" } else if val.TypeID == 0 { // We don't know the type of the pointer, so just output the address as // the value. dcv.Value = fmt.Sprintf("0x%X", val.Address) dcv.Status = statusMessage(messageUnknownPointerType, false, refersToVariableName) } else { // Adds the pointed-to variable to the table, and links this value to // that table entry through VarTableIndex. dcv.Value = fmt.Sprintf("0x%X", val.Address) target := addMember(dcv, "") if index, ok := c.add(debug.Var(val)); !ok { target.Status = statusMessage(messageNotCaptured, true, refersToVariableName) } else { target.VarTableIndex = int64(index) } } case indexable: // Arrays, slices and channels. dcv.Value = "len = " + fmt.Sprint(val.Len()) for j := uint64(0); j < val.Len(); j++ { field := addMember(dcv, fmt.Sprint(`[`, j, `]`)) if j == maxArrayLength { field.Name = "..." field.Status = statusMessage(messageTruncated, true, refersToVariableName) break } vr := val.Element(j) if index, ok := c.add(vr); !ok { // The value table is full; add a member to contain the error message. field.Name = "..." field.Status = statusMessage(messageNotCaptured, true, refersToVariableName) break } else { // Add a member with the index as the name. field.VarTableIndex = int64(index) } } default: dcv.Status = statusMessage(messageUnknownType, false, refersToVariableName) } }