Beispiel #1
0
// Extracts the address of a variable, dereferencing any pointers
func (scope *EvalScope) extractVariableDataAddress(entry *dwarf.Entry, rdr *reader.Reader) (int64, error) {
	instructions, err := rdr.InstructionsForEntry(entry)
	if err != nil {
		return 0, err
	}

	address, err := op.ExecuteStackProgram(scope.CFA, instructions)
	if err != nil {
		return 0, err
	}

	// Dereference pointers to get down the concrete type
	for typeEntry, err := rdr.SeekToType(entry, true, false); typeEntry != nil; typeEntry, err = rdr.SeekToType(typeEntry, true, false) {
		if err != nil {
			return 0, err
		}

		if typeEntry.Tag != dwarf.TagPointerType {
			break
		}

		ptraddress := uintptr(address)

		ptr, err := scope.Thread.readMemory(ptraddress, scope.PtrSize())
		if err != nil {
			return 0, err
		}
		address = int64(binary.LittleEndian.Uint64(ptr))
	}

	return address, nil
}
Beispiel #2
0
// Returns the address for the named entry.
func (reader *Reader) AddrFor(name string) (uint64, error) {
	entry, err := reader.FindEntryNamed(name, false)
	if err != nil {
		return 0, err
	}
	instructions, ok := entry.Val(dwarf.AttrLocation).([]byte)
	if !ok {
		return 0, fmt.Errorf("type assertion failed")
	}
	addr, err := op.ExecuteStackProgram(0, instructions)
	if err != nil {
		return 0, err
	}
	return uint64(addr), nil
}
Beispiel #3
0
// Execute the stack program taking into account the current stack frame
func (thread *Thread) executeStackProgram(instructions []byte) (int64, error) {
	regs, err := thread.Registers()
	if err != nil {
		return 0, err
	}

	var cfa int64 = 0

	fde, err := thread.dbp.frameEntries.FDEForPC(regs.PC())
	if err == nil {
		fctx := fde.EstablishFrame(regs.PC())
		cfa = fctx.CFAOffset() + int64(regs.SP())
	}
	address, err := op.ExecuteStackProgram(cfa, instructions)
	if err != nil {
		return 0, err
	}
	return address, nil
}
Beispiel #4
0
// Returns the address for the named struct member. Expects the reader to be at the parent entry
// or one of the parents children, thus does not seek to parent by itself.
func (reader *Reader) AddrForMember(member string, initialInstructions []byte) (uint64, error) {
	for {
		entry, err := reader.NextMemberVariable()
		if err != nil {
			return 0, err
		}
		if entry == nil {
			return 0, fmt.Errorf("nil entry for member named %s", member)
		}
		name, ok := entry.Val(dwarf.AttrName).(string)
		if !ok || name != member {
			continue
		}
		instructions, ok := entry.Val(dwarf.AttrDataMemberLoc).([]byte)
		if !ok {
			continue
		}
		addr, err := op.ExecuteStackProgram(0, append(initialInstructions, instructions...))
		return uint64(addr), err
	}
}
Beispiel #5
0
// Extracts the name and type of a variable from a dwarf entry
// then executes the instructions given in the  DW_AT_location attribute to grab the variable's address
func (scope *EvalScope) extractVarInfoFromEntry(entry *dwarf.Entry, rdr *reader.Reader) (*Variable, error) {
	if entry == nil {
		return nil, fmt.Errorf("invalid entry")
	}

	if entry.Tag != dwarf.TagFormalParameter && entry.Tag != dwarf.TagVariable {
		return nil, fmt.Errorf("invalid entry tag, only supports FormalParameter and Variable, got %s", entry.Tag.String())
	}

	n, ok := entry.Val(dwarf.AttrName).(string)
	if !ok {
		return nil, fmt.Errorf("type assertion failed")
	}

	offset, ok := entry.Val(dwarf.AttrType).(dwarf.Offset)
	if !ok {
		return nil, fmt.Errorf("type assertion failed")
	}

	t, err := scope.Type(offset)
	if err != nil {
		return nil, err
	}

	instructions, ok := entry.Val(dwarf.AttrLocation).([]byte)
	if !ok {
		return nil, fmt.Errorf("type assertion failed")
	}

	addr, err := op.ExecuteStackProgram(scope.CFA, instructions)
	if err != nil {
		return nil, err
	}

	return scope.newVariable(n, uintptr(addr), t), nil
}
Beispiel #6
0
func (scope *EvalScope) extractValueInternal(instructions []byte, addr int64, typ interface{}, printStructName bool, recurseLevel int) (string, error) {
	var err error

	if addr == 0 {
		addr, err = op.ExecuteStackProgram(scope.CFA, instructions)
		if err != nil {
			return "", err
		}
	}

	// If we have a user defined type, find the
	// underlying concrete type and use that.
	for {
		if tt, ok := typ.(*dwarf.TypedefType); ok {
			typ = tt.Type
		} else {
			break
		}
	}

	ptraddress := uintptr(addr)
	switch t := typ.(type) {
	case *dwarf.PtrType:
		ptr, err := scope.Thread.readMemory(ptraddress, scope.PtrSize())
		if err != nil {
			return "", err
		}

		intaddr := int64(binary.LittleEndian.Uint64(ptr))
		if intaddr == 0 {
			return fmt.Sprintf("%s nil", t.String()), nil
		}

		// Don't increase the recursion level when dereferencing pointers
		val, err := scope.extractValueInternal(nil, intaddr, t.Type, printStructName, recurseLevel)
		if err != nil {
			return "", err
		}

		return fmt.Sprintf("*%s", val), nil
	case *dwarf.StructType:
		switch {
		case t.StructName == "string":
			return scope.Thread.readString(ptraddress)
		case strings.HasPrefix(t.StructName, "[]"):
			return scope.readSlice(ptraddress, t, recurseLevel)
		default:
			// Recursively call extractValue to grab
			// the value of all the members of the struct.
			if recurseLevel <= maxVariableRecurse {
				fields := make([]string, 0, len(t.Field))
				for _, field := range t.Field {
					val, err := scope.extractValueInternal(nil, field.ByteOffset+addr, field.Type, printStructName, recurseLevel+1)
					if err != nil {
						return "", err
					}

					fields = append(fields, fmt.Sprintf("%s: %s", field.Name, val))
				}
				if printStructName {
					return fmt.Sprintf("%s {%s}", t.StructName, strings.Join(fields, ", ")), nil
				}
				return fmt.Sprintf("{%s}", strings.Join(fields, ", ")), nil
			}
			// no fields
			if printStructName {
				return fmt.Sprintf("%s {...}", t.StructName), nil
			}
			return "{...}", nil
		}
	case *dwarf.ArrayType:
		return scope.readArray(ptraddress, t, recurseLevel)
	case *dwarf.ComplexType:
		return scope.Thread.readComplex(ptraddress, t.ByteSize)
	case *dwarf.IntType:
		return scope.Thread.readInt(ptraddress, t.ByteSize)
	case *dwarf.UintType:
		return scope.Thread.readUint(ptraddress, t.ByteSize)
	case *dwarf.FloatType:
		return scope.Thread.readFloat(ptraddress, t.ByteSize)
	case *dwarf.BoolType:
		return scope.Thread.readBool(ptraddress)
	case *dwarf.FuncType:
		return scope.Thread.readFunctionPtr(ptraddress)
	case *dwarf.VoidType:
		return "(void)", nil
	case *dwarf.UnspecifiedType:
		return "(unknown)", nil
	default:
		fmt.Printf("Unknown type: %T\n", t)
	}

	return "", fmt.Errorf("could not find value for type %s", typ)
}