Menu

#54 Emit VHDL call stack.

1.0
closed
2015-11-22
2015-05-11
No

When debugging VHDL code it is very useful to get the call stack trace on for instance a failing assert.
This is found in commercial simulators. Without a call stack trace it can be very hard to determine where the error occurred if re-usable sub-programs like check or check_equal are used. Much verification code will contain such re-usable wrapper functions around asserts; for instance VUnit check package or OSVVM Alert package. Surely many VHDL coders will have wrapped asserts in re-usable functions to raise the abstraction level of their test benches and avoid copy paste coding.

Consider the following code:

test.vhd:

:::vhdl
entity test is
end entity;

architecture a of test is
  procedure check(value : boolean) is
  begin
    assert value;
  end procedure;
begin

  main : process
    procedure do_some_other_stuff is
    begin
      check(false);
    end procedure;

    procedure do_stuff is
    begin
      check(true);
      do_some_other_stuff;
      check(true);
    end procedure;
  begin
    check(true);
    do_stuff;
    wait;
  end process;
end architecture;

unhelpful command line output:

> ghdl -a test.vhd && ghdl --elab-run test
test.vhd:7:5:@0ms:(assertion error): Assertion violation

The error message just tells me an assert has failed in my re-usable check function which is not very helpful and making it very hard to locate the error if it is used everywhere. It would be great to get a full stack trace such as:

helpful command line output:

> ghdl -a test.vhd && ghdl --elab-run test
test.vhd:7:5:@0ms:(assertion error): Assertion violation
        ... called from test.vhd:14 do_some_other_stuff
        ... called from test.vhd:20 do_stuff
        ... called from test.vhd:25 main

Other simulators expose this as a TCL command that you can execute after simulation has stopped on an error or any other reason. Having it enabled by a command line flag would also work.

A simple implementation of this would be to store a static table of line numbers and strings to all possible call locations and pushing/popping indexes to this table when calling and returning from subprograms. For people who do not want to pay for the runtime overhead maybe a flag has to be added such that it can be disabled thus also disabling the possibility to have a stack trace.

Discussion

  • Tristan Gingold

    Tristan Gingold - 2015-05-11

    If you are using llvm or gcc backend, compile and elaborate with -g.
    Then run within gdb. Set a breakpoint on do_report. And then:

    (gdb) break do_report
    Breakpoint 1 at 0x100007548: file /Users/gingold/devel/ghdl/src/grt/grt-lib.adb, line 44.
    (gdb) r
    Starting program: /Users/gingold/devel/ghdl-updates.hg/testsuite/gna/ticket54/test
    
    Breakpoint 1, grt.lib.do_report (msg=..., str=0x0, default_str=..., 
        severity=2, loc=0x1000962c0)
        at /Users/gingold/devel/ghdl/src/grt/grt-lib.adb:44
    44                          Default_Str : String;
    (gdb) where
    #0  grt.lib.do_report (msg=..., str=0x0, default_str=..., severity=2, 
        loc=0x1000962c0) at /Users/gingold/devel/ghdl/src/grt/grt-lib.adb:44
    #1  0x0000000100007a32 in <__ghdl_assert_failed> (str=0x0, severity=2, 
        loc=0x1000962c0) at /Users/gingold/devel/ghdl/src/grt/grt-lib.adb:89
    #2  0x000000010000197c in work__test__ARCH__a__check (INSTANCE=0x100204430, 
        value=false) at test.vhdl:7
    #3  0x000000010000199b in work__test__ARCH__a__main__do_some_other_stuff (
        INSTANCE=0x100204430) at test.vhdl:14
    #4  0x00000001000019c6 in work__test__ARCH__a__main__do_stuff (
        INSTANCE=0x100204430) at test.vhdl:20
    #5  0x0000000100001a02 in work__test__ARCH__a__main__PROC (
        INSTANCE=0x100204430) at test.vhdl:25
    #6  0x000000010005e9ca in grt_stack_loop ()
    #7  0x0000000000000000 in ?? ()
    

    It would be easy to have a better name for the breakpoint.

    But I suppose you'd prefer something easier to use...

    Tristan.

     

    Last edit: Tristan Gingold 2015-05-12
  • Olof Kraigher

    Olof Kraigher - 2015-05-11

    Thank you for the suggestion. As you say I would prefer something more integrated and less dependent on the internal program structure of GHDL. The names in the gdb stack trace does not directly point to vhdl files and corresponding line numbers either. Also users of GHDL might not have gdb. Anyway it is better than nothing for now but I still think my original feature request is valid.

     
  • Tristan Gingold

    Tristan Gingold - 2015-05-12

    I agree this is not integrated and that names aren't demangled.
    But the trace points to vhdl files and line numbers.

    I am investigating which symbolisation libraries can be used.

     
  • Olof Kraigher

    Olof Kraigher - 2015-05-13

    When I suggested the same feature to the author of NVC he said he was thinking about using LLVM debug info. Since you are supporting three backends; mcode, gcc and llvm. This would probably not be attractive to you. Maybe you have to solve it by generating such a location table and manually inserting push/pop of indexes to it in the GHDL base code before emitting it to the backend.

    One general question I have for you is what is your thoughts about the future of the backends of GHDL? It seems mcode cannot work on x86_64 which is what most compures are since many years and that GCC backend is known for being hard to build. Isnt LLVM the best option? Many new programming languages that come out these days are based on LLVM like Swift from Apple and Rust from Mozilla. I could imagine that the cost of an open source project to maintain three backends would be high?

     
    • Tristan Gingold

      Tristan Gingold - 2015-05-13

      All the backends (mcode, gcc and llvm) can generate dwarf debug info; so using debug info is not a real issue.

      I am not thrilled by having a location table - shouldn't be that efficient. I am still investigating.

      The future of the backends is a good question. mcode has some good advantages: easy to build, very scalable, very fast for running the test suite. llvm was recently added and may be less mature than gcc. For sure, mcode and gcc somewhat overlaps...

       
      • Olof Kraigher

        Olof Kraigher - 2015-05-13

        Great that they all support dwarf debug info. Then that might still be a good option.
        LLVM should be quite fast as well when not asking it to do many optimizations. It also supports JIT which I suspect is good for quickly running short tests but will scale up to long tess when more optimization has been performed. It was also easy to build, this is why I choose to use the LLVM backend myself, mcode will not work on my 64-bit machine and I gave up trying to build the gcc backend. Are you planning on adding x86_64 support for mcode by the way?

         
        • Tristan Gingold

          Tristan Gingold - 2015-05-14

          The code to support LLVM JIT is already here, but I haven't tested it strongly.
          Mcode should work on your 64 bit linux machine, provided you use a 32 bit compiler (compatibility mode).

          I don't plan to add x86_64 mcode, unless LLVM JIT reveals to be a disaster - but that's not expected! I am not sure how to use debug info in LLVM JIT.

           
  • Olof Kraigher

    Olof Kraigher - 2015-05-13

    Sorry for claiming that there were not references to vhdl file and line numbers. Somehow I did not see it before you reformatted the post. This makes it more useful actually.

     
    • Tristan Gingold

      Tristan Gingold - 2015-05-14

      No problems. My fault: the formatting of gdb output was indeed unreadable!

       
  • Olof Kraigher

    Olof Kraigher - 2015-05-14

    Just to clarify my request a bit regarding the user interface. One would not want the backtrace for every report. Peferably the severity level of when a backtrace is printed would be separately configured. Personally I would want to exit on severity>=error and have the backtrace for severity>=warning. Also one would want a backtrace for every fatal error that stops simulation such as divide by zero or index out of range errors etc.

     
  • Tristan Gingold

    Tristan Gingold - 2015-11-18

    I have a prototype for this feature:

    GHDL -r test --assert-level=error
    test.vhdl:7:5:@0ms:(assertion error): Assertion violation
    ghdl_mcode:error: assertion failed
    from: work.test(a).check at test.vhdl:7
    from: work.test(a).main.do_some_other_stuff at test.vhdl:14
    from: work.test(a).main.do_stuff at test.vhdl:20
    from: process work.test(a).main at test.vhdl:25
    ghdl_mcode:error: simulation failed

    It currently works with mcode, but I plan to support llvm too.

    Tristan.

     
  • Olof Kraigher

    Olof Kraigher - 2015-11-19

    Great! This would be a big usability lift for GHDL. Looking forward to having this with the LLVM backend which is the one I mainly use.

     
  • Tristan Gingold

    Tristan Gingold - 2015-11-22
    • status: open --> closed
    • assigned_to: Tristan Gingold
     
  • Tristan Gingold

    Tristan Gingold - 2015-11-22

    This is now implemented. You get:

    test.vhdl:7:5:@0ms:(assertion error): Assertion violation
    ghdl:error: assertion failed
    from: work.test(a).check at test.vhdl:7
    from: work.test(a).main.do_some_other_stuff at test.vhdl:14
    from: work.test(a).main.do_stuff at test.vhdl:20
    from: process work.test(a).main at test.vhdl:25

    You need libbacktrace (from gcc) for this feature when using llvm.

    Thanks,
    Tristan.

     

Log in to post a comment.

MongoDB Logo MongoDB