x/debug: change various peeking functions to be methods of Server instead of Printer so they can be used elsewhere.
Make them return error values instead of a bool that indicates success.
Move these functions to peek.go.
Change-Id: Ifbd198ccd162e49e277c7a3b927abe47d18c6955
Reviewed-on: https://go-review.googlesource.com/11881
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/ogle/program/server/peek.go b/ogle/program/server/peek.go
new file mode 100644
index 0000000..484b3f1
--- /dev/null
+++ b/ogle/program/server/peek.go
@@ -0,0 +1,95 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Functions for reading values of various types from a program's memory.
+
+package server
+
+import (
+ "fmt"
+
+ "golang.org/x/debug/dwarf"
+)
+
+// peekBytes reads len(buf) bytes at addr.
+func (s *Server) peekBytes(addr uint64, buf []byte) error {
+ return s.ptracePeek(s.stoppedPid, uintptr(addr), buf)
+}
+
+// peekPtr reads a pointer at addr.
+func (s *Server) peekPtr(addr uint64) (uint64, error) {
+ buf := make([]byte, s.arch.PointerSize)
+ if err := s.peekBytes(addr, buf); err != nil {
+ return 0, err
+ }
+ return s.arch.Uintptr(buf), nil
+}
+
+// peekUint8 reads a single byte at addr.
+func (s *Server) peekUint8(addr uint64) (byte, error) {
+ buf := make([]byte, 1)
+ if err := s.peekBytes(addr, buf); err != nil {
+ return 0, err
+ }
+ return uint8(s.arch.UintN(buf)), nil
+}
+
+// peekInt reads an int of size n bytes at addr.
+func (s *Server) peekInt(addr uint64, n int64) (int64, error) {
+ buf := make([]byte, n)
+ if err := s.peekBytes(addr, buf); err != nil {
+ return 0, err
+ }
+ return s.arch.IntN(buf), nil
+}
+
+// peekUint reads a uint of size n bytes at addr.
+func (s *Server) peekUint(addr uint64, n int64) (uint64, error) {
+ buf := make([]byte, n)
+ if err := s.peekBytes(addr, buf); err != nil {
+ return 0, err
+ }
+ return s.arch.UintN(buf), nil
+}
+
+// peekPtrStructField reads a pointer in the field fieldName of the struct
+// of type t at addr.
+func (s *Server) peekPtrStructField(t *dwarf.StructType, addr uint64, fieldName string) (uint64, error) {
+ f, err := getField(t, fieldName)
+ if err != nil {
+ return 0, fmt.Errorf("reading field %s: %s", fieldName, err)
+ }
+ if _, ok := f.Type.(*dwarf.PtrType); !ok {
+ return 0, fmt.Errorf("field %s is not a pointer", fieldName)
+ }
+ return s.peekPtr(addr + uint64(f.ByteOffset))
+}
+
+// peekUintStructField reads a uint in the field fieldName of the struct
+// of type t at addr. The size of the uint is determined by the field.
+func (s *Server) peekUintStructField(t *dwarf.StructType, addr uint64, fieldName string) (uint64, error) {
+ f, err := getField(t, fieldName)
+ if err != nil {
+ return 0, fmt.Errorf("reading field %s: %s", fieldName, err)
+ }
+ ut, ok := f.Type.(*dwarf.UintType)
+ if !ok {
+ return 0, fmt.Errorf("field %s is not an unsigned integer", fieldName)
+ }
+ return s.peekUint(addr+uint64(f.ByteOffset), ut.ByteSize)
+}
+
+// peekIntStructField reads an int in the field fieldName of the struct
+// of type t at addr. The size of the int is determined by the field.
+func (s *Server) peekIntStructField(t *dwarf.StructType, addr uint64, fieldName string) (int64, error) {
+ f, err := getField(t, fieldName)
+ if err != nil {
+ return 0, fmt.Errorf("reading field %s: %s", fieldName, err)
+ }
+ it, ok := f.Type.(*dwarf.IntType)
+ if !ok {
+ return 0, fmt.Errorf("field %s is not a signed integer", fieldName)
+ }
+ return s.peekInt(addr+uint64(f.ByteOffset), it.ByteSize)
+}
diff --git a/ogle/program/server/print.go b/ogle/program/server/print.go
index 8c5a838..f78a2cb 100644
--- a/ogle/program/server/print.go
+++ b/ogle/program/server/print.go
@@ -22,16 +22,15 @@
// Routines to print a value using DWARF type descriptions.
// TODO: Does this deserve its own package? It has no dependencies on Server.
-// A Printer pretty-prints a values in the target address space.
+// A Printer pretty-prints values in the target address space.
// It can be reused after each printing operation to avoid unnecessary
// allocations. However, it is not safe for concurrent access.
type Printer struct {
err error // Sticky error value.
- peeker Peeker
+ server *Server
dwarf *dwarf.Data
arch *arch.Architecture
printBuf bytes.Buffer // Accumulates the output.
- tmp []byte // Temporary used for I/O.
visited map[typeAndAddress]bool // Prevents looping on cyclic data.
}
@@ -50,103 +49,14 @@
p.err = fmt.Errorf(format, args...)
}
-// peek reads len bytes at addr, leaving p.tmp with the data and sized appropriately.
-func (p *Printer) peek(addr uint64, length int64) bool {
- p.tmp = p.tmp[:length]
- err := p.peeker.peek(uintptr(addr), p.tmp)
- return err == nil
-}
-
-// peekPtr reads a pointer at addr.
-func (p *Printer) peekPtr(addr uint64) (uint64, bool) {
- if p.peek(addr, int64(p.arch.PointerSize)) {
- return p.arch.Uintptr(p.tmp), true
- }
- return 0, false
-}
-
-// peekUint8 reads a uint8 at addr.
-func (p *Printer) peekUint8(addr uint64) (uint8, bool) {
- if p.peek(addr, 1) {
- return p.tmp[0], true
- }
- return 0, false
-}
-
-// peekInt reads an int of size s at addr.
-func (p *Printer) peekInt(addr uint64, s int64) (int64, bool) {
- if p.peek(addr, s) {
- return p.arch.IntN(p.tmp), true
- }
- return 0, false
-}
-
-// peekUint reads a uint of size s at addr.
-func (p *Printer) peekUint(addr uint64, s int64) (uint64, bool) {
- if p.peek(addr, s) {
- return p.arch.UintN(p.tmp), true
- }
- return 0, false
-}
-
-// peekPtrStructField reads a pointer in the field fieldName of the struct
-// of type t at address addr.
-func (p *Printer) peekPtrStructField(t *dwarf.StructType, addr uint64, fieldName string) (uint64, bool) {
- f, err := getField(t, fieldName)
- if err != nil {
- p.errorf("%s", err)
- return 0, false
- }
- _, ok := f.Type.(*dwarf.PtrType)
- if !ok {
- p.errorf("struct field %s is not a pointer", fieldName)
- return 0, false
- }
- return p.peekPtr(addr + uint64(f.ByteOffset))
-}
-
-// peekUintStructField reads a uint in the field fieldName of the struct
-// of type t at address addr. The size of the uint is determined by the field.
-func (p *Printer) peekUintStructField(t *dwarf.StructType, addr uint64, fieldName string) (uint64, bool) {
- f, err := getField(t, fieldName)
- if err != nil {
- return 0, false
- }
- ut, ok := f.Type.(*dwarf.UintType)
- if !ok {
- return 0, false
- }
- return p.peekUint(addr+uint64(f.ByteOffset), ut.ByteSize)
-}
-
-// peekIntStructField reads an int in the field fieldName of the struct
-// of type t at address addr. The size of the int is determined by the field.
-func (p *Printer) peekIntStructField(t *dwarf.StructType, addr uint64, fieldName string) (int64, bool) {
- f, err := getField(t, fieldName)
- if err != nil {
- return 0, false
- }
- it, ok := f.Type.(*dwarf.IntType)
- if !ok {
- return 0, false
- }
- return p.peekInt(addr+uint64(f.ByteOffset), it.ByteSize)
-}
-
-// Peeker is like a read that probes the remote address space.
-type Peeker interface {
- peek(offset uintptr, buf []byte) error
-}
-
-// NewPrinter returns a printer that can use the Peeker to access and print
+// NewPrinter returns a printer that can use the Server to access and print
// values of the specified architecture described by the provided DWARF data.
-func NewPrinter(arch *arch.Architecture, dwarf *dwarf.Data, peeker Peeker) *Printer {
+func NewPrinter(arch *arch.Architecture, dwarf *dwarf.Data, server *Server) *Printer {
return &Printer{
- peeker: peeker,
+ server: server,
arch: arch,
dwarf: dwarf,
visited: make(map[typeAndAddress]bool),
- tmp: make([]byte, 100), // Enough for a largish string.
}
}
@@ -250,56 +160,58 @@
p.errorf("unrecognized bool size %d", typ.ByteSize)
return
}
- if b, ok := p.peekUint8(a); ok {
- p.printf("%t", b != 0)
+ if b, err := p.server.peekUint8(a); err != nil {
+ p.errorf("reading bool: %s", err)
} else {
- p.errorf("couldn't read bool")
+ p.printf("%t", b != 0)
}
case *dwarf.PtrType:
- if ptr, ok := p.peekPtr(a); ok {
- p.printf("%#x", ptr)
+ if ptr, err := p.server.peekPtr(a); err != nil {
+ p.errorf("reading pointer: %s", err)
} else {
- p.errorf("couldn't read pointer")
+ p.printf("%#x", ptr)
}
case *dwarf.IntType:
// Sad we can't tell a rune from an int32.
- if i, ok := p.peekInt(a, typ.ByteSize); ok {
- p.printf("%d", i)
+ if i, err := p.server.peekInt(a, typ.ByteSize); err != nil {
+ p.errorf("reading integer: %s", err)
} else {
- p.errorf("couldn't read int")
+ p.printf("%d", i)
}
case *dwarf.UintType:
- if u, ok := p.peekUint(a, typ.ByteSize); ok {
- p.printf("%d", u)
+ if u, err := p.server.peekUint(a, typ.ByteSize); err != nil {
+ p.errorf("reading unsigned integer: %s", err)
} else {
- p.errorf("couldn't read uint")
+ p.printf("%d", u)
}
case *dwarf.FloatType:
- if !p.peek(a, typ.ByteSize) {
- p.errorf("couldn't read float")
+ buf := make([]byte, typ.ByteSize)
+ if err := p.server.peekBytes(a, buf); err != nil {
+ p.errorf("reading float: %s", err)
return
}
switch typ.ByteSize {
case 4:
- p.printf("%g", math.Float32frombits(uint32(p.arch.UintN(p.tmp))))
+ p.printf("%g", math.Float32frombits(uint32(p.arch.UintN(buf))))
case 8:
- p.printf("%g", math.Float64frombits(p.arch.UintN(p.tmp)))
+ p.printf("%g", math.Float64frombits(p.arch.UintN(buf)))
default:
p.errorf("unrecognized float size %d", typ.ByteSize)
}
case *dwarf.ComplexType:
- if !p.peek(a, typ.ByteSize) {
- p.errorf("couldn't read complex")
+ buf := make([]byte, typ.ByteSize)
+ if err := p.server.peekBytes(a, buf); err != nil {
+ p.errorf("reading complex: %s", err)
return
}
switch typ.ByteSize {
case 8:
- r := math.Float32frombits(uint32(p.arch.UintN(p.tmp[:4])))
- i := math.Float32frombits(uint32(p.arch.UintN(p.tmp[4:8])))
+ r := math.Float32frombits(uint32(p.arch.UintN(buf[:4])))
+ i := math.Float32frombits(uint32(p.arch.UintN(buf[4:8])))
p.printf("%g", complex(r, i))
case 16:
- r := math.Float64frombits(p.arch.UintN(p.tmp[:8]))
- i := math.Float64frombits(p.arch.UintN(p.tmp[8:16]))
+ r := math.Float64frombits(p.arch.UintN(buf[:8]))
+ i := math.Float64frombits(p.arch.UintN(buf[8:16]))
p.printf("%g", complex(r, i))
default:
p.errorf("unrecognized complex size %d", typ.ByteSize)
@@ -379,21 +291,21 @@
return
}
p.printf("(")
- tab, ok := p.peekPtrStructField(st, a, "tab")
- if ok {
+ tab, err := p.server.peekPtrStructField(st, a, "tab")
+ if err != nil {
+ p.errorf("reading interface type: %s", err)
+ } else {
f, err := getField(st, "tab")
if err != nil {
p.errorf("%s", err)
} else {
p.printTypeOfInterface(f.Type, tab)
}
- } else {
- p.errorf("couldn't read interface type")
}
p.printf(", ")
- data, ok := p.peekPtrStructField(st, a, "data")
- if !ok {
- p.errorf("couldn't read interface value")
+ data, err := p.server.peekPtrStructField(st, a, "data")
+ if err != nil {
+ p.errorf("reading interface value: %s", err)
} else if data == 0 {
p.printf("<nil>")
} else {
@@ -461,14 +373,14 @@
p.errorf("bad type")
return
}
- typeAddr, ok := p.peekPtrStructField(t3, a, "_type")
- if !ok {
- p.errorf("couldn't read type structure pointer")
+ typeAddr, err := p.server.peekPtrStructField(t3, a, "_type")
+ if err != nil {
+ p.errorf("reading interface type: %s", err)
return
}
- stringAddr, ok := p.peekPtrStructField(t6, typeAddr, "_string")
- if !ok {
- p.errorf("couldn't read type name")
+ stringAddr, err := p.server.peekPtrStructField(t6, typeAddr, "_string")
+ if err != nil {
+ p.errorf("reading interface type: %s", err)
return
}
p.printStringAt(stringType, stringAddr)
@@ -490,28 +402,28 @@
p.errorf("bad map type: not a pointer to a struct")
return
}
- a, ok = p.peekPtr(a)
- if !ok {
- p.errorf("couldn't read map pointer")
+ a, err := p.server.peekPtr(a)
+ if err != nil {
+ p.errorf("reading map pointer: %s", err)
return
}
if a == 0 {
p.printf("<nil>")
return
}
- b, ok := p.peekUintStructField(st, a, "B")
- if !ok {
- p.errorf(`couldn't read map field "B"`)
+ b, err := p.server.peekUintStructField(st, a, "B")
+ if err != nil {
+ p.errorf("reading map: %s", err)
return
}
- buckets, ok := p.peekPtrStructField(st, a, "buckets")
- if !ok {
- p.errorf(`couldn't read map field "buckets"`)
+ buckets, err := p.server.peekPtrStructField(st, a, "buckets")
+ if err != nil {
+ p.errorf("reading map: %s", err)
return
}
- oldbuckets, ok := p.peekPtrStructField(st, a, "oldbuckets")
- if !ok {
- p.errorf(`couldn't read map field "oldbuckets"`)
+ oldbuckets, err := p.server.peekPtrStructField(st, a, "oldbuckets")
+ if err != nil {
+ p.errorf("reading map: %s", err)
return
}
@@ -608,9 +520,9 @@
// TODO: check for repeated bucket pointers.
for bucketAddr != 0 {
for j := uint64(0); j < bucketCnt; j++ {
- tophash, ok := p.peekUint8(bucketAddr + uint64(tophashField.ByteOffset) + j)
- if !ok {
- p.errorf("couldn't read map")
+ tophash, err := p.server.peekUint8(bucketAddr + uint64(tophashField.ByteOffset) + j)
+ if err != nil {
+ p.errorf("reading map: ", err)
return
}
if tophash < minTopHash {
@@ -634,10 +546,9 @@
bucketAddr+uint64(valuesField.ByteOffset)+j*valuesStride)
}
- var ok bool
- bucketAddr, ok = p.peekPtrStructField(bt, bucketAddr, "overflow")
- if !ok {
- p.errorf("couldn't read map")
+ bucketAddr, err = p.server.peekPtrStructField(bt, bucketAddr, "overflow")
+ if err != nil {
+ p.errorf("reading map: ", err)
return
}
}
@@ -648,9 +559,9 @@
p.printf("(chan %s ", ct.ElemType)
defer p.printf(")")
- a, ok := p.peekPtr(a)
- if !ok {
- p.errorf("couldn't read channel")
+ a, err := p.server.peekPtr(a)
+ if err != nil {
+ p.errorf("reading channel: %s", err)
return
}
if a == 0 {
@@ -673,14 +584,14 @@
// Print the channel buffer's length (qcount) and capacity (dataqsiz),
// if not 0/0.
- qcount, ok := p.peekUintStructField(st, a, "qcount")
- if !ok {
- p.errorf(`couldn't read channel field "qcount"`)
+ qcount, err := p.server.peekUintStructField(st, a, "qcount")
+ if err != nil {
+ p.errorf("reading channel: %s", err)
return
}
- dataqsiz, ok := p.peekUintStructField(st, a, "dataqsiz")
- if !ok {
- p.errorf(`couldn't read channel field "dataqsiz"`)
+ dataqsiz, err := p.server.peekUintStructField(st, a, "dataqsiz")
+ if err != nil {
+ p.errorf("reading channel: %s", err)
return
}
if qcount != 0 || dataqsiz != 0 {
@@ -691,21 +602,29 @@
func (p *Printer) printSliceAt(typ *dwarf.SliceType, a uint64) {
// Slices look like a struct with fields array *elemtype, len uint32/64, cap uint32/64.
// BUG: Slice header appears to have fields with ByteSize == 0
- ptr, ok1 := p.peekPtrStructField(&typ.StructType, a, "array")
- length, ok2 := p.peekIntStructField(&typ.StructType, a, "len")
- if !ok2 {
+ ptr, err := p.server.peekPtrStructField(&typ.StructType, a, "array")
+ if err != nil {
+ p.errorf("reading slice: %s", err)
+ return
+ }
+ length, err := p.server.peekIntStructField(&typ.StructType, a, "len")
+ if err != nil {
var u uint64
- u, ok2 = p.peekUintStructField(&typ.StructType, a, "len")
+ u, err = p.server.peekUintStructField(&typ.StructType, a, "len")
+ if err != nil {
+ p.errorf("reading slice: %s", err)
+ return
+ }
length = int64(u)
}
// Capacity is not used yet.
- _, ok3 := p.peekIntStructField(&typ.StructType, a, "cap")
- if !ok3 {
- _, ok3 = p.peekUintStructField(&typ.StructType, a, "cap")
- }
- if !ok1 || !ok2 || !ok3 {
- p.errorf("couldn't read slice")
- return
+ _, err = p.server.peekIntStructField(&typ.StructType, a, "cap")
+ if err != nil {
+ _, err = p.server.peekUintStructField(&typ.StructType, a, "cap")
+ if err != nil {
+ p.errorf("reading slice: %s", err)
+ return
+ }
}
elemType := typ.ElemType
size, ok := p.sizeof(typ.ElemType)
@@ -725,29 +644,30 @@
func (p *Printer) printStringAt(typ *dwarf.StringType, a uint64) {
// BUG: String header appears to have fields with ByteSize == 0
- ptr, ok := p.peekPtrStructField(&typ.StructType, a, "str")
- if !ok {
- p.errorf("couldn't read string")
+ ptr, err := p.server.peekPtrStructField(&typ.StructType, a, "str")
+ if err != nil {
+ p.errorf("reading string: %s", err)
return
}
- length, ok := p.peekIntStructField(&typ.StructType, a, "len")
- if !ok {
- p.errorf("couldn't read string")
+ length, err := p.server.peekIntStructField(&typ.StructType, a, "len")
+ if err != nil {
+ p.errorf("reading string: %s", err)
return
}
- if length > int64(cap(p.tmp)) {
- if p.peek(ptr, int64(cap(p.tmp))) {
- p.printf("%q...", p.tmp)
+ const maxStringSize = 100
+ if length > maxStringSize {
+ buf := make([]byte, maxStringSize)
+ if err := p.server.peekBytes(ptr, buf); err != nil {
+ p.errorf("reading string: %s", err)
} else {
- p.errorf("couldn't read string")
- return
+ p.printf("%q...", string(buf))
}
} else {
- if p.peek(ptr, int64(length)) {
- p.printf("%q", p.tmp[:length])
+ buf := make([]byte, length)
+ if err := p.server.peekBytes(ptr, buf); err != nil {
+ p.errorf("reading string: %s", err)
} else {
- p.errorf("couldn't read string")
- return
+ p.printf("%q", string(buf))
}
}
}