Download Dynamic linker and debugging/tracing interface for HelenOS

Transcript
Therefore, we adopt the following strategy. First we make sure the memory area
we are about to write is private (i.e. not shared) and anonymous (backed by the
anonymous memory backend). When writing, we proceed page by page, making
sure every page is present in memory before writing it.
This requires some new functionality in the memory management subsystem,
namely the module as.c in kernel/generic/src/mm. We implemented the functions as area make writeable() and as debug write().
The function as area make writeable() checks whether the given memory area
is private and anonymous. If it is not, the function makes a copy of the data in the
memory area and replaces the old memory area with a freshly created one, private
and anonymous and containing the same data.
The function as debug write() splits the address range to be written to on page
boundaries and for each piece it uses a helper function debug write inside page().
This function checks whether the page to be written to is present in memory. If it
is not, it calls the page-fault handler to fetch the page. Then it performs the write
itself.
The implementation of the function will remain valid even when paging out is
implemented in HelenOS (as now it is not). The function makes sure the page stays
present by holding locks on the address space and memory area.
4.4.5
Kbox Thread Benefits
We have already seen that the kbox thread plays an important role in accessing the
memory of the application. But that is not its sole purpose.
Actually all debugging requests are mostly processed in the context of the kbox
thread. The only exception is that accessing the memory of the debugger is performed in the context of the debugger (naturally). The benefit here is that it greatly
simplifies locking.
There are actually two ways in which this makes our life easier. One is locking
order and the other is ensuring continued existence.
Firstly, if we tried to work with the current task (the debugger) and with the
application (or their threads), we would need to be extremely careful not to run into
a deadlock. Secondly, the current task and the current thread are always guaranteed
to exist, while the continued existence of other tasks and threads must be ensured
by some means. One could hold a lock on them, for example, but this creates yet
more locking-order issues.
During development we actually created an implementation that performed most
of the processing in the context of the debugger (i.e. during pre-processing). It was
doable, however, by moving the processing to the kbox thread, the locking scheme
was simplified by an order of magnitude.
4.4.6
Register State Access
User-Space Register State
There are two points where the control can pass from user space to the kernel (and
back). The first one is a system call (i.e. the function syscall handler() and the
second one is an exception (i.e. the function exc dispatch().
46