示例#1
0
// makeFrameType constructs a struct type for the frame of a function.
// The offsets in this struct type are such that the struct can be
// instantiated at this function's frame pointer.
func (p *Process) makeFrameType(s *gosym.Func) (*remoteType, os.Error) {
	n := len(s.Params) + len(s.Locals)
	fields := make([]eval.StructField, n)
	layout := make([]remoteStructField, n)
	i := 0

	// TODO(austin): There can be multiple locals/parameters with
	// the same name.  We probably need liveness information to do
	// anything about this.  Once we have that, perhaps we give
	// such fields interface{} type?  Or perhaps we disambiguate
	// the names with numbers.  Disambiguation is annoying for
	// things like "i", where there's an obvious right answer.

	for _, param := range s.Params {
		rt, err := p.typeOfSym(param)
		if err != nil {
			return nil, err
		}
		if rt == nil {
			//fmt.Printf(" (no type)\n");
			continue
		}
		// TODO(austin): Why do local variables carry their
		// package name?
		fields[i].Name = param.BaseName()
		fields[i].Type = rt.Type
		// Parameters have positive offsets from FP
		layout[i].offset = int(param.Value)
		layout[i].fieldType = rt
		i++
	}

	for _, local := range s.Locals {
		rt, err := p.typeOfSym(local)
		if err != nil {
			return nil, err
		}
		if rt == nil {
			continue
		}
		fields[i].Name = local.BaseName()
		fields[i].Type = rt.Type
		// Locals have negative offsets from FP - PtrSize
		layout[i].offset = -int(local.Value) - p.PtrSize()
		layout[i].fieldType = rt
		i++
	}

	fields = fields[0:i]
	layout = layout[0:i]
	t := eval.NewStructType(fields)
	mk := func(r remote) eval.Value { return remoteStruct{r, layout} }
	return &remoteType{t, 0, 0, mk}, nil
}
示例#2
0
// parseRemoteType parses a Type structure in a remote process to
// construct the corresponding interpreter type and remote type.
func parseRemoteType(a aborter, 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.SymByAddr(uint64(addr))
		name := "<unknown>"
		if sym != nil {
			name = sym.Name
		}
		log.Stderrf("%sParsing type at %#x (%s)", prtIndent, addr, name)
		prtIndent += " "
		defer func() { prtIndent = prtIndent[0 : len(prtIndent)-1] }()
	}

	// Get Type header
	itype := proc.Word(rs.field(p.f.Type.Typ).(remoteUint).aGet(a))
	typ := rs.field(p.f.Type.Ptr).(remotePtr).aGet(a).(remoteStruct)

	// Is this a named type?
	var nt *eval.NamedType
	uncommon := typ.field(p.f.CommonType.UncommonType).(remotePtr).aGet(a)
	if uncommon != nil {
		name := uncommon.(remoteStruct).field(p.f.UncommonType.Name).(remotePtr).aGet(a)
		if name != nil {
			// TODO(austin) Declare type in appropriate remote package
			nt = eval.NewNamedType(name.(remoteString).aGet(a))
			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).aGet(a))
		elem := parseRemoteType(a, typ.field(p.f.ArrayType.Elem).(remotePtr).aGet(a).(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).aGet(a)

		fields := make([]eval.StructField, fs.Len)
		layout := make([]remoteStructField, fs.Len)
		for i := range fields {
			f := fs.Base.(remoteArray).elem(int64(i)).(remoteStruct)
			elemrs := f.field(p.f.StructField.Typ).(remotePtr).aGet(a).(remoteStruct)
			elem := parseRemoteType(a, elemrs)
			fields[i].Type = elem.Type
			name := f.field(p.f.StructField.Name).(remotePtr).aGet(a)
			if name == nil {
				fields[i].Anonymous = true
			} else {
				fields[i].Name = name.(remoteString).aGet(a)
			}
			layout[i].offset = int(f.field(p.f.StructField.Offset).(remoteUint).aGet(a))
			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(a, typ.field(p.f.PtrType.Elem).(remotePtr).aGet(a).(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(a, typ.field(p.f.SliceType.Elem).(remotePtr).aGet(a).(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.SymByAddr(uint64(itype))
		name := "<unknown symbol>"
		if sym != nil {
			name = sym.Name
		}
		err := fmt.Sprintf("runtime type at %#x has unexpected type %#x (%s)", addr, itype, name)
		a.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).aGet(a))
	rt.mk = mk

	return rt
}
示例#3
0
// populateWorld defines constants in the given world for each package
// in this process.  These packages are structs that, in turn, contain
// fields for each global and function in that package.
func (p *Process) populateWorld(w *eval.World) os.Error {
	type def struct {
		t eval.Type
		v eval.Value
	}
	packages := make(map[string]map[string]def)

	for _, s := range p.syms.Syms {
		if s.ReceiverName() != "" {
			// TODO(austin)
			continue
		}

		// Package
		pkgName := s.PackageName()
		switch pkgName {
		case "", "type", "extratype", "string", "go":
			// "go" is really "go.string"
			continue
		}
		pkg, ok := packages[pkgName]
		if !ok {
			pkg = make(map[string]def)
			packages[pkgName] = pkg
		}

		// Symbol name
		name := s.BaseName()
		if _, ok := pkg[name]; ok {
			log.Stderrf("Multiple definitions of symbol %s", s.Name)
			continue
		}

		// Symbol type
		rt, err := p.typeOfSym(&s)
		if err != nil {
			return err
		}

		// Definition
		switch s.Type {
		case 'D', 'd', 'B', 'b':
			// Global variable
			if rt == nil {
				continue
			}
			pkg[name] = def{rt.Type, rt.mk(remote{proc.Word(s.Value), p})}

		case 'T', 't', 'L', 'l':
			// Function
			s := s.Func
			// TODO(austin): Ideally, this would *also* be
			// callable.  How does that interact with type
			// conversion syntax?
			rt, err := p.makeFrameType(s)
			if err != nil {
				return err
			}
			pkg[name] = def{eval.NewPtrType(rt.Type), remoteFramePtr{p, s, rt}}
		}
	}

	// TODO(austin): Define remote types

	// Define packages
	for pkgName, defs := range packages {
		fields := make([]eval.StructField, len(defs))
		vals := make([]eval.Value, len(defs))
		i := 0
		for name, def := range defs {
			fields[i].Name = name
			fields[i].Type = def.t
			vals[i] = def.v
			i++
		}
		pkgType := eval.NewStructType(fields)
		pkgVal := remotePackage{vals}

		err := w.DefineConst(pkgName, pkgType, pkgVal)
		if err != nil {
			log.Stderrf("while defining package %s: %v", pkgName, err)
		}
	}

	return nil
}