proc,service: allow printing registers for arbitrary frames (#1875)
Adds an optional scope prefix to the `regs` command which allows printing registers for any stack frame (as long as they were somehow saved). Issue #1838 is not yet to be closed since we are still not recovering the registers of a segfaulting frame. Updates #1838
This commit is contained in:
parent
186786235f
commit
d925f6b719
@ -45,7 +45,7 @@ goroutines(Start, Count) | Equivalent to API call [ListGoroutines](https://godoc
|
||||
local_vars(Scope, Cfg) | Equivalent to API call [ListLocalVars](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.ListLocalVars)
|
||||
package_vars(Filter, Cfg) | Equivalent to API call [ListPackageVars](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.ListPackageVars)
|
||||
packages_build_info(IncludeFiles) | Equivalent to API call [ListPackagesBuildInfo](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.ListPackagesBuildInfo)
|
||||
registers(ThreadID, IncludeFp) | Equivalent to API call [ListRegisters](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.ListRegisters)
|
||||
registers(ThreadID, IncludeFp, Scope) | Equivalent to API call [ListRegisters](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.ListRegisters)
|
||||
sources(Filter) | Equivalent to API call [ListSources](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.ListSources)
|
||||
threads() | Equivalent to API call [ListThreads](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.ListThreads)
|
||||
types(Filter) | Equivalent to API call [ListTypes](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.ListTypes)
|
||||
|
@ -426,30 +426,34 @@ func (a *AMD64) AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AMD64) DwarfRegisterToString(name string, reg *op.DwarfRegister) string {
|
||||
name = strings.ToLower(name)
|
||||
switch name {
|
||||
func (a *AMD64) DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {
|
||||
name, ok := amd64DwarfToName[i]
|
||||
if !ok {
|
||||
name = fmt.Sprintf("unknown%d", i)
|
||||
}
|
||||
|
||||
switch n := strings.ToLower(name); n {
|
||||
case "rflags":
|
||||
return eflagsDescription.Describe(reg.Uint64Val, 64)
|
||||
return name, false, eflagsDescription.Describe(reg.Uint64Val, 64)
|
||||
|
||||
case "cw", "sw", "tw", "fop":
|
||||
return fmt.Sprintf("%#04x", reg.Uint64Val)
|
||||
return name, true, fmt.Sprintf("%#04x", reg.Uint64Val)
|
||||
|
||||
case "mxcsr_mask":
|
||||
return fmt.Sprintf("%#08x", reg.Uint64Val)
|
||||
return name, true, fmt.Sprintf("%#08x", reg.Uint64Val)
|
||||
|
||||
case "mxcsr":
|
||||
return mxcsrDescription.Describe(reg.Uint64Val, 32)
|
||||
return name, true, mxcsrDescription.Describe(reg.Uint64Val, 32)
|
||||
|
||||
default:
|
||||
if reg.Bytes != nil && strings.HasPrefix(name, "xmm") {
|
||||
return formatSSEReg(reg.Bytes)
|
||||
} else if reg.Bytes != nil && strings.HasPrefix(name, "st(") {
|
||||
return formatX87Reg(reg.Bytes)
|
||||
if reg.Bytes != nil && strings.HasPrefix(n, "xmm") {
|
||||
return name, true, formatSSEReg(reg.Bytes)
|
||||
} else if reg.Bytes != nil && strings.HasPrefix(n, "st(") {
|
||||
return name, true, formatX87Reg(reg.Bytes)
|
||||
} else if reg.Bytes == nil || (reg.Bytes != nil && len(reg.Bytes) <= 8) {
|
||||
return fmt.Sprintf("%#016x", reg.Uint64Val)
|
||||
return name, false, fmt.Sprintf("%#016x", reg.Uint64Val)
|
||||
} else {
|
||||
return fmt.Sprintf("%#x", reg.Bytes)
|
||||
return name, false, fmt.Sprintf("%#x", reg.Bytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ type Arch interface {
|
||||
RegSize(uint64) int
|
||||
RegistersToDwarfRegisters(uint64, Registers) op.DwarfRegisters
|
||||
AddrAndStackRegsToDwarfRegisters(uint64, uint64, uint64, uint64, uint64) op.DwarfRegisters
|
||||
DwarfRegisterToString(string, *op.DwarfRegister) string
|
||||
DwarfRegisterToString(int, *op.DwarfRegister) (string, bool, string)
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -411,8 +411,22 @@ func (a *ARM64) AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint
|
||||
}
|
||||
}
|
||||
|
||||
func (a *ARM64) DwarfRegisterToString(name string, reg *op.DwarfRegister) string {
|
||||
if reg.Bytes != nil && (name[0] == 'v' || name[0] == 'V') {
|
||||
func (a *ARM64) DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {
|
||||
// see arm64DwarfToHardware table for explanation
|
||||
switch {
|
||||
case i <= 30:
|
||||
name = fmt.Sprintf("X%d", i)
|
||||
case i == 31:
|
||||
name = "SP"
|
||||
case i == 32:
|
||||
name = "PC"
|
||||
case i >= 64 && i <= 95:
|
||||
name = fmt.Sprintf("V%d", i-64)
|
||||
default:
|
||||
name = fmt.Sprintf("unknown%d", i)
|
||||
}
|
||||
|
||||
if reg.Bytes != nil && name[0] == 'V' {
|
||||
buf := bytes.NewReader(reg.Bytes)
|
||||
|
||||
var out bytes.Buffer
|
||||
@ -445,9 +459,9 @@ func (a *ARM64) DwarfRegisterToString(name string, reg *op.DwarfRegister) string
|
||||
}
|
||||
fmt.Fprintf(&out, "\tv4_float={ %g %g %g %g }", v4[0], v4[1], v4[2], v4[3])
|
||||
|
||||
return out.String()
|
||||
return name, true, out.String()
|
||||
} else if reg.Bytes == nil || (reg.Bytes != nil && len(reg.Bytes) < 16) {
|
||||
return fmt.Sprintf("%#016x", reg.Uint64Val)
|
||||
return name, false, fmt.Sprintf("%#016x", reg.Uint64Val)
|
||||
}
|
||||
return fmt.Sprintf("%#x", reg.Bytes)
|
||||
return name, false, fmt.Sprintf("%#x", reg.Bytes)
|
||||
}
|
||||
|
@ -185,6 +185,17 @@ func withCoreFile(t *testing.T, name, args string) *proc.Target {
|
||||
return p
|
||||
}
|
||||
|
||||
func logRegisters(t *testing.T, regs proc.Registers, arch proc.Arch) {
|
||||
dregs := arch.RegistersToDwarfRegisters(0, regs)
|
||||
for i, reg := range dregs.Regs {
|
||||
if reg == nil {
|
||||
continue
|
||||
}
|
||||
name, _, value := arch.DwarfRegisterToString(i, reg)
|
||||
t.Logf("%s = %s", name, value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCore(t *testing.T) {
|
||||
if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
|
||||
return
|
||||
@ -243,11 +254,7 @@ func TestCore(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't get current thread registers: %v", err)
|
||||
}
|
||||
regslice := regs.Slice(true)
|
||||
arch := p.BinInfo().Arch
|
||||
for _, reg := range regslice {
|
||||
t.Logf("%s = %s", reg.Name, arch.DwarfRegisterToString(reg.Name, reg.Reg))
|
||||
}
|
||||
logRegisters(t, regs, p.BinInfo().Arch)
|
||||
}
|
||||
|
||||
func TestCoreFpRegisters(t *testing.T) {
|
||||
@ -314,18 +321,17 @@ func TestCoreFpRegisters(t *testing.T) {
|
||||
}
|
||||
|
||||
arch := p.BinInfo().Arch
|
||||
for _, reg := range regs.Slice(true) {
|
||||
t.Logf("%s = %s", reg.Name, arch.DwarfRegisterToString(reg.Name, reg.Reg))
|
||||
}
|
||||
logRegisters(t, regs, arch)
|
||||
dregs := arch.RegistersToDwarfRegisters(0, regs)
|
||||
|
||||
for _, regtest := range regtests {
|
||||
found := false
|
||||
for _, reg := range regs.Slice(true) {
|
||||
if reg.Name == regtest.name {
|
||||
for i, reg := range dregs.Regs {
|
||||
regname, _, regval := arch.DwarfRegisterToString(i, reg)
|
||||
if reg != nil && regname == regtest.name {
|
||||
found = true
|
||||
regval := arch.DwarfRegisterToString(reg.Name, reg.Reg)
|
||||
if !strings.HasPrefix(regval, regtest.value) {
|
||||
t.Fatalf("register %s expected %q got %q", reg.Name, regtest.value, regval)
|
||||
t.Fatalf("register %s expected %q got %q", regname, regtest.value, regval)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1638,7 +1638,13 @@ func regs(t *Term, ctx callContext, args string) error {
|
||||
if args == "-a" {
|
||||
includeFp = true
|
||||
}
|
||||
regs, err := t.client.ListRegisters(0, includeFp)
|
||||
var regs api.Registers
|
||||
var err error
|
||||
if ctx.Scope.GoroutineID < 0 && ctx.Scope.Frame == 0 {
|
||||
regs, err = t.client.ListThreadRegisters(0, includeFp)
|
||||
} else {
|
||||
regs, err = t.client.ListScopeRegisters(ctx.Scope, includeFp)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -967,7 +967,7 @@ func TestIssue1493(t *testing.T) {
|
||||
ra := term.MustExec("regs -a")
|
||||
nra := len(strings.Split(ra, "\n"))
|
||||
t.Logf("regs -a: %s", ra)
|
||||
if nr > nra/2 {
|
||||
if nr > nra/2+1 {
|
||||
t.Fatalf("'regs' returned too many registers (%d) compared to 'regs -a' (%d)", nr, nra)
|
||||
}
|
||||
})
|
||||
|
@ -934,6 +934,15 @@ func (env *Env) starlarkPredeclare() starlark.StringDict {
|
||||
return starlark.None, decorateError(thread, err)
|
||||
}
|
||||
}
|
||||
if len(args) > 2 && args[2] != starlark.None {
|
||||
err := unmarshalStarlarkValue(args[2], &rpcArgs.Scope, "Scope")
|
||||
if err != nil {
|
||||
return starlark.None, decorateError(thread, err)
|
||||
}
|
||||
} else {
|
||||
scope := env.ctx.Scope()
|
||||
rpcArgs.Scope = &scope
|
||||
}
|
||||
for _, kv := range kwargs {
|
||||
var err error
|
||||
switch kv[0].(starlark.String) {
|
||||
@ -941,6 +950,8 @@ func (env *Env) starlarkPredeclare() starlark.StringDict {
|
||||
err = unmarshalStarlarkValue(kv[1], &rpcArgs.ThreadID, "ThreadID")
|
||||
case "IncludeFp":
|
||||
err = unmarshalStarlarkValue(kv[1], &rpcArgs.IncludeFp, "IncludeFp")
|
||||
case "Scope":
|
||||
err = unmarshalStarlarkValue(kv[1], &rpcArgs.Scope, "Scope")
|
||||
default:
|
||||
err = fmt.Errorf("unknown argument %q", kv[0])
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/go-delve/delve/pkg/dwarf/godwarf"
|
||||
"github.com/go-delve/delve/pkg/dwarf/op"
|
||||
"github.com/go-delve/delve/pkg/proc"
|
||||
)
|
||||
|
||||
@ -328,10 +329,18 @@ func LoadConfigFromProc(cfg *proc.LoadConfig) *LoadConfig {
|
||||
}
|
||||
|
||||
// ConvertRegisters converts proc.Register to api.Register for a slice.
|
||||
func ConvertRegisters(in []proc.Register, arch proc.Arch) (out []Register) {
|
||||
out = make([]Register, len(in))
|
||||
for i := range in {
|
||||
out[i] = Register{in[i].Name, arch.DwarfRegisterToString(in[i].Name, in[i].Reg)}
|
||||
func ConvertRegisters(in op.DwarfRegisters, arch proc.Arch, floatingPoint bool) (out []Register) {
|
||||
out = make([]Register, 0, len(in.Regs))
|
||||
for i := range in.Regs {
|
||||
reg := in.Reg(uint64(i))
|
||||
if reg == nil {
|
||||
continue
|
||||
}
|
||||
name, fp, repr := arch.DwarfRegisterToString(i, reg)
|
||||
if !floatingPoint && fp {
|
||||
continue
|
||||
}
|
||||
out = append(out, Register{name, repr, i})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -442,8 +442,9 @@ type SetAPIVersionOut struct {
|
||||
|
||||
// Register holds information on a CPU register.
|
||||
type Register struct {
|
||||
Name string
|
||||
Value string
|
||||
Name string
|
||||
Value string
|
||||
DwarfNumber int
|
||||
}
|
||||
|
||||
// Registers is a list of CPU registers.
|
||||
|
@ -93,8 +93,10 @@ type Client interface {
|
||||
ListLocalVariables(scope api.EvalScope, cfg api.LoadConfig) ([]api.Variable, error)
|
||||
// ListFunctionArgs lists all arguments to the current function.
|
||||
ListFunctionArgs(scope api.EvalScope, cfg api.LoadConfig) ([]api.Variable, error)
|
||||
// ListRegisters lists registers and their values.
|
||||
ListRegisters(threadID int, includeFp bool) (api.Registers, error)
|
||||
// ListThreadRegisters lists registers and their values, for the given thread.
|
||||
ListThreadRegisters(threadID int, includeFp bool) (api.Registers, error)
|
||||
// ListScopeRegisters lists registers and their values, for the given scope.
|
||||
ListScopeRegisters(scope api.EvalScope, includeFp bool) (api.Registers, error)
|
||||
|
||||
// ListGoroutines lists all goroutines.
|
||||
ListGoroutines(start, count int) ([]*api.Goroutine, int, error)
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/go-delve/delve/pkg/dwarf/op"
|
||||
"github.com/go-delve/delve/pkg/goversion"
|
||||
"github.com/go-delve/delve/pkg/logflags"
|
||||
"github.com/go-delve/delve/pkg/proc"
|
||||
@ -949,19 +950,65 @@ func (d *Debugger) PackageVariables(threadID int, filter string, cfg proc.LoadCo
|
||||
}
|
||||
|
||||
// Registers returns string representation of the CPU registers.
|
||||
func (d *Debugger) Registers(threadID int, floatingPoint bool) (api.Registers, error) {
|
||||
func (d *Debugger) Registers(threadID int, scope *api.EvalScope, floatingPoint bool) (api.Registers, error) {
|
||||
d.processMutex.Lock()
|
||||
defer d.processMutex.Unlock()
|
||||
|
||||
thread, found := d.target.FindThread(threadID)
|
||||
if !found {
|
||||
return nil, fmt.Errorf("couldn't find thread %d", threadID)
|
||||
var dregs op.DwarfRegisters
|
||||
|
||||
if scope != nil {
|
||||
s, err := proc.ConvertEvalScope(d.target, scope.GoroutineID, scope.Frame, scope.DeferredCall)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dregs = s.Regs
|
||||
} else {
|
||||
thread, found := d.target.FindThread(threadID)
|
||||
if !found {
|
||||
return nil, fmt.Errorf("couldn't find thread %d", threadID)
|
||||
}
|
||||
regs, err := thread.Registers(floatingPoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dregs = d.target.BinInfo().Arch.RegistersToDwarfRegisters(0, regs)
|
||||
}
|
||||
regs, err := thread.Registers(floatingPoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return api.ConvertRegisters(regs.Slice(floatingPoint), d.target.BinInfo().Arch), err
|
||||
r := api.ConvertRegisters(dregs, d.target.BinInfo().Arch, floatingPoint)
|
||||
// Sort the registers in a canonical order we prefer, this is mostly
|
||||
// because the DWARF register numbering for AMD64 is weird.
|
||||
sort.Slice(r, func(i, j int) bool {
|
||||
a, b := r[i], r[j]
|
||||
an, aok := canonicalRegisterOrder[strings.ToLower(a.Name)]
|
||||
bn, bok := canonicalRegisterOrder[strings.ToLower(b.Name)]
|
||||
// Registers that don't appear in canonicalRegisterOrder sort after registers that do.
|
||||
if !aok {
|
||||
an = 1000
|
||||
}
|
||||
if !bok {
|
||||
bn = 1000
|
||||
}
|
||||
if an == bn {
|
||||
// keep registers that don't appear in canonicalRegisterOrder in DWARF order
|
||||
return a.DwarfNumber < b.DwarfNumber
|
||||
}
|
||||
return an < bn
|
||||
|
||||
})
|
||||
return r, nil
|
||||
}
|
||||
|
||||
var canonicalRegisterOrder = map[string]int{
|
||||
// amd64
|
||||
"rip": 0,
|
||||
"rsp": 1,
|
||||
"rax": 2,
|
||||
"rbx": 3,
|
||||
"rcx": 4,
|
||||
"rdx": 5,
|
||||
|
||||
// arm64
|
||||
"pc": 0,
|
||||
"sp": 1,
|
||||
}
|
||||
|
||||
func convertVars(pv []*proc.Variable) []api.Variable {
|
||||
|
@ -204,7 +204,7 @@ func (s *RPCServer) ListRegisters(arg interface{}, registers *string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
regs, err := s.debugger.Registers(state.CurrentThread.ID, false)
|
||||
regs, err := s.debugger.Registers(state.CurrentThread.ID, nil, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -292,9 +292,15 @@ func (c *RPCClient) ListLocalVariables(scope api.EvalScope, cfg api.LoadConfig)
|
||||
return out.Variables, err
|
||||
}
|
||||
|
||||
func (c *RPCClient) ListRegisters(threadID int, includeFp bool) (api.Registers, error) {
|
||||
func (c *RPCClient) ListThreadRegisters(threadID int, includeFp bool) (api.Registers, error) {
|
||||
out := new(ListRegistersOut)
|
||||
err := c.call("ListRegisters", ListRegistersIn{ThreadID: threadID, IncludeFp: includeFp}, out)
|
||||
err := c.call("ListRegisters", ListRegistersIn{ThreadID: threadID, IncludeFp: includeFp, Scope: nil}, out)
|
||||
return out.Regs, err
|
||||
}
|
||||
|
||||
func (c *RPCClient) ListScopeRegisters(scope api.EvalScope, includeFp bool) (api.Registers, error) {
|
||||
out := new(ListRegistersOut)
|
||||
err := c.call("ListRegisters", ListRegistersIn{ThreadID: 0, IncludeFp: includeFp, Scope: &scope}, out)
|
||||
return out.Regs, err
|
||||
}
|
||||
|
||||
|
@ -368,6 +368,7 @@ func (s *RPCServer) ListPackageVars(arg ListPackageVarsIn, out *ListPackageVarsO
|
||||
type ListRegistersIn struct {
|
||||
ThreadID int
|
||||
IncludeFp bool
|
||||
Scope *api.EvalScope
|
||||
}
|
||||
|
||||
type ListRegistersOut struct {
|
||||
@ -376,8 +377,10 @@ type ListRegistersOut struct {
|
||||
}
|
||||
|
||||
// ListRegisters lists registers and their values.
|
||||
// If ListRegistersIn.Scope is not nil the registers of that eval scope will
|
||||
// be returned, otherwise ListRegistersIn.ThreadID will be used.
|
||||
func (s *RPCServer) ListRegisters(arg ListRegistersIn, out *ListRegistersOut) error {
|
||||
if arg.ThreadID == 0 {
|
||||
if arg.ThreadID == 0 && arg.Scope == nil {
|
||||
state, err := s.debugger.State(false)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -385,7 +388,7 @@ func (s *RPCServer) ListRegisters(arg ListRegistersIn, out *ListRegistersOut) er
|
||||
arg.ThreadID = state.CurrentThread.ID
|
||||
}
|
||||
|
||||
regs, err := s.debugger.Registers(arg.ThreadID, arg.IncludeFp)
|
||||
regs, err := s.debugger.Registers(arg.ThreadID, arg.Scope, arg.IncludeFp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -510,13 +510,28 @@ func TestClientServer_infoArgs(t *testing.T) {
|
||||
if state.Err != nil {
|
||||
t.Fatalf("Unexpected error: %v, state: %#v", state.Err, state)
|
||||
}
|
||||
regs, err := c.ListRegisters(0, false)
|
||||
regs, err := c.ListThreadRegisters(0, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
if len(regs) == 0 {
|
||||
t.Fatal("Expected string showing registers values, got empty string")
|
||||
}
|
||||
|
||||
regs, err = c.ListScopeRegisters(api.EvalScope{GoroutineID: -1, Frame: 0}, false)
|
||||
assertNoError(err, t, "ListScopeRegisters(-1, 0)")
|
||||
if len(regs) == 0 {
|
||||
t.Fatal("Expected string showing registers values, got empty string")
|
||||
}
|
||||
t.Logf("GoroutineID: -1, Frame: 0\n%s", regs.String())
|
||||
|
||||
regs, err = c.ListScopeRegisters(api.EvalScope{GoroutineID: -1, Frame: 1}, false)
|
||||
assertNoError(err, t, "ListScopeRegisters(-1, 1)")
|
||||
if len(regs) == 0 {
|
||||
t.Fatal("Expected string showing registers values, got empty string")
|
||||
}
|
||||
t.Logf("GoroutineID: -1, Frame: 1\n%s", regs.String())
|
||||
|
||||
locals, err := c.ListFunctionArgs(api.EvalScope{-1, 0, 0}, normalLoadConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
@ -925,8 +940,10 @@ func TestIssue355(t *testing.T) {
|
||||
assertError(err, t, "ListLocalVariables()")
|
||||
_, err = c.ListFunctionArgs(api.EvalScope{gid, 0, 0}, normalLoadConfig)
|
||||
assertError(err, t, "ListFunctionArgs()")
|
||||
_, err = c.ListRegisters(0, false)
|
||||
assertError(err, t, "ListRegisters()")
|
||||
_, err = c.ListThreadRegisters(0, false)
|
||||
assertError(err, t, "ListThreadRegisters()")
|
||||
_, err = c.ListScopeRegisters(api.EvalScope{gid, 0, 0}, false)
|
||||
assertError(err, t, "ListScopeRegisters()")
|
||||
_, _, err = c.ListGoroutines(0, 0)
|
||||
assertError(err, t, "ListGoroutines()")
|
||||
_, err = c.Stacktrace(gid, 10, 0, &normalLoadConfig)
|
||||
@ -1279,8 +1296,8 @@ func TestClientServer_FpRegisters(t *testing.T) {
|
||||
protest.AllowRecording(t)
|
||||
withTestClient2("fputest/", t, func(c service.Client) {
|
||||
<-c.Continue()
|
||||
regs, err := c.ListRegisters(0, true)
|
||||
assertNoError(err, t, "ListRegisters()")
|
||||
regs, err := c.ListThreadRegisters(0, true)
|
||||
assertNoError(err, t, "ListThreadRegisters()")
|
||||
|
||||
t.Logf("%s", regs.String())
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user