Skip to content

Instantly share code, notes, and snippets.

@kemlath
Last active April 1, 2019 04:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kemlath/7285356f97f67af5023cf99ee57317d6 to your computer and use it in GitHub Desktop.
Save kemlath/7285356f97f67af5023cf99ee57317d6 to your computer and use it in GitHub Desktop.
gdb 8.2.1 under Mojave

gdb has been more or less broken under OSX and was unusable under mojave, but there is hope...

This is description on how I got the latest release (dating fro 5.1.2019) up and running under mojave. In particular code signing has become more intricate under mojave since a debugger now needs the right entitlements not just a signature.

I'm assuming that a working gcc-8 installation is present (e.g. brew install gcc) and that a valid code signing certificate is in the SYSTEM keychain.

Here are the steps I took to get a working gdb:

1.) Download ftp://sourceware.org/pub/gdb/snapshots/current/gdb-8.2.50.20190105.tar.xz

2.) Build using GCC-8 and G++-8 NOT CLANG: Heres the shell command I used:

CC=gcc-8 CXX=g++-8 ./configure --prefix=/usr/local/opt/gdb/ --disable-debug --disable-dependency-tracking --enable-targets=all --with-python=/usr

If the build fails see "Caveats" below

3.) Codesign it with the right! entitlements:

codesign --entitlements gdb.xml -fs gdb_cert /usr/local/opt/gdb/bin/gdb

Important "gdb_cert" has to be a valid code signing cert from the SYSTEM keychain (login keychain won't do)

The entitlements in gdb.xml look like:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.security.cs.allow-jit</key>
    <true/>
    <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
    <true/>
    <key>com.apple.security.cs.allow-dyld-environment-variables</key>
    <true/>
    <key>com.apple.security.cs.disable-library-validation</key>
    <true/>
    <key>com.apple.security.cs.disable-executable-page-protection</key>
    <true/>
    <key>com.apple.security.cs.debugger</key>
    <true/>
    <key>com.apple.security.get-task-allow</key>
    <true/>
</dict>
</plist>

Not sure if all of them are needed... I stumbled upon the need for entitlement "com.apple.security.cs.debugger" while googling and ended up adding putting all of them in there in my despair.

You can check the entitlements via

codesign -d --entitlements - /usr/local/opt/gdb/bin/gdb

3.) Maybe optionally call (didn't help with gdb 8.2.1 form homebrew)

DevToolsSecurity -enable

In any case this should rid you from password entry prior to debugging

4.) Maybe optionally call (didn't help on Mojave with gdb 8.2.1 form homebrew but was nescessary under el Capitan)

sudo dseditgroup -o edit -a <your user name> -t user procmod

Which adds you to group procmod. It's just bcause only users in procmod can use function task_for_pid

5.) Enjoy ;)

Caveats:

1.) The compile initially fails because of some problems in gb/darwin-nat.c (some variables are double defined and that make gcc fail)

Patch darwin-nat.c as below to get rid of some compiler errors

--- ./gdb-8.2.50_working/gdb/darwin-nat.c	2019-01-05 19:51:48.000000000 +0100
+++ ./gdb-8.2.50.20190105/gdb/darwin-nat.c	2019-01-05 02:49:08.000000000 +0100
@@ -687,7 +687,7 @@
       /* Not a known inferior.  This could happen if the child fork, as
 	 the created process will inherit its exception port.
 	 FIXME: should the exception port be restored ?  */
-      // kern_return_t kret;
+      kern_return_t kret;
       mig_reply_error_t reply;

       inferior_debug
@@ -1125,14 +1125,14 @@

 	  if (!priv->no_ptrace)
 	    {
-	      pid_t pid_res;
+	      pid_t res;
 	      int wstatus;

-	      pid_res = wait4 (inf->pid, &wstatus, 0, NULL);
-	      if (pid_res < 0 || pid_res != inf->pid)
+	      res = wait4 (inf->pid, &wstatus, 0, NULL);
+	      if (res < 0 || res != inf->pid)
 		{
 		  printf_unfiltered (_("wait4: res=%d: %s\n"),
-				     pid_res, safe_strerror (errno));
+				     res, safe_strerror (errno));
 		  status->kind = TARGET_WAITKIND_IGNORE;
 		  return minus_one_ptid;
 		}
@@ -1148,7 +1148,7 @@
 		}

 	      inferior_debug (4, _("darwin_wait: pid=%d exit, status=0x%x\n"),
-			      pid_res, wstatus);
+			      res, wstatus);

 	      /* Looks necessary on Leopard and harmless...  */
 	      wait4 (inf->pid, &wstatus, 0, NULL);
@@ -1559,7 +1559,7 @@
          signaled thus darwin_decode_message function knows that the kill
          signal was sent by gdb and will take the appropriate action
          (cancel signal and reply to the signal message).  */
-      priv = get_darwin_inferior (inf);
+      darwin_inferior *priv = get_darwin_inferior (inf);
       for (darwin_thread_t *thread : priv->threads)
         thread->signaled = 1;

2.) (Not sure if this is important) The way gdb is built it links to the system python version. I've had difficulties in other programs unsing the system python and had python@2 from homebrew installed. Because python@2 overrides the system python I deleted the homebrew generated symlinks /usr/local/bin/python such that an application that calls python gets the system python version. You can then still call python2 for the homebre python@2 installation

@kemlath
Copy link
Author

kemlath commented Jan 6, 2019

There are still some intermittent failures in the gdb built from the above description.

The problem lies in the routine

static ptid_t
darwin_decode_message (mach_msg_header_t *hdr,
		       darwin_thread_t **pthread,
		       struct inferior **pinf,
		       struct target_waitstatus *status)

where wait4 is called twice for a terminating thread. The second call sometimes hangs because there is nothing left to wait for.
In line 1154 in darwin-nat.c I've changed the call from

wait4 (inf->pid, &wstatus, 0, NULL);
to
wait4 (inf->pid, &wstatus, WNOHANG, NULL);

WNOHANG means that wait4 does not block if there is nothing the wait for.

I've now tested this version of gdb from eclipse, the command line on C++ and fortran code and had no problems so far.

Here's the diff of my custom darwin-nat.c

--- ./gdb-8.2.50.20190105/gdb/darwin-nat.c	2019-01-05 02:49:08.000000000 +0100
+++ mojave_darwin-nat.c	2019-01-06 14:45:32.000000000 +0100
@@ -687,7 +687,7 @@
       /* Not a known inferior.  This could happen if the child fork, as
 	 the created process will inherit its exception port.
 	 FIXME: should the exception port be restored ?  */
-      kern_return_t kret;
+      // kern_return_t kret;
       mig_reply_error_t reply;
 
       inferior_debug
@@ -1119,52 +1119,60 @@
 	  return minus_one_ptid;
 	}
 
-      if (inf != NULL)
+  if (inf != NULL)
 	{
 	  darwin_inferior *priv = get_darwin_inferior (inf);
 
 	  if (!priv->no_ptrace)
-	    {
-	      pid_t res;
+	  {
+	      pid_t pid_res;
 	      int wstatus;
 
-	      res = wait4 (inf->pid, &wstatus, 0, NULL);
-	      if (res < 0 || res != inf->pid)
-		{
-		  printf_unfiltered (_("wait4: res=%d: %s\n"),
-				     res, safe_strerror (errno));
-		  status->kind = TARGET_WAITKIND_IGNORE;
-		  return minus_one_ptid;
-		}
-	      if (WIFEXITED (wstatus))
-		{
-		  status->kind = TARGET_WAITKIND_EXITED;
-		  status->value.integer = WEXITSTATUS (wstatus);
-		}
-	      else
-		{
-		  status->kind = TARGET_WAITKIND_SIGNALLED;
-		  status->value.sig = gdb_signal_from_host (WTERMSIG (wstatus));
-		}
-
-	      inferior_debug (4, _("darwin_wait: pid=%d exit, status=0x%x\n"),
-			      res, wstatus);
+	      pid_res = wait4 (inf->pid, &wstatus, 0, NULL);
+    	  if (pid_res < 0 || pid_res != inf->pid)
+    		{
+    		  printf_unfiltered (_("wait4: res=%d: %s\n"),
+    				     pid_res, safe_strerror (errno));
+    		  status->kind = TARGET_WAITKIND_IGNORE;
+    		  return minus_one_ptid;
+    		}
+
+    	  if (WIFEXITED (wstatus))
+    		{
+    		  status->kind = TARGET_WAITKIND_EXITED;
+    		  status->value.integer = WEXITSTATUS (wstatus);
+
+          inferior_debug (4, _("darwin_wait: TARGET_WAITKIND_EXITED pid=%d exit, status=0x%x\n"),
+  			      pid_res, wstatus);
+    		}
+    	  else
+    		{
+    		  status->kind = TARGET_WAITKIND_SIGNALLED;
+    		  status->value.sig = gdb_signal_from_host (WTERMSIG (wstatus));
+
+          if (WIFSIGNALED(wstatus))
+              inferior_debug (4, _("darwin_wait: TARGET_WAITKIND_SIGNALLED pid=%d exit, status=0x%x\n"), pid_res, wstatus);
+          else
+              inferior_debug (4, _("darwin_wait: TARGET_WAITKIND_WIFSTOPPED pid=%d exit, status=0x%x\n"), pid_res, wstatus);
+    		}
 
 	      /* Looks necessary on Leopard and harmless...  */
-	      wait4 (inf->pid, &wstatus, 0, NULL);
+        // On mojave gdb gets stuck here frequently
+        // --> WNOHANG -> Make sure it does not block if no pid wants to report
+	      wait4 (inf->pid, &wstatus, WNOHANG, NULL);
 
 	      inferior_ptid = ptid_t (inf->pid, 0, 0);
 	      return inferior_ptid;
 	    }
-	  else
+	    else
 	    {
 	      inferior_debug (4, _("darwin_wait: pid=%d\n"), inf->pid);
 	      status->kind = TARGET_WAITKIND_EXITED;
 	      status->value.integer = 0; /* Don't know.  */
 	      return ptid_t (inf->pid, 0, 0);
 	    }
-	}
-    }
+	 }
+  }
 
   /* Unknown message.  */
   warning (_("darwin: got unknown message, id: 0x%x"), hdr->msgh_id);
@@ -1559,7 +1567,7 @@
          signaled thus darwin_decode_message function knows that the kill
          signal was sent by gdb and will take the appropriate action
          (cancel signal and reply to the signal message).  */
-      darwin_inferior *priv = get_darwin_inferior (inf);
+      priv = get_darwin_inferior (inf);
       for (darwin_thread_t *thread : priv->threads)
         thread->signaled = 1;

@kemlath
Copy link
Author

kemlath commented Jan 6, 2019

I 've submitted the above to the gdb bug list:

https://sourceware.org/bugzilla/show_bug.cgi?id=24069

and added it as a comment to

https://sourceware.org/bugzilla/show_bug.cgi?id=22960

@lharland
Copy link

link is broken

@deepio
Copy link

deepio commented Apr 1, 2019

@leslieharland
All snapshots are public
https://sourceware.org/pub/gdb/snapshots/current/gdb-weekly-8.3.50.20190326.tar.xz

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment