Hands-on Projects for the Linux Graphics Subsystem

The Virtual Address Space of the X Server and the Modules

Virtual address of the X server

As we previously noticed, in
section 3.2.2.5, backtraces show the virtual address of the X server, which is the current
process we examine, near the address 0x8048000. As we read from the Linux Documentation Project this is
the address that a Linux Process is Loaded:

It is a simple C program that prints ``hello world'' and then exits. The header describes it as an ELF image with two physical headers (e_phnum is 2) starting 52 bytes (e_phoff) from the start of the image file. The first physical header describes the executable code in the image. It goes at virtual address 0x8048000 and there is 65532 bytes of it. This is because it is a statically linked image which contains all of the library code for the printf() call to output ``hello world''. The entry point for the image, the first instruction for the program, is not at the start of the image but at virtual address 0x8048090 (e_entry). The code starts immediately after the second physical header. This physical header describes the data for the program and is to be loaded into virtual memory at address 0x8059BB8. This data is both readable and writeable. You will notice that the size of the data in the file is 2200 bytes (p_filesz) whereas its size in memory is 4248 bytes. This because the first 2200 bytes contain pre-initialized data and the next 2048 bytes contain data that will be initialized by the executing code.

where address is the address space in the process that it occupies, perms is a set of permissions:

r = read
w = write
x = execute
s = shared
p = private (copy on write)

offset is the offset into the file/whatever, dev is the device (major:minor), and inode is the inode on that device. 0 indicates that no inode is associated with the memory region, as the case would be with bss.

It may look strange that the shared library mapping in my Ubuntu system starts from virtual
address 0x110000, since more references on the subject place it at 0x40000000. Consider for
instance the following image from the Linux Journal:

Recent Linux distributions probably manage to make use of some of the unused space, just
below the memory address 0x8048000. Several backtraces can be found in the web that also use
address 0x110000 for loading shared libraries, for instance this link.
See also this link for a short explanation.

The shared libraries mapping

To capture the moment that a specific virtual memory region were assigned to a shared library we
use the strace utility. From the strace man page we read:

It intercepts and records the system calls which are called by a process and the signals which are received by a process.

As with the previous X Server debugging in section 3.2.2.5.1
we have to run strace remotely from another workstasion, otherwise the X Window frozes
(temporarily this time). Also since we have to observe the virtual memory mapping that take
place at the start of the X server we have to start a new X server. There are several ways to
do that, including the startx and xinit commands, I simply use the following from the command
line:

sudo /usr/bin/X :1

I use sudo because I need root privilege to start the X Server and also since this is the
second server in my system I use display 1. Previously with the following command:

ps xa | grep X

I had found the X server process' name /usr/bin/X.

To verify that the second server works fine I run:

xterm -display localhost:1.0

and using Ctrl+Alt+F8 I swap to the second display which naturally includes only the process we
started for this display, the xterm terminal. To return to the first display, if needed I
use the combination Ctrl+Alt+F7. From the xterm I run the scrot utility to
capture the second display contents, in order to illustrate them in the following image:

The second display uses no window manager

After verifying that the second X server works fine I use the kill command to terminate the
second X server and this time I start it remotely from the second machine using a telnet
client. From the command line to connect with my Linux laptop (192.168.1.101) I run:

telnet 192.168.1.101

and after logging in I run:

sudo strace -fo logfile /usr/bin/X :1

With the previous command I use strace to examine the system calls of the X server (/usr/bin/X) from the time the X server starts. The output is recorder to logfile. Since this is a big file I use the head
command to trim the first 200 lines of this as:

head -n 200 logfile > logfile1

Next I use the ps command to find the process id of the second X server:

ps xa | grep X

This was 2134 at the specific time.

I use from the first X server terminal the following command

sudo cat /proc/2134/maps > logfile2

which as we previously saw it shows among other the shared library mapping of the second server.

To examine the mapping of the address 0x110000 we could use the grep command as:

cat logfile1 | grep -B 3 110000
cat logfile2 | grep -B 3 110000

and see that at both files as expected at this address it is mapped the library libbz2.so.

Next we show the part of the logfile1 that include the address 0x110000 and also logfile2.
We use as case study libbz2.so the shared library mapped at the lower address in my system,
0x110000, to show the process of mapping libbz2.so at 0x110000 when the second X server started
(shown in logfile1) the actual mapping as appears for the second X server at current time
(logfile2).

Notice that the output of /proc/<pid>/maps is different from the previous at the start of the
current section, where at virtual address 0x110000 it was mapped libpciaccess.so instead of
libbz2.so. Each time we start a process the shared library mapping of the process is different.

mmap

To understand the process of mapping the shared libraries with the mmap system call, previously
we made use of the strace utility. The following text from
linuxquestions.org analyses the strace output:

analysis

The above example consists of 4 lines that can be analyzed like this:

open("/lib64/libexpat.so.1", O_RDONLY) = 6

This first line performs the syscall open on the file /lib64/libexpat.so.1. The file shall be opened read-only (O_RDONLY). This call returns the file descriptor 6. /lib64/libexpat.so.1 is now file number 6. You can get this information from man 2 open.