Using GNATemulator

Launching GNATemulator

To launch a guest application just run:

$ <target>-gnatemu hello

GNATemulator will automatically load the ELF file (hello) and start execution at the entry point.

To stop, press Control-a x.

Displaying the help

All the available options can be listed with the –help arguments:

$ <target>-gnatemu --help
Usage: <target>-gnatemu [OPTIONS] FILE
Options are:
  -v, --verbose        Be verbose
  -h, --help           Display this help
  -Pproj or -P proj    Use GNAT Project File proj
  -Xnm=val             Specify an external reference for Project Files
  --version            Display version
  --serial=null        Redirect 1st serial port to null file
  --serial=stdio       Redirect 1st serial port to stdio
  --serial=file:FILENAME
                       Redirect 1st serial port to a file (write only)
  --serial=tcp:HOST:PORT[,server]
                       Redirect 1st serial port to HOST:PORT via tcp.
  --serialN            Idem as --serial for the Nth serial port
  --tftp-root=path     Set root directory of tftp server (default: .)
  --gdb[=PORT]         Allow gdb connection on port PORT (default port is 1234)
  -g                   Allow default debug (i.e --wdb or --gdb --freeze-on-startup)
  --freeze-on-startup  Freeze emulation on startup
  --auto-reboot        Don't exit the emulator when the guest reboots or resets.
                       The emulator will run until stopped by the user.
  --gnatbus=HOST:PORT[,HOST:PORT]
                       Connect a GNATBus device
  --gnatbus-timeout=timeout
                       Specify the connection timeout for GNATBus devices
  --add-memory=name=MEM_NAME,size=MEM_SIZE,addr=MEM_ADDR[,read-only=on|off]
                       Add a memory bank to the emulated address space.
                       Address can be in hexadecimal (0xF0000000) and
                       size accepts (K)ilo, (M)ega, (G)iga, (T)era postfix.
  --show-memory-map    Display the emulated address space
  --emulator-help      Display available Qemu options
  --eargs              Start a group of Qemu options
  --eargs-end          End a group of Qemu options
  --board=BOARD_NAME

GNAT Project File

Project attributes for GNATemulator are specified in package “Emulator”:

project Prj is
   package Emulator is
      [...]
   end Emulator;
end Prj;

Supported attributes:

  • Board: equivalent of switch --board=

  • Debug_Port: equivalent of switch --gdb=

  • Switches: A list of switches processed before the command line switches

For example:

package Emulator is
   for Board use "BOARD_NAME";
   for Debug_Port use "1234";
   for Switches use ("Sw1", "Sw2");
end Emulator;

Debugging

This section explains how to set up a debugging session with GNATemulator.

Debugging options in GNATemulator

GNATemulator provides various switches to ease debugging of guest applications. Here are the options that control debugging

--gdb, --gdb=<PORT>

This flags will initiate the gdbserver and wait for gdb connection on port PORT. If not port is specified then the default port 1234 is used. For example:

$ <target>-gnatemu --gdb=2048 hello
--freeze-on-startup

Freeze the CPU at startup. When used GNATemulator will freeze simulation and wait for a continue command from gdb.

-g

This is a shortcut for --gdb --freeze-on-startup.

Debugging with GDB

To debug with gdb:

#. Invoke GNATemulator with the -g flag so that the emulator will stop and await a connection from gdb:

$ <target>-gnatemu -g hello
  1. Invoke gdb and connect to GNATemulator with the GDB target command:

    $ <target>-gdb hello
    (gdb) target remote localhost:1234
    (gdb)
    

We can use a bare-board target to illustrate these steps, in this case a LEON3, working with a simple “hello world” program.

In one console we start the LEON3 version of the emulator:

$ leon3-elf-gnatemu -g hello

The emulator is now waiting for the debugger to connect.

In another console we start the LEON3 version of the debugger:

$ leon3-elf-gdb hello
...
Reading symbols from hello...done.
(gdb)

In response gdb emits several lines of information, loads the image, and then prompts for another command.

Next, we instruct gdb to connect to the simulator over TCP:

(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x40000000 in trap_table ()
(gdb)

Again gdb responds and prompts for another command. We can have it show the source code, for example:

(gdb) list
1       with Ada.Text_IO; use Ada.Text_IO;
2
3       procedure hello is
4       begin
5          Put_Line ("hello world");
6       end;
7
(gdb)

We set a breakpoint on line five:

(gdb) break hello.adb:5

As a result gdb will respond with an indication of the breakpoint being successfully set:

Breakpoint 1 at 0x40001004: file C:\temp\O305-036\hello.adb, line 5.
(gdb)

We can then command gdb to continue execution of the application:

(gdb) cont
Continuing.

Breakpoint 1, hello () at C:\temp\O305-036\hello.adb:5
5          Put_Line ("hello world");
(gdb)

In response, once the breakpoint is hit, gdb displays the breakpoint line and prompts us again. At this point the call to Put_Line has not yet occurred. If we then issue the “step” command the call will occur:

(gdb) step
6       end;

Now gdb is ready to execute from line six.

In the other console we will see the message printed as part of the emulator execution:

$ leon3-elf-gnatemu -g hello
hello world

We can continue debugging if there is more of the program, or simply tell gdb to quit. Quitting will break the connection to the emulator and will cause it to terminate as well.

Debugging with GNAT Studio

To debug with GNAT Studio, you should:

  1. Read the GNAT Studio documentation, section “Working in a Cross Environment -> Debugger Issues” and set the following project attributes::

    package IDE is
       for Program_Host use ":1234";
       for Communication_Protocol use "remote";
    end IDE;
    
  2. Once you have configured your project for cross-debugging in GNAT Studio, just click on the Debug with Emulator toolbar button: this will build the executable, launch GNATemulator with the right options, and start a debugging session in GNAT Studio, automatically connecting the debugger to the port specified via the Emulator’Debug_Port and IDE’Program_Host project attributes (the two port values should match).

Redirecting serial port(s)

In GNATemulator it is possible to redirect the serial communication ports. In order to do that you need to use the switch:

--serial=file:<FILE>, --serial=tcp:<HOST>:<PORT>[,server], --serial=stdio, --serial=null

Serial can be redirected to null, standard output, file (write only) or TCP port. Note that only one serial port can be redirected to standard output. By default if you have several ports then the first one will be redirected to standard output and the others to null.

  1. Redirection to standard output:

    $ <target>-gnatemu --serial=stdio hello
    
  2. Redirection to null:

    $ <target>-gnatemu --serial=null hello
    
  3. Redirection to a file (write only):

    $ <target>-gnatemu --serial=file:/tmp/serial_output.txt hello
    
  4. To a TCP port:

    $ <target>-gnatemu --serial=tcp:hostname:1234 hello
    

    With the ‘server’ option, GNATemulator will wait for the tcp connection:

    $ <target>-gnatemu --serial=tcp:hostname:1234,server hello
    

The switch --serial will redirect the first serial port. If there is more than one serial port on the target, you can redirect them using:

--serial1, --serial2, --serialN

where N is the number of your serial port. --serial is equivalent to --serial1

For example, the first serial to a file and the second to a TCP port:

$ <target>-gnatemu --serial=file:/tmp/serial1.txt \
                         --serial=tcp:localhost:1234 hello

As mentioned before, only one serial port can be redirected to the standard output. By default the first serial port is redirected to that output except if another port has been assigned explicitly to it. In that case the first serial port is redirected to null by default.

Connecting to GNAT Bus devices

In order to connect additional devices developed with GNAT Bus to your board you should use the following option:

--gnatbus=<HOST>:<PORT>[,<HOST2>:<PORT2>...]

For more in depth introduction to that feature please see Extending GNATemulator chapter.

Board selection

If GNATemulator provides multiple emulations for the target platform, use the following option to select a specific board:

---board=<BOARD_NAME>

Use <target>-gnatemu —help to get the list of boards.

Access to host file system

(only for aarch64-elf, arm-elf, leon3-elf, morello-elf, ppc-elf, riscv64-elf and x86_64-elf)

GNATemulator provides a simplified version of the GNAT.OS_Lib package that allows access to the host file system from the simulated program.

To use this package you have to include “hostfs_bareboard.gpr” into your project file:

with "hostfs_bareboard.gpr";

project Test is
...
end Test;

You can then use the package in your project:

with GNAT.OS_Lib; use GNAT.OS_Lib;
with GNAT.IO; use GNAT.IO;

procedure Test is
   FD : File_Descriptor;
   File_Name : constant String := "new_file.txt";
   Text : String (1 .. 12) := "Hello World" & ASCII.LF;
begin

   --  Create a new file on the host file system
   FD := Create_New_File (File_Name, GNAT.OS_Lib.Text);

   if FD /= Invalid_FD then

      if Write (FD, Text'Address, 12) /= 12 then
         Put_Line ("Cannot Write '" & File_Name & "'");
      end if;

      Close (FD);

   else
      Put_Line ("Cannot create new file '" & File_Name & "'");
   end if;
end Test;

Finally, when compiling your project you have to specify the board like so:

$ # Add GNATBus's project files directory in GPR_PROJECT_PATH
$ export GPR_PROJECT_PATH=<PATH_TO_GNATEMULATOR>/share/gpr:$GPR_PROJECT_PATH
$ # And run gprbuild
$ gprbuild --target=leon3-elf -XGNATEMU_BOARD=leon3-elf test

Guest reset behavior

By default, GNATemulator exits when the guest is reset. This behavior can be changed using --auto-reboot which will allow the guest to reset without exiting GNATemulator. Note that in this case the emulator will continue to run until it is explicitly stopped or exited by the user. The parts of the emulator state that are preserved over the reset (such as the contents of RAM) is highly dependent on the emulated target board and the application.