How to Monitor What's Being Put into the Standard Out Buffer and Break When a Specific String Is Deposited in the Pipe

How can I monitor what's being put into the standard out buffer and break when a specific string is deposited in the pipe?

This question might be a good starting point: how can I put a breakpoint on "something is printed to the terminal" in gdb?

So you could at least break whenever something is written to stdout. The method basically involves setting a breakpoint on the write syscall with a condition that the first argument is 1 (i.e. STDOUT). In the comments, there is also a hint as to how you could inspect the string parameter of the write call as well.

x86 32-bit mode

I came up with the following and tested it with gdb 7.0.1-debian. It seems to work quite well. $esp + 8 contains a pointer to the memory location of the string passed to write, so first you cast it to an integral, then to a pointer to char. $esp + 4 contains the file descriptor to write to (1 for STDOUT).

$ gdb break write if 1 == *(int*)($esp + 4) && strcmp((char*)*(int*)($esp + 8), "your string") == 0

x86 64-bit mode

If your process is running in x86-64 mode, then the parameters are passed through scratch registers %rdi and %rsi

$ gdb break write if 1 == $rdi && strcmp((char*)($rsi), "your string") == 0

Note that one level of indirection is removed since we're using scratch registers rather than variables on the stack.

Variants

Functions other than strcmp can be used in the above snippets:

  • strncmp is useful if you want match the first n number of characters of the string being written
  • strstr can be used to find matches within a string, since you can't always be certain that the string you're looking for is at the beginning of string being written through the write function.

Edit: I enjoyed this question and finding it's subsequent answer. I decided to do a blog post about it.

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

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.

Is there a way to find out which function is printing to the terminal?

I usually augment my complex designs with various forms of output tracing. The particular item that applies here is the trace_prefix. For instance:

TRACE = True
# TRACE = False # Uncomment this line for production runs.

def func(param):
trace_prefix = "TRACE func" if TRACE else ""
if TRACE:
print("ENTER", func, "param =", param)

...
print(trace_prefix, func_data)
...

This produces output I can identify by "grep TRACE", as well as picking out the stream from a given routine or package. This is easy enough to parameterize (grab the function name); I've done it with a decorator.

Cannot get correct output from program redirected via pipe C++ (Windows)

Expanding on @Captain Obvlious's comment regarding flush:

The problem you are facing is because the WriteToPipe function does not flush at end of line. You can fix this in the reader by ensuring that you append to the previous string if the the previous ReadFromPipe call did not have a newline as the last character.

Modified functions:

bool ProcessManagement::BufferToQueue(std::stringstream &streamBuffer, char     delim, std::deque<std::deque<std::string>> &elems)
{
std::string line;
std::string word;
std::deque<string> row;

bool is_unflushed_line = streamBuffer.str().back() != '\n';

// Splitting the stringstream into queue of queue (does not work properly)
while (std::getline(streamBuffer, line))
{
std::istringstream iss(line);
while (std::getline(iss, word, delim)) {
row.push_back(word);
}
elems.push_back(row);
row.clear();
}
return is_unflushed_line;
}

void ProcessManagement::ReadFromPipe(void)
// Read output from the child process's pipe for STDOUT
{
DWORD dwRead, dwWritten;
char buffer[BUFSIZE];
BOOL bSuccess = FALSE;
std::deque<std::deque<std::string>> elems;

while (ReadFile(g_hChildStd_OUT_Rd, buffer, sizeof(buffer)-1, &dwRead, NULL) != FALSE)
{
/* add terminating zero */
buffer[dwRead] = '\0';
std::stringstream streamBuffer;
streamBuffer << buffer;
bool is_unflushed_line = BufferToQueue(streamBuffer, ' ', elems);

for(auto idx = 0; idx != elems.size(); ++idx)
{
for (std::string const& b : elems[idx])
std::cout << b;
if(idx == elems.size() - 1 && is_unflushed_line)
break;// don't print a newline if input did not end with a newline
std::cout << std::endl;
}
}
}

How can I set breakpoint in GDB for open(2) syscall returning -1

Is it possible to set breakpoint in GDB in such way that it stops after open(2) syscall returns -1?

It's hard to do better than n.m.s answer for this narrow question, but I would argue that the question is posed incorrectly.

Of course, I can grep through the source code and find all open(2) invocations

That is part of your confusion: when you call open in a C program, you are not in fact executing open(2) system call. Rather, you are invoking an open(3) "stub" from your libc, and that stub will execute the open(2) system call for you.

And if you want to set a breakpoint when the stub is about to return -1, that is very easy.

Example:

/* t.c */
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
int fd = open("/no/such/file", O_RDONLY);
return fd == -1 ? 0 : 1;
}

$ gcc -g t.c; gdb -q ./a.out
(gdb) start
Temporary breakpoint 1 at 0x4004fc: file t.c, line 6.
Starting program: /tmp/a.out

Temporary breakpoint 1, main () at t.c:6
6 int fd = open("/no/such/file", O_RDONLY);
(gdb) s
open64 () at ../sysdeps/unix/syscall-template.S:82
82 ../sysdeps/unix/syscall-template.S: No such file or directory.

Here we've reached the glibc system call stub. Let's disassemble it:

(gdb) disas
Dump of assembler code for function open64:
=> 0x00007ffff7b01d00 <+0>: cmpl $0x0,0x2d74ad(%rip) # 0x7ffff7dd91b4 <__libc_multiple_threads>
0x00007ffff7b01d07 <+7>: jne 0x7ffff7b01d19 <open64+25>
0x00007ffff7b01d09 <+0>: mov $0x2,%eax
0x00007ffff7b01d0e <+5>: syscall
0x00007ffff7b01d10 <+7>: cmp $0xfffffffffffff001,%rax
0x00007ffff7b01d16 <+13>: jae 0x7ffff7b01d49 <open64+73>
0x00007ffff7b01d18 <+15>: retq
0x00007ffff7b01d19 <+25>: sub $0x8,%rsp
0x00007ffff7b01d1d <+29>: callq 0x7ffff7b1d050 <__libc_enable_asynccancel>
0x00007ffff7b01d22 <+34>: mov %rax,(%rsp)
0x00007ffff7b01d26 <+38>: mov $0x2,%eax
0x00007ffff7b01d2b <+43>: syscall
0x00007ffff7b01d2d <+45>: mov (%rsp),%rdi
0x00007ffff7b01d31 <+49>: mov %rax,%rdx
0x00007ffff7b01d34 <+52>: callq 0x7ffff7b1d0b0 <__libc_disable_asynccancel>
0x00007ffff7b01d39 <+57>: mov %rdx,%rax
0x00007ffff7b01d3c <+60>: add $0x8,%rsp
0x00007ffff7b01d40 <+64>: cmp $0xfffffffffffff001,%rax
0x00007ffff7b01d46 <+70>: jae 0x7ffff7b01d49 <open64+73>
0x00007ffff7b01d48 <+72>: retq
0x00007ffff7b01d49 <+73>: mov 0x2d10d0(%rip),%rcx # 0x7ffff7dd2e20
0x00007ffff7b01d50 <+80>: xor %edx,%edx
0x00007ffff7b01d52 <+82>: sub %rax,%rdx
0x00007ffff7b01d55 <+85>: mov %edx,%fs:(%rcx)
0x00007ffff7b01d58 <+88>: or $0xffffffffffffffff,%rax
0x00007ffff7b01d5c <+92>: jmp 0x7ffff7b01d48 <open64+72>
End of assembler dump.

Here you can see that the stub behaves differently depending on whether the program has multiple threads or not. This has to do with asynchronous cancellation.

There are two syscall instructions, and in the general case we'd need to set a breakpoint after each one (but see below).

But this example is single-threaded, so I can set a single conditional breakpoint:

(gdb) b *0x00007ffff7b01d10 if $rax < 0
Breakpoint 2 at 0x7ffff7b01d10: file ../sysdeps/unix/syscall-template.S, line 82.
(gdb) c
Continuing.

Breakpoint 2, 0x00007ffff7b01d10 in __open_nocancel () at ../sysdeps/unix/syscall-template.S:82
82 in ../sysdeps/unix/syscall-template.S
(gdb) p $rax
$1 = -2

Voila, the open(2) system call returned -2, which the stub will translate into setting errno to ENOENT (which is 2 on this system) and returning -1.

If the open(2) succeeded, the condition $rax < 0 would be false, and GDB will keep going.

That is precisely the behavior one usually wants from GDB when looking for one failing system call among many succeeding ones.

Update:

As Chris Dodd points out, there are two syscalls, but on error they both branch to the same error-handling code (the code that sets errno). Thus, we can set an un-conditional breakpoint on *0x00007ffff7b01d49, and that breakpoint will fire only on failure.

This is much better, because conditional breakpoints slow down execution quite a lot when the condition is false (GDB has to stop the inferior, evaluate the condition, and resume the inferior if the condition is false).

Memory management for list of QObject* results in Cannot read property X of null errors in QML

For reasons explained by @samdavydov the Items in the Repeater stay during a model reset, but by unreferencing m_subModels the SubModels are deleted (because of the unique_ptr) and the views are invalidated because of the destroyed signal as you mention.

By swapping the two vectors during the reset, the old SubModels will stay a bit in memory, until the function exits, at which point the reset has already been completed and the new SubModels are being used:

void setSubModels(std::vector<std::unique_ptr<SubModel>> subModels)
{
beginResetModel();
m_subModels.swap(subModels);
endResetModel();
} //RAII deletes old SubModel at this point

With credit to yourself for finding the swap after my mention of keeping them in memory ;-)

How to debug with strace -i when everytime address is different

every time i run [b77d0424] changed to another address

This is happening because of address space layout randomization, which you can disable with setarch -R command.

GDB also disables address randomization by default, but the chance that the same address you'll get in GDB and under strace is quite small, as the execution environment under the two tools is quite different. You don't actually need to find the address under strace, you can find it in GDB:

  • catch syscall open
  • run

You are now looking at one of the open system calls your program does. Use continue until you stop at the one you are interested in. Now use info registers to find the address of the first parameter, and set a watchpoint on that address.



Related Topics



Leave a reply



Submit