Class: ElfUtils::Section::DebugInfo::Die
- Inherits:
-
Object
- Object
- ElfUtils::Section::DebugInfo::Die
- Defined in:
- lib/elf_utils/section/debug_info/die.rb
Defined Under Namespace
Classes: Base
Instance Attribute Summary collapse
-
#abbrev ⇒ Object
readonly
Returns the value of attribute abbrev.
-
#cu ⇒ Object
readonly
Returns the value of attribute cu.
-
#offset ⇒ Object
readonly
Returns the value of attribute offset.
-
#tag ⇒ Object
readonly
Returns the value of attribute tag.
Instance Method Summary collapse
- #[](name) ⇒ Object
- #[]=(name, value) ⇒ Object
- #add_child(child) ⇒ Object
- #addr_ranges ⇒ Object
- #attrs ⇒ Object
- #children ⇒ Object
- #children? ⇒ Boolean
- #ctype ⇒ Object
- #has_addr?(addr) ⇒ Boolean
- #has_attr?(attr) ⇒ Boolean
-
#initialize(cu:, offset:, tag:, children:, abbrev:, attrs: nil, buf: nil) ⇒ Die
constructor
A new instance of Die.
-
#location ⇒ Object
return the value of DW_AT_location.
- #pretty_print(q) ⇒ Object
-
#raw_attr(key) ⇒ Object
get the unprocessed value for an attribute.
-
#subrange_len ⇒ Object
return the number of elements in the subrange.
- #type? ⇒ Boolean
- #type_name ⇒ Object
Constructor Details
#initialize(cu:, offset:, tag:, children:, abbrev:, attrs: nil, buf: nil) ⇒ Die
Returns a new instance of Die.
5 6 7 8 9 10 11 12 13 |
# File 'lib/elf_utils/section/debug_info/die.rb', line 5 def initialize(cu:, offset:, tag:, children:, abbrev:, attrs: nil, buf: nil) @cu = cu @offset = offset @tag = tag @children = children ? [] : false @abbrev = abbrev @unpacked_attrs = attrs @buf = buf end |
Instance Attribute Details
#abbrev ⇒ Object (readonly)
Returns the value of attribute abbrev.
14 15 16 |
# File 'lib/elf_utils/section/debug_info/die.rb', line 14 def abbrev @abbrev end |
#cu ⇒ Object (readonly)
Returns the value of attribute cu.
14 15 16 |
# File 'lib/elf_utils/section/debug_info/die.rb', line 14 def cu @cu end |
#offset ⇒ Object (readonly)
Returns the value of attribute offset.
14 15 16 |
# File 'lib/elf_utils/section/debug_info/die.rb', line 14 def offset @offset end |
#tag ⇒ Object (readonly)
Returns the value of attribute tag.
14 15 16 |
# File 'lib/elf_utils/section/debug_info/die.rb', line 14 def tag @tag end |
Instance Method Details
#[](name) ⇒ Object
89 90 91 92 |
# File 'lib/elf_utils/section/debug_info/die.rb', line 89 def [](name) @attrs ||= parse_attrs @attrs[name] end |
#[]=(name, value) ⇒ Object
94 95 96 97 |
# File 'lib/elf_utils/section/debug_info/die.rb', line 94 def []=(name, value) @attrs ||= parse_attrs @attrs[name] = value end |
#add_child(child) ⇒ Object
65 66 67 68 69 |
# File 'lib/elf_utils/section/debug_info/die.rb', line 65 def add_child(child) raise Error, "This DIE cannot have children" unless @children @children << child self end |
#addr_ranges ⇒ Object
112 113 114 115 116 117 118 119 120 121 |
# File 'lib/elf_utils/section/debug_info/die.rb', line 112 def addr_ranges @attrs ||= parse_attrs @addr_ranges ||= if (low = @attrs[:low_pc]) && (high = @attrs[:high_pc]) [low..(high - 1)] elsif @attrs[:ranges] @cu.file.section(".debug_ranges") .get(offset: @attrs[:ranges], base: @attrs[:low] || 0) end end |
#attrs ⇒ Object
99 100 101 102 |
# File 'lib/elf_utils/section/debug_info/die.rb', line 99 def attrs @attrs ||= parse_attrs @attrs.keys end |
#children ⇒ Object
57 58 59 |
# File 'lib/elf_utils/section/debug_info/die.rb', line 57 def children @children || [] end |
#children? ⇒ Boolean
53 54 55 |
# File 'lib/elf_utils/section/debug_info/die.rb', line 53 def children? @children != false end |
#ctype ⇒ Object
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 |
# File 'lib/elf_utils/section/debug_info/die.rb', line 226 def ctype return unless type? return @ctype if @ctype @attrs ||= parse_attrs @ctype = case tag when :base_type signed = !@attrs[:encoding].to_s.include?("unsigned") int_type(size: @attrs[:byte_size], signed:) when :typedef @attrs[:type].ctype when :const_type, :volatile_type # const void has no equivalent ctype... maybe empty struct? @attrs[:type]&.ctype when :pointer_type, :subroutine_type @cu.addr_type when :array_type # subrange_len may return nil for variable-length arrays sizes = children .select { |c| c.tag == :subrange_type } .map { |c| c.subrange_len } # if we have a signed char array, we'll use a string to hold it inner_type = @attrs[:type].ctype if inner_type.is_a?(CTypes::Int) && inner_type.size == 1 && inner_type.signed? inner_type = CTypes::String.new(size: sizes.pop) end sizes.reverse_each do |size| inner_type = CTypes::Array.new(type: inner_type, size:) end inner_type when :structure_type offset = 0 struct = CTypes::Struct.builder .name(self[:name]) .endian(@endian ||= @cu.file.endian) bitfield = nil (@children || []).each do |child| next unless child.tag == :member name = child[:name]&.to_sym type = child[:type].ctype loc = child[:data_member_location] || 0 if loc.is_a?(Types::Dwarf::Expression) child[:data_member_location] = loc = loc.evaluate(addr_type: @cu.addr_type)[0] end delta = loc - offset # add any bitfield if we're moving past it if bitfield && delta >= 0 struct.attribute bitfield.build bitfield = nil end # handle any padding we need to do struct.pad delta if delta > 0 # check for v2, v3 bitfield if (bits = child[:bit_size]) && (bit_offset = child[:bit_offset]) bitfield ||= CTypes::Bitfield.builder.endian(@endian) # convert the left-hand offset to a right-hand offset when we're # on a little-endian system if CTypes.host_endian == :little bit_offset = child[:byte_size] * 8 - bit_offset - bits end bitfield.field(name, offset: bit_offset, bits: bits, signed: type.signed?) # v4, v5 bitfield elsif (bits = child[:bit_size]) && (bit_offset = child[:data_bit_offset]) bitfield ||= CTypes::Bitfield.builder.endian(@endian) # If the endian of the type doesn't match the host-endian, we # need to flip the offset if @endian != CTypes.host_endian bit_offset = self[:byte_size] * 8 - bit_offset - bits end bitfield.field(name, offset: bit_offset, bits: bits, signed: type.signed?) # not a bitfield elsif name.nil? # handle unnamed field struct.attribute type # must be a named field else struct.attribute name, type end offset = loc + type.size end # if there's tail padding to fit a specific alignment, add it here tail = self[:byte_size] - offset struct.pad(tail) if tail > 0 # ensure we include the bitfield if it was the last element struct.attribute(bitfield.build) if bitfield struct.build when :union_type union = CTypes::Union.builder .name(self[:name]) .endian(@endian ||= @cu.file.endian) (@children || []).each do |child| next unless child.tag == :member name = child[:name] type = child[:type].ctype if name union.member name.to_sym, type else union.member type end end union.build when :enumeration_type type = int_type(size: @attrs[:byte_size], signed: false) values = {} @children.each do |child| values[child[:name].downcase.to_sym] = child[:const_value] end CTypes::Enum.new(type.with_endian(@cu.file.endian), values) when :subrange_type return else raise Error, "unsupported DIE: %p" % [self] end end |
#has_addr?(addr) ⇒ Boolean
123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/elf_utils/section/debug_info/die.rb', line 123 def has_addr?(addr) case tag when :subprogram addr_ranges&.any? { |r| r.include?(addr) } when :variable type = self[:type].ctype [location...location + type.size] else false end end |
#has_attr?(attr) ⇒ Boolean
61 62 63 |
# File 'lib/elf_utils/section/debug_info/die.rb', line 61 def has_attr?(attr) @attrs ? @attrs.has_key?(attr) : @abbrev.attrs.has_key?(attr) end |
#location ⇒ Object
return the value of DW_AT_location
166 167 168 169 170 171 172 173 |
# File 'lib/elf_utils/section/debug_info/die.rb', line 166 def location value = self[:location] if value.is_a?(Types::Dwarf::Expression) value = value.evaluate(addr_type: cu.addr_type, stack: [])[-1] end value end |
#pretty_print(q) ⇒ Object
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 |
# File 'lib/elf_utils/section/debug_info/die.rb', line 16 def pretty_print(q) q.group(4, "<%p 0x%08x: DW_TAG_%s (%d children)" % [self.class, @offset, @tag, @children ? @children.size : 0], ">") do q.text("\n" + " " * q.indent) q.group_sub do attrs = if @attrs @attrs.map do |name, value| ["DW_AT_%-15s " % [name], value] end elsif @unpacked_attrs @unpacked_attrs.map do |name, form, value| ["DW_AT_%-15s [DW_FORM_%s] " % [name, form], value] end end if attrs q.seplist(attrs) do |label, value| q.group(4, label) do case value when self.class q.text("<%p 0x%08x: DW_TAG_%s ...>" % [self.class, value.offset, value.tag]) else q.pp(value) end end end else q.group(1, "abbrev=") { q.pp(@abbrev) } end end end end |
#raw_attr(key) ⇒ Object
get the unprocessed value for an attribute
105 106 107 108 109 110 |
# File 'lib/elf_utils/section/debug_info/die.rb', line 105 def raw_attr(key) unpacked_attrs.each do |name, _, value| return value if name == key end raise Error, "no attribute %p found in DIE: %p" % [key, self] end |
#subrange_len ⇒ Object
return the number of elements in the subrange
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/elf_utils/section/debug_info/die.rb', line 136 def subrange_len @attrs ||= parse_attrs raise "not a subrange DIE: %p" % [self] unless @tag == :subrange_type count = @attrs[:count] case count when Integer return count when Section::DebugInfo::Die # return a size of nil for variable-length array return nil if count.tag == :variable raise ElfUtils::Error, "unexpected DIE type in subrange[:count]: %p" % [count] when nil # fall through when there is no count attribute else raise ElfUtils::Error, "unexpected value in subrange[:count]: %p" % [count] end # upper bound may be DW_TAG_variable, so special handling if (upper_bound = @attrs[:upper_bound]) return @attrs[:upper_bound] + 1 if upper_bound.is_a?(Integer) end # XXX we'll need to do some work to support flexible array members 0 end |
#type? ⇒ Boolean
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/elf_utils/section/debug_info/die.rb', line 71 def type? @is_a_type ||= case @tag when :base_type, :typedef, :volatile_type, :const_type, :pointer_type, :array_type, :union_type, :enumeration_type, :structure_type, :subroutine_type true else false end end |
#type_name ⇒ Object
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
# File 'lib/elf_utils/section/debug_info/die.rb', line 175 def type_name return nil unless type? @type_name ||= begin @attrs ||= parse_attrs case @tag when :base_type, :typedef @attrs[:name] when :volatile_type "volatile #{@attrs[:type]&.type_name || "void"}" when :const_type "const #{@attrs[:type]&.type_name || "void"}" when :array_type buf = "#{@attrs[:type]&.type_name}" sizes = children.each do |child| next unless child.tag == :subrange_type # subrange_len may return nil for variable-length arrays len = child.subrange_len if len buf << "[%d]" % len else buf << "[]" end end buf when :pointer_type inner = @attrs[:type]&.type_name || "void" if inner.end_with?("*") "#{inner}*" else "#{inner} *" end when :structure_type name = @attrs[:name] || ("anon_%x" % @offset) "struct #{name}" when :union_type name = @attrs[:name] || ("anon_%x" % @offset) "union #{name}" when :enumeration_type name = @attrs[:name] || ("anon_%x" % @offset) "enum #{name}" when :subrange_type, :subroutine_type return else raise Error, "unsupported DIE: %p" % [self] end end end |