class Dwarftree::DebugInfoParser
Constants
- CommandError
- ParserError
Public Class Methods
new(offset_ranges, flat:)
click to toggle source
# File lib/dwarftree/debug_info_parser.rb, line 36 def initialize(offset_ranges, flat:) @offset_die = {} # { 12345 => #<Dwarftree::DIE:* ...> } @offset_ranges = offset_ranges # { 12345 => [(12345..67890), ...] } @flat = flat end
parse(object, flat:)
click to toggle source
# File lib/dwarftree/debug_info_parser.rb, line 21 def self.parse(object, flat:) begin offset_ranges = Dwarftree::DebugRangesParser.parse(object) rescue Dwarftree::DebugRangesParser::CommandError => e raise CommandError.new(e.message) end cmd = ['objdump', '--dwarf=info', object] debug_info = IO.popen(cmd, &:read) unless $?.success? raise CommandError.new("Failed to run: #{cmd.join(' ')}") end new(offset_ranges, flat: flat).parse(debug_info) end
Public Instance Methods
parse(debug_info)
click to toggle source
@param [String] debug_info @return [Array<Dwarftree::DIE::CompileUnit>]
# File lib/dwarftree/debug_info_parser.rb, line 44 def parse(debug_info) nodes = [] each_compilation_unit(debug_info) do |compilation_unit| dies = parse_compilation_unit(compilation_unit) if @flat nodes += dies else nodes << build_tree(dies) end end nodes end
scan!(pattern)
click to toggle source
# File lib/dwarftree/debug_info_parser.rb, line 11 def scan!(pattern) scan(pattern).tap do |result| if result.nil? raise ParserError.new("Expected #{pattern.inspect} but got: #{rest}") end end end
Private Instance Methods
build_die(type, level:, offset:, attributes:)
click to toggle source
@param [String] type @param [Integer] level @param [Integer] offset @param [Hash{ Symbol => String }] attributes @return [Dwarftree::DIE::*]
# File lib/dwarftree/debug_info_parser.rb, line 112 def build_die(type, level:, offset:, attributes:) const = type.split('_').map { |s| s.sub(/\A\w/, &:upcase) }.join klass = Dwarftree::DIE.const_get(const, false) begin die = klass.new(**attributes) rescue ArgumentError $stderr.puts "Caught ArgumentError on Dwarftree::DIE::#{const}.new" raise end die.type = type die.level = level @offset_die[offset] = die end
build_tree(nodes)
click to toggle source
@param [Array<Dwarftree::DIE::*>] nodes
# File lib/dwarftree/debug_info_parser.rb, line 137 def build_tree(nodes) stack = [nodes.first] nodes.drop(1).each do |node| while stack.last.level + 1 > node.level stack.pop end if stack.last.level + 1 != node.level raise ParserError.new("unexpected node level #{node.level} against stack #{stack.last.level}") end stack.last.children << node stack.push(node) end stack.first end
each_compilation_unit(debug_info) { |dies| ... }
click to toggle source
@param [String] debug_info
# File lib/dwarftree/debug_info_parser.rb, line 60 def each_compilation_unit(debug_info) compilation_units = debug_info.split(/^ Compilation Unit @ offset 0x\h+:\n/) compilation_units.drop(1).each do |compilation_unit| dies = compilation_unit.sub!(/\A( [^:]+: [^\n]+\n)+/, '') if dies.nil? raise ParserError.new("Expected Compilation Unit to have attributes but got: #{dies}") end yield(dies) end end
each_die(dies, &block)
click to toggle source
@param [String] dies
# File lib/dwarftree/debug_info_parser.rb, line 86 def each_die(dies, &block) dies.scan(/^ <\d+><\h+>:[^\n]+\n(?: <\h+> [^\n]+\n)*/, &block) end
parse_compilation_unit(compilation_unit)
click to toggle source
@param [String] compilation_unit
# File lib/dwarftree/debug_info_parser.rb, line 72 def parse_compilation_unit(compilation_unit) dies = [] each_die(compilation_unit) do |die| if parsed = parse_die(die) dies << parsed end end dies.each do |die| resolve_references(die) die.freeze end end
parse_die(die)
click to toggle source
@param [String] die
# File lib/dwarftree/debug_info_parser.rb, line 91 def parse_die(die) scanner = StringScanner.new(die) scanner.scan!(/ <(?<level>\d+)><(?<offset>\h+)>: Abbrev Number: (\d+ \(DW_TAG_(?<type>[^\)]+)\)|0)\n/) level, offset, type = scanner[:level], scanner[:offset], scanner[:type] return nil if type.nil? attributes = {} while scanner.scan(/ <\h+> DW_AT_(?<key>[^ ]+) *:( \([^\)]+\):)? (?<value>[^\n]+)\n/) key, value = scanner[:key], scanner[:value] attributes[key.to_sym] = value end build_die(type, level: Integer(level), offset: offset.to_i(16), attributes: attributes) end
resolve_references(die)
click to toggle source
# File lib/dwarftree/debug_info_parser.rb, line 126 def resolve_references(die) if die.respond_to?(:ranges) && die[:ranges] die.ranges = @offset_ranges[die[:ranges].to_i(16)] end if die.respond_to?(:abstract_origin) && die[:abstract_origin] offset = die[:abstract_origin].match(/\A<0x(?<offset>\h+)>\z/)[:offset] die.abstract_origin = @offset_die.fetch(offset.to_i(16)) end end