def trace (self): self.type = 'list' self.curr = None self.main = gdb.eval('rb_main_thread') self.unwind = gdb.parameter('unwindonsignal') gdb.execute('set unwindonsignal on') gdb.execute('watch rb_curr_thread') gdb.breakpoints()[-1].silent = True num = gdb.breakpoints()[-1].number try: prev = None while True: gdb.execute('continue') curr = gdb.eval('rb_curr_thread') if curr == prev: break self.print_thread(curr) prev = curr except KeyboardInterrupt: None gdb.execute('delete %d' % num) gdb.execute('set unwindonsignal %s' % (self.unwind and 'on' or 'off'))
def invoke (self, arg, from_tty): self.dont_repeat() num = arg and int(arg) or 100 self.setup() try: while num > 0: num -= 1 gdb.execute('continue') frame = gdb.selected_frame() if frame.pc() != self.func: raise KeyboardInterrupt node = gdb.eval('(NODE*) $rsi') file = node['nd_file'].string() line = gdb.eval('nd_line(%s)' % node) method = gdb.eval('rb_id2name($rcx)') method = method > 0 and method.string() or '(unknown)' print "%s in %s:%d" % (method,file,line) self.teardown() except KeyboardInterrupt: self.teardown() except RuntimeError, text: self.teardown() if not re.search('signaled while in a function called from GDB', text): raise
def print_stack (self, th, frame, node): while True: stk_pos = th['stk_pos'] stk_ptr = th['stk_ptr'] stk_len = th['stk_len'] addr = gdb.eval('(VALUE*)%s' % frame) if not self.is_heap_stack and th != self.curr and stk_pos < addr and addr < (stk_pos+stk_len): frame = (addr-stk_pos) + stk_ptr frame = gdb.eval('(struct FRAME *)%s' % frame) node = frame['node'] file = node['nd_file'].string() line = gdb.eval('nd_line(%s)' % node) type = gdb.eval('(enum node_type) nd_type(%s)' % node) if frame['last_func']: try: method = gdb.eval('rb_id2name(%s)' % frame['last_func']).string() except: method = '(unknown)' else: method = '(unknown)' print " ", print str(type).lower().center(18), "%s in %s:%d" % (method, file, line) if frame['prev'] == 0 or frame['last_func'] == 0: break frame = frame['prev'] node = frame['node'] if node == 0: break
def all_objects (self): self.heaps_used = gdb.eval('heaps_used') for i in xrange(self.heaps_used): p = gdb.eval("(RVALUE*) heaps[%i].slot" % i) pend = p + gdb.eval("heaps[%i].limit" % i) while p < pend: yield p, p['as']['basic']['flags'] p += 1
def invoke (self, arg, from_tty): self.dont_repeat() cache = gdb.eval('cache') size = 0x800 empty = 0 for i in xrange(size): entry = cache[i] if entry['mid'] != 0: klass = gdb.eval('rb_class2name(%d)' % entry['klass']) method = gdb.eval('rb_id2name(%d)' % entry['mid']) print " %s#%s" % (klass and klass.string() or '(unknown)', method and method.string() or '(unknown)') else: empty += 1 print print "%d empty slots (%.2f%%)" % (empty, empty*100.0/size) print
def print_nodes (self): nodes = ZeroDict() for (obj, type) in self.live_objects(): if type == 0x3f: nodes[ (int(obj['as']['node']['flags']) >> 12) & 0xff ] += 1 for (node, num) in sorted(nodes.items(), key=lambda(k,v):(v,k)): print "% 8d %s" % (num, gdb.eval('(enum node_type) (%d)' % node))
def print_classes (self): classes = ZeroDict() for (obj, type) in self.live_objects(): if type == 0x2: classes[ int(obj['as']['basic']['klass']) ] += 1 for (klass, num) in sorted(classes.items(), key=lambda(k,v):(v,k)): print "% 8d %s" % (num, gdb.eval('rb_class2name(%d)' % klass).string())
def print_thread (self, th): if self.type != 'list': print print th, print th == self.main and 'main' or ' ', print th == self.curr and 'curr' or ' ', print "thread", " %s" % str(th['status']).ljust(16), "%s" % self.wait_state(th), " ", if th != self.curr: print "% 8d bytes" % th['stk_len'] else: print if self.type == 'list': return if th == self.curr: frame = gdb.eval('ruby_frame') node = gdb.eval('ruby_current_node') else: frame = th['frame'] node = frame['node'] self.print_stack(th, frame, node)
def invoke (self, arg, from_tty): self.dont_repeat() type = int(gdb.eval("((struct RBasic *)(%d))->flags & 0x3f" % int(arg,0))) rtype = RubyObjects.TYPES.get(type, 'unknown') if rtype == 'array': print rtype elif rtype == 'hash': print rtype else: print 'unknown'
def show (self): self.main = gdb.eval('rb_main_thread') self.curr = gdb.eval('rb_curr_thread') self.now = time.time() try: gdb.eval('rb_thread_start_2') except RuntimeError: self.is_heap_stack = False else: self.is_heap_stack = True if self.main == 0: print "Ruby VM is not running!" else: th = self.main while True: self.print_thread(th) th = th['next'] if th == self.main: break print
def setup (self): commands = """ set $func = malloc(1) p ((char*)$func)[0] = '\xc3' p mprotect(($func&0xfffffffffffff000), 1, 0x7) p rb_add_event_hook($func, RUBY_EVENT_C_CALL|RUBY_EVENT_CALL) b *$func """.split("\n") for c in commands: gdb.execute(c) gdb.breakpoints()[-1].silent = True self.func = gdb.eval('$func') self.unwind = gdb.parameter('unwindonsignal') gdb.execute('set unwindonsignal on')
def print_classes (self): classes = ZeroDict() for (obj, type) in self.live_objects(): if type == 0x0: pass # none elif type == 0x3b: pass # blktag elif type == 0x3c: pass # undef elif type == 0x3d: pass # varmap elif type == 0x3e: pass # scope elif type == 0x3f: pass # node else: klass = obj['as']['basic']['klass'] if klass: classes[ int(klass) ] += 1 for (klass, num) in sorted(classes.items(), key=lambda(k,v):(v,k)): print "% 8d %s" % (num, gdb.eval('rb_class2name(%d)' % klass).string())
def invoke (self, arg, from_tty): self.dont_repeat() arg = arg.replace('\\', '\\\\').replace('"', '\\\"') print gdb.eval("((struct RString*)rb_eval_string_protect(\"begin; (%s).inspect; rescue Exception => e; e.inspect; end\", 0))->ptr" % arg).string()