This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH v3 1/1] Don't rewind PC for GHC generated frames


Hi,

Is there anyway I can help to move this forward?

Thanks,
Bartosz

2018-02-04 0:06 GMT+00:00 Bartosz Nitka <niteria@gmail.com>:
> GHC - the Haskell compiler generates code that violates one of
> GDB's assumptions.
>
> GDB assumes that the address in a frame was generated by the call
> instruction and that it is the address right after the call
> instruction (I'm paraphrasing the comment in get_frame_address_in_block).
> So to get an address in the same block as the call instruction, one
> has to substract 1. This is doubly beneficial because some functions
> are "noreturn" and don't have further instructions after call,
> so GDB would be looking at gibberish.
>
> GHC generates completely different code. It uses jumps instead of call
> and manages the stack itself. Furthermore every piece of code is
> preceeded by some metadata called the Info Table. If we substract
> from the program counter it ends up pointing to the Info Table,
> which is undesirable.
> GHC has a workaround for this [1] that works most of the time, it
> basically lies in the DWARF data and extends the function one byte
> backwards. That helps with making unwinding succeed most of the time,
> but then the address is also used for looking up symbols and
> they can't be resolved.
>
> This change disables program counter rewinding for
> compilation units generated by GHC.
>
> Some additional context can be found here [2].
>
> The impact.
>
> Let's take an example from [2].
> Here's the example Haskell program (fib.hs):
>
>   fib :: Int -> Int
>   fib 0 = 0
>   fib 1 = 1
>   fib n = fib (n-1) + fib (n-2)
>   main :: IO ()
>   main = print $ fib 20
>
> If we run it with current GDB master we get:
>
>   (gdb) br fib.hs:3
>   Breakpoint 1 at 0x405588: file fib.hs, line 3.
>   (gdb) r
>   Breakpoint 1, Main_zdwfib_info () at fib.hs:3
>   3       fib 1 = 1
>   (gdb) bt
>   #0  Main_zdwfib_info () at fib.hs:3
>   #1  0x00000000004055c8 in Main_zdwfib_info () at fib.hs:4
>   #2  0x00000000004055c8 in Main_zdwfib_info () at fib.hs:4
>   #3  0x00000000004055c8 in Main_zdwfib_info () at fib.hs:4
>   #4  0x00000000004055c8 in Main_zdwfib_info () at fib.hs:4
>   #5  0x00000000004055c8 in Main_zdwfib_info () at fib.hs:4
>   #6  0x00000000004055c8 in Main_zdwfib_info () at fib.hs:4
>   #7  0x00000000004055c8 in Main_zdwfib_info () at fib.hs:4
>   #8  0x00000000004055c8 in Main_zdwfib_info () at fib.hs:4
>   #9  0x00000000004055c8 in Main_zdwfib_info () at fib.hs:4
>   #10 0x00000000004055c8 in Main_zdwfib_info () at fib.hs:4
>   #11 0x00000000004055c8 in Main_zdwfib_info () at fib.hs:4
>   #12 0x00000000004055c8 in Main_zdwfib_info () at fib.hs:4
>   #13 0x00000000004055c8 in Main_zdwfib_info () at fib.hs:4
>   #14 0x00000000004055c8 in Main_zdwfib_info () at fib.hs:4
>   #15 0x00000000004055c8 in Main_zdwfib_info () at fib.hs:4
>   #16 0x00000000004055c8 in Main_zdwfib_info () at fib.hs:4
>   #17 0x00000000004055c8 in Main_zdwfib_info () at fib.hs:4
>   #18 0x00000000004055c8 in Main_zdwfib_info () at fib.hs:4
>   #19 0x00000000004055c8 in Main_zdwfib_info () at fib.hs:4
>   #20 0x00000000004056d8 in Main_main2_info () at fib.hs:4
>   #21 0x000000000040bab0 in base_GHCziIOziHandleziText_zdwwriteBlocks_info () at libraries/base/GHC/IO/Handle/Text.hs:595
>   #22 0x0000000000488bf0 in ?? () at rts/Exception.cmm:332
>   Backtrace stopped: previous frame identical to this frame (corrupt stack?)
>
> Here's an analogous session after this patch:
>
>   (gdb) br fib.hs:3
>   Breakpoint 1 at 0x405588: file fib.hs, line 3.
>   (gdb) r
>   Breakpoint 1, Main_zdwfib_info () at fib.hs:3
>   3       fib 1 = 1
>   (gdb) bt
>   #0  Main_zdwfib_info () at fib.hs:3
>   #1  Main_zdwfib_info () at fib.hs:4
>   #2  Main_zdwfib_info () at fib.hs:4
>   #3  Main_zdwfib_info () at fib.hs:4
>   #4  Main_zdwfib_info () at fib.hs:4
>   #5  Main_zdwfib_info () at fib.hs:4
>   #6  Main_zdwfib_info () at fib.hs:4
>   #7  Main_zdwfib_info () at fib.hs:4
>   #8  Main_zdwfib_info () at fib.hs:4
>   #9  Main_zdwfib_info () at fib.hs:4
>   #10 Main_zdwfib_info () at fib.hs:4
>   #11 Main_zdwfib_info () at fib.hs:4
>   #12 Main_zdwfib_info () at fib.hs:4
>   #13 Main_zdwfib_info () at fib.hs:4
>   #14 Main_zdwfib_info () at fib.hs:4
>   #15 Main_zdwfib_info () at fib.hs:4
>   #16 Main_zdwfib_info () at fib.hs:4
>   #17 Main_zdwfib_info () at fib.hs:4
>   #18 Main_zdwfib_info () at fib.hs:4
>   #19 Main_zdwfib_info () at fib.hs:4
>   #20 0x00000000004056d8 in Main_main2_info () at fib.hs:4
>   #21 base_GHCziIOziHandleziText_zdwwriteBlocks_info () at libraries/base/GHC/IO/Handle/Text.hs:582
>   #22 stg_catch_frame_info () at rts/Exception.cmm:370
>   #23 stg_stop_thread_info () at rts/StgStartup.cmm:42
>   #24 0x00000000004a62ab in c2MH_str ()
>   #25 0x00010000006c94c0 in ?? ()
>   #26 0x00000000006e5e60 in ?? ()
>   #27 0x00007fffffffdae8 in ?? ()
>   #28 0x00007fffffffdcb0 in ?? ()
>   #29 0x00000000006c94c0 in Main_main3_closure ()
>   #30 0x00007fffffffdbd0 in ?? ()
>   #31 0x0000000000405480 in ?? ()
>   #32 0x00007fffffffdcb0 in ?? ()
>   #33 0x0000000000000000 in ?? ()
>
> There are a couple of things to note here.
>
> First is that the unwinding got further, even a bit too far. It should
> have ended on frame #23 on stg_stop_thread_info. That's the first thing
> pushed on the stack when running a ligthweight thread. I'm not sure yet
> how GHC is supposed to signal that it's the last thing on the stack and
> if it's trying to do that.
>
> Second thing is that we get the correct line number for frame #22 *and*
> the symbol gets successfully resolved. Before the patch we were
> substracting one, making the symbol lookup fail. I think that's also
> what makes GDB give a cleaner output on frames #0 - #19.
>
> Note that to get the same results as me, you have to compile the
> compiler with debugging symbols as described on [2].
>
> [1] https://phabricator.haskell.org/diffusion/GHC/browse/master/compiler/nativeGen/Dwarf/Types.hs;e9ae0cae9eb6a340473b339b5711ae76c6bdd045$399-417
> [2] https://ghc.haskell.org/trac/ghc/wiki/DWARF
>
> gdb/ChangeLog:
>
>        * dwarf2read.c (process_full_comp_unit): Populate
>        * producer_is_ghc.
>        * frame.c (get_frame_address_in_block): Don't rewind the program
>        counter for code generated by GHC.
>        * symtab.h (struct compunit_symtab): Add producer_is_ghc.
> ---
>  gdb/ChangeLog    | 7 +++++++
>  gdb/dwarf2read.c | 4 ++++
>  gdb/frame.c      | 9 ++++++++-
>  gdb/symtab.h     | 3 +++
>  4 files changed, 22 insertions(+), 1 deletion(-)
>
> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index 3ce980c8c3..6b35bf34b6 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,3 +1,10 @@
> +2018-02-01  Bartosz Nitka  <niteria@gmail.com>
> +
> +       * dwarf2read.c (process_full_comp_unit): Populate producer_is_ghc.
> +       * frame.c (get_frame_address_in_block): Don't rewind the program
> +       counter for code generated by GHC.
> +       * symtab.h (struct compunit_symtab): Add producer_is_ghc.
> +
>  2018-02-01  Yao Qi  <yao.qi@linaro.org>
>
>         * arm-tdep.c (arm_record_data_proc_misc_ld_str): Rewrite it.
> diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
> index 51d0f39f75..2516c48741 100644
> --- a/gdb/dwarf2read.c
> +++ b/gdb/dwarf2read.c
> @@ -10501,6 +10501,10 @@ process_full_comp_unit (struct dwarf2_per_cu_data *per_cu,
>         cust->epilogue_unwind_valid = 1;
>
>        cust->call_site_htab = cu->call_site_htab;
> +
> +      if (startswith (cu->producer,
> +            "The Glorious Glasgow Haskell Compilation System"))
> +        cust->producer_is_ghc = 1;
>      }
>
>    if (dwarf2_per_objfile->using_index)
> diff --git a/gdb/frame.c b/gdb/frame.c
> index 1384ecca4f..9ff0dcb130 100644
> --- a/gdb/frame.c
> +++ b/gdb/frame.c
> @@ -2458,7 +2458,14 @@ get_frame_address_in_block (struct frame_info *this_frame)
>        && (get_frame_type (this_frame) == NORMAL_FRAME
>           || get_frame_type (this_frame) == TAILCALL_FRAME
>           || get_frame_type (this_frame) == INLINE_FRAME))
> -    return pc - 1;
> +    {
> +      /* GHC intermixes metadata (info tables) with code, going back is
> +         guaranteed to land us in the metadata.  */
> +      struct compunit_symtab *cust = find_pc_compunit_symtab (pc);
> +      if (cust != NULL && cust->producer_is_ghc)
> +        return pc;
> +      return pc - 1;
> +    }
>
>    return pc;
>  }
> diff --git a/gdb/symtab.h b/gdb/symtab.h
> index f9d52e7697..c164e5ba5f 100644
> --- a/gdb/symtab.h
> +++ b/gdb/symtab.h
> @@ -1432,6 +1432,9 @@ struct compunit_symtab
>       instruction).  This is supported by GCC since 4.5.0.  */
>    unsigned int epilogue_unwind_valid : 1;
>
> +  /* This CU was produced by Glasgow Haskell Compiler */
> +  unsigned int producer_is_ghc : 1;
> +
>    /* struct call_site entries for this compilation unit or NULL.  */
>    htab_t call_site_htab;
>
> --
> 2.14.1
>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]