-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
info.cr
141 lines (129 loc) · 4.07 KB
/
info.cr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
require "../dwarf"
require "./abbrev"
module Debug
module DWARF
struct Info
property unit_length : UInt32 | UInt64
property version : UInt16
property debug_abbrev_offset : UInt32 | UInt64
property address_size : UInt8
property! abbreviations : Array(Abbrev)
property dwarf64 : Bool
@offset : LibC::OffT
@ref_offset : LibC::OffT
def initialize(@io : IO::FileDescriptor, @offset)
@ref_offset = offset
@unit_length = @io.read_bytes(UInt32)
if @unit_length == 0xffffffff
@dwarf64 = true
@unit_length = @io.read_bytes(UInt64)
else
@dwarf64 = false
end
@offset = @io.tell
@version = @io.read_bytes(UInt16)
@debug_abbrev_offset = read_ulong
@address_size = @io.read_byte.not_nil!
end
alias Value = Bool | Int32 | Int64 | Slice(UInt8) | String | UInt16 | UInt32 | UInt64 | UInt8
def read_abbreviations(io)
@abbreviations = Abbrev.read(io, debug_abbrev_offset)
end
def each
end_offset = @offset + @unit_length
attributes = [] of {AT, FORM, Value}
while @io.tell < end_offset
code = DWARF.read_unsigned_leb128(@io)
attributes.clear
if abbrev = abbreviations[code - 1]? # abbreviations.find { |a| a.code == abbrev }
abbrev.attributes.each do |attr|
value = read_attribute_value(attr.form)
attributes << {attr.at, attr.form, value}
end
yield code, abbrev, attributes
else
yield code, nil, attributes
end
end
end
private def read_attribute_value(form)
case form
when FORM::Addr
case address_size
when 4 then @io.read_bytes(UInt32)
when 8 then @io.read_bytes(UInt64)
else raise "Invalid address size: #{address_size}"
end
when FORM::Block1
len = @io.read_byte.not_nil!
@io.read_fully(bytes = Bytes.new(len.to_i))
bytes
when FORM::Block2
len = @io.read_bytes(UInt16)
@io.read_fully(bytes = Bytes.new(len.to_i))
bytes
when FORM::Block4
len = @io.read_bytes(UInt32)
@io.read_fully(bytes = Bytes.new(len.to_i64))
bytes
when FORM::Block
len = DWARF.read_unsigned_leb128(@io)
@io.read_fully(bytes = Bytes.new(len))
bytes
when FORM::Data1
@io.read_byte.not_nil!
when FORM::Data2
@io.read_bytes(UInt16)
when FORM::Data4
@io.read_bytes(UInt32)
when FORM::Data8
@io.read_bytes(UInt64)
when FORM::Sdata
DWARF.read_signed_leb128(@io)
when FORM::Udata
DWARF.read_unsigned_leb128(@io)
when FORM::Exprloc
len = DWARF.read_unsigned_leb128(@io)
@io.read_fully(bytes = Bytes.new(len))
bytes
when FORM::Flag
@io.read_byte == 1
when FORM::FlagPresent
true
when FORM::SecOffset
read_ulong
when FORM::Ref1
@ref_offset + @io.read_byte.not_nil!.to_u64
when FORM::Ref2
@ref_offset + @io.read_bytes(UInt16).to_u64
when FORM::Ref4
@ref_offset + @io.read_bytes(UInt32).to_u64
when FORM::Ref8
@ref_offset + @io.read_bytes(UInt64).to_u64
when FORM::RefUdata
@ref_offset + DWARF.read_unsigned_leb128(@io)
when FORM::RefAddr
read_ulong
when FORM::RefSig8
@io.read_bytes(UInt64)
when FORM::String
@io.gets('\0').to_s.chomp('\0')
when FORM::Strp
read_ulong
when FORM::Indirect
form = FORM.new(DWARF.read_unsigned_leb128(@io))
read_attribute_value(form)
else
raise "Unknown DW_FORM_#{form.to_s.underscore}"
end
end
private def read_ulong
if @dwarf64
@io.read_bytes(UInt64)
else
@io.read_bytes(UInt32)
end
end
end
end
end