diff options
author | Matt Valentine-House <matt@eightbitraptor.com> | 2022-07-13 18:14:44 +0100 |
---|---|---|
committer | Peter Zhu <peter@peterzhu.ca> | 2022-08-18 13:25:32 -0400 |
commit | b26aec9daa03a4f3da225e9e4f7a43e916928712 (patch) | |
tree | b2002f074b354f743f701b28d3c080d2ec70f5f8 /misc/lldb_rb | |
parent | a4ef2f16728b4b1eb49cc3aded26219cabdfa7e7 (diff) | |
download | ruby-b26aec9daa03a4f3da225e9e4f7a43e916928712.tar.gz |
[ci-skip][Feature #18910][lldb] New directory structure
Push the newly refactored lldb files into a sub-directory so that we're
not cluttering up the misc directory
Diffstat (limited to 'misc/lldb_rb')
-rw-r--r-- | misc/lldb_rb/commands/command_template.py | 30 | ||||
-rw-r--r-- | misc/lldb_rb/commands/heap_page_command.py | 26 | ||||
-rw-r--r-- | misc/lldb_rb/commands/rclass_ext_command.py | 14 | ||||
-rw-r--r-- | misc/lldb_rb/constants.py | 4 | ||||
-rw-r--r-- | misc/lldb_rb/rb_base_command.py | 68 |
5 files changed, 142 insertions, 0 deletions
diff --git a/misc/lldb_rb/commands/command_template.py b/misc/lldb_rb/commands/command_template.py new file mode 100644 index 0000000000..843b66398f --- /dev/null +++ b/misc/lldb_rb/commands/command_template.py @@ -0,0 +1,30 @@ +# This is a command template for implementing a helper function inside LLDB. To +# use this file +# 1. Copy it and rename the copy so it ends with `_command.py`. +# 2. Rename the class to something descriptive that ends with Command. +# 3. Change the program variable to be a descriptive command name +# 4. Ensure you are inheriting from RbBaseCommand or another command that +# implements the same interfact + +import lldb + +from lldb_rb.constants import * +from lldb_rb.rb_base_command import RbBaseCommand + +# This test command inherits from RbBaseCommand which provides access to Ruby +# globals and utility helpers +class TestCommand(RbBaseCommand): + # program is the keyword the user will type in lldb to execute this command + program = "test" + + # help_string will be displayed in lldb when the user uses the help functions + help_string = "This is a test command to show how to implement lldb commands" + + # call is where our command logic will be implemented + def call(self, debugger, command, exe_ctx, result): + # This method will be called once the LLDB environment has been setup. + # You will have access to self.target, self.process, self.frame, and + # self.thread + # + # This is where we should implement our command logic + pass diff --git a/misc/lldb_rb/commands/heap_page_command.py b/misc/lldb_rb/commands/heap_page_command.py new file mode 100644 index 0000000000..edb74a415b --- /dev/null +++ b/misc/lldb_rb/commands/heap_page_command.py @@ -0,0 +1,26 @@ +import lldb + +from lldb_rb.constants import * +from lldb_rb.rb_base_command import RbBaseCommand + +class HeapPageCommand(RbBaseCommand): + program = "heap_page" + help_string = "prints out 'struct heap_page' for a VALUE pointer in the page" + + def call(self, debugger, command, exe_ctx, 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_command_output(debugger, "p (struct heap_page *) %0#x" % page.GetValueAsUnsigned(), result) + self._append_command_output(debugger, "p *(struct heap_page *) %0#x" % page.GetValueAsUnsigned(), result) + + def _get_page(self, val): + addr = val.GetValueAsUnsigned() + page_addr = addr & ~(HEAP_PAGE_ALIGN_MASK) + address = lldb.SBAddress(page_addr, self.target) + body = self.target.CreateValueFromAddress("page", address, self.t_heap_page_body) + + return body.GetValueForExpressionPath("->header.page") diff --git a/misc/lldb_rb/commands/rclass_ext_command.py b/misc/lldb_rb/commands/rclass_ext_command.py new file mode 100644 index 0000000000..8bae911457 --- /dev/null +++ b/misc/lldb_rb/commands/rclass_ext_command.py @@ -0,0 +1,14 @@ +from lldb_rb.rb_base_command import RbBaseCommand + +class RclassExtCommand(RbBaseCommand): + program = "rclass_ext" + help_string = "retrieves and prints the rb_classext_struct for the VALUE pointer passed in" + + def call(self, debugger, command, exe_ctx, result): + uintptr_t = self.target.FindFirstType("uintptr_t") + rclass_t = self.target.FindFirstType("struct RClass") + rclass_ext_t = self.target.FindFirstType("rb_classext_t") + + rclass_addr = self.target.EvaluateExpression(command).Cast(uintptr_t) + rclass_ext_addr = (rclass_addr.GetValueAsUnsigned() + rclass_t.GetByteSize()) + debugger.HandleCommand("p *(rb_classext_t *)%0#x" % rclass_ext_addr) diff --git a/misc/lldb_rb/constants.py b/misc/lldb_rb/constants.py new file mode 100644 index 0000000000..ec3050a399 --- /dev/null +++ b/misc/lldb_rb/constants.py @@ -0,0 +1,4 @@ +HEAP_PAGE_ALIGN_LOG = 16 +HEAP_PAGE_ALIGN_MASK = (~(~0 << HEAP_PAGE_ALIGN_LOG)) +HEAP_PAGE_ALIGN = (1 << HEAP_PAGE_ALIGN_LOG) +HEAP_PAGE_SIZE = HEAP_PAGE_ALIGN diff --git a/misc/lldb_rb/rb_base_command.py b/misc/lldb_rb/rb_base_command.py new file mode 100644 index 0000000000..44b2996d80 --- /dev/null +++ b/misc/lldb_rb/rb_base_command.py @@ -0,0 +1,68 @@ +import lldb +from pydoc import locate + +class RbBaseCommand: + @classmethod + def register_lldb_command(cls, debugger, module_name): + # Add any commands contained in this module to LLDB + command = f"command script add -c {module_name}.{cls.__name__} {cls.program}" + debugger.HandleCommand(command) + + def __init__(self, debugger, _internal_dict): + self.internal_dict = _internal_dict + + def __call__(self, debugger, command, exe_ctx, result): + if not ("RUBY_Qfalse" in globals()): + self._lldb_init(debugger) + + self.build_environment(debugger) + self.call(debugger, command, exe_ctx, result) + + def call(self, debugger, command, exe_ctx, result): + raise NotImplementedError("subclasses must implement call") + + def get_short_help(self): + return self.__class__.help_string + + def get_long_help(self): + return self.__class__.help_string + + def build_environment(self, debugger): + self.target = debugger.GetSelectedTarget() + self.process = self.target.GetProcess() + self.thread = self.process.GetSelectedThread() + self.frame = self.thread.GetSelectedFrame() + + def _append_command_output(self, debugger, command, result): + output1 = result.GetOutput() + debugger.GetCommandInterpreter().HandleCommand(command, result) + output2 = result.GetOutput() + result.Clear() + result.write(output1) + result.write(output2) + + def _lldb_init(self, debugger): + target = debugger.GetSelectedTarget() + global SIZEOF_VALUE + SIZEOF_VALUE = target.FindFirstType("VALUE").GetByteSize() + + value_types = [] + g = globals() + + imemo_types = target.FindFirstType("enum imemo_type") + + for member in imemo_types.GetEnumMembers(): + g[member.GetName()] = member.GetValueAsUnsigned() + + for enum in target.FindFirstGlobalVariable("ruby_dummy_gdb_enums"): + enum = enum.GetType() + members = enum.GetEnumMembers() + for i in range(0, members.GetSize()): + member = members.GetTypeEnumMemberAtIndex(i) + name = member.GetName() + value = member.GetValueAsUnsigned() + g[name] = value + + if name.startswith("RUBY_T_"): + value_types.append(name) + g["value_types"] = value_types |