| // 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() |
| } |