On Mon Feb 26 07:00:09 2024 +0000, Rémi Bernon wrote:
Gdb first looks for `DT_DEBUG` in the dynamic table, expecting to find the address of `_r_debug` there, but it's not set there until we write it ourselves. I couldn't find how to make the linker put `_r_debug` there, so then it falls back to looking for known rendez-vous symbols such as `_dl_debug_state`, and sets a breakpoint into it. If neither of this succeeds, Gdb bails out early and will never try again. If it does, it will later retry `DT_DEBUG` again, for instance when stopping the execution, and will find our `_r_debug` after we've set it. Then sure, I can probably call `_dl_debug_state` so it gets used. Note that I have found an issue still: Gdb doesn't seem to put breakpoints in every `_r_debug.r_brk`, only in `_dl_debug_state`. This means that although it is refreshed and you can see it in `info shared` list, debug symbols for entries in ld.so link_map don't get automatically loaded. They are only loaded when `_dl_debug_state` is called, and although we call it for the PE module updates, we then miss the unix .so updates. I don't see any other way to do that reliably for every .so than to hook `dlopen` and call `_dl_debug_state` there, like I was doing before (but we still don't actually need to mirror the link map).
Do you know if GDB not putting a breakpoints on extended `_r_debug` is intended or a bug? It's not clear to me; I guess that if it's meant for a single loader with multiple namespaces then a single `r_brk` is enough, but the way those structures are arranged suggests that multiple break points make sense.