Ahem... I forgot to note that: I have bootstrapped and regression tested my patch on x86_64-pc-linux-gnu.
Kevin On Thu, 4 May 2017 17:45:51 -0700 Kevin Buettner <kev...@redhat.com> wrote: > Consider the following OpenMP program: > > void foo (int a1) {} > > int > main (void) > { > static int s1 = -41; > int i1 = 11, i2; > > for (i2 = 1; i2 <= 2; i2++) > { > int pass = i2; > #pragma omp parallel num_threads (2) firstprivate (i1) > { > foo (i1); > } > foo(pass); > } > foo (s1); foo (i2); > } > > At the moment, when debugging such a program, GDB is not able to find > and print the values of s1, i2, and pass. > > My changes to omp-low.c and omp-expand.c, in conjunction with several > other patches, allow GDB to find and print these values. > > This is the current behavior when debugging in GDB: > > (gdb) b 14 > Breakpoint 1 at 0x400617: file ex3.c, line 14. > (gdb) run > Starting program: /mesquite2/.ironwood2/omp-tests/k/ex3-trunk > [Thread debugging using libthread_db enabled] > Using host libthread_db library "/lib64/libthread_db.so.1". > [New Thread 0x7ffff73ca700 (LWP 32628)] > > Thread 1 "ex3-trunk" hit Breakpoint 1, main._omp_fn.0 () at ex3.c:14 > 14 foo (i1); > (gdb) p s1 > No symbol "s1" in current context. > (gdb) p i1 > $1 = 11 > (gdb) p i2 > No symbol "i2" in current context. > (gdb) p pass > No symbol "pass" in current context. > (gdb) c > Continuing. > [Switching to Thread 0x7ffff73ca700 (LWP 32628)] > > Thread 2 "ex3-trunk" hit Breakpoint 1, main._omp_fn.0 () at ex3.c:14 > 14 foo (i1); > (gdb) p s1 > No symbol "s1" in current context. > (gdb) p i1 > $2 = 11 > (gdb) p i2 > No symbol "i2" in current context. > (gdb) p pass > No symbol "pass" in current context. > (gdb) bt > #0 main._omp_fn.0 () at ex3.c:14 > #1 0x00007ffff7bc4926 in gomp_thread_start (xdata=<optimized out>) > at gcc/libgomp/team.c:122 > #2 0x00007ffff799761a in start_thread () from /lib64/libpthread.so.0 > #3 0x00007ffff76d159d in clone () from /lib64/libc.so.6 > > Note that GDB is unable to find s1, i2, or pass for either thread. > > I show the backtrace for thread 2 because it's the more difficult case > to handle due to the stack trace stopping at clone(). The stack frame > for main(), which is where the variables of interest reside, is not a > part of this stack. > > When we run this example using the patches associated with this change > along with several other patches, GDB's behavior looks like this: > > (gdb) b 14 > Breakpoint 1 at 0x400617: file ex3.c, line 14. > (gdb) run > Starting program: /mesquite2/.ironwood2/omp-tests/k/ex3-new > [Thread debugging using libthread_db enabled] > Using host libthread_db library "/lib64/libthread_db.so.1". > [New Thread 0x7ffff73ca700 (LWP 32643)] > > Thread 1 "ex3-new" hit Breakpoint 1, main._omp_fn.0 () at ex3.c:14 > 14 foo (i1); > (gdb) p s1 > $1 = -41 > (gdb) p i1 > $2 = 11 > (gdb) p i2 > $3 = 1 > (gdb) p pass > $4 = 1 > (gdb) c > Continuing. > [Switching to Thread 0x7ffff73ca700 (LWP 32643)] > > Thread 2 "ex3-new" hit Breakpoint 1, main._omp_fn.0 () at ex3.c:14 > 14 foo (i1); > (gdb) p s1 > $5 = -41 > (gdb) p i1 > $6 = 11 > (gdb) p i2 > $7 = 1 > (gdb) p pass > $8 = 1 > > I didn't show the stack here. It's the same as before. (I would, > however, like to be able to make GDB display a unified stack.) > > Note that GDB is now able to find and print values for s1, i2, and > pass. > > GCC constructs a new function for executing the parallel code. > The debugging information entry for this function is presently > placed at the same level as that of the function in which the > "#pragma omp parallel" directive appeared. > > This is partial output from "readelf -v" for the (non-working) example > shown above: > > <1><2d>: Abbrev Number: 2 (DW_TAG_subprogram) > <2e> DW_AT_external : 1 > <2e> DW_AT_name : (indirect string, offset: 0x80): main > <32> DW_AT_decl_file : 1 > <33> DW_AT_decl_line : 4 > <34> DW_AT_prototyped : 1 > <34> DW_AT_type : <0x9d> > <38> DW_AT_low_pc : 0x400591 > <40> DW_AT_high_pc : 0x71 > <48> DW_AT_frame_base : 1 byte block: 9c (DW_OP_call_frame_cfa) > <4a> DW_AT_GNU_all_tail_call_sites: 1 > <4a> DW_AT_sibling : <0x9d> > <2><4e>: Abbrev Number: 3 (DW_TAG_variable) > <4f> DW_AT_name : s1 > <52> DW_AT_decl_file : 1 > <53> DW_AT_decl_line : 6 > <54> DW_AT_type : <0x9d> > <58> DW_AT_location : 9 byte block: 3 30 10 60 0 0 0 0 0 > (DW_OP_addr: 601030) > ... > <2><7c>: Abbrev Number: 4 (DW_TAG_lexical_block) > <7d> DW_AT_low_pc : 0x4005a9 > <85> DW_AT_high_pc : 0x31 > <3><8d>: Abbrev Number: 5 (DW_TAG_variable) > <8e> DW_AT_name : (indirect string, offset: 0x55): pass > <92> DW_AT_decl_file : 1 > <93> DW_AT_decl_line : 11 > <94> DW_AT_type : <0x9d> > <98> DW_AT_location : 2 byte block: 91 64 (DW_OP_fbreg: -28) > ... > <1><a4>: Abbrev Number: 7 (DW_TAG_subprogram) > <a5> DW_AT_name : (indirect string, offset: 0x5a): main._omp_fn.0 > <a9> DW_AT_prototyped : 1 > <a9> DW_AT_artificial : 1 > <a9> DW_AT_low_pc : 0x400602 > <b1> DW_AT_high_pc : 0x21 > <b9> DW_AT_frame_base : 1 byte block: 9c (DW_OP_call_frame_cfa) > <bb> DW_AT_GNU_all_tail_call_sites: 1 > <bb> DW_AT_sibling : <0xd5> > <2><bf>: Abbrev Number: 8 (DW_TAG_formal_parameter) > <c0> DW_AT_type : <0xed> > <c4> DW_AT_artificial : 1 > <c4> DW_AT_location : 2 byte block: 91 58 (DW_OP_fbreg: -40) > ... > > The nesting level is indicated by the leading number in angle > brackets. This shows that the DW_TAG_VARIABLE DIE for s1 is nested > within the DIE for main's DW_TAG_subprogram DIE. Likewise, the > lexical block corresponding to the body of the for-loop is also nested > within main(). However, the DIES for main and main._omp_fun.0 are > both at level 1. > > With my patches for omp-low.c and omp-expand.c, the readelf -w output > looks like this instead: > > <1><2d>: Abbrev Number: 2 (DW_TAG_subprogram) > <2e> DW_AT_external : 1 > <2e> DW_AT_name : (indirect string, offset: 0x80): main > <32> DW_AT_decl_file : 1 > <33> DW_AT_decl_line : 4 > <34> DW_AT_prototyped : 1 > <34> DW_AT_type : <0xca> > <38> DW_AT_low_pc : 0x400591 > <40> DW_AT_high_pc : 0x71 > <48> DW_AT_frame_base : 1 byte block: 9c (DW_OP_call_frame_cfa) > <4a> DW_AT_GNU_all_tail_call_sites: 1 > <4a> DW_AT_sibling : <0xca> > <2><4e>: Abbrev Number: 3 (DW_TAG_variable) > <4f> DW_AT_name : s1 > <52> DW_AT_decl_file : 1 > <53> DW_AT_decl_line : 6 > <54> DW_AT_type : <0xca> > <58> DW_AT_location : 9 byte block: 3 30 10 60 0 0 0 0 0 > (DW_OP_addr: 601030) > <2><62>: Abbrev Number: 3 (DW_TAG_variable) > <63> DW_AT_name : i1 > <66> DW_AT_decl_file : 1 > <67> DW_AT_decl_line : 7 > <68> DW_AT_type : <0xca> > <6c> DW_AT_location : 2 byte block: 91 68 (DW_OP_fbreg: -24) > <2><6f>: Abbrev Number: 3 (DW_TAG_variable) > <70> DW_AT_name : i2 > <73> DW_AT_decl_file : 1 > <74> DW_AT_decl_line : 7 > <75> DW_AT_type : <0xca> > <79> DW_AT_location : 2 byte block: 91 6c (DW_OP_fbreg: -20) > <2><7c>: Abbrev Number: 4 (DW_TAG_lexical_block) > <7d> DW_AT_low_pc : 0x4005a9 > <85> DW_AT_high_pc : 0x31 > <3><8d>: Abbrev Number: 5 (DW_TAG_variable) > <8e> DW_AT_name : (indirect string, offset: 0x55): pass > <92> DW_AT_decl_file : 1 > <93> DW_AT_decl_line : 11 > <94> DW_AT_type : <0xca> > <98> DW_AT_location : 2 byte block: 91 64 (DW_OP_fbreg: -28) > <3><9b>: Abbrev Number: 6 (DW_TAG_subprogram) > <9c> DW_AT_name : (indirect string, offset: 0x5a): main._omp_fn.0 > <a0> DW_AT_prototyped : 1 > <a0> DW_AT_artificial : 1 > <a0> DW_AT_low_pc : 0x400602 > <a8> DW_AT_high_pc : 0x21 > <b0> DW_AT_frame_base : 1 byte block: 9c (DW_OP_call_frame_cfa) > <b2> DW_AT_GNU_all_tail_call_sites: 1 > <4><b2>: Abbrev Number: 7 (DW_TAG_formal_parameter) > <b3> DW_AT_type : <0xe9> > <b7> DW_AT_artificial : 1 > <b7> DW_AT_location : 2 byte block: 91 58 (DW_OP_fbreg: -40) > <4><ba>: Abbrev Number: 3 (DW_TAG_variable) > <bb> DW_AT_name : i1 > <be> DW_AT_decl_file : 1 > <bf> DW_AT_decl_line : 7 > <c0> DW_AT_type : <0xca> > <c4> DW_AT_location : 2 byte block: 91 6c (DW_OP_fbreg: -20) > > This time, note that the lexical block for the for-loop is still nested > within main(). The DIE for main._omp_fn.0 is nested within that lexical > block. > > This nesting enables GDB to find variables which ought to be in scope. > > (Obviously, there's some extra work required for finding variables > which reside on the stack in a different thread. That's handled in > patches to GDB and to libgomp.) > > gcc/ChangeLog: > > * omp-low.c (create_omp_child_function): Set DECL_CONTEXT > of child function to that of source function. > * omp-expand.c (expand_parallel_call): Add child function > to var chain in block from which child function originated. > > diff --git a/gcc/omp-expand.c b/gcc/omp-expand.c > index 5c48b78..7029951 100644 > --- a/gcc/omp-expand.c > +++ b/gcc/omp-expand.c > @@ -667,6 +667,25 @@ expand_parallel_call (struct omp_region *region, > basic_block bb, > tree child_fndecl = gimple_omp_parallel_child_fn (entry_stmt); > t2 = build_fold_addr_expr (child_fndecl); > > + if (gimple_block (entry_stmt) != NULL_TREE > + && TREE_CODE (gimple_block (entry_stmt)) == BLOCK) > + { > + tree b = BLOCK_SUPERCONTEXT (gimple_block (entry_stmt)); > + > + /* Add child_fndecl to var chain of the supercontext of the > + block corresponding to entry_stmt. This ensures that debug > + info for the outlined function will be emitted for the correct > + lexical scope. */ > + if (b != NULL_TREE && TREE_CODE (b) == BLOCK) > + { > + tree *tp; > + > + for (tp = &BLOCK_VARS (b); *tp; tp = &DECL_CHAIN (*tp)) > + ; > + *tp = child_fndecl; > + } > + } > + > vec_alloc (args, 4 + vec_safe_length (ws_args)); > args->quick_push (t2); > args->quick_push (t1); > diff --git a/gcc/omp-low.c b/gcc/omp-low.c > index 9cc2996..601d1b4 100644 > --- a/gcc/omp-low.c > +++ b/gcc/omp-low.c > @@ -1626,7 +1626,7 @@ create_omp_child_function (omp_context *ctx, bool > task_copy) > TREE_PUBLIC (decl) = 0; > DECL_UNINLINABLE (decl) = 1; > DECL_EXTERNAL (decl) = 0; > - DECL_CONTEXT (decl) = NULL_TREE; > + DECL_CONTEXT (decl) = ctx->cb.src_fn; > DECL_INITIAL (decl) = make_node (BLOCK); > BLOCK_SUPERCONTEXT (DECL_INITIAL (decl)) = decl; > if (omp_maybe_offloaded_ctx (ctx)) >