how can I put a breakpoint on "something is printed to the terminal" in gdb?
Asked Answered
C

2

34

I would like to know from where inside a huge application a certain message is printed. The application is so big and old that it uses all conceivable ways of printing text to the terminal; for example printf(), fprintf(stdout, ...) etc.

I write to put a breakpoint on the write() system call but then I'm flooded with too many breakpoint stops because of various file I/O operations that use write() as well.

So basically I want gdb to stop whenever the program prints something to the terminal but at the same time I don't want gdb to stop when the program writes something to a file.

Crankpin answered 8/10, 2009 at 15:11 Comment(2)
See also How can I monitor what's being put into the standard out buffer and break when a specific string is deposited in the pipe?Militarism
Can't you just grep the source for that "something" that appears in the terminal, then place a breakpoint there?Bertina
L
37

Use a conditional breakpoint that checks the first parameter. On 64-bit x86 systems the condition would be:

(gdb) b write if 1==$rdi

On 32-bit systems, it is more complex because the parameter is on the stack, meaning that you need to cast $esp to an int * and index the fd parameter. The stack at that point has the return address, the length, buffer and finally fd.

This varies greatly between hardware platforms.

Leopoldine answered 8/10, 2009 at 15:20 Comment(3)
I messes around a bit with this and found that the FD number is availabe as "*(int)($esp+4)" and the string length as "(int)*(int)($esp + 12)" and finally the string data as "*(int)($esp + 8)". So for STDOUT you can do something like: break write if 1 == *(int)($esp+4) commands print (int)*(int)($esp + 12) x/s *(int)($esp + 8) end But when I tried to use this in practice on a huge application it turned out that this method is not foolproof because it doesn't handle redirects etc so if the app uses dup2() on stdout you might miss some stuff being printed to stdout.Crankpin
Here's a slightly more refined attempt: <pre> break write commands silent if !isatty(*(int)($esp + 4)) c end echo \ntty write(), size: x/d (int)($esp + 12) echo tty write(), data: x/s *(int)($esp + 8) end </pre>Crankpin
Fine. For anyone reading this just take in mind if your output is sent to STDERR then should be ´(gdb) b write if 2==$rdi´Divulsion
R
21

With gdb 7.0, you can set conditional breakpoint on syscall write():

(gdb) catch syscall write
Catchpoint 1 (syscall 'write' [4])
(gdb) condition 1 $ebx==1

$ebx contains first syscall parameter - FD number here

Roos answered 6/1, 2010 at 20:9 Comment(1)
Note: printf is buffered, so it may happen that you only see the write for the first printf on a second printf call concatenated up.Biosynthesis

© 2022 - 2024 — McMap. All rights reserved.