<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/115067>115067</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            [BOLT] Debug frame information in .debug_frame section is not updated after bolt optimization
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            BOLT
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          johndoe2012
      </td>
    </tr>
</table>

<pre>
    ### Debug frame information in `.debug_frame` section is not updated after bolt optimization

#### Problem
DWARF call frame information (CFI) may be populated inside the `.debug_frame` section instead of the `.eh_frame` section, for example when a binary is compiled with the `--fno-unwind-tables` flag. When bolt rewrites the binary, the CFIs inside `.debug_frame` are not updated accordingly, thus the pc range they correspond to are now random. When using gdb to unwind a backtrace the presence of stale CFIs will generate wrong frames that fails a gdb backtrace sanity check resulting in truncated or invalid backtraces. On the other hand, CFIs populated inside `eh_frame` section are updated as expected after bolting. The rest of `.debug_*` sections are updated correctly in both cases.
#### Analysis
When looking into the code, we can follow where bolt updates the CFIs in `eh_frame`.
```cpp
RewriteInstance::run() -> RewriteInstance::rewriteFile() -> RewriteInstance::writeEHFrameHeader() -> CFIRdWrt->generateEHFrameHeader()
```

However in file `DWARFRewriter.cpp`, where logically bolt updating `.debug_*` sections should be implemented, we couldn't find similar handling of CFI/FDE in `.debug_frame`. `DWARFRewriter::finalizeDebugSections` contains a list of sections bolt updates, and `.debug_frame` is not included. Further search of the entire code base couldn't find bolt updating `.debug_frame` as well.

So, we’ve concluded that updating information inside `.debug_frame` is not yet implemented.
#### Discussion
The lack of support for updating `.debug_frame` section will impact a wide range of applications from adopting bolt. Keeping debug frame information out of `.eh_frame` and in `.debug_frame` is a valid approach for minimizing production binary size. With this approach, users can still debug offline with the full binary, while using the stripped binary in production. For example, the explicit default behavior of the musl library is to disable debug information in `.eh_frame` (debate on the reasoning is in [https://www.openwall.com/lists/musl/2021/07/17/11](https://www.openwall.com/lists/musl/2021/07/17/11)).

Our asks are:  
- please confirm the issue is valid that we are not misunderstanding the problem.
- is there a plan to add support for updating `.debug_frame` after bolt rewriting?
#### Reproducing incorrect debug frame in hello world
The issue is reproducible on x86 as well as aarch64. tested with gcc version 7.3.1 and 13.3.0. llvm 19.x. 

Detail reproducing steps:
- compile hello.c without debug in eh_frame
```bash
$ gcc -o hello hello.c -Wl,--emit-relocs -g -fno-asynchronous-unwind-tables -fno-unwind-tables
```
- note down main function address range
```bash
$ gdb -batch -ex 'file hello' -ex 'disassemble main' | head -2
Dump of assembler code for function main:
   0x00000000004004c7 <+0>:     push   %rbp
```
- verify main function cfi is inside .debug_frame section
```bash
$ objdump -Wf hello > hello.debug.frame
$ grep -E "(\.eh_frame|\.debug_frame|pc=00000000004004c7)" hello.debug.frame
Contents of the .eh_frame section:
Contents of the .debug_frame section:
00000018 0000000000000024 00000000 FDE cie=00000000 pc=00000000004004c7..00000000004004dc
```
- apply bolt optimization to binary
```bash
$ llvm-bolt hello -o hello.bolted --funcs main --update-debug-sections
```
- verify the new address of main function
```bash
$ gdb -batch -ex 'file hello.bolted' -ex 'disassemble main' | head -2
Dump of assembler code for function main:
   0x0000000000a00000 <+0>:     push   %rbp
```
- verify CFI information of new bolted binary. observe it is still with stale address before applying bolt. 
```bash
$ objdump -Wf hello.bolted > hello.bolted.debug.frame
$ grep -E "(\.eh_frame|\.debug_frame|pc=0000000000a00000)" hello.bolted.debug.frame
Contents of the .eh_frame section:
Contents of the .debug_frame section:

# look inside hello.bolted.debug.frame, cfi is not updated
Contents of the .debug_frame section:

00000000 0000000000000014 ffffffff CIE
  Version:               1
  Augmentation:          ""
  Code alignment factor: 1
  Data alignment factor: -8
  Return address column: 16

  DW_CFA_def_cfa: r7 (rsp) ofs 8
  DW_CFA_offset: r16 (rip) at cfa-8
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop

00000018 0000000000000024 00000000 FDE cie=00000000 pc=00000000004004c7..00000000004004dc
  DW_CFA_advance_loc: 1 to 00000000004004c8
  DW_CFA_def_cfa_offset: 16
  DW_CFA_offset: r6 (rbp) at cfa-16
  DW_CFA_advance_loc: 3 to 00000000004004cb
  DW_CFA_def_cfa_register: r6 (rbp)
  DW_CFA_advance_loc: 16 to 00000000004004db
  DW_CFA_def_cfa: r7 (rsp) ofs 8
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
```
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJy8WF1v6zbS_jXKzUCCTH9f5CLHjtHgfYEuTovN5QFFjiz2UKRAUnHcX78YUvJH4qTddk-NwIGl0Xw8M_PMUNx7tTeI99n8Szbf3vE-NNbd_2YbIy2ycsLuKiuP9xmbpj_YYtXvoXa8RVCmtq7lQVkDykC2KAtJt7_F29miBI8i3fVgbIC-kzygBF4HdFBZHcB2QbXq96gkK7dZ-TB8jxbJ6L-crTS26c72-eHrDgTX-oYbGVttdk8ZW0PLj1AhdLbrdTSqjFcSITT4qafGB-QSbH2SxOadWMY2UFsH-MrbTiMcGjTAoVKGuyNFK2zbKY0SDio0o6Y8r43Ne3NQRuaBVxo96aw13xfwTCoiJA4PTgX08bGkkuzRr83uyY-B3AiCO7zGWQjrpDJ7PWjok9JOgONmH8E4grDOoe-skRDsoONAAtK2g1-9V2YPe1mRRAqAwuXie3BcJFA7hx6NQILOB64Hbw9Ka9ijQccDwsFZM5QPucID1FxpDzwqPyv03KhwBNGg-A4Ofa8DeaAMBNcbEaOzDpR54VrJ84O-gJ9NdMeGBh003EgKPbryrhayRXkjuRGCE4Qe8LVDcV22yuwL-LVBci1QwOdkZOzhQpe_UhaRFkEfKZDKhgYE9-iLGyX_YLg-euXTrZgEbe33BEKwMURhJVJwBwTBDdRWa3ugWnSYKinZ9Zel8ybm0fSiTH-i69KVr6kIn4wP3AjMpg_Z9MH1JmMr6q48mz7CbZl0cac0_qFsvPT4046c-Qm5RHf5yGb39FU-u0A_xgK6IfwmgksS-cke8AWpTKBWOuY7ssfgjCso3EUZMYyoabtXxCzHC_wI8o_T6xvba0lMo4gJWjQB5ZgUumUytgxQU8d41SrNU1FqUmtriGy1220fbzNo8c7nhFytDNfqd4x0_MvgDDkmrAlcUd2BVqk2T75e1gS5yI28xSIDWSsjdC9RFrDrXWwmj9yJZqRGNEG5VIRQcf8-3I8gPNOVhwNqXVym7BebwMseWbYqs_X6hRQPriTGOKm8nj8fkeIQzhHDZYpu9dxWedF7f5pE1OCai-8RxL7rrAuR9T-LaeSQSHuq7bgIwOFAviXKtTXwrtNK8JSU2tkWuKQ5aPYRswL-D7GjX_KDYWv7E-lc8hfl8_YcVlQPiSp51znLRRMjaZWh6Uu2Omdln3wfxphXv2MBz2mAkYbhSUpQ79H5yDo-UKTJU1vXWhk8D7261_pihB0a6sI0TOi2D051HcrT4DQXbhSwO0_YcQDiK0GnAkisea8DVNjwF2XdWJVt7zVoVblhEAcLUnmatYOPN5aWSwwztpJY0aiyaY445N6aWG6JP-dfmhA6T33IdhnbHQ6HwnZoDlzrQtg2YzvqPJ-xHTmTsR0r2SRju3KZsd0kfk2y-TZjq_-FIrbO2PqqhX7uHXD_PY6ebPoAkC7n0GlMfWpq5doYnfK-p--hOGJ_HfC0SLTK90aiI9KWY9a6tI0Vo1oVB4xD4NBpbuISIeWf7piLZTDNDmX22XR3oz-_YqqO1PvDMH3TJNCg1hYO1ml57uJTmG5UQQVhDbyuFiMN0X9OBLeYFRDQh3F72wsBL-iIF2BZTItJbLTJtJgWZQFav7QwWRevBVwmYYuBK322Z_bgA6ZsD7gNO2LyuBDRGHX2WKdwqsvrCVdx34zozKJ3uR3CHlXlzzpjmzzHVoXcobbCQ76HuH9yfzSicdbY3l8vo3BjP701XHOqDQRpDwZaTsO1N8PmJKVD7xPVfe62rCCveBAN5PgKGVvWJywythwvUu96jy2li0zRrWy5gYZ29JwNWPdtF3l1kHRpKFHhnTyLD4_YA0D5Wp4-s7KciSVk003GvpTZ9DF2DQB0vW8AIGNzV3UfQPGCTtXHNziIWiW6iEPpsuJPJ4jPwLHVb5Jiyp_rIbG0D6XkRl3FZV0Qmg47yB8hY4yWovnmzGnLDf287LnlphPZdPs2_sgk7CMrG2sCmuBHnj0ZOAU0gvtO8lb0o3ByYLKC8urDZqcLQLuRUHjhMdz0vyiur0jxQcZo_B7fnz6Jt4ZR9VluqN_z-HDKzNh7BV1DCXlOVeBTQeR5WrfyiEE-bmKflxKBZvBwaiZbX1fXX-6rwcV_ur14Strfaq_N7ul6A6ojRAPmKW0F2Mqje0FQgbovbSaRwtN5dAS0wtrSuKI6OC9d_11Hjuk-N2a68CP6MwF41Z8fGftBbXoaxvEQOvLah66wzciAF28j_rLZU9tfc8RkBvXwgc3T41h6_06Teqyx82cySjz0ezoD8PBWLGaHjWIbKnKu1d6QNNRcBEunr7OiLQ_8pkS-GkW-YujdeS4Kq_s2Gp0sLkME2D5_2-wevkmsv4mak4Rb0jLqfEcHYlt7WL2RtXXtMUTRySLKqijLA4ia52_Fje1-9JV_jNNPprl84UbgN21FRJVI_I2StzgMEF_AN-biFrIJ2OoS2Hfib5yY3nCi-sAJh3vl06n-ytYfhLl4b0J-YOJPldLfzftImnfyfirX0zW_w_vJclquZuVkurpr7sspW5VY83qKlShnKzljU2TLtazWc1xNFnfqnpVsNpmUc1bO59NVwadyzdaL2WyJK7ESmM1KbLnSBQ3gwrr9XVzq7yeTeblY3mleofbxPTZjX37-_1-pk-fbO3efBna_99msjOeps4aggo7vvuMD8-1nb7dvEdWffK991zt9f33W26vQ9NV4ytMv47-8c_Y3FCFjuxiej4e8GOHLPftPAAAA__-xkXVU">