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.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.standard.yml +3 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/CONTRIBUTING.md +55 -0
- data/Gemfile +23 -0
- data/LICENSE.txt +21 -0
- data/MAINTAINERS.md +3 -0
- data/README.md +126 -0
- data/Rakefile +76 -0
- data/SECURITY.md +57 -0
- data/elf_utils.gemspec +41 -0
- data/ext/elf_utils/elf_utils.c +53 -0
- data/ext/elf_utils/extconf.rb +3 -0
- data/lib/elf_utils/elf_file.rb +312 -0
- data/lib/elf_utils/section/base.rb +77 -0
- data/lib/elf_utils/section/debug_abbrev/abbreviation.rb +171 -0
- data/lib/elf_utils/section/debug_abbrev/abbreviation_table.rb +27 -0
- data/lib/elf_utils/section/debug_abbrev.rb +15 -0
- data/lib/elf_utils/section/debug_addr.rb +9 -0
- data/lib/elf_utils/section/debug_arange.rb +54 -0
- data/lib/elf_utils/section/debug_info/compilation_unit.rb +189 -0
- data/lib/elf_utils/section/debug_info/debug_str_offsets_ref.rb +15 -0
- data/lib/elf_utils/section/debug_info/debug_str_ref.rb +17 -0
- data/lib/elf_utils/section/debug_info/die/base.rb +130 -0
- data/lib/elf_utils/section/debug_info/die.rb +470 -0
- data/lib/elf_utils/section/debug_info/die_ref.rb +22 -0
- data/lib/elf_utils/section/debug_info/header.rb +26 -0
- data/lib/elf_utils/section/debug_info.rb +93 -0
- data/lib/elf_utils/section/debug_line/line_number_program/header.rb +48 -0
- data/lib/elf_utils/section/debug_line/line_number_program/state_machine.rb +206 -0
- data/lib/elf_utils/section/debug_line/line_number_program.rb +134 -0
- data/lib/elf_utils/section/debug_line.rb +35 -0
- data/lib/elf_utils/section/debug_ranges.rb +22 -0
- data/lib/elf_utils/section/debug_str_offsets.rb +16 -0
- data/lib/elf_utils/section/dynsym.rb +14 -0
- data/lib/elf_utils/section/strtab.rb +9 -0
- data/lib/elf_utils/section/symtab.rb +11 -0
- data/lib/elf_utils/section.rb +50 -0
- data/lib/elf_utils/segment/base.rb +72 -0
- data/lib/elf_utils/segment.rb +9 -0
- data/lib/elf_utils/string_pread.rb +18 -0
- data/lib/elf_utils/symbol.rb +144 -0
- data/lib/elf_utils/types/dwarf/expression.rb +34 -0
- data/lib/elf_utils/types/dwarf.rb +639 -0
- data/lib/elf_utils/types/dwarf32/v2.rb +44 -0
- data/lib/elf_utils/types/dwarf32/v3.rb +40 -0
- data/lib/elf_utils/types/dwarf32/v4.rb +41 -0
- data/lib/elf_utils/types/dwarf32/v5.rb +44 -0
- data/lib/elf_utils/types/dwarf32.rb +12 -0
- data/lib/elf_utils/types/dwarf64/v3.rb +42 -0
- data/lib/elf_utils/types/dwarf64/v4.rb +43 -0
- data/lib/elf_utils/types/dwarf64/v5.rb +46 -0
- data/lib/elf_utils/types/dwarf64.rb +8 -0
- data/lib/elf_utils/types/sleb128.rb +66 -0
- data/lib/elf_utils/types/uleb128.rb +56 -0
- data/lib/elf_utils/types/unit_length.rb +51 -0
- data/lib/elf_utils/types.rb +328 -0
- data/lib/elf_utils/version.rb +5 -0
- data/lib/elf_utils.rb +83 -0
- data/sig/elf_utils.rbs +4 -0
- 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
|