mirror of
https://github.com/go-delve/delve.git
synced 2025-11-02 04:36:29 +08:00
proc: give unique addresses to registerized variables (#2527)
We told clients that further loading of variables can be done by specifying a type cast using the address of a variable that we returned. This does not work for registerized variables (or, in general, variables that have a complex location expression) because we don't give them unique addresses and we throw away the compositeMemory object we made to read them. This commit changes proc so that: 1. variables with location expression divided in pieces do get a unique memory address 2. the compositeMemory object is saved somewhere 3. when an integer is cast back into a pointer type we look through our saved compositeMemory objects to see if there is one that covers the specified address and use it. The unique memory addresses we generate have the MSB set to 1, as specified by the Intel 86x64 manual addresses in this form are reserved for kernel memory (which we can not read anyway) so we are guaranteed to never generate a fake memory address that overlaps a real memory address of the application. The unfortunate side effect of this is that it will break clients that do not deserialize the address to a 64bit integer. This practice is contrary to how we defined our types and contrary to the specification of the JSON format, as of json.org, however it is also fairly common, due to javascript itself having only 53bit integers. We could come up with a new mechanism but then even more old clients would have to be changed.
This commit is contained in:
committed by
GitHub
parent
7c82164264
commit
1b0c4310c4
@ -1149,10 +1149,10 @@ func evalVariableOrError(p *proc.Target, symbol string) (*proc.Variable, error)
|
||||
var frame proc.Stackframe
|
||||
frame, err = findFirstNonRuntimeFrame(p)
|
||||
if err == nil {
|
||||
scope = proc.FrameToScope(p.BinInfo(), p.Memory(), nil, frame)
|
||||
scope = proc.FrameToScope(p, p.BinInfo(), p.Memory(), nil, frame)
|
||||
}
|
||||
} else {
|
||||
scope, err = proc.GoroutineScope(p.CurrentThread())
|
||||
scope, err = proc.GoroutineScope(p, p.CurrentThread())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@ -1172,7 +1172,7 @@ func evalVariable(p *proc.Target, t testing.TB, symbol string) *proc.Variable {
|
||||
}
|
||||
|
||||
func setVariable(p *proc.Target, symbol, value string) error {
|
||||
scope, err := proc.GoroutineScope(p.CurrentThread())
|
||||
scope, err := proc.GoroutineScope(p, p.CurrentThread())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1350,7 +1350,7 @@ func TestPointerSetting(t *testing.T) {
|
||||
pval(1)
|
||||
|
||||
// change p1 to point to i2
|
||||
scope, err := proc.GoroutineScope(p.CurrentThread())
|
||||
scope, err := proc.GoroutineScope(p, p.CurrentThread())
|
||||
assertNoError(err, t, "Scope()")
|
||||
i2addr, err := scope.EvalExpression("i2", normalLoadConfig)
|
||||
assertNoError(err, t, "EvalExpression()")
|
||||
@ -1481,7 +1481,7 @@ func TestBreakpointCountsWithDetection(t *testing.T) {
|
||||
if bp := th.Breakpoint(); bp.Breakpoint == nil {
|
||||
continue
|
||||
}
|
||||
scope, err := proc.GoroutineScope(th)
|
||||
scope, err := proc.GoroutineScope(p, th)
|
||||
assertNoError(err, t, "Scope()")
|
||||
v, err := scope.EvalVariable("i", normalLoadConfig)
|
||||
assertNoError(err, t, "evalVariable")
|
||||
@ -1551,7 +1551,7 @@ func BenchmarkGoroutinesInfo(b *testing.B) {
|
||||
assertNoError(p.Continue(), b, "Continue()")
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
p.ClearAllGCache()
|
||||
p.ClearCaches()
|
||||
_, _, err := proc.GoroutinesInfo(p, 0, 0)
|
||||
assertNoError(err, b, "GoroutinesInfo")
|
||||
}
|
||||
@ -1611,7 +1611,7 @@ func TestPointerLoops(t *testing.T) {
|
||||
func BenchmarkLocalVariables(b *testing.B) {
|
||||
withTestProcess("testvariables", b, func(p *proc.Target, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), b, "Continue() returned an error")
|
||||
scope, err := proc.GoroutineScope(p.CurrentThread())
|
||||
scope, err := proc.GoroutineScope(p, p.CurrentThread())
|
||||
assertNoError(err, b, "Scope()")
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
@ -1900,7 +1900,7 @@ func TestPackageVariables(t *testing.T) {
|
||||
withTestProcess("testvariables", t, func(p *proc.Target, fixture protest.Fixture) {
|
||||
err := p.Continue()
|
||||
assertNoError(err, t, "Continue()")
|
||||
scope, err := proc.GoroutineScope(p.CurrentThread())
|
||||
scope, err := proc.GoroutineScope(p, p.CurrentThread())
|
||||
assertNoError(err, t, "Scope()")
|
||||
vars, err := scope.PackageVariables(normalLoadConfig)
|
||||
assertNoError(err, t, "PackageVariables()")
|
||||
@ -2698,7 +2698,7 @@ func BenchmarkTrace(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
assertNoError(p.Continue(), b, "Continue()")
|
||||
s, err := proc.GoroutineScope(p.CurrentThread())
|
||||
s, err := proc.GoroutineScope(p, p.CurrentThread())
|
||||
assertNoError(err, b, "Scope()")
|
||||
_, err = s.FunctionArguments(proc.LoadConfig{false, 0, 64, 0, 3, 0})
|
||||
assertNoError(err, b, "FunctionArguments()")
|
||||
@ -2966,10 +2966,10 @@ func TestIssue871(t *testing.T) {
|
||||
var frame proc.Stackframe
|
||||
frame, err = findFirstNonRuntimeFrame(p)
|
||||
if err == nil {
|
||||
scope = proc.FrameToScope(p.BinInfo(), p.Memory(), nil, frame)
|
||||
scope = proc.FrameToScope(p, p.BinInfo(), p.Memory(), nil, frame)
|
||||
}
|
||||
} else {
|
||||
scope, err = proc.GoroutineScope(p.CurrentThread())
|
||||
scope, err = proc.GoroutineScope(p, p.CurrentThread())
|
||||
}
|
||||
assertNoError(err, t, "scope")
|
||||
|
||||
@ -3007,7 +3007,7 @@ func TestShadowedFlag(t *testing.T) {
|
||||
}
|
||||
withTestProcess("testshadow", t, func(p *proc.Target, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), t, "Continue")
|
||||
scope, err := proc.GoroutineScope(p.CurrentThread())
|
||||
scope, err := proc.GoroutineScope(p, p.CurrentThread())
|
||||
assertNoError(err, t, "GoroutineScope")
|
||||
locals, err := scope.LocalVariables(normalLoadConfig)
|
||||
assertNoError(err, t, "LocalVariables")
|
||||
@ -3412,7 +3412,7 @@ func TestIssue1034(t *testing.T) {
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
frames, err := p.SelectedGoroutine().Stacktrace(10, 0)
|
||||
assertNoError(err, t, "Stacktrace")
|
||||
scope := proc.FrameToScope(p.BinInfo(), p.Memory(), nil, frames[2:]...)
|
||||
scope := proc.FrameToScope(p, p.BinInfo(), p.Memory(), nil, frames[2:]...)
|
||||
args, _ := scope.FunctionArguments(normalLoadConfig)
|
||||
assertNoError(err, t, "FunctionArguments()")
|
||||
if len(args) > 0 {
|
||||
@ -3446,7 +3446,7 @@ func testDeclLineCount(t *testing.T, p *proc.Target, lineno int, tgtvars []strin
|
||||
sort.Strings(tgtvars)
|
||||
|
||||
assertLineNumber(p, t, lineno, "Program did not continue to correct next location")
|
||||
scope, err := proc.GoroutineScope(p.CurrentThread())
|
||||
scope, err := proc.GoroutineScope(p, p.CurrentThread())
|
||||
assertNoError(err, t, fmt.Sprintf("GoroutineScope (:%d)", lineno))
|
||||
vars, err := scope.Locals()
|
||||
assertNoError(err, t, fmt.Sprintf("Locals (:%d)", lineno))
|
||||
@ -3864,7 +3864,7 @@ func TestIssue951(t *testing.T) {
|
||||
|
||||
withTestProcess("issue951", t, func(p *proc.Target, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
scope, err := proc.GoroutineScope(p.CurrentThread())
|
||||
scope, err := proc.GoroutineScope(p, p.CurrentThread())
|
||||
assertNoError(err, t, "GoroutineScope")
|
||||
args, err := scope.FunctionArguments(normalLoadConfig)
|
||||
assertNoError(err, t, "FunctionArguments")
|
||||
@ -3910,7 +3910,7 @@ func TestMapLoadConfigWithReslice(t *testing.T) {
|
||||
withTestProcess("testvariables2", t, func(p *proc.Target, fixture protest.Fixture) {
|
||||
zolotovLoadCfg := proc.LoadConfig{FollowPointers: true, MaxStructFields: -1, MaxVariableRecurse: 3, MaxStringLen: 10, MaxArrayValues: 10}
|
||||
assertNoError(p.Continue(), t, "First Continue()")
|
||||
scope, err := proc.GoroutineScope(p.CurrentThread())
|
||||
scope, err := proc.GoroutineScope(p, p.CurrentThread())
|
||||
assertNoError(err, t, "GoroutineScope")
|
||||
m1, err := scope.EvalExpression("m1", zolotovLoadCfg)
|
||||
assertNoError(err, t, "EvalVariable")
|
||||
@ -4152,7 +4152,7 @@ func TestIssue1432(t *testing.T) {
|
||||
svar := evalVariable(p, t, "s")
|
||||
t.Logf("%#x", svar.Addr)
|
||||
|
||||
scope, err := proc.GoroutineScope(p.CurrentThread())
|
||||
scope, err := proc.GoroutineScope(p, p.CurrentThread())
|
||||
assertNoError(err, t, "GoroutineScope()")
|
||||
|
||||
err = scope.SetVariable(fmt.Sprintf("(*\"main.s\")(%#x).i", svar.Addr), "10")
|
||||
@ -5054,8 +5054,8 @@ func TestDump(t *testing.T) {
|
||||
t.Errorf("Frame mismatch %d.%d\nlive:\t%s\ncore:\t%s", gos[i].ID, j, convertFrame(p.BinInfo().Arch, &frames[j]), convertFrame(p.BinInfo().Arch, &cframes[j]))
|
||||
}
|
||||
if frames[j].Call.Fn != nil && frames[j].Call.Fn.Name == "main.main" {
|
||||
scope = proc.FrameToScope(p.BinInfo(), p.Memory(), gos[i], frames[j:]...)
|
||||
cscope = proc.FrameToScope(c.BinInfo(), c.Memory(), cgos[i], cframes[j:]...)
|
||||
scope = proc.FrameToScope(p, p.BinInfo(), p.Memory(), gos[i], frames[j:]...)
|
||||
cscope = proc.FrameToScope(c, c.BinInfo(), c.Memory(), cgos[i], cframes[j:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5132,9 +5132,11 @@ func TestCompositeMemoryWrite(t *testing.T) {
|
||||
return regs.PC(), rax, xmm1
|
||||
}
|
||||
|
||||
const fakeAddress = 0xbeef0000
|
||||
|
||||
getmem := func(mem proc.MemoryReader) uint64 {
|
||||
buf := make([]byte, 8)
|
||||
_, err := mem.ReadMemory(buf, 0xbeef0000)
|
||||
_, err := mem.ReadMemory(buf, fakeAddress)
|
||||
assertNoError(err, t, "ReadMemory")
|
||||
return binary.LittleEndian.Uint64(buf)
|
||||
}
|
||||
@ -5143,9 +5145,9 @@ func TestCompositeMemoryWrite(t *testing.T) {
|
||||
oldPc, oldRax, oldXmm1 := getregs()
|
||||
t.Logf("PC %#x AX %#x XMM1 %#x", oldPc, oldRax, oldXmm1)
|
||||
|
||||
memRax, err := proc.NewCompositeMemory(p, []op.Piece{{Size: 0, Val: 0, Kind: op.RegPiece}})
|
||||
memRax, err := proc.NewCompositeMemory(p, []op.Piece{{Size: 0, Val: 0, Kind: op.RegPiece}}, fakeAddress)
|
||||
assertNoError(err, t, "NewCompositeMemory (rax)")
|
||||
memXmm1, err := proc.NewCompositeMemory(p, []op.Piece{{Size: 0, Val: 18, Kind: op.RegPiece}})
|
||||
memXmm1, err := proc.NewCompositeMemory(p, []op.Piece{{Size: 0, Val: 18, Kind: op.RegPiece}}, fakeAddress)
|
||||
assertNoError(err, t, "NewCompositeMemory (xmm1)")
|
||||
|
||||
if memRax := getmem(memRax); memRax != oldRax {
|
||||
@ -5204,7 +5206,7 @@ func TestWatchpointsBasic(t *testing.T) {
|
||||
assertNoError(p.Continue(), t, "Continue 0")
|
||||
assertLineNumber(p, t, 11, "Continue 0") // Position 0
|
||||
|
||||
scope, err := proc.GoroutineScope(p.CurrentThread())
|
||||
scope, err := proc.GoroutineScope(p, p.CurrentThread())
|
||||
assertNoError(err, t, "GoroutineScope")
|
||||
|
||||
bp, err := p.SetWatchpoint(scope, "globalvar1", proc.WatchWrite, nil)
|
||||
@ -5250,7 +5252,7 @@ func TestWatchpointCounts(t *testing.T) {
|
||||
setFunctionBreakpoint(p, t, "main.main")
|
||||
assertNoError(p.Continue(), t, "Continue 0")
|
||||
|
||||
scope, err := proc.GoroutineScope(p.CurrentThread())
|
||||
scope, err := proc.GoroutineScope(p, p.CurrentThread())
|
||||
assertNoError(err, t, "GoroutineScope")
|
||||
|
||||
bp, err := p.SetWatchpoint(scope, "globalvar1", proc.WatchWrite, nil)
|
||||
|
||||
Reference in New Issue
Block a user