mirror of
https://github.com/golang/go
synced 2024-11-12 09:20:22 -07:00
Update debugger to use Abort interface
R=rsc APPROVED=rsc DELTA=314 (132 added, 2 deleted, 180 changed) OCL=34376 CL=34396
This commit is contained in:
parent
05522cd51e
commit
fdf5efe43c
35
usr/austin/ogle/abort.go
Normal file
35
usr/austin/ogle/abort.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2009 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.
|
||||||
|
|
||||||
|
package ogle
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os";
|
||||||
|
"runtime";
|
||||||
|
)
|
||||||
|
|
||||||
|
// An aborter aborts the thread's current compututation, usually
|
||||||
|
// passing the error to a waiting thread.
|
||||||
|
type aborter interface {
|
||||||
|
Abort(err os.Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
type ogleAborter chan os.Error;
|
||||||
|
|
||||||
|
func (a ogleAborter) Abort(err os.Error) {
|
||||||
|
a <- err;
|
||||||
|
runtime.Goexit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// try executes a computation; if the computation Aborts, try returns
|
||||||
|
// the error passed to abort.
|
||||||
|
func try(f func(a aborter)) os.Error {
|
||||||
|
a := make(ogleAborter);
|
||||||
|
go func() {
|
||||||
|
f(a);
|
||||||
|
a <- nil;
|
||||||
|
}();
|
||||||
|
err := <-a;
|
||||||
|
return err;
|
||||||
|
}
|
@ -6,6 +6,7 @@ package ogle
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt";
|
"fmt";
|
||||||
|
"os";
|
||||||
"ptrace";
|
"ptrace";
|
||||||
"sym";
|
"sym";
|
||||||
)
|
)
|
||||||
@ -29,14 +30,19 @@ type Frame struct {
|
|||||||
inner, outer *Frame;
|
inner, outer *Frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFrame returns the top-most Frame of the given g's thread.
|
// newFrame returns the top-most Frame of the given g's thread.
|
||||||
// This function can abort.
|
func newFrame(g remoteStruct) (*Frame, os.Error) {
|
||||||
func NewFrame(g remoteStruct) *Frame {
|
var f *Frame;
|
||||||
|
err := try(func(a aborter) { f = aNewFrame(a, g) });
|
||||||
|
return f, err;
|
||||||
|
}
|
||||||
|
|
||||||
|
func aNewFrame(a aborter, g remoteStruct) *Frame {
|
||||||
p := g.r.p;
|
p := g.r.p;
|
||||||
var pc, sp ptrace.Word;
|
var pc, sp ptrace.Word;
|
||||||
|
|
||||||
// Is this G alive?
|
// Is this G alive?
|
||||||
switch g.Field(p.f.G.Status).(remoteInt).Get() {
|
switch g.field(p.f.G.Status).(remoteInt).aGet(a) {
|
||||||
case p.runtime.Gidle, p.runtime.Gmoribund, p.runtime.Gdead:
|
case p.runtime.Gidle, p.runtime.Gmoribund, p.runtime.Gdead:
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
@ -61,7 +67,7 @@ func NewFrame(g remoteStruct) *Frame {
|
|||||||
|
|
||||||
// If this thread crashed, try to recover it
|
// If this thread crashed, try to recover it
|
||||||
if pc == 0 {
|
if pc == 0 {
|
||||||
pc = p.peekUintptr(pc);
|
pc = p.peekUintptr(a, pc);
|
||||||
sp += 8;
|
sp += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,22 +78,21 @@ func NewFrame(g remoteStruct) *Frame {
|
|||||||
if pc == 0 && sp == 0 {
|
if pc == 0 && sp == 0 {
|
||||||
// G is not mapped to an OS thread. Use the
|
// G is not mapped to an OS thread. Use the
|
||||||
// scheduler's stored PC and SP.
|
// scheduler's stored PC and SP.
|
||||||
sched := g.Field(p.f.G.Sched).(remoteStruct);
|
sched := g.field(p.f.G.Sched).(remoteStruct);
|
||||||
pc = ptrace.Word(sched.Field(p.f.Gobuf.Pc).(remoteUint).Get());
|
pc = ptrace.Word(sched.field(p.f.Gobuf.Pc).(remoteUint).aGet(a));
|
||||||
sp = ptrace.Word(sched.Field(p.f.Gobuf.Sp).(remoteUint).Get());
|
sp = ptrace.Word(sched.field(p.f.Gobuf.Sp).(remoteUint).aGet(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get Stktop
|
// Get Stktop
|
||||||
stk := g.Field(p.f.G.Stackbase).(remotePtr).Get().(remoteStruct);
|
stk := g.field(p.f.G.Stackbase).(remotePtr).aGet(a).(remoteStruct);
|
||||||
|
|
||||||
return prepareFrame(pc, sp, stk, nil);
|
return prepareFrame(a, pc, sp, stk, nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepareFrame creates a Frame from the PC and SP within that frame,
|
// prepareFrame creates a Frame from the PC and SP within that frame,
|
||||||
// as well as the active stack segment. This function takes care of
|
// as well as the active stack segment. This function takes care of
|
||||||
// traversing stack breaks and unwinding closures. This function can
|
// traversing stack breaks and unwinding closures.
|
||||||
// abort.
|
func prepareFrame(a aborter, pc, sp ptrace.Word, stk remoteStruct, inner *Frame) *Frame {
|
||||||
func prepareFrame(pc, sp ptrace.Word, stk remoteStruct, inner *Frame) *Frame {
|
|
||||||
// Based on src/pkg/runtime/amd64/traceback.c:traceback
|
// Based on src/pkg/runtime/amd64/traceback.c:traceback
|
||||||
p := stk.r.p;
|
p := stk.r.p;
|
||||||
top := inner == nil;
|
top := inner == nil;
|
||||||
@ -101,11 +106,11 @@ func prepareFrame(pc, sp ptrace.Word, stk remoteStruct, inner *Frame) *Frame {
|
|||||||
// Traverse segmented stack breaks
|
// Traverse segmented stack breaks
|
||||||
if p.sys.lessstack != nil && pc == ptrace.Word(p.sys.lessstack.Value) {
|
if p.sys.lessstack != nil && pc == ptrace.Word(p.sys.lessstack.Value) {
|
||||||
// Get stk->gobuf.pc
|
// Get stk->gobuf.pc
|
||||||
pc = ptrace.Word(stk.Field(p.f.Stktop.Gobuf).(remoteStruct).Field(p.f.Gobuf.Pc).(remoteUint).Get());
|
pc = ptrace.Word(stk.field(p.f.Stktop.Gobuf).(remoteStruct).field(p.f.Gobuf.Pc).(remoteUint).aGet(a));
|
||||||
// Get stk->gobuf.sp
|
// Get stk->gobuf.sp
|
||||||
sp = ptrace.Word(stk.Field(p.f.Stktop.Gobuf).(remoteStruct).Field(p.f.Gobuf.Sp).(remoteUint).Get());
|
sp = ptrace.Word(stk.field(p.f.Stktop.Gobuf).(remoteStruct).field(p.f.Gobuf.Sp).(remoteUint).aGet(a));
|
||||||
// Get stk->stackbase
|
// Get stk->stackbase
|
||||||
stk = stk.Field(p.f.Stktop.Stackbase).(remotePtr).Get().(remoteStruct);
|
stk = stk.field(p.f.Stktop.Stackbase).(remotePtr).aGet(a).(remoteStruct);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +134,7 @@ func prepareFrame(pc, sp ptrace.Word, stk remoteStruct, inner *Frame) *Frame {
|
|||||||
spdelta, ok := p.ParseClosure(buf);
|
spdelta, ok := p.ParseClosure(buf);
|
||||||
if ok {
|
if ok {
|
||||||
sp += ptrace.Word(spdelta);
|
sp += ptrace.Word(spdelta);
|
||||||
pc = p.peekUintptr(sp - ptrace.Word(p.PtrSize()));
|
pc = p.peekUintptr(a, sp - ptrace.Word(p.PtrSize()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if fn == nil {
|
if fn == nil {
|
||||||
@ -159,8 +164,14 @@ func prepareFrame(pc, sp ptrace.Word, stk remoteStruct, inner *Frame) *Frame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Outer returns the Frame that called this Frame, or nil if this is
|
// Outer returns the Frame that called this Frame, or nil if this is
|
||||||
// the outermost frame. This function can abort.
|
// the outermost frame.
|
||||||
func (f *Frame) Outer() *Frame {
|
func (f *Frame) Outer() (*Frame, os.Error) {
|
||||||
|
var fr *Frame;
|
||||||
|
err := try(func(a aborter) { fr = f.aOuter(a) });
|
||||||
|
return fr, err;
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Frame) aOuter(a aborter) *Frame {
|
||||||
// Is there a cached outer frame
|
// Is there a cached outer frame
|
||||||
if f.outer != nil {
|
if f.outer != nil {
|
||||||
return f.outer;
|
return f.outer;
|
||||||
@ -177,14 +188,14 @@ func (f *Frame) Outer() *Frame {
|
|||||||
sp += ptrace.Word(2 * p.PtrSize());
|
sp += ptrace.Word(2 * p.PtrSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
pc := p.peekUintptr(f.fp - ptrace.Word(p.PtrSize()));
|
pc := p.peekUintptr(a, f.fp - ptrace.Word(p.PtrSize()));
|
||||||
if pc < 0x1000 {
|
if pc < 0x1000 {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(austin) Register this frame for shoot-down.
|
// TODO(austin) Register this frame for shoot-down.
|
||||||
|
|
||||||
f.outer = prepareFrame(pc, sp, f.stk, f);
|
f.outer = prepareFrame(a, pc, sp, f.stk, f);
|
||||||
return f.outer;
|
return f.outer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package ogle
|
package ogle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"eval";
|
||||||
"fmt";
|
"fmt";
|
||||||
"os";
|
"os";
|
||||||
"ptrace";
|
"ptrace";
|
||||||
@ -31,21 +32,21 @@ func (t *Goroutine) isG0() bool {
|
|||||||
return t.g.addr().base == t.g.r.p.sys.g0.addr().base;
|
return t.g.addr().base == t.g.r.p.sys.g0.addr().base;
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Goroutine) resetFrame() {
|
func (t *Goroutine) resetFrame() (err os.Error) {
|
||||||
// TODO(austin) NewFrame can abort
|
|
||||||
// TODO(austin) Reuse any live part of the current frame stack
|
// TODO(austin) Reuse any live part of the current frame stack
|
||||||
// so existing references to Frame's keep working.
|
// so existing references to Frame's keep working.
|
||||||
t.frame = NewFrame(t.g);
|
t.frame, err = newFrame(t.g);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Out selects the caller frame of the current frame.
|
// Out selects the caller frame of the current frame.
|
||||||
func (t *Goroutine) Out() os.Error {
|
func (t *Goroutine) Out() os.Error {
|
||||||
// TODO(austin) Outer can abort
|
// TODO(austin) Outer can abort
|
||||||
f := t.frame.Outer();
|
f, err := t.frame.Outer();
|
||||||
if f != nil {
|
if f != nil {
|
||||||
t.frame = f;
|
t.frame = f;
|
||||||
}
|
}
|
||||||
return nil;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// In selects the frame called by the current frame.
|
// In selects the frame called by the current frame.
|
||||||
@ -70,7 +71,11 @@ func readylockedBP(ev Event) (EventAction, os.Error) {
|
|||||||
sp := regs.SP();
|
sp := regs.SP();
|
||||||
addr := sp + ptrace.Word(p.PtrSize());
|
addr := sp + ptrace.Word(p.PtrSize());
|
||||||
arg := remotePtr{remote{addr, p}, p.runtime.G};
|
arg := remotePtr{remote{addr, p}, p.runtime.G};
|
||||||
gp := arg.Get();
|
var gp eval.Value;
|
||||||
|
err = try(func(a aborter) { gp = arg.aGet(a) });
|
||||||
|
if err != nil {
|
||||||
|
return EAStop, err;
|
||||||
|
}
|
||||||
if gp == nil {
|
if gp == nil {
|
||||||
return EAStop, UnknownGoroutine{b.osThread, 0};
|
return EAStop, UnknownGoroutine{b.osThread, 0};
|
||||||
}
|
}
|
||||||
|
@ -137,12 +137,17 @@ func NewProcess(proc ptrace.Process, arch Arch, syms *sym.GoSymTable) (*Process,
|
|||||||
|
|
||||||
// Get current goroutines
|
// Get current goroutines
|
||||||
p.goroutines[p.sys.g0.addr().base] = &Goroutine{p.sys.g0, nil, false};
|
p.goroutines[p.sys.g0.addr().base] = &Goroutine{p.sys.g0, nil, false};
|
||||||
g := p.sys.allg.Get();
|
err := try(func(a aborter) {
|
||||||
for g != nil {
|
g := p.sys.allg.aGet(a);
|
||||||
gs := g.(remoteStruct);
|
for g != nil {
|
||||||
fmt.Printf("*** Found goroutine at %#x\n", gs.addr().base);
|
gs := g.(remoteStruct);
|
||||||
p.goroutines[gs.addr().base] = &Goroutine{gs, nil, false};
|
fmt.Printf("*** Found goroutine at %#x\n", gs.addr().base);
|
||||||
g = gs.Field(p.f.G.Alllink).(remotePtr).Get();
|
p.goroutines[gs.addr().base] = &Goroutine{gs, nil, false};
|
||||||
|
g = gs.field(p.f.G.Alllink).(remotePtr).aGet(a);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if err != nil {
|
||||||
|
return nil, err;
|
||||||
}
|
}
|
||||||
p.selectSomeGoroutine();
|
p.selectSomeGoroutine();
|
||||||
|
|
||||||
@ -282,8 +287,8 @@ func (p *Process) Poke(addr ptrace.Word, b []byte) (int, os.Error) {
|
|||||||
return thr.Poke(addr, b);
|
return thr.Poke(addr, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Process) peekUintptr(addr ptrace.Word) ptrace.Word {
|
func (p *Process) peekUintptr(a aborter, addr ptrace.Word) ptrace.Word {
|
||||||
return ptrace.Word(mkUintptr(remote{addr, p}).(remoteUint).Get());
|
return ptrace.Word(mkUintptr(remote{addr, p}).(remoteUint).aGet(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -122,7 +122,7 @@ var prtIndent = "";
|
|||||||
|
|
||||||
// parseRemoteType parses a Type structure in a remote process to
|
// parseRemoteType parses a Type structure in a remote process to
|
||||||
// construct the corresponding interpreter type and remote type.
|
// construct the corresponding interpreter type and remote type.
|
||||||
func parseRemoteType(rs remoteStruct) *remoteType {
|
func parseRemoteType(a aborter, rs remoteStruct) *remoteType {
|
||||||
addr := rs.addr().base;
|
addr := rs.addr().base;
|
||||||
p := rs.addr().p;
|
p := rs.addr().p;
|
||||||
|
|
||||||
@ -156,17 +156,17 @@ func parseRemoteType(rs remoteStruct) *remoteType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get Type header
|
// Get Type header
|
||||||
itype := ptrace.Word(rs.Field(p.f.Type.Typ).(remoteUint).Get());
|
itype := ptrace.Word(rs.field(p.f.Type.Typ).(remoteUint).aGet(a));
|
||||||
typ := rs.Field(p.f.Type.Ptr).(remotePtr).Get().(remoteStruct);
|
typ := rs.field(p.f.Type.Ptr).(remotePtr).aGet(a).(remoteStruct);
|
||||||
|
|
||||||
// Is this a named type?
|
// Is this a named type?
|
||||||
var nt *eval.NamedType;
|
var nt *eval.NamedType;
|
||||||
uncommon := typ.Field(p.f.CommonType.UncommonType).(remotePtr).Get();
|
uncommon := typ.field(p.f.CommonType.UncommonType).(remotePtr).aGet(a);
|
||||||
if uncommon != nil {
|
if uncommon != nil {
|
||||||
name := uncommon.(remoteStruct).Field(p.f.UncommonType.Name).(remotePtr).Get();
|
name := uncommon.(remoteStruct).field(p.f.UncommonType.Name).(remotePtr).aGet(a);
|
||||||
if name != nil {
|
if name != nil {
|
||||||
// TODO(austin) Declare type in appropriate remote package
|
// TODO(austin) Declare type in appropriate remote package
|
||||||
nt = eval.NewNamedType(name.(remoteString).Get());
|
nt = eval.NewNamedType(name.(remoteString).aGet(a));
|
||||||
rt.Type = nt;
|
rt.Type = nt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -227,8 +227,8 @@ func parseRemoteType(rs remoteStruct) *remoteType {
|
|||||||
case p.runtime.PArrayType:
|
case p.runtime.PArrayType:
|
||||||
// Cast to an ArrayType
|
// Cast to an ArrayType
|
||||||
typ := p.runtime.ArrayType.mk(typ.addr()).(remoteStruct);
|
typ := p.runtime.ArrayType.mk(typ.addr()).(remoteStruct);
|
||||||
len := int64(typ.Field(p.f.ArrayType.Len).(remoteUint).Get());
|
len := int64(typ.field(p.f.ArrayType.Len).(remoteUint).aGet(a));
|
||||||
elem := parseRemoteType(typ.Field(p.f.ArrayType.Elem).(remotePtr).Get().(remoteStruct));
|
elem := parseRemoteType(a, typ.field(p.f.ArrayType.Elem).(remotePtr).aGet(a).(remoteStruct));
|
||||||
t = eval.NewArrayType(len, elem.Type);
|
t = eval.NewArrayType(len, elem.Type);
|
||||||
mk = func(r remote) eval.Value {
|
mk = func(r remote) eval.Value {
|
||||||
return remoteArray{r, len, elem};
|
return remoteArray{r, len, elem};
|
||||||
@ -237,22 +237,22 @@ func parseRemoteType(rs remoteStruct) *remoteType {
|
|||||||
case p.runtime.PStructType:
|
case p.runtime.PStructType:
|
||||||
// Cast to a StructType
|
// Cast to a StructType
|
||||||
typ := p.runtime.StructType.mk(typ.addr()).(remoteStruct);
|
typ := p.runtime.StructType.mk(typ.addr()).(remoteStruct);
|
||||||
fs := typ.Field(p.f.StructType.Fields).(remoteSlice).Get();
|
fs := typ.field(p.f.StructType.Fields).(remoteSlice).aGet(a);
|
||||||
|
|
||||||
fields := make([]eval.StructField, fs.Len);
|
fields := make([]eval.StructField, fs.Len);
|
||||||
layout := make([]remoteStructField, fs.Len);
|
layout := make([]remoteStructField, fs.Len);
|
||||||
for i := range fields {
|
for i := range fields {
|
||||||
f := fs.Base.Elem(int64(i)).(remoteStruct);
|
f := fs.Base.(remoteArray).elem(int64(i)).(remoteStruct);
|
||||||
elemrs := f.Field(p.f.StructField.Typ).(remotePtr).Get().(remoteStruct);
|
elemrs := f.field(p.f.StructField.Typ).(remotePtr).aGet(a).(remoteStruct);
|
||||||
elem := parseRemoteType(elemrs);
|
elem := parseRemoteType(a, elemrs);
|
||||||
fields[i].Type = elem.Type;
|
fields[i].Type = elem.Type;
|
||||||
name := f.Field(p.f.StructField.Name).(remotePtr).Get();
|
name := f.field(p.f.StructField.Name).(remotePtr).aGet(a);
|
||||||
if name == nil {
|
if name == nil {
|
||||||
fields[i].Anonymous = true;
|
fields[i].Anonymous = true;
|
||||||
} else {
|
} else {
|
||||||
fields[i].Name = name.(remoteString).Get();
|
fields[i].Name = name.(remoteString).aGet(a);
|
||||||
}
|
}
|
||||||
layout[i].offset = int(f.Field(p.f.StructField.Offset).(remoteUint).Get());
|
layout[i].offset = int(f.field(p.f.StructField.Offset).(remoteUint).aGet(a));
|
||||||
layout[i].fieldType = elem;
|
layout[i].fieldType = elem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,7 +264,7 @@ func parseRemoteType(rs remoteStruct) *remoteType {
|
|||||||
case p.runtime.PPtrType:
|
case p.runtime.PPtrType:
|
||||||
// Cast to a PtrType
|
// Cast to a PtrType
|
||||||
typ := p.runtime.PtrType.mk(typ.addr()).(remoteStruct);
|
typ := p.runtime.PtrType.mk(typ.addr()).(remoteStruct);
|
||||||
elem := parseRemoteType(typ.Field(p.f.PtrType.Elem).(remotePtr).Get().(remoteStruct));
|
elem := parseRemoteType(a, typ.field(p.f.PtrType.Elem).(remotePtr).aGet(a).(remoteStruct));
|
||||||
t = eval.NewPtrType(elem.Type);
|
t = eval.NewPtrType(elem.Type);
|
||||||
mk = func(r remote) eval.Value {
|
mk = func(r remote) eval.Value {
|
||||||
return remotePtr{r, elem};
|
return remotePtr{r, elem};
|
||||||
@ -273,7 +273,7 @@ func parseRemoteType(rs remoteStruct) *remoteType {
|
|||||||
case p.runtime.PSliceType:
|
case p.runtime.PSliceType:
|
||||||
// Cast to a SliceType
|
// Cast to a SliceType
|
||||||
typ := p.runtime.SliceType.mk(typ.addr()).(remoteStruct);
|
typ := p.runtime.SliceType.mk(typ.addr()).(remoteStruct);
|
||||||
elem := parseRemoteType(typ.Field(p.f.SliceType.Elem).(remotePtr).Get().(remoteStruct));
|
elem := parseRemoteType(a, typ.field(p.f.SliceType.Elem).(remotePtr).aGet(a).(remoteStruct));
|
||||||
t = eval.NewSliceType(elem.Type);
|
t = eval.NewSliceType(elem.Type);
|
||||||
mk = func(r remote) eval.Value {
|
mk = func(r remote) eval.Value {
|
||||||
return remoteSlice{r, elem};
|
return remoteSlice{r, elem};
|
||||||
@ -291,7 +291,7 @@ func parseRemoteType(rs remoteStruct) *remoteType {
|
|||||||
name = sym.Common().Name;
|
name = sym.Common().Name;
|
||||||
}
|
}
|
||||||
err := fmt.Sprintf("runtime type at %#x has unexpected type %#x (%s)", addr, itype, name);
|
err := fmt.Sprintf("runtime type at %#x has unexpected type %#x (%s)", addr, itype, name);
|
||||||
eval.Abort(FormatError(err));
|
a.Abort(FormatError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill in the remote type
|
// Fill in the remote type
|
||||||
@ -300,7 +300,7 @@ func parseRemoteType(rs remoteStruct) *remoteType {
|
|||||||
} else {
|
} else {
|
||||||
rt.Type = t;
|
rt.Type = t;
|
||||||
}
|
}
|
||||||
rt.size = int(typ.Field(p.f.CommonType.Size).(remoteUint).Get());
|
rt.size = int(typ.field(p.f.CommonType.Size).(remoteUint).aGet(a));
|
||||||
rt.mk = mk;
|
rt.mk = mk;
|
||||||
|
|
||||||
return rt;
|
return rt;
|
||||||
|
@ -7,6 +7,7 @@ package ogle
|
|||||||
import (
|
import (
|
||||||
"eval";
|
"eval";
|
||||||
"fmt";
|
"fmt";
|
||||||
|
"os";
|
||||||
"ptrace";
|
"ptrace";
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -34,7 +35,7 @@ type remote struct {
|
|||||||
p *Process;
|
p *Process;
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remote) Get(size int) uint64 {
|
func (v remote) Get(a aborter, size int) uint64 {
|
||||||
// TODO(austin) This variable might temporarily be in a
|
// TODO(austin) This variable might temporarily be in a
|
||||||
// register. We could trace the assembly back from the
|
// register. We could trace the assembly back from the
|
||||||
// current PC, looking for the beginning of the function or a
|
// current PC, looking for the beginning of the function or a
|
||||||
@ -55,18 +56,18 @@ func (v remote) Get(size int) uint64 {
|
|||||||
buf := arr[0:size];
|
buf := arr[0:size];
|
||||||
_, err := v.p.Peek(v.base, buf);
|
_, err := v.p.Peek(v.base, buf);
|
||||||
if err != nil {
|
if err != nil {
|
||||||
eval.Abort(err);
|
a.Abort(err);
|
||||||
}
|
}
|
||||||
return uint64(v.p.ToWord(buf));
|
return uint64(v.p.ToWord(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remote) Set(size int, x uint64) {
|
func (v remote) Set(a aborter, size int, x uint64) {
|
||||||
var arr [8]byte;
|
var arr [8]byte;
|
||||||
buf := arr[0:size];
|
buf := arr[0:size];
|
||||||
v.p.FromWord(ptrace.Word(x), buf);
|
v.p.FromWord(ptrace.Word(x), buf);
|
||||||
_, err := v.p.Poke(v.base, buf);
|
_, err := v.p.Poke(v.base, buf);
|
||||||
if err != nil {
|
if err != nil {
|
||||||
eval.Abort(err);
|
a.Abort(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,6 +75,15 @@ func (v remote) plus(x ptrace.Word) remote {
|
|||||||
return remote{v.base + x, v.p};
|
return remote{v.base + x, v.p};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tryRVString(f func(a aborter) string) string {
|
||||||
|
var s string;
|
||||||
|
err := try(func(a aborter) { s = f(a) });
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("<error: %v>", err);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bool
|
* Bool
|
||||||
*/
|
*/
|
||||||
@ -83,22 +93,30 @@ type remoteBool struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteBool) String() string {
|
func (v remoteBool) String() string {
|
||||||
return fmt.Sprintf("%v", v.Get());
|
return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) });
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteBool) Assign(o eval.Value) {
|
func (v remoteBool) Assign(t *eval.Thread, o eval.Value) {
|
||||||
v.Set(o.(eval.BoolValue).Get());
|
v.Set(t, o.(eval.BoolValue).Get(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteBool) Get() bool {
|
func (v remoteBool) Get(t *eval.Thread) bool {
|
||||||
return v.r.Get(1) != 0;
|
return v.aGet(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteBool) Set(x bool) {
|
func (v remoteBool) aGet(a aborter) bool {
|
||||||
|
return v.r.Get(a, 1) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v remoteBool) Set(t *eval.Thread, x bool) {
|
||||||
|
v.aSet(t, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v remoteBool) aSet(a aborter, x bool) {
|
||||||
if x {
|
if x {
|
||||||
v.r.Set(1, 1);
|
v.r.Set(a, 1, 1);
|
||||||
} else {
|
} else {
|
||||||
v.r.Set(1, 0);
|
v.r.Set(a, 1, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,19 +138,27 @@ type remoteUint struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteUint) String() string {
|
func (v remoteUint) String() string {
|
||||||
return fmt.Sprintf("%v", v.Get());
|
return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) });
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteUint) Assign(o eval.Value) {
|
func (v remoteUint) Assign(t *eval.Thread, o eval.Value) {
|
||||||
v.Set(o.(eval.UintValue).Get());
|
v.Set(t, o.(eval.UintValue).Get(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteUint) Get() uint64 {
|
func (v remoteUint) Get(t *eval.Thread) uint64 {
|
||||||
return v.r.Get(v.size);
|
return v.aGet(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteUint) Set(x uint64) {
|
func (v remoteUint) aGet(a aborter) uint64 {
|
||||||
v.r.Set(v.size, x);
|
return v.r.Get(a, v.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v remoteUint) Set(t *eval.Thread, x uint64) {
|
||||||
|
v.aSet(t, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v remoteUint) aSet(a aborter, x uint64) {
|
||||||
|
v.r.Set(a, v.size, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteUint) addr() remote {
|
func (v remoteUint) addr() remote {
|
||||||
@ -173,19 +199,27 @@ type remoteInt struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteInt) String() string {
|
func (v remoteInt) String() string {
|
||||||
return fmt.Sprintf("%v", v.Get());
|
return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) });
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteInt) Assign(o eval.Value) {
|
func (v remoteInt) Assign(t *eval.Thread, o eval.Value) {
|
||||||
v.Set(o.(eval.IntValue).Get());
|
v.Set(t, o.(eval.IntValue).Get(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteInt) Get() int64 {
|
func (v remoteInt) Get(t *eval.Thread) int64 {
|
||||||
return int64(v.r.Get(v.size));
|
return v.aGet(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteInt) Set(x int64) {
|
func (v remoteInt) aGet(a aborter) int64 {
|
||||||
v.r.Set(v.size, uint64(x));
|
return int64(v.r.Get(a, v.size));
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v remoteInt) Set(t *eval.Thread, x int64) {
|
||||||
|
v.aSet(t, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v remoteInt) aSet(a aborter, x int64) {
|
||||||
|
v.r.Set(a, v.size, uint64(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteInt) addr() remote {
|
func (v remoteInt) addr() remote {
|
||||||
@ -222,15 +256,19 @@ type remoteFloat struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteFloat) String() string {
|
func (v remoteFloat) String() string {
|
||||||
return fmt.Sprintf("%v", v.Get());
|
return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) });
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteFloat) Assign(o eval.Value) {
|
func (v remoteFloat) Assign(t *eval.Thread, o eval.Value) {
|
||||||
v.Set(o.(eval.FloatValue).Get());
|
v.Set(t, o.(eval.FloatValue).Get(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteFloat) Get() float64 {
|
func (v remoteFloat) Get(t *eval.Thread) float64 {
|
||||||
bits := v.r.Get(v.size);
|
return v.aGet(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v remoteFloat) aGet(a aborter) float64 {
|
||||||
|
bits := v.r.Get(a, v.size);
|
||||||
switch v.size {
|
switch v.size {
|
||||||
case 4:
|
case 4:
|
||||||
return float64(v.r.p.ToFloat32(uint32(bits)));
|
return float64(v.r.p.ToFloat32(uint32(bits)));
|
||||||
@ -240,7 +278,11 @@ func (v remoteFloat) Get() float64 {
|
|||||||
panic("Unexpected float size ", v.size);
|
panic("Unexpected float size ", v.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteFloat) Set(x float64) {
|
func (v remoteFloat) Set(t *eval.Thread, x float64) {
|
||||||
|
v.aSet(t, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v remoteFloat) aSet(a aborter, x float64) {
|
||||||
var bits uint64;
|
var bits uint64;
|
||||||
switch v.size{
|
switch v.size{
|
||||||
case 4:
|
case 4:
|
||||||
@ -250,7 +292,7 @@ func (v remoteFloat) Set(x float64) {
|
|||||||
default:
|
default:
|
||||||
panic("Unexpected float size ", v.size);
|
panic("Unexpected float size ", v.size);
|
||||||
}
|
}
|
||||||
v.r.Set(v.size, bits);
|
v.r.Set(a, v.size, bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteFloat) addr() remote {
|
func (v remoteFloat) addr() remote {
|
||||||
@ -278,30 +320,38 @@ type remoteString struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteString) String() string {
|
func (v remoteString) String() string {
|
||||||
return v.Get();
|
return tryRVString(func(a aborter) string { return v.aGet(a) });
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteString) Assign(o eval.Value) {
|
func (v remoteString) Assign(t *eval.Thread, o eval.Value) {
|
||||||
v.Set(o.(eval.StringValue).Get());
|
v.Set(t, o.(eval.StringValue).Get(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteString) Get() string {
|
func (v remoteString) Get(t *eval.Thread) string {
|
||||||
|
return v.aGet(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v remoteString) aGet(a aborter) string {
|
||||||
rs := v.r.p.runtime.String.mk(v.r).(remoteStruct);
|
rs := v.r.p.runtime.String.mk(v.r).(remoteStruct);
|
||||||
str := ptrace.Word(rs.Field(v.r.p.f.String.Str).(remoteUint).Get());
|
str := ptrace.Word(rs.field(v.r.p.f.String.Str).(remoteUint).aGet(a));
|
||||||
len := rs.Field(v.r.p.f.String.Len).(remoteInt).Get();
|
len := rs.field(v.r.p.f.String.Len).(remoteInt).aGet(a);
|
||||||
|
|
||||||
bytes := make([]uint8, len);
|
bytes := make([]uint8, len);
|
||||||
_, err := v.r.p.Peek(str, bytes);
|
_, err := v.r.p.Peek(str, bytes);
|
||||||
if err != nil {
|
if err != nil {
|
||||||
eval.Abort(err);
|
a.Abort(err);
|
||||||
}
|
}
|
||||||
return string(bytes);
|
return string(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteString) Set(x string) {
|
func (v remoteString) Set(t *eval.Thread, x string) {
|
||||||
|
v.aSet(t, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v remoteString) aSet(a aborter, x string) {
|
||||||
// TODO(austin) This isn't generally possible without the
|
// TODO(austin) This isn't generally possible without the
|
||||||
// ability to allocate remote memory.
|
// ability to allocate remote memory.
|
||||||
eval.Abort(RemoteMismatchError("remote strings cannot be assigned to"));
|
a.Abort(RemoteMismatchError("remote strings cannot be assigned to"));
|
||||||
}
|
}
|
||||||
|
|
||||||
func mkString(r remote) eval.Value {
|
func mkString(r remote) eval.Value {
|
||||||
@ -324,30 +374,34 @@ func (v remoteArray) String() string {
|
|||||||
if i > 0 {
|
if i > 0 {
|
||||||
res += ", ";
|
res += ", ";
|
||||||
}
|
}
|
||||||
res += v.Elem(i).String();
|
res += v.elem(i).String();
|
||||||
}
|
}
|
||||||
return res + "}";
|
return res + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteArray) Assign(o eval.Value) {
|
func (v remoteArray) Assign(t *eval.Thread, o eval.Value) {
|
||||||
// TODO(austin) Could do a bigger memcpy if o is a
|
// TODO(austin) Could do a bigger memcpy if o is a
|
||||||
// remoteArray in the same Process.
|
// remoteArray in the same Process.
|
||||||
oa := o.(eval.ArrayValue);
|
oa := o.(eval.ArrayValue);
|
||||||
for i := int64(0); i < v.len; i++ {
|
for i := int64(0); i < v.len; i++ {
|
||||||
v.Elem(i).Assign(oa.Elem(i));
|
v.Elem(t, i).Assign(t, oa.Elem(t, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteArray) Get() eval.ArrayValue {
|
func (v remoteArray) Get(t *eval.Thread) eval.ArrayValue {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteArray) Elem(i int64) eval.Value {
|
func (v remoteArray) Elem(t *eval.Thread, i int64) eval.Value {
|
||||||
|
return v.elem(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v remoteArray) elem(i int64) eval.Value {
|
||||||
return v.elemType.mk(v.r.plus(ptrace.Word(int64(v.elemType.size) * i)));
|
return v.elemType.mk(v.r.plus(ptrace.Word(int64(v.elemType.size) * i)));
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteArray) From(i int64) eval.ArrayValue {
|
func (v remoteArray) Sub(i int64, len int64) eval.ArrayValue {
|
||||||
return remoteArray{v.r.plus(ptrace.Word(int64(v.elemType.size) * i)), v.len - i, v.elemType};
|
return remoteArray{v.r.plus(ptrace.Word(int64(v.elemType.size) * i)), len, v.elemType};
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -370,25 +424,29 @@ func (v remoteStruct) String() string {
|
|||||||
if i > 0 {
|
if i > 0 {
|
||||||
res += ", ";
|
res += ", ";
|
||||||
}
|
}
|
||||||
res += v.Field(i).String();
|
res += v.field(i).String();
|
||||||
}
|
}
|
||||||
return res + "}";
|
return res + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteStruct) Assign(o eval.Value) {
|
func (v remoteStruct) Assign(t *eval.Thread, o eval.Value) {
|
||||||
// TODO(austin) Could do a bigger memcpy.
|
// TODO(austin) Could do a bigger memcpy.
|
||||||
oa := o.(eval.StructValue);
|
oa := o.(eval.StructValue);
|
||||||
l := len(v.layout);
|
l := len(v.layout);
|
||||||
for i := 0; i < l; i++ {
|
for i := 0; i < l; i++ {
|
||||||
v.Field(i).Assign(oa.Field(i));
|
v.Field(t, i).Assign(t, oa.Field(t, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteStruct) Get() eval.StructValue {
|
func (v remoteStruct) Get(t *eval.Thread) eval.StructValue {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteStruct) Field(i int) eval.Value {
|
func (v remoteStruct) Field(t *eval.Thread, i int) eval.Value {
|
||||||
|
return v.field(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v remoteStruct) field(i int) eval.Value {
|
||||||
f := &v.layout[i];
|
f := &v.layout[i];
|
||||||
return f.fieldType.mk(v.r.plus(ptrace.Word(f.offset)));
|
return f.fieldType.mk(v.r.plus(ptrace.Word(f.offset)));
|
||||||
}
|
}
|
||||||
@ -411,35 +469,45 @@ type remotePtr struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v remotePtr) String() string {
|
func (v remotePtr) String() string {
|
||||||
e := v.Get();
|
return tryRVString(func(a aborter) string {
|
||||||
if e == nil {
|
e := v.aGet(a);
|
||||||
return "<nil>";
|
if e == nil {
|
||||||
}
|
return "<nil>";
|
||||||
return "&" + e.String();
|
}
|
||||||
|
return "&" + e.String();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remotePtr) Assign(o eval.Value) {
|
func (v remotePtr) Assign(t *eval.Thread, o eval.Value) {
|
||||||
v.Set(o.(eval.PtrValue).Get());
|
v.Set(t, o.(eval.PtrValue).Get(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remotePtr) Get() eval.Value {
|
func (v remotePtr) Get(t *eval.Thread) eval.Value {
|
||||||
addr := ptrace.Word(v.r.Get(v.r.p.PtrSize()));
|
return v.aGet(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v remotePtr) aGet(a aborter) eval.Value {
|
||||||
|
addr := ptrace.Word(v.r.Get(a, v.r.p.PtrSize()));
|
||||||
if addr == 0 {
|
if addr == 0 {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
return v.elemType.mk(remote{addr, v.r.p});
|
return v.elemType.mk(remote{addr, v.r.p});
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remotePtr) Set(x eval.Value) {
|
func (v remotePtr) Set(t *eval.Thread, x eval.Value) {
|
||||||
|
v.aSet(t, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v remotePtr) aSet(a aborter, x eval.Value) {
|
||||||
if x == nil {
|
if x == nil {
|
||||||
v.r.Set(v.r.p.PtrSize(), 0);
|
v.r.Set(a, v.r.p.PtrSize(), 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
xr, ok := x.(remoteValue);
|
xr, ok := x.(remoteValue);
|
||||||
if !ok || v.r.p != xr.addr().p {
|
if !ok || v.r.p != xr.addr().p {
|
||||||
eval.Abort(RemoteMismatchError("remote pointer must point within the same process"));
|
a.Abort(RemoteMismatchError("remote pointer must point within the same process"));
|
||||||
}
|
}
|
||||||
v.r.Set(v.r.p.PtrSize(), uint64(xr.addr().base));
|
v.r.Set(a, v.r.p.PtrSize(), uint64(xr.addr().base));
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remotePtr) addr() remote {
|
func (v remotePtr) addr() remote {
|
||||||
@ -456,39 +524,49 @@ type remoteSlice struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteSlice) String() string {
|
func (v remoteSlice) String() string {
|
||||||
b := v.Get().Base;
|
return tryRVString(func(a aborter) string {
|
||||||
if b == nil {
|
b := v.aGet(a).Base;
|
||||||
return "<nil>";
|
if b == nil {
|
||||||
}
|
return "<nil>";
|
||||||
return b.String();
|
}
|
||||||
|
return b.String();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteSlice) Assign(o eval.Value) {
|
func (v remoteSlice) Assign(t *eval.Thread, o eval.Value) {
|
||||||
v.Set(o.(eval.SliceValue).Get());
|
v.Set(t, o.(eval.SliceValue).Get(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteSlice) Get() eval.Slice {
|
func (v remoteSlice) Get(t *eval.Thread) eval.Slice {
|
||||||
|
return v.aGet(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v remoteSlice) aGet(a aborter) eval.Slice {
|
||||||
rs := v.r.p.runtime.Slice.mk(v.r).(remoteStruct);
|
rs := v.r.p.runtime.Slice.mk(v.r).(remoteStruct);
|
||||||
base := ptrace.Word(rs.Field(v.r.p.f.Slice.Array).(remoteUint).Get());
|
base := ptrace.Word(rs.field(v.r.p.f.Slice.Array).(remoteUint).aGet(a));
|
||||||
nel := rs.Field(v.r.p.f.Slice.Len).(remoteInt).Get();
|
nel := rs.field(v.r.p.f.Slice.Len).(remoteInt).aGet(a);
|
||||||
cap := rs.Field(v.r.p.f.Slice.Cap).(remoteInt).Get();
|
cap := rs.field(v.r.p.f.Slice.Cap).(remoteInt).aGet(a);
|
||||||
if base == 0 {
|
if base == 0 {
|
||||||
return eval.Slice{nil, nel, cap};
|
return eval.Slice{nil, nel, cap};
|
||||||
}
|
}
|
||||||
return eval.Slice{remoteArray{remote{base, v.r.p}, nel, v.elemType}, nel, cap};
|
return eval.Slice{remoteArray{remote{base, v.r.p}, nel, v.elemType}, nel, cap};
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v remoteSlice) Set(x eval.Slice) {
|
func (v remoteSlice) Set(t *eval.Thread, x eval.Slice) {
|
||||||
|
v.aSet(t, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v remoteSlice) aSet(a aborter, x eval.Slice) {
|
||||||
rs := v.r.p.runtime.Slice.mk(v.r).(remoteStruct);
|
rs := v.r.p.runtime.Slice.mk(v.r).(remoteStruct);
|
||||||
if x.Base == nil {
|
if x.Base == nil {
|
||||||
rs.Field(v.r.p.f.Slice.Array).(remoteUint).Set(0);
|
rs.field(v.r.p.f.Slice.Array).(remoteUint).aSet(a, 0);
|
||||||
} else {
|
} else {
|
||||||
ar, ok := x.Base.(remoteArray);
|
ar, ok := x.Base.(remoteArray);
|
||||||
if !ok || v.r.p != ar.r.p {
|
if !ok || v.r.p != ar.r.p {
|
||||||
eval.Abort(RemoteMismatchError("remote slice must point within the same process"));
|
a.Abort(RemoteMismatchError("remote slice must point within the same process"));
|
||||||
}
|
}
|
||||||
rs.Field(v.r.p.f.Slice.Array).(remoteUint).Set(uint64(ar.r.base));
|
rs.field(v.r.p.f.Slice.Array).(remoteUint).aSet(a, uint64(ar.r.base));
|
||||||
}
|
}
|
||||||
rs.Field(v.r.p.f.Slice.Len).(remoteInt).Set(x.Len);
|
rs.field(v.r.p.f.Slice.Len).(remoteInt).aSet(a, x.Len);
|
||||||
rs.Field(v.r.p.f.Slice.Cap).(remoteInt).Set(x.Cap);
|
rs.field(v.r.p.f.Slice.Cap).(remoteInt).aSet(a, x.Cap);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user