def main(): ctx = common.parse_args() if ctx.input: threads = common.load_threads(ctx.input) if ctx.invert: common.print_inverted_callgraph(threads, ctx.threshold) else: common.print_callgraph(threads, ctx.threshold) elif ctx.pid: this_path = os.path.realpath(__file__) pargs = ' '.join(sys.argv[1:]) args = [ ctx.gdb_path, "-q", "--ex", "source %s" % this_path, "--ex", "gdbpmp %s" % pargs ] proc = subprocess.Popen(args) try: while proc.poll() is None: time.sleep(0.1) except KeyboardInterrupt: proc.send_signal(signal.SIGINT) while proc.poll() is None: time.sleep(0.1)
def invoke(self, argument, from_tty): detatch_and_kill = 0 self.dont_repeat() ctx = common.parse_args(gdb.string_to_argv(argument)) if ctx.input: threads = common.load_threads(ctx.input) common.print_callgraph(threads) return gdb.execute("set print thread-events off") gdb.execute("set print inferior-events off") gdb.execute("set pagination off") if ctx.pid and ctx.pid != gdb.selected_inferior().pid: detach_and_kill = 1 gdb.write("Attaching to process %d..." % ctx.pid) gdb.flush(gdb.STDOUT) if gdb.selected_inferior().pid != 0: gdb.execute("detach", to_string=True) os.kill(ctx.pid, signal.SIGSTOP) gdb.execute("attach %d" % ctx.pid, to_string=True) os.kill(ctx.pid, signal.SIGCONT) gdb.execute("continue", to_string=True) gdb.write("Done.\n") gdb.flush(gdb.STDOUT) def detach_attach(): pid = gdb.selected_inferior().pid os.kill(pid, signal.SIGSTOP) # Make sure the process does nothing until # it's reattached. gdb.execute("detach", to_string=True) os.kill(pid, signal.SIGCONT) sleep(ctx.sleep) os.kill(pid, signal.SIGSTOP) gdb.execute("attach %d" % pid, to_string=True) os.kill(pid, signal.SIGCONT) gdb.execute("continue", to_string=True) def breaking_continue_handler(event): sleep(ctx.sleep) os.kill(gdb.selected_inferior().pid, signal.SIGINT) samples = 0 gdb.write("Gathering Samples") gdb.flush(gdb.STDOUT) try: for i in range(0, ctx.samples): # Some processes handle signals in strange ways. For those # processes we may have to fully detach from the process, # sleep, and then reattach. This is quite slow. For other # processes we may be able to tell gdb to continue, sleep, # and then send SIGINT to let GDB stop the process. if ctx.detachattach: detach_attach() else: gdb.events.cont.connect(breaking_continue_handler) gdb.execute("continue", to_string=True) gdb.events.cont.disconnect(breaking_continue_handler) for inf in gdb.inferiors(): inum = inf.num for th in inf.threads(): thn = th.num if thn not in self.threads: f = GDBFunction(None, 2) self.threads[thn] = GDBThread( th.name, thn, th.ptid, f) if ctx.match and not any( m in th.name for m in ctx.match.split(',')): pass elif ctx.exclude and any( m in th.name for m in ctx.exclude.split(',')): pass else: th.switch() frame = gdb.newest_frame() while (frame.older() != None): frame = frame.older() self.threads[thn].function.inverse_add_frame(frame) samples += 1 gdb.write(".") gdb.flush(gdb.STDOUT) except KeyboardInterrupt: pass finally: print(("\nProfiling complete with %d samples." % samples)) if ctx.output: common.dump_threads(self.threads, ctx.output) else: common.print_callgraph(self.threads) if detach_and_kill: gdb.execute("detach", to_string=True) gdb.execute("quit") else: pid = gdb.selected_inferior().pid os.kill(pid, signal.SIGSTOP) # Make sure the process does nothing until # it's reattached. gdb.execute("detach", to_string=True) gdb.execute("attach %d" % pid, to_string=True) os.kill(pid, signal.SIGCONT) gdb.execute("continue", to_string=True)