elf_utils 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.standard.yml +3 -0
  4. data/CODE_OF_CONDUCT.md +132 -0
  5. data/CONTRIBUTING.md +55 -0
  6. data/Gemfile +23 -0
  7. data/LICENSE.txt +21 -0
  8. data/MAINTAINERS.md +3 -0
  9. data/README.md +126 -0
  10. data/Rakefile +76 -0
  11. data/SECURITY.md +57 -0
  12. data/elf_utils.gemspec +41 -0
  13. data/ext/elf_utils/elf_utils.c +53 -0
  14. data/ext/elf_utils/extconf.rb +3 -0
  15. data/lib/elf_utils/elf_file.rb +312 -0
  16. data/lib/elf_utils/section/base.rb +77 -0
  17. data/lib/elf_utils/section/debug_abbrev/abbreviation.rb +171 -0
  18. data/lib/elf_utils/section/debug_abbrev/abbreviation_table.rb +27 -0
  19. data/lib/elf_utils/section/debug_abbrev.rb +15 -0
  20. data/lib/elf_utils/section/debug_addr.rb +9 -0
  21. data/lib/elf_utils/section/debug_arange.rb +54 -0
  22. data/lib/elf_utils/section/debug_info/compilation_unit.rb +189 -0
  23. data/lib/elf_utils/section/debug_info/debug_str_offsets_ref.rb +15 -0
  24. data/lib/elf_utils/section/debug_info/debug_str_ref.rb +17 -0
  25. data/lib/elf_utils/section/debug_info/die/base.rb +130 -0
  26. data/lib/elf_utils/section/debug_info/die.rb +470 -0
  27. data/lib/elf_utils/section/debug_info/die_ref.rb +22 -0
  28. data/lib/elf_utils/section/debug_info/header.rb +26 -0
  29. data/lib/elf_utils/section/debug_info.rb +93 -0
  30. data/lib/elf_utils/section/debug_line/line_number_program/header.rb +48 -0
  31. data/lib/elf_utils/section/debug_line/line_number_program/state_machine.rb +206 -0
  32. data/lib/elf_utils/section/debug_line/line_number_program.rb +134 -0
  33. data/lib/elf_utils/section/debug_line.rb +35 -0
  34. data/lib/elf_utils/section/debug_ranges.rb +22 -0
  35. data/lib/elf_utils/section/debug_str_offsets.rb +16 -0
  36. data/lib/elf_utils/section/dynsym.rb +14 -0
  37. data/lib/elf_utils/section/strtab.rb +9 -0
  38. data/lib/elf_utils/section/symtab.rb +11 -0
  39. data/lib/elf_utils/section.rb +50 -0
  40. data/lib/elf_utils/segment/base.rb +72 -0
  41. data/lib/elf_utils/segment.rb +9 -0
  42. data/lib/elf_utils/string_pread.rb +18 -0
  43. data/lib/elf_utils/symbol.rb +144 -0
  44. data/lib/elf_utils/types/dwarf/expression.rb +34 -0
  45. data/lib/elf_utils/types/dwarf.rb +639 -0
  46. data/lib/elf_utils/types/dwarf32/v2.rb +44 -0
  47. data/lib/elf_utils/types/dwarf32/v3.rb +40 -0
  48. data/lib/elf_utils/types/dwarf32/v4.rb +41 -0
  49. data/lib/elf_utils/types/dwarf32/v5.rb +44 -0
  50. data/lib/elf_utils/types/dwarf32.rb +12 -0
  51. data/lib/elf_utils/types/dwarf64/v3.rb +42 -0
  52. data/lib/elf_utils/types/dwarf64/v4.rb +43 -0
  53. data/lib/elf_utils/types/dwarf64/v5.rb +46 -0
  54. data/lib/elf_utils/types/dwarf64.rb +8 -0
  55. data/lib/elf_utils/types/sleb128.rb +66 -0
  56. data/lib/elf_utils/types/uleb128.rb +56 -0
  57. data/lib/elf_utils/types/unit_length.rb +51 -0
  58. data/lib/elf_utils/types.rb +328 -0
  59. data/lib/elf_utils/version.rb +5 -0
  60. data/lib/elf_utils.rb +83 -0
  61. data/sig/elf_utils.rbs +4 -0
  62. metadata +120 -0
@@ -0,0 +1,144 @@
1
+ module ElfUtils
2
+ # Represents a symbol found in an ELF file.
3
+ class Symbol
4
+ # @param file [ElfFile] ElfFile that declared this symbol
5
+ # @param symbol [Integer] symbol index in symbol table
6
+ # @param strtab [Section::Strtab] string table to lookup symbol name in
7
+ # @api private
8
+ def initialize(file, symbol, strtab = file.strtab)
9
+ @file = file
10
+ @sym = symbol
11
+ @strtab = strtab
12
+ end
13
+
14
+ # @api private
15
+ attr_reader :file
16
+
17
+ # get the name of the symbol
18
+ # @return [String, nil] symbol name
19
+ def name
20
+ @name ||= @strtab[@sym.st_name]
21
+ end
22
+
23
+ # get the ELF section this symbol resides in
24
+ # @return [Section::Base]
25
+ def section
26
+ @file.sections[@sym.st_shndx]
27
+ end
28
+
29
+ # get the symbol type
30
+ # @return [Symbol] symbol type
31
+ # @see Types::Elf_Stt
32
+ def type
33
+ Types::Elf_Stt[@sym.st_info & 0xf] or
34
+ raise Error, "invalid symbol table type: %p", @sym.st_info & 0xf
35
+ end
36
+
37
+ # get the address of the symbol
38
+ #
39
+ # This method will return the address of the symbol in memory, taking into
40
+ # account any relocation performed on the section or load segment.
41
+ #
42
+ # @return [Integer] address of the symbol in memory
43
+ # @see Segment::Base#relocate
44
+ # @see Section::Base#relocate
45
+ def addr
46
+ if @sym.st_shndx == Types::SHN_COMMON
47
+ nil
48
+ elsif @sym.st_shndx == Types::SHN_ABS
49
+ @sym.st_value
50
+ elsif @file.relocatable?
51
+ @sym.st_value + section.addr
52
+ else
53
+ @sym.st_value + section.relocation_offset
54
+ end
55
+ end
56
+
57
+ # get the offset of this symbol within the ELF section
58
+ # @return [Integer] offset in bytes from the start of the ELF section
59
+ def section_offset
60
+ addr - section.addr
61
+ end
62
+
63
+ # get the size of this symbol in memory
64
+ # @return [Integer] size in bytes of this symbol
65
+ def size
66
+ @sym.st_size
67
+ end
68
+
69
+ # get the range of memory addresses this symbol occupies in memory
70
+ # @return [Range]
71
+ def to_range
72
+ addr = self.addr || 0
73
+ (addr...addr + size)
74
+ end
75
+
76
+ # get the CType datatype instance for the variable declared in this symbol
77
+ # @return [CType::Type] datatype instance
78
+ # @see https://rubydoc.info/gems/ctypes
79
+ #
80
+ # @example
81
+ # elf_file = ElfUtils.open("spec/data/complex_64be-dwarf64-v5")
82
+ # symbol = elf_file.symbol("my_tlv") # => #<ElfUtils::Symbol ...>
83
+ # ctype = symbol.ctype # => #<CTypes::Struct ... >
84
+ # tlv = ctype.unpack("\1\bhello world") # => { type: 1,
85
+ # # => len: 11,
86
+ # # => value: "hello world" }
87
+ def ctype
88
+ return nil unless type == :object && (debug_info = @file.debug_info)
89
+
90
+ name = self.name
91
+ addr = self.addr
92
+ die = debug_info.dies(top: true).find do |die|
93
+ die.tag == :variable &&
94
+ die[:name] == name &&
95
+ die.location == addr
96
+ end or return nil
97
+ die[:type]&.ctype
98
+ end
99
+
100
+ # get the source location for an :object or :func symbol
101
+ # @return [Hash<file, line>]
102
+ #
103
+ # @example
104
+ # elf_file = ElfUtils.open("spec/data/complex_64be-dwarf64-v5")
105
+ # symbol = elf_file.symbol("main") # => #<ElfUtils::Symbol ...>
106
+ # symbol.source_location # => { file: "test.c", line: 13 }
107
+ def source_location
108
+ # look up the CU die, and the die for this object
109
+ name = self.name
110
+ addr = self.addr
111
+ cu_die = nil
112
+ die = @file.debug_info
113
+ .dies(root: true, top: true)
114
+ .find do |die|
115
+ cu_die = die if die.tag == :compile_unit
116
+ die[:name] == name && die.has_addr?(addr)
117
+ end or return
118
+
119
+ # get the line number program for the compilation unit
120
+ lnp = @file
121
+ .section(".debug_line")
122
+ &.line_number_program(cu_die[:stmt_list]) or return
123
+
124
+ # based on the type of symbol, we have different ways of looking up the
125
+ # source location
126
+ case type
127
+ when :func
128
+ lnp.source_location(addr)
129
+ when :object
130
+ {
131
+ file: lnp.file_name(die[:decl_file]),
132
+ line: die[:decl_line]
133
+ }
134
+ end
135
+ end
136
+
137
+ def inspect
138
+ "<%p %-7p %-18s %s, 0x%08x>" %
139
+ [self.class, type, section&.name, name, addr]
140
+ rescue
141
+ @sym.inspect
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,34 @@
1
+ module ElfUtils
2
+ class Types::Dwarf::Expression
3
+ def initialize(cu, bytes)
4
+ @cu = cu
5
+ @bytes = bytes
6
+ end
7
+
8
+ def evaluate(addr_type:, stack: [0])
9
+ return @result if @result
10
+
11
+ buf = @bytes
12
+ until buf.empty?
13
+ op, buf = Types::Dwarf::Operation.unpack_one(buf)
14
+ case op
15
+ when :plus_uconst
16
+ a = stack.pop
17
+ b, buf = Types::ULEB128.unpack_one(buf)
18
+ stack.push(a + b)
19
+ when :addr
20
+ v, buf = addr_type.unpack_one(buf)
21
+ stack.push(v)
22
+ when :addrx
23
+ index, buf = Types::ULEB128.unpack_one(buf)
24
+ stack.push(@cu.debug_addr_get!(index))
25
+ when nil
26
+ # noop
27
+ else
28
+ raise Error, "unsupported DWARF operation: %p" % [op]
29
+ end
30
+ end
31
+ @result = stack.freeze
32
+ end
33
+ end
34
+ end