mirror of
https://github.com/golang/go
synced 2024-11-12 08:40:21 -07:00
Debugged processes, remote values, and remote type parser
R=rsc APPROVED=rsc DELTA=917 (917 added, 0 deleted, 0 changed) OCL=34049 CL=34066
This commit is contained in:
parent
0a969fa983
commit
345c1bd473
129
usr/austin/ogle/process.go
Normal file
129
usr/austin/ogle/process.go
Normal file
@ -0,0 +1,129 @@
|
||||
// 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 (
|
||||
"eval";
|
||||
"ptrace";
|
||||
"reflect";
|
||||
"os";
|
||||
"sym";
|
||||
)
|
||||
|
||||
// A FormatError indicates a failure to process information in or
|
||||
// about a remote process, such as unexpected or missing information
|
||||
// in the object file or runtime structures.
|
||||
type FormatError string
|
||||
|
||||
func (e FormatError) String() string {
|
||||
return string(e);
|
||||
}
|
||||
|
||||
// An UnknownArchitecture occurs when trying to load an object file
|
||||
// that indicates an architecture not supported by the debugger.
|
||||
type UnknownArchitecture sym.ElfMachine
|
||||
|
||||
func (e UnknownArchitecture) String() string {
|
||||
return "unknown architecture: " + sym.ElfMachine(e).String();
|
||||
}
|
||||
|
||||
// A Process represents a remote attached process.
|
||||
type Process struct {
|
||||
Arch;
|
||||
ptrace.Process;
|
||||
|
||||
// The symbol table of this process
|
||||
syms *sym.GoSymTable;
|
||||
|
||||
// Current thread
|
||||
thread ptrace.Thread;
|
||||
// Current frame, or nil if the current thread is not stopped
|
||||
frame *frame;
|
||||
|
||||
// Types parsed from the remote process
|
||||
types map[ptrace.Word] *remoteType;
|
||||
|
||||
// Types and values from the remote runtime package
|
||||
runtime runtimeValues;
|
||||
|
||||
// Runtime field indexes
|
||||
f runtimeIndexes;
|
||||
}
|
||||
|
||||
// NewProcess constructs a new remote process around a ptrace'd
|
||||
// process, an architecture, and a symbol table.
|
||||
func NewProcess(proc ptrace.Process, arch Arch, syms *sym.GoSymTable) *Process {
|
||||
p := &Process{
|
||||
Arch: arch,
|
||||
Process: proc,
|
||||
syms: syms,
|
||||
thread: proc.Threads()[0],
|
||||
types: make(map[ptrace.Word] *remoteType),
|
||||
};
|
||||
|
||||
// TODO(austin) Set p.frame if proc is stopped
|
||||
|
||||
p.bootstrap();
|
||||
return p;
|
||||
}
|
||||
|
||||
// NewProcessElf constructs a new remote process around a ptrace'd
|
||||
// process and the process' ELF object.
|
||||
func NewProcessElf(proc ptrace.Process, elf *sym.Elf) (*Process, os.Error) {
|
||||
syms, err := sym.ElfGoSyms(elf);
|
||||
if err != nil {
|
||||
return nil, err;
|
||||
}
|
||||
if syms == nil {
|
||||
return nil, FormatError("Failed to find symbol table");
|
||||
}
|
||||
var arch Arch;
|
||||
switch elf.Machine {
|
||||
case sym.ElfX86_64:
|
||||
arch = Amd64;
|
||||
default:
|
||||
return nil, UnknownArchitecture(elf.Machine);
|
||||
}
|
||||
return NewProcess(proc, arch, syms), nil;
|
||||
}
|
||||
|
||||
// bootstrap constructs the runtime structure of a remote process.
|
||||
func (p *Process) bootstrap() {
|
||||
// Manually construct runtime types
|
||||
p.runtime.String = newManualType(eval.TypeOfNative(rt1String{}), p.Arch);
|
||||
p.runtime.Slice = newManualType(eval.TypeOfNative(rt1Slice{}), p.Arch);
|
||||
p.runtime.Eface = newManualType(eval.TypeOfNative(rt1Eface{}), p.Arch);
|
||||
|
||||
p.runtime.Type = newManualType(eval.TypeOfNative(rt1Type{}), p.Arch);
|
||||
p.runtime.CommonType = newManualType(eval.TypeOfNative(rt1CommonType{}), p.Arch);
|
||||
p.runtime.UncommonType = newManualType(eval.TypeOfNative(rt1UncommonType{}), p.Arch);
|
||||
p.runtime.StructField = newManualType(eval.TypeOfNative(rt1StructField{}), p.Arch);
|
||||
p.runtime.StructType = newManualType(eval.TypeOfNative(rt1StructType{}), p.Arch);
|
||||
p.runtime.PtrType = newManualType(eval.TypeOfNative(rt1PtrType{}), p.Arch);
|
||||
p.runtime.ArrayType = newManualType(eval.TypeOfNative(rt1ArrayType{}), p.Arch);
|
||||
p.runtime.SliceType = newManualType(eval.TypeOfNative(rt1SliceType{}), p.Arch);
|
||||
|
||||
p.runtime.Stktop = newManualType(eval.TypeOfNative(rt1Stktop{}), p.Arch);
|
||||
p.runtime.Gobuf = newManualType(eval.TypeOfNative(rt1Gobuf{}), p.Arch);
|
||||
p.runtime.G = newManualType(eval.TypeOfNative(rt1G{}), p.Arch);
|
||||
|
||||
// Get addresses of type·*runtime.XType for discrimination.
|
||||
rtv := reflect.Indirect(reflect.NewValue(&p.runtime)).(*reflect.StructValue);
|
||||
rtvt := rtv.Type().(*reflect.StructType);
|
||||
for i := 0; i < rtv.NumField(); i++ {
|
||||
n := rtvt.Field(i).Name;
|
||||
if n[0] != 'P' || n[1] < 'A' || n[1] > 'Z' {
|
||||
continue;
|
||||
}
|
||||
sym := p.syms.SymFromName("type·*runtime." + n[1:len(n)]);
|
||||
if sym == nil {
|
||||
continue;
|
||||
}
|
||||
rtv.Field(i).(*reflect.Uint64Value).Set(sym.Common().Value);
|
||||
}
|
||||
|
||||
// Get field indexes
|
||||
fillRuntimeIndexes(&p.runtime, &p.f);
|
||||
}
|
306
usr/austin/ogle/rtype.go
Normal file
306
usr/austin/ogle/rtype.go
Normal file
@ -0,0 +1,306 @@
|
||||
// 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 (
|
||||
"eval";
|
||||
"fmt";
|
||||
"log";
|
||||
"ptrace";
|
||||
)
|
||||
|
||||
const debugParseRemoteType = false
|
||||
|
||||
// A remoteType is the local representation of a type in a remote process.
|
||||
type remoteType struct {
|
||||
eval.Type;
|
||||
// The size of values of this type in bytes.
|
||||
size int;
|
||||
// The field alignment of this type. Only used for
|
||||
// manually-constructed types.
|
||||
fieldAlign int;
|
||||
// The maker function to turn a remote address of a value of
|
||||
// this type into an interpreter Value.
|
||||
mk maker;
|
||||
}
|
||||
|
||||
var manualTypes = make(map[Arch] map[eval.Type] *remoteType)
|
||||
|
||||
// newManualType constructs a remote type from an interpreter Type
|
||||
// using the size and alignment properties of the given architecture.
|
||||
// Most types are parsed directly out of the remote process, but to do
|
||||
// so we need to layout the structures that describe those types ourselves.
|
||||
func newManualType(t eval.Type, arch Arch) *remoteType {
|
||||
if nt, ok := t.(*eval.NamedType); ok {
|
||||
t = nt.Def;
|
||||
}
|
||||
|
||||
// Get the type map for this architecture
|
||||
typeMap, ok := manualTypes[arch];
|
||||
if typeMap == nil {
|
||||
typeMap = make(map[eval.Type] *remoteType);
|
||||
manualTypes[arch] = typeMap;
|
||||
|
||||
// Construct basic types for this architecture
|
||||
basicType := func(t eval.Type, mk maker, size int, fieldAlign int) {
|
||||
t = t.(*eval.NamedType).Def;
|
||||
if fieldAlign == 0 {
|
||||
fieldAlign = size;
|
||||
}
|
||||
typeMap[t] = &remoteType{t, size, fieldAlign, mk};
|
||||
};
|
||||
basicType(eval.Uint8Type, mkUint8, 1, 0);
|
||||
basicType(eval.Uint32Type, mkUint32, 4, 0);
|
||||
basicType(eval.UintptrType, mkUintptr, arch.PtrSize(), 0);
|
||||
basicType(eval.Int32Type, mkInt32, 4, 0);
|
||||
basicType(eval.IntType, mkInt, arch.IntSize(), 0);
|
||||
basicType(eval.StringType, mkString, arch.PtrSize() + arch.IntSize(), arch.PtrSize());
|
||||
}
|
||||
|
||||
if rt, ok := typeMap[t]; ok {
|
||||
return rt;
|
||||
}
|
||||
|
||||
var rt *remoteType;
|
||||
switch t := t.(type) {
|
||||
case *eval.PtrType:
|
||||
var elem *remoteType;
|
||||
mk := func(r remote) eval.Value {
|
||||
return remotePtr{r, elem};
|
||||
};
|
||||
rt = &remoteType{t, arch.PtrSize(), arch.PtrSize(), mk};
|
||||
// Construct the element type after registering the
|
||||
// type to break cycles.
|
||||
typeMap[t] = rt;
|
||||
elem = newManualType(t.Elem, arch);
|
||||
|
||||
case *eval.ArrayType:
|
||||
elem := newManualType(t.Elem, arch);
|
||||
mk := func(r remote) eval.Value {
|
||||
return remoteArray{r, t.Len, elem};
|
||||
};
|
||||
rt = &remoteType{t, elem.size*int(t.Len), elem.fieldAlign, mk};
|
||||
|
||||
case *eval.SliceType:
|
||||
elem := newManualType(t.Elem, arch);
|
||||
mk := func(r remote) eval.Value {
|
||||
return remoteSlice{r, elem};
|
||||
};
|
||||
rt = &remoteType{t, arch.PtrSize() + 2*arch.IntSize(), arch.PtrSize(), mk};
|
||||
|
||||
case *eval.StructType:
|
||||
layout := make([]remoteStructField, len(t.Elems));
|
||||
offset := 0;
|
||||
fieldAlign := 0;
|
||||
for i, f := range t.Elems {
|
||||
elem := newManualType(f.Type, arch);
|
||||
if fieldAlign == 0 {
|
||||
fieldAlign = elem.fieldAlign;
|
||||
}
|
||||
offset = arch.Align(offset, elem.fieldAlign);
|
||||
layout[i].offset = offset;
|
||||
layout[i].fieldType = elem;
|
||||
offset += elem.size;
|
||||
}
|
||||
mk := func(r remote) eval.Value {
|
||||
return remoteStruct{r, layout};
|
||||
};
|
||||
rt = &remoteType{t, offset, fieldAlign, mk};
|
||||
|
||||
default:
|
||||
log.Crashf("cannot manually construct type %T", t);
|
||||
}
|
||||
|
||||
typeMap[t] = rt;
|
||||
return rt;
|
||||
}
|
||||
|
||||
var prtIndent = "";
|
||||
|
||||
// parseRemoteType parses a Type structure in a remote process to
|
||||
// construct the corresponding interpreter type and remote type.
|
||||
func parseRemoteType(rs remoteStruct) *remoteType {
|
||||
addr := rs.addr().base;
|
||||
p := rs.addr().p;
|
||||
|
||||
// We deal with circular types by discovering cycles at
|
||||
// NamedTypes. If a type cycles back to something other than
|
||||
// a named type, we're guaranteed that there will be a named
|
||||
// type somewhere in that cycle. Thus, we continue down,
|
||||
// re-parsing types until we reach the named type in the
|
||||
// cycle. In order to still create one remoteType per remote
|
||||
// type, we insert an empty remoteType in the type map the
|
||||
// first time we encounter the type and re-use that structure
|
||||
// the second time we encounter it.
|
||||
|
||||
rt, ok := p.types[addr];
|
||||
if ok && rt.Type != nil {
|
||||
return rt;
|
||||
} else if !ok {
|
||||
rt = &remoteType{};
|
||||
p.types[addr] = rt;
|
||||
}
|
||||
|
||||
if debugParseRemoteType {
|
||||
sym := p.syms.SymFromAddr(uint64(addr));
|
||||
name := "<unknown>";
|
||||
if sym != nil {
|
||||
name = sym.Common().Name;
|
||||
}
|
||||
log.Stderrf("%sParsing type at %#x (%s)", prtIndent, addr, name);
|
||||
prtIndent += " ";
|
||||
defer func() { prtIndent = prtIndent[0:len(prtIndent)-1] }();
|
||||
}
|
||||
|
||||
// Get Type header
|
||||
itype := ptrace.Word(rs.Field(p.f.Type.Typ).(remoteUint).Get());
|
||||
typ := rs.Field(p.f.Type.Ptr).(remotePtr).Get().(remoteStruct);
|
||||
|
||||
// Is this a named type?
|
||||
var nt *eval.NamedType;
|
||||
uncommon := typ.Field(p.f.CommonType.UncommonType).(remotePtr).Get();
|
||||
if uncommon != nil {
|
||||
name := uncommon.(remoteStruct).Field(p.f.UncommonType.Name).(remotePtr).Get();
|
||||
if name != nil {
|
||||
// TODO(austin) Declare type in appropriate remote package
|
||||
nt = eval.NewNamedType(name.(remoteString).Get());
|
||||
rt.Type = nt;
|
||||
}
|
||||
}
|
||||
|
||||
// Create type
|
||||
var t eval.Type;
|
||||
var mk maker;
|
||||
switch itype {
|
||||
case p.runtime.PBoolType:
|
||||
t = eval.BoolType;
|
||||
mk = mkBool;
|
||||
case p.runtime.PUint8Type:
|
||||
t = eval.Uint8Type;
|
||||
mk = mkUint8;
|
||||
case p.runtime.PUint16Type:
|
||||
t = eval.Uint16Type;
|
||||
mk = mkUint16;
|
||||
case p.runtime.PUint32Type:
|
||||
t = eval.Uint32Type;
|
||||
mk = mkUint32;
|
||||
case p.runtime.PUint64Type:
|
||||
t = eval.Uint64Type;
|
||||
mk = mkUint64;
|
||||
case p.runtime.PUintType:
|
||||
t = eval.UintType;
|
||||
mk = mkUint;
|
||||
case p.runtime.PUintptrType:
|
||||
t = eval.UintptrType;
|
||||
mk = mkUintptr;
|
||||
case p.runtime.PInt8Type:
|
||||
t = eval.Int8Type;
|
||||
mk = mkInt8;
|
||||
case p.runtime.PInt16Type:
|
||||
t = eval.Int16Type;
|
||||
mk = mkInt16;
|
||||
case p.runtime.PInt32Type:
|
||||
t = eval.Int32Type;
|
||||
mk = mkInt32;
|
||||
case p.runtime.PInt64Type:
|
||||
t = eval.Int64Type;
|
||||
mk = mkInt64;
|
||||
case p.runtime.PIntType:
|
||||
t = eval.IntType;
|
||||
mk = mkInt;
|
||||
case p.runtime.PFloat32Type:
|
||||
t = eval.Float32Type;
|
||||
mk = mkFloat32;
|
||||
case p.runtime.PFloat64Type:
|
||||
t = eval.Float64Type;
|
||||
mk = mkFloat64;
|
||||
case p.runtime.PFloatType:
|
||||
t = eval.FloatType;
|
||||
mk = mkFloat;
|
||||
case p.runtime.PStringType:
|
||||
t = eval.StringType;
|
||||
mk = mkString;
|
||||
|
||||
case p.runtime.PArrayType:
|
||||
// Cast to an ArrayType
|
||||
typ := p.runtime.ArrayType.mk(typ.addr()).(remoteStruct);
|
||||
len := int64(typ.Field(p.f.ArrayType.Len).(remoteUint).Get());
|
||||
elem := parseRemoteType(typ.Field(p.f.ArrayType.Elem).(remotePtr).Get().(remoteStruct));
|
||||
t = eval.NewArrayType(len, elem.Type);
|
||||
mk = func(r remote) eval.Value {
|
||||
return remoteArray{r, len, elem};
|
||||
};
|
||||
|
||||
case p.runtime.PStructType:
|
||||
// Cast to a StructType
|
||||
typ := p.runtime.StructType.mk(typ.addr()).(remoteStruct);
|
||||
fs := typ.Field(p.f.StructType.Fields).(remoteSlice).Get();
|
||||
|
||||
fields := make([]eval.StructField, fs.Len);
|
||||
layout := make([]remoteStructField, fs.Len);
|
||||
for i := range fields {
|
||||
f := fs.Base.Elem(int64(i)).(remoteStruct);
|
||||
elemrs := f.Field(p.f.StructField.Typ).(remotePtr).Get().(remoteStruct);
|
||||
elem := parseRemoteType(elemrs);
|
||||
fields[i].Type = elem.Type;
|
||||
name := f.Field(p.f.StructField.Name).(remotePtr).Get();
|
||||
if name == nil {
|
||||
fields[i].Anonymous = true;
|
||||
} else {
|
||||
fields[i].Name = name.(remoteString).Get();
|
||||
}
|
||||
layout[i].offset = int(f.Field(p.f.StructField.Offset).(remoteUint).Get());
|
||||
layout[i].fieldType = elem;
|
||||
}
|
||||
|
||||
t = eval.NewStructType(fields);
|
||||
mk = func(r remote) eval.Value {
|
||||
return remoteStruct{r, layout};
|
||||
};
|
||||
|
||||
case p.runtime.PPtrType:
|
||||
// Cast to a PtrType
|
||||
typ := p.runtime.PtrType.mk(typ.addr()).(remoteStruct);
|
||||
elem := parseRemoteType(typ.Field(p.f.PtrType.Elem).(remotePtr).Get().(remoteStruct));
|
||||
t = eval.NewPtrType(elem.Type);
|
||||
mk = func(r remote) eval.Value {
|
||||
return remotePtr{r, elem};
|
||||
};
|
||||
|
||||
case p.runtime.PSliceType:
|
||||
// Cast to a SliceType
|
||||
typ := p.runtime.SliceType.mk(typ.addr()).(remoteStruct);
|
||||
elem := parseRemoteType(typ.Field(p.f.SliceType.Elem).(remotePtr).Get().(remoteStruct));
|
||||
t = eval.NewSliceType(elem.Type);
|
||||
mk = func(r remote) eval.Value {
|
||||
return remoteSlice{r, elem};
|
||||
};
|
||||
|
||||
case p.runtime.PMapType, p.runtime.PChanType, p.runtime.PFuncType, p.runtime.PInterfaceType, p.runtime.PUnsafePointerType, p.runtime.PDotDotDotType:
|
||||
// TODO(austin)
|
||||
t = eval.UintptrType;
|
||||
mk = mkUintptr;
|
||||
|
||||
default:
|
||||
sym := p.syms.SymFromAddr(uint64(itype));
|
||||
name := "<unknown symbol>";
|
||||
if sym != nil {
|
||||
name = sym.Common().Name;
|
||||
}
|
||||
err := fmt.Sprintf("runtime type at %#x has unexpected type %#x (%s)", addr, itype, name);
|
||||
eval.Abort(FormatError(err));
|
||||
}
|
||||
|
||||
// Fill in the remote type
|
||||
if nt != nil {
|
||||
nt.Complete(t);
|
||||
} else {
|
||||
rt.Type = t;
|
||||
}
|
||||
rt.size = int(typ.Field(p.f.CommonType.Size).(remoteUint).Get());
|
||||
rt.mk = mk;
|
||||
|
||||
return rt;
|
||||
}
|
494
usr/austin/ogle/rvalue.go
Normal file
494
usr/austin/ogle/rvalue.go
Normal file
@ -0,0 +1,494 @@
|
||||
// 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 (
|
||||
"eval";
|
||||
"fmt";
|
||||
"ptrace";
|
||||
)
|
||||
|
||||
// A RemoteMismatchError occurs when an operation that requires two
|
||||
// identical remote processes is given different process. For
|
||||
// example, this occurs when trying to set a pointer in one process to
|
||||
// point to something in another process.
|
||||
type RemoteMismatchError string
|
||||
|
||||
func (e RemoteMismatchError) String() string {
|
||||
return string(e);
|
||||
}
|
||||
|
||||
// A maker is a function that converts a remote address into an
|
||||
// interpreter Value.
|
||||
type maker func(remote) eval.Value
|
||||
|
||||
type remoteValue interface {
|
||||
addr() remote;
|
||||
}
|
||||
|
||||
// remote represents an address in a remote process.
|
||||
type remote struct {
|
||||
base ptrace.Word;
|
||||
p *Process;
|
||||
}
|
||||
|
||||
func (v remote) Get(size int) uint64 {
|
||||
// TODO(austin) This variable might temporarily be in a
|
||||
// register. We could trace the assembly back from the
|
||||
// current PC, looking for the beginning of the function or a
|
||||
// call (both of which guarantee that the variable is in
|
||||
// memory), or an instruction that loads the variable into a
|
||||
// register.
|
||||
//
|
||||
// TODO(austin) If this is a local variable, it might not be
|
||||
// live at this PC. In fact, because the compiler reuses
|
||||
// slots, there might even be a different local variable at
|
||||
// this location right now. A simple solution to both
|
||||
// problems is to include the range of PC's over which a local
|
||||
// variable is live in the symbol table.
|
||||
//
|
||||
// TODO(austin) We need to prevent the remote garbage
|
||||
// collector from collecting objects out from under us.
|
||||
var arr [8]byte;
|
||||
buf := arr[0:size];
|
||||
_, err := v.p.thread.Peek(v.base, buf);
|
||||
if err != nil {
|
||||
eval.Abort(err);
|
||||
}
|
||||
return uint64(v.p.ToWord(buf));
|
||||
}
|
||||
|
||||
func (v remote) Set(size int, x uint64) {
|
||||
var arr [8]byte;
|
||||
buf := arr[0:size];
|
||||
v.p.FromWord(ptrace.Word(x), buf);
|
||||
_, err := v.p.thread.Poke(v.base, buf);
|
||||
if err != nil {
|
||||
eval.Abort(err);
|
||||
}
|
||||
}
|
||||
|
||||
func (v remote) plus(x ptrace.Word) remote {
|
||||
return remote{v.base + x, v.p};
|
||||
}
|
||||
|
||||
/*
|
||||
* Bool
|
||||
*/
|
||||
|
||||
type remoteBool struct {
|
||||
r remote;
|
||||
}
|
||||
|
||||
func (v remoteBool) String() string {
|
||||
return fmt.Sprintf("%v", v.Get());
|
||||
}
|
||||
|
||||
func (v remoteBool) Assign(o eval.Value) {
|
||||
v.Set(o.(eval.BoolValue).Get());
|
||||
}
|
||||
|
||||
func (v remoteBool) Get() bool {
|
||||
return v.r.Get(1) != 0;
|
||||
}
|
||||
|
||||
func (v remoteBool) Set(x bool) {
|
||||
if x {
|
||||
v.r.Set(1, 1);
|
||||
} else {
|
||||
v.r.Set(1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
func (v remoteBool) addr() remote {
|
||||
return v.r;
|
||||
}
|
||||
|
||||
func mkBool(r remote) eval.Value {
|
||||
return remoteBool{r};
|
||||
}
|
||||
|
||||
/*
|
||||
* Uint
|
||||
*/
|
||||
|
||||
type remoteUint struct {
|
||||
r remote;
|
||||
size int;
|
||||
}
|
||||
|
||||
func (v remoteUint) String() string {
|
||||
return fmt.Sprintf("%v", v.Get());
|
||||
}
|
||||
|
||||
func (v remoteUint) Assign(o eval.Value) {
|
||||
v.Set(o.(eval.UintValue).Get());
|
||||
}
|
||||
|
||||
func (v remoteUint) Get() uint64 {
|
||||
return v.r.Get(v.size);
|
||||
}
|
||||
|
||||
func (v remoteUint) Set(x uint64) {
|
||||
v.r.Set(v.size, x);
|
||||
}
|
||||
|
||||
func (v remoteUint) addr() remote {
|
||||
return v.r;
|
||||
}
|
||||
|
||||
func mkUint8(r remote) eval.Value {
|
||||
return remoteUint{r, 1};
|
||||
}
|
||||
|
||||
func mkUint16(r remote) eval.Value {
|
||||
return remoteUint{r, 2};
|
||||
}
|
||||
|
||||
func mkUint32(r remote) eval.Value {
|
||||
return remoteUint{r, 4};
|
||||
}
|
||||
|
||||
func mkUint64(r remote) eval.Value {
|
||||
return remoteUint{r, 8};
|
||||
}
|
||||
|
||||
func mkUint(r remote) eval.Value {
|
||||
return remoteUint{r, r.p.IntSize()};
|
||||
}
|
||||
|
||||
func mkUintptr(r remote) eval.Value {
|
||||
return remoteUint{r, r.p.PtrSize()};
|
||||
}
|
||||
|
||||
/*
|
||||
* Int
|
||||
*/
|
||||
|
||||
type remoteInt struct {
|
||||
r remote;
|
||||
size int;
|
||||
}
|
||||
|
||||
func (v remoteInt) String() string {
|
||||
return fmt.Sprintf("%v", v.Get());
|
||||
}
|
||||
|
||||
func (v remoteInt) Assign(o eval.Value) {
|
||||
v.Set(o.(eval.IntValue).Get());
|
||||
}
|
||||
|
||||
func (v remoteInt) Get() int64 {
|
||||
return int64(v.r.Get(v.size));
|
||||
}
|
||||
|
||||
func (v remoteInt) Set(x int64) {
|
||||
v.r.Set(v.size, uint64(x));
|
||||
}
|
||||
|
||||
func (v remoteInt) addr() remote {
|
||||
return v.r;
|
||||
}
|
||||
|
||||
func mkInt8(r remote) eval.Value {
|
||||
return remoteInt{r, 1};
|
||||
}
|
||||
|
||||
func mkInt16(r remote) eval.Value {
|
||||
return remoteInt{r, 2};
|
||||
}
|
||||
|
||||
func mkInt32(r remote) eval.Value {
|
||||
return remoteInt{r, 4};
|
||||
}
|
||||
|
||||
func mkInt64(r remote) eval.Value {
|
||||
return remoteInt{r, 8};
|
||||
}
|
||||
|
||||
func mkInt(r remote) eval.Value {
|
||||
return remoteInt{r, r.p.IntSize()};
|
||||
}
|
||||
|
||||
/*
|
||||
* Float
|
||||
*/
|
||||
|
||||
type remoteFloat struct {
|
||||
r remote;
|
||||
size int;
|
||||
}
|
||||
|
||||
func (v remoteFloat) String() string {
|
||||
return fmt.Sprintf("%v", v.Get());
|
||||
}
|
||||
|
||||
func (v remoteFloat) Assign(o eval.Value) {
|
||||
v.Set(o.(eval.FloatValue).Get());
|
||||
}
|
||||
|
||||
func (v remoteFloat) Get() float64 {
|
||||
bits := v.r.Get(v.size);
|
||||
switch v.size {
|
||||
case 4:
|
||||
return float64(v.r.p.ToFloat32(uint32(bits)));
|
||||
case 8:
|
||||
return v.r.p.ToFloat64(bits);
|
||||
}
|
||||
panic("Unexpected float size ", v.size);
|
||||
}
|
||||
|
||||
func (v remoteFloat) Set(x float64) {
|
||||
var bits uint64;
|
||||
switch v.size{
|
||||
case 4:
|
||||
bits = uint64(v.r.p.FromFloat32(float32(x)));
|
||||
case 8:
|
||||
bits = v.r.p.FromFloat64(x);
|
||||
default:
|
||||
panic("Unexpected float size ", v.size);
|
||||
}
|
||||
v.r.Set(v.size, bits);
|
||||
}
|
||||
|
||||
func (v remoteFloat) addr() remote {
|
||||
return v.r;
|
||||
}
|
||||
|
||||
func mkFloat32(r remote) eval.Value {
|
||||
return remoteFloat{r, 4};
|
||||
}
|
||||
|
||||
func mkFloat64(r remote) eval.Value {
|
||||
return remoteFloat{r, 8};
|
||||
}
|
||||
|
||||
func mkFloat(r remote) eval.Value {
|
||||
return remoteFloat{r, r.p.FloatSize()};
|
||||
}
|
||||
|
||||
/*
|
||||
* String
|
||||
*/
|
||||
|
||||
type remoteString struct {
|
||||
r remote;
|
||||
}
|
||||
|
||||
func (v remoteString) String() string {
|
||||
return v.Get();
|
||||
}
|
||||
|
||||
func (v remoteString) Assign(o eval.Value) {
|
||||
v.Set(o.(eval.StringValue).Get());
|
||||
}
|
||||
|
||||
func (v remoteString) Get() string {
|
||||
rs := v.r.p.runtime.String.mk(v.r).(remoteStruct);
|
||||
str := ptrace.Word(rs.Field(v.r.p.f.String.Str).(remoteUint).Get());
|
||||
len := rs.Field(v.r.p.f.String.Len).(remoteInt).Get();
|
||||
|
||||
bytes := make([]uint8, len);
|
||||
_, err := v.r.p.thread.Peek(str, bytes);
|
||||
if err != nil {
|
||||
eval.Abort(err);
|
||||
}
|
||||
return string(bytes);
|
||||
}
|
||||
|
||||
func (v remoteString) Set(x string) {
|
||||
// TODO(austin) This isn't generally possible without the
|
||||
// ability to allocate remote memory.
|
||||
eval.Abort(RemoteMismatchError("remote strings cannot be assigned to"));
|
||||
}
|
||||
|
||||
func mkString(r remote) eval.Value {
|
||||
return remoteString{r};
|
||||
}
|
||||
|
||||
/*
|
||||
* Array
|
||||
*/
|
||||
|
||||
type remoteArray struct {
|
||||
r remote;
|
||||
len int64;
|
||||
elemType *remoteType;
|
||||
}
|
||||
|
||||
func (v remoteArray) String() string {
|
||||
res := "{";
|
||||
for i := int64(0); i < v.len; i++ {
|
||||
if i > 0 {
|
||||
res += ", ";
|
||||
}
|
||||
res += v.Elem(i).String();
|
||||
}
|
||||
return res + "}";
|
||||
}
|
||||
|
||||
func (v remoteArray) Assign(o eval.Value) {
|
||||
// TODO(austin) Could do a bigger memcpy if o is a
|
||||
// remoteArray in the same Process.
|
||||
oa := o.(eval.ArrayValue);
|
||||
for i := int64(0); i < v.len; i++ {
|
||||
v.Elem(i).Assign(oa.Elem(i));
|
||||
}
|
||||
}
|
||||
|
||||
func (v remoteArray) Get() eval.ArrayValue {
|
||||
return v;
|
||||
}
|
||||
|
||||
func (v remoteArray) Elem(i int64) eval.Value {
|
||||
return v.elemType.mk(v.r.plus(ptrace.Word(int64(v.elemType.size) * i)));
|
||||
}
|
||||
|
||||
func (v remoteArray) From(i int64) eval.ArrayValue {
|
||||
return remoteArray{v.r.plus(ptrace.Word(int64(v.elemType.size) * i)), v.len - i, v.elemType};
|
||||
}
|
||||
|
||||
/*
|
||||
* Struct
|
||||
*/
|
||||
|
||||
type remoteStruct struct {
|
||||
r remote;
|
||||
layout []remoteStructField;
|
||||
}
|
||||
|
||||
type remoteStructField struct {
|
||||
offset int;
|
||||
fieldType *remoteType;
|
||||
}
|
||||
|
||||
func (v remoteStruct) String() string {
|
||||
res := "{";
|
||||
for i := range v.layout {
|
||||
if i > 0 {
|
||||
res += ", ";
|
||||
}
|
||||
res += v.Field(i).String();
|
||||
}
|
||||
return res + "}";
|
||||
}
|
||||
|
||||
func (v remoteStruct) Assign(o eval.Value) {
|
||||
// TODO(austin) Could do a bigger memcpy.
|
||||
oa := o.(eval.StructValue);
|
||||
l := len(v.layout);
|
||||
for i := 0; i < l; i++ {
|
||||
v.Field(i).Assign(oa.Field(i));
|
||||
}
|
||||
}
|
||||
|
||||
func (v remoteStruct) Get() eval.StructValue {
|
||||
return v;
|
||||
}
|
||||
|
||||
func (v remoteStruct) Field(i int) eval.Value {
|
||||
f := &v.layout[i];
|
||||
return f.fieldType.mk(v.r.plus(ptrace.Word(f.offset)));
|
||||
}
|
||||
|
||||
func (v remoteStruct) addr() remote {
|
||||
return v.r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pointer
|
||||
*/
|
||||
|
||||
// TODO(austin) Comparing two remote pointers for equality in the
|
||||
// interpreter will crash it because the Value's returned from
|
||||
// remotePtr.Get() will be structs.
|
||||
|
||||
type remotePtr struct {
|
||||
r remote;
|
||||
elemType *remoteType;
|
||||
}
|
||||
|
||||
func (v remotePtr) String() string {
|
||||
e := v.Get();
|
||||
if e == nil {
|
||||
return "<nil>";
|
||||
}
|
||||
return "&" + e.String();
|
||||
}
|
||||
|
||||
func (v remotePtr) Assign(o eval.Value) {
|
||||
v.Set(o.(eval.PtrValue).Get());
|
||||
}
|
||||
|
||||
func (v remotePtr) Get() eval.Value {
|
||||
addr := ptrace.Word(v.r.Get(v.r.p.PtrSize()));
|
||||
if addr == 0 {
|
||||
return nil;
|
||||
}
|
||||
return v.elemType.mk(remote{addr, v.r.p});
|
||||
}
|
||||
|
||||
func (v remotePtr) Set(x eval.Value) {
|
||||
if x == nil {
|
||||
v.r.Set(v.r.p.PtrSize(), 0);
|
||||
return;
|
||||
}
|
||||
xr, ok := x.(remoteValue);
|
||||
if !ok || v.r.p != xr.addr().p {
|
||||
eval.Abort(RemoteMismatchError("remote pointer must point within the same process"));
|
||||
}
|
||||
v.r.Set(v.r.p.PtrSize(), uint64(xr.addr().base));
|
||||
}
|
||||
|
||||
func (v remotePtr) addr() remote {
|
||||
return v.r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Slice
|
||||
*/
|
||||
|
||||
type remoteSlice struct {
|
||||
r remote;
|
||||
elemType *remoteType;
|
||||
}
|
||||
|
||||
func (v remoteSlice) String() string {
|
||||
b := v.Get().Base;
|
||||
if b == nil {
|
||||
return "<nil>";
|
||||
}
|
||||
return b.String();
|
||||
}
|
||||
|
||||
func (v remoteSlice) Assign(o eval.Value) {
|
||||
v.Set(o.(eval.SliceValue).Get());
|
||||
}
|
||||
|
||||
func (v remoteSlice) Get() eval.Slice {
|
||||
rs := v.r.p.runtime.Slice.mk(v.r).(remoteStruct);
|
||||
base := ptrace.Word(rs.Field(v.r.p.f.Slice.Array).(remoteUint).Get());
|
||||
nel := rs.Field(v.r.p.f.Slice.Len).(remoteInt).Get();
|
||||
cap := rs.Field(v.r.p.f.Slice.Cap).(remoteInt).Get();
|
||||
if base == 0 {
|
||||
return eval.Slice{nil, nel, cap};
|
||||
}
|
||||
return eval.Slice{remoteArray{remote{base, v.r.p}, nel, v.elemType}, nel, cap};
|
||||
}
|
||||
|
||||
func (v remoteSlice) Set(x eval.Slice) {
|
||||
rs := v.r.p.runtime.Slice.mk(v.r).(remoteStruct);
|
||||
if x.Base == nil {
|
||||
rs.Field(v.r.p.f.Slice.Array).(remoteUint).Set(0);
|
||||
} else {
|
||||
ar, ok := x.Base.(remoteArray);
|
||||
if !ok || v.r.p != ar.r.p {
|
||||
eval.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.Len).(remoteInt).Set(x.Len);
|
||||
rs.Field(v.r.p.f.Slice.Cap).(remoteInt).Set(x.Cap);
|
||||
}
|
Loading…
Reference in New Issue
Block a user