Should custom uploader be invoked by debugger?

This will only be done if debug_load_cmds (docs) is set to preload.

PlatformIO’s default configuration is to start up the debug server (e.g., “openocd”), which gdb will establish a connection to, and then use the gdb load <path to elf> command to upload the firmware.

With the above config value set to preload, it will however first try to “upload” the firmware (until the upload process exits, by the way), then start the debug sever and connect to it via gdb.

Sure:

  1. Adding support for essentially debug_tool = xtensa-qemu should be done by modifying the platform code (espressif32 in this case) rather an extra script in a project. (This is of course fine for just a proof of concept). This use case is extremely close to other “emulator” / simulator already being used by PlatformIO, e.g., debug_tool = simavr to emulate AVR firmwares using SimAVR. See the relevant Python code for that here. Same goes for debug_tool = renode in e.g. the ststm32 platform. I would suggest forking pioarduino as a base for your modified platform (see below).
  2. Re “The GDB version that is installed for Platformio has a dependency on an older version of Python and does not play nice on newer operating system versions” in the repo: This may be true for the official platformio/platform-espressif32/ platform, but very likely not for pioarduino/platform-espressif32, which is essentially the “up-to-date” continuation of the official platform that supports Arduino-ESP32 3.x, newer boards and newer toolchains. You should check whether these versions still have the problem of the Python2 dependency. That would eliminate your qemu_gdb_override.py hack.
  3. The PoC assumes qemu-system-xtensa to be installed globally on the machine. That’s not how PlatformIO manages tool dependencies normally: You should compile the XTensa Qemu for the common operating systems (Windows x64, Linux x64, MacOS ARM64) and package them as a PlatformIO package (package.json) that can then be uploaded to the PlatformIO registry. That way, a modified espressif32 platform can easily take advantage of the new package, plus it automatically picks the one matching the host architecture. See here for an introduction to the platform internals.
  4. This line assumes the tool-esptoolpy tool used for the project is always at this path. Technically that is not always true, it could also e.g. be tool-esptoolpy@xx.yy.zz. You should be querying the platform for the path to the currently used tool-esptoolpy package. See here.