// Copyright 2014 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 dwarf // This file provides simple methods to access the symbol table by name and address. import ( "fmt" "regexp" "sort" ) // lookupEntry returns the first Entry for the name. // If tag is non-zero, only entries with that tag are considered. func (d *Data) lookupEntry(name string, tag Tag) (*Entry, error) { x, ok := d.nameCache[name] if !ok { return nil, fmt.Errorf("DWARF entry for %q not found", name) } for ; x != nil; x = x.link { if tag == 0 || x.entry.Tag == tag { return x.entry, nil } } return nil, fmt.Errorf("no DWARF entry for %q with tag %s", name, tag) } // LookupMatchingSymbols returns the names of all top-level entries matching // the given regular expression. func (d *Data) LookupMatchingSymbols(nameRE *regexp.Regexp) (result []string, err error) { for name := range d.nameCache { if nameRE.MatchString(name) { result = append(result, name) } } return result, nil } // LookupEntry returns the Entry for the named symbol. func (d *Data) LookupEntry(name string) (*Entry, error) { return d.lookupEntry(name, 0) } // LookupFunction returns the entry for a function. func (d *Data) LookupFunction(name string) (*Entry, error) { return d.lookupEntry(name, TagSubprogram) } // LookupVariable returns the entry for a (global) variable. func (d *Data) LookupVariable(name string) (*Entry, error) { return d.lookupEntry(name, TagVariable) } // EntryLocation returns the address of the object referred to by the given Entry. func (d *Data) EntryLocation(e *Entry) (uint64, error) { loc, _ := e.Val(AttrLocation).([]byte) if len(loc) == 0 { return 0, fmt.Errorf("DWARF entry has no Location attribute") } // TODO: implement the DWARF Location bytecode. What we have here only // recognizes a program with a single literal opAddr bytecode. if asize := d.unit[0].asize; loc[0] == opAddr && len(loc) == 1+asize { switch asize { case 1: return uint64(loc[1]), nil case 2: return uint64(d.order.Uint16(loc[1:])), nil case 4: return uint64(d.order.Uint32(loc[1:])), nil case 8: return d.order.Uint64(loc[1:]), nil } } return 0, fmt.Errorf("DWARF entry has an unimplemented Location op") } // EntryType returns the Type for an Entry. func (d *Data) EntryType(e *Entry) (Type, error) { off, err := d.EntryTypeOffset(e) if err != nil { return nil, err } return d.Type(off) } // EntryTypeOffset returns the offset in the given Entry's type attribute. func (d *Data) EntryTypeOffset(e *Entry) (Offset, error) { v := e.Val(AttrType) if v == nil { return 0, fmt.Errorf("DWARF entry has no Type attribute") } off, ok := v.(Offset) if !ok { return 0, fmt.Errorf("DWARF entry has an invalid Type attribute") } return off, nil } // PCToFunction returns the entry and address for the function containing the // specified PC. func (d *Data) PCToFunction(pc uint64) (entry *Entry, lowpc uint64, err error) { p := d.pcToFuncEntries if len(p) == 0 { return nil, 0, fmt.Errorf("no function addresses loaded") } i := sort.Search(len(p), func(i int) bool { return p[i].pc > pc }) - 1 // The search failed if: // - pc was before the start of any function. // - The largest function bound not larger than pc was the end of a function, // not the start of one. // - The largest function bound not larger than pc was the start of a function // that we don't know the end of, and the PC is much larger than the start. if i == -1 || p[i].entry == nil || (i+1 == len(p) && pc-p[i].pc >= 1<<20) { return nil, 0, fmt.Errorf("no function at %x", pc) } return p[i].entry, p[i].pc, nil }