AdaCore / bb-runtimes

Source repository for the GNAT Bare Metal BSPs
Other
63 stars 50 forks source link

Strange behaviour #49

Closed NicoPy closed 3 years ago

NicoPy commented 3 years ago

Hi,

I use GNAT CE 2020 on a ARM platform. I've created a new runtime for a NXP Kinetis µController. This system randomly crashes. To be more exact, the crash always happens in the same way for a defined source set. Change one line and the crash happens later or in another location. I tried to set bigger stacks without success.

For some reason, I can't use this board anymore so I started to use a new project with another board which populates another µController (NXP iMX RT). I created a new runtime for this board (ARM) and started coding stuff to get access to essential peripherals (GPIO, UART). As the CPU core frequency is defined in the runtime, I have created a procedure to check the defined frequency is correct :

   --**************************************************************************
   -- Check the CPU frequency set in runtime is the one that is actually used.
   --
   procedure Check_Core_Frequency is
      function Time_Span_To_UInt64 is new Ada.Unchecked_Conversion(Source => Ada.Real_Time.Time_Span,
                                                                   Target => Integer_64);   
      TicksPerSecond : constant Integer_64 := Time_Span_To_UInt64(Ada.Real_Time.To_Time_Span(1.0));
      CoreFreq : constant Natural := clock.GetFrequency(clock.CpuClk);
   begin
      --Put_Line("Ticks per second : " & TicksPerSecond'Image);
      --Put_Line("Core Frequency   : " & CoreFreq'Image);
      pragma Assert(Integer_64(CoreFreq) = TicksPerSecond,
                 "Ticks per second (" & TicksPerSecond'Image & ")" &
                 " do not match Core Frequency (" & CoreFreq'Image & ")");
   end Check_Core_Frequency;

This procedure is called early in my code. The output is surprising :

In last chance handler
Unhandled Ada Exception: SYSTEM.ASSERTIONS.ASSERT_FAILURE
Message: Ticks per second ( 20971520) do not match Core F
                                                         ▒
                                                          ▒▒▒▒)
Call stack traceback locations:
0x6001C4F1 0x6001CCAD 0x6000244B 0x6000285D

The output is sometimes slightly different but garbage characters are always shown.

When I uncomment the second Put_Line, I most often get a correct output :

Core Frequency   :  396000000
In last chance handler
Unhandled Ada Exception: SYSTEM.ASSERTIONS.ASSERT_FAILURE
Message: Ticks per second ( 20971520) do not match Core Frequency ( 396000000)
Call stack traceback locations:
0x6001C655 0x6001CDFD 0x6000244B 0x6000285D

The output often shows only the first line Core Frequency : 396000000 (about half the time). Same problem when I uncomment the first Put_Line only.

However, when I uncomment both Put_Line the output is always correct.

In my first project, there where a lot of numbers printed (Integer and Floats). When not printing numbers, the system was (apparently) operating correctly.

I know the problem can be located somewhere else and not at all related to this but my feeling is that there is a problem with Integer'Image() and alike functions.

Any direction to find the culprit ?

Regards, Nicolas

Fabien-Chouteau commented 3 years ago

Hi @NicoPy, This does look like stack or secondary stack overflow, I would search in that direction.

Unless you have a strong need to Ravenscar tasking, I suggest you have a look at this solution: https://blog.adacore.com/ada-on-any-arm-cortex-m-device-in-just-a-couple-minutes

Based on the info you provided I don't think this is a bug in the run-time code, so I am closing this issue for now.

NicoPy commented 3 years ago

As I said in my original post, I tried to change the stacks sizes.

In my new project, there is no task. In fact it is very basic. Just GPIO and UART init. And the failling assert.

Can you explain me, what in my code, can break Ada runtime ?

Fabien-Chouteau commented 3 years ago

Hello @NicoPy ,

As I said in my original post, I tried to change the stacks sizes.

Did you also look at the secondary stack? You have all the symptoms of stack overflow: garbage output that is only happening when doing string concatenation.

In my new project, there is no task. In fact it is very basic. Just GPIO and UART init. And the failling assert.

In that case I recommend not doing your own run-time and using zfp-cortex-m7df and startup-gen instead.

Can you explain me, what in my code, can break Ada runtime ?

As I said, my best guess based on the info you provide is stack overflow. If you think that there is a bug in the run-time code, then you should be able to reproduce it with one of the standard BSP provided with GNAT Community and we will then be able to investigate.

NicoPy commented 3 years ago

Bonjour Fabien,

Did you also look at the secondary stack?

Yes, I did. But maybe the requested stack size is much more than I think it should be.

You have all the symptoms of stack overflow: garbage output that is only happening when doing string concatenation.

Is there a way to check the requested stack size ? GNATstack is only for pro, right ?

One weird thing is that after erasing the output dir (obj) manually and recompiling all sources, the behavior is different (on the target). I already had issues where the compiler was outputting non sense errors. I had to manually erase the obj dir to recover a correct compiler behavior. It was like the sources I was editing were not modified (an old version was used by the compiler).

Note : I'm using GNAT community 2020

Nicolas

Fabien-Chouteau commented 3 years ago

Hello @NicoPy ,

Is there a way to check the requested stack size ? GNATstack is only for pro, right ?

GNATstack is indeed a GNAT Pro tool. There is one other option which is to implement a "watermark" for the primary stack, but it has a lot of impact on your program. It's the compiler option -fstack-check, with this option the compiler generates a call to the _gnat_stack_check function every time data is allocated on the stack. You can then implement the _gnat_stack_check yourself and record the stack pointer to see if it goes out of bounds.

One weird thing is that after erasing the output dir (obj) manually and recompiling all sources, the behavior is different (on the target). I already had issues where the compiler was outputting non sense errors. I had to manually erase the obj dir to recover a correct compiler behavior. It was like the sources I was editing were not modified (an old version was used by the compiler).

It could be an issue with your build or project file then.