3

I'm using GNU Arm Embedded Toolchain 10.3 to cross-compile for a Cortex-M0+ target, and using the accompanying GDB to debug.

I want to set a breakpoint on the following line of code:

    if (mPendingMessageIndex == 0)
    {
        // Start a new pending message
-->     mPendingMessage[0] = extracted;

        // Check for running status first
        if (isChannelMessage(getTypeFromStatusByte(mRunningStatus_RX)))
        {
            // Only these types allow Running Status

This is line 818 of the file, so in GDB, while stopped at a nearby line, I type:

b 818

And I get the response:

Breakpoint 2 at 0x2000cc1c: file lib/arduino_midi_library/src/MIDI.hpp, line 1090.

Now, this is an inlined template method, and I appreciate that inlining can complicate matters, even when compiling (as I am) with -Og -ggdb3. But line 1090 is in a separate method that's not invoked from here.

So... really?

Disassembly of the ELF file shows this:

            if (mPendingMessageIndex == 0)
    2000bed0:   6e63        ldr r3, [r4, #100]  ; 0x64
    2000bed2:   2b00        cmp r3, #0
    2000bed4:   d000        beq.n   2000bed8 <midi::MidiInterface<usbMidi::usbMidiTransport, midi::DefaultSettings, midi::DefaultPlatform>::parse()+0x3c>
    2000bed6:   e0b6        b.n 2000c046 <midi::MidiInterface<usbMidi::usbMidiTransport, midi::DefaultSettings, midi::DefaultPlatform>::parse()+0x1aa>
    lib/arduino_midi_library/src/MIDI.hpp:818
            mPendingMessage[0] = extracted;
--> 2000bed8:   335b        adds    r3, #91 ; 0x5b
    2000beda:   54e1        strb    r1, [r4, r3]
    lib/arduino_midi_library/src/MIDI.hpp:821
            if (isChannelMessage(getTypeFromStatusByte(mRunningStatus_RX)))
    2000bedc:   3b02        subs    r3, #2
    2000bede:   5ce2        ldrb    r2, [r4, r3]

Line 818 corresponds to address 0x2000bed8 so in GDB I type:

b *0x2000bed8

And get:

Breakpoint 3 at 0x2000bed8: file lib/arduino_midi_library/src/MIDI.hpp, line 818.

So GDB can map the address to the line, but not vice versa. It's a major pain in the arse, but I can work with it - so I do.

But curiosity gnaws at me - so after a lot more rooting around I eventually find in the GDB sources:

static int
find_line_common (struct linetable *l, int lineno,
                  int *exact_match, int start)
{
    ...
      /* Ignore non-statements.  */
      if (!item->is_stmt)
        continue;

So it looks like GDB will only set breakpoints on lines where the is_stmt flag is set in the DWARF info.

And sure enough, readelf -wL tells me that that line is not marked as is_stmt (indicated by 'x'):

    USB-MIDI.h                                   130          0x2000beca       1       x
    USB-MIDI.h                                   130          0x2000beca       2

    lib/arduino_midi_library/src/MIDI.hpp:
    MIDI.hpp                                     812          0x2000beca       3
    MIDI.hpp                                     815          0x2000bed0
    MIDI.hpp                                     815          0x2000bed2
--> MIDI.hpp                                     818          0x2000bed8
    MIDI.hpp                                     821          0x2000bedc
    MIDI.hpp                                    1228          0x2000bee0               x

readelf also tells me that no other line of code corresponds to address 0x2000bed8, and no other address corresponds to line MIDI.hpp:818.

So... I guess this boils down to two questions.

  • Why would GCC not mark such an unambiguous location as is_stmt?
  • If GCC can be expected to produce such output, why does GDB so naively ignore lines not marked is_stmt?

And the bonus question is:

  • Is there a way around this?

NB: I've experimented with compiler switches such as -gstatement-frontiers and -ginline-points, and they have no effect.

EDITED TO ADD:

readelf further indicates that large swathes of templated code from this file lack is_stmt flags. Literally hundreds of lines, corresponding to scores of statements, mostly consisting of switch statements and assignments, producing 250 line table records in the readelf output - of which ten are marked is_stmt, and precisely all of those correspond to inline expansions of helper functions.

Jeremy
  • 5,055
  • 1
  • 28
  • 44

0 Answers0