You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

130 lines
4.1 KiB

  1. // Copyright 2018 Google Inc. All Rights Reserved.
  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. package dwarf
  15. // This file provides simple methods to access the symbol table by name and address.
  16. import (
  17. "fmt"
  18. "regexp"
  19. "sort"
  20. )
  21. // lookupEntry returns the first Entry for the name.
  22. // If tag is non-zero, only entries with that tag are considered.
  23. func (d *Data) lookupEntry(name string, tag Tag) (*Entry, error) {
  24. x, ok := d.nameCache[name]
  25. if !ok {
  26. return nil, fmt.Errorf("DWARF entry for %q not found", name)
  27. }
  28. for ; x != nil; x = x.link {
  29. if tag == 0 || x.entry.Tag == tag {
  30. return x.entry, nil
  31. }
  32. }
  33. return nil, fmt.Errorf("no DWARF entry for %q with tag %s", name, tag)
  34. }
  35. // LookupMatchingSymbols returns the names of all top-level entries matching
  36. // the given regular expression.
  37. func (d *Data) LookupMatchingSymbols(nameRE *regexp.Regexp) (result []string, err error) {
  38. for name := range d.nameCache {
  39. if nameRE.MatchString(name) {
  40. result = append(result, name)
  41. }
  42. }
  43. return result, nil
  44. }
  45. // LookupEntry returns the Entry for the named symbol.
  46. func (d *Data) LookupEntry(name string) (*Entry, error) {
  47. return d.lookupEntry(name, 0)
  48. }
  49. // LookupFunction returns the entry for a function.
  50. func (d *Data) LookupFunction(name string) (*Entry, error) {
  51. return d.lookupEntry(name, TagSubprogram)
  52. }
  53. // LookupVariable returns the entry for a (global) variable.
  54. func (d *Data) LookupVariable(name string) (*Entry, error) {
  55. return d.lookupEntry(name, TagVariable)
  56. }
  57. // EntryLocation returns the address of the object referred to by the given Entry.
  58. func (d *Data) EntryLocation(e *Entry) (uint64, error) {
  59. loc, _ := e.Val(AttrLocation).([]byte)
  60. if len(loc) == 0 {
  61. return 0, fmt.Errorf("DWARF entry has no Location attribute")
  62. }
  63. // TODO: implement the DWARF Location bytecode. What we have here only
  64. // recognizes a program with a single literal opAddr bytecode.
  65. if asize := d.unit[0].asize; loc[0] == opAddr && len(loc) == 1+asize {
  66. switch asize {
  67. case 1:
  68. return uint64(loc[1]), nil
  69. case 2:
  70. return uint64(d.order.Uint16(loc[1:])), nil
  71. case 4:
  72. return uint64(d.order.Uint32(loc[1:])), nil
  73. case 8:
  74. return d.order.Uint64(loc[1:]), nil
  75. }
  76. }
  77. return 0, fmt.Errorf("DWARF entry has an unimplemented Location op")
  78. }
  79. // EntryType returns the Type for an Entry.
  80. func (d *Data) EntryType(e *Entry) (Type, error) {
  81. off, err := d.EntryTypeOffset(e)
  82. if err != nil {
  83. return nil, err
  84. }
  85. return d.Type(off)
  86. }
  87. // EntryTypeOffset returns the offset in the given Entry's type attribute.
  88. func (d *Data) EntryTypeOffset(e *Entry) (Offset, error) {
  89. v := e.Val(AttrType)
  90. if v == nil {
  91. return 0, fmt.Errorf("DWARF entry has no Type attribute")
  92. }
  93. off, ok := v.(Offset)
  94. if !ok {
  95. return 0, fmt.Errorf("DWARF entry has an invalid Type attribute")
  96. }
  97. return off, nil
  98. }
  99. // PCToFunction returns the entry and address for the function containing the
  100. // specified PC.
  101. func (d *Data) PCToFunction(pc uint64) (entry *Entry, lowpc uint64, err error) {
  102. p := d.pcToFuncEntries
  103. if len(p) == 0 {
  104. return nil, 0, fmt.Errorf("no function addresses loaded")
  105. }
  106. i := sort.Search(len(p), func(i int) bool { return p[i].pc > pc }) - 1
  107. // The search failed if:
  108. // - pc was before the start of any function.
  109. // - The largest function bound not larger than pc was the end of a function,
  110. // not the start of one.
  111. // - The largest function bound not larger than pc was the start of a function
  112. // that we don't know the end of, and the PC is much larger than the start.
  113. if i == -1 || p[i].entry == nil || (i+1 == len(p) && pc-p[i].pc >= 1<<20) {
  114. return nil, 0, fmt.Errorf("no function at %x", pc)
  115. }
  116. return p[i].entry, p[i].pc, nil
  117. }