4

I'm working with some Objective-C++ code that launches a background process from my main app. The background process has no GUI, only runs for a moment, and must be run from the main app for it to be useful. This means I can't easily attach to the background process with Xcode or run it stand-alone, so I need to rely on output to stderr.

In this scenario, where should I be looking to find the stderr output?

More information in case I'm asking the wrong question: I am using an old version of Xcode (3.2.6) for reasons related to the age of the project I'm maintaining. I'm working on exception handling/reporting code, which makes it difficult to step through the code since GDB likes to catch exceptions rather than letting my code do it. The background process is only launched when a structured exception occurs within the main app.

Excerpt of the results of the lsof command on my main app, might be relevant:

COMMAND   PID  USER       FD     TYPE  DEVICE   SIZE/OFF  NODE NAME
<appname> 2788 <username> 0r     CHR   3,2           0t0   311 /dev/null  
<appname> 2788 <username> 1w     CHR   3,2      0t473379   311 /dev/null  
<appname> 2788 <username> 2w     CHR   3,2     0x6d545f8   311 /dev/null
NSGod
  • 22,699
  • 3
  • 58
  • 66
Ben
  • 163
  • 1
  • 7
  • 2
    Have you looked in the Console (the app for which is found in "`/Application/Utilities/`"? – Michael Dautermann Apr 14 '14 at 18:44
  • 1
    @Michael Yes, the console is one of the places I've looked. I'm not sure where in the console I should expect to see the stderr output, since there are quite a few different logs/filters/files/etc. I don't even know if anything is being successfully written to stderr, since I don't know where I should expect it to be written. – Ben Apr 14 '14 at 19:02
  • @Ben: How is the background process launched? – Martin R Apr 14 '14 at 19:08
  • @MartinR The background process is launched by existing code in the framework I'm using. Essentially, the process is configured to run when it receives a mach message, then a message is sent to start it. – Ben Apr 14 '14 at 19:23
  • @Ben: If the daemon is launched by some custom code then it could be that stderr is redirected to /dev/null (and you have no chance to read it). – Martin R Apr 14 '14 at 19:28
  • See [this question](http://stackoverflow.com/questions/13104588/how-to-get-stdout-into-console-app). By the way, what's a "structured exception"? I've only heard that term on Windows. – JWWalker Apr 14 '14 at 19:31
  • @MartinR Presumably someone would have to intentionally redirect to /dev/null, and since the existing code already included several writes to stderr I doubt the author intentionally nullified their own debug writes. In the off chance that this was the case, how would I find out? – Ben Apr 14 '14 at 19:34
  • @JWWalker I may have used the wrong term, since I'm primarily a Windows developer. I mean segmentation violations, bus errors, illegal instructions, etc. – Ben Apr 14 '14 at 19:40
  • @Ben: Do you have the code that launches the background process? Do you have the code of the background process itself? – Martin R Apr 14 '14 at 19:42
  • @MartinR Yes, I have all the code you mentioned. – Ben Apr 14 '14 at 19:46

1 Answers1

2

You can use the lsof command to figure out where a particular file descriptor has been redirected:

lsof -a -p <your pid> -d 0,1,2

When a background process is launched usually the child proccess is attached to the same standard streams as the parent process. For normal Cocoa applications by default you should be able to see that output in Console.app under 'all messages' or 'console messages'.

Before Mountain Lion you could also view the output of launchd services there, but I believe since then launchd redirects stdout and stderr to /dev/null.


This means I can't easily attach to the background process with XCode or run it stand-alone

If you can run the main application from Xcode you should be able to set the debugger to attach to child processes it launches.

The Xcode debugger can also be told to wait for a particular process to launch and to attach to it.

bleater
  • 5,098
  • 50
  • 48
bames53
  • 86,085
  • 15
  • 179
  • 244
  • I'd love to run everything in the debugger, but it's too eager about trying to handle exceptions on its own. GDB won't let me get past exceptions I manually trigger, so I can't step through the code I'm trying to test. – Ben Apr 14 '14 at 20:09
  • @Ben You should be able to configure gdb to allow exception handling to occur normally. -- Yes, that `lsof` output says says stderr has been redirected to /dev/null, which means it's discarded rather than sent anywhere. – bames53 Apr 14 '14 at 20:39
  • I was struggling for a while to put the output of lsof into a nicely formatted comment, before realizing it can't be done... so I added it to my question. I believe the gist of what you're saying is that if the main app is directing stderr to /dev/null, child apps will do the same. I'm going to try to figure out how the redirect is being set. – Ben Apr 14 '14 at 20:42
  • @Ben Yep. Either make sure the parent sends its output somewhere useful, or you can go to where the child process is launched and specifically redirect its stderr to someplace useful. If you don't care how you get output from the program then another option would be to use the syslog API, instead of printing to stderr. – bames53 Apr 14 '14 at 20:46
  • Any idea where in an XCode (3.2.6) project the redirect would be set? Is /dev/null the default location unless I make a change somewhere? Sorry for the noobish questions, I don't have a ton of experience on OSX and I'm dealing with a massive blob of legacy code. – Ben Apr 14 '14 at 21:39
  • @Ben There are no setting in Xcode to produce a binary that redirects its output. Xcode would only control output redirection when the application is started by Xcode. That would be set somewhere around the same place you would set command line flags to pass to the program when starting it for debugging. – bames53 Apr 14 '14 at 23:58
  • 2
    As a side note for anyone trying to run an app from the terminal, running "open " will direct stdout/stderr to /dev/null since the process is detached from the terminal, while running the executable itself from within the package keeps the process running within the terminal (so the terminal displays text written to stderr/stdout). – Ben Apr 16 '14 at 17:57