mirror of
https://github.com/go-delve/delve.git
synced 2025-10-28 04:35:19 +08:00
A significant amount of time is spent generating the string representation for the proc.Registers object of each thread, since this field is rarely used (only when the Registers API is called) it should be generated on demand. Also by changing the internal representation of proc.Register to be closer to that of op.DwarfRegister it will help us implement #1838 (when Delve will need to be able to display the registers of an internal frame, which we currently represent using op.DwarfRegister objects). Benchmark before: BenchmarkConditionalBreakpoints-4 1 22292554301 ns/op Benchmark after: BenchmarkConditionalBreakpoints-4 1 17326345671 ns/op Reduces conditional breakpoint latency from 2.2ms to 1.7ms. Updates #1549, #1838
124 lines
2.8 KiB
Go
124 lines
2.8 KiB
Go
package proc
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"math"
|
|
"strings"
|
|
|
|
"github.com/go-delve/delve/pkg/dwarf/op"
|
|
)
|
|
|
|
// Registers is an interface for a generic register type. The
|
|
// interface encapsulates the generic values / actions
|
|
// we need independent of arch. The concrete register types
|
|
// will be different depending on OS/Arch.
|
|
type Registers interface {
|
|
PC() uint64
|
|
SP() uint64
|
|
BP() uint64
|
|
TLS() uint64
|
|
// GAddr returns the address of the G variable if it is known, 0 and false otherwise
|
|
GAddr() (uint64, bool)
|
|
Get(int) (uint64, error)
|
|
Slice(floatingPoint bool) []Register
|
|
// Copy returns a copy of the registers that is guaranteed not to change
|
|
// when the registers of the associated thread change.
|
|
Copy() Registers
|
|
}
|
|
|
|
// Register represents a CPU register.
|
|
type Register struct {
|
|
Name string
|
|
Reg *op.DwarfRegister
|
|
}
|
|
|
|
func AppendUint64Register(regs []Register, name string, value uint64) []Register {
|
|
return append(regs, Register{name, op.DwarfRegisterFromUint64(value)})
|
|
}
|
|
|
|
func AppendBytesRegister(regs []Register, name string, value []byte) []Register {
|
|
return append(regs, Register{name, op.DwarfRegisterFromBytes(value)})
|
|
}
|
|
|
|
// ErrUnknownRegister is returned when the value of an unknown
|
|
// register is requested.
|
|
var ErrUnknownRegister = errors.New("unknown register")
|
|
|
|
type flagRegisterDescr []flagDescr
|
|
type flagDescr struct {
|
|
name string
|
|
mask uint64
|
|
}
|
|
|
|
var mxcsrDescription flagRegisterDescr = []flagDescr{
|
|
{"FZ", 1 << 15},
|
|
{"RZ/RN", 1<<14 | 1<<13},
|
|
{"PM", 1 << 12},
|
|
{"UM", 1 << 11},
|
|
{"OM", 1 << 10},
|
|
{"ZM", 1 << 9},
|
|
{"DM", 1 << 8},
|
|
{"IM", 1 << 7},
|
|
{"DAZ", 1 << 6},
|
|
{"PE", 1 << 5},
|
|
{"UE", 1 << 4},
|
|
{"OE", 1 << 3},
|
|
{"ZE", 1 << 2},
|
|
{"DE", 1 << 1},
|
|
{"IE", 1 << 0},
|
|
}
|
|
|
|
var eflagsDescription flagRegisterDescr = []flagDescr{
|
|
{"CF", 1 << 0},
|
|
{"", 1 << 1},
|
|
{"PF", 1 << 2},
|
|
{"AF", 1 << 4},
|
|
{"ZF", 1 << 6},
|
|
{"SF", 1 << 7},
|
|
{"TF", 1 << 8},
|
|
{"IF", 1 << 9},
|
|
{"DF", 1 << 10},
|
|
{"OF", 1 << 11},
|
|
{"IOPL", 1<<12 | 1<<13},
|
|
{"NT", 1 << 14},
|
|
{"RF", 1 << 16},
|
|
{"VM", 1 << 17},
|
|
{"AC", 1 << 18},
|
|
{"VIF", 1 << 19},
|
|
{"VIP", 1 << 20},
|
|
{"ID", 1 << 21},
|
|
}
|
|
|
|
func (descr flagRegisterDescr) Mask() uint64 {
|
|
var r uint64
|
|
for _, f := range descr {
|
|
r = r | f.mask
|
|
}
|
|
return r
|
|
}
|
|
|
|
func (descr flagRegisterDescr) Describe(reg uint64, bitsize int) string {
|
|
var r []string
|
|
for _, f := range descr {
|
|
if f.name == "" {
|
|
continue
|
|
}
|
|
// rbm is f.mask with only the right-most bit set:
|
|
// 0001 1100 -> 0000 0100
|
|
rbm := f.mask & -f.mask
|
|
if rbm == f.mask {
|
|
if reg&f.mask != 0 {
|
|
r = append(r, f.name)
|
|
}
|
|
} else {
|
|
x := (reg & f.mask) >> uint64(math.Log2(float64(rbm)))
|
|
r = append(r, fmt.Sprintf("%s=%x", f.name, x))
|
|
}
|
|
}
|
|
if reg & ^descr.Mask() != 0 {
|
|
r = append(r, fmt.Sprintf("unknown_flags=%x", reg&^descr.Mask()))
|
|
}
|
|
return fmt.Sprintf("%#0*x\t[%s]", bitsize/4, reg, strings.Join(r, " "))
|
|
}
|