summaryrefslogtreecommitdiff
path: root/misc
diff options
context:
space:
mode:
Diffstat (limited to 'misc')
-rw-r--r--misc/.vscode/settings.json8
-rw-r--r--misc/call_fuzzer.rb372
-rwxr-xr-xmisc/call_fuzzer.sh13
-rwxr-xr-xmisc/expand_tabs.rb34
-rwxr-xr-xmisc/jit_perf.py116
-rw-r--r--[-rwxr-xr-x]misc/lldb_cruby.py24
-rw-r--r--misc/lldb_rb/commands/heap_page_command.py5
-rw-r--r--misc/lldb_rb/commands/print_flags_command.py6
-rw-r--r--misc/lldb_rb/lldb_interface.py11
-rw-r--r--misc/lldb_rb/rb_heap_structs.py19
-rw-r--r--misc/lldb_rb/utils.py500
-rw-r--r--misc/lldb_yjit.py47
-rw-r--r--misc/ruby-style.el15
-rw-r--r--misc/tsan_suppressions.txt109
14 files changed, 931 insertions, 348 deletions
diff --git a/misc/.vscode/settings.json b/misc/.vscode/settings.json
index 7b1a38c536..a2e4e1ec69 100644
--- a/misc/.vscode/settings.json
+++ b/misc/.vscode/settings.json
@@ -2,7 +2,9 @@
"rust-analyzer.cargo.features": [
"disasm",
],
- "rust-analyzer.cargo.unsetTest": [
- "yjit",
- ],
+ "rust-analyzer.cfg.setTest": false,
+ // rust-analyzer bundled in the VSCode extension may only support Rust newer than 1.85.0.
+ // To avoid warnings, install rust-analyzer with `rustup component add rust-analyzer` and
+ // use `~/.cargo/bin/rust-analyzer` with the following config.
+ "rust-analyzer.server.path": "rust-analyzer",
}
diff --git a/misc/call_fuzzer.rb b/misc/call_fuzzer.rb
new file mode 100644
index 0000000000..c3f9f90490
--- /dev/null
+++ b/misc/call_fuzzer.rb
@@ -0,0 +1,372 @@
+require 'optparse'
+require 'set'
+
+# Number of iterations to test
+num_iters = 10_000
+
+# Parse the command-line options
+OptionParser.new do |opts|
+ opts.on("--num-iters=N") do |n|
+ num_iters = n.to_i
+ end
+end.parse!
+
+# Format large numbers with comma separators for readability
+def format_number(pad, number)
+ s = number.to_s
+ i = s.index('.') || s.size
+ s.insert(i -= 3, ',') while i > 3
+ s.rjust(pad, ' ')
+end
+
+# Wrap an integer to pass as argument
+# We use this so we can have some object arguments
+class IntWrapper
+ def initialize(v)
+ # Force the object to have a random shape
+ if rand() < 50
+ @v0 = 1
+ end
+ if rand() < 50
+ @v1 = 1
+ end
+ if rand() < 50
+ @v2 = 1
+ end
+ if rand() < 50
+ @v3 = 1
+ end
+ if rand() < 50
+ @v4 = 1
+ end
+ if rand() < 50
+ @v5 = 1
+ end
+ if rand() < 50
+ @v6 = 1
+ end
+
+ @value = v
+ end
+
+ attr_reader :value
+end
+
+# Generate a random argument value, integer or string or object
+def sample_arg()
+ c = ['int', 'string', 'object'].sample()
+
+ if c == 'int'
+ return rand(0...100)
+ end
+
+ if c == 'string'
+ return 'f' * rand(0...100)
+ end
+
+ if c == 'object'
+ return IntWrapper.new(rand(0...100))
+ end
+
+ raise "should not get here"
+end
+
+# Evaluate the value of an argument with respect to the checksum
+def arg_val(arg)
+ if arg.kind_of? Integer
+ return arg
+ end
+
+ if arg.kind_of? String
+ return arg.length
+ end
+
+ if arg.kind_of? Object
+ return arg.value
+ end
+
+ raise "unknown arg type"
+end
+
+# List of parameters/arguments for a method
+class ParamList
+ def initialize()
+ self.sample_params()
+ self.sample_args()
+ end
+
+ # Sample/generate a random set of parameters for a method
+ def sample_params()
+ # Choose how many positional arguments to use, and how many are optional
+ num_pargs = rand(10)
+ @opt_parg_idx = rand(num_pargs)
+ @num_opt_pargs = rand(num_pargs + 1 - @opt_parg_idx)
+ @num_pargs_req = num_pargs - @num_opt_pargs
+ @pargs = (0...num_pargs).map do |i|
+ {
+ :name => "p#{i}",
+ :optional => (i >= @opt_parg_idx && i < @opt_parg_idx + @num_opt_pargs)
+ }
+ end
+
+ # Choose how many kwargs to use, and how many are optional
+ num_kwargs = rand(10)
+ @kwargs = (0...num_kwargs).map do |i|
+ {
+ :name => "k#{i}",
+ :optional => rand() < 0.5
+ }
+ end
+
+ # Choose whether to have rest parameters or not
+ @has_rest = @num_opt_pargs == 0 && rand() < 0.5
+ @has_kwrest = rand() < 0.25
+
+ # Choose whether to have a named block parameter or not
+ @has_block_param = rand() < 0.25
+ end
+
+ # Sample/generate a random set of arguments corresponding to the parameters
+ def sample_args()
+ # Choose how many positional args to pass
+ num_pargs_passed = rand(@num_pargs_req..@pargs.size)
+
+ # How many optional arguments will be filled
+ opt_pargs_filled = num_pargs_passed - @num_pargs_req
+
+ @pargs.each_with_index do |parg, i|
+ if parg[:optional]
+ parg[:default] = rand(100)
+ end
+
+ if !parg[:optional] || i < @opt_parg_idx + opt_pargs_filled
+ parg[:argval] = rand(100)
+ end
+ end
+
+ @kwargs.each_with_index do |kwarg, i|
+ if kwarg[:optional]
+ kwarg[:default] = rand(100)
+ end
+
+ if !kwarg[:optional] || rand() < 0.5
+ kwarg[:argval] = rand(100)
+ end
+ end
+
+ # Randomly pass a block or not
+ @block_arg = nil
+ if rand() < 0.5
+ @block_arg = rand(100)
+ end
+ end
+
+ # Compute the expected checksum of arguments ahead of time
+ def compute_checksum()
+ checksum = 0
+
+ @pargs.each_with_index do |arg, i|
+ value = (arg.key? :argval)? arg[:argval]:arg[:default]
+ checksum += (i+1) * arg_val(value)
+ end
+
+ @kwargs.each_with_index do |arg, i|
+ value = (arg.key? :argval)? arg[:argval]:arg[:default]
+ checksum += (i+1) * arg_val(value)
+ end
+
+ if @block_arg
+ if @has_block_param
+ checksum += arg_val(@block_arg)
+ end
+
+ checksum += arg_val(@block_arg)
+ end
+
+ checksum
+ end
+
+ # Generate code for the method signature and method body
+ def gen_method_str()
+ m_str = "def m("
+
+ @pargs.each do |arg|
+ if !m_str.end_with?("(")
+ m_str += ", "
+ end
+
+ m_str += arg[:name]
+
+ # If this has a default value
+ if arg[:optional]
+ m_str += " = #{arg[:default]}"
+ end
+ end
+
+ if @has_rest
+ if !m_str.end_with?("(")
+ m_str += ", "
+ end
+ m_str += "*rest"
+ end
+
+ @kwargs.each do |arg|
+ if !m_str.end_with?("(")
+ m_str += ", "
+ end
+
+ m_str += "#{arg[:name]}:"
+
+ # If this has a default value
+ if arg[:optional]
+ m_str += " #{arg[:default]}"
+ end
+ end
+
+ if @has_kwrest
+ if !m_str.end_with?("(")
+ m_str += ", "
+ end
+ m_str += "**kwrest"
+ end
+
+ if @has_block_param
+ if !m_str.end_with?("(")
+ m_str += ", "
+ end
+
+ m_str += "&block"
+ end
+
+ m_str += ")\n"
+
+ # Add some useless locals
+ rand(0...16).times do |i|
+ m_str += "local#{i} = #{i}\n"
+ end
+
+ # Add some useless if statements
+ @pargs.each_with_index do |arg, i|
+ if rand() < 50
+ m_str += "if #{arg[:name]} > 4; end\n"
+ end
+ end
+
+ m_str += "checksum = 0\n"
+
+ @pargs.each_with_index do |arg, i|
+ m_str += "checksum += #{i+1} * arg_val(#{arg[:name]})\n"
+ end
+
+ @kwargs.each_with_index do |arg, i|
+ m_str += "checksum += #{i+1} * arg_val(#{arg[:name]})\n"
+ end
+
+ if @has_block_param
+ m_str += "if block; r = block.call; checksum += arg_val(r); end\n"
+ end
+
+ m_str += "if block_given?; r = yield; checksum += arg_val(r); end\n"
+
+ if @has_rest
+ m_str += "raise 'rest is not array' unless rest.kind_of?(Array)\n"
+ m_str += "raise 'rest size not integer' unless rest.size.kind_of?(Integer)\n"
+ end
+
+ if @has_kwrest
+ m_str += "raise 'kwrest is not a hash' unless kwrest.kind_of?(Hash)\n"
+ m_str += "raise 'kwrest size not integer' unless kwrest.size.kind_of?(Integer)\n"
+ end
+
+ m_str += "checksum\n"
+ m_str += "end"
+
+ m_str
+ end
+
+ # Generate code to call into the method and pass the arguments
+ def gen_call_str()
+ c_str = "m("
+
+ @pargs.each_with_index do |arg, i|
+ if !arg.key? :argval
+ next
+ end
+
+ if !c_str.end_with?("(")
+ c_str += ", "
+ end
+
+ c_str += "#{arg[:argval]}"
+ end
+
+ @kwargs.each_with_index do |arg, i|
+ if !arg.key? :argval
+ next
+ end
+
+ if !c_str.end_with?("(")
+ c_str += ", "
+ end
+
+ c_str += "#{arg[:name]}: #{arg[:argval]}"
+ end
+
+ c_str += ")"
+
+ # Randomly pass a block or not
+ if @block_arg
+ c_str += " { #{@block_arg} }"
+ end
+
+ c_str
+ end
+end
+
+iseqs_compiled_start = RubyVM::YJIT.runtime_stats[:compiled_iseq_entry]
+start_time = Time.now.to_f
+
+num_iters.times do |i|
+ puts "Iteration #{i}"
+
+ lst = ParamList.new()
+ m_str = lst.gen_method_str()
+ c_str = lst.gen_call_str()
+ checksum = lst.compute_checksum()
+
+ f = Object.new
+
+ # Define the method on f
+ puts "Defining"
+ p m_str
+ f.instance_eval(m_str)
+ #puts RubyVM::InstructionSequence.disasm(f.method(:m))
+ #exit 0
+
+ puts "Calling"
+ c_str = "f.#{c_str}"
+ p c_str
+ r = eval(c_str)
+ puts "checksum=#{r}"
+
+ if r != checksum
+ raise "return value #{r} doesn't match checksum #{checksum}"
+ end
+
+ puts ""
+end
+
+# Make sure that YJIT actually compiled the tests we ran
+# Should be run with --yjit-call-threshold=1
+iseqs_compiled_end = RubyVM::YJIT.runtime_stats[:compiled_iseq_entry]
+if iseqs_compiled_end - iseqs_compiled_start < num_iters
+ raise "YJIT did not compile enough ISEQs"
+end
+
+puts "Code region size: #{ format_number(0, RubyVM::YJIT.runtime_stats[:code_region_size]) }"
+
+end_time = Time.now.to_f
+itrs_per_sec = num_iters / (end_time - start_time)
+itrs_per_hour = 3600 * itrs_per_sec
+puts "#{'%.1f' % itrs_per_sec} iterations/s"
+puts "#{format_number(0, itrs_per_hour.round)} iterations/hour"
diff --git a/misc/call_fuzzer.sh b/misc/call_fuzzer.sh
new file mode 100755
index 0000000000..cf4ec76fe8
--- /dev/null
+++ b/misc/call_fuzzer.sh
@@ -0,0 +1,13 @@
+# Stop at first error
+set -e
+
+# TODO
+# TODO: boost --num-iters to 1M+ for actual test
+# TODO
+export NUM_ITERS=25000
+
+# Enable code GC so we don't stop compiling when we hit the code size limit
+ruby --yjit-call-threshold=1 --yjit-code-gc misc/call_fuzzer.rb --num-iters=$NUM_ITERS
+
+# Do another pass with --verify-ctx
+ruby --yjit-call-threshold=1 --yjit-code-gc --yjit-verify-ctx misc/call_fuzzer.rb --num-iters=$NUM_ITERS
diff --git a/misc/expand_tabs.rb b/misc/expand_tabs.rb
index a94eea5046..d26568eefc 100755
--- a/misc/expand_tabs.rb
+++ b/misc/expand_tabs.rb
@@ -59,53 +59,31 @@ class Git
end
DEFAULT_GEM_LIBS = %w[
- abbrev
- base64
- benchmark
bundler
- cmath
- csv
- debug
delegate
did_you_mean
- drb
english
erb
+ error_highlight
fileutils
find
forwardable
- getoptlong
ipaddr
- irb
- logger
- mutex_m
net-http
net-protocol
- observer
open3
open-uri
optparse
ostruct
pp
prettyprint
- prime
- pstore
- rdoc
- readline
- reline
+ prism
resolv
- resolv-replace
- rexml
- rinda
- rss
rubygems
- scanf
securerandom
- set
shellwords
singleton
tempfile
- thwait
time
timeout
tmpdir
@@ -117,27 +95,19 @@ DEFAULT_GEM_LIBS = %w[
]
DEFAULT_GEM_EXTS = %w[
- bigdecimal
- cgi
date
digest
etc
fcntl
- fiddle
io-console
io-nonblock
io-wait
json
- nkf
openssl
pathname
psych
- racc
- readline-ext
stringio
strscan
- syslog
- win32ole
zlib
]
diff --git a/misc/jit_perf.py b/misc/jit_perf.py
new file mode 100755
index 0000000000..bc0f961b20
--- /dev/null
+++ b/misc/jit_perf.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env python3
+import os
+import sys
+from collections import Counter, defaultdict
+import os.path
+
+# Aggregating cycles per symbol and dso
+total_cycles = 0
+category_cycles = Counter()
+detailed_category_cycles = defaultdict(Counter)
+categories = set()
+
+def truncate_symbol(symbol, max_length=50):
+ """ Truncate the symbol name to a maximum length """
+ return symbol if len(symbol) <= max_length else symbol[:max_length-3] + '...'
+
+def categorize_symbol(dso, symbol):
+ """ Categorize the symbol based on the defined criteria """
+ if dso == 'sqlite3_native.so':
+ return '[sqlite3]'
+ elif 'SHA256' in symbol:
+ return '[sha256]'
+ elif symbol.startswith('[JIT] gen_send'):
+ return '[JIT send]'
+ elif symbol.startswith('[JIT]') or symbol.startswith('ZJIT: ') or dso.startswith('perf-'):
+ return '[JIT code]'
+ elif '::' in symbol or symbol.startswith('_ZN4yjit') or symbol.startswith('_ZN4zjit'):
+ return '[JIT compile]'
+ elif symbol.startswith('rb_vm_') or symbol.startswith('vm_') or symbol in {
+ "rb_call0", "callable_method_entry_or_negative", "invoke_block_from_c_bh",
+ "rb_funcallv_scope", "setup_parameters_complex", "rb_yield"}:
+ return '[interpreter]'
+ elif symbol.startswith('rb_hash_') or symbol.startswith('hash_'):
+ return '[rb_hash_*]'
+ elif symbol.startswith('rb_ary_') or symbol.startswith('ary_'):
+ return '[rb_ary_*]'
+ elif symbol.startswith('rb_str_') or symbol.startswith('str_'):
+ return '[rb_str_*]'
+ elif symbol.startswith('rb_sym') or symbol.startswith('sym_'):
+ return '[rb_sym_*]'
+ elif symbol.startswith('rb_st_') or symbol.startswith('st_'):
+ return '[rb_st_*]'
+ elif symbol.startswith('rb_ivar_') or 'shape' in symbol:
+ return '[ivars]'
+ elif 'match' in symbol or symbol.startswith('rb_reg') or symbol.startswith('onig'):
+ return '[regexp]'
+ elif 'alloc' in symbol or 'free' in symbol or 'gc' in symbol:
+ return '[GC]'
+ elif 'pthread' in symbol and 'lock' in symbol:
+ return '[pthread lock]'
+ else:
+ return symbol # Return the symbol itself for uncategorized symbols
+
+def process_event(event):
+ global total_cycles, category_cycles, detailed_category_cycles, categories
+
+ full_dso = event.get("dso", "Unknown_dso")
+ dso = os.path.basename(full_dso)
+ symbol = event.get("symbol", "[unknown]")
+ cycles = event["sample"]["period"]
+ total_cycles += cycles
+
+ category = categorize_symbol(dso, symbol)
+ category_cycles[category] += cycles
+ detailed_category_cycles[category][(dso, symbol)] += cycles
+
+ if category.startswith('[') and category.endswith(']'):
+ categories.add(category)
+
+def trace_end():
+ if total_cycles == 0:
+ return
+
+ print("Aggregated Event Data:")
+ print("{:<20} {:<50} {:>20} {:>15}".format("[dso]", "[symbol or category]", "[top-most cycle ratio]", "[num cycles]"))
+
+ for category, cycles in category_cycles.most_common():
+ ratio = (cycles / total_cycles) * 100
+ dsos = {dso for dso, _ in detailed_category_cycles[category]}
+ dso_display = next(iter(dsos)) if len(dsos) == 1 else "Multiple DSOs"
+ print("{:<20} {:<50} {:>20.2f}% {:>15}".format(dso_display, truncate_symbol(category), ratio, cycles))
+
+ # Category breakdown
+ for category in categories:
+ symbols = detailed_category_cycles[category]
+ category_total = sum(symbols.values())
+ category_ratio = (category_total / total_cycles) * 100
+ print(f"\nCategory: {category} ({category_ratio:.2f}%)")
+ print("{:<20} {:<50} {:>20} {:>15}".format("[dso]", "[symbol]", "[top-most cycle ratio]", "[num cycles]"))
+ for (dso, symbol), cycles in symbols.most_common():
+ symbol_ratio = (cycles / category_total) * 100
+ print("{:<20} {:<50} {:>20.2f}% {:>15}".format(dso, truncate_symbol(symbol), symbol_ratio, cycles))
+
+# There are two ways to use this script:
+# 1) perf script -s misc/yjit_perf.py -- native interface
+# 2) perf script > perf.txt && misc/yjit_perf.py perf.txt -- hack, which doesn't require perf with Python support
+#
+# In both cases, __name__ is "__main__". The following code implements (2) when sys.argv is 2.
+if __name__ == "__main__" and len(sys.argv) == 2:
+ if len(sys.argv) != 2:
+ print("Usage: yjit_perf.py <filename>")
+ sys.exit(1)
+
+ with open(sys.argv[1], "r") as file:
+ for line in file:
+ # [Example]
+ # ruby 78207 3482.848465: 1212775 cpu_core/cycles:P/: 5c0333f682e1 [JIT] getlocal_WC_0+0x0 (/tmp/perf-78207.map)
+ row = line.split(maxsplit=6)
+
+ period = row[3] # "1212775"
+ symbol, dso = row[6].rsplit(" (", 1) # "[JIT] getlocal_WC_0+0x0", "/tmp/perf-78207.map)\n"
+ symbol = symbol.split("+")[0] # "[JIT] getlocal_WC_0"
+ dso = dso.split(")")[0] # "/tmp/perf-78207.map"
+
+ process_event({"dso": dso, "symbol": symbol, "sample": {"period": int(period)}})
+ trace_end()
diff --git a/misc/lldb_cruby.py b/misc/lldb_cruby.py
index 400ccb45b9..b3d4fb509a 100755..100644
--- a/misc/lldb_cruby.py
+++ b/misc/lldb_cruby.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
#coding: utf-8
#
# Usage: run `command script import -r misc/lldb_cruby.py` on LLDB
@@ -14,6 +13,7 @@ import sys
import shlex
import platform
import glob
+import math
from lldb_rb.constants import *
@@ -67,7 +67,7 @@ class BackTrace:
return self.VM_FRAME_MAGIC_NAME.get(frame_type, "(none)")
def rb_iseq_path_str(self, iseq):
- tRBasic = self.target.FindFirstType("struct RBasic").GetPointerType()
+ tRBasic = self.target.FindFirstType("::RBasic").GetPointerType()
pathobj = iseq.GetValueForExpressionPath("->body->location.pathobj")
pathobj = pathobj.Cast(tRBasic)
@@ -269,8 +269,7 @@ def lldb_inspect(debugger, target, result, val):
elif num & RUBY_IMMEDIATE_MASK:
print('immediate(%x)' % num, file=result)
else:
- tRBasic = target.FindFirstType("struct RBasic").GetPointerType()
- tRValue = target.FindFirstType("struct RVALUE")
+ tRBasic = target.FindFirstType("::RBasic").GetPointerType()
val = val.Cast(tRBasic)
flags = val.GetValueForExpressionPath("->flags").GetValueAsUnsigned()
@@ -524,10 +523,11 @@ def rb_backtrace(debugger, command, result, internal_dict):
bt.print_bt(val)
def dump_bits(target, result, page, object_address, end = "\n"):
- tRValue = target.FindFirstType("struct RVALUE")
+ slot_size = page.GetChildMemberWithName("heap").GetChildMemberWithName("slot_size").unsigned
+ byte_size = 40 ** math.floor(math.log(slot_size, 40))
tUintPtr = target.FindFirstType("uintptr_t") # bits_t
- num_in_page = (object_address & HEAP_PAGE_ALIGN_MASK) // tRValue.GetByteSize();
+ num_in_page = (object_address & HEAP_PAGE_ALIGN_MASK) // byte_size;
bits_bitlength = tUintPtr.GetByteSize() * 8
bitmap_index = num_in_page // bits_bitlength
bitmap_offset = num_in_page & (bits_bitlength - 1)
@@ -547,10 +547,9 @@ class HeapPageIter:
self.target = target
self.start = page.GetChildMemberWithName('start').GetValueAsUnsigned();
self.num_slots = page.GetChildMemberWithName('total_slots').unsigned
- self.slot_size = page.GetChildMemberWithName('size_pool').GetChildMemberWithName('slot_size').unsigned
+ self.slot_size = page.GetChildMemberWithName('heap').GetChildMemberWithName('slot_size').unsigned
self.counter = 0
- self.tRBasic = target.FindFirstType("struct RBasic")
- self.tRValue = target.FindFirstType("struct RVALUE")
+ self.tRBasic = target.FindFirstType("::RBasic")
def is_valid(self):
heap_page_header_size = self.target.FindFirstType("struct heap_page_header").GetByteSize()
@@ -582,14 +581,13 @@ def dump_page_internal(page, target, process, thread, frame, result, debugger, h
freelist = []
fl_start = page.GetChildMemberWithName('freelist').GetValueAsUnsigned()
- tRVALUE = target.FindFirstType("struct RVALUE")
+ free_slot = target.FindFirstType("struct free_slot")
while fl_start > 0:
freelist.append(fl_start)
obj_addr = lldb.SBAddress(fl_start, target)
- obj = target.CreateValueFromAddress("object", obj_addr, tRVALUE)
- fl_start = obj.GetChildMemberWithName("as").GetChildMemberWithName("free").GetChildMemberWithName("next").GetValueAsUnsigned()
-
+ obj = target.CreateValueFromAddress("object", obj_addr, free_slot)
+ fl_start = obj.GetChildMemberWithName("next").GetValueAsUnsigned()
page_iter = HeapPageIter(page, target)
if page_iter.is_valid():
diff --git a/misc/lldb_rb/commands/heap_page_command.py b/misc/lldb_rb/commands/heap_page_command.py
index b56a3eae4e..2eed3c3bee 100644
--- a/misc/lldb_rb/commands/heap_page_command.py
+++ b/misc/lldb_rb/commands/heap_page_command.py
@@ -8,14 +8,15 @@ class HeapPageCommand(RbBaseCommand):
help_string = "prints out 'struct heap_page' for a VALUE pointer in the page"
def call(self, debugger, command, exe_ctx, result):
+ self.result = result
self.t_heap_page_body = self.target.FindFirstType("struct heap_page_body")
self.t_heap_page_ptr = self.target.FindFirstType("struct heap_page").GetPointerType()
page = self._get_page(self.frame.EvaluateExpression(command))
page.Cast(self.t_heap_page_ptr)
- self._append_expression(debugger, "(struct heap_page *) %0#x" % page.GetValueAsUnsigned(), result)
- self._append_expression(debugger, "*(struct heap_page *) %0#x" % page.GetValueAsUnsigned(), result)
+ self._append_expression("(struct heap_page *) %0#x" % page.GetValueAsUnsigned())
+ self._append_expression("*(struct heap_page *) %0#x" % page.GetValueAsUnsigned())
def _get_page(self, val):
addr = val.GetValueAsUnsigned()
diff --git a/misc/lldb_rb/commands/print_flags_command.py b/misc/lldb_rb/commands/print_flags_command.py
index 00da4834bf..bc494ae01a 100644
--- a/misc/lldb_rb/commands/print_flags_command.py
+++ b/misc/lldb_rb/commands/print_flags_command.py
@@ -11,13 +11,13 @@ class PrintFlagsCommand(RbBaseCommand):
# call is where our command logic will be implemented
def call(self, debugger, command, exe_ctx, result):
- rclass_t = self.target.FindFirstType("struct RBasic")
+ rclass_t = self.target.FindFirstType("::RBasic")
rcass_ptr = self.target.EvaluateExpression(command).Cast(rclass_t.GetPointerType())
obj_flags = rcass_ptr.GetValueForExpressionPath("->flags").GetValueAsUnsigned()
flags = [
- "RUBY_FL_WB_PROTECTED", "RUBY_FL_PROMOTED0", "RUBY_FL_PROMOTED1", "RUBY_FL_FINALIZE",
- "RUBY_FL_SHAREABLE", "RUBY_FL_EXIVAR", "RUBY_FL_FREEZE",
+ "RUBY_FL_WB_PROTECTED", "RUBY_FL_PROMOTED", "RUBY_FL_FINALIZE",
+ "RUBY_FL_SHAREABLE", "RUBY_FL_FREEZE",
"RUBY_FL_USER0", "RUBY_FL_USER1", "RUBY_FL_USER2", "RUBY_FL_USER3", "RUBY_FL_USER4",
"RUBY_FL_USER5", "RUBY_FL_USER6", "RUBY_FL_USER7", "RUBY_FL_USER8", "RUBY_FL_USER9",
"RUBY_FL_USER10", "RUBY_FL_USER11", "RUBY_FL_USER12", "RUBY_FL_USER13", "RUBY_FL_USER14",
diff --git a/misc/lldb_rb/lldb_interface.py b/misc/lldb_rb/lldb_interface.py
index 785a54b3e3..25930b2e16 100644
--- a/misc/lldb_rb/lldb_interface.py
+++ b/misc/lldb_rb/lldb_interface.py
@@ -5,3 +5,14 @@ class LLDBInterface:
self.process = self.target.GetProcess()
self.thread = self.process.GetSelectedThread()
self.frame = self.thread.GetSelectedFrame()
+
+ def _append_command_output(self, command):
+ output1 = self.result.GetOutput()
+ self.debugger.GetCommandInterpreter().HandleCommand(command, self.result)
+ output2 = self.result.GetOutput()
+ self.result.Clear()
+ self.result.write(output1)
+ self.result.write(output2)
+
+ def _append_expression(self, expression):
+ self._append_command_output("expression " + expression)
diff --git a/misc/lldb_rb/rb_heap_structs.py b/misc/lldb_rb/rb_heap_structs.py
index 86b38dbbbd..798b838080 100644
--- a/misc/lldb_rb/rb_heap_structs.py
+++ b/misc/lldb_rb/rb_heap_structs.py
@@ -1,4 +1,5 @@
import lldb
+import math
from lldb_rb.lldb_interface import LLDBInterface
from lldb_rb.constants import *
@@ -50,8 +51,7 @@ class RbObject(LLDBInterface):
self.flUser9 = self.ruby_globals["RUBY_FL_USER9"]
self.flUshift = self.ruby_globals["RUBY_FL_USHIFT"]
- self.tRBasic = self.target.FindFirstType("struct RBasic").GetPointerType()
- self.tRValue = self.target.FindFirstType("struct RVALUE")
+ self.tRBasic = self.target.FindFirstType("::RBasic").GetPointerType()
self.val = ptr.Cast(self.tRBasic)
self.page = HeapPage(self.debugger, self.val)
@@ -70,10 +70,12 @@ class RbObject(LLDBInterface):
return ' '
def dump_bits(self, result, end = "\n"):
- tRValue = self.target.FindFirstType("struct RVALUE")
tUintPtr = self.target.FindFirstType("uintptr_t") # bits_t
- num_in_page = (self.val.GetValueAsUnsigned() & HEAP_PAGE_ALIGN_MASK) // tRValue.GetByteSize();
+ slot_size = self.page.to_heap_page_struct().GetChildMemberWithName("heap").GetChildMemberWithName("slot_size").unsigned
+ byte_size = 40 ** math.floor(math.log(slot_size, 40))
+
+ num_in_page = (self.val.GetValueAsUnsigned() & HEAP_PAGE_ALIGN_MASK) // byte_size;
bits_bitlength = tUintPtr.GetByteSize() * 8
bitmap_index = num_in_page // bits_bitlength
bitmap_offset = num_in_page & (bits_bitlength - 1)
@@ -109,7 +111,14 @@ class RbObject(LLDBInterface):
return False
def as_type(self, type_name):
- return self.val.Cast(self.tRValue.GetPointerType()).GetValueForExpressionPath("->as."+type_name)
+ if type_name == "array":
+ tRarray = self.target.FindFirstType("struct RArray")
+ return self.val.Cast(tRarray.GetPointerType())
+ elif type_name == "bignum":
+ tRbignum = self.target.FindFirstType("struct RBignum")
+ return self.val.Cast(tRbignum.GetPointerType())
+ else:
+ print("as_type is not implemented for:", type_name)
def ary_ptr(self):
rval = self.as_type("array")
diff --git a/misc/lldb_rb/utils.py b/misc/lldb_rb/utils.py
index 26517b7fee..a2bcedc328 100644
--- a/misc/lldb_rb/utils.py
+++ b/misc/lldb_rb/utils.py
@@ -8,17 +8,6 @@ class RbInspector(LLDBInterface):
self.result = result
self.ruby_globals = ruby_globals
- def _append_command_output(self, command):
- output1 = self.result.GetOutput()
- self.debugger.GetCommandInterpreter().HandleCommand(command, self.result)
- output2 = self.result.GetOutput()
- self.result.Clear()
- self.result.write(output1)
- self.result.write(output2)
-
- def _append_expression(self, expression):
- self._append_command_output("expression " + expression)
-
def string2cstr(self, rstring):
"""Returns the pointer to the C-string in the given String object"""
if rstring.TypeIsPointerType():
@@ -60,6 +49,9 @@ class RbInspector(LLDBInterface):
rbUndef = self.ruby_globals["RUBY_Qundef"]
rbImmediateMask = self.ruby_globals["RUBY_IMMEDIATE_MASK"]
+ if self.inspect_node(val):
+ return
+
num = val.GetValueAsSigned()
if num == rbFalse:
print('false', file=self.result)
@@ -110,7 +102,7 @@ class RbInspector(LLDBInterface):
self._append_expression("*(struct RClass*)%0#x" % val.GetValueAsUnsigned())
if not val.Cast(tRClass).GetChildMemberWithName("ptr").IsValid():
- self._append_command_expression(
+ self._append_expression(
"*(struct rb_classext_struct*)%0#x" %
(val.GetValueAsUnsigned() + tRClass.GetByteSize())
)
@@ -119,6 +111,10 @@ class RbInspector(LLDBInterface):
self.result.write('T_STRING: %s' % flaginfo)
tRString = self.target.FindFirstType("struct RString").GetPointerType()
+ chilled = self.ruby_globals["RUBY_FL_USER3"]
+ if (rval.flags & chilled) != 0:
+ self.result.write("[CHILLED] ")
+
rb_enc_mask = self.ruby_globals["RUBY_ENCODING_MASK"]
rb_enc_shift = self.ruby_globals["RUBY_ENCODING_SHIFT"]
encidx = ((rval.flags & rb_enc_mask) >> rb_enc_shift)
@@ -131,6 +127,16 @@ class RbInspector(LLDBInterface):
else:
self.result.write('[enc=%d] ' % encidx)
+ coderange = rval.flags & self.ruby_globals["RUBY_ENC_CODERANGE_MASK"]
+ if coderange == self.ruby_globals["RUBY_ENC_CODERANGE_7BIT"]:
+ self.result.write('[7BIT] ')
+ elif coderange == self.ruby_globals["RUBY_ENC_CODERANGE_VALID"]:
+ self.result.write('[VALID] ')
+ elif coderange == self.ruby_globals["RUBY_ENC_CODERANGE_BROKEN"]:
+ self.result.write('[BROKEN] ')
+ else:
+ self.result.write('[UNKNOWN] ')
+
ptr, len = self.string2cstr(val.Cast(tRString))
if len == 0:
self.result.write("(empty)\n")
@@ -230,237 +236,20 @@ class RbInspector(LLDBInterface):
elif rval.is_type("RUBY_T_DATA"):
tRTypedData = self.target.FindFirstType("struct RTypedData").GetPointerType()
val = val.Cast(tRTypedData)
- flag = val.GetValueForExpressionPath("->typed_flag")
- if flag.GetValueAsUnsigned() == 1:
- print("T_DATA: %s" %
- val.GetValueForExpressionPath("->type->wrap_struct_name"),
- file=self.result)
- self._append_expression("*(struct RTypedData *) %0#x" % val.GetValueAsUnsigned())
- else:
- print("T_DATA:", file=self.result)
- self._append_expression("*(struct RData *) %0#x" % val.GetValueAsUnsigned())
-
- elif rval.is_type("RUBY_T_NODE"):
- tRNode = self.target.FindFirstType("struct RNode").GetPointerType()
- rbNodeTypeMask = self.ruby_globals["RUBY_NODE_TYPEMASK"]
- rbNodeTypeShift = self.ruby_globals["RUBY_NODE_TYPESHIFT"]
-
- nd_type = (rval.flags & rbNodeTypeMask) >> rbNodeTypeShift
- val = val.Cast(tRNode)
-
- self._append_expression("(node_type) %d" % nd_type)
-
- if nd_type == self.ruby_globals["NODE_SCOPE"]:
- self._append_expression("*(struct RNode_SCOPE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_BLOCK"]:
- self._append_expression("*(struct RNode_BLOCK *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_IF"]:
- self._append_expression("*(struct RNode_IF *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_UNLESS"]:
- self._append_expression("*(struct RNode_UNLESS *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CASE"]:
- self._append_expression("*(struct RNode_CASE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CASE2"]:
- self._append_expression("*(struct RNode_CASE2 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CASE3"]:
- self._append_expression("*(struct RNode_CASE3 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_WHEN"]:
- self._append_expression("*(struct RNode_WHEN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_IN"]:
- self._append_expression("*(struct RNode_IN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_WHILE"]:
- self._append_expression("*(struct RNode_WHILE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_UNTIL"]:
- self._append_expression("*(struct RNode_UNTIL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ITER"]:
- self._append_expression("*(struct RNode_ITER *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FOR"]:
- self._append_expression("*(struct RNode_FOR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FOR_MASGN"]:
- self._append_expression("*(struct RNode_FOR_MASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_BREAK"]:
- self._append_expression("*(struct RNode_BREAK *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_NEXT"]:
- self._append_expression("*(struct RNode_NEXT *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_REDO"]:
- self._append_expression("*(struct RNode_REDO *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_RETRY"]:
- self._append_expression("*(struct RNode_RETRY *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_BEGIN"]:
- self._append_expression("*(struct RNode_BEGIN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_RESCUE"]:
- self._append_expression("*(struct RNode_RESCUE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_RESBODY"]:
- self._append_expression("*(struct RNode_RESBODY *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ENSURE"]:
- self._append_expression("*(struct RNode_ENSURE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_AND"]:
- self._append_expression("*(struct RNode_AND *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OR"]:
- self._append_expression("*(struct RNode_OR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_MASGN"]:
- self._append_expression("*(struct RNode_MASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_LASGN"]:
- self._append_expression("*(struct RNode_LASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DASGN"]:
- self._append_expression("*(struct RNode_DASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_GASGN"]:
- self._append_expression("*(struct RNode_GASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_IASGN"]:
- self._append_expression("*(struct RNode_IASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CDECL"]:
- self._append_expression("*(struct RNode_CDECL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CVASGN"]:
- self._append_expression("*(struct RNode_CVASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OP_ASGN1"]:
- self._append_expression("*(struct RNode_OP_ASGN1 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OP_ASGN2"]:
- self._append_expression("*(struct RNode_OP_ASGN2 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OP_ASGN_AND"]:
- self._append_expression("*(struct RNode_OP_ASGN_AND *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OP_ASGN_OR"]:
- self._append_expression("*(struct RNode_OP_ASGN_OR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OP_CDECL"]:
- self._append_expression("*(struct RNode_OP_CDECL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CALL"]:
- self._append_expression("*(struct RNode_CALL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OPCALL"]:
- self._append_expression("*(struct RNode_OPCALL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FCALL"]:
- self._append_expression("*(struct RNode_FCALL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_VCALL"]:
- self._append_expression("*(struct RNode_VCALL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_QCALL"]:
- self._append_expression("*(struct RNode_QCALL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_SUPER"]:
- self._append_expression("*(struct RNode_SUPER *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ZSUPER"]:
- self._append_expression("*(struct RNode_ZSUPER *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_LIST"]:
- self._append_expression("*(struct RNode_LIST *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ZLIST"]:
- self._append_expression("*(struct RNode_ZLIST *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_HASH"]:
- self._append_expression("*(struct RNode_HASH *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_RETURN"]:
- self._append_expression("*(struct RNode_RETURN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_YIELD"]:
- self._append_expression("*(struct RNode_YIELD *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_LVAR"]:
- self._append_expression("*(struct RNode_LVAR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DVAR"]:
- self._append_expression("*(struct RNode_DVAR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_GVAR"]:
- self._append_expression("*(struct RNode_GVAR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CONST"]:
- self._append_expression("*(struct RNode_CONST *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CVAR"]:
- self._append_expression("*(struct RNode_CVAR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_NTH_REF"]:
- self._append_expression("*(struct RNode_NTH_REF *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_BACK_REF"]:
- self._append_expression("*(struct RNode_BACK_REF *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_MATCH"]:
- self._append_expression("*(struct RNode_MATCH *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_MATCH2"]:
- self._append_expression("*(struct RNode_MATCH2 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_MATCH3"]:
- self._append_expression("*(struct RNode_MATCH3 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_LIT"]:
- self._append_expression("*(struct RNode_LIT *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_STR"]:
- self._append_expression("*(struct RNode_STR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DSTR"]:
- self._append_expression("*(struct RNode_DSTR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_XSTR"]:
- self._append_expression("*(struct RNode_XSTR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DXSTR"]:
- self._append_expression("*(struct RNode_DXSTR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_EVSTR"]:
- self._append_expression("*(struct RNode_EVSTR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DREGX"]:
- self._append_expression("*(struct RNode_DREGX *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ONCE"]:
- self._append_expression("*(struct RNode_ONCE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ARGS"]:
- self._append_expression("*(struct RNode_ARGS *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ARGS_AUX"]:
- self._append_expression("*(struct RNode_ARGS_AUX *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OPT_ARG"]:
- self._append_expression("*(struct RNode_OPT_ARG *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_KW_ARG"]:
- self._append_expression("*(struct RNode_KW_ARG *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_POSTARG"]:
- self._append_expression("*(struct RNode_POSTARG *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ARGSCAT"]:
- self._append_expression("*(struct RNode_ARGSCAT *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ARGSPUSH"]:
- self._append_expression("*(struct RNode_ARGSPUSH *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_SPLAT"]:
- self._append_expression("*(struct RNode_SPLAT *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DEFN"]:
- self._append_expression("*(struct RNode_DEFN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DEFS"]:
- self._append_expression("*(struct RNode_DEFS *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ALIAS"]:
- self._append_expression("*(struct RNode_ALIAS *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_VALIAS"]:
- self._append_expression("*(struct RNode_VALIAS *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_UNDEF"]:
- self._append_expression("*(struct RNode_UNDEF *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CLASS"]:
- self._append_expression("*(struct RNode_CLASS *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_MODULE"]:
- self._append_expression("*(struct RNode_MODULE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_SCLASS"]:
- self._append_expression("*(struct RNode_SCLASS *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_COLON2"]:
- self._append_expression("*(struct RNode_COLON2 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_COLON3"]:
- self._append_expression("*(struct RNode_COLON3 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DOT2"]:
- self._append_expression("*(struct RNode_DOT2 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DOT3"]:
- self._append_expression("*(struct RNode_DOT3 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FLIP2"]:
- self._append_expression("*(struct RNode_FLIP2 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FLIP3"]:
- self._append_expression("*(struct RNode_FLIP3 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_SELF"]:
- self._append_expression("*(struct RNode_SELF *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_NIL"]:
- self._append_expression("*(struct RNode_NIL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_TRUE"]:
- self._append_expression("*(struct RNode_TRUE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FALSE"]:
- self._append_expression("*(struct RNode_FALSE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ERRINFO"]:
- self._append_expression("*(struct RNode_ERRINFO *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DEFINED"]:
- self._append_expression("*(struct RNode_DEFINED *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_POSTEXE"]:
- self._append_expression("*(struct RNode_POSTEXE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DSYM"]:
- self._append_expression("*(struct RNode_DSYM *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ATTRASGN"]:
- self._append_expression("*(struct RNode_ATTRASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_LAMBDA"]:
- self._append_expression("*(struct RNode_LAMBDA *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ARYPTN"]:
- self._append_expression("*(struct RNode_ARYPTN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_HSHPTN"]:
- self._append_expression("*(struct RNode_HSHPTN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FNDPTN"]:
- self._append_expression("*(struct RNode_FNDPTN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ERROR"]:
- self._append_expression("*(struct RNode_ERROR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_RIPPER"]:
- self._append_expression("*(struct RNode_RIPPER *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_RIPPER_VALUES"]:
- self._append_expression("*(struct RNode_RIPPER_VALUES *) %0#x" % val.GetValueAsUnsigned())
- else:
- self._append_expression("*(struct RNode *) %0#x" % val.GetValueAsUnsigned())
+ type = val.GetValueForExpressionPath("->type").GetValueAsUnsigned()
+ embed = (type & 1)
+ if embed:
+ flaginfo += "[EMBED] "
+ type = self.frame.EvaluateExpression("(rb_data_type_t *)%0#x" % (type & ~1))
+ print("T_DATA: %s%s" %
+ (flaginfo, type.GetValueForExpressionPath("->wrap_struct_name")),
+ file=self.result)
+ print("%s", type.Dereference(), file=self.result)
+ ptr = val.GetValueForExpressionPath("->data")
+ if embed:
+ ptr = ptr.AddressOf()
+ self._append_expression("(void *)%0#x" % ptr.GetValueAsUnsigned())
elif rval.is_type("RUBY_T_IMEMO"):
imemo_type = ((rval.flags >> self.ruby_globals["RUBY_FL_USHIFT"])
@@ -488,3 +277,230 @@ class RbInspector(LLDBInterface):
else:
print("Not-handled type %0#x" % rval.type, file=self.result)
print(val, file=self.result)
+
+ def inspect_node(self, val):
+ tRNode = self.target.FindFirstType("struct RNode").GetPointerType()
+
+ # if val.GetType() != tRNode: does not work for unknown reason
+
+ if val.GetType().GetPointeeType().GetCanonicalType().name != "RNode":
+ return False
+
+ rbNodeTypeMask = self.ruby_globals["RUBY_NODE_TYPEMASK"]
+ rbNodeTypeShift = self.ruby_globals["RUBY_NODE_TYPESHIFT"]
+ flags = val.Cast(tRNode).GetChildMemberWithName("flags").GetValueAsUnsigned()
+ nd_type = (flags & rbNodeTypeMask) >> rbNodeTypeShift
+
+ self._append_expression("(node_type) %d" % nd_type)
+
+ if nd_type == self.ruby_globals["NODE_SCOPE"]:
+ self._append_expression("*(rb_node_scope_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_BLOCK"]:
+ self._append_expression("*(rb_node_block_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_IF"]:
+ self._append_expression("*(rb_node_if_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_UNLESS"]:
+ self._append_expression("*(rb_node_unless_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_CASE"]:
+ self._append_expression("*(rb_node_case_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_CASE2"]:
+ self._append_expression("*(rb_node_case2_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_CASE3"]:
+ self._append_expression("*(rb_node_case3_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_WHEN"]:
+ self._append_expression("*(rb_node_when_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_IN"]:
+ self._append_expression("*(rb_node_in_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_WHILE"]:
+ self._append_expression("*(rb_node_while_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_UNTIL"]:
+ self._append_expression("*(rb_node_until_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ITER"]:
+ self._append_expression("*(rb_node_iter_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_FOR"]:
+ self._append_expression("*(rb_node_for_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_FOR_MASGN"]:
+ self._append_expression("*(rb_node_for_masgn_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_BREAK"]:
+ self._append_expression("*(rb_node_break_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_NEXT"]:
+ self._append_expression("*(rb_node_next_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_REDO"]:
+ self._append_expression("*(rb_node_redo_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_RETRY"]:
+ self._append_expression("*(rb_node_retry_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_BEGIN"]:
+ self._append_expression("*(rb_node_begin_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_RESCUE"]:
+ self._append_expression("*(rb_node_rescue_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_RESBODY"]:
+ self._append_expression("*(rb_node_resbody_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ENSURE"]:
+ self._append_expression("*(rb_node_ensure_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_AND"]:
+ self._append_expression("*(rb_node_and_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_OR"]:
+ self._append_expression("*(rb_node_or_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_MASGN"]:
+ self._append_expression("*(rb_node_masgn_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_LASGN"]:
+ self._append_expression("*(rb_node_lasgn_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DASGN"]:
+ self._append_expression("*(rb_node_dasgn_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_GASGN"]:
+ self._append_expression("*(rb_node_gasgn_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_IASGN"]:
+ self._append_expression("*(rb_node_iasgn_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_CDECL"]:
+ self._append_expression("*(rb_node_cdecl_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_CVASGN"]:
+ self._append_expression("*(rb_node_cvasgn_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_OP_ASGN1"]:
+ self._append_expression("*(rb_node_op_asgn1_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_OP_ASGN2"]:
+ self._append_expression("*(rb_node_op_asgn2_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_OP_ASGN_AND"]:
+ self._append_expression("*(rb_node_op_asgn_and_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_OP_ASGN_OR"]:
+ self._append_expression("*(rb_node_op_asgn_or_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_OP_CDECL"]:
+ self._append_expression("*(rb_node_op_cdecl_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_CALL"]:
+ self._append_expression("*(rb_node_call_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_OPCALL"]:
+ self._append_expression("*(rb_node_opcall_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_FCALL"]:
+ self._append_expression("*(rb_node_fcall_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_VCALL"]:
+ self._append_expression("*(rb_node_vcall_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_QCALL"]:
+ self._append_expression("*(rb_node_qcall_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_SUPER"]:
+ self._append_expression("*(rb_node_super_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ZSUPER"]:
+ self._append_expression("*(rb_node_zsuper_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_LIST"]:
+ self._append_expression("*(rb_node_list_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ZLIST"]:
+ self._append_expression("*(rb_node_zlist_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_HASH"]:
+ self._append_expression("*(rb_node_hash_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_RETURN"]:
+ self._append_expression("*(rb_node_return_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_YIELD"]:
+ self._append_expression("*(rb_node_yield_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_LVAR"]:
+ self._append_expression("*(rb_node_lvar_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DVAR"]:
+ self._append_expression("*(rb_node_dvar_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_GVAR"]:
+ self._append_expression("*(rb_node_gvar_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_CONST"]:
+ self._append_expression("*(rb_node_const_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_CVAR"]:
+ self._append_expression("*(rb_node_cvar_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_NTH_REF"]:
+ self._append_expression("*(rb_node_nth_ref_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_BACK_REF"]:
+ self._append_expression("*(rb_node_back_ref_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_MATCH"]:
+ self._append_expression("*(rb_node_match_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_MATCH2"]:
+ self._append_expression("*(rb_node_match2_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_MATCH3"]:
+ self._append_expression("*(rb_node_match3_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_STR"]:
+ self._append_expression("*(rb_node_str_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DSTR"]:
+ self._append_expression("*(rb_node_dstr_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_XSTR"]:
+ self._append_expression("*(rb_node_xstr_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DXSTR"]:
+ self._append_expression("*(rb_node_dxstr_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_EVSTR"]:
+ self._append_expression("*(rb_node_evstr_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_REGX"]:
+ self._append_expression("*(rb_node_regx_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DREGX"]:
+ self._append_expression("*(rb_node_dregx_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ONCE"]:
+ self._append_expression("*(rb_node_once_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ARGS"]:
+ self._append_expression("*(rb_node_args_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ARGS_AUX"]:
+ self._append_expression("*(rb_node_args_aux_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_OPT_ARG"]:
+ self._append_expression("*(rb_node_opt_arg_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_KW_ARG"]:
+ self._append_expression("*(rb_node_kw_arg_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_POSTARG"]:
+ self._append_expression("*(rb_node_postarg_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ARGSCAT"]:
+ self._append_expression("*(rb_node_argscat_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ARGSPUSH"]:
+ self._append_expression("*(rb_node_argspush_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_SPLAT"]:
+ self._append_expression("*(rb_node_splat_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DEFN"]:
+ self._append_expression("*(rb_node_defn_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DEFS"]:
+ self._append_expression("*(rb_node_defs_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ALIAS"]:
+ self._append_expression("*(rb_node_alias_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_VALIAS"]:
+ self._append_expression("*(rb_node_valias_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_UNDEF"]:
+ self._append_expression("*(rb_node_undef_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_CLASS"]:
+ self._append_expression("*(rb_node_class_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_MODULE"]:
+ self._append_expression("*(rb_node_module_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_SCLASS"]:
+ self._append_expression("*(rb_node_sclass_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_COLON2"]:
+ self._append_expression("*(rb_node_colon2_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_COLON3"]:
+ self._append_expression("*(rb_node_colon3_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DOT2"]:
+ self._append_expression("*(rb_node_dot2_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DOT3"]:
+ self._append_expression("*(rb_node_dot3_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_FLIP2"]:
+ self._append_expression("*(rb_node_flip2_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_FLIP3"]:
+ self._append_expression("*(rb_node_flip3_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_SELF"]:
+ self._append_expression("*(rb_node_self_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_NIL"]:
+ self._append_expression("*(rb_node_nil_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_TRUE"]:
+ self._append_expression("*(rb_node_true_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_FALSE"]:
+ self._append_expression("*(rb_node_false_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ERRINFO"]:
+ self._append_expression("*(rb_node_errinfo_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DEFINED"]:
+ self._append_expression("*(rb_node_defined_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_POSTEXE"]:
+ self._append_expression("*(rb_node_postexe_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_DSYM"]:
+ self._append_expression("*(rb_node_dsym_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ATTRASGN"]:
+ self._append_expression("*(rb_node_attrasgn_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_LAMBDA"]:
+ self._append_expression("*(rb_node_lambda_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ARYPTN"]:
+ self._append_expression("*(rb_node_aryptn_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_HSHPTN"]:
+ self._append_expression("*(rb_node_hshptn_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_FNDPTN"]:
+ self._append_expression("*(rb_node_fndptn_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_ERROR"]:
+ self._append_expression("*(rb_node_error_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_LINE"]:
+ self._append_expression("*(rb_node_line_t *) %0#x" % val.GetValueAsUnsigned())
+ elif nd_type == self.ruby_globals["NODE_FILE"]:
+ self._append_expression("*(rb_node_file_t *) %0#x" % val.GetValueAsUnsigned())
+ else:
+ self._append_expression("*(NODE *) %0#x" % val.GetValueAsUnsigned())
+ return True
diff --git a/misc/lldb_yjit.py b/misc/lldb_yjit.py
deleted file mode 100644
index cc37b990ea..0000000000
--- a/misc/lldb_yjit.py
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env python
-#coding: utf-8
-#
-# Usage: run `command script import -r misc/lldb_yjit.py` on LLDB
-#
-
-from __future__ import print_function
-import lldb
-import os
-import shlex
-
-def list_comments(debugger, command, result, internal_dict):
- target = debugger.GetSelectedTarget()
- process = target.GetProcess()
- thread = process.GetSelectedThread()
- frame = thread.GetSelectedFrame()
-
- # Get the different types we need
- rb_darray_meta_t = target.FindFirstType("rb_darray_meta_t")
- codeblock_t = target.FindFirstType("codeblock_t")
- yjit_comment = target.FindFirstType("yjit_comment")
-
- # Get the global variables we need
- comments = target.FindFirstGlobalVariable("yjit_code_comments")
- cb = target.FindFirstGlobalVariable("cb").Cast(codeblock_t.GetPointerType())
-
- # Get the address of the memory block we're using
- mem_addr = cb.GetChildMemberWithName("mem_block").GetValueAsUnsigned()
-
- # Find the size of the darray comment list
- meta = comments.Cast(rb_darray_meta_t.GetPointerType())
- size = meta.GetChildMemberWithName("size").GetValueAsUnsigned()
-
- # Get the address of the block following the metadata header
- t_offset = comments.GetValueAsUnsigned() + rb_darray_meta_t.GetByteSize()
-
- # Loop through each comment and print
- for t in range(0, size):
- addr = lldb.SBAddress(t_offset + (t * yjit_comment.GetByteSize()), target)
- comment = target.CreateValueFromAddress("yjit_comment", addr, yjit_comment)
- string = comment.GetChildMemberWithName("comment")
- comment_offset = mem_addr + comment.GetChildMemberWithName("offset").GetValueAsUnsigned()
- print("%0#x %s" % (comment_offset, string.GetSummary()), file = result)
-
-
-def __lldb_init_module(debugger, internal_dict):
- debugger.HandleCommand("command script add -f lldb_yjit.list_comments lc")
diff --git a/misc/ruby-style.el b/misc/ruby-style.el
index 13aad77b3d..03d0830d3a 100644
--- a/misc/ruby-style.el
+++ b/misc/ruby-style.el
@@ -56,7 +56,9 @@
(c-basic-offset . 4)
(tab-width . 8)
(indent-tabs-mode . nil)
- (setq show-trailing-whitespace t)
+ (show-trailing-whitespace . t)
+ (c-backslash-column . 1)
+ (c-backslash-max-column . 1)
(c-offsets-alist
(case-label . *)
(label . (ruby-style-label-indent *))
@@ -66,6 +68,17 @@
(access-label /)
)))
+(c-add-style
+ "prism"
+ '("bsd"
+ (c-basic-offset . 4)
+ (tab-width . 8)
+ (indent-tabs-mode . nil)
+ (show-trailing-whitespace . t)
+ (c-offsets-alist
+ (case-label . +)
+ )))
+
;;;###autoload
(defun ruby-style-c-mode ()
(interactive)
diff --git a/misc/tsan_suppressions.txt b/misc/tsan_suppressions.txt
new file mode 100644
index 0000000000..5492500e7f
--- /dev/null
+++ b/misc/tsan_suppressions.txt
@@ -0,0 +1,109 @@
+# TSan: ThreadSanitizer
+# https://github.com/google/sanitizers/wiki/threadsanitizersuppressions
+#
+# This file describes a number of places where TSAN detects problems in CRuby.
+# Many of these indicate bugs. Others are benign (ex. data races that can be
+# replaced with relaxed atomic loads)
+#
+# Usage:
+# Configure with:
+# ./configure cflags='-fsanitize=thread' CC=clang
+# Build and run with:
+# TSAN_OPTIONS="suppressions=$(pwd)/misc/tsan_suppressions.txt:die_after_fork=0"
+#
+# Other useful TSAN_OPTIONS:
+# * halt_on_error=1
+# * strip_path_prefix=$(pwd)/
+
+# Namespaces
+race_top:push_subclass_entry_to_list
+
+# sub_nounderflow includes non-atomic read, possibly other issue
+race:objspace_malloc_increase_body
+
+# Signals and ubf
+race:unregister_ubf_list
+
+# It's already crashing. We're doing our best
+signal:rb_vm_bugreport
+race:check_reserved_signal_
+
+race_top:rb_check_deadlock
+
+# vm->ractor.sched.grq_cnt++
+race_top:ractor_sched_enq
+race_top:ractor_sched_deq
+
+# Race between vm_remove_ractor writing ractor count and
+# native_thread_check_and_create_shared reading it during thread creation.
+# The write happens when a ractor thread exits, the read happens when
+# checking if new shared threads need to be created.
+race:vm_remove_ractor
+
+# th->sched.finished at end of co_start
+race_top:rb_thread_sched_mark_zombies
+
+# Races against timer thread setting th->sched.waiting_reason.flags
+race_top:thread_sched_wait_events
+
+# At thread start
+race_top:rb_ractor_set_current_ec_
+
+# TSan reports a lock-order-inversion between thread_sched_lock_ and this lock.
+# It's unclear if that can cause a deadlock since the lock is on self
+deadlock:ractor_lock_self
+
+# TSan reports a deadlock when reacquiring the this lock after a barrier, but
+# we know the other threads have been stopped
+deadlock:rb_ractor_sched_barrier_start
+
+# RVALUE_AGE_SET manipulates flag bits on objects which may be accessed in Ractors
+race_top:RVALUE_AGE_SET
+
+# Inline caches and call cache updates
+# Multiple threads can race when updating shared call caches during method lookups
+# and argument forwarding. These races involve reading/writing cd->cc fields.
+race_top:vm_cc_call_set
+race_top:vm_cc_class_check
+race_top:vm_search_cc
+race_top:vm_search_method_slowpath0
+race_top:rb_vm_opt_getconstant_path
+race_top:vm_ic_attr_index_set
+race:vm_ic_update
+race:vm_caller_setup_fwd_args
+
+# Race in shape_get_next where multiple threads simultaneously access and modify
+# RCLASS_MAX_IV_COUNT and RCLASS_VARIATION_COUNT fields in class objects.
+# One thread reads the field while another thread calls RCLASS_SET_MAX_IV_COUNT.
+# This happens during instance variable shape transitions in multi-threaded code.
+race:shape_get_next
+
+# Non-atomic reads/writes
+race:gccct_method_search
+
+# Ignore exit for now
+race:rb_ec_finalize
+race:rb_ec_cleanup
+
+# TSan doesn't work well post-fork, this raises errors when creating the new
+# timer thread
+race:after_fork_ruby
+
+# Sets objspace->flags.dont_incremental while writebarrier may be running
+race_top:objspace_each_exec
+race_top:objspace_each_objects_ensure
+
+# Non-atomic lazy initialized static variable
+race_top:rbimpl_intern_const
+
+# Setting def->aliased bitfield non-atomically
+race_top:method_definition_addref
+
+# Switching to setting up tracing. Likely other ractors should be stopped for this.
+race_top:encoded_iseq_trace_instrument
+race:rb_iseq_trace_set_all
+race:rb_tracepoint_enable
+
+# GC enable/disable flag modifications race with object allocation flag reads
+race_top:rb_gc_impl_gc_disable
+race_top:rb_gc_impl_gc_enable