// SeekToType moves the reader to the type specified by the entry, // optionally resolving typedefs and pointer types. If the reader is set // to a struct type the NextMemberVariable call can be used to walk all member data. func (reader *Reader) SeekToType(entry *dwarf.Entry, resolveTypedefs bool, resolvePointerTypes bool) (*dwarf.Entry, error) { offset, ok := entry.Val(dwarf.AttrType).(dwarf.Offset) if !ok { return nil, fmt.Errorf("entry does not have a type attribute") } // Seek to the first type offset reader.Seek(offset) // Walk the types to the base for typeEntry, err := reader.Next(); typeEntry != nil; typeEntry, err = reader.Next() { if err != nil { return nil, err } if typeEntry.Tag == dwarf.TagTypedef && !resolveTypedefs { return typeEntry, nil } if typeEntry.Tag == dwarf.TagPointerType && !resolvePointerTypes { return typeEntry, nil } offset, ok = typeEntry.Val(dwarf.AttrType).(dwarf.Offset) if !ok { return typeEntry, nil } reader.Seek(offset) } return nil, fmt.Errorf("no type entry found") }
func (d *DWARFHelper) toContentMethod(e *dwarf.Entry) (m content.Method, err error) { if v, ok := e.Val(dwarf.AttrName).(string); ok { m.Name.Relative = v } if v, ok := e.Val(dwarf.AttrType).(dwarf.Offset); ok { if t, err := d.GetType(v); err != nil { return m, err } else { m.Returns = append(m.Returns, content.Variable{Type: t}) } } else { m.Returns = append(m.Returns, content.Variable{Type: content.Type{Name: content.FullyQualifiedName{Relative: "void"}}}) } m.Flags = d.Flags(e) if !e.Children { return } r := d.df.Reader() r.Seek(e.Offset) for { e, err := r.Next() if err != nil { return m, err } else if e == nil || e.Tag == 0 { break } if e.Tag != dwarf.TagFormalParameter { continue } var p content.Variable if v, ok := e.Val(dwarf.AttrType).(dwarf.Offset); ok { if t, err := d.GetType(v); err != nil { return m, err } else { p.Type = t } } if v, ok := e.Val(dwarf.AttrName).(string); ok { p.Name.Relative = v } if v, ok := e.Val(dwarf.AttrArtificial).(bool); ok && v { if p.Type.Flags&content.FLAG_TYPE_MASK != content.FLAG_TYPE_POINTER { m.Parameters = append(m.Parameters, p) continue } // C++ "this" pointer t := p.Type.Specialization[0] if t.Flags&content.FLAG_CONST != 0 { m.Flags |= content.FLAG_CONST } //m.Name.Absolute = t.Name.Relative + "::" + m.Name.Relative } else { m.Parameters = append(m.Parameters, p) } } return }
//============================================================================ // processCompileUnit : Process a compile unit. //---------------------------------------------------------------------------- func processCompileUnit(theReader *dwarf.Reader, depth int, theEntry *dwarf.Entry) { // Process the entry gCurrentFile = theEntry.Val(dwarf.AttrName).(string) if theEntry.Children { processChildren(theReader, depth+1, false) } gCurrentFile = "" }
func (d *DWARFHelper) Flags(e *dwarf.Entry) (ret content.Flags) { if v, ok := e.Val(dwarf.AttrAccessibility).(int64); ok { switch v { case 1: ret |= content.FLAG_ACC_PUBLIC case 2: ret |= content.FLAG_ACC_PROTECTED case 3: ret |= content.FLAG_ACC_PRIVATE } } return }
//============================================================================ // processSubprogram : Process a subprogram. //---------------------------------------------------------------------------- func processSubprogram(theReader *dwarf.Reader, depth int, theEntry *dwarf.Entry) { var lowAddr uint64 var highAddr uint64 // Get the state we need lowVal := theEntry.Val(dwarf.AttrLowpc) highVal := theEntry.Val(dwarf.AttrHighpc) if lowVal != nil && highVal != nil { lowAddr = lowVal.(uint64) highAddr = highVal.(uint64) } // Check for a match if gTargetAddress >= lowAddr && gTargetAddress < highAddr { name := theEntry.Val(dwarf.AttrName) line := theEntry.Val(dwarf.AttrDeclLine) fmt.Printf("%v (%v:%v)\n", name, path.Base(gCurrentFile), line) } // Process the entry if theEntry.Children { processChildren(theReader, depth+1, false) } }
func (d *DWARFHelper) toContentField(e *dwarf.Entry) (content.Field, error) { var f content.Field if v, ok := e.Val(dwarf.AttrName).(string); ok { f.Name.Relative = v } if v, ok := e.Val(dwarf.AttrType).(dwarf.Offset); ok { if t, err := d.GetType(v); err != nil { return f, err } else { f.Type = t } } f.Flags = d.Flags(e) return f, nil }
// dwarfSourceLineEntry tries to get file/line information from a // DWARF compilation unit. Returns nil if it doesn't find anything. func (f *file) dwarfSourceLineEntry(r *dwarf.Reader, entry *dwarf.Entry, addr uint64) []plugin.Frame { lines, err := f.dwarf.LineReader(entry) if err != nil { return nil } var lentry dwarf.LineEntry if err := lines.SeekPC(addr, &lentry); err != nil { return nil } // Try to find the function name. name := "" FindName: for entry, err := r.Next(); entry != nil && err == nil; entry, err = r.Next() { if entry.Tag == dwarf.TagSubprogram { ranges, err := f.dwarf.Ranges(entry) if err != nil { return nil } for _, pcs := range ranges { if pcs[0] <= addr && addr < pcs[1] { var ok bool // TODO: AT_linkage_name, AT_MIPS_linkage_name. name, ok = entry.Val(dwarf.AttrName).(string) if ok { break FindName } } } } } // TODO: Report inlined functions. frames := []plugin.Frame{ { Func: name, File: lentry.File.Name, Line: lentry.Line, }, } return frames }
func (reader *Reader) InstructionsForEntry(entry *dwarf.Entry) ([]byte, error) { if entry.Tag == dwarf.TagMember { instructions, ok := entry.Val(dwarf.AttrDataMemberLoc).([]byte) if !ok { return nil, fmt.Errorf("member data has no data member location attribute") } // clone slice to prevent stomping on the dwarf data return append([]byte{}, instructions...), nil } // non-member instructions, ok := entry.Val(dwarf.AttrLocation).([]byte) if !ok { return nil, fmt.Errorf("entry has no location attribute") } // clone slice to prevent stomping on the dwarf data return append([]byte{}, instructions...), nil }
// Extracts the name, type, and value of a variable from a dwarf entry func (thread *Thread) extractVariableFromEntry(entry *dwarf.Entry) (*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") } data := thread.dbp.dwarf t, err := data.Type(offset) if err != nil { return nil, err } instructions, ok := entry.Val(dwarf.AttrLocation).([]byte) if !ok { return nil, fmt.Errorf("type assertion failed") } val, err := thread.extractValue(instructions, 0, t, true) if err != nil { return nil, err } return &Variable{Name: n, Type: t.String(), Value: val}, nil }
// 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 (thread *Thread) evaluateStructMember(parentEntry *dwarf.Entry, rdr *reader.Reader, memberName string) (*Variable, error) { parentAddr, err := thread.extractVariableDataAddress(parentEntry, rdr) if err != nil { return nil, err } // Get parent variable name parentName, ok := parentEntry.Val(dwarf.AttrName).(string) if !ok { return nil, fmt.Errorf("unable to retrive variable name") } // Seek reader to the type information so members can be iterated _, err = rdr.SeekToType(parentEntry, true, true) if err != nil { return nil, err } // Iterate to find member by name for memberEntry, err := rdr.NextMemberVariable(); memberEntry != nil; memberEntry, err = rdr.NextMemberVariable() { if err != nil { return nil, err } name, ok := memberEntry.Val(dwarf.AttrName).(string) if !ok { continue } if name == memberName { // Nil ptr, wait until here to throw a nil pointer error to prioritize no such member error if parentAddr == 0 { return nil, fmt.Errorf("%s is nil", parentName) } memberInstr, err := rdr.InstructionsForEntry(memberEntry) if err != nil { return nil, err } offset, ok := memberEntry.Val(dwarf.AttrType).(dwarf.Offset) if !ok { return nil, fmt.Errorf("type assertion failed") } data := thread.dbp.dwarf t, err := data.Type(offset) if err != nil { return nil, err } baseAddr := make([]byte, 8) binary.LittleEndian.PutUint64(baseAddr, uint64(parentAddr)) parentInstructions := append([]byte{op.DW_OP_addr}, baseAddr...) val, err := thread.extractValue(append(parentInstructions, memberInstr...), 0, t, true) if err != nil { return nil, err } return &Variable{Name: strings.Join([]string{parentName, memberName}, "."), Type: t.String(), Value: val}, nil } } return nil, fmt.Errorf("%s has no member %s", parentName, memberName) }