[Openmcl-devel] Debugging Carbon applications

Gary Byers gb at clozure.com
Fri Jan 28 02:14:08 PST 2005

On Thu, 27 Jan 2005, Clayton Wheeler wrote:

> David,
> On Jan 27, 2005, at 12:04 PM, David Steuber wrote:
> > [... Carbon ...]
> >
> > I'm still rather inexperienced with Lisp in general and OS X
> > development in particular.  If anyone has any tips on how I can
> > improve my process or has other information I may have missed that
> > would make trouble shooting easier, I would love to hear about it.
> Apple recently posted Tech Note 2124: Mac OS X Debugging Magic; about
> fifteen seconds into reading it, I said to myself "wow, this would have
> saved me a few weeks when I was writing Carbon and Apple Event stuff in
> OpenMCL..."
> It is here:
> http://developer.apple.com/technotes/tn2004/tn2124.html
> Cheers,
> --
> Clayton Wheeler
> csw at thirdshoe.net

One other Fun Fact that I didn't see mentioned in that TN:

If you "launch" a bundled OSX application (either by double-clicking
it or by using the "open" command in the shell), the program will
run with its standard ouput and error (file descriptors 1 and 2)
redirected to the console log (/dev/console; the Console application
provides a convenient way to view this output) and with file descriptor
0 redirected to /dev/null.

If you just run the executable inside the bundle (e.g., via something

shell> /path/to/MyApp.app/Contents/MacOS/dppccl


the standard file descriptors aren't redirected, so any debugging
output written to either of those file descriptors goes to the
terminal or Emacs shell buffer.  Perhaps more interestingly,
if you drop into OpenMCL's kernel debugger - which tries to
read input from standard input - you can poke around with
backtrace and register display commands, and maybe figure out
how you got there.)

A year or so ago, I wrote a little library/framework thing: if
you call some entrypoint in the library, it allocates a pty or
socket, runs a little Cocoa program with fd's 0,1,and 2 attached
to that pty or socket, and returns the file descriptor.  The little
Cocoa program waits for activity on its standard input before initializing
its GUI; any input it receives is displayed in a simple (and crude)
NSTextView, and anything typed into that text view is written to
fd 1 (connected to the socket/pty.)

If a client does something like:

(let* ((fd (open-library-and-call-entrypoint-whose-name-i-cant-remember)))
  (when fd	; if no error
    (#_dup2 fd 0)
    (#_dup2 fd 1)
    (#_dup2 fd 2)))

then any output to standard output/standard error (or *TERMINAL-IO*,
or a synonym-stream to it, unless it's been redirected somehow) will
get written to the little Cocoa program, and anything written by the
little Cocoa program will wind up on fd 0 in the client program.

If something else like this already exists, I'd be willing to believe
that that something else is better (the editing facilities that the
little Cocoa program provides are pretty primitive.)  If you don't
expect a GUI application to wind up in the kernel debugger and the
application violates those expectations, the little library/Cocoa
application provide enough of a UI to interact with the debugger
without having to add much code to the application, and if the
application doesn't generate debugging output the little Cocoa
application just stays in the background.

(The program/library is in CVS on clozure somewhere; if anyone's
interested, I'll try to remember where and provide further details.)

There are other (higher-level) ways of doing debugging in GUI applications
(and in servers); in at least some cases, those other ways could be
combined with the #_dup2 idea.  I'm not sure how well that idea would
work for things like SWANK/SLIME (IIRC, there's a sort of RPC protocol
going on there), but it might work for schemes that embed a simple
Telnet server in the application (or do something similar.)

More information about the Openmcl-devel mailing list