summaryrefslogtreecommitdiff
path: root/misc/lldb_cruby.py
diff options
context:
space:
mode:
Diffstat (limited to 'misc/lldb_cruby.py')
-rwxr-xr-xmisc/lldb_cruby.py143
1 files changed, 89 insertions, 54 deletions
diff --git a/misc/lldb_cruby.py b/misc/lldb_cruby.py
index c7a25984ae..400ccb45b9 100755
--- a/misc/lldb_cruby.py
+++ b/misc/lldb_cruby.py
@@ -9,13 +9,16 @@
from __future__ import print_function
import lldb
import os
+import inspect
+import sys
import shlex
+import platform
+import glob
-HEAP_PAGE_ALIGN_LOG = 14
-HEAP_PAGE_ALIGN_MASK = (~(~0 << HEAP_PAGE_ALIGN_LOG))
-HEAP_PAGE_ALIGN = (1 << HEAP_PAGE_ALIGN_LOG)
-HEAP_PAGE_SIZE = HEAP_PAGE_ALIGN
+from lldb_rb.constants import *
+# BEGIN FUNCTION STYLE DECLS
+# This will be refactored to use class style decls in the misc/commands dir
class BackTrace:
VM_FRAME_MAGIC_METHOD = 0x11110001
VM_FRAME_MAGIC_BLOCK = 0x22220001
@@ -75,7 +78,7 @@ class BackTrace:
pathobj = pathobj.Cast(self.tRArray)
if flags & RUBY_FL_USER1:
- len = ((flags & (RUBY_FL_USER3|RUBY_FL_USER4)) >> (RUBY_FL_USHIFT+3))
+ len = ((flags & (RUBY_FL_USER3|RUBY_FL_USER4|RUBY_FL_USER5|RUBY_FL_USER6|RUBY_FL_USER7|RUBY_FL_USER8|RUBY_FL_USER9)) >> (RUBY_FL_USHIFT+3))
ptr = pathobj.GetValueForExpressionPath("->as.ary")
else:
len = pathobj.GetValueForExpressionPath("->as.heap.len").GetValueAsSigned()
@@ -166,6 +169,14 @@ def lldb_init(debugger):
value_types = []
g = globals()
+
+ imemo_types = target.FindFirstType('enum imemo_type')
+ enum_members = imemo_types.GetEnumMembers()
+
+ for i in range(enum_members.GetSize()):
+ member = enum_members.GetTypeEnumMemberAtIndex(i)
+ g[member.GetName()] = member.GetValueAsUnsigned()
+
for enum in target.FindFirstGlobalVariable('ruby_dummy_gdb_enums'):
enum = enum.GetType()
members = enum.GetEnumMembers()
@@ -186,18 +197,16 @@ def string2cstr(rstring):
flags = rstring.GetValueForExpressionPath(".basic->flags").unsigned
if flags & RUBY_T_MASK != RUBY_T_STRING:
raise TypeError("not a string")
+ clen = int(rstring.GetValueForExpressionPath(".len").value, 0)
if flags & RUBY_FL_USER1:
cptr = int(rstring.GetValueForExpressionPath(".as.heap.ptr").value, 0)
- clen = int(rstring.GetValueForExpressionPath(".as.heap.len").value, 0)
else:
- cptr = int(rstring.GetValueForExpressionPath(".as.ary").location, 0)
- clen = (flags & RSTRING_EMBED_LEN_MASK) >> RSTRING_EMBED_LEN_SHIFT
+ cptr = int(rstring.GetValueForExpressionPath(".as.embed.ary").location, 0)
return cptr, clen
def output_string(debugger, result, rstring):
cptr, clen = string2cstr(rstring)
- expr = "print *(const char (*)[%d])%0#x" % (clen, cptr)
- append_command_output(debugger, expr, result)
+ append_expression(debugger, "*(const char (*)[%d])%0#x" % (clen, cptr), result)
def fixnum_p(x):
return x & RUBY_FIXNUM_FLAG != 0
@@ -216,6 +225,9 @@ def append_command_output(debugger, command, result):
result.write(output1)
result.write(output2)
+def append_expression(debugger, expression, result):
+ append_command_output(debugger, "expression " + expression, result)
+
def lldb_rp(debugger, command, result, internal_dict):
if not ('RUBY_Qfalse' in globals()):
lldb_init(debugger)
@@ -247,13 +259,13 @@ def lldb_inspect(debugger, target, result, val):
elif fixnum_p(num):
print(num >> 1, file=result)
elif flonum_p(num):
- append_command_output(debugger, "print rb_float_value(%0#x)" % val.GetValueAsUnsigned(), result)
+ append_expression(debugger, "rb_float_value(%0#x)" % val.GetValueAsUnsigned(), result)
elif static_sym_p(num):
if num < 128:
print("T_SYMBOL: %c" % num, file=result)
else:
print("T_SYMBOL: (%x)" % num, file=result)
- append_command_output(debugger, "p rb_id2name(%0#x)" % (num >> 8), result)
+ append_expression(debugger, "rb_id2name(%0#x)" % (num >> 8), result)
elif num & RUBY_IMMEDIATE_MASK:
print('immediate(%x)' % num, file=result)
else:
@@ -281,37 +293,43 @@ def lldb_inspect(debugger, target, result, val):
print('T_NIL: %s%s' % (flaginfo, val.Dereference()), file=result)
elif flType == RUBY_T_OBJECT:
result.write('T_OBJECT: %s' % flaginfo)
- append_command_output(debugger, "print *(struct RObject*)%0#x" % val.GetValueAsUnsigned(), result)
+ append_expression(debugger, "*(struct RObject*)%0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_CLASS or flType == RUBY_T_MODULE or flType == RUBY_T_ICLASS:
result.write('T_%s: %s' % ('CLASS' if flType == RUBY_T_CLASS else 'MODULE' if flType == RUBY_T_MODULE else 'ICLASS', flaginfo))
- append_command_output(debugger, "print *(struct RClass*)%0#x" % val.GetValueAsUnsigned(), result)
+ append_expression(debugger, "*(struct RClass*)%0#x" % val.GetValueAsUnsigned(), result)
+ tRClass = target.FindFirstType("struct RClass")
+ if not val.Cast(tRClass).GetChildMemberWithName("ptr").IsValid():
+ append_expression(debugger, "*(struct rb_classext_struct*)%0#x" % (val.GetValueAsUnsigned() + tRClass.GetByteSize()), result)
elif flType == RUBY_T_STRING:
result.write('T_STRING: %s' % flaginfo)
encidx = ((flags & RUBY_ENCODING_MASK)>>RUBY_ENCODING_SHIFT)
- result.write('[%s] ' % target.FindFirstType("enum ruby_preserved_encindex").GetEnumMembers().GetTypeEnumMemberAtIndex(encidx).GetName()[14:])
+ encname = target.FindFirstType("enum ruby_preserved_encindex").GetEnumMembers().GetTypeEnumMemberAtIndex(encidx).GetName()
+ if encname is not None:
+ result.write('[%s] ' % encname[14:])
+ else:
+ result.write('[enc=%d] ' % encidx)
tRString = target.FindFirstType("struct RString").GetPointerType()
ptr, len = string2cstr(val.Cast(tRString))
if len == 0:
result.write("(empty)\n")
else:
- append_command_output(debugger, "print *(const char (*)[%d])%0#x" % (len, ptr), result)
+ append_expression(debugger, "*(const char (*)[%d])%0#x" % (len, ptr), result)
elif flType == RUBY_T_SYMBOL:
result.write('T_SYMBOL: %s' % flaginfo)
tRSymbol = target.FindFirstType("struct RSymbol").GetPointerType()
val = val.Cast(tRSymbol)
- append_command_output(debugger, 'print (ID)%0#x ' % val.GetValueForExpressionPath("->id").GetValueAsUnsigned(), result)
+ append_expression(debugger, '(ID)%0#x ' % val.GetValueForExpressionPath("->id").GetValueAsUnsigned(), result)
tRString = target.FindFirstType("struct RString").GetPointerType()
output_string(debugger, result, val.GetValueForExpressionPath("->fstr").Cast(tRString))
elif flType == RUBY_T_ARRAY:
tRArray = target.FindFirstType("struct RArray").GetPointerType()
val = val.Cast(tRArray)
if flags & RUBY_FL_USER1:
- len = ((flags & (RUBY_FL_USER3|RUBY_FL_USER4)) >> (RUBY_FL_USHIFT+3))
+ len = ((flags & (RUBY_FL_USER3|RUBY_FL_USER4|RUBY_FL_USER5|RUBY_FL_USER6|RUBY_FL_USER7|RUBY_FL_USER8|RUBY_FL_USER9)) >> (RUBY_FL_USHIFT+3))
ptr = val.GetValueForExpressionPath("->as.ary")
else:
len = val.GetValueForExpressionPath("->as.heap.len").GetValueAsSigned()
ptr = val.GetValueForExpressionPath("->as.heap.ptr")
- #print(val.GetValueForExpressionPath("->as.heap"), file=result)
result.write("T_ARRAY: %slen=%d" % (flaginfo, len))
if flags & RUBY_FL_USER1:
result.write(" (embed)")
@@ -326,12 +344,12 @@ def lldb_inspect(debugger, target, result, val):
else:
result.write("\n")
if ptr.GetValueAsSigned() == 0:
- append_command_output(debugger, "expression -fx -- ((struct RArray*)%0#x)->as.ary" % val.GetValueAsUnsigned(), result)
+ append_expression(debugger, "-fx -- ((struct RArray*)%0#x)->as.ary" % val.GetValueAsUnsigned(), result)
else:
- append_command_output(debugger, "expression -Z %d -fx -- (const VALUE*)%0#x" % (len, ptr.GetValueAsUnsigned()), result)
+ append_expression(debugger, "-Z %d -fx -- (const VALUE*)%0#x" % (len, ptr.GetValueAsUnsigned()), result)
elif flType == RUBY_T_HASH:
result.write("T_HASH: %s" % flaginfo)
- append_command_output(debugger, "p *(struct RHash *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_expression(debugger, "*(struct RHash *) %0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_BIGNUM:
tRBignum = target.FindFirstType("struct RBignum").GetPointerType()
val = val.Cast(tRBignum)
@@ -339,15 +357,15 @@ def lldb_inspect(debugger, target, result, val):
if flags & RUBY_FL_USER2:
len = ((flags & (RUBY_FL_USER3|RUBY_FL_USER4|RUBY_FL_USER5)) >> (RUBY_FL_USHIFT+3))
print("T_BIGNUM: sign=%s len=%d (embed)" % (sign, len), file=result)
- append_command_output(debugger, "print ((struct RBignum *) %0#x)->as.ary" % val.GetValueAsUnsigned(), result)
+ append_expression(debugger, "((struct RBignum *) %0#x)->as.ary" % val.GetValueAsUnsigned(), result)
else:
len = val.GetValueForExpressionPath("->as.heap.len").GetValueAsSigned()
print("T_BIGNUM: sign=%s len=%d" % (sign, len), file=result)
print(val.Dereference(), file=result)
- append_command_output(debugger, "expression -Z %x -fx -- (const BDIGIT*)((struct RBignum*)%d)->as.heap.digits" % (len, val.GetValueAsUnsigned()), result)
- # append_command_output(debugger, "x ((struct RBignum *) %0#x)->as.heap.digits / %d" % (val.GetValueAsUnsigned(), len), result)
+ append_expression(debugger, "-Z %x -fx -- (const BDIGIT*)((struct RBignum*)%d)->as.heap.digits" % (len, val.GetValueAsUnsigned()), result)
+ # append_expression(debugger, "((struct RBignum *) %0#x)->as.heap.digits / %d" % (val.GetValueAsUnsigned(), len), result)
elif flType == RUBY_T_FLOAT:
- append_command_output(debugger, "print ((struct RFloat *)%d)->float_value" % val.GetValueAsUnsigned(), result)
+ append_expression(debugger, "((struct RFloat *)%d)->float_value" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_RATIONAL:
tRRational = target.FindFirstType("struct RRational").GetPointerType()
val = val.Cast(tRRational)
@@ -380,34 +398,39 @@ def lldb_inspect(debugger, target, result, val):
flag = val.GetValueForExpressionPath("->typed_flag")
if flag.GetValueAsUnsigned() == 1:
print("T_DATA: %s" % val.GetValueForExpressionPath("->type->wrap_struct_name"), file=result)
- append_command_output(debugger, "p *(struct RTypedData *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_expression(debugger, "*(struct RTypedData *) %0#x" % val.GetValueAsUnsigned(), result)
else:
print("T_DATA:", file=result)
- append_command_output(debugger, "p *(struct RData *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_expression(debugger, "*(struct RData *) %0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_NODE:
tRTypedData = target.FindFirstType("struct RNode").GetPointerType()
nd_type = (flags & RUBY_NODE_TYPEMASK) >> RUBY_NODE_TYPESHIFT
- append_command_output(debugger, "p (node_type) %d" % nd_type, result)
+ append_expression(debugger, "(node_type) %d" % nd_type, result)
val = val.Cast(tRTypedData)
- append_command_output(debugger, "p *(struct RNode *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_expression(debugger, "*(struct RNode *) %0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_MOVED:
tRTypedData = target.FindFirstType("struct RMoved").GetPointerType()
val = val.Cast(tRTypedData)
- append_command_output(debugger, "p *(struct RMoved *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_expression(debugger, "*(struct RMoved *) %0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_MATCH:
tRTypedData = target.FindFirstType("struct RMatch").GetPointerType()
val = val.Cast(tRTypedData)
- append_command_output(debugger, "p *(struct RMatch *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_expression(debugger, "*(struct RMatch *) %0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_IMEMO:
# I'm not sure how to get IMEMO_MASK out of lldb. It's not in globals()
imemo_type = (flags >> RUBY_FL_USHIFT) & 0x0F # IMEMO_MASK
+
print("T_IMEMO: ", file=result)
- append_command_output(debugger, "p (enum imemo_type) %d" % imemo_type, result)
- append_command_output(debugger, "p *(struct MEMO *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_expression(debugger, "(enum imemo_type) %d" % imemo_type, result)
+ append_expression(debugger, "*(struct MEMO *) %0#x" % val.GetValueAsUnsigned(), result)
+ elif flType == RUBY_T_STRUCT:
+ tRTypedData = target.FindFirstType("struct RStruct").GetPointerType()
+ val = val.Cast(tRTypedData)
+ append_expression(debugger, "*(struct RStruct *) %0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_ZOMBIE:
tRZombie = target.FindFirstType("struct RZombie").GetPointerType()
val = val.Cast(tRZombie)
- append_command_output(debugger, "p *(struct RZombie *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_expression(debugger, "*(struct RZombie *) %0#x" % val.GetValueAsUnsigned(), result)
else:
print("Not-handled type %0#x" % flType, file=result)
print(val, file=result)
@@ -448,19 +471,6 @@ def check_bits(page, bitmap_name, bitmap_index, bitmap_bit, v):
else:
return ' '
-def heap_page(debugger, command, ctx, result, internal_dict):
- target = debugger.GetSelectedTarget()
- process = target.GetProcess()
- thread = process.GetSelectedThread()
- frame = thread.GetSelectedFrame()
-
- val = frame.EvaluateExpression(command)
- page = get_page(lldb, target, val)
- page_type = target.FindFirstType("struct heap_page").GetPointerType()
- page.Cast(page_type)
- append_command_output(debugger, "p (struct heap_page *) %0#x" % page.GetValueAsUnsigned(), result)
- append_command_output(debugger, "p *(struct heap_page *) %0#x" % page.GetValueAsUnsigned(), result)
-
def heap_page_body(debugger, command, ctx, result, internal_dict):
target = debugger.GetSelectedTarget()
process = target.GetProcess()
@@ -493,6 +503,8 @@ def dump_node(debugger, command, ctx, result, internal_dict):
output_string(ctx, result, dump)
def rb_backtrace(debugger, command, result, internal_dict):
+ if not ('RUBY_Qfalse' in globals()):
+ lldb_init(debugger)
bt = BackTrace(debugger, command, result, internal_dict)
frame = bt.frame
@@ -591,9 +603,13 @@ def dump_page_internal(page, target, process, thread, frame, result, debugger, h
try:
flidx = "%3d" % freelist.index(obj_addr)
except ValueError:
- flidx = ' '
+ flidx = ' -1'
- result_str = "%s idx: [%3d] freelist_idx: {%s} Addr: %0#x (flags: %0#x)" % (rb_type(flags, ruby_type_map), page_index, flidx, obj_addr, flags)
+ if flType == RUBY_T_NONE:
+ klass = obj.GetChildMemberWithName('klass').GetValueAsUnsigned()
+ result_str = "%s idx: [%3d] freelist_idx: {%s} Addr: %0#x (flags: %0#x, next: %0#x)" % (rb_type(flags, ruby_type_map), page_index, flidx, obj_addr, flags, klass)
+ else:
+ result_str = "%s idx: [%3d] freelist_idx: {%s} Addr: %0#x (flags: %0#x)" % (rb_type(flags, ruby_type_map), page_index, flidx, obj_addr, flags)
if highlight == obj_addr:
result_str = ' '.join([result_str, "<<<<<"])
@@ -697,18 +713,37 @@ def rb_id2str(debugger, command, result, internal_dict):
pos = (num % ID_ENTRY_UNIT) * ID_ENTRY_SIZE
id_str = rb_ary_entry(target, ary, pos, result)
lldb_inspect(debugger, target, result, id_str)
+# END FUNCTION STYLE DECLS
+
+
+load_dir, _ = os.path.split(os.path.realpath(__file__))
+
+for fname in glob.glob(f"{load_dir}/lldb_rb/commands/*_command.py"):
+ _, basename = os.path.split(fname)
+ mname, _ = os.path.splitext(basename)
+
+ exec(f"import lldb_rb.commands.{mname}")
def __lldb_init_module(debugger, internal_dict):
- debugger.HandleCommand("command script add -f lldb_cruby.lldb_rp rp")
+ # Register all classes that subclass RbBaseCommand
+
+ for memname, mem in inspect.getmembers(sys.modules["lldb_rb.rb_base_command"]):
+ if memname == "RbBaseCommand":
+ for sclass in mem.__subclasses__():
+ sclass.register_lldb_command(debugger, f"{__name__}.{sclass.__module__}")
+
+
+ ## FUNCTION INITS - These should be removed when converted to class commands
+ debugger.HandleCommand("command script add -f lldb_cruby.lldb_rp old_rp")
debugger.HandleCommand("command script add -f lldb_cruby.count_objects rb_count_objects")
debugger.HandleCommand("command script add -f lldb_cruby.stack_dump_raw SDR")
debugger.HandleCommand("command script add -f lldb_cruby.dump_node dump_node")
- debugger.HandleCommand("command script add -f lldb_cruby.heap_page heap_page")
debugger.HandleCommand("command script add -f lldb_cruby.heap_page_body heap_page_body")
debugger.HandleCommand("command script add -f lldb_cruby.rb_backtrace rbbt")
debugger.HandleCommand("command script add -f lldb_cruby.dump_page dump_page")
debugger.HandleCommand("command script add -f lldb_cruby.dump_page_rvalue dump_page_rvalue")
- debugger.HandleCommand("command script add -f lldb_cruby.rb_id2str rb_id2str")
+ debugger.HandleCommand("command script add -f lldb_cruby.rb_id2str old_rb_id2str")
+
+ lldb_rb.rb_base_command.RbBaseCommand.lldb_init(debugger)
- lldb_init(debugger)
print("lldb scripts for ruby has been installed.")