Strace: Understanding Software Through Syscalls
We’re constantly running software that we don’t exactly understand. We know it does things, useful things, but now always how it gets the necessary information, or what effects it causes on our system. Is it from a file, deep within my hard drive? Is it from the operating system? Or is it fetching from the Internet?
And so, in comes ✨strace✨ . It’s a program that lets you trace (inspect) all the communication between a process and the Linux Kernel. This means you can monitor all the information that comes in and out of your process. It’s an invaluable tool for when a process is misbehaving, or to learn more about how things work.
Nelly Just read the source code. Most software in Linux is source available. It’s not that hard.
While the source code is the ultimate source of truth, it’s also very time consuming to read, if you even know how to read it, that is. Most of the time, we don’t care much about each individual instruction a program is doing, only what it’s reading and writing.
In this article, I intend to not only explain strace’s output format, but also to go through the entire output of tracing a regular program, explaining bit by bit of what’s going on. My hope is that you, the reader, will leave this article capable of parsing strace’s output to find what you’re looking for.
First, what does strace do?
Strace is a syscall tracer. It prints every syscall a process does. Without syscalls, a process is just a very complicated electric heater, so inspecting syscalls is crucial for understanding what it does.
A system call (abbreviated to syscall) is a request that programs make to the operating system (OS), which in this case is the Linux Kernel. The OS is responsible for managing all resources on a computer, so if a program wants to access any resource, it must ask the OS first.
You can think of a syscall as a function call to the OS. It has arguments and a
return value (always an integer). Reading files? open and read syscalls;
Writing files? open and write syscalls; Connecting to the internet? socket
and connect syscalls.
Running strace is very simple: strace [OPTIONS]... PROGRAM [ARGS].... So, for
tracing a program, like printf, you’d do strace printf "hello, world!".
Understanding the output
Let’s try running the line mentioned above: strace printf "Hello, wold!"
$ strace printf "Hello, world!"
execve("/usr/bin/printf", ["printf", "Hello, world!"], 0x7ffdaab444e8 /* 18 vars */) = 0
brk(NULL) = 0x55f320282000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=22731, ...}) = 0
mmap(NULL, 22731, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274be000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360w\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 896, 64) = 896
fstat(3, {st_mode=S_IFREG|0755, st_size=2145632, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9c274bc000
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 896, 64) = 896
mmap(NULL, 2169904, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f9c27200000
mmap(0x7f9c27224000, 1511424, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x24000) = 0x7f9c27224000
mmap(0x7f9c27395000, 454656, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x195000) = 0x7f9c27395000
mmap(0x7f9c27404000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x203000) = 0x7f9c27404000
mmap(0x7f9c2740a000, 31792, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f9c2740a000
close(3) = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9c274b9000
arch_prctl(ARCH_SET_FS, 0x7f9c274b9740) = 0
set_tid_address(0x7f9c274b9a10) = 2670
set_robust_list(0x7f9c274b9a20, 24) = 0
rseq(0x7f9c274b9680, 0x20, 0, 0x53053053) = 0
mprotect(0x7f9c27404000, 16384, PROT_READ) = 0
mprotect(0x55f2e229b000, 4096, PROT_READ) = 0
mprotect(0x7f9c27505000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
getrandom("\x2f\x77\x04\x87\x6d\xb5\xb8\xd2", 8, GRND_NONBLOCK) = 8
munmap(0x7f9c274be000, 22731) = 0
brk(NULL) = 0x55f320282000
brk(0x55f3202a3000) = 0x55f3202a3000
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=2998, ...}) = 0
read(3, "# Locale name alias data base.\n#"..., 4096) = 2998
read(3, "", 4096) = 0
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=258, ...}) = 0
mmap(NULL, 258, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274c3000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/gconv/gconv-modules.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=27010, ...}) = 0
mmap(NULL, 27010, PROT_READ, MAP_SHARED, 3, 0) = 0x7f9c274b2000
close(3) = 0
futex(0x7f9c2740972c, FUTEX_WAKE_PRIVATE, 2147483647) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_MEASUREMENT", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_MEASUREMENT", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=23, ...}) = 0
mmap(NULL, 23, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274c2000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_TELEPHONE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_TELEPHONE", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=47, ...}) = 0
mmap(NULL, 47, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274c1000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_ADDRESS", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_ADDRESS", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=127, ...}) = 0
mmap(NULL, 127, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274c0000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_NAME", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_NAME", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=62, ...}) = 0
mmap(NULL, 62, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274bf000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_PAPER", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_PAPER", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=34, ...}) = 0
mmap(NULL, 34, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274be000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_MESSAGES", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_MESSAGES", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_MESSAGES/SYS_LC_MESSAGES", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=48, ...}) = 0
mmap(NULL, 48, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274b1000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_MONETARY", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_MONETARY", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=270, ...}) = 0
mmap(NULL, 270, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274b0000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_COLLATE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_COLLATE", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=1406, ...}) = 0
mmap(NULL, 1406, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274af000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_TIME", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_TIME", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=3360, ...}) = 0
mmap(NULL, 3360, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274ae000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_NUMERIC", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_NUMERIC", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=50, ...}) = 0
mmap(NULL, 50, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274ad000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_CTYPE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_CTYPE", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=367708, ...}) = 0
mmap(NULL, 367708, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c27453000
close(3) = 0
fstat(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(0x88, 0), ...}) = 0
write(1, "Hello, world!", 13Hello, world!) = 13
close(1) = 0
close(2) = 0
exit_group(0) = ?
+++ exited with 0 +++ This was run on an x86_64 Arch Linux distribution.
Each line in the output is a syscall made by the program, printf. It has the
syscall name, the arguments, and the return value. If there was an error, it’ll
also helpfully append the
errno symbol to the end of
the line.
For example, the line
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
shows the syscall access, called with the arguments "/etc/ld.so.preload" and
R_OK, and returned -1, which means the file was not found.
An important detail: strace will print the syscall arguments after the syscall
is done. This means it will show the final value of any buffers or structs
modified by the kernel. This is important for syscalls like read and fstat,
which fills up the buffer passed to them as an argument.
This information is a great start, but this output just looks like a huge wall of text. It’s barely comprehensible. So what I’ll try to do here is break it down into smaller chunks and try to explain what’s going on. My hope is that you, the reader, will leave this article capable of understanding strace’s output as a whole, not line by line.
The exec
The first syscall is always exec. This is because strace will start tracing as
soon as the process forks, which happens before the accompanying exec. Here’s
the line for the syscall:
execve("/usr/bin/printf", ["printf", "Hello, world!"], 0x7ffdaab444e8 /* 18 vars */) = 0
fork? exec? What syscalls are those? fork requests the kernel to duplicate the current process. exec requests the
kernel to replace the current process with a different program, specified at the
path provided as the first argument.
So strace will clones itself with fork, and the process being traced will then
call exec to become the process we specified in the command line (in this
case, printf)
The Dynamic Linker (aka Runtime Loader)
The dynamic linker is in itself very complicated and very out of scope for this article, but it does make a lot of syscalls, which show up in strace. We’ll cover just the basics of it; enough to explain its syscalls.
Some libraries are so common that almost every sigle program depends on them (ex: libc). These libraries could be embeded into the programs, but that would cause almost every program running to have a duplicate of the same libary, wasting disk space and ram. Instead, what programs do is reference these libraries by name, but not include the actual code of the library. When the program starts, it executes a small subroutine that fetches the contents of library’s contents from the filesystem, loads them into the process’s address space, and fixes up any references to the library in the program to the correct addresses. This subroutine is the dynamic linker.
Do note that not all programs use the dynamic linker. A program with no runtime dependencies is called a static program, and does not invoke the dynamic linker.
With this in mind, let’s take a look at the output of strace that’s related to the dynamic linker:
brk(NULL) = 0x55f320282000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=22731, ...}) = 0
mmap(NULL, 22731, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274be000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360w\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 896, 64) = 896
fstat(3, {st_mode=S_IFREG|0755, st_size=2145632, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9c274bc000
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 896, 64) = 896
mmap(NULL, 2169904, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f9c27200000
mmap(0x7f9c27224000, 1511424, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x24000) = 0x7f9c27224000
mmap(0x7f9c27395000, 454656, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x195000) = 0x7f9c27395000
mmap(0x7f9c27404000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x203000) = 0x7f9c27404000
mmap(0x7f9c2740a000, 31792, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f9c2740a000
close(3) = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9c274b9000
arch_prctl(ARCH_SET_FS, 0x7f9c274b9740) = 0
set_tid_address(0x7f9c274b9a10) = 2670
set_robust_list(0x7f9c274b9a20, 24) = 0
rseq(0x7f9c274b9680, 0x20, 0, 0x53053053) = 0
mprotect(0x7f9c27404000, 16384, PROT_READ) = 0
mprotect(0x55f2e229b000, 4096, PROT_READ) = 0
mprotect(0x7f9c27505000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
getrandom("\x2f\x77\x04\x87\x6d\xb5\xb8\xd2", 8, GRND_NONBLOCK) = 8
munmap(0x7f9c274be000, 22731) = 0 This still looks like an incomprehensible wall of text, so let’s break it into smaller chunks:
brk(NULL) = 0x55f320282000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=22731, ...}) = 0
mmap(NULL, 22731, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274be000
close(3) = 0
The first thing it tries to do is load the ld.so.preload file, which is
missing, and then the ld.so.cache file, which is found and then mmaped into
memory. The ld.so.cache file assists the dynamic linker in finding the
location for the libraries it’ll later load.
mmap? From the point of view of a process, a memory page is a block of continuous non-overlapping memory (usually 4096 bytes or 0x1000, but can vary from system to system). There are more details regarding virtual memory but it’s out of scope for this article. When allocating/deallocating memory, the kernel doesn’t track individual bytes, only memory pages.
mmap is a system call
that allocates a new page to the process:
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);It has two modes relevant to this article: one for allocating file-backed pages,
and one for allocating anonymous pages. File-backed pages are initialized with
the contents of the file associated with the fd file descriptor, starting at
offset. Anonymous pages are zero-initialized and are not associated with any
file.
openat(AT_FDCWD, "/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360w\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 896, 64) = 896
fstat(3, {st_mode=S_IFREG|0755, st_size=2145632, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9c274bc000
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 896, 64) = 896
The dynamic linker will then start loading the libc.so.6 library located at
/usr/lib/. The first read will load the first 832 bytes of the file on a
buffer. This is a guess made by the glibc authors of how long the program
headers will be. Since libc is usually huge, 832 is not enough, so it later does
a pread call to load 896 bytes from the library, which is presumably the size
of all the necessary headers.
The fstat call reads some information about the library, most importantly the
file size, as it’ll be used soon. It then allocates 8192 bytes of memory (two
memory pages in my system) through mmap, presumably to store metadata about
the loaded libraries. Then, for some reason, it does another pread syscall to
a part of the library it previously read, which is beyond me.
TODO: CHECK WHY THERE ARE TWO SYSCALLS
mmap(NULL, 2169904, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f9c27200000
mmap(0x7f9c27224000, 1511424, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x24000) = 0x7f9c27224000
mmap(0x7f9c27395000, 454656, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x195000) = 0x7f9c27395000
mmap(0x7f9c27404000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x203000) = 0x7f9c27404000
mmap(0x7f9c2740a000, 31792, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f9c2740a000
close(3) = 0
These mmaps are part of the library loading process. The first mmap will map
the entire library into the process’s memory space, and the following mmaps
will adjust the necessary permissions for the segments of the library. Lastly,
it closes the library file.
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9c274b9000
arch_prctl(ARCH_SET_FS, 0x7f9c274b9740) = 0
set_tid_address(0x7f9c274b9a10) = 2670
set_robust_list(0x7f9c274b9a20, 24) = 0
rseq(0x7f9c274b9680, 0x20, 0, 0x53053053) = 0
These syscalls are reponsible for setting up the thread-local memory used for multithreading. It’s really specific stuff that’s not worth going too much into.
mprotect(0x7f9c27404000, 16384, PROT_READ) = 0
mprotect(0x55f2e229b000, 4096, PROT_READ) = 0
mprotect(0x7f9c27505000, 8192, PROT_READ) = 0
mprotect sets access protection to previously allocated memory pages. These
pages were previously allocated with write access, but are now being set to
read-only.
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
getrandom("\x2f\x77\x04\x87\x6d\xb5\xb8\xd2", 8, GRND_NONBLOCK) = 8
munmap(0x7f9c274be000, 22731) = 0
glibc localization
Not all programs will have this section.
brk(NULL) = 0x55f320282000
brk(0x55f3202a3000) = 0x55f3202a3000
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=2998, ...}) = 0
read(3, "# Locale name alias data base.\n#"..., 4096) = 2998
read(3, "", 4096) = 0
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=258, ...}) = 0
mmap(NULL, 258, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274c3000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/gconv/gconv-modules.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=27010, ...}) = 0
mmap(NULL, 27010, PROT_READ, MAP_SHARED, 3, 0) = 0x7f9c274b2000
close(3) = 0
futex(0x7f9c2740972c, FUTEX_WAKE_PRIVATE, 2147483647) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_MEASUREMENT", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_MEASUREMENT", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=23, ...}) = 0
mmap(NULL, 23, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274c2000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_TELEPHONE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_TELEPHONE", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=47, ...}) = 0
mmap(NULL, 47, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274c1000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_ADDRESS", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_ADDRESS", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=127, ...}) = 0
mmap(NULL, 127, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274c0000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_NAME", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_NAME", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=62, ...}) = 0
mmap(NULL, 62, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274bf000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_PAPER", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_PAPER", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=34, ...}) = 0
mmap(NULL, 34, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274be000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_MESSAGES", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_MESSAGES", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_MESSAGES/SYS_LC_MESSAGES", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=48, ...}) = 0
mmap(NULL, 48, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274b1000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_MONETARY", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_MONETARY", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=270, ...}) = 0
mmap(NULL, 270, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274b0000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_COLLATE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_COLLATE", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=1406, ...}) = 0
mmap(NULL, 1406, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274af000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_TIME", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_TIME", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=3360, ...}) = 0
mmap(NULL, 3360, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274ae000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_NUMERIC", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_NUMERIC", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=50, ...}) = 0
mmap(NULL, 50, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c274ad000
close(3) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_CTYPE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_CTYPE", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=367708, ...}) = 0
mmap(NULL, 367708, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9c27453000
close(3) = 0 The actual program
Until now, everything has just been initialization.
fstat(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(0x88, 0), ...}) = 0
write(1, "Hello, world!", 13Hello, world!) = 13
close(1) = 0
close(2) = 0
exit_group(0) = ?
asdasd
open(path, flags, mode): Opens a file located atpath, with modes and permissions described byflagsandmode. Returns a file descriptor to the file (a number that represents the open file) [^open_manpage].openat(dirfd, path, flags, mode): Same asopen, but the first argument is the file descriptor of a directory from where the path is relative to.[^open_manpage]read(fd, &buffer, len):