xref: /llvm-project/openmp/libompd/gdb-plugin/ompd/ompd.py (revision 11a9ab125737e4b43a98073ccf238cef9c8501b9)
1import ompdModule
2import gdb
3import re
4import traceback
5from ompd_address_space import ompd_address_space
6from ompd_handles import ompd_thread, ompd_task, ompd_parallel
7from frame_filter import FrameFilter
8from enum import Enum
9
10
11addr_space = None
12ff = None
13icv_map = None
14ompd_scope_map = {
15    1: "global",
16    2: "address_space",
17    3: "thread",
18    4: "parallel",
19    5: "implicit_task",
20    6: "task",
21}
22in_task_function = False
23
24
25class ompd(gdb.Command):
26    def __init__(self):
27        super(ompd, self).__init__("ompd", gdb.COMMAND_STATUS, gdb.COMPLETE_NONE, True)
28
29
30class ompd_init(gdb.Command):
31    """Find and initialize ompd library"""
32
33    # first parameter is command-line input, second parameter is gdb-specific data
34    def __init__(self):
35        self.__doc__ = "Find and initialize OMPD library\n usage: ompd init"
36        super(ompd_init, self).__init__("ompd init", gdb.COMMAND_DATA)
37
38    def invoke(self, arg, from_tty):
39        global addr_space
40        global ff
41        try:
42            try:
43                print(gdb.newest_frame())
44            except:
45                gdb.execute("start")
46            try:
47                lib_list = gdb.parse_and_eval("(char**)ompd_dll_locations")
48            except gdb.error:
49                raise ValueError(
50                    "No ompd_dll_locations symbol in execution, make sure to have an OMPD enabled OpenMP runtime"
51                )
52
53            while not gdb.parse_and_eval("(char**)ompd_dll_locations"):
54                gdb.execute("tbreak ompd_dll_locations_valid")
55                gdb.execute("continue")
56
57            lib_list = gdb.parse_and_eval("(char**)ompd_dll_locations")
58
59            i = 0
60            while lib_list[i]:
61                ret = ompdModule.ompd_open(lib_list[i].string())
62                if ret == -1:
63                    raise ValueError("Handle of OMPD library is not a valid string!")
64                if ret == -2:
65                    print("ret == -2")
66                    pass  # It's ok to fail on dlopen
67                if ret == -3:
68                    print("ret == -3")
69                    pass  # It's ok to fail on dlsym
70                if ret < -10:
71                    raise ValueError("OMPD error code %i!" % (-10 - ret))
72
73                if ret > 0:
74                    print("Loaded OMPD lib successfully!")
75                    try:
76                        addr_space = ompd_address_space()
77                        ff = FrameFilter(addr_space)
78                    except:
79                        traceback.print_exc()
80                    return
81                i = i + 1
82
83            raise ValueError("OMPD library could not be loaded!")
84        except:
85            traceback.print_exc()
86
87
88class ompd_threads(gdb.Command):
89    """Register thread ids of current context"""
90
91    def __init__(self):
92        self.__doc__ = (
93            "Provide information on threads of current context.\n usage: ompd threads"
94        )
95        super(ompd_threads, self).__init__("ompd threads", gdb.COMMAND_STATUS)
96
97    def invoke(self, arg, from_tty):
98        global addr_space
99        if init_error():
100            return
101        addr_space.list_threads(True)
102
103
104def print_parallel_region(curr_parallel, team_size):
105    """Helper function for ompd_parallel_region. To print out the details of the parallel region."""
106    for omp_thr in range(team_size):
107        thread = curr_parallel.get_thread_in_parallel(omp_thr)
108        ompd_state = str(addr_space.states[thread.get_state()[0]])
109        ompd_wait_id = thread.get_state()[1]
110        task = curr_parallel.get_task_in_parallel(omp_thr)
111        task_func_addr = task.get_task_function()
112        # Get the function this addr belongs to
113        sal = gdb.find_pc_line(task_func_addr)
114        block = gdb.block_for_pc(task_func_addr)
115        while block and not block.function:
116            block = block.superblock
117        if omp_thr == 0:
118            print(
119                "%6d (master) %-37s %ld    0x%lx %-25s %-17s:%d"
120                % (
121                    omp_thr,
122                    ompd_state,
123                    ompd_wait_id,
124                    task_func_addr,
125                    block.function.print_name,
126                    sal.symtab.filename,
127                    sal.line,
128                )
129            )
130        else:
131            print(
132                "%6d          %-37s %ld    0x%lx %-25s %-17s:%d"
133                % (
134                    omp_thr,
135                    ompd_state,
136                    ompd_wait_id,
137                    task_func_addr,
138                    block.function.print_name,
139                    sal.symtab.filename,
140                    sal.line,
141                )
142            )
143
144
145class ompd_parallel_region(gdb.Command):
146    """Parallel Region Details"""
147
148    def __init__(self):
149        self.__doc__ = "Display the details of the current and enclosing parallel regions.\n usage: ompd parallel"
150        super(ompd_parallel_region, self).__init__("ompd parallel", gdb.COMMAND_STATUS)
151
152    def invoke(self, arg, from_tty):
153        global addr_space
154        if init_error():
155            return
156        if addr_space.icv_map is None:
157            addr_space.get_icv_map()
158        if addr_space.states is None:
159            addr_space.enumerate_states()
160        curr_thread_handle = addr_space.get_curr_thread()
161        curr_parallel_handle = curr_thread_handle.get_current_parallel_handle()
162        curr_parallel = ompd_parallel(curr_parallel_handle)
163        while curr_parallel_handle is not None and curr_parallel is not None:
164            nest_level = ompdModule.call_ompd_get_icv_from_scope(
165                curr_parallel_handle,
166                addr_space.icv_map["levels-var"][1],
167                addr_space.icv_map["levels-var"][0],
168            )
169            if nest_level == 0:
170                break
171            team_size = ompdModule.call_ompd_get_icv_from_scope(
172                curr_parallel_handle,
173                addr_space.icv_map["team-size-var"][1],
174                addr_space.icv_map["team-size-var"][0],
175            )
176            print("")
177            print(
178                "Parallel Region: Nesting Level %d: Team Size: %d"
179                % (nest_level, team_size)
180            )
181            print("================================================")
182            print("")
183            print(
184                "OMP Thread Nbr  Thread State                     Wait Id  EntryAddr FuncName                 File:Line"
185            )
186            print(
187                "======================================================================================================"
188            )
189            print_parallel_region(curr_parallel, team_size)
190            enclosing_parallel = curr_parallel.get_enclosing_parallel()
191            enclosing_parallel_handle = curr_parallel.get_enclosing_parallel_handle()
192            curr_parallel = enclosing_parallel
193            curr_parallel_handle = enclosing_parallel_handle
194
195
196class ompd_icvs(gdb.Command):
197    """ICVs"""
198
199    def __init__(self):
200        self.__doc__ = (
201            "Display the values of the Internal Control Variables.\n usage: ompd icvs"
202        )
203        super(ompd_icvs, self).__init__("ompd icvs", gdb.COMMAND_STATUS)
204
205    def invoke(self, arg, from_tty):
206        global addr_space
207        global ompd_scope_map
208        if init_error():
209            return
210        curr_thread_handle = addr_space.get_curr_thread()
211        if addr_space.icv_map is None:
212            addr_space.get_icv_map()
213        print("ICV Name                        Scope                     Value")
214        print("===============================================================")
215
216        try:
217            for icv_name in addr_space.icv_map:
218                scope = addr_space.icv_map[icv_name][1]
219                # {1:'global', 2:'address_space', 3:'thread', 4:'parallel', 5:'implicit_task', 6:'task'}
220                if scope == 2:
221                    handle = addr_space.addr_space
222                elif scope == 3:
223                    handle = curr_thread_handle.thread_handle
224                elif scope == 4:
225                    handle = curr_thread_handle.get_current_parallel_handle()
226                elif scope == 6:
227                    handle = curr_thread_handle.get_current_task_handle()
228                else:
229                    raise ValueError("Invalid scope")
230
231                if icv_name == "nthreads-var" or icv_name == "bind-var":
232                    icv_value = ompdModule.call_ompd_get_icv_from_scope(
233                        handle, scope, addr_space.icv_map[icv_name][0]
234                    )
235                    if icv_value is None:
236                        icv_string = ompdModule.call_ompd_get_icv_string_from_scope(
237                            handle, scope, addr_space.icv_map[icv_name][0]
238                        )
239                        print(
240                            "%-31s %-26s %s"
241                            % (icv_name, ompd_scope_map[scope], icv_string)
242                        )
243                    else:
244                        print(
245                            "%-31s %-26s %d"
246                            % (icv_name, ompd_scope_map[scope], icv_value)
247                        )
248
249                elif (
250                    icv_name == "affinity-format-var"
251                    or icv_name == "run-sched-var"
252                    or icv_name == "tool-libraries-var"
253                    or icv_name == "tool-verbose-init-var"
254                ):
255                    icv_string = ompdModule.call_ompd_get_icv_string_from_scope(
256                        handle, scope, addr_space.icv_map[icv_name][0]
257                    )
258                    print(
259                        "%-31s %-26s %s" % (icv_name, ompd_scope_map[scope], icv_string)
260                    )
261                else:
262                    icv_value = ompdModule.call_ompd_get_icv_from_scope(
263                        handle, scope, addr_space.icv_map[icv_name][0]
264                    )
265                    print(
266                        "%-31s %-26s %d" % (icv_name, ompd_scope_map[scope], icv_value)
267                    )
268        except:
269            traceback.print_exc()
270
271
272def curr_thread():
273    """Helper function for ompd_step. Returns the thread object for the current thread number."""
274    global addr_space
275    if addr_space is not None:
276        return addr_space.threads[int(gdb.selected_thread().num)]
277    return None
278
279
280class ompd_test(gdb.Command):
281    """Test area"""
282
283    def __init__(self):
284        self.__doc__ = "Test functionalities for correctness\n usage: ompd test"
285        super(ompd_test, self).__init__("ompd test", gdb.COMMAND_OBSCURE)
286
287    def invoke(self, arg, from_tty):
288        global addr_space
289        if init_error():
290            return
291        # get task function for current task of current thread
292        try:
293            current_thread = int(gdb.selected_thread().num)
294            current_thread_obj = addr_space.threads[current_thread]
295            task_function = current_thread_obj.get_current_task().get_task_function()
296            print("bt value:", int("0x0000000000400b6c", 0))
297            print("get_task_function value:", task_function)
298
299            # get task function of implicit task in current parallel region for current thread
300            current_parallel_obj = current_thread_obj.get_current_parallel()
301            task_in_parallel = current_parallel_obj.get_task_in_parallel(current_thread)
302            task_function_in_parallel = task_in_parallel.get_task_function()
303            print("task_function_in_parallel:", task_function_in_parallel)
304        except:
305            print("Task function value not found for this thread")
306
307
308class ompdtestapi(gdb.Command):
309    """To test API's return code"""
310
311    def __init__(self):
312        self.__doc__ = "Test OMPD tool Interface APIs.\nUsage: ompdtestapi <api name>"
313        super(ompdtestapi, self).__init__("ompdtestapi", gdb.COMMAND_OBSCURE)
314
315    def invoke(self, arg, from_tty):
316        global addr_space
317        if init_error():
318            print("Error in Initialization.")
319            return
320        if not arg:
321            print("No API provided to test, eg: ompdtestapi ompd_initialize")
322
323        if arg == "ompd_get_thread_handle":
324            addr_handle = addr_space.addr_space
325            threadId = gdb.selected_thread().ptid[1]
326            ompdModule.test_ompd_get_thread_handle(addr_handle, threadId)
327        elif arg == "ompd_get_curr_parallel_handle":
328            addr_handle = addr_space.addr_space
329            threadId = gdb.selected_thread().ptid[1]
330            thread_handle = ompdModule.get_thread_handle(threadId, addr_handle)
331            ompdModule.test_ompd_get_curr_parallel_handle(thread_handle)
332        elif arg == "ompd_get_thread_in_parallel":
333            addr_handle = addr_space.addr_space
334            threadId = gdb.selected_thread().ptid[1]
335            thread_handle = ompdModule.get_thread_handle(threadId, addr_handle)
336            parallel_handle = ompdModule.call_ompd_get_curr_parallel_handle(
337                thread_handle
338            )
339            ompdModule.test_ompd_get_thread_in_parallel(parallel_handle)
340        elif arg == "ompd_thread_handle_compare":
341            addr_handle = addr_space.addr_space
342            threadId = gdb.selected_thread().ptid[1]
343            thread_handle = ompdModule.get_thread_handle(threadId, addr_handle)
344            parallel_handle = ompdModule.call_ompd_get_curr_parallel_handle(
345                thread_handle
346            )
347            thread_handle1 = ompdModule.call_ompd_get_thread_in_parallel(
348                parallel_handle, 1
349            )
350            thread_handle2 = ompdModule.call_ompd_get_thread_in_parallel(
351                parallel_handle, 2
352            )
353            ompdModule.test_ompd_thread_handle_compare(thread_handle1, thread_handle1)
354            ompdModule.test_ompd_thread_handle_compare(thread_handle1, thread_handle2)
355        elif arg == "ompd_get_thread_id":
356            addr_handle = addr_space.addr_space
357            threadId = gdb.selected_thread().ptid[1]
358            thread_handle = ompdModule.get_thread_handle(threadId, addr_handle)
359            ompdModule.test_ompd_get_thread_id(thread_handle)
360        elif arg == "ompd_rel_thread_handle":
361            addr_handle = addr_space.addr_space
362            threadId = gdb.selected_thread().ptid[1]
363            thread_handle = ompdModule.get_thread_handle(threadId, addr_handle)
364            ompdModule.test_ompd_rel_thread_handle(thread_handle)
365        elif arg == "ompd_get_enclosing_parallel_handle":
366            addr_handle = addr_space.addr_space
367            threadId = gdb.selected_thread().ptid[1]
368            thread_handle = ompdModule.get_thread_handle(threadId, addr_handle)
369            parallel_handle = ompdModule.call_ompd_get_curr_parallel_handle(
370                thread_handle
371            )
372            ompdModule.test_ompd_get_enclosing_parallel_handle(parallel_handle)
373        elif arg == "ompd_parallel_handle_compare":
374            addr_handle = addr_space.addr_space
375            threadId = gdb.selected_thread().ptid[1]
376            thread_handle = ompdModule.get_thread_handle(threadId, addr_handle)
377            parallel_handle1 = ompdModule.call_ompd_get_curr_parallel_handle(
378                thread_handle
379            )
380            parallel_handle2 = ompdModule.call_ompd_get_enclosing_parallel_handle(
381                parallel_handle1
382            )
383            ompdModule.test_ompd_parallel_handle_compare(
384                parallel_handle1, parallel_handle1
385            )
386            ompdModule.test_ompd_parallel_handle_compare(
387                parallel_handle1, parallel_handle2
388            )
389        elif arg == "ompd_rel_parallel_handle":
390            addr_handle = addr_space.addr_space
391            threadId = gdb.selected_thread().ptid[1]
392            thread_handle = ompdModule.get_thread_handle(threadId, addr_handle)
393            parallel_handle = ompdModule.call_ompd_get_curr_parallel_handle(
394                thread_handle
395            )
396            ompdModule.test_ompd_rel_parallel_handle(parallel_handle)
397        elif arg == "ompd_initialize":
398            ompdModule.test_ompd_initialize()
399        elif arg == "ompd_get_api_version":
400            ompdModule.test_ompd_get_api_version()
401        elif arg == "ompd_get_version_string":
402            ompdModule.test_ompd_get_version_string()
403        elif arg == "ompd_finalize":
404            ompdModule.test_ompd_finalize()
405        elif arg == "ompd_process_initialize":
406            ompdModule.call_ompd_initialize()
407            ompdModule.test_ompd_process_initialize()
408        elif arg == "ompd_device_initialize":
409            ompdModule.test_ompd_device_initialize()
410        elif arg == "ompd_rel_address_space_handle":
411            ompdModule.test_ompd_rel_address_space_handle()
412        elif arg == "ompd_get_omp_version":
413            addr_handle = addr_space.addr_space
414            ompdModule.test_ompd_get_omp_version(addr_handle)
415        elif arg == "ompd_get_omp_version_string":
416            addr_handle = addr_space.addr_space
417            ompdModule.test_ompd_get_omp_version_string(addr_handle)
418        elif arg == "ompd_get_curr_task_handle":
419            addr_handle = addr_space.addr_space
420            threadId = gdb.selected_thread().ptid[1]
421            thread_handle = ompdModule.get_thread_handle(threadId, addr_handle)
422            ompdModule.test_ompd_get_curr_task_handle(thread_handle)
423        elif arg == "ompd_get_task_parallel_handle":
424            addr_handle = addr_space.addr_space
425            threadId = gdb.selected_thread().ptid[1]
426            thread_handle = ompdModule.get_thread_handle(threadId, addr_handle)
427            task_handle = ompdModule.call_ompd_get_curr_task_handle(thread_handle)
428            ompdModule.test_ompd_get_task_parallel_handle(task_handle)
429        elif arg == "ompd_get_generating_task_handle":
430            addr_handle = addr_space.addr_space
431            threadId = gdb.selected_thread().ptid[1]
432            thread_handle = ompdModule.get_thread_handle(threadId, addr_handle)
433            task_handle = ompdModule.call_ompd_get_curr_task_handle(thread_handle)
434            ompdModule.test_ompd_get_generating_task_handle(task_handle)
435        elif arg == "ompd_get_scheduling_task_handle":
436            addr_handle = addr_space.addr_space
437            threadId = gdb.selected_thread().ptid[1]
438            thread_handle = ompdModule.get_thread_handle(threadId, addr_handle)
439            task_handle = ompdModule.call_ompd_get_curr_task_handle(thread_handle)
440            ompdModule.test_ompd_get_scheduling_task_handle(task_handle)
441        elif arg == "ompd_get_task_in_parallel":
442            addr_handle = addr_space.addr_space
443            threadId = gdb.selected_thread().ptid[1]
444            thread_handle = ompdModule.get_thread_handle(threadId, addr_handle)
445            parallel_handle = ompdModule.call_ompd_get_curr_parallel_handle(
446                thread_handle
447            )
448            ompdModule.test_ompd_get_task_in_parallel(parallel_handle)
449        elif arg == "ompd_rel_task_handle":
450            addr_handle = addr_space.addr_space
451            threadId = gdb.selected_thread().ptid[1]
452            thread_handle = ompdModule.get_thread_handle(threadId, addr_handle)
453            task_handle = ompdModule.call_ompd_get_curr_task_handle(thread_handle)
454            ompdModule.test_ompd_rel_task_handle(task_handle)
455        elif arg == "ompd_task_handle_compare":
456            addr_handle = addr_space.addr_space
457            threadId = gdb.selected_thread().ptid[1]
458            thread_handle = ompdModule.get_thread_handle(threadId, addr_handle)
459            task_handle1 = ompdModule.call_ompd_get_curr_task_handle(thread_handle)
460            task_handle2 = ompdModule.call_ompd_get_generating_task_handle(task_handle1)
461            ompdModule.test_ompd_task_handle_compare(task_handle1, task_handle2)
462            ompdModule.test_ompd_task_handle_compare(task_handle2, task_handle1)
463        elif arg == "ompd_get_task_function":
464            addr_handle = addr_space.addr_space
465            threadId = gdb.selected_thread().ptid[1]
466            thread_handle = ompdModule.get_thread_handle(threadId, addr_handle)
467            task_handle = ompdModule.call_ompd_get_curr_task_handle(thread_handle)
468            ompdModule.test_ompd_get_task_function(task_handle)
469        elif arg == "ompd_get_task_frame":
470            addr_handle = addr_space.addr_space
471            threadId = gdb.selected_thread().ptid[1]
472            thread_handle = ompdModule.get_thread_handle(threadId, addr_handle)
473            task_handle = ompdModule.call_ompd_get_curr_task_handle(thread_handle)
474            ompdModule.test_ompd_get_task_frame(task_handle)
475        elif arg == "ompd_get_state":
476            addr_handle = addr_space.addr_space
477            threadId = gdb.selected_thread().ptid[1]
478            thread_handle = ompdModule.get_thread_handle(threadId, addr_handle)
479            ompdModule.test_ompd_get_state(thread_handle)
480        elif arg == "ompd_get_display_control_vars":
481            addr_handle = addr_space.addr_space
482            ompdModule.test_ompd_get_display_control_vars(addr_handle)
483        elif arg == "ompd_rel_display_control_vars":
484            ompdModule.test_ompd_rel_display_control_vars()
485        elif arg == "ompd_enumerate_icvs":
486            addr_handle = addr_space.addr_space
487            ompdModule.test_ompd_enumerate_icvs(addr_handle)
488        elif arg == "ompd_get_icv_from_scope":
489            addr_handle = addr_space.addr_space
490            threadId = gdb.selected_thread().ptid[1]
491            thread_handle = ompdModule.get_thread_handle(threadId, addr_handle)
492            parallel_handle = ompdModule.call_ompd_get_curr_parallel_handle(
493                thread_handle
494            )
495            task_handle = ompdModule.call_ompd_get_curr_task_handle(thread_handle)
496            ompdModule.test_ompd_get_icv_from_scope_with_addr_handle(addr_handle)
497            ompdModule.test_ompd_get_icv_from_scope_with_thread_handle(thread_handle)
498            ompdModule.test_ompd_get_icv_from_scope_with_parallel_handle(
499                parallel_handle
500            )
501            ompdModule.test_ompd_get_icv_from_scope_with_task_handle(task_handle)
502        elif arg == "ompd_get_icv_string_from_scope":
503            addr_handle = addr_space.addr_space
504            ompdModule.test_ompd_get_icv_string_from_scope(addr_handle)
505        elif arg == "ompd_get_tool_data":
506            ompdModule.test_ompd_get_tool_data()
507        elif arg == "ompd_enumerate_states":
508            ompdModule.test_ompd_enumerate_states()
509        else:
510            print("Invalid API.")
511
512
513class ompd_bt(gdb.Command):
514    """Turn filter for 'bt' on/off for output to only contain frames relevant to the application or all frames."""
515
516    def __init__(self):
517        self.__doc__ = 'Turn filter for "bt" output on or off. Specify "on continued" option to trace worker threads back to master threads.\n usage: ompd bt on|on continued|off'
518        super(ompd_bt, self).__init__("ompd bt", gdb.COMMAND_STACK)
519
520    def invoke(self, arg, from_tty):
521        global ff
522        global addr_space
523        global icv_map
524        global ompd_scope_map
525        if init_error():
526            return
527        if icv_map is None:
528            icv_map = {}
529            current = 0
530            more = 1
531            while more > 0:
532                tup = ompdModule.call_ompd_enumerate_icvs(
533                    addr_space.addr_space, current
534                )
535                (current, next_icv, next_scope, more) = tup
536                icv_map[next_icv] = (current, next_scope, ompd_scope_map[next_scope])
537            print('Initialized ICV map successfully for filtering "bt".')
538
539        arg_list = gdb.string_to_argv(arg)
540        if len(arg_list) == 0:
541            print(
542                'When calling "ompd bt", you must either specify "on", "on continued" or "off". Check "help ompd".'
543            )
544        elif len(arg_list) == 1 and arg_list[0] == "on":
545            addr_space.list_threads(False)
546            ff.set_switch(True)
547            ff.set_switch_continue(False)
548        elif arg_list[0] == "on" and arg_list[1] == "continued":
549            ff.set_switch(True)
550            ff.set_switch_continue(True)
551        elif len(arg_list) == 1 and arg_list[0] == "off":
552            ff.set_switch(False)
553            ff.set_switch_continue(False)
554        else:
555            print(
556                'When calling "ompd bt", you must either specify "on", "on continued" or "off". Check "help ompd".'
557            )
558
559
560# TODO: remove
561class ompd_taskframes(gdb.Command):
562    """Prints task handles for relevant task frames. Meant for debugging."""
563
564    def __init__(self):
565        self.__doc__ = "Prints list of tasks.\nUsage: ompd taskframes"
566        super(ompd_taskframes, self).__init__("ompd taskframes", gdb.COMMAND_STACK)
567
568    def invoke(self, arg, from_tty):
569        global addr_space
570        if init_error():
571            return
572        frame = gdb.newest_frame()
573        while frame:
574            print(frame.read_register("sp"))
575            frame = frame.older()
576        curr_task_handle = None
577        if addr_space.threads and addr_space.threads.get(gdb.selected_thread().num):
578            curr_thread_handle = curr_thread().thread_handle
579            curr_task_handle = ompdModule.call_ompd_get_curr_task_handle(
580                curr_thread_handle
581            )
582        if not curr_task_handle:
583            return None
584        prev_frames = None
585        try:
586            while 1:
587                frames_with_flags = ompdModule.call_ompd_get_task_frame(
588                    curr_task_handle
589                )
590                frames = (frames_with_flags[0], frames_with_flags[3])
591                if prev_frames == frames:
592                    break
593                if not isinstance(frames, tuple):
594                    break
595                (ompd_enter_frame, ompd_exit_frame) = frames
596                print(hex(ompd_enter_frame), hex(ompd_exit_frame))
597                curr_task_handle = ompdModule.call_ompd_get_scheduling_task_handle(
598                    curr_task_handle
599                )
600                prev_frames = frames
601                if not curr_task_handle:
602                    break
603        except:
604            traceback.print_exc()
605
606
607def print_and_exec(string):
608    """Helper function for ompd_step. Executes the given command in GDB and prints it."""
609    print(string)
610    gdb.execute(string)
611
612
613class TempFrameFunctionBp(gdb.Breakpoint):
614    """Helper class for ompd_step. Defines stop function for breakpoint on frame function."""
615
616    def stop(self):
617        global in_task_function
618        in_task_function = True
619        self.enabled = False
620
621
622class ompd_step(gdb.Command):
623    """Executes 'step' and skips frames irrelevant to the application / the ones without debug information."""
624
625    def __init__(self):
626        self.__doc__ = 'Executes "step" and skips runtime frames as much as possible.'
627        super(ompd_step, self).__init__("ompd step", gdb.COMMAND_STACK)
628
629    class TaskBeginBp(gdb.Breakpoint):
630        """Helper class. Defines stop function for breakpoint ompd_bp_task_begin."""
631
632        def stop(self):
633            try:
634                code_line = curr_thread().get_current_task().get_task_function()
635                frame_fct_bp = TempFrameFunctionBp(
636                    ("*%i" % code_line), temporary=True, internal=True
637                )
638                frame_fct_bp.thread = self.thread
639                return False
640            except:
641                return False
642
643    def invoke(self, arg, from_tty):
644        global in_task_function
645        if init_error():
646            return
647        tbp = self.TaskBeginBp("ompd_bp_task_begin", temporary=True, internal=True)
648        tbp.thread = int(gdb.selected_thread().num)
649        print_and_exec("step")
650        while gdb.selected_frame().find_sal().symtab is None:
651            if not in_task_function:
652                print_and_exec("finish")
653            else:
654                print_and_exec("si")
655
656
657def init_error():
658    global addr_space
659    if (gdb.selected_thread() is None) or (addr_space is None) or (not addr_space):
660        print("Run 'ompd init' before running any of the ompd commands")
661        return True
662    return False
663
664
665def main():
666    ompd()
667    ompd_init()
668    ompd_threads()
669    ompd_icvs()
670    ompd_parallel_region()
671    ompd_test()
672    ompdtestapi()
673    ompd_taskframes()
674    ompd_bt()
675    ompd_step()
676
677
678if __name__ == "__main__":
679    try:
680        main()
681    except:
682        traceback.print_exc()
683
684# NOTE: test code using:
685# OMP_NUM_THREADS=... gdb a.out -x ../../projects/gdb_plugin/gdb-ompd/__init__.py
686# ompd init
687# ompd threads
688