Due to the universal problems (volume, intrusion, access) encountered when writing tools that monitor the execution of a program, development of execution monitors is very difficult. Lots of effort must be expended solving those problems whenever a monitoring tool is written. The goal of the Alamo framework is to reduce the difficulties in writing monitoring tools by constructing a platform on which monitor construction is relatively easier. Alamo's design extends earlier work developed for an interpretive language [Jeff93] by developing techniques suitable for a compiled systems programming language ANSI C.
The Alamo framework supports a range of dynamic analysis tools. It runs on Sun workstations that use the Solaris 2.x operating system. It consists of three major components: a Configurable C Instrumentation (CCI) tool [Templ96], the Alamo Monitor Executive (AME), and run-time support libraries for graphics and visualization and for target program access [Zhou96]. This document introduces the AME component.
Since threads execute concurrently, a standard thread model would allow the execution of TP and EMs to be truly parallel on multi-processor machines. If the TP and EMs execute simultaneously, the TP might modify state while it is being accessed by EMs. In Alamo the TP and EMs are synchronized in order to ensure the consistency between them. This has the advantage of giving EMs full stable information about the behavior of the TP and equally importantly, it substantially simplifies monitor development.
AME implemented two approaches for the context switch. The first one employed the Solaris threads package. Under Solaris threads, AME assigns each loaded module a separate thread, but because of the synchronous execution, at any instant only one thread is running. Semaphores are used to synchronize the execution of multiple threads. Since Alamo's execution model is not concurrent, and semaphore operations impose additional overheads, we choose the second approach because it removes semaphores and threads and uses a more portable and simpler model.
In our second approach, a new user-level context is created for each loaded module. The new context includes a stack region allocated out of the heap space of that module. Each module has a handle to its context. Each context executes with its own control flow, stack, and a separate set of registers. Important register values (eg. sp, fp, and pc) are saved onto the stack before the control is transferred to another context. The core piece of code for the context switch, which comes from the coroutine facilities in the Icon programming language is written in assembly code and has been ported to many different machines and operating systems, such as UNIX, MS-DOS, Macintosh, VMS, etc. This approach is more efficient timewise and more portable than the Solaris threads approach.
Whenever a desired event occurs in the TP, execution control is transferred to the EM along with a code and a value for that event. When this occurs, an event has been reported to the EM. When an EM resumes the execution of the TP, it uses an event mask to explicitly specify what kind of events are to be reported in the execution that follows. The event mask is a bit vector with each bit representing a particular event code. When a bit is set, that means the event code corresponding to that bit is used by an EM.
AME supports dynamic event masking based on the event code. It chooses to mask events in the TP instead of filtering them in the EM. This reduces the number of context switches between the TP and EMs. Moreover, event masking allows an EM to specify what events are to be reported and to change the specification at run-time.
Two alternatives for managing the heap space of loaded programs are implemented in AME. The first approach is to use a single system heap. The advantage of this approach is that the heap space is not limited for the loaded modules, since they are sharing the system's heap space. The disadvantage of it is that the heap space allocated for the TP is interleaved with the heap space allocated for EMs. If the TP is buggy, random pointers can write over EM code or data regions. Memory protection can be provided for EM code regions, but protecting EM data regions is impossible in this approach because of memory interleaving.
The second approach provides an independent heap space for each module, giving monitor writers the ability to specify memory protection on both EM code and data regions. The disadvantage of this solution is that the fixed-sized heap space represents a limitation imposed by the monitoring framework at the beginning of execution. The heap size can be set to a large number without recompilation and it is not a problem in practice.
[Jeff93] Jeffery, C. L., "A Framework for Monitoring Program Execution", Technical Report 93-21, Department of Computer Science, University of Arizona, 1993.
[Templ96] Templer, K. S. and Jeffery, C. L., "Design of a Configurable C Instrumentation Tool", Technical Report 96-6, Division of Computer Science, University of Texas at San Antonio, February, 1996.
[Zhou96] Zhou, Wenyi and Jeffery, C. L., "Target Program State Access in Alamo Monitor Framework", Technical Report 96-5, Division of Computer Science, University of Texas at San Antonio, February, 1996.