From d6fc9ad48e9f40ae406d663ac3a96f48b385ddec Mon Sep 17 00:00:00 2001 From: Tomasz Grabiec Date: Fri, 22 Jul 2016 14:44:02 +0200 Subject: [PATCH 1/3] scylla-gdb.py: Break down code into finer abstractions --- scylla-gdb.py | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/scylla-gdb.py b/scylla-gdb.py index 90d440e03b..6f76324e8d 100644 --- a/scylla-gdb.py +++ b/scylla-gdb.py @@ -211,17 +211,18 @@ class scylla_memory(gdb.Command): front = int(span['link']['_next']) gdb.write('{index:5} {size:13} {total}\n'.format(index=index, size=(1< Date: Fri, 22 Jul 2016 14:44:59 +0200 Subject: [PATCH 2/3] scylla-gdb.py: Introduce "scylla thread" command Switches into a seastar thread. "scylla unthread" switches back. Example: ``` (gdb) scylla thread 0x6000000e1800 Switched to thread 1, (seastar::thread_context*) 0x6000000e1800 (gdb) bt #0 seastar::thread_context::switch_out (this=0x6000000e1800) at core/thread.cc:104 #1 0x00000000004cfb07 in future<>::wait() (this=0x600008ca2c70) at core/future.hh:817 #2 0x0000000000f7752c in future<>::get() (this=0x600008ca2c70) at /home/tgrabiec/src/scylla2/seastar/core/future.hh:787 ... #16 seastar::thread_context::main (this=0x6000000e1800) at core/thread.cc:166 #17 0x000000000051a702 in seastar::thread_context::s_main (lo=, hi=) at core/thread.cc:157 #18 0x00007f2c34861f20 in ?? () from /lib64/libc.so.6 #19 0x0000000000000000 in ?? () (gdp) scylla unthread Switched to thread 1 ``` --- scylla-gdb.py | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/scylla-gdb.py b/scylla-gdb.py index 6f76324e8d..19149d8f7f 100644 --- a/scylla-gdb.py +++ b/scylla-gdb.py @@ -225,6 +225,12 @@ def seastar_memory_layout(): results.append((t, start, total_mem)) return results +def get_thread_owning_memory(ptr): + for t in reactor_threads(): + start, size = get_seastar_memory_start_and_size() + if start <= ptr < start + size: + return t + class scylla_ptr(gdb.Command): def __init__(self): gdb.Command.__init__(self, 'scylla ptr', gdb.COMMAND_USER, gdb.COMPLETE_COMMAND) @@ -424,6 +430,116 @@ class thread_switched_in(object): def __exit__(self, *_): self.old.switch() +class seastar_thread_context(object): + ulong_type = gdb.lookup_type('unsigned long') + + # FIXME: The jmpbuf interpreting code targets x86_64 and glibc 2.19 + # Offsets taken from sysdeps/x86_64/jmpbuf-offsets.h. + jmpbuf_offsets = { + 'rbx': 0, + 'rbp': 1, + 'r12': 2, + 'r13': 3, + 'r14': 4, + 'r15': 5, + 'rsp': 6, + 'rip': 7, + } + mangled_registers = ['rip', 'rsp', 'rbp'] + + def save_regs(self): + result = {} + for reg in self.jmpbuf_offsets.keys(): + result[reg] = gdb.parse_and_eval('$%s' % reg).cast(self.ulong_type) + return result + + def restore_regs(self, values): + gdb.newest_frame().select() + for reg, value in values.items(): + gdb.execute('set $%s = %s' % (reg, value)) + + def get_fs_base(self): + holder_addr = get_seastar_memory_start_and_size()[0] + holder = gdb.Value(holder_addr).reinterpret_cast(self.ulong_type.pointer()) + saved = holder.dereference() + gdb.execute('set *(void**)%s = 0' % holder_addr) + if gdb.parse_and_eval('arch_prctl(0x1003, %d)' % holder_addr) != 0: + raise Exception('arch_prctl() failed') + fs_base = holder.dereference() + gdb.execute('set *(void**)%s = %s' % (holder_addr, saved)) + return fs_base + + def regs_from_jmpbuf(self, jmpbuf): + canary = gdb.Value(self.get_fs_base()).reinterpret_cast(self.ulong_type.pointer())[6] + result = {} + for reg, offset in self.jmpbuf_offsets.items(): + value = jmpbuf['__jmpbuf'][offset].cast(self.ulong_type) + if reg in self.mangled_registers: + # glibc mangles by doing: + # xor %reg, %fs:0x30 + # rol %reg, $0x11 + bits = 64 + shift = 0x11 + value = (value << (bits-shift)) & (2**bits-1) | (value >> shift) + value = value ^ canary + result[reg] = value + return result + + def is_switched_in(self): + jmpbuf_link_ptr = gdb.parse_and_eval('seastar::g_current_context') + if jmpbuf_link_ptr['thread'] == self.thread_ctx.address: + return True + return False + + def __init__(self, thread_ctx): + self.thread_ctx = thread_ctx + self.old_frame = gdb.selected_frame() + self.old_regs = self.save_regs() + self.old_gdb_thread = gdb.selected_thread() + self.gdb_thread = get_thread_owning_memory(thread_ctx.address) + self.new_regs = None + + def __enter__(self): + gdb.write('Switched to thread %d, (seastar::thread_context*) 0x%x\n' % (self.gdb_thread.num, self.thread_ctx.address)) + self.gdb_thread.switch() + if not self.is_switched_in(): + self.new_regs = self.regs_from_jmpbuf(self.thread_ctx['_context']['jmpbuf']) + self.restore_regs(self.new_regs) + + def __exit__(self, *_): + if self.new_regs: + self.gdb_thread.switch() + self.restore_regs(self.old_regs) + self.old_gdb_thread.switch() + self.old_frame.select() + gdb.write('Switched to thread %d\n' % self.old_gdb_thread.num) + +active_thread_context = None + +def exit_thread_context(): + global active_thread_context + if active_thread_context: + active_thread_context.__exit__() + active_thread_context = None + +class scylla_thread(gdb.Command): + def __init__(self): + gdb.Command.__init__(self, 'scylla thread', gdb.COMMAND_USER, + gdb.COMPLETE_COMMAND, True) + def invoke(self, arg, for_tty): + addr = gdb.parse_and_eval(arg) + ctx = addr.reinterpret_cast(gdb.lookup_type('seastar::thread_context').pointer()).dereference() + exit_thread_context() + global active_thread_context + active_thread_context = seastar_thread_context(ctx) + active_thread_context.__enter__() + +class scylla_unthread(gdb.Command): + def __init__(self): + gdb.Command.__init__(self, 'scylla unthread', gdb.COMMAND_USER, gdb.COMPLETE_NONE, True) + def invoke(self, arg, for_tty): + exit_thread_context() + scylla() scylla_databases() scylla_keyspaces() @@ -436,3 +552,5 @@ scylla_lsa_zones() scylla_timers() scylla_apply() scylla_shard() +scylla_thread() +scylla_unthread() From 0db79c71534f907ab3588d039b6a2dd22bda2601 Mon Sep 17 00:00:00 2001 From: Tomasz Grabiec Date: Fri, 22 Jul 2016 15:18:51 +0200 Subject: [PATCH 3/3] scylla-gdb.py: Introduce "scylla mem-range" command Prints memory range belonging to current shard. --- scylla-gdb.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/scylla-gdb.py b/scylla-gdb.py index 19149d8f7f..9f7d3e2897 100644 --- a/scylla-gdb.py +++ b/scylla-gdb.py @@ -421,6 +421,15 @@ class scylla_mem_ranges(gdb.Command): for t, start, total_mem in seastar_memory_layout(): gdb.write('0x%x +%d\n' % (start, total_mem)) +class scylla_mem_range(gdb.Command): + def __init__(self): + gdb.Command.__init__(self, 'scylla mem-range', gdb.COMMAND_USER, gdb.COMPLETE_NONE) + def invoke(self, arg, from_tty): + if not has_reactor(): + gdb.write('Not a reactor thread') + return + gdb.write('0x%x +%d\n' % get_seastar_memory_start_and_size()) + class thread_switched_in(object): def __init__(self, gdb_thread): self.new = gdb_thread @@ -547,6 +556,7 @@ scylla_column_families() scylla_memory() scylla_ptr() scylla_mem_ranges() +scylla_mem_range() scylla_lsa() scylla_lsa_zones() scylla_timers()