Help with Dwarf file output from avr-gcc

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

I'm building a  software debugger (for AtMega328p to start with, may extend later). So far I've successfully parsed the debug file (created with objdump) and extracted function names, typedefs, addresses of globals, values of (global) array contents etc.

But I'm having trouble understanding​ how the local variables work. I've read through this and this but they don't refer specifically to the avr-gcc output format.

As a simple example I'm trying this function:

int myFunc(int var1, int var2)
{
 int varR;
 long long1;
 long1 = var1 * 2;
 varR = long1 / var2 * var1;
 return varR;
}

​in order to create a mixture of locals stored in registers and on the stack. These are shown quite clearly in Atmel Studio when I debug with a hardware device:

so as you can see, only 'var1' has been allocated to the stack, and the others to registers. So far so good. But when I look at the relevant section of the debug file, I see this (for 'var1' and 'var2'):

 <2><673>: Abbrev Number: 5 (DW_TAG_formal_parameter)
    <674>   DW_AT_name        : (indirect string, offset: 0x31f): var1
    <678>   DW_AT_decl_file   : 1
    <679>   DW_AT_decl_line   : 24
    <67a>   DW_AT_type        : <0x62b>
    <67e>   DW_AT_location    : 0x47 (location list)
 <2><682>: Abbrev Number: 5 (DW_TAG_formal_parameter)
    <683>   DW_AT_name        : (indirect string, offset: 0x324): var2
    <687>   DW_AT_decl_file   : 1
    <688>   DW_AT_decl_line   : 24
    <689>   DW_AT_type        : <0x62b>
    <68d>   DW_AT_location    : 0x6b (location list)

Their locations are described in the same way, as entries 0x47 and 0x6b in the location list. But when I look at the location list for those numbers I see this:

    0000003f <End of list>
    00000047 0000008a 000000ae (DW_OP_reg24 (r24); DW_OP_piece: 1; DW_OP_reg25 (r25); DW_OP_piece: 1)
    00000057 000000ae 0000010a (DW_OP_fbreg: -11)
    00000063 <End of list>
    0000006b 0000008a 000000d6 (DW_OP_reg22 (r22); DW_OP_piece: 1; DW_OP_reg23 (r23); DW_OP_piece: 1)
    0000007b 000000d6 0000010a (DW_OP_fbreg: -9)
    00000087 <End of list>

Again they have the same structure, even though Atmel Studio is telling me that one of these variables is stored in r22/r23 and one at fp-11.

So, my question is, how do I determine where to look when I want to find the value of these variables? I've attached the full debug file if that helps!

Attachment(s): 

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

OK, solved this one now (I think). I found the ultimate reference for Dwarf 2 which helped!

    00000047 0000008a 000000ae (DW_OP_reg24 (r24); DW_OP_piece: 1; DW_OP_reg25 (r25); DW_OP_piece: 1)
    00000057 000000ae 0000010a (DW_OP_fbreg: -11)
    00000063 <End of list>

So, if the program counter is between 0x8a and 0xae, then my local variable sits in r24/25. If it's after 0xae then  it's at offset 11 from the frame.

The compiler is being clever and shifting things between registers and stack all the time to make the most efficient code.

I also need to check for the DW_OP_piece attributes, since in theory a variable needn't be in consecutive addresses, but I guess this won't be a problem until I get to working with non-basic types.

 

Last Edited: Tue. Mar 21, 2017 - 03:01 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

quilkin wrote:
I don't see why it should move halfway through the function but I'll go with that and see how I get on.
The compiler will tend to cache into registers variables it has immediate need to use but then move them out and other things into the working registers when those new items need fast access. Obviously the ultimate would be to try and keep everything in registers all the time but often there aren't enough for that. You will also find (optimised) code reordered where possible so all the actions on certain values are still performed while they are in registers 9assuming the program logic is maintained). That of course (in a debugger like AS7 leads to the "yellow arrow jumping around". If you are writing a debugger that can single step code you are going to see this too.

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

Oops, yes, thanks, edited my post before I saw your reply.

Since my debugger is aimed at inexperienced users, by default I'm calling for zero optimisation on the file that's being debugged. It'll waste program space but be less confusing to watch the single-step.

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

quilkin wrote:
by default I'm calling for zero optimisation on the file that's being debugged.
An atrocious idea. No one but no one should be encouraged to use the -O0 mode in GCC. It is only there as a test mode for the compiler developers so they can see code pre-optimisation. Almost the entire raison d'etre for using avr-gcc (an "optimising compiler") is lost if you use -O0 to run the main feature off.

 

What's more the code you now generate may not even work. suppose the user had used:

MCUSR = (1 << JTD);
MCUSR = (1 << JTD);

to switch off JTAG relying on the 4 cycle gate here (or maybe the CCP in Xmega?). You simply cannot get code to make those two writes in 4 cycles if you switch the optimiser off. So now they are going to spend days trying to work out why something that looks right in the C does not actually work in reality and your debugger is not going to help. In fact it insisting on -O0 is actually the cause!

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

In the case of switching JTAG off, just the act of single stepping will defeat the 4 cycle requirement...

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

clawson wrote:

An atrocious idea.

Hmmm. Maybe. That's interesting, thanks for the warning. I can easily change the optimisation level later; setting it to zero makes it easier for novice debugger developers as well!

This debugger is software-only, so users won't have JTAG devices. And AFAIK there aren't any Arduino boards (the target here) that use the Xmega devices. 

I could also parse the code to look for calls to CCP (or similar, if there are also concerns with short-cycle operations on atMega328 or 256 devices) to warn the user if such methods are being used (by a library routine; it's unlikely that my target audience will be using such constructs themselves because mostly they're very new to 'C' development).