blob: 5f58cecd1975d900e2fb7cab3819ae526ccbf75e [file] [log] [blame] [edit]
// Copyright (C) 2016 The Android Open Source Project
//
// 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.
package path
import (
"fmt"
"android.googlesource.com/platform/tools/gpu/framework/binary"
)
// MemoryRange is a path that refers to a range of memory for a specific pool at
// a specific point in the capture.
type MemoryRange struct {
binary.Generate
After *Atom // The path to the atom the memory snapshot immediately follows.
Pool uint64 // The pool identifier.
Address uint64 // The memory base address.
Size uint64 // The size in bytes of this memory range.
}
// String returns the string representation of the path.
func (n *MemoryRange) String() string { return n.Path() }
// Path implements the Path interface.
func (n *MemoryRange) Path() string {
return fmt.Sprintf("%v.MemoryRange<%v>[0x%x:0x%x]",
n.After, n.Pool, n.Address, n.Address+n.Size-1)
}
// Base implements the Path interface, returning the path to the atom list.
func (n *MemoryRange) Base() Path {
return n.After
}
// Clone implements the Path interface, returning a deep-copy of this path.
func (n *MemoryRange) Clone() Path {
return &MemoryRange{
After: n.After.Clone().(*Atom),
Pool: n.Pool,
Address: n.Address,
Size: n.Size,
}
}
// Validate implements the Path interface.
func (n *MemoryRange) Validate() error {
switch {
case n == nil:
return fmt.Errorf("MemoryRange is nil")
case n.After == nil:
return fmt.Errorf("MemoryRange.After is nil")
}
return n.After.Validate()
}
// FindMemoryRange returns the first MemoryRange found traversing the path p.
// If no MemoryRange was found, then nil is returned.
func FindMemoryRange(p Path) *MemoryRange {
for p != nil {
if p, ok := p.(*MemoryRange); ok {
return p
}
p = p.Base()
}
return nil
}
// MemoryType represents the type of data as it is represented in memory
type MemoryType struct {
binary.Generate `java:"MemoryType"` // do not append "Path" suffix
Kind MemoryKind // Non-size and sign dependent description.
ByteSize uint64 // Number of bytes. 0 means variable size.
Signed bool // Presentation as signed number is valid.
To *MemoryType // Description of the destination for Addr
}
func (n *MemoryType) String() string {
if err := n.Validate(); err != nil {
return fmt.Sprintf("MemoryType<invalid:%v>", err)
}
switch n.Kind {
case MemoryKind_Unknown:
return "Unknown" // unknown unknown
case MemoryKind_Void:
return "Void" // known unknown
case MemoryKind_Char:
return "Char"
case MemoryKind_Float:
return fmt.Sprintf("%s(%v)", n.Kind, n.ByteSize)
case MemoryKind_Address:
return fmt.Sprintf("%s(To:%v)", n.Kind, n.To)
case MemoryKind_Integer:
if n.ByteSize == 0 {
return fmt.Sprintf("%s(Signed:%v)", n.Kind, n.Signed)
} else {
return fmt.Sprintf("%s(ByteSize:%v,Signed:%v)", n.Kind, n.ByteSize, n.Signed)
}
default:
return fmt.Sprintf("MemoryType<invalid-kind(%v)>", int(n.Kind))
}
}
func (n *MemoryType) Validate() error {
switch {
case n == nil:
return fmt.Errorf("memory type is nil")
case n.To != nil && n.Kind != MemoryKind_Address:
return fmt.Errorf("memory type To is set for kind %s", n.Kind)
case n.ByteSize != 1 && (n.Kind == MemoryKind_Char || n.Kind == MemoryKind_Void):
return fmt.Errorf("memory type must be 1 (not %d) for kind %s", n.ByteSize, n.Kind)
case n.Kind == MemoryKind_Float && n.ByteSize == 0:
return fmt.Errorf("memory type float can not be variable size")
}
return nil
}
var (
// CharType memory type for Char (there is only one meaningful way supported)
CharType = MemoryType{Kind: MemoryKind_Char, ByteSize: 1}
// VoidType memory type for Void (there is only one meaningful way supported)
VoidType = MemoryType{Kind: MemoryKind_Void, ByteSize: 1}
// UnknownType memory type for Unknown.
UnknownType = MemoryType{Kind: MemoryKind_Unknown}
)
// TypedMemory is a path that refers to a range or single point in memory
// for a specific pool and includes the static type information on how to
// interpret the memory.
type TypedMemory struct {
binary.Generate
Range *MemoryRange // A range of size zero represents a pointer.
Type MemoryType // The type of the memory.
}
// String returns the string representation of the path.
func (n *TypedMemory) String() string { return n.Path() }
// Path implements the Path interface.
func (n *TypedMemory) Path() string {
return fmt.Sprintf("%v:%v", n.Range, &n.Type)
}
// Base implements the Path interface, returning the path to the atom list.
func (n *TypedMemory) Base() Path {
return n.Range.Base()
}
// Clone implements the Path interface, returning a deep-copy of this path.
func (n *TypedMemory) Clone() Path {
return &TypedMemory{
Range: n.Range.Clone().(*MemoryRange),
Type: n.Type,
}
}
// Validate implements the Path interface.
func (n *TypedMemory) Validate() error {
if n == nil {
return fmt.Errorf("TypeMemory is nil")
}
if err := n.Range.Validate(); err != nil {
return err
}
return n.Type.Validate()
}