summaryrefslogtreecommitdiff
path: root/misc/gdb.py
diff options
context:
space:
mode:
Diffstat (limited to 'misc/gdb.py')
-rw-r--r--misc/gdb.py115
1 files changed, 83 insertions, 32 deletions
diff --git a/misc/gdb.py b/misc/gdb.py
index 85507fb540..6034a389bb 100644
--- a/misc/gdb.py
+++ b/misc/gdb.py
@@ -1,8 +1,18 @@
+import argparse
import textwrap
-# Usage:
-# cfp: Dump the current cfp
-# cfp 1: Dump the caller cfp
+# usage: [-h] [-a | --all | --no-all] [-s STACK_SIZE] [uplevel]
+#
+# Dump a control frame
+#
+# positional arguments:
+# uplevel CFP offset from the stack top
+#
+# options:
+# -h, --help show this help message and exit
+# -a, --all, --no-all dump all frames
+# -s STACK_SIZE, --stack-size STACK_SIZE
+# override stack_size (useful for JIT frames)
class CFP(gdb.Command):
FRAME_MAGICS = [
# frame types
@@ -35,44 +45,77 @@ class CFP(gdb.Command):
def __init__(self):
super(CFP, self).__init__('cfp', gdb.COMMAND_USER)
- def invoke(self, offset, from_tty):
- if not offset:
- offset = '0'
- cfp = f'(ruby_current_ec->cfp + ({offset}))'
-
+ self.parser = argparse.ArgumentParser(description='Dump a control frame')
+ self.parser.add_argument('uplevel', type=int, nargs='?', default=0, help='CFP offset from the stack top')
+ self.parser.add_argument('-a', '--all', action=argparse.BooleanOptionalAction, help='dump all frames')
+ self.parser.add_argument('-s', '--stack-size', type=int, help='override stack_size (useful for JIT frames)')
+
+ def invoke(self, args, from_tty):
+ try:
+ args = self.parser.parse_args(args.split())
+ except SystemExit:
+ return
+ cfp = f'(ruby_current_ec->cfp + ({args.uplevel}))'
end_cfp = self.get_int('ruby_current_ec->vm_stack + ruby_current_ec->vm_stack_size')
- cfp_count = int((end_cfp - self.get_int('ruby_current_ec->cfp')) / self.get_int('sizeof(rb_control_frame_t)'))
- print('CFP (count={}, addr=0x{:x}):'.format(cfp_count, self.get_int(cfp)))
+ cfp_index = int((end_cfp - self.get_int(cfp) - 1) / self.get_int('sizeof(rb_control_frame_t)'))
+
+ if args.all:
+ cfp_count = int((end_cfp - self.get_int('ruby_current_ec->cfp')) / self.get_int('sizeof(rb_control_frame_t)')) - 1 # exclude dummy CFP
+ for i in range(cfp_count):
+ print('-' * 80)
+ self.invoke(str(cfp_count - i - 1), from_tty)
+ return
+
+ print('CFP (addr=0x{:x}, index={}):'.format(self.get_int(cfp), cfp_index))
gdb.execute(f'p *({cfp})')
print()
if self.get_int(f'{cfp}->iseq'):
local_size = self.get_int(f'{cfp}->iseq->body->local_table_size - {cfp}->iseq->body->param.size')
param_size = self.get_int(f'{cfp}->iseq->body->param.size')
- print(f'Params (size={param_size}):')
- for i in range(-3 - local_size - param_size, -3 - local_size):
- self.print_stack(cfp, i, self.rp(cfp, i))
- print()
- print(f'Locals (size={local_size}):')
- for i in range(-3 - local_size, -3):
- self.print_stack(cfp, i, self.rp(cfp, i))
- print()
+ if local_size:
+ print(f'Params (size={param_size}):')
+ for i in range(-3 - local_size - param_size, -3 - local_size):
+ self.print_stack(cfp, i, self.rp(cfp, i))
+ print()
+
+ if param_size:
+ print(f'Locals (size={local_size}):')
+ for i in range(-3 - local_size, -3):
+ self.print_stack(cfp, i, self.rp(cfp, i))
+ print()
print('Env:')
- self.print_stack(cfp, -3, self.rp(cfp, -3))
- self.print_stack(cfp, -2, self.specval(cfp, -2))
- self.print_stack(cfp, -1, self.frame_types(cfp, -1))
+ self.print_env(cfp, -3, self.rp_env(cfp, -3))
+ self.print_env(cfp, -2, self.specval(cfp, -2))
+ self.print_env(cfp, -1, self.frame_types(cfp, -1))
print()
- stack_size = int((self.get_int(f'{cfp}->sp') - self.get_int(f'{cfp}->__bp__')) / 8)
- print(f'Stack (size={stack_size}):')
- for i in range(0, stack_size):
- self.print_stack(cfp, i, self.rp(cfp, i))
- print(self.regs(cfp, stack_size))
+ # We can't calculate BP for the first frame.
+ # vm_base_ptr doesn't work for C frames either.
+ if cfp_index > 0 and self.get_int(f'{cfp}->iseq'):
+ if args.stack_size is not None:
+ stack_size = args.stack_size
+ else:
+ stack_size = int((self.get_int(f'{cfp}->sp') - self.get_int(f'vm_base_ptr({cfp})')) / 8)
+ print(f'Stack (size={stack_size}):')
+ for i in range(0, stack_size):
+ self.print_stack(cfp, i, self.rp(cfp, i))
+ print(self.regs(cfp, stack_size))
+
+ def print_env(self, cfp, bp_index, content):
+ ep_index = bp_index + 1
+ address = self.get_int(f'((rb_control_frame_t *){cfp})->ep + {ep_index}')
+ value = self.get_env(cfp, bp_index)
+ regs = self.regs(cfp, bp_index)
+ if content:
+ content = textwrap.indent(content, ' ' * 3).lstrip() # Leave the regs column empty
+ content = f'{content} '
+ print('{:2} 0x{:x} [{}] {}(0x{:x})'.format(regs, address, bp_index, content, value))
def print_stack(self, cfp, bp_index, content):
- address = self.get_int(f'{cfp}->__bp__ + {bp_index}')
+ address = self.get_int(f'vm_base_ptr({cfp}) + {bp_index}')
value = self.get_value(cfp, bp_index)
regs = self.regs(cfp, bp_index)
if content:
@@ -81,9 +124,9 @@ class CFP(gdb.Command):
print('{:2} 0x{:x} [{}] {}(0x{:x})'.format(regs, address, bp_index, content, value))
def regs(self, cfp, bp_index):
- address = self.get_int(f'{cfp}->__bp__ + {bp_index}')
+ address = self.get_int(f'vm_base_ptr({cfp}) + {bp_index}')
regs = []
- for reg, field in { 'EP': 'ep', 'BP': '__bp__', 'SP': 'sp' }.items():
+ for reg, field in { 'EP': 'ep', 'SP': 'sp' }.items():
if address == self.get_int(f'{cfp}->{field}'):
regs.append(reg)
return ' '.join(regs)
@@ -92,9 +135,13 @@ class CFP(gdb.Command):
value = self.get_value(cfp, bp_index)
return self.get_string(f'rp {value}').rstrip()
+ def rp_env(self, cfp, bp_index):
+ value = self.get_env(cfp, bp_index)
+ return self.get_string(f'rp {value}').rstrip()
+
# specval: block_handler or previous EP
def specval(self, cfp, bp_index):
- value = self.get_value(cfp, bp_index)
+ value = self.get_env(cfp, bp_index)
if value == 0:
return 'VM_BLOCK_HANDLER_NONE'
if value == self.get_int('rb_block_param_proxy'):
@@ -103,7 +150,7 @@ class CFP(gdb.Command):
def frame_types(self, cfp, bp_index):
types = []
- value = self.get_value(cfp, bp_index)
+ value = self.get_env(cfp, bp_index)
magic_mask = self.get_int('VM_FRAME_MAGIC_MASK')
for magic in self.FRAME_MAGICS:
@@ -118,8 +165,12 @@ class CFP(gdb.Command):
return ' | '.join(types)
+ def get_env(self, cfp, bp_index):
+ ep_index = bp_index + 1
+ return self.get_int(f'((rb_control_frame_t *){cfp})->ep[{ep_index}]')
+
def get_value(self, cfp, bp_index):
- return self.get_int(f'{cfp}->__bp__[{bp_index}]')
+ return self.get_int(f'vm_base_ptr({cfp})[{bp_index}]')
def get_int(self, expr):
return int(self.get_string(f'printf "%ld", ({expr})'))