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

    <tr>
        <th>Summary</th>
        <td>
            LLDB loses breakpoints across `run` on MacOS for externally-linked Go binaries
        </td>
    </tr>

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

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

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

<pre>
    Breakpoints set in a Go program prior to the initial `run` never trigger. Similarly if the program is running, any set breakpoints are lost (i.e., never fire, they are still listed in `breakpoint list`) across another `run`.

This seems to only apply to "externally-linked" Go binaries. By default, Go binaries are "internally-linked", meaning Go's linker does the full final linking of the binary. In some cases, most notably with applications using cgo (C FFI from Go), binaries are "externally-linked", meaning that we pass objects to the system linker to do the final link.

I have tested this with:

* Go 1.21.1
* `lldb -v`:
```
lldb-1400.0.38.13
Apple Swift version 5.7.1 (swiftlang-5.7.1.135.3 clang-1400.0.29.51)
```
* `ld -v`:
```
@(#)PROGRAM:ld  PROJECT:ld64-820.1
BUILD 18:42:34 Sep 11 2022
configured to support archs: armv6 armv7 armv7s arm64 arm64e arm64_32 i386 x86_64 x86_64h armv6m armv7k armv7m armv7em
LTO support using: LLVM version 14.0.0, (clang-1400.0.29.202) (static support for 29, runtime is 29)
TAPI support using: Apple TAPI version 14.0.0 (tapi-1400.0.11)
```
* MacOS 13.0

Apologies I have not tested this with HEAD LLVM, as I don't have a build environment set up on this MacOS dev machine, but I can get it set up if necessary.

# Reproducer

## Setup

If you don't have Go, you can fetch and extract a tar from https://go.dev/dl. The `go` binary below is at `./go/bin/go` in the tar.

```
$ mkdir /tmp/example
$ cd /tmp/example
$ go mod init example
$ cat > main.go <<EOF
package main

import "fmt"

func main() {
 fmt.Println("Hello World!")
}
EOF
```

## Working version ("internally-linked")

```
$ go build
$ lldb ./example
(lldb) target create "./example"
Current executable set to '/tmp/buildlet/lldb/example' (x86_64).
(lldb) breakpoint set -r main.main
Breakpoint 1: where = example`main.main, address = 0x0000000001086e00
(lldb) run
Process 9165 launched: '/tmp/buildlet/lldb/example' (x86_64)
Process 9165 stopped
* thread #1, stop reason = breakpoint 1.1
    frame #0: 0x0000000001086e00 example`main.main
example`main.main:
->  0x1086e00 <+0>: cmpq 0x10(%r14), %rsp
    0x1086e04 <+4>: jbe    0x1086e52                 ; <+82>
    0x1086e06 <+6>: pushq  %rbp
    0x1086e07 <+7>: movq   %rsp, %rbp
Target 0: (example) stopped.
```

(Note `breakpoint set -r` here. Simple `b main.main` doesn't properly find the `main.main` symbol for some reason. But that is not this bug.)

## Broken version ("externally-linked")

```
$ go build "-ldflags=-linkmode=external -v"
# example
HEADER = -H1 -T0x1001000 -R0x1000
host link: "clang" "-arch" "x86_64" "-m64" "-Wl,-headerpad,1144" "-Wl,-no_pie" "-o" "/var/folders/wh/9yc0j5w50z97w3528z_7qvr40000gn/T/go-build3740925102/b001/exe/a.out" "-Qunused-arguments" "/var/folders/wh/9yc0j5w50z97w3528z_7qvr40000gn/T/go-link-2866632490/go.o" "-lresolv" "-no-pie"
90105 symbols, 25881 reachable
        40055 package symbols, 34120 hashed symbols, 12116 non-package symbols, 3814 external symbols
92049 liveness data
```

Note: `-v` is not required, but it shows how we invoke `clang` for final link.

Note: Typically a user would end up with external linking automatically by using cgo. Invoking it directly keeps this repro simpler.

```
$ lldb ./example
(lldb) target create "./example"
Current executable set to '/tmp/buildlet/lldb/example' (x86_64).
(lldb) breakpoint set -r main.main
Breakpoint 1: where = example`main.main, address = 0x00000001000892c0
(lldb) run
Process 9215 launched: '/tmp/buildlet/lldb/example' (x86_64)
Hello World!
Process 9215 exited with status = 0 (0x00000000) 
```

The breakpoint never fired. Running `process launch --stop-at-start` and then setting the breakpoint is not sufficient either. What does work is waiting for the dynamic linker to finish loading and then set the breakpoint:

```
(lldb) b dyld`start
Breakpoint 2: where = dyld`start, address = 0x00007ff814000990
(lldb) run
Process 9225 launched: '/tmp/buildlet/lldb/example' (x86_64)
Process 9225 stopped
* thread #1, stop reason = breakpoint 2.1
    frame #0: 0x0000000100184990 dyld`start
dyld`start:
->  0x100184990 <+0>: pushq  %rbp
 0x100184991 <+1>: movq   %rsp, %rbp
    0x100184994 <+4>: pushq  %r15
 0x100184996 <+6>: pushq  %r14
Target 0: (example) stopped.
(lldb) disassemble
<snip long output>
<look for the `call *%r15` near the end of the function where `start` calls into the loaded application, and set a breakpoint there>
(lldb) b 0x10018530d
Breakpoint 3: where = dyld`start + 2429, address = 0x000000010018530d
(lldb) c
Process 9225 resuming
Process 9225 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 3.1
    frame #0: 0x00007ff81400130d dyld`start + 2429
dyld`start:
->  0x7ff81400130d <+2429>: callq  *%r15
    0x7ff814001310 <+2432>: movl   %eax, %ebx
 0x7ff814001312 <+2434>: movq   0x8(%r14), %rax
    0x7ff814001316 <+2438>: movl   0x44(%rax), %edi
Target 0: (example) stopped.
(lldb) breakpoint set -r main.main
Breakpoint 4: where = example`main.main, address = 0x00000001000892c0
(lldb) c
Process 9225 resuming
Process 9225 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 4.1
    frame #0: 0x00000001000892c0 example`main.main
example`main.main:
->  0x1000892c0 <+0>: cmpq 0x10(%r14), %rsp
    0x1000892c4 <+4>: jbe    0x100089312               ; <+82>
    0x1000892c6 <+6>: pushq  %rbp
    0x1000892c7 <+7>: movq %rsp, %rbp
Target 0: (example) stopped.
```

At this point if I run `run` again, none of the breakpoints will work except for the `dyld`start` breakpoint, and I will have to go through the same process. Even the explicit PC breakpoint at the end of `dyld`start` stops working, even though the PC does not change across runs (The Go PCs don't change either).

Clearly there is some difference in our internal vs external linking that is confusing lldb, but I'm not sure where it might be. In fact, I'm rather surprised that it is the internally-linked one that works and the externally-linked is broken. I would have expected the opposite.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzsWcty2ziXfhp4c0osEKQoaeGFL1HaU-mJJ_FMlimIhETEIMAAoCz9Tz91AFKiZMVJuvuvmsW4XJJI4Fxwrh8A7pzcaCGuyfSWTO-veOdrY69by71vZHm1MtX--tYK_twaqb0DJzxIDRzeG2it2VjeQGulseAN-FqA1NJLroAU1HaaFBS02AoL3srNRtgEPstGKm7VHuQ6UAxspAPbaS31hrA74HofhK1GwrkVoIzzQNhcJiLBeZH7WlqBT74W-zDNeakUKOm8qFBhUtAjp_CeFJSwBfDSGueAa-NrYY9qJ4TeE3oTP59qiUsXjcNlGq32wNtW7fGJMCZ2XljNldpPlNTPoiKMoYFWUnMrhUvgdg-VWPNOedRyNBSUJYxJ_ZoFTm0ER4vAe0PYzEEYs1AZ4YLt1p1SsJaaqzCEM020ahCwT-BBgzONgJI74QJHNKA2nq_UHl6kr8NSZMm9NNpB55BJucGFze9guXyAtTVNUGCB9OeaX1r8WHNfcw8vAlruHJjVN1F6NwSL2zsvmmFV3kAV3x9XdOKGB6j5VoAXwasenYILINnNeBZhN2jhNGFpkh5fkYIqVa1gskXPH0gK2v-HR5wxSXNKE5pk8yTN4uubtlUCPr_ItYetsE4aDdNklqRoJIevFdebSXiVpNk0yaAMb3pWbJFMU7TfJZmDctXbqpGcEjYnLCNs8fjp4_tPN3-S7EZVAI-fPv7Hu7un8FTkkzmjw7pv__vhwz2kc5Ld5IxkN1kOn0ULaQqMMhbnlEav5aazaFEDrmtbYz1wW9aOZDfAbbMtwucsfqLjmyKPnyJ-fc0YyGxewG5efC3y_quOxE2ke45f_ZNoovQPTx8PMkPoocwPH_7nz4Od0zyhCcWIImx-blVGGSYxesFzL8sDr7WxEOPVdtrLRmB5wRe9D55uHh9eC45-DmOn4lGC560cRKdvevNPXn78DGmW0HFc3rRGmQ1mTh_H2vhXsQx_vLu5DwYIRRDnVkYTNvORhsOqk6oCobfSGt0I7UOZ7FowOrKJ0iuxhYaXtdShMK46Dw9Qcg0brOAHIrkGLUrhHBaL0yzK4JNoram6UtizERz8LHzXnmTnGvamO1UXq8ZdeI2i18KXNXBdgdh5y0sPHDy3scDU3rcYcYQtCVtuTFKJLWHLSiXwVAvMkI3BdhILG6yEMi_oVO4hlGukIWy5kjr-LCjWfawmntvTpZ17LIfmuZIWCFv6piVsKXa8aZU4jpfVG4MbA42pQueD15SoX_YOGi51glU1uyPZ3buPyzil5eUz34gwPNZRNiEyCWPrxpMhV-PnutNlJMB6sAAyu40DsG588mil9iqOsT-EUga-GKsqwtJQmYewnd3HHwdVzs0ydvYXY0NzGbIicr_ctBY_sfXGxBg-vgl1OXlt2jkO4Ao9txi2pRXch6YznjwY566zFtNB7ETZYXsTIchDi54dvBdEK-EJW0buRz4zXFYsXYQtkldajAAEMp7Y6NSj645ACVIsJy-1wB6Z3R_CoqBHEszvqrLCuTCF7ujwl9J5ISh9pQAik_Du0RrMWVikxRQU73RZiwol_qWVXuDpvGlbUR1Lmq-t4JgEWYqK4zhYwR3GQnY_Ns2h6QIArC1v0GEZtrULS7xomEB9aWDojBNMKKC7gQnmFLulJHuHUsqm_R4GQ5BObZr3yAUfXHtUbmCQ9wzynsG3lRgNTxmc_5HstieZM6R5xbHoh4ueY9u5-jsEBVYXFJj102f99MZsvwMM-vaaD4RPMRdodPf84NPF4LTkzXSe_6fx4gwOx2jGiokBGyA69kGcNArxggbcGat7a00rEMSvpa5ClT3xVEHB7ZuVUaERBwAaoyWB285HTChd7IDYs1bdJjmvHLHy3FrzLPRZ4bmMOX-18GABmahqrfjGkew-sGhMJUh2PzBGKHYouiw7LevYot99CnE_-SOFyRP6kaaUUph8Cr97oTVCbeQefcUCesG9ASqACKv_PWRiHGiOP78owu4mteCVsC2vCLtL0_xsVJuvrRTDO9P_IGy55Zaw5dqoSlhH2PKlJmy52Jf02_RlSv-1mL1kUzb_19fZ963NMSc32DmfQvecBENls5wu2DRFkLVcUZqGGiIIW_LEdH6Q-V-d7pyoJtxuOgQk7h_SAS03YfOiKDKWL2hEBcMCJ8oKZ9R2eNRmEs0QTb-gKZ32MRi2PWw6n6cYhGWNreGYhPiXUzqdwtCLR1RZnjIKNXe1qMbvU5amBWijJ5eI5mkOh0gaBqJajOYLUHIrNNbainv-RrZiqobQKWjYGgwpY8X3TlqM-gjsEM7V5sVBbV5wqyX11jyHjIwRV9CQhj_YVQ1SnvatLDGngEPnhIUX0wWkWSFQDOD0sKhhs8k7bxoE3oFutT9uH3HnuTVhkvRQSStKr_bwLETrYs5bRJfgQq35KUD7f4gwhghYYuYLVv4KRGDpPwYRztDkazliJ3E3E2IFN2RdrzfyOjb_gFl_HPWI9kd2PB7wVAl8igdEGNptLziuDSYTbH8T7ifOc-sx5nnsTBpd4eNRxAnnPptct17LUoa4kL4WNoEv2J_CIcuLsc848YXLwALzCNlUe80bWY6OLtZSS1eDMrwKmTESfib4_LziPNqP0QTVXlWkoHFJ5wHETgPoZO7FyJmt13PcwNLF4pcih_3z4BJ5_g1wyX4BXGIvnueLBb1gvZM3r-HkQHgKKC-ht-PstJ-d_gp4G1BfJD0HniNB6fSVoDdAZZr_JjY8ur2SjjsnmkNPJNmd07IFZfQGTOfbzh8wLsnulDHPhyzADsOVAsJueqXDeS-Po9g5-tNI3LJ6xG99uA4uKCggAwdS90eCmD-iGp9JxtPgKiQSHwcD5qo46jbOm95q04xWr9Im-3HaAGG3wPK4XfhR5R2zHQktL0S6Fa5rpN78hST43okuKkjYrDRNghYRoS1M4tSQjm9mS_azbBkKQprR6geG-HnanDCJIRoo-90YVypE6c1JWMMpZUoPlBk7JpKKiST4rk8ksdod8mJEzY7U-Wka0t380jaQ736gR3HkND_Vg-4Qec976gMrUcm_nHu_gxbyfwda-D8Ys_mvVfi4oL97fDCw-RsHCJHFG0cIOAEj9DeOECLP3zhEiAQXjxH-DYcIN_2mvUdRa3hA8DC68eObPhy10eJwITW6yHuRSkVoJXalaP24oZzUmoKOcVPfCB4ifbwLMrit97U13aaOd0oYMj04TODdVsRDYLHDhiI9PN6Nw437cau6IB7tEWFgfzEpIseDvMe7iBQRSpY11xsx3CnaTju0LgLa9wYe79zhcLyfGPHmaCcRdylKhPvR0N8QfIbzk0qu18IKXeL-DkxnYTh-ha17vTMbjlhKo9dxUxaTvr8KIGzW9OjXir6uSA-N3NQeViLcG655GWweJ1seLkhdZ1srXbiz4GHrKV1_8Xt2JgPo_Hj7Z-yzGxAxvDq8QQ6rcMyToG_DrjM4V-xaUcbrEQGmbY2TXiRX1XVWLbIFvxLXabHI82I2K9hVfZ2xeVWK1YzO86pMMzZfLDhls3RRrjKW0dWVvGaUZXSRpixlC8aSbJ4Xi4JOBZuV-TwTJKei4VIlSm2bxNjNlXSuE9dFQdPsSvGVUG64KrfXOGmy6jaO5FRJ592RzEuvxPWHD_e3oIwT7vQaO4bHMV-M7i9tMA1em2d0XXzVWXV9dlMifd2tktI0AYtvh69Ja803gR5chkU4wpZhHf8bAAD__y9xd1I">