Gdb: Redirect Target Stdout Temporarly

gdb: Redirect stdout without running the program


My intended workflow is:

Your intended workflow will not work: you can't call func1(...) without first running the program.

It appears that what you want is (roughly):

  1. start the program (runs to main).
  2. call func1(...) with its output redirected to a file.

This answer shows how to redirect the output wherever you want at an arbitrary point in program execution.

Invoke gdb to automatically pass arguments to the program being debugged

If you want to run some commands through GDB and then have it exit or run to completion, just do

echo commands | gdb X

If you want to leave it at the command prompt after running those commands, you can do

(echo commands; cat) | gdb X

This results in echoing the commands to GDB, and then you type into the cat process, which copies its stdin to stdout, which is piped into GDB.

LLDB redirect inferior stdout


(lldb) process launch -o /dev/null -- <OTHER ARGUMENTS>

will do what you want. You can also make an alias to do this:

(lldb) command alias silent-run process launch -o /dev/null --

then:

(lldb) silent-run a b c 

will run your program, redirect stdout to /dev/null, and pass a, b and c as arguments.

Showing the stack trace from a running Python application

I have module I use for situations like this - where a process will be running for a long time but gets stuck sometimes for unknown and irreproducible reasons. Its a bit hacky, and only works on unix (requires signals):

import code, traceback, signal

def debug(sig, frame):
"""Interrupt running process, and provide a python prompt for
interactive debugging."""
d={'_frame':frame} # Allow access to frame object.
d.update(frame.f_globals) # Unless shadowed by global
d.update(frame.f_locals)

i = code.InteractiveConsole(d)
message = "Signal received : entering python shell.\nTraceback:\n"
message += ''.join(traceback.format_stack(frame))
i.interact(message)

def listen():
signal.signal(signal.SIGUSR1, debug) # Register handler

To use, just call the listen() function at some point when your program starts up (You could even stick it in site.py to have all python programs use it), and let it run. At any point, send the process a SIGUSR1 signal, using kill, or in python:

    os.kill(pid, signal.SIGUSR1)

This will cause the program to break to a python console at the point it is currently at, showing you the stack trace, and letting you manipulate the variables. Use control-d (EOF) to continue running (though note that you will probably interrupt any I/O etc at the point you signal, so it isn't fully non-intrusive.

I've another script that does the same thing, except it communicates with the running process through a pipe (to allow for debugging backgrounded processes etc). Its a bit large to post here, but I've added it as a python cookbook recipe.

Xcode attach to process doesn't display NSLog

I can reproduce that with a simple test app, sans WatchKit. The app consists of a NSTimer that prints "Timer fired" every second. (This code is 100% correct ;). Nothing shows in the log after I have manually attached to the process.

As far as I know NSLog outputs to stderr, I guess attaching the debugger does not redirect stderr to the Xcode terminal.

If you are okay with using the console app or the terminal to look at your logs you can do that. iOS8 stores simulator logs in ~/Library/Logs/CoreSimulator/<Device-UUID>. In this directory you will find a system.log, which contains all your NSLog output.

You can look at it in terminal (cat, grep, tail), or open it in the Console.app.

Sample Image


Apple confirms that (at least for GDB) in Technical Note TN2239: iOS Debugging Magic.

Console Output

Many programs, and indeed many system frameworks, print debugging
messages to stderr. The destination for this output is ultimately
controlled by the program: it can redirect stderr to whatever
destination it chooses. However, in most cases a program does not
redirect stderr, so the output goes to the default destination
inherited by the program from its launch environment. This is
typically one of the following:

  • If you launch a GUI application as it would be launched by a normal
    user, the system redirects any messages printed on stderr to the
    system log. You can view these messages using the techniques described
    earlier.
  • If you run a program from within Xcode, you can see its
    stderr output in Xcode's debugger Console window (choose the Console
    menu item from the Run menu to see this window).

Attaching to a
running program (using Xcode's Attach to Process menu, or the attach
command in GDB) does not automatically connect the program's stderr to
your GDB window.
You can do this from within GDB using the trick
described in the "Seeing stdout and stderr After Attaching" section of
Technical Note TN2030, 'GDB for MacsBug Veterans'.

The mentioned TN2030 is no longer available on their server (mirror). It showed how you can redirect stdout and stderr to the Xcode console. However, since shell tty isn't a valid command for LLDB it won't help much. But maybe there is a different way to access the tty Xcodes console uses, so I attach the important part of that TN.

Seeing stdout and stderr After Attaching

If you attach GDB to a process (as opposed to starting the process
from within GDB), you won't be able to see anything that the process
prints to stdout or stderr. Programs launched by the Finder typically
have stdout and stderr connected to "/dev/console", so the information
they print goes to the console. You can view this by launching the
Console application (in the Utilities folder), however, it's
inconvenient to have to look in a separate window. Another alternative
is to connect the process's stdout or stderr to the terminal device
for GDB's Terminal window. Listing 9 shows how to do this.

Listing 9. Connecting stdout and stderr to GDB's terminal device.

(gdb) attach 795
[... output omitted ...]
(gdb) call (void) DebugPrintMenuList()
No output )-:

Close the stdout and stderr file descriptors.
(gdb) call (void) close(1)
(gdb) call (void) close(2)

Determine the name of the terminal device for GDB itself.
(gdb) shell tty
/dev/ttyp1

Reopen stdout and stderr, but connected to GDB's terminal.
The function results should be 1 and 2; if not, something
is horribly wrong.
(gdb) call (int) open("/dev/ttyp1", 2, 0)
$1 = 1
(gdb) call (int) open("/dev/ttyp1", 2, 0)
$2 = 2

Try the DebugPrintMenuList again.
(gdb) call (void) DebugPrintMenuList()
Yay output!
Index MenuRef ID Title
----- ---------- ---- -----
<regular menus>
00001 0x767725D3 -21629 Ed
00002 0x76772627 1128 <Apple>
00003 0x767726CF 1129 File
00004 0x76772567 1130 Edit
[... remaining output omitted ...]

Do containsAll() and retainAll() in the Collection interface address cardinality?

The javadocs for containsAll (in Collection) say:

Returns: true if this collection
contains all of the elements in the
specified collection

and for retainAll (in Collection):

Retains only the elements in this
collection that are contained in the
specified collection (optional
operation). In other words, removes
from this collection all of its
elements that are not contained in the
specified collection.

I read containsAll's contract to mean that calling a.containsAll(b) will return true, if and only if, calling a.contains(bElem) for each element bElem in b would return true. I would also take it to imply that a.containsAll(someEmptyCollection) would also return true. As you state the javadocs for AbstractCollection more explicitly state this:

This implementation iterates over the
specified collection, checking each
element returned by the iterator in
turn to see if it's contained in this
collection. If all elements are so
contained true is returned, otherwise
false.

I agree that the contact for Collection for containsAll sould be more explicit to avoid any possiblity for confusion. (And that the reading of the javadocs for AbstractCollection should NOT have been necessary to confirm ones understanding of Collection)

I would not have made an assumption with regard to number of duplicate elements after a call to retainAll. The stated contract in Collection (by my reading) doesn't imply either way how duplicates in either collection would be handled. Based on my reading of retainAll in collection multiple possible results of a.retainAll(b) are all reasonable:

  1. result contains 1 of each element that has at least one copy in both a and b
  2. result contains each element (including duplicates) that was in a, except those that are not in b
  3. or even, result contains somewhere between 1 and the number of copies found in a of each element in a, except those not in b.
    I would have expected either #1 or #2, but would assume any of the the three to be legal based on the contract.

The javadocs for AbstractCollection confirm that it uses #2:

This implementation iterates over this
collection, checking each element
returned by the iterator in turn to
see if it's contained in the specified
collection. If it's not so contained,
it's removed from this collection with
the iterator's remove method

Although since this isn't in my reading of the original Collection interface's contract, I wouldn't necessarily assume the behavior of Collection to generally be this way.

Perhaps you should consider submitting suggested updates to the JavaDoc once you're done.

As to 'why the Collection interface was left so ambiguous' - I seriously doubt it was intentionally done - probably just something that wasn't given its due priority when that part of the API's were being written.



Related Topics



Leave a reply



Submit