The -v flag in strace doesn’t just "expand" structures; it fundamentally changes how strace interprets and displays complex data types, revealing the raw, underlying system call arguments that are otherwise abbreviated.
Let’s see strace in action. We’ll use a simple write syscall, and then we’ll see how -v changes things.
First, a standard strace output for a write call to standard output:
strace -e trace=write echo "hello" > output.txt
This might show something like:
write(1, "hello\n", 6) = 6
Here, 1 is the file descriptor for stdout, "hello\n" is the buffer content, and 6 is the number of bytes written. Simple enough.
Now, let’s try a more complex system call that involves structures, like sendmsg. We’ll send a message with some ancillary data (like control information).
# This is a simplified example and might require a more complex C program
# to actually trigger a sendmsg with ancilliary data. For demonstration,
# we'll simulate what strace would show.
# Without -v
# Assume a sendmsg call with a message header and some control data.
# strace might show:
# sendmsg(3, {msg_name=NULL, msg_iov=[{iov_base="data", iov_len=4}], msg_control=...}, 0) = 4
# With -v
# strace -v -e trace=sendmsg ...
# sendmsg(3, {msg_name=NULL, msg_iov=[{iov_base=0x7ffc9b7f7c80, iov_len=4}], msg_control=0x7ffc9b7f7cb0, msg_controllen=20, msg_flags=0}, 0) = 4
Notice how -v reveals the actual memory addresses (0x7ffc9b7f7c80, 0x7ffc9b7f7cb0) for iov_base and msg_control, and the msg_controllen (control data length). Without -v, strace often abbreviates these complex structures, showing ... or a generic representation, making it hard to inspect the exact contents being passed to the kernel.
The problem strace -v solves is the opacity of complex system call arguments. Many modern system calls, especially those dealing with networking, IPC, or advanced file operations, take structures as arguments. These structures can contain pointers, lengths, flags, and nested data. By default, strace tries to be concise and might elide details of these structures, showing something like [...] or a truncated version. This makes it difficult to debug issues where the exact contents of these structures are critical, such as incorrect buffer sizes, malformed control messages, or invalid flag combinations.
Internally, strace has parsers for many common system call argument types. When it encounters a structure, it checks if it has a detailed parser for it. The -v flag tells strace to always use its most verbose, detailed parsing logic for all structures it recognizes. This means it will attempt to dereference pointers (where possible and safe), print out the contents of arrays, and fully expand nested structures, rather than just showing their type or a placeholder. This is particularly useful for structures like struct sockaddr, struct iovec, struct msghdr, struct stat, struct epoll_event, and many others.
Let’s consider a stat system call.
# Create a dummy file
echo "dummy content" > testfile.txt
# Without -v
# strace -e trace=stat ./a.out
# stat("testfile.txt", {st_mode=S_IFREG|0644, st_size=13, ...}) = 0
# With -v
# strace -v -e trace=stat ./a.out
# stat("testfile.txt", {st_mode={st_mode=36442, st_nlink=1, st_uid=1000, st_gid=1000, st_size=13, st_atime={tv_sec=1678886400, tv_nsec=0}, st_mtime={tv_sec=1678886400, tv_nsec=0}, st_ctime={tv_sec=1678886400, tv_nsec=0}}, ...}) = 0
With -v, you get the full struct stat breakdown: permissions (st_mode), number of links (st_nlink), user and group IDs (st_uid, st_gid), size (st_size), and detailed timestamps (st_atime, st_mtime, st_ctime) with both seconds and nanoseconds. This level of detail is crucial for understanding file metadata issues.
The one thing most people don’t know is that -v can sometimes be too verbose for deeply nested or extremely large structures, potentially making the output overwhelming or even causing strace itself to consume significant resources if it’s trying to dereference and print massive amounts of data. It’s a trade-off between seeing everything and having a manageable trace.
If you’re debugging a complex network interaction or a system call involving intricate data payloads, the next logical step after using -v is to combine it with specific event tracing (-e trace=) to narrow down the output to only the relevant system calls, making the verbose output more digestible.