[fpc-devel] Overlapping addresses between 2 procedures in dwarf info / 3.2.0

Martin Frb lazarus at mfriebe.de
Sat Dec 25 14:44:48 CET 2021


I am looking at some oddity I found following up 
https://forum.lazarus.freepascal.org/index.php/topic,57568.0.html

Unfortunately, I have no code yet to reproduce it.
I have looked at the generated debug info, as given by objdump.

file format pei-x86-64
   Compilation Unit @ offset 0x0:
    Length:        0xa1 (32-bit)
    Version:       2
    Abbrev Offset: 0x0
    Pointer Size:  8
  <0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
     <18>   DW_AT_producer    : Free Pascal 3.2.0 2021/02/21

The following part of the info looks wrong to me (original names replaced):

  <1><cef4f>: Abbrev Number: 8 (DW_TAG_subprogram)
     <cef50>   DW_AT_name        : FOO
     <cef60>   DW_AT_prototyped  : 1
     <cef61>   DW_AT_calling_convention: 65    (user defined)
     <cef62>   DW_AT_external    : 1
     <cef63>   DW_AT_low_pc      : 0x10004a990
     <cef6b>   DW_AT_high_pc     : 0x10004adc4 <<<<<<<<<<<<< NOTE THE 
END ADDR

  <1><cefa8>: Abbrev Number: 9 (DW_TAG_subprogram)
     <cefa9>   DW_AT_name        : fin$000000B0
     <cefb6>   DW_AT_prototyped  : 1
     <cefb7>   DW_AT_calling_convention: 65    (user defined)
     <cefb8>   DW_AT_low_pc      : 0x10004a950
     <cefc0>   DW_AT_high_pc     : 0x10004a988

  <1><cefda>: Abbrev Number: 8 (DW_TAG_subprogram)
     <cefdb>   DW_AT_name        : XYZ
     <cefee>   DW_AT_low_pc      : 0x0 <<<<<<<<<<<<<  code not included, 
not used/called
     <ceff6>   DW_AT_high_pc     : 0x0

  <1><cf040>: Abbrev Number: 6 (DW_TAG_subprogram)
... Several other DW_TAG_subprogram, with address BEFORE FOO, and (as 
far as I checked also line-numbers before FOO.
... I guess those are included here, because they did not get called 
before, and the compiler adds the debug info only now ???
... Or could there be other reasons for the out-of-order inclusion???

  <1><cf812>: Abbrev Number: 8 (DW_TAG_subprogram)
     <cf813>   DW_AT_name        : BAR
     <cf822>   DW_AT_prototyped  : 1
     <cf823>   DW_AT_calling_convention: 65    (user defined)
     <cf824>   DW_AT_external    : 1
     <cf825>   DW_AT_low_pc      : 0x10004adb0 <<<<<<<<<<<<< NOTE THE 
START ADDR
     <cf82d>   DW_AT_high_pc     : 0x10004ae26

BAR starts within FOO. That seems wrong? (also see the line info below)
 From the code samples I received from the author, this is NOT a nested 
proc.

This (and the line-info) leads to a crash of the app, when run under 
gdb, as gdb adjusts the position of breakpoints, and ends setting it 
into the middle of an asm instruction.

According to the author, the crash only happens if there are no calls to 
XYZ. Otherwise the crash does not happen. I do not have info (yet), if 
the overlapping addresses are present or not, if XYZ is used.
The inclusion/exclusion of XYZ triggers 
https://gitlab.com/freepascal.org/fpc/source/-/issues/38117  which can 
be seen in the line-info of this app too (i.e. line info contains none 
relocated entries that compute to invalid addresses for those lines).



** The line-info of "FOO"
   [0x00011cee]  Extended opcode 2: set Address to 0x10004a990
   [0x00011cf9]  Set column to 1
   [0x00011cfb]  Advance Line by 2452 to 2453
   [0x00011cfe]  Copy
   [0x00011cff]  Advance PC by 37 to 0x10004a9b5
   [0x00011d01]  Copy
....
   [0x00011d5b]  Advance Line by -2 to 2453
   [0x00011d5d]  Copy
   [0x00011d5e]  Advance PC by 9 to 0x10004ad95
   [0x00011d60]  Special opcode 22: advance Address by 0 to 0x10004ad95 
and Line by 23 to 2476
   [0x00011d61]  Extended opcode 2: set Address to 0x10004adc4
   [0x00011d6c]  Extended opcode 1: End of Sequence

It advances all the way to line 2476 / 0x10004ad95
Then it goes to address 0x10004adc4 (before  "End of Sequence")
This is inside of "BAR".

** The line info shows that the next line (2484) is within the "not 
included / not called" proc XYZ
   [0x00011d6f]  Extended opcode 2: set Address to 0x0
   [0x00011d7a]  Set column to 1
   [0x00011d7c]  Advance Line by 2483 to 2484
   [0x00011d7f]  Copy
   [0x00011d80]  Advance PC by 13 to 0xd


** The line-info of "BAR"
     This continues from the line-info of XYZ (as seen by the none 
relocated entries)

   [0x00011db8]  Special opcode 9: advance Address by 0 to 0x12c and 
Line by 10 to 2500
....
   [0x00011dc2]  Special opcode 0: advance Address by 0 to 0x17c and 
Line by 1 to 2504
   [0x00011dc3]  Advance PC by 80 to 0x1cc
   [0x00011dc5]  Set column to 1
   [0x00011dc7]  Special opcode 12: advance Address by 0 to 0x1cc and 
Line by 13 to 2517
   [0x00011dc8]  Extended opcode 2: set Address to 0x0
   [0x00011dd3]  Extended opcode 1: End of Sequence

** BAR
   [0x00011dd6]  Extended opcode 2: set Address to 0x10004adb0
   [0x00011de1]  Set column to 1
   [0x00011de3]  Advance Line by 2521 to 2522
   [0x00011de6]  Copy
   [0x00011de7]  Advance PC by 21 to 0x10004adc5
   [0x00011de9]  Set column to 3
   [0x00011deb]  Special opcode 0: advance Address by 0 to 0x10004adc5 
and Line by 1 to 2523

BAR starts at line 2522 (confirmed by the author).
The address 0x10004adb0  could be correct, as procs should afaik start 
at 16 byte boundaries?

Line 2522 at 0x10004adb0 is an entry in the line info table, made by the 
"copy" statement.

-----------------
So in conclusion something is wrong there.

As for the GDB crash (2500 is in the dead code, and gdb searches the 
next line with code, which we know to be 2522 in BAR):
<info line "code1.pas":2500>
~"Line 2500 of \"code1.pas\" is at address 0x10004adb0 <FOO> but 
contains no code.\n"

GDB found the line, after that I don't know what GDB did exactly
- line 2500 is in XYZ and gdb must have seen the address is not correct, 
and ignored it.
- then probably it went to the last good line, and that is the "End of 
Sequence"
    => which would explain "no code"
    => and explain the address found when setting the break

Setting a breakpoint:
<-break-insert "code1.pas:2500">
^done,bkpt={number="37",type="breakpoint",disp="keep",enabled="y",addr="0x000000010004adc4",func="FOO",file="code1.pas",line="2500",times="0",original-location="code1.pas:2500"}

The address 0x000000010004adc4 is indeed from the "End of Sequence" for 
"BAR"

However, if that address is not in BAR (and if BAR ends long before), 
then this is
- the address 1 byte before line 2523
- or the address $14 bytes into line 2522 (the last byte of asm code of 
that line).
In that case, it is possible that this is not the start of an 
asm-instruction, but in the middle of one, and then the app would crash, 
after running the modified code (by having $CC somewhere in the operand 
part of an asm instruction).

---------------
---------------
In any case, if the initial part of my analysis is correct then fpc 
wrote incorrect address to the dwarf info (both the high/low_pc, and the 
"End of Sequence").

Ideally we need a reproducible example.
But in order to get this, any idea what we are looking at, and therefore 
how to strip the original code, so we can get such an example would be 
helpful.

Any comments / ideas?

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freepascal.org/pipermail/fpc-devel/attachments/20211225/dee0cf9c/attachment.htm>


More information about the fpc-devel mailing list