// 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 }
// 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 }
// 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 }
// 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 } }
// 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 }
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) }