When using the -g compiler option, avr-gcc only generates line number and other debug information for C (and C++) files that pass the compiler. Functions that don't have line number information will be completely skipped by a single step command in gdb. This includes functions linked from a standard library, but by default also functions defined in an assembler source file, since the -g compiler switch does not apply to the assembler.

So in order to debug an assembler input file (possibly one that has to be passed through the C preprocessor), it's the assembler that needs to be told to include line-number information into the output file. (Other debug information like data types and variable allocation cannot be generated, since unlike a compiler, the assembler basically doesn't know about this.) This is done using the (GNU) assembler option --gstabs.

Example:

$ avr-as -mmcu=atmega128 --gstabs -o foo.o foo.s

When the assembler is not called directly but through the C compiler frontend (either implicitly by passing a source file ending in .S, or explicitly using -x assembler-with-cpp), the compiler frontend needs to be told to pass the --gstabs option down to the assembler. This is done using -Wa,--gstabs. Please take care to only pass this option when compiling an assembler input file. Otherwise, the assembler code that results from the C compilation stage will also get line number information, which confuses the debugger.

Example:

$ EXTRA_OPTS="-Wall -mmcu=atmega128 -x assembler-with-cpp" $ avr-gcc -Wa,--gstabs ${EXTRA_OPTS} -c -o foo.o foo.S

Also note that the debugger might get confused when entering a piece of code that has a non-local label before, since it then takes this label as the name of a new function that appears to have been entered. Thus, the best practice to avoid this confusion is to only use non-local labels when declaring a new function, and restrict anything else to local labels. Local labels consist just of a number only. References to these labels consist of the number, followed by the letter b for a backward reference, or f for a forward reference. These local labels may be re-used within the source file, references will pick the closest label with the same number and given direction.

Example:

myfunc: push    r16
        push    r17
        push    r18
        push    YL
        push    YH
        ...
        eor     r16, r16        ; start loop
        ldi     YL, lo8(sometable)
        ldi     YH, hi8(sometable)
        rjmp    2f              ; jump to loop test at end
1:      ld      r17, Y+         ; loop continues here
        ...
        breq    1f              ; return from myfunc prematurely
        ...
        inc     r16
2:      cmp     r16, r18
        brlo    1b              ; jump back to top of loop

1:      pop     YH
        pop     YL
        pop     r18
        pop     r17
        pop     r16
        ret

Back to FAQ Index.