| import gdb |
| import ompdModule |
| import itertools |
| from gdb.FrameDecorator import FrameDecorator |
| import ompd |
| from ompd_handles import ompd_task, ompd_parallel, ompd_thread |
| import traceback |
| from tempfile import NamedTemporaryFile |
| |
| |
| class OmpdFrameDecorator(FrameDecorator): |
| def __init__(self, fobj, curr_task_handle): |
| """Initializes a FrameDecorator with the given GDB Frame object. The global OMPD address space defined in |
| ompd.py is set as well. |
| """ |
| super(OmpdFrameDecorator, self).__init__(fobj) |
| self.addr_space = ompd.addr_space |
| self.fobj = None |
| if isinstance(fobj, gdb.Frame): |
| self.fobj = fobj |
| elif isinstance(fobj, FrameDecorator): |
| self.fobj = fobj.inferior_frame() |
| self.curr_task_handle = curr_task_handle |
| |
| def function(self): |
| """This appends the name of a frame that is printed with the information whether the task started in the frame |
| is implicit or explicit. The ICVs are evaluated to determine that. |
| """ |
| name = str(self.fobj.name()) |
| |
| if self.curr_task_handle is None: |
| return name |
| |
| icv_value = ompdModule.call_ompd_get_icv_from_scope( |
| self.curr_task_handle, |
| ompd.icv_map["implicit-task-var"][1], |
| ompd.icv_map["implicit-task-var"][0], |
| ) |
| if icv_value == 0: |
| name = '@thread %i: %s "#pragma omp task"' % ( |
| gdb.selected_thread().num, |
| name, |
| ) |
| elif icv_value == 1: |
| name = '@thread %i: %s "#pragma omp parallel"' % ( |
| gdb.selected_thread().num, |
| name, |
| ) |
| else: |
| name = "@thread %i: %s" % (gdb.selected_thread().num, name) |
| return name |
| |
| |
| class OmpdFrameDecoratorThread(FrameDecorator): |
| def __init__(self, fobj): |
| """Initializes a FrameDecorator with the given GDB Frame object.""" |
| super(OmpdFrameDecoratorThread, self).__init__(fobj) |
| if isinstance(fobj, gdb.Frame): |
| self.fobj = fobj |
| elif isinstance(fobj, FrameDecorator): |
| self.fobj = fobj.inferior_frame() |
| |
| def function(self): |
| name = str(self.fobj.name()) |
| return "@thread %i: %s" % (gdb.selected_thread().num, name) |
| |
| |
| class FrameFilter: |
| def __init__(self, addr_space): |
| """Initializes the FrameFilter, registers is in the GDB runtime and saves the given OMPD address space capsule.""" |
| self.addr_space = addr_space |
| self.name = "Filter" |
| self.priority = 100 |
| self.enabled = True |
| gdb.frame_filters[self.name] = self |
| self.switched_on = False |
| self.continue_to_master = False |
| |
| def set_switch(self, on_off): |
| """Prints output when executing 'ompd bt on' or 'ompd bt off'.""" |
| self.switched_on = on_off |
| if self.switched_on: |
| print('Enabled filter for "bt" output successfully.') |
| else: |
| print('Disabled filter for "bt" output successfully.') |
| |
| def set_switch_continue(self, on_off): |
| """Prints output when executing 'ompd bt on continued'." """ |
| self.continue_to_master = on_off |
| if self.continue_to_master: |
| print( |
| 'Enabled "bt" mode that continues backtrace on to master thread for worker threads.' |
| ) |
| else: |
| print('Disabled "bt" mode that continues onto master thread.') |
| |
| def get_master_frames_for_worker(self, past_thread_num, latest_sp): |
| """Prints master frames for worker thread with id past_thread_num.""" |
| gdb.execute("t 1") |
| gdb.execute("ompd bt on") |
| gdb.execute("bt") |
| |
| frame = gdb.newest_frame() |
| |
| while frame.older() is not None: |
| print("master frame sp:", str(frame.read_register("sp"))) |
| yield OmpdFrameDecorator(frame) |
| frame = frame.older() |
| print("latest sp:", str(latest_sp)) |
| |
| gdb.execute("ompd bt on continued") |
| gdb.execute("t %d" % int(past_thread_num)) |
| |
| def filter_frames(self, frame_iter): |
| """Iterates through frames and only returns those that are relevant to the application |
| being debugged. The OmpdFrameDecorator is applied automatically. |
| """ |
| curr_thread_num = gdb.selected_thread().num |
| is_no_omp_thread = False |
| if curr_thread_num in self.addr_space.threads: |
| curr_thread_obj = self.addr_space.threads[curr_thread_num] |
| self.curr_task = curr_thread_obj.get_current_task() |
| self.frames = self.curr_task.get_task_frame() |
| else: |
| is_no_omp_thread = True |
| print( |
| "Thread %d is no OpenMP thread, printing all frames:" % curr_thread_num |
| ) |
| |
| stop_iter = False |
| for x in frame_iter: |
| if is_no_omp_thread: |
| yield OmpdFrameDecoratorThread(x) |
| continue |
| |
| if x.inferior_frame().older() is None: |
| continue |
| if self.curr_task.task_handle is None: |
| continue |
| |
| gdb_sp = int(str(x.inferior_frame().read_register("sp")), 16) |
| gdb_sp_next_new = int( |
| str(x.inferior_frame()).split(",")[0].split("=")[1], 16 |
| ) |
| if x.inferior_frame().older(): |
| gdb_sp_next = int( |
| str(x.inferior_frame().older().read_register("sp")), 16 |
| ) |
| else: |
| gdb_sp_next = int(str(x.inferior_frame().read_register("sp")), 16) |
| while 1: |
| (ompd_enter_frame, ompd_exit_frame) = self.frames |
| |
| if ompd_enter_frame != 0 and gdb_sp_next_new < ompd_enter_frame: |
| break |
| if ompd_exit_frame != 0 and gdb_sp_next_new < ompd_exit_frame: |
| if ( |
| x.inferior_frame().older().older() |
| and int( |
| str(x.inferior_frame().older().older().read_register("sp")), |
| 16, |
| ) |
| < ompd_exit_frame |
| ): |
| if self.continue_to_master: |
| yield OmpdFrameDecoratorThread(x) |
| else: |
| yield OmpdFrameDecorator(x, self.curr_task.task_handle) |
| else: |
| yield OmpdFrameDecorator(x, self.curr_task.task_handle) |
| break |
| sched_task_handle = self.curr_task.get_scheduling_task_handle() |
| |
| if sched_task_handle is None: |
| stop_iter = True |
| break |
| |
| self.curr_task = self.curr_task.get_scheduling_task() |
| self.frames = self.curr_task.get_task_frame() |
| if stop_iter: |
| break |
| |
| # implementation of "ompd bt continued" |
| if self.continue_to_master: |
| |
| orig_thread = gdb.selected_thread().num |
| gdb_threads = dict([(t.num, t) for t in gdb.selected_inferior().threads()]) |
| |
| # iterate through generating tasks until outermost task is reached |
| while 1: |
| # get OMPD thread id for master thread (systag in GDB output) |
| try: |
| master_num = ( |
| self.curr_task.get_task_parallel() |
| .get_thread_in_parallel(0) |
| .get_thread_id() |
| ) |
| except: |
| break |
| # search for thread id without the "l" for long via "thread find" and get GDB thread num from output |
| hex_str = str(hex(master_num)) |
| thread_output = gdb.execute( |
| "thread find %s" % hex_str[0 : len(hex_str) - 1], to_string=True |
| ).split(" ") |
| if thread_output[0] == "No": |
| raise ValueError("Master thread num could not be found!") |
| gdb_master_num = int(thread_output[1]) |
| # get task that generated last task of worker thread |
| try: |
| self.curr_task = ( |
| self.curr_task.get_task_parallel() |
| .get_task_in_parallel(0) |
| .get_generating_task() |
| ) |
| except: |
| break |
| self.frames = self.curr_task.get_task_frame() |
| (enter_frame, exit_frame) = self.frames |
| if exit_frame == 0: |
| print("outermost generating task was reached") |
| break |
| |
| # save GDB num for worker thread to change back to it later |
| worker_thread = gdb.selected_thread().num |
| |
| # use InferiorThread.switch() |
| gdb_threads = dict( |
| [(t.num, t) for t in gdb.selected_inferior().threads()] |
| ) |
| gdb_threads[gdb_master_num].switch() |
| print("#### switching to thread %i ####" % gdb_master_num) |
| |
| frame = gdb.newest_frame() |
| stop_iter = False |
| |
| while not stop_iter: |
| if self.curr_task.task_handle is None: |
| break |
| self.frames = self.curr_task.get_task_frame() |
| |
| while frame: |
| if self.curr_task.task_handle is None: |
| break |
| |
| gdb_sp_next_new = int( |
| str(frame).split(",")[0].split("=")[1], 16 |
| ) |
| |
| if frame.older(): |
| gdb_sp_next = int( |
| str(frame.older().read_register("sp")), 16 |
| ) |
| else: |
| gdb_sp_next = int(str(frame.read_register("sp")), 16) |
| |
| while 1: |
| (ompd_enter_frame, ompd_exit_frame) = self.frames |
| |
| if ( |
| ompd_enter_frame != 0 |
| and gdb_sp_next_new < ompd_enter_frame |
| ): |
| break |
| if ( |
| ompd_exit_frame == 0 |
| or gdb_sp_next_new < ompd_exit_frame |
| ): |
| if ( |
| ompd_exit_frame == 0 |
| or frame.older() |
| and frame.older().older() |
| and int( |
| str(frame.older().older().read_register("sp")), |
| 16, |
| ) |
| < ompd_exit_frame |
| ): |
| yield OmpdFrameDecoratorThread(frame) |
| else: |
| yield OmpdFrameDecorator( |
| frame, self.curr_task.task_handle |
| ) |
| break |
| sched_task_handle = ( |
| ompdModule.call_ompd_get_scheduling_task_handle( |
| self.curr_task.task_handle |
| ) |
| ) |
| |
| if sched_task_handle is None: |
| stop_iter = True |
| break |
| self.curr_task = self.curr_task.get_generating_task() |
| self.frames = self.curr_task.get_task_frame() |
| |
| frame = frame.older() |
| break |
| |
| gdb_threads[worker_thread].switch() |
| |
| gdb_threads[orig_thread].switch() |
| |
| def filter(self, frame_iter): |
| """Function is called automatically with every 'bt' executed. If switched on, this will only let revelant frames be printed |
| or all frames otherwise. If switched on, a FrameDecorator will be applied to state whether '.ompd_task_entry.' refers to an |
| explicit or implicit task. |
| """ |
| if self.switched_on: |
| return self.filter_frames(frame_iter) |
| else: |
| return frame_iter |