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