#defines show up as unidentified during debug.

Go To Last Post
13 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Simalr problem all of my #defines show up as unidentified during debug. How can I fix that? Use constants?

Last Edited: Thu. Dec 7, 2017 - 08:39 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

mikey1 wrote:
Simalr problem all of my #defines show up as unidentified during debug.

A define can never be seen during debugging. A #define is NOT similar to a variable. Defines are handled by the C preprocessor that runs before the compiler proper sees the source code. And it is a matter of simple text substitution in trhe source.

 

Suppose you had this source snippet:

#define FOO 42

  .
  .
  .
  PORTD = FOO;

After preprocessing, tis is what will be left for the compiler to see:

 

PORTD = 42;

And since it is the compiler that produces the debugging information it can not produce any information about the define. It never even knew it existed.

 

mikey1 wrote:
Use constants?

That might help, but if the compiler decides to optimize it away then you're into the same fix again. Similar effects as above but because of a totally different phenomenon. You have

 

const uint8_t bar = 7;

 .
 .
 .
 
PORTD = bar;

The optimizer of the compiler sees that the variable is actually only used as a temporary storage for a value, and decides it can replace this with the simpler

 

PORTD = 7;

Again, thee variable won't be visible in a debugger. If you're lucky you'll get the reason reported. In some cases Atmel Studio will actually say "optimized away" or some such.

 

Best bet: Make it a volatile initialized variable.

volatile uint8_t baz = 99;

But now you're consuming RAM that you didn't in the variants above. No free lunch..

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mikey1 wrote:
Simalr problem .

Not really:

JohanEkdahl wrote:
A define can never be seen during debugging. A #define is NOT similar to a variable.

Hence this isn't really related to the 5-year-old thread http://www.avrfreaks.net/forum/atmel-studio-6-watch-unknown-identifier

 

Another option would be to use an enum - as this is seen by the compiler and can be included in debug info (though not all compilers do).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:
but if the compiler decides to optimize it away then you're into the same fix again
You sure about that? As you'll know, in C++ it's more usual to use "static const int", "static const uint8_t" etc for numeric constants than #define in the pre-pro. I'm pretty sure visual studio will show you the values of such static const variables even if they are ultimately optimised away (as you would hope).

 

 

As you can see it's happy to show me "width" in the debugger even though it's "static const int".

 

I just checked that for both Debug and Release. Of course this is MSVC, the Microsoft compiler and their debugger but I think behaviour will be the same in AS7.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It's possible for the preprocessor to generate the information for a #define to show up in the debugger.

I've never heard of it happening.

enums are always seen by the compiler proper.

They are much more likely to be known to the debugger.

 

What debugging information the

compiler emits was determined by its authors.

What information the debugger

understands was determined by  its authors.

International Theophysical Year seems to have been forgotten..
Anyone remember the song Jukebox Band?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

skeeve wrote:
It's possible for the preprocessor to generate the information for a #define to show up in the debugger. I've never heard of it happening.
I'm pretty sure Morten said that they do that and presumably the intention is to use/display the info at some point.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm pretty sure I have seen it happen - maybe not in Atmel Studio / GCC, though.

 

But I might be confused by enums ...

 

ISTR that Keil's C51 debugger, when it saw a magic number for which it had no symbol information, would just use the first #define it found which matched that magic number!

This, of course, produced nonsense a lot of the time!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
This, of course, produced nonsense a lot of the time!!
The GNU debugger does that too!

 

Hence:

C:\SysGCC\avr\bin>type avr.c
#include <avr/io.h>

int main(void) {
        while(1);
}
C:\SysGCC\avr\bin>avr-gcc -mmcu=attiny13 -Os avr.c -o avr.elf

C:\SysGCC\avr\bin>avr-objdump -S avr.elf

avr.elf:     file format elf32-avr


Disassembly of section .text:

00000000 <__vectors>:
   0:   09 c0           rjmp    .+18            ; 0x14 <__ctors_end>
   2:   0e c0           rjmp    .+28            ; 0x20 <__bad_interrupt>
   4:   0d c0           rjmp    .+26            ; 0x20 <__bad_interrupt>
   6:   0c c0           rjmp    .+24            ; 0x20 <__bad_interrupt>
   8:   0b c0           rjmp    .+22            ; 0x20 <__bad_interrupt>
   a:   0a c0           rjmp    .+20            ; 0x20 <__bad_interrupt>
   c:   09 c0           rjmp    .+18            ; 0x20 <__bad_interrupt>
   e:   08 c0           rjmp    .+16            ; 0x20 <__bad_interrupt>
  10:   07 c0           rjmp    .+14            ; 0x20 <__bad_interrupt>
  12:   06 c0           rjmp    .+12            ; 0x20 <__bad_interrupt>

00000014 <__ctors_end>:
  14:   11 24           eor     r1, r1
  16:   1f be           out     0x3f, r1        ; 63
  18:   cf e9           ldi     r28, 0x9F       ; 159
  1a:   cd bf           out     0x3d, r28       ; 61
  1c:   02 d0           rcall   .+4             ; 0x22 <main>
  1e:   02 c0           rjmp    .+4             ; 0x24 <_exit>

00000020 <__bad_interrupt>:
  20:   ef cf           rjmp    .-34            ; 0x0 <__vectors>

00000022 <main>:
  22:   ff cf           rjmp    .-2             ; 0x22 <main>

00000024 <_exit>:
  24:   f8 94           cli

00000026 <__stop_program>:
  26:   ff cf           rjmp    .-2             ; 0x26 <__stop_program>

"ctors"? In a C program ?

 

As it happens the generic linker scripts caters for C and C++ with:

    /* For future tablejump instruction arrays for 3 byte pc devices.
       We don't relax jump/call instructions within these sections.  */
    *(.jumptables)
     *(.jumptables*)
    /* For code that needs to reside in the lower 128k progmem.  */
    *(.lowtext)
     *(.lowtext*)
     __ctors_start = . ;
     *(.ctors)
     __ctors_end = . ;
     __dtors_start = . ;
     *(.dtors)
     __dtors_end = . ;
    KEEP(SORT(*)(.ctors))
    KEEP(SORT(*)(.dtors))
    /* From this point on, we don't bother about wether the insns are
       below or above the 16 bits boundary.  */
    *(.init0)  /* Start here after reset.  */
    KEEP (*(.init0))
    *(.init1)
    KEEP (*(.init1))
    *(.init2)  /* Clear __zero_reg__, set up stack pointer.  */
    KEEP (*(.init2))
    *(.init3)
    KEEP (*(.init3))
    *(.init4)  /* Initialize data and BSS.  */
    KEEP (*(.init4))
    *(.init5)
    KEEP (*(.init5))
    *(.init6)  /* C++ constructors.  */
    KEEP (*(.init6))
    *(.init7)
    KEEP (*(.init7))
    *(.init8)
    KEEP (*(.init8))
    *(.init9)  /* Call main().  */
    KEEP (*(.init9))
    *(.text)
    . = ALIGN(2);
     *(.text.*)

The code at:

00000014 <__ctors_end>:
  14:   11 24           eor     r1, r1

is actually part of:

    *(.init2)  /* Clear __zero_reg__, set up stack pointer.  */
    KEEP (*(.init2))

but before that are defined:

     __ctors_start = . ;
     __ctors_end = . ;
     __dtors_start = . ;
     __dtors_end = . ;

and as none of them has any associated code they also happen to label the first thing that comes along that does provide code and the disassembler just takes the first of them and emits that in the Asm listing.

 

One slight mystery here is that the .map file actually shows:

 *(.vectors)
 *(.progmem.gcc*)
                0x00000014                . = ALIGN (0x2)
                0x00000014                __trampolines_start = .
 *(.trampolines)
 .trampolines   0x00000014        0x0 linker stubs
 *(.trampolines*)
                0x00000014                __trampolines_end = .
 *(.progmem*)
                0x00000014                . = ALIGN (0x2)
 *(.jumptables)
 *(.jumptables*)
 *(.lowtext)
 *(.lowtext*)
                0x00000014                __ctors_start = .
 *(.ctors)
                0x00000014                __ctors_end = .
                0x00000014                __dtors_start = .
 *(.dtors)
                0x00000014                __dtors_end = .
 SORT(*)(.ctors)
 SORT(*)(.dtors)
 *(.init0)
 .init0         0x00000014        0x0 c:/sysgcc/avr/bin/../lib/gcc/avr/5.3.0/../../../../avr/lib/avr25/tiny-stack/crtattiny13.o
                0x00000014                __init
 *(.init0)
 *(.init1)
 *(.init1)
 *(.init2)
 .init2         0x00000014        0x8 c:/sysgcc/avr/bin/../lib/gcc/avr/5.3.0/../../../../avr/lib/avr25/tiny-stack/crtattiny13.o

All of those things are at address 0x0014 so I guess the big question is why the disasm labelled it as "__ctors_end" and not "__trampolines_start" which is actually the first thing defined for 0x0014. I'm guessing that it knows:

                0x00000014                __trampolines_start = .
                0x00000014                __trampolines_end = .
                0x00000014                __ctors_start = .
                0x00000014                __ctors_end = .
                0x00000014                __dtors_start = .
                0x00000014                __dtors_end = .
                0x00000014                __init

but it then holds these in alpha-order so:

                0x00000014                __ctors_end = .
                0x00000014                __ctors_start = .
                0x00000014                __dtors_end = .
                0x00000014                __dtors_start = .
                0x00000014                __init
                0x00000014                __trampolines_end = .
                0x00000014                __trampolines_start = .

and therefore __ctors_end is the first one. Obviously the disassembly would have made more sense if "__init" had been used.

 

In the .map file one also sees:

                0x00000020                __vector_1
                0x00000020                __bad_interrupt
                0x00000020                __vector_6
                0x00000020                __vector_3
                0x00000020                __vector_7
                0x00000020                __vector_5
                0x00000020                __vector_4
                0x00000020                __vector_9
                0x00000020                __vector_2
                0x00000020                __vector_8

So all those symbols have the value 0x0020 but when the disassembler disassembled the code it used:

00000020 <__bad_interrupt>:
  20:   ef cf           rjmp    .-34            ; 0x0 <__vectors>

which is again the first one if all the symbols with value 0x0020 are in alpha order.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks all for the education - I now have some more arrows in my quiver

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:
A define can never be seen during debugging

Aparently, it can!

 

skeeve wrote:
It's possible for the preprocessor to generate the information for a #define to show up in the debugger. I've never heard of it happening.

 

clawson wrote:
I'm pretty sure Morten said that they do that

 

Here you go:

 

The GCC Manual wrote:
3.9 Options for Debugging Your Program

 

-glevel

-ggdblevel

-gstabslevel

-gxcofflevel

-gvmslevel

 

Request debugging information and also use level to specify how much information. The default level is 2.

 

Level 0 produces no debug information at all. Thus, -g0 negates -g.

 

Level 1 produces minimal information, enough for making backtraces in parts of the program that you don’t plan to debug. This includes descriptions of functions and external variables, and line number tables, but no information about local variables.

 

Level 3 includes extra information, such as all the macro definitions present in the program. Some debuggers support macro expansion when you use -g3.

 

https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html

 

EDIT

 

sorry, the formatting of the GCC paste has gone wild ...

 

surprise

 

EDIT 2

 

I think that's better now ...

 

But note that it does say, "Some debuggers support macro expansion..."

 

#GCCMacroDebug

Last Edited: Thu. Dec 21, 2017 - 08:34 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Andy but have you actually tried this? For it to work it needs to be an end to end implementation. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Aha - there's the catch!

 

That's the "some debuggers" proviso ...

 

I think I may have seen it in Eclipse with ARM GCC ...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hmm ... just noticed in #10

I wrote:

The GCC Manual wrote:

Request debugging information and also use level to specify how much information. The default level is 2.

And yet level 2 is not documented!!

 

surprise

 

EDIT

 

Yes, it is missing from the original GCC page: https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html

 

 

Last Edited: Thu. Dec 21, 2017 - 11:52 AM