Saturday 6 August 2011

Debugging and stack traces on Mac OS X Lion

Mac OS X 10.7 Lion (really, Xcode 4) has changed the way that the system linker works in a way which makes debugging and interpreting stack traces difficult-to-impossible without special action.

From man ld,
Options when creating a main executable
-pie
This makes a special kind of main executable that is position independent (PIE).  On Mac OS X 10.5 and later, the OS the OS will load a PIE at a random address each time it is executed. You cannot create a PIE from .o files compiled with -mdynamic-no-pic. That means the codegen is less optimal, but the address randomization adds some security. When targeting Mac OS X 10.7 or later PIE is the default for main executables.
-no_pie
Do not make a position independent executable (PIE). This is the default, when targeting 10.6 and earlier.

With GNAT, as well as building with -g to keep debug symbols in the executable, you need to use the -E option to gnatbind to store an exception’s stack trace in the exception information. The result of Apple’s change is that you also need to link using -no_pie if you intend to use atos to interpret a stack trace, or gdb to debug your program. Without it,

failed in read/respond, Exception name: CONSTRAINT_ERROR
Message: ews-server-test.adb:133 explicit raise
Call stack traceback locations:
0x103712a31 0x103710110 0x103722d96 0x10370a98e 0x103709cb6 0x1037b50c6 0x7fff88fcc8bd

^C
$ atos -o ews-server-test 0x103712a31 0x103710110 0x103722d96 0x10370a98e 0x103709cb6 0x1037b50c6 0x7fff88fcc8bd
0x103712a31
0x103710110
0x103722d96
0x10370a98e
0x103709cb6
0x1037b50c6
0x7fff88fcc8bd

(in other words, nothing!) while with it,

$ gnatmake -P EWS -g -largs -Wl,-no_pie
$ ./ews-server-test
[...]
failed in read/respond, Exception name: CONSTRAINT_ERROR
Message: ews-server-test.adb:133 explicit raise
Call stack traceback locations:
0x10000aa31 0x100008110 0x10001ad96 0x10000298e 0x100001cb6 0x1000a30c6 0x7fff88fcc8bd
^C
$ atos -o ews-server-test 0x10000aa31 0x100008110 0x10001ad96 0x10000298e 0x100001cb6 0x1000a30c6 0x7fff88fcc8bd
ews__server__test__ajax_change.2355 (in ews-server-test) (ews-server-test.adb:133)
ews__dynamic__find (in ews-server-test) (ews-dynamic.adb:138)
ews__http__find (in ews-server-test) (ews-http.adb:472)
ews__server__respond (in ews-server-test) (ews-server.adb:206)
ews__server__serverTB (in ews-server-test) (ews-server.adb:124)
0x1000a30c6
0x7fff88fcc8bd

Edited 20.i.12 to mention the need for 'gnatbind -E’.
Edited 27.i.12 to mendion the need for 'gnatmake -g'.

7 comments:

  1. Hi Simon, thanks for this useful tip.
    But in my case there is no improvement, I get the same traceback:
    Exception name: CONSTRAINT_ERROR
    Message: stbga.adb:7 explicit raise
    Call stack traceback locations:
    stbga__p1.2247 (in stbga) + 30
    stbga__p2.2249 (in stbga) + 21
    _ada_stbga (in stbga) (stbga.adb:14)
    main (in stbga) (b~stbga.adb:264)

    Is there a way to get more useful information (all trace with file and line number)?

    Thanks, Pascal.

    ReplyDelete
    Replies
    1. Pascal, I hate to mention the obvious, but did you build with -g?
      Oops, I see I left that out of the example, will fix immediately.

      Delete
    2. Hi Simon, here is the complete example:
      with Ada.Text_IO; use Ada.Text_IO;
      -- with GNAT.Traceback.Symbolic; use GNAT.Traceback.Symbolic;
      -- with Exception_Information_Workaround;
      with Ada.Exceptions; use Ada.Exceptions;
      procedure STBGA is
      procedure P1 is
      begin
      raise Constraint_Error;
      end P1;
      procedure P2 is
      begin
      P1;
      end P2;
      begin
      P2;
      exception
      when E : others =>
      Put_Line ("----------------------------");
      -- Put_Line (Exception_Information_Workaround (E));
      -- Put_Line (Symbolic_Traceback (E));
      Put_Line (Exception_Information (E));
      Put_Line ("----------------------------");
      end STBGA;
      $ gnatmake -d -Pessais.gpr stbga.adb
      gcc -c -g -gnatwa -gnatf -gnateE -g -I- -gnatA stbga.adb
      gnatbind -E -I- -x stbga.ali
      gnatlink stbga.ali -g -Wl,-no_pie -o stbga
      $ ./stbga
      ----------------------------
      Exception name: CONSTRAINT_ERROR
      Message: stbga.adb:8 explicit raise
      Call stack traceback locations:
      0x100001898 0x100001a6b 0x1000018b4 0x100001862
      $ atos -o stbga -arch x86_64 0x100001898 0x100001a6b 0x1000018b4 0x100001862
      stbga__p1.2247 (in stbga) + 30
      stbga__p2.2249 (in stbga) + 21
      _ada_stbga (in stbga) (stbga.adb:15)
      main (in stbga) (b~stbga.adb:248)
      Is there something wrong?
      Thanks, Pascal.

      Delete
    3. Pascal,
      I compiled with
      $ gnatmake -f -g stbga.adb -bargs -E -largs -Wl,-no_pie
      gcc -c -g stbga.adb
      gnatbind -E -x stbga.ali
      gnatlink stbga.ali -g -Wl,-no_pie
      then atos gave
      stbga__p1.2211 (in stbga) (stbga.adb:8)
      stbga__p2.2213 (in stbga) (stbga.adb:12)
      _ada_stbga (in stbga) (stbga.adb:15)
      main (in stbga) (b~stbga.adb:194)
      so I don’t see where the difference is. Tried with GNAT GPL 2011 & GCC 4.6.0, both OK.
      ???

      Delete
    4. Hi Simon, interesting result indeed!
      On MacOSX 10.6.8, I've installed: Xcode 3.2.3 and GNAT GPL 2011 with binaries from libre.adacore.com. I get :
      $ gcc -v
      Using built-in specs.
      COLLECT_GCC=gcc
      COLLECT_LTO_WRAPPER=/usr/local/gnat-2011/bin/../libexec/gcc/x86_64-apple-darwin10.2.0/4.5.3/lto-wrapper
      Target: x86_64-apple-darwin10.2.0
      Configured with: ../src/configure --prefix=/usr/local/gnat --with-mpc=/Volumes/lena.a/gnatmail/release-gpl/build-lena/libmpfr/install --with-gmp=/Volumes/lena.a/gnatmail/release-gpl/build-lena/libmpfr/install --with-mpfr=/Volumes/lena.a/gnatmail/release-gpl/build-lena/libmpfr/install --build=x86_64-apple-darwin10.2.0 --enable-languages=c,ada,c++ --disable-nls --without-libiconv-prefix --disable-libmudflap --disable-libstdcxx-pch --disable-libada --enable-checking=release --enable-lto --with-bugurl=URL:mailto:report@adacore.com --with-build-time-tools=/Volumes/lena.a/gnatmail/release-gpl/build-lena/obj
      Thread model: posix
      gcc version 4.5.3 20110419 for GNAT GPL 2011 (20110419) (GCC)

      How do you get gcc 4.6.0 with GNAT GPL 2011?
      Would you advise me to update XCode?
      Thanks, Pascal.

      Delete
    5. Pascal,
      I’m using Lion, and I know things have changed since Snow Leopard, but not -- I thought -- that much.
      I talked about building GCC at http://forward-in-code.blogspot.com/2011/11/building-gcc-again.html, which includes a link to a 4.6.0 compiler - should work for you, I’m pretty sure it was built on Snow Leopard.
      I suppose it might be worth upgrading to Xcode 3.2.6, though no guarantees!

      Delete
    6. Hi Simon, I got it with XCode 3.2.6.
      atos have changed:
      -rwxr-xr-x 1 root wheel 72368 22 jan 2010 /usr/bin/atos*
      -rwxr-xr-x 1 root wheel 72368 24 oct 2010 /usr/bin/atos*
      And then:
      $ atos -o stbga -arch x86_64 0x100001898 0x100001a6b 0x1000018b4 0x100001862
      stbga__p1.2247 (in stbga) (stbga.adb:8)
      stbga__p2.2249 (in stbga) (stbga.adb:12)
      _ada_stbga (in stbga) (stbga.adb:15)
      main (in stbga) (b~stbga.adb:248)

      Many thanks, Pascal.

      Delete