import lldb import traceback def print_frames(thread, num_frames, current_thread): # TODO: Make output header similar to bt. print('%c thread #%i' % ('*' if current_thread else ' ', thread.idx)) if current_thread: selected_frame = thread.GetSelectedFrame() for frame in thread.frames[:+num_frames]: pc = str(frame.addr) var = frame function_name = frame.GetFunctionName() if function_name == "interp_exec_method_full": try: s = 'frame->imethod->method' methoddesc = frame.EvaluateExpression('(char*) mono_method_full_name (' + s + ', 1)').summary[1:-1] ipoffset = frame.EvaluateExpression('ip').GetValueAsUnsigned() insn = '' if ipoffset != 0: ipoffset -= frame.EvaluateExpression('frame->imethod->code').GetValueAsUnsigned() insn = "\"" + frame.EvaluateExpression('mono_interp_opname (*ip)').summary[1:-1] + "\"" var = '%s @ %d %s || %s' % (methoddesc, ipoffset, insn, frame) except Exception as e: traceback.print_exc() elif function_name == "mono_interp_transform_method": try: s = 'runtime_method->method' klassname = frame.EvaluateExpression('(char*) ' + s + '->klass->name').summary[1:-1] methodname = frame.EvaluateExpression('(char*) ' + s + '->name').summary[1:-1] var = 'transforming %s::%s || %s' % (klassname, methodname, frame) except Exception as e: print("DBG: transformfail:" + str(e)) elif pc[0] == '0': try: framestr = frame.EvaluateExpression('(char*)mono_pmip((void*)%s)' % pc).summary[1:-1] var = 'frame #%i: %s%s' % (frame.idx, pc, framestr) except: pass print(' %c %s' % ('*' if current_thread and frame.idx == selected_frame.idx else ' ', var)) def monobt(debugger, command, result, dict): opts = {'all_bt': False, 'num_frames': None} if command == 'all': opts['all_bt'] = True elif command.isdigit(): opts['num_frames'] = int(command) elif command != '': print('error: monobt [|all]') return target = debugger.GetSelectedTarget() process = target.process if not process.IsValid(): print('error: invalid process') return if opts['all_bt']: for thread in process.threads: print_frames(thread, len(thread), process.selected_thread == thread) print('') else: thread = process.selected_thread num_frames = len(thread) if opts['num_frames'] is None else opts['num_frames'] print_frames(thread, num_frames, True) return None def __lldb_init_module (debugger, dict): # This initializer is being run from LLDB in the embedded command interpreter # Add any commands contained in this module to LLDB debugger.HandleCommand('command script add -f monobt.monobt monobt') debugger.HandleCommand('command alias mbt monobt') print('"monobt" command installed')