1import gdb 2import ompdModule 3import itertools 4from gdb.FrameDecorator import FrameDecorator 5import ompd 6from ompd_handles import ompd_task, ompd_parallel, ompd_thread 7import traceback 8from tempfile import NamedTemporaryFile 9 10 11class OmpdFrameDecorator(FrameDecorator): 12 def __init__(self, fobj, curr_task_handle): 13 """Initializes a FrameDecorator with the given GDB Frame object. The global OMPD address space defined in 14 ompd.py is set as well. 15 """ 16 super(OmpdFrameDecorator, self).__init__(fobj) 17 self.addr_space = ompd.addr_space 18 self.fobj = None 19 if isinstance(fobj, gdb.Frame): 20 self.fobj = fobj 21 elif isinstance(fobj, FrameDecorator): 22 self.fobj = fobj.inferior_frame() 23 self.curr_task_handle = curr_task_handle 24 25 def function(self): 26 """This appends the name of a frame that is printed with the information whether the task started in the frame 27 is implicit or explicit. The ICVs are evaluated to determine that. 28 """ 29 name = str(self.fobj.name()) 30 31 if self.curr_task_handle is None: 32 return name 33 34 icv_value = ompdModule.call_ompd_get_icv_from_scope( 35 self.curr_task_handle, 36 ompd.icv_map["implicit-task-var"][1], 37 ompd.icv_map["implicit-task-var"][0], 38 ) 39 if icv_value == 0: 40 name = '@thread %i: %s "#pragma omp task"' % ( 41 gdb.selected_thread().num, 42 name, 43 ) 44 elif icv_value == 1: 45 name = '@thread %i: %s "#pragma omp parallel"' % ( 46 gdb.selected_thread().num, 47 name, 48 ) 49 else: 50 name = "@thread %i: %s" % (gdb.selected_thread().num, name) 51 return name 52 53 54class OmpdFrameDecoratorThread(FrameDecorator): 55 def __init__(self, fobj): 56 """Initializes a FrameDecorator with the given GDB Frame object.""" 57 super(OmpdFrameDecoratorThread, self).__init__(fobj) 58 if isinstance(fobj, gdb.Frame): 59 self.fobj = fobj 60 elif isinstance(fobj, FrameDecorator): 61 self.fobj = fobj.inferior_frame() 62 63 def function(self): 64 name = str(self.fobj.name()) 65 return "@thread %i: %s" % (gdb.selected_thread().num, name) 66 67 68class FrameFilter: 69 def __init__(self, addr_space): 70 """Initializes the FrameFilter, registers is in the GDB runtime and saves the given OMPD address space capsule.""" 71 self.addr_space = addr_space 72 self.name = "Filter" 73 self.priority = 100 74 self.enabled = True 75 gdb.frame_filters[self.name] = self 76 self.switched_on = False 77 self.continue_to_master = False 78 79 def set_switch(self, on_off): 80 """Prints output when executing 'ompd bt on' or 'ompd bt off'.""" 81 self.switched_on = on_off 82 if self.switched_on: 83 print('Enabled filter for "bt" output successfully.') 84 else: 85 print('Disabled filter for "bt" output successfully.') 86 87 def set_switch_continue(self, on_off): 88 """Prints output when executing 'ompd bt on continued'." """ 89 self.continue_to_master = on_off 90 if self.continue_to_master: 91 print( 92 'Enabled "bt" mode that continues backtrace on to master thread for worker threads.' 93 ) 94 else: 95 print('Disabled "bt" mode that continues onto master thread.') 96 97 def get_master_frames_for_worker(self, past_thread_num, latest_sp): 98 """Prints master frames for worker thread with id past_thread_num.""" 99 gdb.execute("t 1") 100 gdb.execute("ompd bt on") 101 gdb.execute("bt") 102 103 frame = gdb.newest_frame() 104 105 while frame.older() is not None: 106 print("master frame sp:", str(frame.read_register("sp"))) 107 yield OmpdFrameDecorator(frame) 108 frame = frame.older() 109 print("latest sp:", str(latest_sp)) 110 111 gdb.execute("ompd bt on continued") 112 gdb.execute("t %d" % int(past_thread_num)) 113 114 def filter_frames(self, frame_iter): 115 """Iterates through frames and only returns those that are relevant to the application 116 being debugged. The OmpdFrameDecorator is applied automatically. 117 """ 118 curr_thread_num = gdb.selected_thread().num 119 is_no_omp_thread = False 120 if curr_thread_num in self.addr_space.threads: 121 curr_thread_obj = self.addr_space.threads[curr_thread_num] 122 self.curr_task = curr_thread_obj.get_current_task() 123 self.frames = self.curr_task.get_task_frame() 124 else: 125 is_no_omp_thread = True 126 print( 127 "Thread %d is no OpenMP thread, printing all frames:" % curr_thread_num 128 ) 129 130 stop_iter = False 131 for x in frame_iter: 132 if is_no_omp_thread: 133 yield OmpdFrameDecoratorThread(x) 134 continue 135 136 if x.inferior_frame().older() is None: 137 continue 138 if self.curr_task.task_handle is None: 139 continue 140 141 gdb_sp = int(str(x.inferior_frame().read_register("sp")), 16) 142 gdb_sp_next_new = int( 143 str(x.inferior_frame()).split(",")[0].split("=")[1], 16 144 ) 145 if x.inferior_frame().older(): 146 gdb_sp_next = int( 147 str(x.inferior_frame().older().read_register("sp")), 16 148 ) 149 else: 150 gdb_sp_next = int(str(x.inferior_frame().read_register("sp")), 16) 151 while 1: 152 (ompd_enter_frame, ompd_exit_frame) = self.frames 153 154 if ompd_enter_frame != 0 and gdb_sp_next_new < ompd_enter_frame: 155 break 156 if ompd_exit_frame != 0 and gdb_sp_next_new < ompd_exit_frame: 157 if ( 158 x.inferior_frame().older().older() 159 and int( 160 str(x.inferior_frame().older().older().read_register("sp")), 161 16, 162 ) 163 < ompd_exit_frame 164 ): 165 if self.continue_to_master: 166 yield OmpdFrameDecoratorThread(x) 167 else: 168 yield OmpdFrameDecorator(x, self.curr_task.task_handle) 169 else: 170 yield OmpdFrameDecorator(x, self.curr_task.task_handle) 171 break 172 sched_task_handle = self.curr_task.get_scheduling_task_handle() 173 174 if sched_task_handle is None: 175 stop_iter = True 176 break 177 178 self.curr_task = self.curr_task.get_scheduling_task() 179 self.frames = self.curr_task.get_task_frame() 180 if stop_iter: 181 break 182 183 # implementation of "ompd bt continued" 184 if self.continue_to_master: 185 186 orig_thread = gdb.selected_thread().num 187 gdb_threads = dict([(t.num, t) for t in gdb.selected_inferior().threads()]) 188 189 # iterate through generating tasks until outermost task is reached 190 while 1: 191 # get OMPD thread id for master thread (systag in GDB output) 192 try: 193 master_num = ( 194 self.curr_task.get_task_parallel() 195 .get_thread_in_parallel(0) 196 .get_thread_id() 197 ) 198 except: 199 break 200 # search for thread id without the "l" for long via "thread find" and get GDB thread num from output 201 hex_str = str(hex(master_num)) 202 thread_output = gdb.execute( 203 "thread find %s" % hex_str[0 : len(hex_str) - 1], to_string=True 204 ).split(" ") 205 if thread_output[0] == "No": 206 raise ValueError("Master thread num could not be found!") 207 gdb_master_num = int(thread_output[1]) 208 # get task that generated last task of worker thread 209 try: 210 self.curr_task = ( 211 self.curr_task.get_task_parallel() 212 .get_task_in_parallel(0) 213 .get_generating_task() 214 ) 215 except: 216 break 217 self.frames = self.curr_task.get_task_frame() 218 (enter_frame, exit_frame) = self.frames 219 if exit_frame == 0: 220 print("outermost generating task was reached") 221 break 222 223 # save GDB num for worker thread to change back to it later 224 worker_thread = gdb.selected_thread().num 225 226 # use InferiorThread.switch() 227 gdb_threads = dict( 228 [(t.num, t) for t in gdb.selected_inferior().threads()] 229 ) 230 gdb_threads[gdb_master_num].switch() 231 print("#### switching to thread %i ####" % gdb_master_num) 232 233 frame = gdb.newest_frame() 234 stop_iter = False 235 236 while not stop_iter: 237 if self.curr_task.task_handle is None: 238 break 239 self.frames = self.curr_task.get_task_frame() 240 241 while frame: 242 if self.curr_task.task_handle is None: 243 break 244 245 gdb_sp_next_new = int( 246 str(frame).split(",")[0].split("=")[1], 16 247 ) 248 249 if frame.older(): 250 gdb_sp_next = int( 251 str(frame.older().read_register("sp")), 16 252 ) 253 else: 254 gdb_sp_next = int(str(frame.read_register("sp")), 16) 255 256 while 1: 257 (ompd_enter_frame, ompd_exit_frame) = self.frames 258 259 if ( 260 ompd_enter_frame != 0 261 and gdb_sp_next_new < ompd_enter_frame 262 ): 263 break 264 if ( 265 ompd_exit_frame == 0 266 or gdb_sp_next_new < ompd_exit_frame 267 ): 268 if ( 269 ompd_exit_frame == 0 270 or frame.older() 271 and frame.older().older() 272 and int( 273 str(frame.older().older().read_register("sp")), 274 16, 275 ) 276 < ompd_exit_frame 277 ): 278 yield OmpdFrameDecoratorThread(frame) 279 else: 280 yield OmpdFrameDecorator( 281 frame, self.curr_task.task_handle 282 ) 283 break 284 sched_task_handle = ( 285 ompdModule.call_ompd_get_scheduling_task_handle( 286 self.curr_task.task_handle 287 ) 288 ) 289 290 if sched_task_handle is None: 291 stop_iter = True 292 break 293 self.curr_task = self.curr_task.get_generating_task() 294 self.frames = self.curr_task.get_task_frame() 295 296 frame = frame.older() 297 break 298 299 gdb_threads[worker_thread].switch() 300 301 gdb_threads[orig_thread].switch() 302 303 def filter(self, frame_iter): 304 """Function is called automatically with every 'bt' executed. If switched on, this will only let revelant frames be printed 305 or all frames otherwise. If switched on, a FrameDecorator will be applied to state whether '.ompd_task_entry.' refers to an 306 explicit or implicit task. 307 """ 308 if self.switched_on: 309 return self.filter_frames(frame_iter) 310 else: 311 return frame_iter 312