1// Copyright 2019 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package dwarf 16 17// This file provides simple methods to access the symbol table by name and address. 18 19import ( 20 "fmt" 21 "regexp" 22 "sort" 23) 24 25// lookupEntry returns the first Entry for the name. 26// If tag is non-zero, only entries with that tag are considered. 27func (d *Data) lookupEntry(name string, tag Tag) (*Entry, error) { 28 x, ok := d.nameCache[name] 29 if !ok { 30 return nil, fmt.Errorf("DWARF entry for %q not found", name) 31 } 32 for ; x != nil; x = x.link { 33 if tag == 0 || x.entry.Tag == tag { 34 return x.entry, nil 35 } 36 } 37 return nil, fmt.Errorf("no DWARF entry for %q with tag %s", name, tag) 38} 39 40// LookupMatchingSymbols returns the names of all top-level entries matching 41// the given regular expression. 42func (d *Data) LookupMatchingSymbols(nameRE *regexp.Regexp) (result []string, err error) { 43 for name := range d.nameCache { 44 if nameRE.MatchString(name) { 45 result = append(result, name) 46 } 47 } 48 return result, nil 49} 50 51// LookupEntry returns the Entry for the named symbol. 52func (d *Data) LookupEntry(name string) (*Entry, error) { 53 return d.lookupEntry(name, 0) 54} 55 56// LookupFunction returns the entry for a function. 57func (d *Data) LookupFunction(name string) (*Entry, error) { 58 return d.lookupEntry(name, TagSubprogram) 59} 60 61// LookupVariable returns the entry for a (global) variable. 62func (d *Data) LookupVariable(name string) (*Entry, error) { 63 return d.lookupEntry(name, TagVariable) 64} 65 66// EntryLocation returns the address of the object referred to by the given Entry. 67func (d *Data) EntryLocation(e *Entry) (uint64, error) { 68 loc, _ := e.Val(AttrLocation).([]byte) 69 if len(loc) == 0 { 70 return 0, fmt.Errorf("DWARF entry has no Location attribute") 71 } 72 // TODO: implement the DWARF Location bytecode. What we have here only 73 // recognizes a program with a single literal opAddr bytecode. 74 if asize := d.unit[0].asize; loc[0] == opAddr && len(loc) == 1+asize { 75 switch asize { 76 case 1: 77 return uint64(loc[1]), nil 78 case 2: 79 return uint64(d.order.Uint16(loc[1:])), nil 80 case 4: 81 return uint64(d.order.Uint32(loc[1:])), nil 82 case 8: 83 return d.order.Uint64(loc[1:]), nil 84 } 85 } 86 return 0, fmt.Errorf("DWARF entry has an unimplemented Location op") 87} 88 89// EntryType returns the Type for an Entry. 90func (d *Data) EntryType(e *Entry) (Type, error) { 91 off, err := d.EntryTypeOffset(e) 92 if err != nil { 93 return nil, err 94 } 95 return d.Type(off) 96} 97 98// EntryTypeOffset returns the offset in the given Entry's type attribute. 99func (d *Data) EntryTypeOffset(e *Entry) (Offset, error) { 100 v := e.Val(AttrType) 101 if v == nil { 102 return 0, fmt.Errorf("DWARF entry has no Type attribute") 103 } 104 off, ok := v.(Offset) 105 if !ok { 106 return 0, fmt.Errorf("DWARF entry has an invalid Type attribute") 107 } 108 return off, nil 109} 110 111// PCToFunction returns the entry and address for the function containing the 112// specified PC. 113func (d *Data) PCToFunction(pc uint64) (entry *Entry, lowpc uint64, err error) { 114 p := d.pcToFuncEntries 115 if len(p) == 0 { 116 return nil, 0, fmt.Errorf("no function addresses loaded") 117 } 118 i := sort.Search(len(p), func(i int) bool { return p[i].pc > pc }) - 1 119 // The search failed if: 120 // - pc was before the start of any function. 121 // - The largest function bound not larger than pc was the end of a function, 122 // not the start of one. 123 // - The largest function bound not larger than pc was the start of a function 124 // that we don't know the end of, and the PC is much larger than the start. 125 if i == -1 || p[i].entry == nil || (i+1 == len(p) && pc-p[i].pc >= 1<<20) { 126 return nil, 0, fmt.Errorf("no function at %x", pc) 127 } 128 return p[i].entry, p[i].pc, nil 129} 130