The data would be physically transferred through the only serial port available, that would at this point be used for programming, debugging and exchanging data between the Arduino code and the user's PC program.
I made you a drawing!
https://www.dropbox.com/s/3ulziiynjwn0xy8/2017-07-16%2017.22.41.jpg?dl=0When compiling code with "Debug" target, you change every debugger-injected code's Serial.write(...) to TransportLibrary.write(TYPE_DEBUG, ...) and every user program code's Serial.write(...) to TransportLibrary.write(TYPE_USER, ...). This function would encapsulate whatever payload it's given into an hypothetical transport header (see drawing) that would indicated whether the payload has originated from code that the user has written or code the debugger has generated.
At this point, on the computer side, the debugger is attached to the serial port, and receives the header and the payload. It de-encapsulates and demultiplexes i.e. if the header had TYPE_DEBUG it keeps the payload and processes it exactly as it does now and if it had TYPE_USER it prints it on the serial console/relays it, depending on the settings, exactly as it does now.
The same principles apply the other way: what's typed into the serial console or received by the "relay" serial port is encapsulated with TYPE_USER, what's written by the debugger for the injected code on the Arduino is encapsulated with TYPE_DEBUG, and on the Arduino Serial.read(...) calls are replaced by TransportLibrary.read(TYPE_whatever, ...) which de-encapsulates and demultiplexes Arduino's receive buffer into two separate debug & user buffers and returns the data from the right one depending on the TYPE parameter.