venerdì 21 marzo 2014

GDB and Geany IDE: Remote Cross Debugging

Embedded Linux System Debugging with Geany


Remote debugging is when GDB runs on one machine and the program being debugged runs on another. This is useful in embedded systems, and often in this case it's called remote cross-debugging because the target CPU is differerent from the host used for developing code.
gdbserver can be used to remotely debug the program without needing to change it in any way.

The Geany IDE debugger plugin does not support remote debugging natively. Some graphical debugger such as Insight or the Eclipse IDE support it, but not Geany. And I like Geany very much, while I don't like Eclipse: so I arranged a patch/workaround to do it (based on plugin version 0.21).


Compiling the patch

Download geany plugins sources [http://plugins.geany.org/downloads.html] and install geany and gtk devel packages for your distribution. You'll need also Geany devel package installed. Compiling debugger plugin needs also vte-devel package installed.
  # cd geany-plugins-0.21.1
  # ./configure --prefix=/usr --mandir=/usr/share/man/
  # cd debugger/src
  # make

Compiled plugin is in the debugger/src/.libs/ directory (debugger.so). You will need to copy it in /usr/lib/geany (or where your distribution places the geany plugins), or install it with:
  make install

Geany can use an addictional path for plugins search (see Geany options), and if you want to use it you will have to configure the sources with:
  # ./configure --prefix=/your/path/to/plugins --mandir=/usr/share/man/

Here below the patch for dbm_gdb.c file:

  --- geany-plugins-0.21.1/debugger/src/dbm_gdb.c.original
  +++ geany-plugins-0.21.1/debugger/src/dbm_gdb.c
  @@ -96,6 +96,9 @@
   
   /* flag, showing that on debugger stop we have to call a callback */
   gboolean requested_interrupt = FALSE;
  +
  +/* flag: remote debugging session*/
  +gboolean remote_session = FALSE;
   
   /* autos list */
   static GList *autos = NULL;
  @@ -598,6 +601,9 @@
    */
   gboolean load(char* file, char* commandline, GList* env, GList *witer)
   {
  +char *ip;
  +char *port;
  +
    /* loading file */
    GString *command = g_string_new("");
    g_string_printf(command, "-file-exec-and-symbols %s", file);
  @@ -610,11 +616,38 @@
     return FALSE;
    }
   
  - /* set arguments */
  - command = g_string_new("");
  - g_string_printf(command, "-exec-arguments %s", commandline);
  - exec_sync_command(command->str, TRUE, NULL);
  - g_string_free(command, TRUE);
  + /* is it a remote target? */
  + /* (remote sessions handle commandline on debugserver side) */
  + if (commandline[0] == '@') {
  +  ip = commandline + 1;
  +  port = strchr(ip, ':');
  +  if (port != NULL) {
  +   *port = '\0';
  +   port++;
  +  }
  +  else {
  +   port = (char *)"3278";
  +  }
  +  if (ip == '\0') {
  +   ip = (char *)"127.0.0.1";
  +  }
  +  if (port == '\0') {
  +   port = (char *)"3278";
  +  }
  +  command = g_string_new("");
  +  g_string_printf(command, "target remote %s:%s", ip, port);
  +  exec_sync_command(command->str, TRUE, NULL);
  +  g_string_free(command, TRUE);
  +  remote_session = TRUE;
  + }
  + /* set arguments in non-remote sessions */
  + else {
  +  remote_session = FALSE;
  +  command = g_string_new("");
  +  g_string_printf(command, "-exec-arguments %s", commandline);
  +  exec_sync_command(command->str, TRUE, NULL);
  +  g_string_free(command, TRUE);
  + }
    
    /* set locale */
    command = g_string_new("");
  @@ -678,7 +711,14 @@
    }
    free_start_messages();
   
  - exec_async_command("-exec-run &");
  + if (remote_session) {
  +  exec_async_command("break main");
  +  sleep(2);
  +  exec_async_command("continue");
  + }
  + else {
  +  exec_async_command("-exec-run &");
  + }
   }
   
   /*
  @@ -686,6 +726,9 @@
    */
   void restart(char* terminal_device)
   {
  + if (remote_session) {
  +  dbg_cbs->report_error(_("Restart command not available in remote sessions"));
  + }
    dbg_cbs->clear_messages();
    exec_async_command("-exec-run &");
   }


Remote debugging

After compiling and installing this patched plugin, enable Debugger plugin in Geany. Remote debugging can be used inserting in the debugger plugin tab "Command Line" field the following format string:
  @remoteipaddr:port

for example:
  @192.168.2.51:4567

If you don't specify remoteipaddr, the default used is 127.0.0.1; if you don't specify port, the default used is 3278.

On the remote side, you'll have to start gdbserver:
  # gdbserver localhost:4567 yourprogram [yourprogram options]

Command options must be specified on the gdbserver side, when debugging remotely.


Cross debugging

The remote device can be a target CPU different from the host. For example it could be an embedded ARM Linux board. In this case you have to use a shell script to start geany with the correct path for the right gdb executable (x86 gdb executable can not debug other target CPUs than x86); let's suppose your ARM gdb executable is gdb-arm-linux (you can download it from emdebian: gdb-arm-linux-gnueabi_7.2-1_i386.deb) and you installed it in your ~/bin/arm-linux-emdebian/usr/bin/ directory:
  • create a symlink gdb to gdb-arm-linux:
      # cd ~/bin/arm-linux-emdebian/usr/bin/
    
      # ln -s gdb-arm-linux gdb
    
  • then create a shell script like this and use it for starting Geany:
      #!/bin/sh
      PATH=/home/yourhome/bin/arm-linux-emdebian/usr/bin/:$PATH
      geany $1
    
    
    

Notes

A few notes on remote debugging use:
  • don't use "Restart" command in remote debugging session: it can't be used
  • a breakpoint is automatically placed at main start (break main) so program stops there after first run, but it's not shown in Geany
  • place manually yourself a breakpoint in the place where program stops initially: it will prevents other breakpoints garbage later
This does not want to be a definitive solution: it's a dirty patch/workaround for my needs.

4 commenti:

  1. Hi, this little hack looks quite useful. I tried to apply it to current geany-plugings-master and most of the patches failed due to the base code being too different. But with a few mods it looked quite easy to account for the changes and it compiled first time ( to my surprise ).

    Sadly, as soon as I start the debugger it dumps out.


    My initial aim is run a trivial hello world prog under gdbserver and run it from debugger. In a second step I will try the symlinked cross-gdb trick. If that works OK, I want to add a second line to the combe to add the cross debugger in a cleaner way.

    Have you done this on a more recent version ? I have not tried debugging it yet since it may be a duplication of effort. You may also have a better solution by now.

    Thanks for any news.

    RispondiElimina
  2. Hi, this little hack looks quite useful. I tried to apply it to current geany-plugings-master and most of the patches failed due to the base code being too different. But with a few mods it looked quite easy to account for the changes and it compiled first time ( to my surprise ).

    Sadly, as soon as I start the debugger it dumps out.


    My initial aim is run a trivial hello world prog under gdbserver and run it from debugger. In a second step I will try the symlinked cross-gdb trick. If that works OK, I want to add a second line to the combe to add the cross debugger in a cleaner way.

    Have you done this on a more recent version ? I have not tried debugging it yet since it may be a duplication of effort. You may also have a better solution by now.

    Thanks for any news.

    RispondiElimina
    Risposte
    1. No, I did not port the patch to any newer version up to now. I will be happy to see your work.
      In this moment I'm using Geany 1.32 with the Scope Debugger plugin, and I connect to a pseudo-remote server (NXP redlink) for cross debugging an embedded microcontroller board.
      It would be very useful if Geany would have a native better support to cross-debugging and embedded-debugging.
      The only real world IDE for embedded developing is Eclipse, and I don't like it at all.

      Elimina
  3. Thank you for this article !
    I need such debugging to debug with arm-none-eabi-gdb/openocd pair in Geany. So as I understand, the "Scope Debugger plugin" (https://plugins.geany.org/scope.html) will do the job.

    RispondiElimina