#defines show up as unidentified during debug.

Go To Last Post
9 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..

Happy 75th anniversary to one of the best movies ever made! Rick Blane [Bogart]: "Of all the gin joints, in all the towns, in all the world, she walks into mine."

 

"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