Alexandru_Sutii_-_teza_diploma

advertisement
InspectOS - Extending Features for
Operating System Inspection
Supervisors:
Drd. Ing. Octavian Purdilă
As. Drd. Răzvan Deaconescu
Bachelor Thesis
Computer Science and Engineering Department
Automatic Control and Computers Faculty
University Politehnica of Bucharest
July 2011
Author:
Alexandru Șutîi
Abstract
Operating Systems are one of the most interesting Computer Science fields. In order to become an
excellent software engineer, one should have at least basic knowledge about the operating systems
concepts. However, for most of the students it is hard to understand many of them.
The most spread teaching technique is with repeated explanations of the low level mechanisms. As
there are some tools that inspect the processes for industrial purposes, there is a lack of educational
tools that would present the OS concepts dynamically to the students based on a given program.
InspectOS is coming to solve this problem. It is a useful educational tool that gathers information
about a traced process directly from the running operating system. It comes to extend the OS-Tool,
an application developed a year before by our colleagues Lucian Cojocar, Vlad Dogaru and Andrei
Buhaiu.
In this paper we shall present both the initial and the added features, however focusing more on the
design, the implementation and the testing of the newly added features.
Contents
InspectOS - Extending Features for Operating System Inspection ......................................................... 1
Abstract................................................................................................................................................... 2
Acronyms ................................................................................................................................................ 5
1
Introduction .................................................................................................................................... 6
1.1
InspectOS ................................................................................................................................ 6
2
Operating System Theory ............................................................................................................... 7
3
Architecture and Features .............................................................................................................. 9
4
3.1
Architecture ............................................................................................................................ 9
3.2
OS-Tool Features .................................................................................................................. 10
3.3
InspectOS New Features ....................................................................................................... 11
Implementation ............................................................................................................................ 12
4.1
Underlying Technology ......................................................................................................... 12
4.1.1
GTK ................................................................................................................................ 12
4.1.2
Graphviz and Cairo........................................................................................................ 12
4.1.3
GDB ............................................................................................................................... 12
4.2
Graphical User Interface Redesign ....................................................................................... 13
4.3
GDB Asynchronous Commands ............................................................................................ 16
4.3.1
Another Possible Implementation ................................................................................ 17
4.3.2
A Known Issue ............................................................................................................... 17
4.4
Thread Support ..................................................................................................................... 17
4.4.1
4.5
Process Standard Input ......................................................................................................... 19
4.5.1
4.6
Known Issues ................................................................................................................ 20
Process Standard Output ...................................................................................................... 20
4.6.1
The First Failed Approach – Redirect the Process Output ............................................ 20
4.6.2
The Second Failed Approach – Parse the GDB Output ................................................. 20
4.6.3
The Final Solution ......................................................................................................... 20
4.7
5
Problems encountered ................................................................................................. 19
Variable Value Display .......................................................................................................... 22
Test Scenarios ............................................................................................................................... 23
5.1
Compiling and Tracing a Process .......................................................................................... 23
5.2
Unit Tests .............................................................................................................................. 23
5.2.1
Memory Management .................................................................................................. 23
6
7
5.2.2
File Descriptor Table ..................................................................................................... 24
5.2.3
Asynchronous Commands ............................................................................................ 25
5.2.4
Thread Support ............................................................................................................. 25
5.2.5
Process Output ............................................................................................................. 28
5.2.6
Process Input ................................................................................................................ 28
User Feedback .............................................................................................................................. 29
6.1
InspectOS Developers’ Feedback.......................................................................................... 29
6.2
Feedback from the OS-Tool Developers and our Supervisors .............................................. 29
6.3
Feedback from Students ....................................................................................................... 30
Conclusions and Future Plans ....................................................................................................... 31
A. Compiling, Installing and Running InspectOS ................................................................................... 32
System Requirements ....................................................................................................................... 32
Installation ........................................................................................................................................ 32
Cloning the repository .................................................................................................................. 32
Installing auxiliary packages ......................................................................................................... 32
Running InspectOS ............................................................................................................................ 32
Tracing a process .............................................................................................................................. 33
B. InspectOS Repository Description .................................................................................................... 34
References ............................................................................................................................................ 35
Acronyms
OS – Operating System
COW – Copy-On-Write
VMA – Virtual Memory Area
FDT – File Descriptor Table
GDB – GNU Debugger
GUI – Graphical User Interface
PID – Process Identifier
TID – Thread Identifier
Alexandru Șutîi
1 Introduction
An Operating System is a set of software programs and data that runs on a computer, manages the
computer hardware and provides common services for the application software [1]. The main goal
of an operating system is the hardware abstraction for the running processes. In order to do this an
operating system has a series of management mechanisms for every hardware resource type.
The main features of an operating system are:






Process management
Memory management
File system management
Networking
I/O
Security
In this paper I am presenting the InspectOS, a tool that provides dynamic information about some of
the most important above mentioned mechanisms: process management, memory management,
file system management.
1.1 InspectOS
InspectOS is a continuation of the project called OS-Tool developed by our colleagues Lucian
Cojocar, Vlad Dogaru and Andrei Buhaiu in 2010. They have designed the basic structure and worked
hard on the information gathering, processing and on presentation. They have done a great work,
but there were needed a series of improvements. Therefore we, Alexandru Șutîi and Radu Velea,
continued the project development, calling it InspectOS this year. As it is described later in the
Architecture and Features and Implementation chapters we have added a series of features and
performed some refactoring and redesign in the user space modules.
InspectOS – Extending Features for Operating System Inspection
2 Operating System Theory
In order to better understand the way InspectOS works and the concepts it is describing you have to
be presented some basic operating systems theory. I will present the concepts, their definition and a
short explanation.




Process - an instance of a computer program that is being executed. It contains the program
code and its current activity. Depending on the operating system (OS), a process may be
made up of multiple threads of execution that execute instructions concurrently [3]. A
process has an independent address space, a file descriptor table, a process id, etc.
Thread - In computer science, a thread of execution is the smallest unit of processing that
can be scheduled by an operating system. It generally results from a fork of a computer
program into two or more concurrently running tasks. The implementation of threads and
processes differs from one operating system to another, but in most cases, a thread is
contained inside a process. Multiple threads can exist within the same process and share
resources such as memory, while different processes do not share these resources. [4]
Differences between a process and a thread - Threads differ from traditional multitasking
operating system processes in that [4]:
o Processes are typically independent, while threads exist as subsets of a process
o Processes carry considerable state information, whereas multiple threads within a
process share state as well as memory and other resources
o Processes have separate address spaces, whereas threads share their address space
o Processes interact only through system-provided inter-process communication
mechanisms.
o Context switching between threads in the same process is typically faster than
context switching between processes.
Virtual memory - virtual memory is a memory management technique developed for
multitasking kernels. This technique virtualizes a computer architecture's various
hardware memory devices (such as RAM modules and disk storage drives), allowing
a program to be designed as though [5]:
o


There is only one hardware memory device and this "virtual" device acts like a RAM
module.
o The program has, by default, sole access to this virtual RAM module as the basis for
a contiguous working memory (an address space).
Demand paging - demand paging (as opposed to anticipatory paging) is an application of
virtual memory. In a system that uses demand paging, the operating system copies a disk
page into physical memory only if an attempt is made to access it (i.e., if a page fault
occurs). It follows that a process begins execution with none of its pages in physical
memory, and many page faults will occur until most of a process's working set of pages is
located in physical memory [8].
Copy-On-Write - Copy-on-write (sometimes referred to as "COW") is an optimization
strategy used in computer programming. The fundamental idea is that if multiple callers ask
for resources which are initially indistinguishable, they can all be given pointers to the same
resource. This function can be maintained until a caller tries to modify its "copy" of the
Alexandru Șutîi


resource, at which point a true private copy is created to prevent the changes becoming
visible to everyone else. All of this happens transparently to the callers. The primary
advantage is that if a caller never makes any modifications, no private copy need ever be
created. [9]
File Descriptor - In computer programming, a file descriptor is an abstract indicator for
accessing a file. Generally, a file descriptor is an index for an entry in a kernel-resident data
structure containing the details of all open files. In POSIX this data structure is called a file
descriptor table, and each process has its own file descriptor table. The user application
passes the abstract key to the kernel through a system call, and the kernel will access the
file on behalf of the application, based on the key. The application itself cannot read or write
the file descriptor table directly [6].
Virtual Memory Area - The virtual memory area (VMA) is the kernel data structure used to
manage distinct regions of a process's address space. A VMA represents a homogeneous
region in the virtual memory of a process: a contiguous range of virtual addresses that have
the same permission flags and are backed up by the same object (a file, say, or swap space).
It corresponds loosely to the concept of a "segment," although it is better described as "a
memory object with its own properties." [7].
InspectOS – Extending Features for Operating System Inspection
3 Architecture and Features
3.1 Architecture
InspectOS was designed with a high degree of modularity as can be seen in Figure 1. This approach is
better suited for parallel development and for efficient sustainment.
The four main modules are as follows:




The Gathering Module – This is the module that is responsible with gathering the
information about the traced process directly from the Operating System. It collects data
about the VMA structures, the File Descriptor Table and the Virtual and Physical Memory
pages. The data is presented to the user space via a procfs interface.
The Information Processing Module – As the GUI and Process Tracing modules, it is written
entirely in Python. The main purpose of this Processing Module is to take the information
from the Gathering Module via the procfs interface and transform in an easy presentable
way for the GUI module.
The GUI module – Displays the processed process information in a friendly way. Each
process is presented in its container with several panes displaying specific type of
information. The GUI also interacts with the Process Tracer for both sending commands to
the process and retrieving certain information about the process state.
Process Tracer – This is an interface for manipulating the process run state. It is a wrapper
over GDB and uses expect for interaction with GDB. It gives the opportunity to step the
process, provide process input and retrieve line information, process output and variable
values.
Alexandru Șutîi
Figure 1 - InspectOS Architecture Diagram
3.2 OS-Tool Features
As mentioned above OS-Tool is the application InspectOS began from. The architecture was
designed in OS-Tool and InspectOS came to improve the application with new features. The features
that OS-Tool already had are the following:




Virtual and Physical Pages – The application displays the table of virtual and physical pages
and show the correspondence between a virtual page and the physical frame it is mapped
on. Also it notifies whenever a Copy-On-Write or a Demand Paging event occurs.
File Descriptor Table – For the traced process you have the opportunity to visualize the open
file descriptors and the type of the open files.
VMA Tree – The red-black Virtual Memory Area Tree can be found in the VMA pane.
Source code visualization – Whenever a process is traced, its source code is displayed. By
pressing the Next button you can advance the process an instruction at a time.
InspectOS – Extending Features for Operating System Inspection
3.3 InspectOS New Features
InspectOS main purpose was to improve the graphical user interface in order to make it more
intuitive for beginners and extend the OS-Tool by developing new features.
Below you can see a list of new features we have developed:








GUI Redesign – In OS-Tool the GUI was divided in components displaying a specific resource.
For example, whenever a new process was created a new widget was added for each the
Source Code, Memory, File Table and VMA containers, rather than adding a container
encapsulating all above mentioned widgets. Therefore we redesign GUI so a better per
process encapsulation could be achieved.
Support for blocking instructions – If the traced process happened to block at a specific
instruction (e.g. an I/O instruction) the application used to freeze until the instruction was
finished. To avoid this situation we had to redesign the Process Tracer to make it use
asynchronous GDB commands for manipulating the traced process.
“Back” Feature – This feature is meant to memorize the states the process passed through
and give the opportunity to restore a previous state of the traced process.
Process Input – The GUI displays a container for each traced process that allows introducing
text that would be sent to process on its standard input.
Process Output – Also the GUI displays a container that shows the output of the traced
process.
Process Tree – This feature helps the user to visualize in a tree form the processes created
by the traced process. The user can select any of the created processes and see details
about its state.
Command line arguments – InspectOS is able to run the program with the given command
line arguments. The user is displayed a text field that allows him/her to introduce them.
Action Logging – At the button of the main window there appears a text area that displays
all user actions and the events.
Alexandru Șutîi
4 Implementation
4.1 Underlying Technology
The InspectOS modules are build using some libraries and tools. I will emphasize on the description
of the technology used by the user space modules, as our work in InspectOS was mainly oriented to
improvement of this parts.
4.1.1 GTK
All the Graphical User Interface was developed using a Python binding of GTK library called pyGTK.
This is a ubiquitous library on Linux. Although it contains the basic needed widgets, it lacks more
sophisticated widgets for drawing pages, graphs, trees, etc. Therefore some other graphical libraries
had to be added for displaying this kind of structures.
4.1.2 Graphviz and Cairo
For drawing the physical and virtual memory tables, Cairo was chosen. It has the necessary methods
for drawing this kind of structures. Graphviz is the tool used for drawing graphs. The input graph is
given in its specific description language and it provides an output image displaying the graph. That
image is taken by our GUI and displayed in a frame.
4.1.3 GDB
In order to manipulate the traced process we implemented our tracer over the known GNU
debugger GDB.
For every traced process we create a GDB instance [10]. If the process forks new processes they
remain in the same GDB instance. The Tracer module sends the GDB commands via the Expect
interface. Expect is implemented in TCL programming language for interacting with running
processes (in this case GDB). The tracer gets the GDB response via Expect, too, and takes the
appropriate action.
InspectOS – Extending Features for Operating System Inspection
4.2 Graphical User Interface Redesign
The OS-Tool developers chose a bottom up development mode, i.e. they first of all thought how to
gather and organize the information about the traced process from the OS, and only after that they
came with a way to display this information in the user interface. In consequence, the GUI was not
as intuitive for the beginners as it should be for an educational application. When we began working
on InspectOS our first goal was to redesign the user interface so that it was easier to understand and
encapsulate all the process data in the same graphical container.
In Figure 2 you can see the diagram of the OS-Tool GUI and Figure 3 displays a screenshot of the
graphical user interface. As you can see, the main window contained five main containers: the
source container, the VMA container, the memory container, the file descriptor table container and
the “Next” buttons container.
Figure 2 OS-Tool GUI Design
Alexandru Șutîi
Whenever a new process was spawned by the fork() system call, new frames were added to Source
and Memory containers and a new “Next” button was created. Also the VMA and File Table tabs
showed only the last process’s table.
Figure 3 OS-Tool Graphical User Interface
We did not find this interface well organized and we decided to have a better per process
organization. Therefore we reorganized the GUI as seen in the UML diagram from Figure 5 and in
the screenshot from Figure 4.
Figure 4 - InspectOS Screenshot
InspectOS – Extending Features for Operating System Inspection
The window contains two main frames. The frame in the right displays the physical memory. It
displays the physical memory frames for all the traced processes. In the right frame there is a pane
that allows the visualization of maximum two processes at the same time (you can select the
processes to view). All of the process resources are encapsulated in the same container.
The whole window is created in the Main class. When first opening the application, it displays a form
that prompts for the program to trace. For the each newly created process the Main object creates a
ProcessView object. This object encapsulates all the process information and returns a frame to be
displayed by Main. The Main object creates a VMA, a COW and a FileTableTab object and passes
these objects to all the new created ProcessView Objects. Also all the child processes created from a
traced process share the same Tracer object as they all of them reside in the same GDB session.
Whenever the ProcessView object has to display its frame, it gets its virtual memory table frame
from the COW object, its file descriptor table from the FileTableTab object and the VMA frame from
the VMA objects, by passing them its process id. Also it adds to the process frame the source, the
standard input and output frames.
Figure 5 - InspectOS New GUI Design
Alexandru Șutîi
4.3 GDB Asynchronous Commands
At the beginning the process tracer used only synchronous commands for interactions with GDB. It
worked well as long as there was no blocking instruction in the traced process, such as I/O
operations, synchronization object operations (semaphores, mutexes, waiting queues). When the
user was pressing the “Next” button, the tracer waited for the GDB response. If the process had
blocked in an instruction, the GUI thread also blocked, therefore the whole application was getting
frozen.
We had a lot of time searching the web for a solution to this problem. However, we did not find a
solution. So we wrote an email to the GDB users list to ask for help. This way we found out about
the GDB asynchronous commands.
So we have redesigned the tracer to send asynchronous commands and interrogate the status in
order to see if the current instruction ended. The detailed flow can be seen in the Figure 6. When
stepping the process the “step&” command is sent to GDB. The GDB prompt immediately returns as
this is an asynchronous command. In order to check the actual state of the process, the tracer sends
the “where” command. If the response contains the string “Target is executing” it means the
process is still blocked in the stepped instruction. To be sure that a non blocking instruction is not
perceived as blocking, the tracer waits 0.5 seconds before requesting the status. In this time the non
blocking instruction will end for sure.
Figure 6 - GDB asynchronous command flow
When the tracer announces that process is blocked, the GUI changes the “Next” button’s caption to
“Blocked” for a small amount of time. The next time the user presses “Next”, the tracer will check
again whether process is still blocked or not.
InspectOS – Extending Features for Operating System Inspection
In order to prepare GDB for asynchronous commands we have to input the following command
when starting the GDB instance:
> gdb ./program
[…]
(gdb) set target-async on
4.3.1 Another Possible Implementation
For the first time we thought to create a separate thread whenever a process got blocked. This
thread would have had to send “where” or “info program” commands in order to check whether the
process unblocked, and after that update the “Next” button’s state. We have renounced this idea as
adding multithreading to the application would have added a lot of new problems regarding thread
synchronization. Furthermore, this would have forced us to implement a safe access to the GDB
session. This would have been a bad idea, as we found a lot of bugs in GDB and this feature would
have revealed a lot more. Also it would have increased the used processing power.
4.3.2 A Known Issue
We have found a bug related to GDB asynchronous commands that we could not solve. The scenario
is as follows. Say we have a process A that blocks in reading from a pipe. The process B has to write
something in that pipe, causing the process A to unblock. However if we step the process B a few
times, but not enough that it would get to the instruction that will write in the pipe, and we step
again the process A (that is being blocked in the read instruction), the GDB sends a SIGKILL signal to
both the processes.
In order to solve this issue, we tried to get the process’s blocking state before sending a “step&” to it
again. But this approach was unsuccessful, as GDB takes all the debugged processes into the
“Stopped” state (stopped at a breakpoint), rather than leaving the blocked processes in “Sleeping”
state. Therefore, we could not find out the status of a process without resending the “step&”
command to it. The same problem occurs with multiple threads in the same situation.
4.4 Thread Support
An interesting and a challenging feature we came with, is the thread support. We first of all thought
that it would be useful for the users to visualize on real examples, problems like producerconsumer.
Threads in a process share the same address memory, the same VMA and the same file descriptor
table. The only private properties and resources of a thread are: the stack, the registers, current line
number (this is actually also stored in a register), the thread private data. Therefore we didn’t need
to change the memory, VMA and file table views as they are the same for all the threads in a
process.
Alexandru Șutîi
Figure 7 - Thread Diagram
We chose to display the line number for each thread and the variable values. Also InspectOS is able
to step each thread.
For every time a new thread is created, GDB announces this and the ProcessView object adds a new
entry for the newly created thread. The entry contains a thread id, a line number and a next button.
You can find a diagram in the Error! Reference source not found. and a screenshot of how the GUI
looks like. The thread TID is displayed in the left of its current line. Whenever the “Next” button is
pressed the tracer gets the TID of the thread, switches the thread number in GDB and sends the
“step&” command.
InspectOS – Extending Features for Operating System Inspection
Figure 8 - Thread Screenshot
As I have mentioned in the previous section, the thread support meets the same issue as for the
situation when there are more processes open. You have to step a thread until it unblocks another
before stepping the blocked thread again. Otherwise, GDB will kill all the threads.
We focused first of all on making the thread support feature work for the producer-consumer
problem. Therefore we have not tested it much for processes that both create processes and
threads.
4.4.1 Problems encountered
Whenever the process being debugged creates a new thread or process the GDB notifies by saying
“New process/thread created”. So to step a specific thread/process you have to switch to that
thread by entering the command “thread thread_no”. When you step a process, all the other
processes in the GDB session stay stopped.
However, GDB was not performing the same with the threads. Whenever you step a thread, the
other threads of that process begin running as well. So we had to figure out how to make them stay
stopped. In order to solve this problem we have to enter the following commands:
> gdb ./program
[…]
(gdb) run …
(gdb) set scheduler-locking on
[…]
Alexandru Șutîi
4.5 Process Standard Input
In its initial stage InspectOS was not designed to interact in any way with the traced process.
Therefore, we considered it necessary to provide a means to interact with the process’s input and
output and to pass the process with initial command line arguments.
In order to send input to the process, we have tuned the GUI and the Tracer modules. You can see a
diagram in the Error! Reference source not found.. In the GUI we added a frame that provides a text
box where the user can input the text and submit it.
Figure 9 - Input Flow
In order to make the process receive our input we had to redirect its standard input from a named
pipe. When the process is to be traced, InspectOS creates a named pipe. After this, it creates a GDB
session for the given process with the following commands:
> touch named_pipe
> gdb ./process
[…]
(gdb) run < named_pipe
When the user inserts some text in the input frame, the GUI sends the text to the Tracer by calling
its send_text() method with the text as an argument. The Tracer opens the write edge of the named
pipe and writes the text to it.
4.5.1 Known Issues
This approach is the only one we have thought of. Although, it works well for most of the cases, it
has some drawbacks.
If a process creates more processes with fork() system calls, all the spawned processes have the
same named pipe redirected to the standard input. Therefore, the user has to be careful that the
given text goes to the intended process. Moreover, if a process performs a read from the input, it
flushes all data from the pipe, even if it does not need the whole of it.
InspectOS – Extending Features for Operating System Inspection
4.6 Process Standard Output
4.6.1 The First Failed Approach – Redirect the Process Output
We have had a lot of headaches developing this feature. First time we thought to implement it the
easy, and we though the normal, way: by redirecting the output to a named pipe, and reading it
from the pipe, as we did with the standard input.
We realized that GDB has several ways of flushing the output for de debugging process. If you debug
the program without redirecting the output (its output is displayed in the terminal), GDB flushes
every line to the terminal every time the process outputs a new line. However, when redirecting the
output to a file, GDB realizes that this is not a terminal and flushes blocks of data, i.e. it buffers many
lines, and flushes them when the buffer is full. As a result we didn’t get the output from the pipe
immediately after it was written. So we renounced this solution.
4.6.2 The Second Failed Approach – Parse the GDB Output
The second approach was not very reliably, however it worked for most of the situations. This time
the Tracer was parsing the GDB output. We implemented a way to differentiate between the output
of the GDB commands and the output of the traced process. In most of the cases the GDB
commands’ output was following an easy patter so we could easily differentiate it. However things
got worse when we implemented the support for blocking instructions, i.e. using the GDB
asynchronous commands. The GDB output began to be less organized and we were failing to
differentiate the process output very well. Therefore, we thought to the last and the good solution
presented in the next section.
4.6.3 The Final Solution
We have found that there is a way to redirect the GDB output to a file, i.e. the output of the GDB
commands, while the output of the process being debugged is displayed in the terminal. This way
we do not have to parse the GDB output, we now know that we can get the process status (current
line, running status, etc.) from the redirected file, and in the terminal we get the pure output of the
process.
In order to enable this behavior we give the following GDB commands at the beginning of the debug
session:
> gdb
(gdb)
(gdb)
(gdb)
./program
set logging redirect on
set logging file redirect_file
set logging on
Whenever the “Next” button is pressed, the ProcessView object calls the step() method of the
Tracer by passing the process id. The Tracer sends the “step&” commands to the GDB. If the process
has not got blocked, the Tracer reads the response of the “step&” command from the redirection
file and returns the status of the process to the ProcessView (i.e. current line, blocked/not blocked,
Alexandru Șutîi
process created, thread created, process terminated, etc.). Also the tracer reads the output from the
terminal and saves it internally in a list of lines.
After the step() method ends, the ProcessView asks for the output from the Tracer and appends the
new output lines to the Output Frame text field.
Figure 10 - The Output flow
4.7 Variable Value Display
When we implemented the thread support, in a problem like Producer-Consumer the user could
only learn about the thread synchronization. However, this was not enough. So we decided to
implement the feature that would display the values of the variables, both global and local.
We just used the GDB “print” command that takes a variable name and returns its value. When the
user wants to find the value of a variable he is displayed a frame that contains a text input field
where he can give the variable name, a button and a read only text field where the value is
displayed. When the user presses the button, the ProcessView object calls the get_variable_value()
method of the Tracer with the variable name. The Tracer sends the print command to GDB and gets
the value that it returns to the ProcessView object.
The event flow can be better seen in Figure 11.
InspectOS – Extending Features for Operating System Inspection
Figure 11 - Print variable value command flow
Alexandru Șutîi
5 Test Scenarios
5.1 Compiling and Tracing a Process
In order to trace a process you have to have the source code and compile it with debugging symbols.
You can see an example of source code below:
#include <stdio.h>
#include <string.h>
#include <assert.h>
#define PAGE_SIZE (1024 * 4)
int
main(void)
{
char buf[5 * PAGE_SIZE];
memset(buf, 'x', PAGE_SIZE);
memset(buf + PAGE_SIZE, 'x', PAGE_SIZE);
memset(buf + 2 * PAGE_SIZE, 'x', PAGE_SIZE);
memset(buf + 3 * PAGE_SIZE, 'x', PAGE_SIZE);
memset(buf + 4 * PAGE_SIZE, 'x', PAGE_SIZE);
return 0;
}
You can compile this example by entering the following commands:
> gcc –g –Wall –o fault fault.c
The resulted binary can be selected in InspectOS and traced. While tracing the process, you are
displayed the source code and you can step the process. Note that the source file has to be in the
same folder with the binary so GDB could find it.
5.2 Unit Tests
In order to test InspectOS we have created a folder called examples in our repository [11]. For every
implemented feature we have a unit test that resides in this directory. This directory is a good start
for our users, in order to make them understand where to start from when using InspectOS. I will
present below the tests used for the basic features.
5.2.1 Memory Management
The following source code is a very good example to show the way the physical memory frames are
allocated while running the process.
1
2
3
4
5
6
7
#include <stdio.h>
#include <string.h>
#include <assert.h>
#define PAGE_SIZE (1024 * 4)
int
InspectOS – Extending Features for Operating System Inspection
8 main(void)
9 {
10
char buf[5 * PAGE_SIZE];
11
char *pbuf;
12
memset(buf, 'x', PAGE_SIZE);
13
memset(buf + PAGE_SIZE, 'x', PAGE_SIZE);
14
memset(buf + 2 * PAGE_SIZE, 'x', PAGE_SIZE);
15
memset(buf + 3 * PAGE_SIZE, 'x', PAGE_SIZE);
16
memset(buf + 4 * PAGE_SIZE, 'x', PAGE_SIZE);
17
pbuf = (((unsigned long)&buf[0]) & ~(PAGE_SIZE-1)) + PAGE_SIZE;
18
fork();
19
pbuf[PAGE_SIZE] = 'x';
20
pbuf[0] = 'x';
21
return 0;
22 }
At line 10 a buffer of five pages is allocated, that means only 5 pages of virtual memory are
allocated. The physical pages are allocated one by one from the line 12 to line 16. For each of these
lines a demand paging event is generated.
At the line 18 a new process is created. Five virtual pages are allocated for the child process and the
physical memory pages are marked read-only and shared between the two processes. At the lines
19 and 20 when the first process writes the second and the first page, two Copy-on-Write events
occur and two more physical pages are allocated for the child process.
5.2.2 File Descriptor Table
In order to test our File Descriptor feature we use the following program:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include
#include
#include
#include
<stdio.h>
<fcntl.h>
<sys/stat.h>
<sys/types.h>
int
main(void)
{
int fd1, fd2, fd3, fd4, fd5;
fd1 = open("/tmp/a",
fd2 = dup(fd1);
close(0);
fd3 = open("/tmp/b",
close(1);
close(2);
fd5 = open("/tmp/a",
fd4 = open("/tmp/c",
O_RDONLY);
O_RDONLY); /* /tmp/b is a hard link to /tmp/a */
O_WRONLY);
O_WRONLY); /* /tmp/c is a soft link to /tmp/b */
return 0;
}
When the program starts, the descriptors 0 (standard input), 1 (standard output) and 2 (standard
error) are open. At line 11 the file descriptor 4 is being opened. At line 12 a new descriptor (5) points
to the file opened at line 11. Line 13 closes the standard input file descriptor. Line 14 opens file
descriptor 0 to point to /tmp/b. Lines 15 and 16 close the descriptors 1 and 2 (the standard output
and error). Line 17 opens file descriptor 1 to point to new file structure that point to /tmp/a. Line 18
Alexandru Șutîi
opens the file descriptor 2 to write to /tmp/c. This means the standard output and error will be
redirected to /tmp/a, respectively to/tmp/c. Standard input is redirected from /tmp/a.
5.2.3 Asynchronous Commands
In order to test that the GDB asynchronous commands work as expected and that the application
realizes when there is blocking instruction, we use the following unit test. The main process creates
a pipe. At the line 18 it creates a new process. The child process is being stepped till the line 23
where it should block as it wants to read from the pipe. Its “Next” button has to show Blocked until
the parent process gets to write in the pipe at the line 33. When the parent gets to the line 35 its
button has to show Blocked until the child process exits at the line 26.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include
#include
#include
#include
#include
<unistd.h>
<stdio.h>
<stdlib.h>
<string.h>
<sys/wait.h>
int main()
{
int pipefd[2];
int pid, status;
int dummy = 0;
char hello[] = "Hello";
char recv[20];
if (pipe(pipefd))
perror("create pipe");
pid = fork();
if (pid == 0)
{
dummy = 2;
close(pipefd[1]);
read(pipefd[0], recv, 19);
printf("Got %s\n", recv);
close(pipefd[0]);
exit(0);
}
else if (pid < 0)
perror("fork");
dummy = 3;
close(pipefd[0]);
write(pipefd[1], hello, strlen(hello)+1);
close(pipefd[1]);
waitpid(pid, &status, 0);
return 0;
}
5.2.4 Thread Support
As I have explained earlier, the main purpose of implementing the thread support was to illustrate
the Producer-Consumer problem using threads. Therefore, we created a test example that creates
two threads, a producer and a consumer, that share a global buffer of five elements. The producer
InspectOS – Extending Features for Operating System Inspection
inserts randomly generated numbers and the consumer consumes them. This example is good for
testing the asynchronous commands and for displaying the variable values. In this problem the user
is interested to see when the threads stop at the synchronization points and the values from the
buffer.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include
#include
#include
#include
#include
<pthread.h>
<unistd.h>
<stdio.h>
<stdlib.h>
<string.h>
#define BUFFER_SIZE
#define NR_ITERATIONS
5
30
typedef struct {
int buff[BUFFER_SIZE];
int first;
int count;
} buffer_t;
void init_buffer(buffer_t* b) {
memset(b->buff, 0, sizeof(int) * BUFFER_SIZE);
b->count = 0;
b->first = 0;
}
void insert_item(buffer_t* b, int item) {
b->buff[(b->first + b->count)%BUFFER_SIZE] = item;
b->count++;
}
int remove_item(buffer_t* b) {
int item = b->buff[b->first];
b->first = (b->first + 1)%BUFFER_SIZE;
b->count--;
return item;
}
int is_buffer_full(buffer_t* b) {
return b->count == BUFFER_SIZE;
}
int is_buffer_empty(buffer_t* b) {
return b->count == 0;
}
/*
* the buffer where the producer will place items
* and from which the consumer will take items
*/
buffer_t common_area;
pthread_cond_t buffer_not_full = PTHREAD_COND_INITIALIZER;
pthread_cond_t buffer_not_empty = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void* producer_fn (void* arg) {
int item_to_insert, i;
for(i = 0; i < NR_ITERATIONS; i++) {
Alexandru Șutîi
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
item_to_insert = rand() % 100;
pthread_mutex_lock(&mutex);
// Wait the buffer not to be full
if (is_buffer_full(&common_area))
pthread_cond_wait(&buffer_not_full, &mutex);
// Insert the item
insert_item(&common_area, item_to_insert);
// Signal buffer not empty
if (common_area.count == 1)
pthread_cond_signal(&buffer_not_empty);
pthread_mutex_unlock(&mutex);
}
return NULL;
}
void* consumer_fn (void* arg) {
int item_consumed, i;
for(i = 0; i < NR_ITERATIONS; i++) {
pthread_mutex_lock(&mutex);
// Wait the buffer not to be empty
if (is_buffer_empty(&common_area))
pthread_cond_wait(&buffer_not_empty, &mutex);
// Consume the item
item_consumed = remove_item(&common_area);
// Signal buffer not full
if (common_area.count == BUFFER_SIZE-1)
pthread_cond_signal(&buffer_not_full);
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main ()
{
pthread_t producer_th, consumer_th;
int rc;
/* initialization */
init_buffer(&common_area);
srand(time(NULL));
/* create the threads */
rc = pthread_create(&producer_th, NULL, producer_fn, NULL);
if (rc != 0)
perror("pthread_create");
rc = pthread_create(&consumer_th, NULL, consumer_fn, NULL);
if (rc != 0)
perror("pthread_create");
/* wait for the threads to finish execution */
rc = pthread_join(producer_th, NULL);
if (rc != 0)
perror("pthread_join");
rc = pthread_join(consumer_th, NULL);
if (rc != 0)
perror("pthread_join");
return 0;
}
InspectOS – Extending Features for Operating System Inspection
5.2.5 Process Output
The unit test for the output feature is not a hard one. The traced process creates a child process.
Both of them print text to the output. The GUI has to know how to separate the output of each
process and show it in its output frame. Also the processes have to synchronize.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
#include <sys/wait.h>
int main()
{
int pid;
printf("Started the process\n");
pid = fork();
if (pid == 0)
{
printf("The child process is created\n");
exit(0);
}
else if (pid < 0)
perror("fork");
printf("Child process created\n");
waitpid(pid, &status, 0);
printf("Child process exited\n");
return 0;
}
5.2.6 Process Input
In order to test the process input feature we use a test program that creates a child process and
both of them read integers from the input. This example shows the problem I have iterated in the
implementation section. If you enter more integers at a time, one process reads them all even if it
does not need all of them (it flushes the input pipe).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
int read_value;
int nr_steps;
int i;
printf("Give the number of steps\n");
scanf("%d", &nr_steps);
if (fork() < 0)
perror("fork");
for (i = 0; i < nr_steps; i++) {
printf("Give a value to read.\n");
scanf("%d", &read_value);
printf("Read %d.\n", read_value);
}
printf("Exiting...\n");
return 0;
}
Alexandru Șutîi
6 User Feedback
6.1 InspectOS Developers’ Feedback
Before we started the development, we decided to put ourselves in the position of a project’s user,
i.e. the student that has pour operating system concepts knowledge. Without looking over the
source code we had to compile the project, run it and come with some objective impressions. This
was a productive thing to do, as we came with a list of bugs and issues that were to be discussed [2].
First of all we did not like the graphical user interface organization. It took some time to figure out
what every widget mean. So we decided to redesign the GUI as the first thing.
We also looked again over the operating systems labs and tried to identify new concepts that could
be visualized in InspectOS. This way we came with the ideas to implement the thread support, as it
is one of the hardest concepts to comprehend by the students. Also we decided to implement the
visualization of the process standard output and error and the created process tree. The idea to
implement a way to send text to the standard input came later.
When tracing processes in OS-Tool we often needed to see how the memory or the file table looked
at a previous moment. This led us to the idea to implement the “Back” option that would create
snapshots of the process resources and be able to display them on demand.
6.2 Feedback from the OS-Tool Developers and our
Supervisors
After finishing the proposed ideas list, we had a meeting with Andrei, Lucian and Vlad, the OS-Tool
developers, and presented them the list and the way we wanted to approach the implementation of
that features.
Although we had read their bachelor’s thesis and learned about the problems they have confronted
with while developing OS-Tool, this meeting helped us a lot. Lucian brought to our knowledge that
new Linux kernels provide the same information about a process without the need of the OS-Tool
kernel module. So we had been given the idea to renounce the kernel module. We did not do this,
as there were features more important to implement and to improve, such as the GUI redesign.
However, this could be accomplished in future development. Also Andrei and Vlad shared some
thoughts of how to redesign the GUI and what tools exactly to use.
A very objective feedback came from our supervisor Razvan Deaconescu, whom we presented our
work weekly. He came with a lot of great ideas regarding the thread support, GUI redesign, “Back”
feature.
InspectOS – Extending Features for Operating System Inspection
6.3 Feedback from Students
As InspectOS is an educational application, the most important feedback is the one from its future
users, the students. We have sent a presentation email to a list of students and asked them to try
InspectOS and respond with a valuable feedback.
The feedback was a really good one. We have received some improvement idea, and bug reports,
that we have solved. There were some small issues related to the GUI, but in great the users had a
good opinion about the application and found it helpful in understanding the operating systems
concepts. From this feedback we like to think that InspectOS is a stable and useful application at the
moment.
Alexandru Șutîi
7 Conclusions and Future Plans
From the beginning we planned to realize some new features and improvements. We are confident
that we have realized the most part of what we intended. The GUI redesign and the refactoring of
the GUI class hierarchy are one of our greatest realizations in this project. I believe that we have
created a better environment for our other features development and it will open new
opportunities for who is going to continue this project in the future.
The thread support feature seemed to me hard to realize, but after a lot of research and many tries I
feel confident that we have done a great job. The redesigning of the tracer to support asynchronous
GDB commands was also a great challenge that needed some research as well. Although the
implementation has some known issues, it works well for most of the cases.
Another feature we planned and realized is the “Back” feature. It suffered a lot of modifications until
it got to the current state, but the final result is a great one. I congratulate Radu for accomplishing
this goal of InspectOS.
Although we believe we accomplished most of our goals, there have remained some ideas that we
didn’t implement. Some of them are:





Create a full documentation for the GUI and add a Help menu entry.
Create a configuration file.
Create an installer (although we could implement this in the near future).
Although the file table shows the file types descriptors point to, we wanted to add more
details to this.
Improve the process stepping. This feature should allow placing break points and adding
more buttons (besides the Next button) that a normal debugger has.
These ideas can be found in our project’s issue list, too [2]. They can serve as a good starting point
for future development. Also the OS-Tool developers’ ideas that we haven’t accomplished can be
implemented by the future developers.
I feel very happy to have worked with my colleague Radu Velea. I want to thank him and our
supervisors for the interesting collaboration, as it was a successful one. Although we have
encountered several obstacles during our development, we have managed to surpass most of them.
I have learned a lot of new things and improved my knowledge and skills.
InspectOS – Extending Features for Operating System Inspection
A. Compiling, Installing and Running
InspectOS
System Requirements
In order to run InspectOS you need a Linux operating system with a 2.6 kernel. The kernel must
support Kprobes [15]. You also need python 2.6 to run the application.
Installation
Cloning the repository
To clone the InspectOS repository you have to have Git [16] installed on your computer. You can
create a read-only clone by entering the following command in the shell:
> git clone http://ixlabs.cs.pub.ro/git/inspectos.git
Installing auxiliary packages
There are a couple of third-party libraries and tools that have to be installed for InspectOS to run.
o
Python-rsvg [17]
o
> sudo apt-get install python-rsvg
RBTree module [18]
o
> wget http://newcenturycomputers.net/projects/download.cgi/RBTree-1.6.zip
> unzip RBTree-1.6.zip
> cd RBTree-1.6
> sudo python RBTree.py install
Graphviz [19]
o
> sudo apt-get install Graphviz
GDB [20]
> sudo apt-get install gdb
Running InspectOS
First of all you need to compile the kernel module and insert it. For this you need to enter the
following commands:
> cd $INSPECTOS_ROOT/fault
> make
> sudo insmod os-mon.ko
Alexandru Șutîi
Now you are ready to run the application. You simply need to go to InspectOS root directory and run
the script inspectOS.sh.
> cd $INSPECTOS_ROOT
> sudo bash inspectOS.sh
Tracing a process
When InspectOS starts you are displayed a form that lets you choose the program you want to
trace. You have to choose a binary that was compiled with debugging symbols and resides in the
same directory with its source code. You also can trace more processes by accessing Menu->File>Open.
When you are running InspectOS you are displayed a container for each process. Every process is
identified by its process id. You can find it in the Next button, in the container name, etc. You can
select what process to visualize by checking its checkbox in the up left corner of the window. You
can visualize maximum two processes at the same time.
In the right of the main window you can see the physical memory. Each process container contains
Next buttons for each thread, a source code frame, an input and an output frame, a virtual memory
frame, a VMA frame and a File Table frame. You can choose the frame to view by selecting the
appropriate radio button. There is also a Print button for printing the variables’ value.
InspectOS – Extending Features for Operating System Inspection
B. InspectOS Repository Description
I will briefly describe some of the directories that form our repository.





fault/ - This is the directory containing the source code for the kernel module. This is where
to compile the module and insert it.
examples/ - All our unit tests can be found here. This is a good starting point for the users
that use our application for the first time.
ixia-slides/ - This directory contains the presentation slides, logos, images.
styles/ - In order to give a custom color (yellow) to the current line in the source code frame
I had to extend a style. This style resides in this directory.
src/ - This is the source directory for the user space modules. The main directories and files
are:
o src/main.py – This file defines the Main class, the one that creates the window and
starts the application.
o src/ostool and src/os_tool/event – The processing module files reside in these
directories. Here are the classes that read the VMA, memory tables and file table
information from procfs and present it to the GUI.
o src/os_tool/gui – The GUI classes can be found in this directory. The file
process_view.py defines the ProcessView class that encapsulates all the information
about a process. It gets the VMA, memory and file descriptor frames from the
classes COW, VMA and FileTableTab that are defined in the files cow.py, vma.py and
file_table_tab.py respectively.
o src/os_tool/tracer.py - This file defines the Tracer module.
Alexandru Șutîi
References
[1] Wikipedia. Operating system - Wikipedia, the free encyclopedia.
http://en.wikipedia.org/wiki/Operating_system , 2011. [Online; accessed 1-July-2011].
[2] InspectOS issue list - https://ixlabs.cs.pub.ro/redmine/projects/inspectos/issues.
[3] Wikipedia. Process (Computing) - Wikipedia, the free encyclopedia.
http://en.wikipedia.org/wiki/Process_%28computing%29, 2011. [Online; accessed 1-July-2011].
[4] Wikipedia. Thread (Computer Science) - Wikipedia, the free encyclopedia.
http://en.wikipedia.org/wiki/Thread_%28computer_science%29, 2011. [Online; accessed 1-July2011].
[5] Wikipedia. Virtual Memory - Wikipedia, the free encyclopedia.
http://en.wikipedia.org/wiki/Virtual_memory , 2011. [Online; accessed 1-July-2011].
[6] Wikipedia. File descriptor - Wikipedia, the free encyclopedia.
http://en.wikipedia.org/wiki/File_descriptor , 2011. [Online; accessed 1-July-2011].
[7] Memory Management in Linux, http://www.makelinux.net/ldd3/chp-15-sect-1 , 2011. [Online;
accessed 1-July-2011].
[8 ] Wikipedia. Demand Paging - Wikipedia, the free encyclopedia.
http://en.wikipedia.org/wiki/Demand_paging , 2011. [Online; accessed 1-July-2011].
[9] Wikipedia. Copy-on-write - Wikipedia, the free encyclopedia. http://en.wikipedia.org/wiki/Copyon-write , 2011. [Online; accessed 1-July-2011].
[10] R. Stallman, R. Pesch, S. Shebs, “Debugging with GDB”.
http://www.tutok.sk/fastgl/download/books/DebuggingWithGDB.pdf
[11] InspectOS Git Repository http://ixlabs.cs.pub.ro/git/inspectos.git
[12] A. Silberschatz, P.B. Galvin, G. Gagne, “Operating Systems Concepts – 7th Edition”.
[13] R. Love, “Linux Kernel Development”.
stid.googlecode.com/files/Linux.Kernel.Development.3rd.Edition.pdf
[14] GDB Mailing List, http://sourceware.org/ml/gdb/
[15] Kernel Probes Home Page, http://sourceware.org/systemtap/kprobes/
[16] Git Home Page, http://git-scm.com/
[17] Python rsvg Home Page, http://cairographics.org/pyrsvg/
InspectOS – Extending Features for Operating System Inspection
[18] RBTree Home Page, http://newcenturycomputers.net/projects/rbtree.html
[19] Graphviz Home Page, http://www.graphviz.org/
[20] GDB Home Page, http://www.gnu.org/software/gdb/
Download