Opened 10 years ago

Closed 10 years ago

#10459 closed bug (no change required)

[Debugger] Investigate anomalous single stepping behavior

Reported by: anevilyak Owned by: anevilyak
Priority: normal Milestone: R1
Component: Applications/Debugger Version: R1/Development
Keywords: Cc: stippi
Blocked By: Blocking:
Platform: All

Description

In certain instances, some unusual single stepping behavior can be observed, as seen in the attached example program. If one steps through the program until hitting line 19, the next single step would be expected to jump to either the closing scope line of the current block (line 22), or the closing line of the function (line 25).

With gcc2, the latter is observed as expected. With gcc4 however, the next step unexpectedly takes us to line 21 instead. There are some differences in the generated line number programs between the two compilers, but at least a cursory glance through our state machine implementation doesn't reveal any obvious problems in handling the involved opcodes. It should further be noted that this behavior is only observed when the locally scoped object is declared at line 15 ; without it, behavior similar to gcc2 is observed.

Needs further investigation, and probably some additional tracing output to allow us to better compare our state machine execution with the corresponding output of objdump for the line number program in question. One possible candidate that gcc4 emits that gcc2 does not is the discriminator, but the DWARF specification is quite vague on how to actually make use of that apart from simply parsing the corresponding instruction/value.

Objdump output for gcc2:

Raw dump of debug contents of section .debug_line:

  Offset:                      0x0
  Length:                      252
  DWARF Version:               2
  Prologue Length:             46
  Minimum Instruction Length:  4
  Initial value of 'is_stmt':  1
  Line Base:                   -10
  Line Range:                  245
  Opcode Base:                 10

 Opcodes:
  Opcode 1 has 0 args
  Opcode 2 has 1 args
  Opcode 3 has 1 args
  Opcode 4 has 1 args
  Opcode 5 has 1 args
  Opcode 6 has 0 args
  Opcode 7 has 0 args
  Opcode 8 has 0 args
  Opcode 9 has 1 args

 The Directory Table is empty.

 The File Name Table:
  Entry Dir     Time    Size    Name
  1     0       0       0       steptest.cpp
  2     0       0       0       <internal>

 Line Number Statements:
  Extended opcode 2: set Address to 0xa30
  Special opcode 20: advance Address by 0 to 0xa30 and Line by 10 to 11
  Extended opcode 2: set Address to 0xa43
  Special opcode 11: advance Address by 0 to 0xa43 and Line by 1 to 12
  Extended opcode 2: set Address to 0xa4a
  Special opcode 11: advance Address by 0 to 0xa4a and Line by 1 to 13
  Extended opcode 2: set Address to 0xa4a
  Special opcode 11: advance Address by 0 to 0xa4a and Line by 1 to 14
  Extended opcode 2: set Address to 0xa4a
  Special opcode 11: advance Address by 0 to 0xa4a and Line by 1 to 15
  Extended opcode 2: set Address to 0xa59
  Special opcode 11: advance Address by 0 to 0xa59 and Line by 1 to 16
  Extended opcode 2: set Address to 0xa5f
  Special opcode 11: advance Address by 0 to 0xa5f and Line by 1 to 17
  Extended opcode 2: set Address to 0xa80
  Special opcode 11: advance Address by 0 to 0xa80 and Line by 1 to 18
  Extended opcode 2: set Address to 0xa89
  Special opcode 11: advance Address by 0 to 0xa89 and Line by 1 to 19
  Extended opcode 2: set Address to 0xaa6
  Special opcode 11: advance Address by 0 to 0xaa6 and Line by 1 to 20
  Extended opcode 2: set Address to 0xaaf
  Special opcode 11: advance Address by 0 to 0xaaf and Line by 1 to 21
  Extended opcode 2: set Address to 0xae8
  Special opcode 13: advance Address by 0 to 0xae8 and Line by 3 to 24
  Extended opcode 2: set Address to 0xb63
  Special opcode 11: advance Address by 0 to 0xb63 and Line by 1 to 25
  Extended opcode 2: set Address to 0xb6c
  Special opcode 14: advance Address by 0 to 0xb6c and Line by 4 to 29
  Extended opcode 2: set Address to 0xb7f
  Special opcode 11: advance Address by 0 to 0xb7f and Line by 1 to 30
  Extended opcode 2: set Address to 0xb84
  Special opcode 12: advance Address by 0 to 0xb84 and Line by 2 to 32
  Extended opcode 2: set Address to 0xb8c
  Special opcode 11: advance Address by 0 to 0xb8c and Line by 1 to 33
  Extended opcode 2: set Address to 0xb97
  Extended opcode 1: End of Sequence

  Extended opcode 2: set Address to 0xb98
  Special opcode 12: advance Address by 0 to 0xb98 and Line by 2 to 3
  Extended opcode 2: set Address to 0xbc7
  Extended opcode 1: End of Sequence

  Extended opcode 2: set Address to 0xbd0
  Special opcode 13: advance Address by 0 to 0xbd0 and Line by 3 to 4
  Extended opcode 2: set Address to 0xc1d
  Extended opcode 1: End of Sequence

  Extended opcode 2: set Address to 0xc20
  Special opcode 42: advance Address by 0 to 0xc20 and Line by 32 to 33
  Extended opcode 2: set Address to 0xc6c
  Extended opcode 1: End of Sequence

Objdump output for gcc4:

Raw dump of debug contents of section .debug_line:

  Offset:                      0x0
  Length:                      127
  DWARF Version:               2
  Prologue Length:             35
  Minimum Instruction Length:  1
  Initial value of 'is_stmt':  1
  Line Base:                   -5
  Line Range:                  14
  Opcode Base:                 13

 Opcodes:
  Opcode 1 has 0 args
  Opcode 2 has 1 args
  Opcode 3 has 1 args
  Opcode 4 has 1 args
  Opcode 5 has 1 args
  Opcode 6 has 0 args
  Opcode 7 has 0 args
  Opcode 8 has 0 args
  Opcode 9 has 1 args
  Opcode 10 has 0 args
  Opcode 11 has 0 args
  Opcode 12 has 1 args

 The Directory Table is empty.

 The File Name Table:
  Entry Dir     Time    Size    Name
  1     0       0       0       steptest.cpp

 Line Number Statements:
  Extended opcode 2: set Address to 0x952
  Special opcode 7: advance Address by 0 to 0x952 and Line by 2 to 3
  Special opcode 201: advance Address by 14 to 0x960 and Line by 0 to 3
  Advance PC by 26 to 0x97a
  Extended opcode 1: End of Sequence

  Extended opcode 2: set Address to 0x97a
  Special opcode 8: advance Address by 0 to 0x97a and Line by 3 to 4
  Advance PC by constant 17 to 0x98b
  Special opcode 19: advance Address by 1 to 0x98c and Line by 0 to 4
  Extended opcode 4: set Discriminator to 1
  Set is_stmt to 0
  Advance PC by 36 to 0x9b0
  Special opcode 5: advance Address by 0 to 0x9b0 and Line by 0 to 4
  Special opcode 201: advance Address by 14 to 0x9be and Line by 0 to 4
  Advance PC by 5 to 0x9c3
  Extended opcode 1: End of Sequence

  Extended opcode 2: set Address to 0x9c4
  Special opcode 8: advance Address by 0 to 0x9c4 and Line by 3 to 4
  Advance PC by constant 17 to 0x9d5
  Special opcode 19: advance Address by 1 to 0x9d6 and Line by 0 to 4
  Advance PC by 33 to 0x9f7
  Extended opcode 1: End of Sequence

  Extended opcode 2: set Address to 0x898
  Advance Line by 10 to 11
  Copy
  Advance PC by constant 17 to 0x8a9
  Special opcode 48: advance Address by 3 to 0x8ac and Line by 1 to 12
  Special opcode 106: advance Address by 7 to 0x8b3 and Line by 3 to 15
  Special opcode 216: advance Address by 15 to 0x8c2 and Line by 1 to 16
  Special opcode 90: advance Address by 6 to 0x8c8 and Line by 1 to 17
  Special opcode 174: advance Address by 12 to 0x8d4 and Line by 1 to 18
  Special opcode 132: advance Address by 9 to 0x8dd and Line by 1 to 19
  Special opcode 174: advance Address by 12 to 0x8e9 and Line by 1 to 20
  Special opcode 132: advance Address by 9 to 0x8f2 and Line by 1 to 21
  Advance PC by 37 to 0x917
  Special opcode 8: advance Address by 0 to 0x917 and Line by 3 to 24
  Special opcode 104: advance Address by 7 to 0x91e and Line by 1 to 25
  Special opcode 121: advance Address by 8 to 0x926 and Line by 4 to 29
  Advance PC by constant 17 to 0x937
  Special opcode 132: advance Address by 9 to 0x940 and Line by 1 to 30
  Special opcode 77: advance Address by 5 to 0x945 and Line by 2 to 32
  Special opcode 76: advance Address by 5 to 0x94a and Line by 1 to 33
  Advance PC by 7 to 0x951
  Extended opcode 1: End of Sequence

Attachments (2)

steptest.cpp (308 bytes ) - added by anevilyak 10 years ago.
Test program that reproduces the described problem.
steptest.disassembled (19.2 KB ) - added by anevilyak 10 years ago.
objdump -d output

Download all attachments as: .zip

Change History (7)

by anevilyak, 10 years ago

Attachment: steptest.cpp added

Test program that reproduces the described problem.

comment:1 by bonefish, 10 years ago

Can you attach the disassembly for the program? It is possible that in the code gcc generates some function exits share instructions (other than the epilogue).

by anevilyak, 10 years ago

Attachment: steptest.disassembled added

objdump -d output

in reply to:  1 comment:2 by anevilyak, 10 years ago

Replying to bonefish:

It is possible that in the code gcc generates some function exits share instructions (other than the epilogue).

Disassembly attached. If that's indeed the case, then that perfectly explains the presence of the aforementioned discriminator command, as its intended purpose is precisely to differentiate multiple source lines overlapping the same instruction address. The problem I have is simply that from the specification, it's not obvious how to actually determine which of said lines is the correct one while stepping, as no other reference is made to it beyond the line number program section (c.f. http://dwarfstd.org/doc/DWARF4.pdf section 6.2).

comment:3 by bonefish, 10 years ago

The three cases do use the same exit code:

318	 8c2:   83 7d e4 05             cmpl   $0x5,-0x1c(%ebp)
319	 8c6:   75 0c                   jne    8d4 <_Z1av+0x3c>
320	 8c8:   be 03 00 00 00          mov    $0x3,%esi
321	 8cd:   bf 00 00 00 00          mov    $0x0,%edi
322	 8d2:   eb 2f                   jmp    903 <_Z1av+0x6b>

323	 8d4:   81 7d e4 ef cd ab 00    cmpl   $0xabcdef,-0x1c(%ebp)
324	 8db:   75 0c                   jne    8e9 <_Z1av+0x51>
325	 8dd:   be 0c 00 00 00          mov    $0xc,%esi
326	 8e2:   bf 00 00 00 00          mov    $0x0,%edi
327	 8e7:   eb 1a                   jmp    903 <_Z1av+0x6b>

328	 8e9:   81 7d e4 e0 2e 00 00    cmpl   $0x2ee0,-0x1c(%ebp)
329	 8f0:   75 0c                   jne    8fe <_Z1av+0x66>
330	 8f2:   be 05 00 00 00          mov    $0x5,%esi
331	 8f7:   bf 00 00 00 00          mov    $0x0,%edi
332	 8fc:   eb 05                   jmp    903 <_Z1av+0x6b>

It's really just for the destruction of myA and the epilogue, though:

334	 903:   83 ec 0c                sub    $0xc,%esp
335	 906:   8d 45 dc                lea    -0x24(%ebp),%eax
336	 909:   50                      push   %eax
337	 90a:   e8 51 fd ff ff          call   660 <_ZN1AD1Ev@plt>
338	 90f:   83 c4 10                add    $0x10,%esp
339	 912:   83 ff 01                cmp    $0x1,%edi
340	 915:   75 05                   jne    91c <_Z1av+0x84>
341	 917:   be 11 00 00 00          mov    $0x11,%esi
342	 91c:   89 f0                   mov    %esi,%eax
343	 91e:   8d 65 f4                lea    -0xc(%ebp),%esp
344	 921:   5b                      pop    %ebx
345	 922:   5e                      pop    %esi
346	 923:   5f                      pop    %edi
347	 924:   5d                      pop    %ebp
348	 925:   c3                      ret

I haven't checked how the addresses match up with the line number info.

in reply to:  3 comment:4 by anevilyak, 10 years ago

Replying to bonefish:

The three cases do use the same exit code: [...] It's really just for the destruction of myA and the epilogue, though:

That's more or less what I expected, what's odd to me is simply that said exit code is being computed as matching the address of the third return statement rather than the closing brace. That could simply be a quirk of gcc that we can't do anything about though, but I want to verify the line number program to be sure, as that behavior is a bit confusing.

comment:5 by anevilyak, 10 years ago

Resolution: no change required
Status: newclosed

After digging a bit further, I'm forced to conclude that this is indeed simply a quirk of the line number program in question. Both objdump and our state machine agree that line 21 (aka "return 5") spans range 0x8f2-0x917, unrelocated. As you pointed out, 0x903 is the starting point of the object destructor + epilogue, aka in the middle of the aforementioned statement, and that is in fact precisely the address we wind up at after stepping over line 19. So yes, gcc has condensed that last return + destructor/epilogue into a single statement for debugging purposes, and there's unfortunately nothing we can really do to simplify the confusion there.

Note: See TracTickets for help on using tickets.