[前][次][番号順一覧][スレッド一覧]

ruby-changes:68608

From: Alan <ko1@a...>
Date: Thu, 21 Oct 2021 08:10:39 +0900 (JST)
Subject: [ruby-changes:68608] 453218b272 (master): Preliminary GNU/Linux support for code scraper

https://git.ruby-lang.org/ruby.git/commit/?id=453218b272

From 453218b272e694b10ca3ad781001600df0a1c3d9 Mon Sep 17 00:00:00 2001
From: Alan Wu <XrXr@u...>
Date: Thu, 24 Sep 2020 03:07:53 -0400
Subject: Preliminary GNU/Linux support for code scraper

Let's see if this works on CI
---
 tool/ruby_vm/models/micro_jit.rb | 82 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 77 insertions(+), 5 deletions(-)

diff --git a/tool/ruby_vm/models/micro_jit.rb b/tool/ruby_vm/models/micro_jit.rb
index eee829a2e6..61c28c84b2 100644
--- a/tool/ruby_vm/models/micro_jit.rb
+++ b/tool/ruby_vm/models/micro_jit.rb
@@ -12,6 +12,17 @@ https://github.com/ruby/ruby/blob/trunk/tool/ruby_vm/models/micro_jit.rb#L12
 
 module RubyVM::MicroJIT
   class << self
+    def target_platform
+      # Note, checking RUBY_PLATRFORM doesn't work when cross compiling
+      @platform ||= if RUBY_PLATFORM.include?('darwin')
+        :darwin
+      elsif RUBY_PLATFORM.include?('linux')
+        :linux
+      else
+        :unknown
+      end
+    end
+
     def get_fileoff
       # use the load command to figure out the offset to the start of the content of vm.o
       `otool -l vm.o`.each_line do |line|
@@ -38,16 +49,58 @@ module RubyVM::MicroJIT https://github.com/ruby/ruby/blob/trunk/tool/ruby_vm/models/micro_jit.rb#L49
       bytes.unpack('q').first #  this is native endian but we want little endian. it's fine if the host moachine is x86
     end
 
+    def get_symbol_section_and_offset(name)
+      `objdump -w -t vm.o`.each_line do |line|
+        split_line = line.split
+        next unless split_line.size >= 6
+        # the table should go into a data section
+        if split_line[5].include?('insns_address_table') && split_line[3].include?('data')
+          p line if $DEBUG
+          return [split_line[3], Integer(split_line[0], 16)]
+        end
+      end
+      raise 'Failed to find section and offset for the the instruction address table'
+    end
+
+    def get_handler_offset(table_section, table_offset, insn_id)
+      target_offset = insn_id * 8 + table_offset
+      reloc_start_message = "RELOCATION RECORDS FOR [#{table_section}]:"
+      `objdump -w -r vm.o`.each_line do |line|
+        line.strip!
+        if (line == reloc_start_message)...(line.empty?)
+          split_line = line.split
+          next if split_line.first == 'RELOCATION'
+          next if split_line == ['OFFSET', 'TYPE', 'VALUE']
+          if Integer(split_line.first, 16) == target_offset
+            section, offset = split_line[2].split('+')
+            p line if $DEBUG
+            return section, Integer(offset, 16)
+          end
+        end
+      end
+      raise 'Failed to find relocation info for the target instruction'
+    end
+
+    def objdump_disassemble_command(offset)
+      case target_platform
+      when :darwin
+        "objdump --x86-asm-syntax=intel --start-address=#{offset} --stop-address=#{offset+50} -d vm.o"
+      when :linux
+        "objdump -M intel --start-address=#{offset} --stop-address=#{offset+50} -d vm.o"
+      else
+        raise "unkown platform"
+      end
+    end
+
     def disassemble(offset)
-      command = "objdump --x86-asm-syntax=intel --start-address=#{offset} --stop-address=#{offset+50} -d vm.o"
+      command = objdump_disassemble_command(offset)
       puts "Running: #{command}"
-      puts "feel free to verify with --reloc"
       disassembly = `#{command}`
       instructions = []
       puts disassembly if $DEBUG
       disassembly.each_line do |line|
         line = line.strip
-        match_data = /\h+: ((?:\h\h\s?)+)\s+(\w+)/.match(line)
+        match_data = /\s*\h+:\s*((?:\h\h\s)+)\s+(\w+)/.match(line)
         if match_data
           bytes = match_data[1]
           mnemonic = match_data[2]
@@ -91,8 +144,7 @@ module RubyVM::MicroJIT https://github.com/ruby/ruby/blob/trunk/tool/ruby_vm/models/micro_jit.rb#L144
       end
     end
 
-    def scrape
-      instruction_id = RubyVM::Instructions.find_index { |insn| insn.name == 'ujit_call_example' }
+    def darwin_scrape(instruction_id)
       fileoff = get_fileoff
       tc_table_offset = get_symbol_offset('vm_exec_core.insns_address_table')
       vm_exec_core_offset = get_symbol_offset('vm_exec_core')
@@ -106,6 +158,26 @@ module RubyVM::MicroJIT https://github.com/ruby/ruby/blob/trunk/tool/ruby_vm/models/micro_jit.rb#L158
       disassemble(vm_exec_core_offset + offset_to_handler_code_from_vm_exec_core)
     end
 
+    def linux_scrape(instruction_id)
+      table_section, table_offset = get_symbol_section_and_offset('vm_exec_core.insns_address_table')
+      p [table_section, table_offset] if $DEBUG
+      handler_section, handler_offset = get_handler_offset(table_section, table_offset, instruction_id)
+      p [handler_section, handler_offset] if $DEBUG
+      disassemble(handler_offset)
+    end
+
+    def scrape
+      instruction_id = RubyVM::Instructions.find_index { |insn| insn.name == 'ujit_call_example' }
+      case target_platform
+      when :darwin
+        darwin_scrape(instruction_id)
+      when :linux
+        linux_scrape(instruction_id)
+      else
+        raise 'Unkonwn platform. Only Mach-O on macOS and ELF on Linux are supported'
+      end
+    end
+
     def comma_separated_hex_string(nums)
       nums.map{ |byte| '0x'+byte}.join(', ')
     end
-- 
cgit v1.2.1


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]