I was trying to make a simple static heap module, and when trying to verify proper operation of the heap functions via the debugger I got quite confused.
Whether I build and run the below code for an AT91SAM7S32 in the simulator or on my target hardware, local variables in the watch window change in ways that I just can't believe could be valid.
For example, when stepping through the heap_alloc function (for the first call to it from main), the blocksize variable changes every time I press F10 once I get into the part where I'm actually allocating the block. The comments show how the value of blocksize changes when I don't think it should be changing at all.
Can anyone shed any light on this...?
It doesn't matter whether I declare the heap variables at the top of the file as static or not, the wierd behavior is the same.
#define NULL (0) #define HEAP_SIZE (1000) static char the_heap[HEAP_SIZE]; static char* ptr_the_heap = the_heap; static int heap_left = HEAP_SIZE; int heap_size(void) { return(heap_left); } void* heap_alloc(int blocksize) { int remainder; int padding; void* ptr_block; // allocate blocks on 32-bit boundaries remainder = blocksize % 4; padding = 4 - remainder; blocksize += padding; if (blocksize <= heap_left) { ptr_block = (void*)ptr_the_heap; // blocksize changes to 0x3E8 (1000) here ptr_the_heap += blocksize; // blocksize changes to 0x200000 here heap_left -= blocksize; // blocksize changes to 0x20000C here return(ptr_block); // blocksize changes to 0x3E8 here } else { return(NULL); // not enough space on the_heap for blocksize } } int main(void) { volatile void *p1; volatile void *p2; volatile void *p3; volatile void *p4; p1 = heap_alloc(1); p2 = heap_alloc(2); p3 = heap_alloc(3); p4 = heap_alloc(4); while(p1); while(p2); while(p3); while(p4); return(0); }
Frustrated, Dave.
P.S. I previewed this post, but the preview of it got really screwy in the code listing part as soon as I started using the wheel on my mouse to go up and down through the post. I hope it doesn't look that way once I actually post it!
The funny thing is that p1 through p4 all get set to the proper values after calling the heap_alloc function as shown, implying that the code that got generated was indeed correct.
However, what good is a watch window if the values shown for watched variables can be so wrong? How can you know when you should trust or not trust the information displayed in watch windows...?
If I had been debugging a larger, more complicated program, I would've probably incorrectly assumed that somehow code associated with an interrupt was corrupting those variables. The unfortunate result being much time wasted chasing down a problem that didn't really exist, well... at least it didn't exist in my code... it existed in the toolset.
Surely the solution is not to use global variables for everything. Can anyone tell me if there's some way to make the watch window work properly?
Dave,
this lookes like a compiler issue rather than a debugger issue. While trying your example and looking at the generated elf/dwarf output, the following can be seen:
parameter 'blocksize' is assigned to R0 temporary '__result' is also mapped to R0 variable 'ptr_block' is mapped to R0
this means, that the compiler optimizes the usage of registers even with optimize #0. The debugger has no chance to know which value is represented by 'R0' at a given location. The code is correct, just the lifetime info and probably the alternative location for the variables is missing in the generated debug info:
001127: 13 = 0x11 (DW_TAG_compile_unit) 001128: DW_AT_name Heap.c 00112f: DW_AT_producer ARM/Thumb C/C++ Compiler with , RVCT3.0 [Build 942] for uVision ... 001181: 59 = 0x2e (DW_TAG_subprogram) 001182: DW_AT_sibling 0xde (0x11fa) ... 001187: DW_AT_name heap_alloc 0011a1: 90 = 0x5 (DW_TAG_formal_parameter) 0011a2: DW_AT_name blocksize 0011ac: DW_AT_type indirect DW_FORM_ref1 0x94 (0x11b0) 0011ae: DW_AT_location block size 0x1 = { DW_OP_reg0 } <<=== R0 0011b0: 101 = 0x35 (DW_TAG_volatile_type) 0011b1: DW_AT_type indirect DW_FORM_ref_addr 0x821 0011b6: 82 = 0x34 (DW_TAG_variable) 0011b7: DW_AT_name __result 0011c0: DW_AT_type indirect DW_FORM_ref1 0xde (0x11fa) 0011c2: DW_AT_location block size 0x1 = { DW_OP_reg0 } <<=== R0 0011c4: DW_AT_artificial 0x1 0011c5: 78 = 0x34 (DW_TAG_variable) 0011c6: DW_AT_name remainder 0011d0: DW_AT_type indirect DW_FORM_ref_addr 0x821 0011d5: DW_AT_location block size 0x1 = { DW_OP_reg1 } 0011d7: DW_AT_start_scope 0x0 0011d8: 78 = 0x34 (DW_TAG_variable) 0011d9: DW_AT_name padding 0011e1: DW_AT_type indirect DW_FORM_ref_addr 0x821 0011e6: DW_AT_location block size 0x1 = { DW_OP_reg1 } 0011e8: DW_AT_start_scope 0x0 0011e9: 78 = 0x34 (DW_TAG_variable) 0011ea: DW_AT_name ptr_block 0011f4: DW_AT_type indirect DW_FORM_ref1 0xde (0x11fa) 0011f6: DW_AT_location block size 0x1 = { DW_OP_reg0 } <<=== R0 0011f8: DW_AT_start_scope 0x34 ...
Hmmm... sounds like one more level of optimization might be needed to fix this problem. Perhaps that level should be called -1, since 0 is already taken. Seems to me that currently there is no way to turn all compiler optimizations off, which in my opinion markedly reduces the usefulness of the debugger.
I've submitted this situation to KEIL for customer assistance, and a dialog has begun.
Thanks Peter.
Dave.
This is not a problem with the optimization level. It is a problem in the compiler where the debug information regarding the lifetime chains and locations is incomplete. This problem has already been addressed, the next compiler release will fix this. The current internal compiler release (under development) already fixes this issue. I need to find out when this new release will be available.
Regards, Peter
Many thanks Peter.
I'll be anxiously awaiting the next compiler release. Hopefully it'll be before my current support period expires.
When my wife recently me asked me how my day went, I told her about this and she asked "Why don't you just write your own tools?" I got a good chuckle out of that!
I've always been very pleased with the quality of KEIL products and their support. I'm glad to hear that this problem should disappear soon.
Thanks for your support, Dave.