Debugger stopping in main() but not at my breakpont in setup()

With many, many thanks to @ maxgerhardt for his patience and help with my previous question, I can now debug, after a fashion.

However, the debugger halts at the main() function, but not at my breakpoint in setup() :frowning:

This worked once yesterday, but not since.

Any idea what I am doing wrongly?

The short story is: you can only use one breakpoint and it’s not retained across executions.

The longer story is: Setting break points requires hardware break points as the code is in flash and therefore cannot be modified. The ESP32 has two hardware breakpoints; one of them is often required for stepping across function calls etc. (also see Tips and Quirks). And likely due to bugs and shortcomings in OpenOCD and/or Visual Studio Code, breakpoints are usually not retained across executions even though Visual Studio Code still displays them.

If breakpoints are exceeded, the debugger will appear to behave strangely. That’s mainly because Visual Studio Code and gdb will let you set as many breakpoints as you like and not reflect the fact that this does not work.

So I recommend to:

Initially stop in setup() by adding the following line to platformio.ini:

debug_init_break = tbreak setup

Once the debugging has been started and the program has stopped in setup(), clear all breakpoints and set the next breakpoint. If stepping is not required, a second one can be set.

When the program stops at a breakpoint and a further breakpoint is needed, clear one and set the new one. Make sure you don’t set more than two breakpoints.

2 Likes

Thank you very, very much for along and informative answer. I am currently in the office and will check this out this evening. I have no doubt that things will be as you say.

I am surprised about PlatformIO. I would expect it to issue warnings, such as “you are attempting to set a 3rd breakpoint, but maximum 2 are supported”, and “I just lost all of your breakpoints”.

Although I suppose that I could limp along with one or two breakpoints, I would strongly prefer more.

I have, until now, eschewed a JTAG probe debugger, as that would be just one more thing to master, and purchased boards with on-board software debugging, expecting to be able to plug & play debug with multiple breakpoints.

Now I am contemplating a JTAG probe. I am strongly focused on ESP32, although I can envisage possibly using STM32 (I like to code Ada). Would Black Magic Probe or SEGER J-Link be more suitable to my needs, do you know? I am not much of a hardware guy, so am looking something simple to set up, which would allow multiple breakpoints. I am well familiar with GDB, but would prefer something that would integrate with my IDE . Any advice?

Hardware breakpoints are implemented in hardware. So it mainly depends on the particular MCU how many hardware breakpoints it has - if any. It would be possible to modify the flash code to set breakpoints. But the OpenOCD for ESP32 doesn’t implement it.

In ESP32 debugging, many components are involved: Visual Studio Code’s debugger view as a UI, gdb as the debugger itself, attaching to an OpenOCD background process (pretending to be a remote debugging target), OpenOCD implementing the JTAG protocol and communicating with the MCU via a debug adapter. PlatformIO provides the debugger configuration and startup script. I don’t fully understand which component would be reponsible for the number of active breakpoints, probably OpenOCD. So Espressif would need to enhance their ESP32 specific OpenOCD version.

The BlackMagic Probe works somewhat differently. It has more software built in. gdb can communicate directly with it - so OpenOCD is not required. To the best of my knowledge, it implement flash breakpoints. However, it only supports ARM based MCUs. ESP32 is not supported.

I’ve successfully used SEGER probes with ARM based processor but haven’t tried it with ESP32. They are a reliable solution and I beleive they implement advanced breakpoints as well.

2 Likes

So I recommend to:

Initially stop in setup() by adding the following line to platformio.ini :

debug_init_break = tbreak setup

Interestingly, doing that had my code stop at eh first line of

void setup()

without any breakpoints at all.

It no longer stops at the PlatformIO injected main() - which is fine by me.

The important thing is that it stops at breakpoints which I set.

Not exactly what I am used to in a debugging IDE, but SO MUCH better than debug by printf()

Thank you again for all of your help