Unable to step into C standard library source code

Asked by Matthias Kläy on 2018-08-31

Hi,

I teach how to write firmware, currently using Simplicity Studio on EFM32WG990 Cortex-M4F based MCUs. For educational reasons, I would like to demonstrate to my audience what exactly happens between the hardware reset and the call to main().

I have already spent approx. 20 hours trying to achieve this with Simplicity Studio on an EFM32 STK3800, with no success so far. The compacted case conversation with Silicon Labs is summarized at https://www.silabs.com/community/mcu/32-bit/forum.topic.html/searching_for_c_libr-Y1V4. Silicon Labs has concluded that this is rather an issue of the GNU Arm toolchain than Simplicity Studio, which made me create a case at https://developer.arm.com/open-source/gnu-toolchain/gnu-rm, where I got redirected here.

All three so far (me, SiLabs, Arm) concluded that it *should* be possible, but none of us is able to make it happen. I assume that the issue is either...
...missing debug information in crt0.o/libc.a/... of the GNU Arm distribution, or...
...a general configuration issue in Simplicity Studio / Eclipse, or...
...a configuration issue in the project specific debug configuration in Simplicity Studio / Eclipse, or...
...not possible at all? Can hardly believe so.
Guidance on how to configure Simplicity Studio / Eclipse to step into crt0.S and .c source files (located in a local workspace folder) of the C standard library objects (located at C:\SiliconLabs\SimplicityStudio\v4\developer\toolchains\gnu_arm\7.2_2017q4\arm-none-eabi\lib) is highly appreciated.

Best regards,
Matthias

Question information

Language:
English Edit question
Status:
Open
For:
GNU Arm Embedded Toolchain Edit question
Assignee:
No assignee Edit question
Last query:
2018-09-12
Last reply:
2018-09-12
john (jkovach) said : #1

For a long time now I've been providing my own startup code. Something like this:

#include <string.h>

extern char __etext, __data_start__, __data_end__, __bss_start__, __bss_end__;
extern int main();

void __attribute((used, noreturn))
Reset_Handler(void)
{
    // copy-init variables
    memcpy(&__data_start__, &__etext, &__data_end__ - &__data_start__);
    // zero-init variables
    memset(&__bss_start__, 0, &__bss_end__ - &__bss_start__);
    (void)main();
    for (;;) ;
}

Obviously, you can easily step into it. Besides, it demonstrates that there is really nothing special to it. After all, one of the stated design goals behind Cortex-M is that you can run it without writing a single line in assembly.

Hi John,

While this may be a feasible approach for some projects, this is a no-go for teaching. Why?
- Students would have to modify new projects that were created by the IDE, replacing something vendor provided by something hacked.
- Startup may do more than just data init and bss zero. Take a look at e.g. C:\SiliconLabs\SimplicityStudio\v4\developer\sdks\gecko_sdk_suite\v2.3\platform\Device\SiliconLabs\EFM32WG\Source\GCC\startup_efm32wg.S and you will find a bunch of interrupt handlers. The file is 341 lines long. And for C++, somebody would also have to call the initializers of static objects. And yes, if done with some precaution, this is OK even on embedded systems.
- Replacing something vendor provided by something hacked may be the solution in some situations. But in this case, including from an economic point of view (i.e. cost of verification, maintenance,...) this make-or-buy-decision is a very simple one: Keep what's provided by the vendor as long as it works fine. And, hacking to work around a tool configuration issue isn't a very wise decision either.

Summarizing:
This cannot be the final answer for my question I am attempting to get a solution for.

Best regards,
Matthias

Hi Matthias,

What is exactly the problem you are facing? What happen when you put a breakpoint on _mainCRTStartup?

Best regards,

Thomas

Hi Matthias,

What is exactly the problem you are facing? What happen when you put a breakpoint on _mainCRTStartup?

Best regards,

Thomas

Fix status after hitting the wrong button

Hi Thomas,

Answer to #1:

I cannot locate _mainCRTStartup in my project, so I cannot simply put a breakpoint there, at least not without some trick which I am not yet aware of.

Answer to #2:

I have a standard Simplicity Studio workspace with a standard Simplicity Studio project.
 - standard = based on the GNU ARM toolchain and the Gecko SDK
 - GNU ARM toolchain installed at C:\SiliconLabs\SimplicityStudio\v4\developer\toolchains\gnu_arm\7.2_2017q4
 - Gecko SDK installed at C:\SiliconLabs\SimplicityStudio\v4\developer\sdks\gecko_sdk_suite\v2.3

The GNU ARM toolchain only contains .a / .o / .h files, e.g. \arm-none-eabi\lib\crt0.o and libc_nano.a, but does not contain source code. Therefore, I have checked out the source code of GNU ARM 7.2_2017q4 to a local working directory, incl. e.g. D:\<Workspace>\newlib_of_gnu-arm-7.2_2017q4\libc\sys\arm\crt0.S.

So all should be set for stepping into crt0.S as well as standard C library source like e.g. memset(). At first, debugging in Simplicity Studio / Eclipse starts fine, execution stops at Reset_Handler: in startup_gcc_efm32wg.s (line #144). Stepping and/or resuming also works fine to bl __START (which is defined to _start) in startup_gcc_efm32wg.s (line #267). But then, stepping leaves the source code and only shows the disassembly. Eclipse shows no "cannot locate source code" dialog, adding the Newlib source to [Debug Configurations > Source] doesn't help, activating [Windows > Preferences > C/C++ > Debug > Show source files in binaries] doesn't help either. *I don't mange telling Eclipse to step through the crt0.S and standard C library source like e.g. memset()*. As a consequence, I never get to _mainCRTStartup either.

Best regards,
Matthias

Some string routines and startup code is written in assembly so showing assembly might be perfectly normal. Does it show a filename for that assembly? Perhaps step does not work for assembly code, in which case you can try stepi but of course that won't show you more than the assembly.

Best regards,

Thomas

Hi Thomas,

I appreciate your support, and at the same time ask you reading my explanations accuratly enough:

"Perhaps step does not work for assembly code"
Of course it does:
"Stepping and/or resuming also works fine to bl __START (which is defined to _start) in startup_gcc_efm32wg.s (line #267)"

"showing assembly might be perfectly normal"
Of course it is, but I stated:
"only shows the disassembly"

"Does it show a filename for that assembly?"
Actually not. So maybe this is the root cause for the whole matter:

When opening C:\SiliconLabs\SimplicityStudio\v4\developer\toolchains\gnu_arm\7.2_2017q4\arm-none-eabi\lib\crt0.o in a text editor, I cannot find anything like "crt0.S". I am not an expert on binary formats, but I'd expect seeing the filename in plaintext somewhere.

However, when opening C:\SiliconLabs\SimplicityStudio\v4\developer\toolchains\gnu_arm\7.2_2017q4\arm-none-eabi\lib\libc_nano.a in a text editor, I do see file names like "aeabi_memset.c". So I'd expect Eclipse being able to locate that file in the configured source paths.

You are more into the GNU ARM toolchain than me. Could you verify, whether objects and libraries are indeed built with debug information included, such that Eclipse has a chance to locate related source files? Or could you tell me, how I can find out this, e.g. by using objdump? Also, could you confirm that this is something defined by the GNU ARM toolchain distribution itself? Or is this something a vendor like Silicon Labs can configure?

Thank you and best regards,
Matthias

Leo Havmøller (leh-p) said : #9

The contents of an elf file can be displayed using readelf e.g.:
  arm-none-eabi-readelf.exe --all -wlLiaprmfFsoRt crtbegin.o > dump.txt
A file compiled with debug information would have sections like these:
  [626] .debug_info PROGBITS 00000000 011f47 03a80d 00 0 0 1
  [627] .debug_abbrev PROGBITS 00000000 04c754 0046eb 00 0 0 1
  [628] .debug_aranges PROGBITS 00000000 050e3f 0009c0 00 0 0 1
  [629] .debug_ranges PROGBITS 00000000 0517ff 000c80 00 0 0 1
  [630] .debug_line PROGBITS 00000000 05247f 007aae 00 0 0 1
  [631] .debug_str PROGBITS 00000000 059f2d 01164e 01 MS 0 0 1
  [632] .debug_frame PROGBITS 00000000 06b57c 0018c8 00 0 0 4
  [633] .debug_loc PROGBITS 00000000 06ce44 002de2 00 0 0 1
Dumping crtbegin.o and libgcc.a shows no debug sections.
The filename you found is just the filename, in the .symtab section.
Libs are generally built without debug information, and this seems to be consistent across different gcc target architectures.
My guess is that it is related to file size and distribution complexity. Different debuggers prefer different DWARF formats, and as such the toolchain would need to deliver libs built for each format.

Can you help with this problem?

Provide an answer of your own, or ask Matthias Kläy for more information if necessary.

To post a message you must log in.