Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GDB support #618

Closed
dirkwhoffmann opened this issue Nov 30, 2021 · 66 comments
Closed

Add GDB support #618

dirkwhoffmann opened this issue Nov 30, 2021 · 66 comments
Labels
Enhancement New feature or request

Comments

@dirkwhoffmann
Copy link
Owner

This is a follow-up to discussion #525.

To get an idea about what has to be done, I had a brief look at the links @prb28 provided.

https://github.com/prb28/WinUAE/blob/master/od-win32/barto_gdbserver.cpp
https://github.com/prb28/fs-uae/tree/master/src/remote_debug

What I understand from the source code is that vAmiga needs to implement (part of) the GDB Remote Serial Protocol (RSP). Communication will be performed via sockets.

To make myself familiar with GDB and the socket API, I’ve written a small test program that opens a socket (port 8080) and waits for another application to connect. When this happens, it sends back a - which is interpreted by GDB as an unsuccessful transmission.

To test the code, I’ve connected to my app in GDB as follows:

GNU gdb (GDB) 11.1
(gdb) target remote :8080

As response to the payload (-) GDB sent me this:

+$qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+;memory-tagging+;xmlRegisters=i386#77

The contents doesn't matter, because it's all about establishing communication yet. The output shows that some communication is taking place in both directions.

What I would do as a starting point is to add the ability to vAmiga to communicate with GDB this way. Once this works, I would start implementing parts of the protocol. Does this make sense or am I heading in the wrong direction?

@dirkwhoffmann dirkwhoffmann added the Enhancement New feature or request label Nov 30, 2021
@prb28
Copy link
Contributor

prb28 commented Nov 30, 2021

Totally, yes, I've used gdb to test the emulators api.
It should be as, much as possible, compatible to be used by the C extension from bartman as well as mine.
I've added some tweaks to have more info from the debugger as the frame's history but that comes later.

@mras0
Copy link

mras0 commented Nov 30, 2021

Wouldn't it be easier to start out by creating a facade that mimics FS/WinUAE? I.e. at first provide hacky implementations of e..g. x_get_long and m68k_areg etc., but still leverage the existing work.

Getting familiar with the protocol is a good idea, but you can probably get something working a lot quicker by leaning more on the previous implementations. Should also make integrating changes easier.

Just my 2 cents.

@prb28
Copy link
Contributor

prb28 commented Nov 30, 2021

I think mimicking fsuae or winuae, is too much work for a temporary solution.
Creating a facade with the needed function for the protocol may help. I'm thinking of : step, add breakpoint, remove breakpoint, breakpoint hit, exception hit, read register for stack trace frame, read memory, set memory, get stack trace, etc.
I can do a list of the needed functions.
To plug the protocol on it is straightforward. There aren't a lot of commands needed.

@prb28
Copy link
Contributor

prb28 commented Dec 1, 2021

Example of exchange between the extension and WinUAE

Start of a debugging session and breakpoint hit.

To have these traces in the debug console add the trace:"true" option in the launch parameters.

Remote protocol documentation https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html

Emitter (Client extension / Server winuae) message description documentation
C $qSupported:+;multiprocess+;
vContSupported+;QNonStop+#9a
asks for supported options General-Query-Packets
S PacketSize=;BreakpointCommands+;swbreak+;
hwbreak+;QStartNoAckMode+;vContSupported+;QTFrame+
supported options General-Query-Packets
C $QStartNoAckMode#b0 Starting communication without acknowledgment General-Query-Packets
S OK Request accepted
Starting program: uae/dh0/gencop
C $qOffsets#4b Get section offsets that the target used when relocating the downloaded image General-Query-Packets
S 00c3de70 Relocation address
C $qfThreadInfo#bb Obtain a list of all active thread IDs from the target (OS) General-Query-Packets
S m01,02 2 threads: 1=CPU / 2=Copper
C $Z0,c3de8e#b2 Insert a breakpoint at $c3de8e Packets
S OK Request accepted
C $vCont;s:1#23 step thread 1 vCont-packet
S S05 Stopped signal 05 : breakpoint hit Stop-Reply-Packets
C $?#3f query the reason the target halted Packets
S S05 Stopped signal 05 : breakpoint hit Stop-Reply-Packets
C $Hg2#e1 Set thread 2 (copper) for subsequent operations Packets
S 0000000100f9068400...fb40000001000000004 registers for thread 2 - must check this one... seems a odd response
C $m4,a#2e Read 10 bytes at $4 Packets
S 00c0059400fe80d000fe Memory dump
C $mdff080,4#95 Read 4 bytes at $dff080 Packets
S 00003a3c Memory dump
C $Z1,0,0;X4,1ffc#96 Used to add the exceptions masks - One parameter of 4 bytes as mask Packets
S OK Request accepted
C $QTFrame:ffffffff#fa Select the n`th tracepoint frame from the buffer, -1 no frame General-Query-Packets
S OK Request accepted
C $p11#d2 Read the value of register 17 (PC) Packets
S 00c3de74 Contents of register
C $qTStatus#49 Retrieve stack trace: Ask the stub if there is a trace experiment running right now. Tracepoint-Packets
S T1;tstop::0;tframes:00;tcreated:00;tfree:ffffff;tsize:50*!;
circular:1;disconn:1;starttime:;stoptime:;username:;notes::
No frames
C $mc3de74,64#cd Read 0x64 bytes at $c3de74
S 2c7800047000203c000003e8223c0001000... Memory dump
C $QTFrame:ffffffff#fa Select the n`th tracepoint frame from the buffer, -1 no frame General-Query-Packets
S OK Request accepted
C $g#67 Reads the registers Packets
S 0000000100f9... Register values

Debugger stopped and waiting for user input.

@dirkwhoffmann
Copy link
Owner Author

@prb28: Thanks a lot for the example log which is an excellent starting point. Right now, I am playing around with a small example program that opens a socket, talks to gdb, computes checksums etc. Once I feel confident in what I am doing, I'll start on implementing the necessary commands to get the above example conversation working.

@dirkwhoffmann
Copy link
Owner Author

Brief update: I'm working on the basic infrastructure for sockets. Data from gdb can already be received, but nothing is reported back, yet.

Bildschirmfoto 2021-12-03 um 18 00 43

@dirkwhoffmann
Copy link
Owner Author

My first milestone was to open up a socket connection which has been achieved. My second milestone was to set a breakpoint in vAmiga via GDB which has been achieved partly.

To allow GDB to connect, vAmiga's gdbserver needs to be started. Currently, this is done via a shell command:

Bildschirmfoto 2021-12-05 um 13 27 21

The small bug icon in the status bar indicates that the server is running. Now, GDB can be connected:

GNU gdb (GDB) 11.1
Copyright (C) 2021 Free Software Foundation, Inc.
(gdb) target remote :8080
Remote debugging using :8080

GDB and vAmiga are exchanging some information at this point:

Bildschirmfoto 2021-12-05 um 13 28 34

Some replies are "fake replies" at the moment to get the conversation going.

Now, a breakpoint can be set in GDB:

> (gdb) b *16686158
Breakpoint 1 at 0xfe9c4e
(gdb) c
Continuing.

vAmiga continues emulation and stops at the specified location:

Bildschirmfoto 2021-12-05 um 13 29 08

It would be nice if I could see the breakpoint in the inspector. Unfortunately, GDB does not set them immediately when the b command is issued. They are set when c is executed and deleted when the emulator tells GDB that it has stopped.

There is various internal stuff that needs to be cleaned up before I continue with the next milestone.

What I haven't looked at yet is the way how executables have to be loaded into vAmiga to make them debuggable in VSC later. E.g., by looking at the protocol snippet posted above, I see that a relocation address has to be transmitted to GDB.

@prb28
Copy link
Contributor

prb28 commented Dec 5, 2021

Great progress!
Yes the relocation address must be returned. The debugger knows the position of the code to set the breakpoints accordingly.

@dirkwhoffmann
Copy link
Owner Author

Yes the relocation address must be returned

OK, I see. This is done in handle_qoffsets_packet in Emoon's FSUAE implementation and in handle_qoffsets in the UAE version. handle_qoffsets duplicates some code from show_exec_tasks which basically crawls through the raw exec structures in Amiga memory.

So my next milestone will be to add functionality similar to show_exec_tasks in vAmiga. Once this is done, I will have the necessary information available about the relocation offsets.

@dirkwhoffmann
Copy link
Owner Author

Brief update: vAmiga will get a new component called OSDebugger which allows the user to retrieve AmigaOS related information in RetroShell. Eventually, this component will deliver the relocation offsets that we need. At the moment, OSDebugger is able to print some information about tasks, similar to the ’T’ command in UAE:

Bildschirmfoto 2021-12-07 um 17 39 35

In the next step, I want to extend the functionality to processes. I understand that the Process struct has a field called pr_SegList which I need to scan to get the relocation offsets.

BPTR    pr_SegList;		/* Array of seg lists used by this process  */

I’ve found the following description which is not 100% clear to me:

"To identify the segments that a particular process uses, you must use pr_SegList. pr_SegList is an array of longwords with its size in Seg_List[0]. Other elements are either zero or a BPTR to a SegList."

My current understanding is as follows: pr_SegList points to an array which uses the following memory layout:

U32: Number of items
U32: Pointer to segment list 1 (maybe 0)
U32: Pointer to segment list 2 (maybe 0)

Here is what I am unsure about: There is no structure called SegList, but a structure called Segment:

struct Segment {
	BPTR seg_Next;
	LONG seg_UC;
	BPTR seg_Seg;
	UBYTE seg_Name[4];	/* actually the first 4 chars of BSTR name */
};

This struct can be chained, so I guess this structure is meant with SegList in the citation shown above. In other words: The items which I’ve referred to as „Pointer to segment list 1“ in the above memory layout are pointers to Segment structs? Is this correct?

@mras0
Copy link

mras0 commented Dec 7, 2021

pr_segList is some arcane stuff, I'm sure others know more. You can ignore the first two entries, either the third or fourth entry has the list you're after. Here's where AROS sets it up (SEGARRAY_LENGTH is 6, but I think it's 4 in classic AmigaDOS unless overlays are used, but don't quote me on that). I think the third entry is usually what you're after (but maybe some shells use entry four, see here).

It's a linked linked (0 terminated) of BPTR's (i.e. you must multiply the value with 4 to get the real address), the ULONG just before holds the size of the segment and the actual segment follows. You can see how AROS chains the loaded segments together here.

(I recently coded up some hacky stuff to scan the system structures as well, which is why I looked into it link)

BTW: At some point you may want to add some more sanity checks to your code (e..g. that the SysBase structure is valid and that you're not traversing corrupted, circular lists).

@dirkwhoffmann
Copy link
Owner Author

which is why I looked into it link)

void analyzer::do_system_scan()
auto process_seg_list = [this](uint32_t seg_list_ptr) 

Great! I think these two functions tell me exactly what I need to know.

@dirkwhoffmann
Copy link
Owner Author

By reviewing the code from @mras0, I've got the following understanding about the segment list structure. Did I get it right?

SegList

@mras0
Copy link

mras0 commented Dec 8, 2021

Yes, but to be clear what you've labelled "start" is literally the start of the segment (not a pointer).

I can see the segment list is processed similarly here in the WinUAE gdb stub. Looks like the fs-uae stub calls LoadSeg directly instead of trawling through exec/dos data structures.

BTW I found a bit more info on the other entries: AmigaDOS Technical Reference Manual page 3-2 says the first two entries point to resident code and the third being the SegList passed in as an argument (most of the time from LoadSeg). This matches what the WinUAE gdb stub does (only looking at the third entry, in the case of a normal task).

@dirkwhoffmann
Copy link
Owner Author

Update: The new code is able to traverse the SegList data structure. After booting the Workbench, it looks like this:

Bildschirmfoto 2021-12-08 um 14 22 58

The first entry in the first list is equal for all tasks. I hope this is normal, as is the size (which is 0xFFFFF000 in hex).

@dirkwhoffmann
Copy link
Owner Author

@prb28 I have a couple of questions about the way the VSC plugin will launch vAmiga.

  • How does the VSC plugin run the vAmiga executable?

    In contrast to UAE and FSUAE, vAmiga cannot be configured via the command line. Instead, a script-based approach has been taken. E.g., here is an example script that is used to perform a regression test.

    # Regression testing script for vAmiga
    # Dirk W. Hoffmann, 2021
    
    # Setup the test environment
    regression setup A500_ECS_1MB /tmp/kick13.rom
    
    # Run the test
    regression run /tmp/cputim1.adf
    wait 9 seconds
    
    # Exit with a screensht
    screenshot set cutout 196 56 908 314
    screenshot save cputim1
    

    The regression tester starts vAmiga with a path to the script file as argument. Everything else is handled inside the script. Can we do the same with VSC? I.e., can VSC setup a script file and run vAmiga with it? The scripting language is already quite powerful and can be extended as we like. E.g., it can be used to load Roms, to configure the GdbServer, or to insert ADFs.

  • How do we get the Kickstart Rom into the emulator?

    Does the VSC plugin know the path to the Kickstart Rom? In this case, it would be easy: The plug-in would write a command into the launch script that tells the memory to load the Rom from disk.

  • How do we get the program into the emulator?

    vAmiga accepts ADF and EXE files. Are any of these two provided by the VSC plugin?

@mras0
Copy link

mras0 commented Dec 8, 2021

I don't know how OS tasks are supposed to look, but the lists look suspicious. For the interesting case (a user provided executable loaded from disk) the output is wrong.

If I add the following to the start of OSDebugger::dumpProcess(std::ostream& s, const os::Process &process) const I get a much more plausible result:

    if (process.pr_CLI) {
        auto cli_Module = BPTR(mem.spypeek32<ACCESSOR_CPU>(BPTR(process.pr_CLI) + 0x3c));
        SegList sl;
        read(cli_Module, sl);
        
        for (const auto& it : sl) {
            s << hex(it.second) << " (" << dec(it.first) << " bytes)" << std::endl;
        }
        return;
    }

@prb28
Copy link
Contributor

prb28 commented Dec 8, 2021

* How does the VSC plugin run the vAmiga executable?

The run command is different for each UAE.
FS-UAE starts with arguments setting the program to execute. It loads it in memory at startup and runs the program directly in debug.
Win-UAE starts with a default configuration set in the launch arguments. The executable name to debug is one of the arguments. A disk dh0 is mounted with a startup-sequence. When the startup-sequence runs the program, it enters in debug mode.

  The regression tester starts vAmiga with a path to the script file as argument. Everything else is handled inside the script. Can we do the same with VSC? I.e., can VSC setup a script file and run vAmiga with it?

Yes, no problem.

I think the script should be set as an example and we may let the user edit it if he wants. Or/And it can be generated by vscode with parameters set in the launch command.

* How do we get the Kickstart Rom into the emulator?

It's on the launch arguments of the UAEs. These arguments are set in the .vscode/launch.json file

  Does the VSC plugin know the path to the Kickstart Rom?

No I let the user set it in the launch parameters of the debugger.

In this case, it would be easy: The plug-in would write a command into the launch script that tells the memory to load the Rom from disk.
Yes that's the target.

* How do we get the program into the emulator?
  vAmiga accepts ADF and EXE files. Are any of these two provided by the VSC plugin?

Yes we can do both.
I think it's better to have a dh0 mounted on a local directory So you can edit your assets directly.

Can vAmiga mount a disk linked to a local directory ?

Can I run vAmiga on a simple window for all the os ? Do I need to make a custom build with a window library as wx-windows or others ?

@dirkwhoffmann
Copy link
Owner Author

Yes, no problem. I think the script should be set as an example and we may let the user edit it if he wants.

OK, sounds good to me. I think this is better than letting VSC create the script based on some other description. It would add another layer of indirection.

It's on the launch arguments of the UAEs.

Ok, good. So the user would add the path the Kickstart to the script file.

Yes we can do both. I think it's better to have a dh0 mounted on a local directory So you can edit your assets directly.

vAmiga doesn't support hard drives. We would have to load the program into the emulator in form of a bootable ADF (an EXE file is fine, too, because vAmiga can convert those to bootable ADFs on-the-fly. However, if ADFs are already there or if they are easy to create on the VSC side, I would prefer ADFs to EXE files.

Can vAmiga mount a disk linked to a local directory ?

No, vAmiga doesn't know where the disks are coming from. When a disk is inserted into a drive, the MFM encoder is utilised to translate the ADF into a MFM stream. From that moment on, vAmiga only works on the bit stream (i.e., no changes are written back to the original ADF). If the user wants to persist his work, he has to export the disk explicitly, e.g., in form of another ADF.

Can I run vAmiga on a simple window for all the os ?

The original vAmiga app runs on macOS, only. Then there is the outdated vAmigaBM Linux port. I could resurrect this project, but I would rather prefer to let it die. @mras0 has successfully compiled vAmiga on Windows with some GUI code attached (based on SDL). Maybe this project is the most promising at the moment to get vAmiga work on Windows, at least to the point that it can connect to VSC via the GDB remote protocol. At the moment, the GDB server wouldn't compile on Windows because of the Socket code, but this shouldn't be too hard to fix. I also want to mention the two great web ports of vAmiga based on WASM, but they don't help us in this special scenario.

@mras0
Copy link

mras0 commented Dec 9, 2021

I'll gladly share the latest version of my "frontend" (which seems to work OK under both windows and Linux (WSL2)), but it's not really user friendly to put it mildly. The big issue is the user interface, which I don't want to be responsible for :). I just handle everything with command line arguments (and the retroshell, which I've made accessible with a hacky overlay).

For just this purpose: Starting an executable from VS code and running it vAmiga on most platforms, it'll work fine, but as soon as people want to do anything more it'll be lacking (especially if they expect to access the same tools/debugging capabilities that are available in the MacOS version).

I see multiple issues here that you probably want to track differently:

The last one could be hacked by creating a disk image of the directory, but currently I think that'll be limited to a HD floppy size (which is probably OK for now). Doing it properly is a bit more involved (it's on the TODO list for my own for-fun emulator). Getting some (hacky) harddisk support isn't too difficult (I've already managed that), but mounting a directory isn't as easy.

@prb28
Copy link
Contributor

prb28 commented Dec 9, 2021

I'll gladly share the latest version of my "frontend" (which seems to work OK under both windows and Linux (WSL2))

If you agree I'll would like to try building running it. I would be interested in testing the script feature.

For just this purpose: Starting an executable from VS code and running it vAmiga on most platforms, it'll work fine, but as soon as people want to do anything more it'll be lacking (especially if they expect to access the same tools/debugging capabilities that are available in the MacOS version).

The first need, as you mention, is simple for the Gui. The fancy options for debugging should be integrated in the IDE so we don't need a complex GUI (thinking of a step back option ;-)).

I see multiple issues here that you probably want to track differently:
* Get GdbServer working on windows (as you write, this should not be too hard)
* Non-MacOS version of vAmiga with any frontend
* Non-MacOS version of vAmiga with proper GUI
* Mounting a local directory as a filesystem

Totally agree with your view.

The last one could be hacked by creating a disk image of the directory, but currently I think that'll be limited to a HD floppy size (which is probably OK for now).

I don't have a clear idea if this option is mandatory for users. It can be useful to be able to inspect the files written during the process. I think being able to bring them out of the emulator at least at the end of the run maybe important. A script command may do the trick.

The WASM build could be an interesting option for an integrated emulator, but it way be difficult and too heavy to have it in vscode.

@dirkwhoffmann
Copy link
Owner Author

Brief update: Today, I'm working on

  • making the Socket code compile in MSVC.
  • setting up an example script that loads a kickstart, loads an ADF, and enables the debug server.

Once this is done, I'll create a new branch which will make experimental modifications easier.

@dirkwhoffmann
Copy link
Owner Author

Update:

  • Now OSDebugger and GDBServer compile on Window.
  • I've merged all changes into the master branch and forked a new branch called gdb.

Here is an example script that configures and launches vAmiga:

# Make sure the Amiga is switched off
amiga power off

# Load a Kickstart Rom
memory load rom "/tmp/kick13.rom"

# Configure memory
memory set chip 512
memory set slow 512
memory set fast 0

# Set the search path for all connected drives
dfn set searchpath "/tmp"

# Insert some ADF
df0 insert "defender.adf"

# Activate the GDB server
gdbserver set port 8080
gdbserver set verbose true
gdbserver start 

# Switch the Amiga on and continue emulation
amiga power on
amiga run

Bildschirmfoto 2021-12-10 um 11 23 38

@mithrendal
Copy link
Contributor

mithrendal commented Dec 10, 2021

The WASM build could be an interesting option for an integrated emulator, but it way be difficult and too heavy to have it in vscode.

@prb28 interesting idea ... could possibly be done if vsc Amiga Assembly would act as a simple webserver

one way to make that work from vsc amiga assembly would probably be to

  1. vsc amiga assembly opens a http listener port e.g. on 8080
  2. it then starts the favourite browser with a command line parameter which points to the opened port
    chrome http://localhost:8080
  3. then upon the incoming http-request vsc amiga assembly would respond with the vAmiga Web port (e.g. special version of the already existing https://vAmigaWeb.github.io )
  4. the loaded vAmigaWeb port has then to communicate back to vsc amiga assembly via port 8080 and establish the gbd session connect
  5. that way we would have gdb communication between vAmiga and amiga assembly via http

@prb28
Copy link
Contributor

prb28 commented Dec 10, 2021

Well vscode is made with chromium. And it can load wasm in a webview.
So there is no need for an external navigator. But I don't know if it can handle vAmiga in wasm.
Can be fun to try.

@mithrendal
Copy link
Contributor

Ah well I see that would be then "really" integrated 😎 and therefore much more simple and robust ... no need for any additionally socket communication ... only pure javascript ... everything inside vsc ... 🤤

lets definitely schedule this as an experimental goal for a phase 2 ...

we are still at phase 1
+implementing gdb in the desktop version and connecting it to vsc amiga assembly

when phase1 is done we try to integrate a wasm build into the amiga assembly plugin. Maybe we can just move basic parts of the code from one of our current web ports which is hosted at https://github.com/vAmigaWeb/vAmigaWeb over into yours repo and as a result make a special version for amiga assembly... does that make sense ?

@prb28
Copy link
Contributor

prb28 commented Dec 11, 2021

Yes totally.
Step by step is the best way to go.

@prb28
Copy link
Contributor

prb28 commented Dec 13, 2021

Vscode will wait for the answer, you can hold and send the response when it's ready.

@mras0
Copy link

mras0 commented Dec 13, 2021

Looks like the other implementation return error/blank responses until the process is loaded (1, 2) if you don't want to/cant wait.

@dirkwhoffmann
Copy link
Owner Author

Looks like the other implementation return error/blank responses until the process is loaded

This means that VSC will periodically send a qOffset command until it gets a proper answer? This would be the easiest solution for me.

@prb28
Copy link
Contributor

prb28 commented Dec 13, 2021

I just did one call, but; if needed I can change it.
There are different ways to do it:

  • The emulator starts, loads the program and opens the socket at this point waiting for a debugger connection
  • The emulator stores the qoffsets demand and wait to have the value to answer, keeping the socket opened to respond.
  • The emulator starts and waits for the vRun command to select the program to run. It responds to this command when the program is loaded and the debugger continues.

@dirkwhoffmann
Copy link
Owner Author

There are different ways to do it:

The second approach sound most promising to me. A general issue is how to detect when the program has been loaded. Is it sufficient to wait until a process has been created? In other words: Is the first created process the process we are looking for? How do the other emulators deal with this issue?

@prb28
Copy link
Contributor

prb28 commented Dec 13, 2021

WinUAE uses a parameter telling what is the program name that triggers the debug session.
FS-UAE uses the vRun command and load the file sent by the command.

@dirkwhoffmann
Copy link
Owner Author

I am playing around with a version that defers the answer to the qOffset command until the segment information is present. Unfortunately, it seems that VSC doesn't wait for the answer. If I don't reply anything to the qOffset command, VSC keeps on sending the next request:

Bildschirmfoto 2021-12-14 um 14 51 20

@prb28
Copy link
Contributor

prb28 commented Dec 15, 2021

Did you close the socket ?
I think if not it will keep vscode waiting for the answer.

@dirkwhoffmann
Copy link
Owner Author

dirkwhoffmann commented Dec 15, 2021

Did you close the socket ?

No. The socket connection is still open (otherwise I wouldn't have received the Z command). The socket is closed after receiving the Z command because vAmiga can't interpret the X2,3c condition, yet.

More questions:

  • What is the semantics of the X2,3c condition in the Z command? If I understand the GDB docs correctly, the interpretation of the condition is up to the target.

@dirkwhoffmann
Copy link
Owner Author

I've been running into more issues. I've tried to connect vAmiga to m68k-amigaos-gdb to see what messages are coming in.

  • On Ubuntu, it seemed to work fine. I got requests that looked identical to what standard GDB was sending. However, on Ubuntu, I can only connect to vAmigaBM which is basically a dead project.

  • On macOS, I got this:
    R: +$qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+#df
    T: $PacketSize=512;BreakpointCommands+;swbreak+;hwbreak+;QStartNoAckMode+;vContSupported+#5a
    R: +0m

    The third request seems to be random garbage (it changes when GDB is rerun).

Maybe I am doing something fundamentally wrong (maybe in my socket code) or the currently existing Amiga toolchains have issues.

@mras0
Copy link

mras0 commented Dec 15, 2021

You should be able to test on ubuntu with "my" frontend (just change the submodule to point at your preferred vAmiga version).

Is your dev branch up to date with what you're trying with? The change to Socket::recv seems suspect (I don't see how buffer can assumed to be NUL-terminated there, so maybe you're just seeing stack garbage).

I can do some testing tomorrow after work if you'd like.

@prb28
Copy link
Contributor

prb28 commented Dec 15, 2021

The parse in winuae : https://github.com/prb28/WinUAE/blob/fee2f4ce524994c29ede9bce45bdad0a315bb5a1/od-win32/barto_gdbserver.cpp#L1155

You can respond "ok" and skip this message for now.

@prb28
Copy link
Contributor

prb28 commented Dec 15, 2021

  • R: +0m

Looks like a acknowledgment: https://sourceware.org/gdb/onlinedocs/gdb/Packet-Acknowledgment.html#Packet-Acknowledgment
You can ignore these "+", they must disappear after the command QStartNoAckMode.

@prb28
Copy link
Contributor

prb28 commented Dec 15, 2021

Unfortunately, it seems that VSC doesn't wait for the answer. If I don't reply anything to the qOffset command, VSC keeps on sending the next request

I've tried it and, Yes the Z1 command arrives at the before the end of the qOffsets.
Vscode is multi-threaded and the debugger sets the breakpoint while the other command is pending. I thought I had a mutex to prevent that... I must look at it closer.
After that 2 commands are glued in the same buffer.

@prb28
Copy link
Contributor

prb28 commented Dec 15, 2021

I thought I had a mutex to prevent that...

I can confirm, my mutex doesn't seem to work. I'll try to fix it tomorrow.

@dirkwhoffmann
Copy link
Owner Author

The change to Socket::recv seems suspect

You got it! This change is the major cause of all the trouble. Originally, the code looked like this (with an additional n parameter in the string constructor).

    auto n = ::recv(socket, buffer, BUFFER_SIZE, 0);
    if (n > 0) {    
        string result = string(buffer, n);
        return result;
    }

I removed the n parameter, because at some point, I got a string from VSC with the last character being equal to 0. My "fix" to this then screwed it up. I'll fix this asap.

@prb28
Copy link
Contributor

prb28 commented Dec 16, 2021

@dirkwhoffmann The problem was the timeout of the mutex that was too short.
Here is a fixed version : https://github.com/prb28/vscode-amiga-assembly/releases/download/pre_1.1.0/amiga-assembly-1.1.0.vsix

@dirkwhoffmann
Copy link
Owner Author

Here is a fixed version

Thanks! Now, it works until I receive the QTFrame command. I need to look into that in more detail, because vAmiga doesn't record stack frames at the moment.

R: $QTFrame:ffffffff#fa

@dirkwhoffmann
Copy link
Owner Author

I’ve run into another problem, this time using m68k-amigaos-gcc (I’ve posted something about this yesterday, but it seems the post didn’t get through).

Here is my example program:

#include <stdio.h>

int fibo[2];
char *txt = "Press Any Key to Continue\n";

void next()
{
    int n = fibo[0] + fibo[1];
    fibo[0] = fibo[1];
    fibo[1] = n;
}

int main(int argc, char *argv[])
{
    fibo[0] = 0x11221122; // 0   
    fibo[1] = 0x33443344; // 1

    for (int i = 0;; i++) {
    
        printf(txt);
        getchar();

        printf("fibo[i] = %d\n", fibo[0]);
        next(); 
    }

    return 0;
}

Firstly, I compiled the program with m68k-amigaos-gcc:

/opt/amiga/bin/m68k-amigaos-gcc hello.c -g -o fibo.exe -mcrt=nix13

The resulting exe file can be loaded in vAmiga via drag and drop. After loading, the process shows up in the OSDebugger. My test program is process number 2:
Bildschirmfoto 2021-12-16 um 20 05 19
Secondly, I’ve started a GDB server on the vAmiga side and connected to it via m68k-amigaos-gdb:

Reading symbols from fibo.exe...
(gdb) target remote :8080
Remote debugging using :8080
0x00fc0f94 in ?? ()
(gdb) print fibo
$1 = {-1431655766, -1431655766}

GDB displays bogus numbers for the fibo array. This is because it reads the contents from a wrong memory location:
Bildschirmfoto 2021-12-16 um 20 08 06
The fibo array is located here:

Bildschirmfoto 2021-12-16 um 20 06 48

I don’t unterstand why GDB is reading from memory location 0x2E04. I must still be missing something fundamental here about segments, the Amiga memory layout, or something else.

@prb28
Copy link
Contributor

prb28 commented Dec 17, 2021

You can run the bebbo's gdbserver in your emulator and print the protocol dialog (skipping your implementation).
You will maybe see a difference that will help you.

@dirkwhoffmann
Copy link
Owner Author

You can run the bebbo's gdbserver

I had this idea, too. But there doesn't seem to be a gdbserver in /opt/amiga/bin. The only gdb related executable is m68k-amigaos-gdb.

@prb28
Copy link
Contributor

prb28 commented Dec 17, 2021

@dirkwhoffmann
Copy link
Owner Author

I want to thank everyone who has supported me in trying to make vAmiga VSC/GDB compatible. I wouldn't have found much of the needed information on my own.

Nevertheless, I have decided to personally withdraw from this project. This may come as a surprise, but every project reaches the point where progress has to be weighed against invested time. Based on my experience so far, I expect it would take me a long time to reach a usable result. This in turn means that I couldn’t work on other projects during this time. There are still quite a few open issues in the bug database concerning the compatibility of the emulator and I don't want to leave these issues unprocessed for a long period of time.

If someone else wants to continue working on the debug functionality, feel free. I think the VSC/GDB integration is a worthwhile goal and it would be nice if it can be achieved sometime.

@prb28
Copy link
Contributor

prb28 commented Dec 17, 2021

Thank you for starting it!
I understand your choice, it needs time to be finished.
I don't have that time too for now to fully understand vAmiga and implement all the bindings.
Maybe later next year.
I can still help someone thanking this forward.

@dirkwhoffmann
Copy link
Owner Author

Somehow unexpectedly, I’ve been successful in connecting @bebbo'sm68k-amigaos-gdb to vAmiga. With the latest code, it is possible to debug a program via single-step.

Details are documented in this wiki article, in case anyone is still interested:
https://github.com/dirkwhoffmann/vAmiga/wiki/GDB-Server

@dirkwhoffmann
Copy link
Owner Author

The experimental GDB server (as described in the Wiki article) is part of v1.1b7.

@prb28
Copy link
Contributor

prb28 commented Mar 17, 2022

Connected and stepping in v1.1b9:
image
I did some minor modifications to get there.
The exe is halted a bit late after it's start, so it looses the first breakpoints but it's almost usable.
I'll slowly continue the modifications of the gdb adapter in the next weeks.
Great job!

@dirkwhoffmann
Copy link
Owner Author

I'll slowly continue the modifications of the gdb adapter in the next weeks.

Impressive. Great to see this going forward.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants